1
0
Fork 0
mirror of https://gitlab.com/bztsrc/bootboot.git synced 2023-02-13 20:54:32 -05:00

Initial commit

This commit is contained in:
bzt 2018-06-05 20:34:03 +02:00
commit 52c96a7d88
50 changed files with 9920 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Debug files
*.dSYM/
*.su
aarch64-rpi/LIC*
aarch64-rpi/*.bin
aarch64-rpi/*.dat
aarch64-rpi/*.elf

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
Copyright (C) 2017 bzt (bztsrc@gitlab)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

390
README.md Normal file
View file

@ -0,0 +1,390 @@
BOOTBOOT Reference Implementations
==================================
I provide pre-compiled images ready for use.
1. *x86_64-efi* the preferred way of booting on x86_64 architecture.
Standard GNU toolchain and a few files from gnuefi (included).
[bootboot.efi](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.efi?raw=true) (76k), [bootboot.rom](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.rom?raw=true) (76k)
2. *x86_64-bios* BIOS and Multiboot (GRUB) compatible, OBSOLETE loader.
If you want to recompile this, you'll need fasm (not included).
[boot.bin](https://gitlab.com/bztsrc/bootboot/blob/master/boot.bin?raw=true) (512 bytes, works as MBR and VBR too), [bootboot.bin](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.bin?raw=true) (8k)
3. *aarch64-rpi* ARMv8 boot loader for Raspberry Pi 3
[bootboot.img](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.img?raw=true) (27k)
4. *mykernel* an example BOOTBOOT [compatible kernel](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel) in C which draws lines and boxes
Please note that the reference implementations do not support the full protocol at level 2,
they only handle static mappings which makes them level 1 loaders.
BOOTBOOT Protocol
=================
Rationale
---------
The protocol describes how to boot an ELF64 or PE32+ executable inside an initial ram disk image
into clean 64 bit mode, without using any configuration or even knowing the file system of initrd.
On [BIOS](https://gitlab.com/bztsrc/bootboot/tree/master/x86_64-bios) based systems, the same image can be loaded via
Multiboot, chainload from MBR or VBR (GPT hybrid booting) or run as a BIOS Expansion ROM
(so not only the ramdisk can be in ROM, but the loader as well).
On [UEFI machines](https://gitlab.com/bztsrc/bootboot/tree/master/x86_64-efi), it is a standard EFI OS Loader application.
On [Raspberry Pi 3](https://gitlab.com/bztsrc/bootboot/tree/master/aarch64-rpi) board the bootboot.img
is loaded from the boot partition on SD card as kernel8.img by start.elf.
The difference to other booting protocols is flexibility and portability;
only clean 64 bit support; and that BOOTBOOT expects the kernel to fit inside the
initial ramdisk. This is ideal for hobby OSes and micro-kernels. The advantage it gaves is that your kernel
can be splitted up into several files and yet they will be loaded together
as if it were a monolitic kernel. And you can use your own file system for the initrd.
Note: BOOTBOOT is not a boot manager, it's a boot loader protocol. If you want an interactive boot menu, you should
integrate that *before* a BOOTBOOT compatible loader is called. Like GRUB chainloading boot.bin (or loading bootboot.bin as a
kernel) or adding bootboot.efi to UEFI Boot Manager's menu for example.
Licence
-------
The BOOTBOOT Protocol as well as the reference implementations are free
software and licensed under the terms of MIT licence.
```
Copyright (C) 2017 bzt (bztsrc@gitlab)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
Authors
-------
efirom: Michael Brown
zlib: Mark Adler
tinflate: Joergen Ibsen
raspbootcom: (GPL) Goswin von Brederlow
BOOTBOOT, FS/Z: bzt
Glossary
--------
* _boot partition_: the first bootable partition of the first bootable disk,
a rather small one. Most likely an EFI System Partition with FAT, but can be
any other partition as well if the partition is bootable (bit 2 set in flags).
* _environment file_: a maximum one page frame long, utf-8 [file](https://gitlab.com/bztsrc/bootboot/blob/master/README.md#environment-file) on boot partition
at `BOOTBOOT\CONFIG` (or when your initrd is on the entire partition, `/sys/config`). It
has "key=value" pairs (separated by newlines). The protocol
only specifies two of the keys: "screen" for screen size,
and "kernel" for the name of the executable inside the initrd.
* _initrd_: initial [ramdisk image](https://gitlab.com/bztsrc/bootboot/blob/master/README.md#installation)
(probably in ROM or flash, or on a GPT boot partition at BOOTBOOT\INITRD, or it can occupy the whole partition, or can be loaded
over the network). It's format and whereabouts are not specified (the good part :-) ) and can be optionally gzip compressed.
* _loader_: a native executable on the boot partition or in ROM. For multi-bootable disks
more loader implementations can co-exists.
* _file system driver_: a separated function that parses initrd for the kernel file.
Without one the first executable found will be loaded.
* _kernel file_: an ELF64 / PE32+ [executable inside initrd](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel),
optionally with the following symbols: `fb`, `environment`, `bootboot` (see machine state and linker script).
* _BOOTBOOT structure_: an informational structure defined in [bootboot.h](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.h).
Boot process
------------
1. the firmware locates the loader, loads it and passes control to it.
2. the loader initializes hardware (64 bit mode, screen resolution, memory map etc.)
3. then loads environment file and initrd file (probably from the boot partition or from ROM).
4. iterates on file system drivers, and loads kernel file from initrd.
5. if file system is not recognized, scans for the first executable in the initrd.
6. parses executable header and symbols to get link addresses (only level 2 compatible loaders).
7. maps linear framebuffer, environment and [bootboot structure](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.h) accordingly.
8. sets up stack, registers and jumps to kernel entry point. See [example kernel](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel).
Machine state
-------------
When the kernel gains control, the memory mapping looks like this:
```
-64M "fb" framebuffer (0xFFFFFFFFFC000000)
-2M "bootboot" structure (0xFFFFFFFFFFE00000)
-2M+1page "environment" string (0xFFFFFFFFFFE01000)
-2M+2page.. code segment v (0xFFFFFFFFFFE02000)
..0 stack ^ (0x0000000000000000)
0-16G RAM identity mapped (0x0000000400000000)
```
All infomration is passed at linker defined addresses. No API required at all, therefore the BOOTBOOT Protocol is
totally architecture and ABI agnostic. Level 1 expects these symbols at pre-defined addresses, level 2 loaders
parse the symbol table in executable to get the actual addresses.
The RAM (up to 16G) is identity mapped in the positive address range. Interrups are turned off and code is running
in supervisor mode.
The screen is properly set up with a 32 bit packed pixel linear framebuffer, mapped at the negative address defined by
the `fb` symbol. Level 1 loaders limit the framebuffer size somewhere around 4096 x 4096 pixels (depends on scanline size
and aspect ratio too). That's more than enough for [Ultra HD 4K](https://en.wikipedia.org/wiki/4K_resolution)
(3840 x 2160). Level 2 loaders can place the fb anywhere in memory therefore they do not have such a limitation.
The main information [bootboot structure](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot.h) is mapped
at `bootboot` symbol. It consist of a fixed 128 bytes long header followed by various number of fixed
records. Your initrd (with the additional kernel modules and servers) is enitrely in the memory, and you can locate it
using this struct's *initrd_ptr* and *initrd_size* members. The physical address of the framebuffer can be found in
the *fb_ptr* field. The *boot time* and a platform independent *memory map* are also provided.
The configuration string (or command line if you like) is mapped at `environment` symbol.
Kernel's code segment is mapped at ELF header's `p_vaddr` or PE header's `code_base` (level 2 only). Level 1 loaders
load kernels at -2M, therefore limiting the kernel's size in 2M, including configuration, data, bss and stack. That
must be more than enough for all micro-kernels.
The stack is at the top of the memory, starting at zero and growing downwards.
Environment file
----------------
Configuration is passed to your kernel as newline separated, zero terminated UTF-8 string with "key=value" pairs.
```
// BOOTBOOT Options
// --- Loader specific ---
// requested screen dimension. If not given, autodetected
screen=800x600
// elf or pe binary to load inside initrd
kernel=sys/core
// --- Kernel specific, you're choosing ---
anythingyouwant=somevalue
otherstuff=enabled
somestuff=100
someaddress=0xA0000
```
That cannot be larger than a page size (4096 bytes). Temporary variables will be appended at the end (from
UEFI command line). C style single line and multi line comments can be used. BOOTBOOT protocol only uses `screen` and
`kernel` keys, all the others and their values are up to your kernel (or drivers) to parse. Be creative :-)
To modify the environment, one will need to insert the disk into another machine (or boot a simple OS like DOS) and edit
BOOTBOOT\CONFIG on the boot partition. With UEFI, you can use the `edit` command provided by the EFI Shell or append
"key=value" pairs on the command line (value specified on command line takes precedence over the one in the file).
File system drivers
-------------------
The file system of the boot partition and how initrd is loaded from it is out of the scope of this specification:
the BOOTBOOT Protocol only states that a compatible loader must be able to load initrd and the environment file,
but does not describe how or from where. They can be loaded from nvram, ROM or over
network for example, it does not matter.
On the other hand BOOTBOOT does specify one API function to locate a file (the kernel)
inside the initrd image, but the ABI is also implementation (and architecture) specific.
This function receives a pointer to initrd in memory as well as the kernel's filename, and
returns a pointer to the first byte of the kernel and it's size. On error (if file system is
not recognized or the kernel file is not found) returns {NULL,0}. Plain simple.
```c
typedef struct {
uint8_t *ptr;
uint64_t size;
} file_t;
file_t myfs_initrd(uint8_t *initrd, char *filename);
```
The protocol expects that a BOOTBOOT compliant loader iterates on a list of drivers until one
returns a valid result. If all file system drivers returned {NULL,0}, the loader will brute-force
scan for the first ELF64 / PE32+ image in the initrd. This feature is quite comfortable when you
want to use your own file system but you don't have written an fs driver for it yet, or when your
"initrd" is a single, statically linked executable, like the Minix kernel. You just copy
your initrd on the boot partition, and you're ready to rock and roll!
The BOOTBOOT Protocol expects the file system drivers ([here](https://gitlab.com/bztsrc/bootboot/blob/master/x86_64-efi/fs.h),
[here](https://gitlab.com/bztsrc/bootboot/blob/master/x86_64-bios/fs.inc) and [here](https://gitlab.com/bztsrc/bootboot/blob/master/aarch64-rpi/fs.h))
to be separated from the rest of the loader's source. This is so because it was designed to help the needs of hobby
OS developers, specially for those who want to write their own file systems.
The reference implementations support [cpio](https://en.wikipedia.org/wiki/Cpio) (all hpodc, newc and crc variants),
[ustar](https://en.wikipedia.org/wiki/Tar_(computing)), osdev.org's [SFS](http://wiki.osdev.org/SFS),
[James Molloy's initrd](http://www.jamesmolloy.co.uk/tutorial_html/8.-The%20VFS%20and%20the%20initrd.html)
format and OS/Z's native [FS/Z](https://gitlab.com/bztsrc/osz/blob/master/etc/include/fsZ.h).
Gzip compressed initrds also supported to save disk space and fasten up load time (not recommended on RPi3).
Example kernel
--------------
An [example kernel](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel/kernel.c) is included with BOOTBOOT Protocol
to demostrate how to access the environment:
```c
#include <bootboot.h>
/* imported virtual addresses, see linker script below */
extern BOOTBOOT bootboot; // see bootboot.h
extern unsigned char *environment; // configuration, UTF-8 text key=value pairs
extern uint8_t fb; // linear framebuffer mapped
void _start()
{
int x, y, s=bootboot.fb_scanline, w=bootboot.fb_width, h=bootboot.fb_height;
// cross-hair to see screen dimension detected correctly
for(y=0;y<h;y++) { *((uint32_t*)(&fb + s*y + (w*2)))=0x00FFFFFF; }
for(x=0;x<w;x++) { *((uint32_t*)(&fb + s*(h/2)+x*4))=0x00FFFFFF; }
// red, green, blue boxes in order
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+20)*4))=0x00FF0000; } }
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+50)*4))=0x0000FF00; } }
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+80)*4))=0x000000FF; } }
// say hello
puts("Hello from a simple BOOTBOOT kernel");
// hang for now
while(1);
}
```
For compilation, see example bootboot kernel's [Makefile](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel/Makefile) and
[link.ld](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel/link.ld).
Installation
------------
1. make an initrd with your kernel in it. Example:
```shell
mkdir -r tmp/sys
cp mykernel.x86_64.elf tmp/sys/core
# copy more files to tmp/ directory
# create your file system image or an archive. For example use one of these:
cd tmp
find . | cpio -H newc -o | gzip > ../INITRD
find . | cpio -H crc -o | gzip > ../INITRD
find . | cpio -H hpodc -o | gzip > ../INITRD
tar -czf ../INITRD *
mkfs ../INITRD .
```
2. Create FS0:\BOOTBOOT directory on the boot partition, and copy the image you've created
into it. If you want, create a text file named CONFIG there too, and put your
environment variables there. If you use a different name than "sys/core" for your
kernel, specify "kernel=" in it.
Alternatively you can copy an uncompressed INITRD into the whole partition using your fs only, leaving FAT file system entirely out.
You can also create an Option ROM out of INITRD (on BIOS there's not much space ~64-96k, but on EFI it can be 16M).
3. copy the BOOTBOOT loader on the boot partition.
3.1. *UEFI disk*: copy __bootboot.efi__ to **_FS0:\EFI\BOOT\BOOTX64.EFI_**.
3.2. *BIOS disk*: copy __bootboot.bin__ to **_FS0:\BOOTBOOT\LOADER_**.
3.3. *Raspberry Pi 3*: copy __bootboot.img__ to **_FS0:\KERNEL8.IMG_**.
**IMPORTANT**: see the relevant port's README.md for more details.
Troubleshooting
---------------
```
BOOTBOOT-PANIC: LBA support not found
```
Really old hardware. Your BIOS does not support LBA. This message is generated by 1st stage loader (boot.bin).
```
BOOTBOOT-PANIC: FS0:\BOOTBOOT\LOADER not found
```
The loader (bootboot.bin) is not on the disk or it's starting LBA address is not recorded in the boot sector at dword [0x1B0]
(see [mkboot](https://gitlab.com/bztsrc/bootboot/blob/master/x86_64-bios/mkboot.c)). As the boot sector supports RAID mirror,
it will try to load the loader from other drives as well. This message is generated by 1st stage loader (boot.bin).
```
BOOTBOOT-PANIC: Hardware not supported
```
Really old hardware. On x86_64, your CPU is older than family 6.0 or PAE, MSR, LME features not supported.
On AArch64 it means the MMU does not support 4k granule size, at least 36 bit address size or the system timer
(0x3F003000) is not available.
```
BOOTBOOT-PANIC: Unable to initialize SDHC card
```
The loader was unable to initialize EMMC for SDHC card access, probably hardware error or old card.
```
BOOTBOOT-PANIC: No boot partition
```
Either the disk does not have a GPT, or there's no EFI System Partition nor any other bootable
partition on it. Or the FAT file system is found but inconsistent, or doesn't have a BOOTBOOT directory.
```
BOOTBOOT-PANIC: INITRD not found
```
The loader could not find the initial ramdisk image on the boot partition. This message will be shown
even if you specify an alternative initrd file on EFI command line.
```
BOOTBOOT-PANIC: Kernel not found in initrd
```
Kernel is not included in the initrd, or initrd's fileformat is not recognized by any of the file system
drivers and scanning haven't found a valid executable header in it.
```
BOOTBOOT-PANIC: Kernel is not a valid executable
```
The file that was specified as kernel could be loaded by fs drivers, but it's not an ELF64 or PE32+,
does not match the architecture, or does not have any program header with a loadable segment (p_vaddr or core_base)
in the negative range (see linker script). This error is also shown by level 2 loaders if the address of `fb`,
`bootboot` and `environment` symbols are not in the negative range.
```
BOOTBOOT-PANIC: GOP failed, no framebuffer
BOOTBOOT-PANIC: VESA VBE error, no framebuffer
BOOTBOOT-PANIC: VideoCore error, no framebuffer
```
The first part of the message varies on different platforms. It means that the loader was unable to set up linear
framebuffer with packed 32 bit pixels in the requested resolution. Possible solution is to modify screen to
`screen=800x600` or `screen=1024x768` in environment.
That's all, hope it will be useful!

27
aarch64-rpi/Makefile Normal file
View file

@ -0,0 +1,27 @@
all: boot.S bootboot.c fs.h
@echo " src aarch64-rpi (Raspberry Pi 3+)"
@aarch64-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c boot.S -o boot.o
@aarch64-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -I ./ -c tinflate.c -o tinflate.o
@aarch64-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -I ./ -c bootboot.c -o bootboot.o
@aarch64-elf-ld -r -b binary -o font.o font.psf
@aarch64-elf-ld -nostdlib -nostartfiles boot.o bootboot.o tinflate.o font.o -T link.ld -o bootboot.elf
@aarch64-elf-objcopy -O binary bootboot.elf ../bootboot.img
@rm *.o bootboot.elf
mkboot: mkboot.c
gcc mkboot.c -o mkboot
raspbootcom: raspbootcom.c
gcc raspbootcom.c -o raspbootcom
getfw:
wget -q https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/LICENCE.broadcom
wget -q https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bootcode.bin
wget -q https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/fixup.dat
wget -q https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/start.elf
cleanfw:
@rm LICENCE.broadcom bootcode.bin fixup.dat start.elf
clean:
@rm mkboot raspbootcom *.o >/dev/null 2>/dev/null || true

49
aarch64-rpi/README.md Normal file
View file

@ -0,0 +1,49 @@
BOOTBOOT Raspberry Pi 3 Implementation
======================================
See [BOOTBOOT Protocol](https://gitlab.com/bztsrc/bootboot) for common details.
On [Raspberry Pi 3](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/sdcard.md) board the bootboot.img
is loaded from the boot (or firmware) partition on SD card as kernel8.img by start.elf. For separating firmware and boot
partitions see [documentation](https://gitlab.com/bztsrc/bootboot/blob/master/bootboot_spec_1st_ed.pdf).
Machine state
-------------
In addition to standard mappings, the MMIO is also mapped in kernel space:
```
-128M MMIO (0xFFFFFFFFF8000000)
```
Code is running in supervisor mode, at EL1. Dummy exception handlers are installed, but your kernel should use it's own
handlers as soon as possible.
File system drivers
-------------------
For boot partition, RPi3 version expects FAT16 or FAT32 file systems (if the
initrd is a file and does not occupy the whole boot partition). The initrd can also be loaded over serial line,
running [raspbootcom](https://gitlab.com/bztsrc/bootboot/blob/master/aarch64-rpi/raspbootcom.c) on a remote machine.
Gzip compression is not recommended as reading from SD card is considerably faster than uncompressing.
Installation
------------
1. Copy __bootboot.img__ to **_FS0:\KERNEL8.IMG_**.
2. You'll need other [firmware files](https://gitlab.com/raspberrypi/firmware/tree/master/boot) as well.
3. If you have used a GPT disk with ESP as boot partition, then you need to map it in MBR so that Raspberry Pi
firmware could find those files. The [mkboot](https://gitlab.com/bztsrc/bootboot/blob/master/aarch64-rpi/mkboot.c)
utility will do that for you.
Limitations
-----------
- Initrd in ROM is not possible
- Maps only the first 1G of RAM.
- Cards other than SDHC Class 10 not supported.
- Raspberry Pi does not have an on-board RTC, so always 0000-00-00 00:00:00 returned as bootboot.datetime.

154
aarch64-rpi/boot.S Normal file
View file

@ -0,0 +1,154 @@
/*
* aarch64-rpi/boot.S
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief Boot loader for the Raspberry Pi 3+ ARMv8
*
*/
.section ".text.boot"
.global _start
.global jumptokernel
/*********************************************************************
* Entry point called by start.elf *
*********************************************************************/
_start:
// magic
b 1f
.ascii "BOOTBOOT"
// read cpu id, stop slave cores
1: mrs x7, mpidr_el1
and x7, x7, #3
cbz x7, 2f
1: wfe
b 1b
2: // set stack before our code
ldr x1, =_start
// set up EL1
mrs x0, CurrentEL
and x0, x0, #12
// running at EL3?
cmp x0, #12
bne 1f
mov x2, #0x5b1
msr scr_el3, x2
mov x2, #0x3c9
msr spsr_el3, x2
adr x2, 1f
msr elr_el3, x2
eret
// running at EL2?
1: cmp x0, #4
beq 1f
msr sp_el1, x1
// set up exception handlers
ldr x1, =_vectors
msr vbar_el2, x1
// enable CNTP for EL1
mrs x0, cnthctl_el2
orr x0, x0, #3
msr cnthctl_el2, x0
msr cntvoff_el2, xzr
// initialize virtual MPIDR
mrs x0, midr_el1
mrs x2, mpidr_el1
msr vpidr_el2, x0
msr vmpidr_el2, x2
// disable coprocessor traps
mov x0, #0x33FF
msr cptr_el2, x0
msr hstr_el2, xzr
mov x0, #(3 << 20)
msr cpacr_el1, x0
// enable AArch64 in EL1
mov x0, #(1 << 31) // AArch64
orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3
msr hcr_el2, x0
mrs x0, hcr_el2
// Setup SCTLR access
mov x2, #0x0800
movk x2, #0x30d0, lsl #16
msr sctlr_el1, x2
// change exception level to EL1
mov x2, #0x3c4
msr spsr_el2, x2
adr x2, 1f
msr elr_el2, x2
eret
1: // clear bss
ldr x2, =__bss_start
ldr w3, =__bss_size
1: cbz w3, 2f
str xzr, [x2], #8
sub w3, w3, #1
cbnz w3, 1b
2: mov sp, x1
// set up exception handlers
ldr x1, =_vectors
msr vbar_el1, x1
// jump to C code
bl bootboot_main
1: wfe
b 1b
.align 11
_vectors:
.align 7
mov x0, #0
mrs x1, esr_el1
mrs x2, elr_el1
mrs x3, spsr_el1
mrs x4, far_el1
mrs x5, sctlr_el1
mrs x6, tcr_el1
b uart_exc
.align 7
mov x0, #1
mrs x1, esr_el1
mrs x2, elr_el1
mrs x3, spsr_el1
mrs x4, far_el1
mrs x5, sctlr_el1
mrs x6, tcr_el1
b uart_exc
.align 7
mov x0, #2
mrs x1, esr_el1
mrs x2, elr_el1
mrs x3, spsr_el1
mrs x4, far_el1
mrs x5, sctlr_el1
mrs x6, tcr_el1
b uart_exc
.align 7
mov x0, #3
mrs x1, esr_el1
mrs x2, elr_el1
mrs x3, spsr_el1
mrs x4, far_el1
mrs x5, sctlr_el1
mrs x6, tcr_el1
b uart_exc

1574
aarch64-rpi/bootboot.c Normal file

File diff suppressed because it is too large Load diff

BIN
aarch64-rpi/font.psf Normal file

Binary file not shown.

274
aarch64-rpi/fs.h Normal file
View file

@ -0,0 +1,274 @@
/*
* aarch64-rpi/fs.h
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief Filesystem drivers for initial ramdisk.
*
*/
/**
* return type for fs drivers
*/
typedef struct {
uint8_t *ptr;
uint64_t size;
} file_t;
extern int oct2bin(unsigned char *str,int size);
extern int hex2bin(unsigned char *str,int size);
#ifdef _FS_Z_H_
/**
* FS/Z initrd (OS/Z's native file system)
*/
file_t fsz_initrd(unsigned char *initrd_p, char *kernel)
{
FSZ_SuperBlock *sb = (FSZ_SuperBlock *)initrd_p;
FSZ_DirEnt *ent;
FSZ_Inode *in=(FSZ_Inode *)(initrd_p+sb->rootdirfid*FSZ_SECSIZE);
file_t ret = { NULL, 0 };
if(initrd_p==NULL || memcmp(sb->magic,FSZ_MAGIC,4) || kernel==NULL){
return ret;
}
DBG(" * FS/Z ");
DBG(kernel);
DBG("\n");
// Get the inode
int i,ss=1<<(sb->logsec+11);
char *s,*e;
s=e=kernel;
i=0;
again:
while(*e!='/'&&*e!=0){e++;}
if(*e=='/'){e++;}
if(!memcmp(in->magic,FSZ_IN_MAGIC,4)){
//is it inlined?
if(!memcmp(in->inlinedata,FSZ_DIR_MAGIC,4)){
ent=(FSZ_DirEnt *)(in->inlinedata);
} else if(!memcmp(initrd_p+in->sec*ss,FSZ_DIR_MAGIC,4)){
// go, get the sector pointed
ent=(FSZ_DirEnt *)(initrd_p+in->sec*ss);
} else {
return ret;
}
//skip header
FSZ_DirEntHeader *hdr=(FSZ_DirEntHeader *)ent; ent++;
//iterate on directory entries
int j=hdr->numentries;
while(j-->0){
if(!memcmp(ent->name,s,e-s)) {
if(*e==0) {
i=ent->fid;
break;
} else {
s=e;
in=(FSZ_Inode *)(initrd_p+ent->fid*ss);
goto again;
}
}
ent++;
}
} else {
i=0;
}
if(i!=0) {
// fid -> inode ptr -> data ptr
FSZ_Inode *in=(FSZ_Inode *)(initrd_p+i*ss);
if(!memcmp(in->magic,FSZ_IN_MAGIC,4)){
ret.size=in->size;
switch(FSZ_FLAG_TRANSLATION(in->flags)) {
case FSZ_IN_FLAG_INLINE:
// inline data
ret.ptr=(uint8_t*)(initrd_p+i*ss+1024);
break;
case FSZ_IN_FLAG_SECLIST:
case FSZ_IN_FLAG_SDINLINE:
// sector directory or list inlined
ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)&in->inlinedata) * ss);
break;
case FSZ_IN_FLAG_DIRECT:
// direct data
ret.ptr=(uint8_t*)(initrd_p + in->sec * ss);
break;
// sector directory (only one level supported here, and no holes in files)
case FSZ_IN_FLAG_SECLIST0:
case FSZ_IN_FLAG_SD:
ret.ptr=(uint8_t*)(initrd_p + (unsigned int)(((FSZ_SectorList *)(initrd_p+in->sec*ss))->sec) * ss);
break;
default:
ret.size=0;
break;
}
}
}
return ret;
}
#endif
/**
* cpio archive
*/
file_t cpio_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p;
int k;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL ||
(memcmp(initrd_p,"070701",6) && memcmp(initrd_p,"070702",6) && memcmp(initrd_p,"070707",6)))
return ret;
DBG(" * cpio ");
DBG(kernel);
DBG("\n");
k=strlen((unsigned char*)kernel);
// hpodc archive
while(!memcmp(ptr,"070707",6)){
int ns=oct2bin(ptr+8*6+11,6);
int fs=oct2bin(ptr+8*6+11+6,11);
if(!memcmp(ptr+9*6+2*11,kernel,k+1)){
ret.size=fs;
ret.ptr=(uint8_t*)(ptr+9*6+2*11+ns);
return ret;
}
ptr+=(76+ns+fs);
}
// newc and crc archive
while(!memcmp(ptr,"07070",5)){
int fs=hex2bin(ptr+8*6+6,8);
int ns=hex2bin(ptr+8*11+6,8);
if(!memcmp(ptr+110,kernel,k+1)){
ret.size=fs;
ret.ptr=(uint8_t*)(ptr+((110+ns+3)/4)*4);
return ret;
}
ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4;
}
return ret;
}
/**
* ustar tarball archive
*/
file_t tar_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p;
int k;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL || memcmp(initrd_p+257,"ustar",5))
return ret;
DBG(" * tar ");
DBG(kernel);
DBG("\n");
k=strlen((unsigned char*)kernel);
while(!memcmp(ptr+257,"ustar",5)){
int fs=oct2bin(ptr+0x7c,11);
if(!memcmp(ptr,kernel,k+1)){
ret.size=fs;
ret.ptr=(uint8_t*)(ptr+512);
return ret;
}
ptr+=(((fs+511)/512)+1)*512;
}
return ret;
}
/**
* Simple File System
*/
file_t sfs_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr, *end;
int k,bs,ver;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL || (memcmp(initrd_p+0x1AC,"SFS",3) && memcmp(initrd_p+0x1A6,"SFS",3)))
return ret;
// 1.0 Brendan's version, 1.10 BenLunt's version
ver=!memcmp(initrd_p+0x1A6,"SFS",3)?10:0;
bs=1<<(7+(uint8_t)initrd_p[ver?0x1B6:0x1BC]);
end=initrd_p + *((uint64_t *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize
// get index area
ptr=end - *((uint64_t *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area
// got a Starting Marker Entry?
if(ptr[0]!=2)
return ret;
DBG(" * SFS 1.");
DBG(ver?"10":"0");
DBG(kernel);
DBG("\n");
k=strlen((unsigned char*)kernel);
// iterate on index until we reach the end or Volume Identifier
while(ptr<end && ptr[0]!=0x01){
ptr+=64;
// file entry?
if(ptr[0]!=0x12)
continue;
// filename match?
if(!memcmp(ptr+(ver?0x23:0x22),kernel,k+1)){
ret.size=*((uint64_t*)&ptr[ver?0x1B:0x1A]); // file_length
ret.ptr=initrd_p + *((uint64_t*)&ptr[ver?0x0B:0x0A]) * bs; // base + start_block * blocksize
break;
}
}
return ret;
}
/**
* James Molloy's initrd (for some reason it's popular among hobby OS developers)
* http://www.jamesmolloy.co.uk/tutorial_html
*/
file_t jamesm_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p+4;
int i,k,nf=*((int*)initrd_p);
file_t ret = { NULL, 0 };
// no real magic, so we assume initrd contains at least 2 files...
if(initrd_p==NULL || kernel==NULL || initrd_p[2]!=0 || initrd_p[3]!=0 || initrd_p[4]!=0xBF || initrd_p[77]!=0xBF)
return ret;
DBG(" * JamesM ");
DBG(kernel);
DBG("\n");
k=strlen((unsigned char*)kernel);
for(i=0;i<nf && ptr[0]==0xBF;i++) {
if(!memcmp(ptr+1,kernel,k+1)){
ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
ret.size=*((uint32_t*)(ptr+69));
}
ptr+=73;
}
return ret;
}
/**
* Static file system drivers registry
*/
file_t (*fsdrivers[]) (unsigned char *, char *) = {
#ifdef _FS_Z_H_
fsz_initrd,
#endif
cpio_initrd,
tar_initrd,
sfs_initrd,
jamesm_initrd,
NULL
};

36
aarch64-rpi/link.ld Normal file
View file

@ -0,0 +1,36 @@
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
d = ALIGN(16);
/* place these manually, gcc would otherwise waste lots of memory */
. = ALIGN(4096);
__bootboot = .;
. += 4096;
__environment = .;
. += 4096;
__paging = .;
. += (23*4096);
__corestack = .;
. += 4096;
__bss_end = .;
}
_end = .;
/DISCARD/ :
{
*(.comment)
*(.gnu*)
*(.note*)
*(.eh_frame*)
}
}
__bss_size = (__bss_end - __bss_start)>>3;

112
aarch64-rpi/mkboot.c Normal file
View file

@ -0,0 +1,112 @@
/*
* aarch64-rpi/mkboot.c
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief Little tool to create a RPi compatible MBR for ESP
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
/* entry point */
int main(int argc, char** argv)
{
// variables
unsigned char data[65536];
unsigned int np,sp,i,es,ee;
int f;
// check arguments
if(argc < 2) {
printf( "BOOTBOOT mkboot utility - bztsrc@gitlab\n\nUsage:\n"
" ./mkboot <disk>\n\n"
"Maps GPT EFI System Partition into MBR so that Raspberry Pi 3\n"
"firmware can find it's files and boot from it.\n"
"Examples:\n"
" ./mkboot diskimage.dd - modify a disk image file\n"
" ./mkboot /dev/sda - modify a real disk\n");
return 1;
}
// open file
f = open(argv[1], O_RDONLY);
if(f < 0) {
fprintf(stderr, "mkboot: file not found\n");
return 2;
}
// read the partitioning tables
if(read(f, data, 65536)==-1) {
close(f);
fprintf(stderr, "mkboot: unable to read file\n");
return 2;
}
close(f);
if(memcmp((void*)&data[512], "EFI PART", 8)) {
fprintf(stderr, "mkboot: GPT partitioning table not found\n");
return 2;
}
// get number of partitions and size of partition entry
np=*((unsigned int*)&data[512+80]); sp=*((unsigned int*)&data[512+84]);
i=*((unsigned int*)&data[512+72])*512; es=ee=0;
// get esp start and esp end sectors
while(np--) {
if(*((unsigned int*)&data[i])==0xC12A7328 && *((unsigned int*)&data[i+4])==0x11D2F81F) {
es=*((unsigned int*)&data[i+32]); ee=*((unsigned int*)&data[i+40]); break;
}
i+=sp;
}
if(es==0 || ee==0 || ee<es+1) {
fprintf(stderr, "mkboot: ESP not found in GPT\n");
return 2;
}
// if first MBR partition is not a FAT, make space for it
if(data[0x1C2]!=0xC/*FAT32 LBA*/ && data[0x1C2]!=0xE/*FAT16 LBA*/) {
memcpy(&data+0x1EE, &data+0x1DE, 16);
memcpy(&data+0x1DE, &data+0x1CE, 16);
memcpy(&data+0x1CE, &data+0x1BE, 16);
data[0x1C2]=0xC;
}
// check if it's already pointing to ESP
ee-=sp-1;
if(*((unsigned int*)&data[0x1C6])==es && *((unsigned int*)&data[0x1CA])==ee) {
fprintf(stderr, "mkboot: ESP already mapped to MBR, nothing to do\n");
return 0;
}
*((unsigned int*)&data[0x1C6])=es;
*((unsigned int*)&data[0x1CA])=ee;
// save boot record
f = open(argv[1], O_WRONLY);
if(f < 0 || write(f, data, 512) <= 0) {
fprintf(stderr, "mkboot: unable to write MBR\n");
return 3;
}
close(f);
// all went well
printf("mkboot: GPT ESP mapped to MBR successfully\n");
}

379
aarch64-rpi/raspbootcom.c Normal file
View file

@ -0,0 +1,379 @@
/* raspbootcom.c - upload INITRD via serial port to the RPi running BOOTBOOT */
/* Copyright (C) 2013 Goswin von Brederlow <goswin-v-b@web.de>
* minor modifications for BOOTBOOT: 2017 bzt (bztsrc@gitlab)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include <stdint.h>
#include <termios.h>
#include "../bootboot.h"
#define BUF_SIZE 65536
struct termios old_tio, new_tio;
void do_exit(int fd, int res) {
// close FD
if (fd != -1) close(fd);
// restore settings for STDIN_FILENO
if (isatty(STDIN_FILENO)) {
tcsetattr(STDIN_FILENO,TCSANOW,&old_tio);
}
exit(res);
}
// open serial connection
int open_serial(const char *dev) {
// The termios structure, to be configured for serial interface.
struct termios termios;
// Open the device, read/write, not the controlling tty, and non-blocking I/O
int fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
// failed to open
return -1;
}
// must be a tty
if (!isatty(fd)) {
fprintf(stderr, "%s is not a tty\n", dev);
do_exit(fd, EXIT_FAILURE);
}
// Get the attributes.
if(tcgetattr(fd, &termios) == -1)
{
perror("Failed to get attributes of device");
do_exit(fd, EXIT_FAILURE);
}
// So, we poll.
termios.c_cc[VTIME] = 0;
termios.c_cc[VMIN] = 0;
// 8N1 mode, no input/output/line processing masks.
termios.c_iflag = 0;
termios.c_oflag = 0;
termios.c_cflag = CS8 | CREAD | CLOCAL;
termios.c_lflag = 0;
// Set the baud rate.
if((cfsetispeed(&termios, B115200) < 0) ||
(cfsetospeed(&termios, B115200) < 0))
{
perror("Failed to set baud-rate");
do_exit(fd, EXIT_FAILURE);
}
// Write the attributes.
if (tcsetattr(fd, TCSAFLUSH, &termios) == -1) {
perror("tcsetattr()");
do_exit(fd, EXIT_FAILURE);
}
return fd;
}
// send initrd to rpi
void send_initrd(int fd, const char *file) {
int file_fd;
off_t off;
uint32_t size;
ssize_t pos, total=0;
char *p;
int done = 0;
// Set fd blocking
if (fcntl(fd, F_SETFL, 0) == -1) {
perror("fcntl()");
do_exit(fd, EXIT_FAILURE);
}
// Open file. If not found, simply continue with terminal
if (file==NULL || file[0]==0 || (file_fd = open(file, O_RDONLY)) == -1) {
return;
}
// Get initrd size
off = lseek(file_fd, 0L, SEEK_END);
if (off >= INITRD_MAXSIZE*1024*1024) {
fprintf(stderr, "initrd too big\n");
close(file_fd);
return;
}
// empty file
if (off == 0) {
close(file_fd);
return;
}
size = htole32(off);
lseek(file_fd, 0L, SEEK_SET);
fprintf(stderr, "### sending initrd %s [%zu byte]\n", file, (size_t)off);
// send initrd size to RPi
p = (char*)&size;
pos = 0;
while(pos < 4) {
ssize_t len = write(fd, &p[pos], 4 - pos);
if (len == -1) {
perror("write()");
do_exit(fd, EXIT_FAILURE);
}
pos += len;
}
// wait for OK
char ok_buf[2];
p = ok_buf;
pos = 0;
while(pos < 2) {
ssize_t len = read(fd, &p[pos], 2 - pos);
if (len == -1) {
perror("read()");
do_exit(fd, EXIT_FAILURE);
}
pos += len;
}
if (ok_buf[0] != 'O' || ok_buf[1] != 'K') {
fprintf(stderr, "error after sending size\n");
close(file_fd);
return;
}
while(!done) {
char buf[BUF_SIZE];
ssize_t pos = 0;
ssize_t len = read(file_fd, buf, BUF_SIZE);
switch(len) {
case -1:
perror("read()");
close(file_fd);
return;
case 0:
done = 1;
}
while(len > 0) {
ssize_t len2 = write(fd, &buf[pos], len);
if (len2 == -1) {
perror("write()");
do_exit(fd, EXIT_FAILURE);
}
len -= len2;
pos += len2;
total += len2;
fprintf(stderr,"%3d%% %d / %d\r",total*100/off, total, off);
}
}
close(file_fd);
// Set fd non-blocking
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl()");
do_exit(fd, EXIT_FAILURE);
}
fprintf(stderr, "### finished sending\n");
return;
}
int main(int argc, char *argv[]) {
int fd, max_fd = STDIN_FILENO;
fd_set rfds, wfds, efds;
char buf[BUF_SIZE];
size_t start = 0;
size_t end = 0;
int done = 0, leave = 0;
int breaks = 0;
printf("Raspbootcom V1.0 - BOOTBOOT version\n\n");
if (argc < 2) {
printf("USAGE: %s <dev> [file]\n", argv[0]);
printf("Example: %s /dev/ttyUSB0 BOOTBOOT/INITRD\n", argv[0]);
exit(EXIT_FAILURE);
}
// Set STDIN non-blocking and unbuffered
if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl()");
exit(EXIT_FAILURE);
}
if (isatty(STDIN_FILENO)) {
// get the terminal settings for stdin
if (tcgetattr(STDIN_FILENO, &old_tio) == -1) {
perror("tcgetattr");
exit(EXIT_FAILURE);
}
// we want to keep the old setting to restore them a the end
new_tio=old_tio;
// disable canonical mode (buffered i/o) and local echo
new_tio.c_lflag &= (~ICANON & ~ECHO);
// set the new settings immediately
if (tcsetattr(STDIN_FILENO, TCSANOW, &new_tio) == -1) {
perror("tcsetattr()");
do_exit(-1, EXIT_FAILURE);
}
}
while(!leave) {
// Open device
if ((fd = open_serial(argv[1])) == -1) {
// udev takes a while to change ownership
// so sometimes one gets EPERM
if (errno == ENOENT || errno == ENODEV || errno == EACCES) {
fprintf(stderr, "\r### Waiting for %s...\r", argv[1]);
sleep(1);
continue;
}
perror(argv[1]);
do_exit(fd, EXIT_FAILURE);
}
fprintf(stderr, "### Listening on %s \n", argv[1]);
// select needs the largeds FD + 1
if (fd > STDIN_FILENO) {
max_fd = fd + 1;
} else {
max_fd = STDIN_FILENO + 1;
}
done = 0;
start = end = 0;
while(!done || start != end) {
// Watch stdin and dev for input.
FD_ZERO(&rfds);
if (!done && end < BUF_SIZE) FD_SET(STDIN_FILENO, &rfds);
FD_SET(fd, &rfds);
// Watch fd for output if needed.
FD_ZERO(&wfds);
if (start != end) FD_SET(fd, &wfds);
// Watch stdin and dev for error.
FD_ZERO(&efds);
FD_SET(STDIN_FILENO, &efds);
FD_SET(fd, &efds);
// Wait for something to happend
if (select(max_fd, &rfds, &wfds, &efds, NULL) == -1) {
perror("select()");
do_exit(fd, EXIT_FAILURE);
} else {
// check for errors
if (FD_ISSET(STDIN_FILENO, &efds)) {
fprintf(stderr, "error on STDIN\n");
do_exit(fd, EXIT_FAILURE);
}
if (FD_ISSET(fd, &efds)) {
fprintf(stderr, "error on device\n");
do_exit(fd, EXIT_FAILURE);
}
// RPi is ready to recieve more data, send more
if (FD_ISSET(fd, &wfds)) {
ssize_t len = write(fd, &buf[start], end - start);
if (len == -1) {
perror("write()");
do_exit(fd, EXIT_FAILURE);
}
start += len;
if (start == end) start = end = 0;
// shift buffer contents
if (end == BUF_SIZE) {
memmove(buf, &buf[start], end - start);
end -= start;
start = 0;
}
}
// input from the user, copy to RPi
if (FD_ISSET(STDIN_FILENO, &rfds)) {
ssize_t len = read(STDIN_FILENO, &buf[end], BUF_SIZE - end);
switch(len) {
case -1:
perror("read()");
do_exit(fd, EXIT_FAILURE);
case 0:
done = 1;
leave = 1;
}
end += len;
}
// output from the RPi, copy to STDOUT
if (FD_ISSET(fd, &rfds)) {
char buf2[BUF_SIZE];
ssize_t len = read(fd, buf2, BUF_SIZE);
switch(len) {
case -1:
perror("read()");
do_exit(fd, EXIT_FAILURE);
case 0:
done = 1;
}
// scan output for tripple break (^C^C^C)
// send initrd on tripple break, otherwise output text
const char *p = buf2;
while(p < &buf2[len]) {
const char *q = index(p, '\x03');
if (q == NULL) q = &buf2[len];
if (p == q) {
++breaks;
++p;
if (breaks == 3) {
if (start != end) {
fprintf(stderr, "Discarding input after tripple break\n");
start = end = 0;
}
if(argv[2]!=NULL)
send_initrd(fd, argv[2]);
breaks = 0;
}
} else {
while (breaks > 0) {
ssize_t len2 = write(STDOUT_FILENO, "\x03\x03\x03", breaks);
if (len2 == -1) {
perror("write()");
do_exit(fd, EXIT_FAILURE);
}
breaks -= len2;
}
while(p < q) {
ssize_t len2 = write(STDOUT_FILENO, p, q - p);
if (len2 == -1) {
perror("write()");
do_exit(fd, EXIT_FAILURE);
}
p += len2;
}
}
}
}
}
}
close(fd);
}
do_exit(-1, EXIT_SUCCESS);
}

120
aarch64-rpi/tinf.h Normal file
View file

@ -0,0 +1,120 @@
/*
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
*
* Copyright (c) 2003 by Joergen Ibsen / Jibz
* All Rights Reserved
* http://www.ibsensoftware.com/
*
* Copyright (c) 2014-2016 by Paul Sokolovsky
*/
#ifndef TINF_H_INCLUDED
#define TINF_H_INCLUDED
/* we don't have stdint.h */
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
/* calling convention */
#ifndef TINFCC
#ifdef __WATCOMC__
#define TINFCC __cdecl
#else
#define TINFCC
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* ok status, more data produced */
#define TINF_OK 0
/* end of compressed stream reached */
#define TINF_DONE 1
#define TINF_DATA_ERROR (-3)
#define TINF_CHKSUM_ERROR (-4)
#define TINF_DICT_ERROR (-5)
/* checksum types */
#define TINF_CHKSUM_NONE 0
#define TINF_CHKSUM_ADLER 1
#define TINF_CHKSUM_CRC 2
/* data structures */
typedef struct {
unsigned int table[16]; /* table of code length counts */
unsigned int trans[288]; /* code -> symbol translation table */
} TINF_TREE;
struct TINF_DATA;
typedef struct TINF_DATA {
TINF_TREE ltree; /* dynamic length/symbol tree */
TINF_TREE dtree; /* dynamic distance tree */
const unsigned char *source;
/* If source above is NULL, this function will be used to read
next byte from source stream */
unsigned char (*readSource)(volatile struct TINF_DATA *data);
unsigned int tag;
unsigned int bitcount;
/* Buffer start */
unsigned char *destStart;
/* Buffer total size */
unsigned int destSize;
/* Current pointer in buffer */
unsigned char *dest;
/* Remaining bytes in buffer */
unsigned int destRemaining;
/* Accumulating checksum */
unsigned int checksum;
unsigned int checksum_type;
int btype;
int bfinal;
unsigned int curlen;
int lzOff;
} TINF_DATA;
#define TINF_PUT(d, c) \
{ \
*d->dest++ = c; \
}
unsigned char TINFCC uzlib_get_byte(volatile TINF_DATA *d);
/* Decompression API */
void TINFCC uzlib_init(void);
void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);
int TINFCC uzlib_uncompress(volatile TINF_DATA *d);
int TINFCC uzlib_uncompress_chksum(TINF_DATA *d);
int TINFCC uzlib_zlib_parse_header(TINF_DATA *d);
int TINFCC uzlib_gzip_parse_header(TINF_DATA *d);
/* Compression API */
void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen);
/* Checksum API */
/* prev_sum is previous value for incremental computation, 1 initially */
uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
/* crc is previous value for incremental computation, 0xffffffff initially */
uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* TINF_H_INCLUDED */

475
aarch64-rpi/tinflate.c Normal file
View file

@ -0,0 +1,475 @@
/*
* tinflate - tiny inflate
*
* Copyright (c) 2003 by Joergen Ibsen / Jibz
* All Rights Reserved
* http://www.ibsensoftware.com/
*
* Copyright (c) 2014-2016 by Paul Sokolovsky
*
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software
* for any purpose, including commercial applications,
* and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be
* misrepresented; you must not claim that you
* wrote the original software. If you use this
* software in a product, an acknowledgment in
* the product documentation would be appreciated
* but is not required.
*
* 2. Altered source versions must be plainly marked
* as such, and must not be misrepresented as
* being the original software.
*
* 3. This notice may not be removed or altered from
* any source distribution.
*/
#include "tinf.h"
uint32_t tinf_get_le_uint32(TINF_DATA *d);
uint32_t tinf_get_be_uint32(TINF_DATA *d);
/* --------------------------------------------------- *
* -- uninitialized global data (static structures) -- *
* --------------------------------------------------- */
#ifdef RUNTIME_BITS_TABLES
/* extra bits and base tables for length codes */
unsigned char length_bits[30];
unsigned short length_base[30];
/* extra bits and base tables for distance codes */
unsigned char dist_bits[30];
unsigned short dist_base[30];
#else
const unsigned char length_bits[30] = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4,
5, 5, 5, 5
};
const unsigned short length_base[30] = {
3, 4, 5, 6, 7, 8, 9, 10,
11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115,
131, 163, 195, 227, 258
};
const unsigned char dist_bits[30] = {
0, 0, 0, 0, 1, 1, 2, 2,
3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10,
11, 11, 12, 12, 13, 13
};
const unsigned short dist_base[30] = {
1, 2, 3, 4, 5, 7, 9, 13,
17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073,
4097, 6145, 8193, 12289, 16385, 24577
};
#endif
/* special ordering of code length codes */
const unsigned char clcidx[] = {
16, 17, 18, 0, 8, 7, 9, 6,
10, 5, 11, 4, 12, 3, 13, 2,
14, 1, 15
};
/* ----------------------- *
* -- utility functions -- *
* ----------------------- */
#ifdef RUNTIME_BITS_TABLES
/* build extra bits and base tables */
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
{
int i, sum;
/* build bits table */
for (i = 0; i < delta; ++i) bits[i] = 0;
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
/* build base table */
for (sum = first, i = 0; i < 30; ++i)
{
base[i] = sum;
sum += 1 << bits[i];
}
}
#endif
/* build the fixed huffman trees */
static void tinf_build_fixed_trees(volatile TINF_TREE *lt, volatile TINF_TREE *dt)
{
int i;
/* build fixed length tree */
for (i = 0; i < 7; ++i) lt->table[i] = 0;
lt->table[7] = 24;
lt->table[8] = 152;
lt->table[9] = 112;
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
/* build fixed distance tree */
for (i = 0; i < 5; ++i) dt->table[i] = 0;
dt->table[5] = 32;
for (i = 0; i < 32; ++i) dt->trans[i] = i;
}
/* given an array of code lengths, build a tree */
static void tinf_build_tree(volatile TINF_TREE *t, const unsigned char *lengths, unsigned int num)
{
unsigned short offs[16];
unsigned int i, sum;
/* clear code length count table */
for (i = 0; i < 16; ++i) t->table[i] = 0;
/* scan symbol lengths, and sum code length counts */
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
t->table[0] = 0;
/* compute offset table for distribution sort */
for (sum = 0, i = 0; i < 16; ++i)
{
offs[i] = sum;
sum += t->table[i];
}
/* create code->symbol translation table (symbols sorted by code) */
for (i = 0; i < num; ++i)
{
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
}
}
/* ---------------------- *
* -- decode functions -- *
* ---------------------- */
unsigned char uzlib_get_byte(volatile TINF_DATA *d)
{
if (d->source) {
return *d->source++;
}
return d->readSource(d);
}
uint32_t tinf_get_le_uint32(TINF_DATA *d)
{
uint32_t val = 0;
int i;
for (i = 4; i--;) {
val = val >> 8 | uzlib_get_byte(d) << 24;
}
return val;
}
uint32_t tinf_get_be_uint32(TINF_DATA *d)
{
uint32_t val = 0;
int i;
for (i = 4; i--;) {
val = val << 8 | uzlib_get_byte(d);
}
return val;
}
/* get one bit from source stream */
static int tinf_getbit(volatile TINF_DATA *d)
{
unsigned int bit;
/* check if tag is empty */
if (!d->bitcount--)
{
/* load next tag */
d->tag = uzlib_get_byte(d);
d->bitcount = 7;
}
/* shift bit out of tag */
bit = d->tag & 0x01;
d->tag >>= 1;
return bit;
}
/* read a num bit value from a stream and add base */
static unsigned int tinf_read_bits(volatile TINF_DATA *d, int num, int base)
{
unsigned int val = 0;
/* read num bits */
if (num)
{
unsigned int limit = 1 << (num);
unsigned int mask;
for (mask = 1; mask < limit; mask *= 2)
if (tinf_getbit(d)) val += mask;
}
return val + base;
}
/* given a data stream and a tree, decode a symbol */
static int tinf_decode_symbol(volatile TINF_DATA *d, volatile TINF_TREE *t)
{
int sum = 0, cur = 0, len = 0;
/* get more bits while code value is above sum */
do {
cur = 2*cur + tinf_getbit(d);
++len;
sum += t->table[len];
cur -= t->table[len];
} while (cur >= 0);
return t->trans[sum + cur];
}
/* given a data stream, decode dynamic trees from it */
static void tinf_decode_trees(volatile TINF_DATA *d, volatile TINF_TREE *lt, volatile TINF_TREE *dt)
{
unsigned char lengths[288+32];
unsigned int hlit, hdist, hclen;
unsigned int i, num, length;
/* get 5 bits HLIT (257-286) */
hlit = tinf_read_bits(d, 5, 257);
/* get 5 bits HDIST (1-32) */
hdist = tinf_read_bits(d, 5, 1);
/* get 4 bits HCLEN (4-19) */
hclen = tinf_read_bits(d, 4, 4);
for (i = 0; i < 19; ++i) lengths[i] = 0;
/* read code lengths for code length alphabet */
for (i = 0; i < hclen; ++i)
{
/* get 3 bits code length (0-7) */
unsigned int clen = tinf_read_bits(d, 3, 0);
lengths[clcidx[i]] = clen;
}
/* build code length tree, temporarily use length tree */
tinf_build_tree(lt, lengths, 19);
/* decode code lengths for the dynamic trees */
for (num = 0; num < hlit + hdist; )
{
int sym = tinf_decode_symbol(d, lt);
switch (sym)
{
case 16:
/* copy previous code length 3-6 times (read 2 bits) */
{
unsigned char prev = lengths[num - 1];
for (length = tinf_read_bits(d, 2, 3); length; --length)
{
lengths[num++] = prev;
}
}
break;
case 17:
/* repeat code length 0 for 3-10 times (read 3 bits) */
for (length = tinf_read_bits(d, 3, 3); length; --length)
{
lengths[num++] = 0;
}
break;
case 18:
/* repeat code length 0 for 11-138 times (read 7 bits) */
for (length = tinf_read_bits(d, 7, 11); length; --length)
{
lengths[num++] = 0;
}
break;
default:
/* values 0-15 represent the actual code lengths */
lengths[num++] = sym;
break;
}
}
/* build dynamic trees */
tinf_build_tree(lt, lengths, hlit);
tinf_build_tree(dt, lengths + hlit, hdist);
}
/* ----------------------------- *
* -- block inflate functions -- *
* ----------------------------- */
/* given a stream and two trees, inflate a block of data */
static int tinf_inflate_block_data(volatile TINF_DATA *d, volatile TINF_TREE *lt, volatile TINF_TREE *dt)
{
if (d->curlen == 0) {
unsigned int offs;
int dist;
int sym = tinf_decode_symbol(d, lt);
//printf("huff sym: %02x\n", sym);
/* literal byte */
if (sym < 256) {
TINF_PUT(d, sym);
return TINF_OK;
}
/* end of block */
if (sym == 256) {
return TINF_DONE;
}
/* substring from sliding dictionary */
sym -= 257;
/* possibly get more bits from length code */
d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);
dist = tinf_decode_symbol(d, dt);
/* possibly get more bits from distance code */
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
d->lzOff = -offs;
}
/* copy next byte from dict substring */
d->dest[0] = d->dest[d->lzOff];
d->dest++;
d->curlen--;
return TINF_OK;
}
/* inflate an uncompressed block of data */
static int tinf_inflate_uncompressed_block(volatile TINF_DATA *d)
{
if (d->curlen == 0) {
unsigned int length, invlength;
/* get length */
length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
/* get one's complement of length */
invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
/* check length */
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
/* increment length to properly return TINF_DONE below, without
producing data at the same time */
d->curlen = length + 1;
/* make sure we start next block on a byte boundary */
d->bitcount = 0;
}
if (--d->curlen == 0) {
return TINF_DONE;
}
unsigned char c = uzlib_get_byte(d);
TINF_PUT(d, c);
return TINF_OK;
}
/* ---------------------- *
* -- public functions -- *
* ---------------------- */
/* initialize global (static) data */
void uzlib_init(void)
{
#ifdef RUNTIME_BITS_TABLES
/* build extra bits and base tables */
tinf_build_bits_base(length_bits, length_base, 4, 3);
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
/* fix a special case */
length_bits[28] = 0;
length_base[28] = 258;
#endif
}
/* inflate next byte of compressed stream */
int uzlib_uncompress(volatile TINF_DATA *d)
{
do {
int res;
/* start a new block */
if (d->btype == -1) {
next_blk:
/* read final block flag */
d->bfinal = tinf_getbit(d);
/* read block type (2 bits) */
d->btype = tinf_read_bits(d, 2, 0);
//printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal);
if (d->btype == 1) {
/* build fixed huffman trees */
tinf_build_fixed_trees(&d->ltree, &d->dtree);
} else if (d->btype == 2) {
/* decode trees from stream */
tinf_decode_trees(d, &d->ltree, &d->dtree);
}
}
/* process current block */
switch (d->btype)
{
case 0:
/* decompress uncompressed block */
res = tinf_inflate_uncompressed_block(d);
break;
case 1:
case 2:
/* decompress block with fixed/dyanamic huffman trees */
/* trees were decoded previously, so it's the same routine for both */
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
break;
default:
return TINF_DATA_ERROR;
}
if (res == TINF_DONE && !d->bfinal) {
/* the block has ended (without producing more data), but we
can't return without data, so start procesing next block */
goto next_blk;
}
if (res != TINF_OK) {
return res;
}
} while (--d->destSize);
return TINF_OK;
}

BIN
boot.bin Normal file

Binary file not shown.

BIN
bootboot.bin Normal file

Binary file not shown.

BIN
bootboot.efi Executable file

Binary file not shown.

142
bootboot.h Normal file
View file

@ -0,0 +1,142 @@
/*
* bootboot.h
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief The BOOTBOOT structure
*
*/
#ifndef _BOOTBOOT_H_
#define _BOOTBOOT_H_
#ifdef __cplusplus
extern "C" {
#endif
#define BOOTBOOT_MAGIC "BOOT"
// minimum protocol level:
// hardcoded kernel name, static kernel memory addresses
#define PROTOCOL_MINIMAL 0
// static protocol level:
// kernel name parsed from environment, static kernel memory addresses
#define PROTOCOL_STATIC 1
// dynamic protocol level:
// kernel name parsed, kernel memory addresses from ELF or PE symbols
#define PROTOCOL_DYNAMIC 2
// big-endian flag
#define PROTOCOL_BIGENDIAN 0x80
// loader types, just informational
#define LOADER_BIOS 0
#define LOADER_UEFI 1
#define LOADER_RPI 2
// framebuffer pixel format, only 32 bits supported
#define FB_ARGB 0
#define FB_RGBA 1
#define FB_ABGR 2
#define FB_BGRA 3
// mmap entry, type is stored in least significant tetrad (half byte) of size
// this means size described in 16 byte units (not a problem, most modern
// firmware report memory in pages, 4096 byte units anyway).
typedef struct {
uint64_t ptr;
uint64_t size;
} __attribute__((packed)) MMapEnt;
#define MMapEnt_Ptr(a) (a->ptr)
#define MMapEnt_Size(a) (a->size & 0xFFFFFFFFFFFFFFF0)
#define MMapEnt_Type(a) (a->size & 0xF)
#define MMapEnt_IsFree(a) ((a->size&0xF)==1||(a->size&0xF)==2)
#define MMAP_USED 0 // don't use. Reserved or unknown regions
#define MMAP_FREE 1 // usable memory
#define MMAP_ACPIFREE 2 // free to use after acpi tables are parsed
#define MMAP_ACPINVS 3 // don't use. Acpi non-volatile
#define MMAP_MMIO 4 // memory mapped IO region
#define INITRD_MAXSIZE 16 //Mb
typedef struct {
uint8_t magic[4]; // 'BOOT', first 64 bytes are platform independent
uint32_t size; // length of bootboot structure, minimum 128
uint8_t protocol; // 1, static addresses, see PROTOCOL_* above
uint8_t loader_type; // see LOADER_* above
uint8_t pagesize; // in power of two, 12 = 4096
uint8_t fb_type; // framebuffer type, see FB_* above
int16_t timezone; // in minutes -1440..1440
uint16_t bspid; // Bootsrap processor ID (Local APIC Id on x86_64)
uint8_t datetime[8]; // in BCD yyyymmddhhiiss UTC (independent to timezone)
uint64_t initrd_ptr; // ramdisk image position and size
uint64_t initrd_size;
uint8_t *fb_ptr; // framebuffer pointer and dimensions
uint32_t fb_size;
uint32_t fb_width;
uint32_t fb_height;
uint32_t fb_scanline;
// the rest (64 bytes) is platform specific
union {
struct {
uint64_t acpi_ptr;
uint64_t smbi_ptr;
uint64_t efi_ptr;
uint64_t mp_ptr;
uint64_t unused0;
uint64_t unused1;
uint64_t unused2;
uint64_t unused3;
} x86_64;
struct {
uint64_t acpi_ptr;
uint64_t mmio_ptr;
uint64_t unused0;
uint64_t unused1;
uint64_t unused2;
uint64_t unused3;
uint64_t unused4;
uint64_t unused5;
} aarch64;
};
/* from 128th byte, MMapEnt[], more records may follow */
MMapEnt mmap;
/* use like this:
* MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++;
* until you reach bootboot->size */
} __attribute__((packed)) BOOTBOOT;
#ifdef __cplusplus
}
#endif
#endif

BIN
bootboot.img Executable file

Binary file not shown.

BIN
bootboot.rom Normal file

Binary file not shown.

BIN
bootboot_spec_1st_ed.pdf Normal file

Binary file not shown.

50
mykernel/Makefile Normal file
View file

@ -0,0 +1,50 @@
#
# mykernel/Makefile
#
# Copyright (C) 2017 bzt (bztsrc@gitlab)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# This file is part of the BOOTBOOT Protocol package.
# @brief An example Makefile for sample kernel
#
#
CFLAGS = -Wall -fpic -ffreestanding -fno-stack-protector -nostdinc -nostdlib -I../
all: mykernel.x86_64.elf mykernel.aarch64.elf
mykernel.x86_64.elf: kernel.c
x86_64-elf-gcc $(CFLAGS) -mno-red-zone -c kernel.c -o kernel.o
x86_64-elf-ld -r -b binary -o font.o font.psf
x86_64-elf-ld -nostdlib -nostartfiles -T link.ld kernel.o font.o -o mykernel.x86_64.elf
x86_64-elf-strip -s -K fb -K bootboot -K environment mykernel.x86_64.elf
x86_64-elf-readelf -hls mykernel.x86_64.elf >mykernel.x86_64.txt
mykernel.aarch64.elf: kernel.c
aarch64-elf-gcc $(CFLAGS) -c kernel.c -o kernel.o
aarch64-elf-ld -r -b binary -o font.o font.psf
aarch64-elf-ld -nostdlib -nostartfiles -T link.ld kernel.o font.o -o mykernel.aarch64.elf
aarch64-elf-strip -s -K fb -K bootboot -K environment mykernel.aarch64.elf
aarch64-elf-readelf -hls mykernel.aarch64.elf >mykernel.aarch64.txt
clean:
rm *.o *.elf *.txt

BIN
mykernel/font.psf Normal file

Binary file not shown.

106
mykernel/kernel.c Normal file
View file

@ -0,0 +1,106 @@
/*
* mykernel/kernel.c
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief A sample BOOTBOOT compatible kernel
*
*/
/* function to display a string, see below */
void puts(char *s);
/* we don't assume stdint.h exists */
typedef short int int16_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#include <bootboot.h>
/* imported virtual addresses, see linker script */
extern BOOTBOOT bootboot; // see bootboot.h
extern unsigned char *environment; // configuration, UTF-8 text key=value pairs
extern uint8_t fb; // linear framebuffer mapped
/******************************************
* Entry point, called by BOOTBOOT Loader *
******************************************/
void _start()
{
int x, y, s=bootboot.fb_scanline, w=bootboot.fb_width, h=bootboot.fb_height;
// cross-hair to see screen dimension detected correctly
for(y=0;y<h;y++) { *((uint32_t*)(&fb + s*y + (w*2)))=0x00FFFFFF; }
for(x=0;x<w;x++) { *((uint32_t*)(&fb + s*(h/2)+x*4))=0x00FFFFFF; }
// red, green, blue boxes in order
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+20)*4))=0x00FF0000; } }
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+50)*4))=0x0000FF00; } }
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+80)*4))=0x000000FF; } }
// say hello
puts("Hello from a simple BOOTBOOT kernel");
// hang for now
while(1);
}
/**************************
* Display text on screen *
**************************/
typedef struct {
uint32_t magic;
uint32_t version;
uint32_t headersize;
uint32_t flags;
uint32_t numglyph;
uint32_t bytesperglyph;
uint32_t height;
uint32_t width;
uint8_t glyphs;
} __attribute__((packed)) psf2_t;
extern volatile unsigned char _binary_font_psf_start;
void puts(char *s)
{
psf2_t *font = (psf2_t*)&_binary_font_psf_start;
int x,y,kx=0,line,mask,offs;
int bpl=(font->width+7)/8;
while(*s) {
unsigned char *glyph = (unsigned char*)&_binary_font_psf_start + font->headersize +
(*s>0&&*s<font->numglyph?*s:0)*font->bytesperglyph;
offs = (kx * (font->width+1) * 4);
for(y=0;y<font->height;y++) {
line=offs; mask=1<<(font->width-1);
for(x=0;x<font->width;x++) {
*((uint32_t*)((uint64_t)&fb+line))=((int)*glyph) & (mask)?0xFFFFFF:0;
mask>>=1; line+=4;
}
*((uint32_t*)((uint64_t)&fb+line))=0; glyph+=bpl; offs+=bootboot.fb_scanline;
}
s++; kx++;
}
}

48
mykernel/link.ld Normal file
View file

@ -0,0 +1,48 @@
/*
* mykernel/link.ld
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief An example linker script for sample kernel
*
*/
mmio = 0xfffffffffa000000;
fb = 0xfffffffffc000000;
SECTIONS
{
. = 0xffffffffffe00000;
bootboot = .; . += 4096;
environment = .; . += 4096;
.text : {
KEEP(*(.text.boot)) *(.text .text.*) /* code */
*(.rodata .rodata.*) /* data */
*(.data .data.*)
}
.bss (NOLOAD) : { /* bss */
. = ALIGN(16);
*(.bss .bss.*)
*(COMMON)
}
}

BIN
mykernel/mykernel.aarch64.elf Executable file

Binary file not shown.

View file

@ -0,0 +1,42 @@
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: AArch64
Version: 0x1
Entry point address: 0xffffffffffe02000
Start of program headers: 64 (bytes into file)
Start of section headers: 3760 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 9
Section header string table index: 8
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000078 0xffffffffffe02000 0xffffffffffe02000
0x0000000000000cf0 0x0000000000000cf0 RWE 0x8
Section to Segment mapping:
Segment Sections...
00 .text .got .got.plt
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: ffffffffffe02000 0 SECTION LOCAL DEFAULT 1
2: ffffffffffe02cb8 0 SECTION LOCAL DEFAULT 2
3: ffffffffffe02cd8 0 SECTION LOCAL DEFAULT 3
4: ffffffffffe02cf0 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: ffffffffffe01000 0 NOTYPE GLOBAL DEFAULT 1 environment
7: fffffffffc000000 0 NOTYPE GLOBAL DEFAULT ABS fb
8: ffffffffffe00000 0 NOTYPE GLOBAL DEFAULT 1 bootboot

BIN
mykernel/mykernel.x86_64.elf Executable file

Binary file not shown.

View file

@ -0,0 +1,42 @@
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0xffffffffffe02000
Start of program headers: 64 (bytes into file)
Start of section headers: 3512 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 9
Section header string table index: 8
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000078 0xffffffffffe02000 0xffffffffffe02000
0x0000000000000bf0 0x0000000000000bf0 RWE 0x8
Section to Segment mapping:
Segment Sections...
00 .text .eh_frame .got.plt
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: ffffffffffe02000 0 SECTION LOCAL DEFAULT 1
2: ffffffffffe02b70 0 SECTION LOCAL DEFAULT 2
3: ffffffffffe02bd8 0 SECTION LOCAL DEFAULT 3
4: ffffffffffe02bf0 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: ffffffffffe01000 0 NOTYPE GLOBAL DEFAULT 1 environment
7: fffffffffc000000 0 NOTYPE GLOBAL DEFAULT ABS fb
8: ffffffffffe00000 0 NOTYPE GLOBAL DEFAULT 1 bootboot

BIN
mykernel/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

15
x86_64-bios/Makefile Normal file
View file

@ -0,0 +1,15 @@
all:
@# NOTE: GNU assembler cannot mix 16 bit real mode with 32 bit prot mode instructions
@# as easily as I need it in a boot loader. So I decided to use fasm.
@echo " src x86_64-bios (MultiBoot / BIOS)"
@fasm boot.asm ../boot.bin >/dev/null
@fasm bootboot.asm ../bootboot.bin >/dev/null
mkboot: ../boot.bin mkboot.c
@echo " src mkboot"
@ld -r -b binary -o boot.o ../boot.bin
@gcc boot.o mkboot.c -o mkboot
@rm boot.o 2>/dev/null || true
clean:
@rm *.o ../mbr.bin ../bootboot.bin mkboot >/dev/null 2>/dev/null || true

34
x86_64-bios/README.md Normal file
View file

@ -0,0 +1,34 @@
BOOTBOOT BIOS / Multiboot Implementation
========================================
See [BOOTBOOT Protocol](https://gitlab.com/bztsrc/bootboot) for common details.
On [BIOS](http://www.scs.stanford.edu/05au-cs240c/lab/specsbbs101.pdf) based systems, the same image can be loaded via
[Multiboot](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html),
chainload from MBR or VBR (GPT hybrid booting) or run as a BIOS Expansion ROM
(so not only the ramdisk can be in ROM, but the loader as well).
Machine state
-------------
IRQs masked. GDT unspecified, but valid, IDT unset. Code is running in supervisor mode in ring 0.
Installation
------------
1. *BIOS disk*: copy __bootboot.bin__ to **_FS0:\BOOTBOOT\LOADER_**. You can place it inside your INITRD partition
or outside of partition area as well (with `dd conv=notrunc oseek=x`). Finally install __boot.bin__ in the
master boot record (or in volume boot record if you have a boot manager), saving bootboot.bin's first sector's
LBA number in a dword at 0x1B0. The [mkboot](https://gitlab.com/bztsrc/bootboot/blob/master/x86_64-bios/mkboot.c)
utility will do that for you.
2. *BIOS ROM*: install __bootboot.bin__ in a **_BIOS Expansion ROM_**.
3. *GRUB*: specify __bootboot.bin__ as "kernel" in grub.cfg, or you can chainload __boot.bin__.
Limitations
-----------
- As it boots in protected mode, it only maps the first 4G of RAM.
- Compressed initrd in ROM is limited to ~96k.
- The CMOS nvram does not store timezone, so always GMT+0 returned in bootboot.timezone.

218
x86_64-bios/boot.asm Normal file
View file

@ -0,0 +1,218 @@
;*
;* x86_64-bios/boot.asm
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief 1nd stage loader, compatible with BIOS boot specification
;*
;*********************************************************************
;* Macros *
;*********************************************************************
;LBA packet fields
virtual at lba_packet
lbapacket.size: dw ?
lbapacket.count:dw ?
lbapacket.addr0:dw ?
lbapacket.addr1:dw ?
lbapacket.sect0:dw ?
lbapacket.sect1:dw ?
lbapacket.sect2:dw ?
lbapacket.sect3:dw ?
end virtual
;memory locations
ldr.header equ 800h ;position of 2nd stage loader
ldr.executor equ 804h ;ptr to init code
;Writes a message on screen.
macro print msg
{
if ~ msg eq si
push si
mov si, msg
end if
call printfunc
if ~ msg eq si
pop si
end if
}
;*********************************************************************
;* code *
;*********************************************************************
;-----------------ENTRY POINT called by BIOS--------------------
ORG 0600h
USE16
bootboot_record:
jmp short .skipid
nop
.system: db "BOOTBOOT",0
;skip BPB area so that we can use this
;boot code on a FAT volume if needed
db 05Ah-($-$$) dup 0
.skipid: ;relocate our code to offset 600h
cli
xor ax, ax
mov ss, ax
mov sp, 600h
push ax
pop es
push cs
pop ds
;find our position in memory.
call .getaddr
.getaddr: pop si
sub si, .getaddr-bootboot_record
cld
mov di, sp
;clear data area 500h-600h
sub di, 100h
mov cx, 80h
repnz stosw
;and copy ourselves to 600h
mov cx, 100h
repnz movsw
jmp 0:.start
.start: ;save boot drive code
mov byte [drive], dl
;initialize lba packet
mov byte [lbapacket.size], 16
mov byte [lbapacket.count], 58
mov byte [lbapacket.addr0+1], 08h ;to address 800h
;check for lba presistance - floppy not supported any more
;we use pendrive as removable media for a long time
cmp dl, byte 80h
jl .nolba
cmp dl, byte 84h
jae .nostage2err
.notfloppy: mov ah, byte 41h
mov bx, word 55AAh
int 13h
jc .nolba
cmp bx, word 0AA55h
jne .nolba
test cl, byte 1
jnz .lbaok
.nolba: mov si, lbanotf
jmp diefunc
.lbaok: ;try to load stage2 - it's a continous area on disk
;started at given sector with maximum size of 7400h bytes
mov si, stage2_addr
mov di, lbapacket.sect0
push di
movsw
movsw
movsw
movsw
call loadsectorfunc
;do we have a 2nd stage loader?
.chk: cmp word [ldr.header], bx
jne .nostage2
cmp byte [ldr.header+3], 0E9h
jne .nostage2
;invoke stage2 real mode code
print okay
mov ax, [ldr.executor]
add ax, ldr.executor+3
jmp ax
.nostage2: ;try to load stage2 from a RAID mirror
inc byte [drive]
cmp byte [drive], 84h
jl .lbaok
.nostage2err:
mov si, stage2notf
;fall into the diefunc code
;*********************************************************************
;* functions *
;*********************************************************************
;writes the reason, waits for a key and reboots.
diefunc:
print bootboot_record.system
print panic
call printfunc
mov si, found
call printfunc
sti
xor ax, ax
int 16h
mov al, 0FEh
out 64h, al
jmp far 0FFFFh:0 ;invoke BIOS POST routine
;loads an LBA sector
loadsectorfunc:
push bx
push si
mov ah, byte 42h
mov dl, byte [drive]
mov si, lba_packet
int 13h
pop si
pop bx
ret
;ds:si zero terminated string to write
printfunc:
lodsb
or al, al
jz .end
mov ah, byte 0Eh
mov bx, word 11
int 10h
jmp printfunc
.end: ret
;*********************************************************************
;* data area *
;*********************************************************************
panic: db "-PANIC: ",0
lbanotf: db "LBA support",0
stage2notf: db "FS0:\BOOTBOOT\LOADER",0
found: db " not found",10,13,0
okay: db "Booting LOADER...",10,13,0
drive: db 0
lba_packet: db 01B0h-($-$$) dup 0
;right before the partition table some data
stage2_addr:dd 0FFFFFFFFh,0 ;1B0h 2nd stage loader address
;this should be set by mkfs
diskid: dd 0 ;1B8h WinNT expects it here
dw 0
;1BEh first partition entry
;padding and magic
db 01FEh-($-$$) dup 0
db 55h,0AAh
bootboot_record_end:

1965
x86_64-bios/bootboot.asm Normal file

File diff suppressed because it is too large Load diff

121
x86_64-bios/bootboot.inc Normal file
View file

@ -0,0 +1,121 @@
;*
;* x86_64-bios/bootboot.inc
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief The BOOTBOOT structure
;*
; ------ !!! WARNING: MUST MATCH ../bootboot.h !!! ------
bootboot = 8000h
; this define is in the 18th line of bootboot.h
bootboot_MAGIC equ 'BOOT'
; minimum protocol level:
; hardcoded kernel name, static kernel memory addresses
PROTOCOL_MINIMAL equ 0
; static protocol level:
; kernel name parsed from environment, static kernel memory addresses
PROTOCOL_STATIC equ 1
; dynamic protocol level:
; kernel name parsed from environment, kernel memory addresses parsed from ELF symbols
PROTOCOL_DYNAMIC equ 2
; big-endian flag
PROTOCOL_BIGENDIAN equ 080h
; loader types, just informational
LOADER_BIOS equ 0
LOADER_UEFI equ 1
LOADER_RPI equ 2
; framebuffer pixel format, only 32 bits supported
FB_ARGB equ 0
FB_RGBA equ 1
FB_ABGR equ 2
FB_BGRA equ 3
; mmap entry, type is stored in least significant tetrad of size
virtual at 0
mmap_ent.ptr: dq 0
mmap_ent.size: dq 0
end virtual
; we don't have entry field macros for asm
; realsize = size & 0xFFFFFFFFFFF0
; type = size & 0xF
MMAP_USED equ 0
MMAP_FREE equ 1
MMAP_ACPIFREE equ 2
MMAP_ACPINVS equ 3
MMAP_MMIO equ 4
INITRD_MAXSIZE equ 16 ; Mb
virtual at bootboot
bootboot.magic: dd 0
bootboot.size: dd 0
bootboot.protocol_ver:db 1
bootboot.loader_type: db 0
bootboot.pagesize: db 0
bootboot.fb_type: db 0
bootboot.timezone: dw 0
bootboot.bspid: dw 0
bootboot.datetime: dq 0
bootboot.initrd_ptr: dq 0
bootboot.initrd_size: dq 0
bootboot.fb_ptr: dq 0
bootboot.fb_size: dd 0
bootboot.fb_width: dd 0
bootboot.fb_height: dd 0
bootboot.fb_scanline: dd 0
; architecture specific pointers
bootboot.acpi_ptr: dq 0
bootboot.smbi_ptr: dq 0
bootboot.efi_ptr: dq 0
bootboot.mp_ptr: dq 0
bootboot.unused: dq 0,0,0,0
bootboot.mmap:
end virtual

502
x86_64-bios/fs.inc Normal file
View file

@ -0,0 +1,502 @@
;*
;* x86_64-bios/fs.inc
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief Filesystem drivers for initial ramdisk.
;*
FSZ_SUPPORT equ 1
;*********************************************************************
;* File System Drivers *
;*********************************************************************
USE32
fsdrivers:
if FSZ_SUPPORT eq 1
dw fsz_initrd
end if
dw cpio_initrd
dw tar_initrd
dw sfs_initrd
dw jamesm_initrd
dw 0
if FSZ_SUPPORT eq 1
; ----------- FS/Z ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
fsz_initrd:
mov ebx, ecx
xor ecx, ecx
; FS/Z superblock
; get root dir inode
mov eax, dword [esi+560] ; FSZ_SuperBlock.rootdirfid
shl eax, 12
add esi, eax
cmp dword [esi], 'FSIN'
je @f
.nolib: mov esi, nolib
.err: xor ecx, ecx
ret
.nocore: mov esi, nocore
jmp .err
@@: ; it has inlined data?
.again: add esi, 1024 ; FSZ_Inode.inlinedata
cmp dword [esi], 'FSDR'
je .srchdir
; no, locate the data
mov ecx, dword [esi]
mov eax, dword [esi-1024+448] ; FSZ_Inode.sec
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSDR'
je .srchdir
; inlined sector directory or list?
shl ecx, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, ecx
cmp dword [esi], 'FSDR'
jne .nolib
.srchdir: ; find sys/
mov ecx, dword [esi+16] ; FSZ_DirEntHeader.numentries
mov eax, dword [edi]
@@: add esi, 128 ; directories than
cmp dword [esi+17], eax
je @f
dec ecx
jnz @b
jmp .nolib
; found, get it's inode
@@:
mov eax, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSIN'
jne .nolib
;this is not bullet proof
add edi, 4
cmp byte [edi+3], '/'
je .again
; it has inlined data?
add esi, 1024 ; FSZ_Inode.inlinedata
cmp dword [esi], 'FSDR'
je .srchcore
; no, locate the data
mov ecx, dword [esi]
mov eax, dword [esi-1024+448] ; FSZ_Inode.sec
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSDR'
je .srchdir
; inlined sector directory or list?
shl ecx, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, ecx
cmp dword [esi], 'FSDR'
jne .nolib
.srchcore: ; find filename
mov ecx, dword [esi+16] ; FSZ_DirEntHeader.numentries
;filename, 8 characters supported
mov eax, dword [edi]
mov edx, dword [edi+4]
@@: add esi, 128
cmp dword [esi+21], edx
jne .not
cmp dword [esi+17], eax
je @f
.not: dec ecx
jnz @b
jmp .nocore
; found, get it's inode
@@: mov eax, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSIN'
jne .nocore
; get data
mov eax, dword [esi+448] ; FSZ_Inode.sec
mov ecx, dword [esi+464] ; FSZ_Inode.size
mov bl, byte [esi+492] ; FSZ_Inode.flags
; inline
cmp bl, 0FFh ; FSZ_IN_FLAG_INLINE
jne @f
add esi, 1024
ret
; direct data block
@@: or bl, bl ; FSZ_IN_FLAG_DIRECT
je .load
; inlined sector directory or sector list
@@: cmp bl, 07Fh ; FSZ_IN_FLAG_SDINLINE
je @f
cmp bl, 080h ; FSZ_IN_FLAG_SECLIST
je @f
cmp bl, 1 ; FSZ_IN_FLAG_SD
jne .nocore
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
mov eax, dword [esi] ; first FSZ_SectorList.sec
jmp .load
@@: add esi, 1024
; sector directory at esi, file size in ecx
mov eax, dword [esi] ; first FSZ_SectorList.sec
.load: shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
ret
end if
; ----------- cpio ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
cpio_initrd:
; upper bound
mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; while(ptr.magic=='070707' && ptr<limit)
.next: cmp esi, ebx
jae .err
mov eax, '0707'
cmp dword [esi], eax ; cpio magic
jne .err
cmp word [esi+4], ax ; hpodc
je @f
cmp word [esi+4], '01' ; newc
je .newc
cmp word [esi+4], '02' ; crc
je .newc
.err: xor ecx, ecx
ret
@@: mov eax, esi ; filename len
add eax, 8*6+11
mov ecx, 6
call prot_oct2bin
mov dword [.ns], eax
mov eax, esi ; filesize
add eax, 8*6+11+6
mov ecx, 11
call prot_oct2bin
mov dword [.fs], eax
push esi ; name equals?
push edi
add esi, 9*6+2*11
mov ecx, dword [.ks]
repz cmpsb
pop edi
pop esi
jz @f
add esi, 76 ; no skip this record
add esi, dword [.ns] ; and check the next one
add esi, dword [.fs]
jmp .next
@@: add esi, 76 ; found! esi=data
add esi, dword [.ns]
mov ecx, dword [.fs] ; ecx=size
ret
.newc: mov edx, esi ; filename len
add esi, 8*11+6
mov ecx, 8
call prot_hex2bin
mov dword [.ns], eax
mov esi, edx ; filesize
add esi, 8*6+6
mov ecx, 8
call prot_hex2bin
mov dword [.fs], eax
mov esi, edx
push esi ; name equals?
push edi
add esi, 110
mov ecx, dword [.ks]
repz cmpsb
pop edi
pop esi
jz @f
mov eax, 113 ; no skip this record
add eax, dword [.ns] ; and check the next one
and al, 0FCh
add esi, eax
mov eax, dword [.fs]
add eax, 3
and al, 0FCh
add esi, eax
cmp dword [esi], '0707' ; cpio magic
jne .err
jmp .newc
@@: mov eax, 113 ; found! esi=data
add eax, dword [.ns]
and al, 0FCh
add esi, eax
mov ecx, dword [.fs] ; ecx=size
ret
.ks: dd 0
.ns: dd 0
.fs: dd 0
; ----------- tar ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
tar_initrd:
; upper bound
mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; while(ptr.magic=='ustar' && ptr<limit)
.next: cmp esi, ebx
jae .err
cmp dword [esi+257], 'usta' ; tar magic
jne .err
cmp byte [esi+261], 'r' ; tar magic
je @f
.err: xor ecx, ecx
ret
@@: mov eax, esi ; filesize
add eax, 07ch
mov ecx, 11
call prot_oct2bin
mov dword [.fs], eax
push esi ; name equals?
push edi
mov ecx, dword [.ks]
repz cmpsb
pop edi
pop esi
jz @f
add esi, 512 ; no skip this record
mov eax, dword [.fs] ; and check the next one
add eax, 511
shr eax, 9
shl eax, 9
add esi, eax
jmp .next
@@: add esi, 512 ; found! esi=data
mov ecx, dword [.fs] ; ecx=size
ret
.ks: dd 0
.fs: dd 0
; ----------- SFS ----------
; Find the kernel on Stupid File System
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
sfs_initrd:
; check magic
; 1.0, Brendan's version
mov byte [.ver], 0
cmp word [esi+01ACh], 'SF'
jne @f
cmp byte [esi+01AEh], 'S'
je .ok
; 1.1, BenLunt's version
@@: cmp word [esi+01A6h], 'SF'
jne .err
cmp byte [esi+01A8h], 'S'
jne .err
inc byte [.ver]
; upper bound
.ok: mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; get block size
xor eax, eax
inc eax
xor ecx, ecx
mov cl, byte [esi+01BCh]
cmp byte [.ver], 0
jz @f
mov cl, byte [esi+01B6h]
@@: add cl, 7
shl eax, cl
mov dword [.bs], ecx
; get index area, base + totalblocks*blocksize - indexsize
xor edx, edx
mov eax, dword [esi+01B0h] ; total number of blocks
cmp byte [.ver], 0
jz @f
mov eax, dword [esi+01AAh] ; total number of blocks
@@: mul ecx
add eax, esi
mov ebx, eax
mov edx, dword [esi+01A4h] ; size of index area
cmp byte [.ver], 0
jz @f
mov edx, dword [esi+019Eh] ; size of index area
@@: sub eax, edx
mov edx, esi
mov esi, eax
cmp byte [esi], 02h ; got Starting Marker Entry?
jne .err
; iterate on index until we reach end or Volume Identifier
.nextindex: cmp esi, ebx
jae .err
cmp byte [esi], 01h
je .err
add esi, 64
cmp byte [esi], 12h ; file entry?
jne .nextindex
push esi ; name equals?
push edi
mov ecx, dword [.ks]
add esi, 022h
add esi, dword [.ver]
repz cmpsb
pop edi
pop esi
jnz .nextindex
mov ebx, esi
mov eax, dword [esi+0Ah] ; start_block
cmp byte [.ver], 0
jz @f
mov eax, dword [esi+0Bh] ; start_block
@@: mov esi, edx
xor edx, edx
mov ecx, dword [.bs]
mul ecx ; * blocksize
add esi, eax ; base +
; found! esi=data, ecx=size
mov ecx, dword [ebx+01Ah] ; file_length
cmp byte [.ver], 0
jz @f
mov ecx, dword [ebx+01Bh] ; file_length
@@: ret
.err: xor ecx, ecx
ret
.ks: dd 0
.bs: dd 0
.ver: dd 0
; ----------- JamesMolloy's ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
jamesm_initrd:
; no real magic, so we assume initrd contains at least 2 files...
cmp word [esi+2], 0
jne .err
cmp byte [esi+4], 0BFh
jne .err
cmp byte [esi+77], 0BFh
jne .err
; upper bound
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
mov ebx, esi
; edx=*(int*)initrd_p
lodsd
mov edx, eax
; for(i=0;i<nf && ptr[0]==0xBF;i++)
@@: lodsb
cmp al, 0BFh
jne .err
push esi ; name equals?
push edi
mov ecx, dword [.ks]
repz cmpsb
pop edi
pop esi
jz @f
add esi, 72
dec dx
jnz @b
.err: xor ecx, ecx
ret
@@: mov ecx, dword [esi+68]
mov esi, dword [esi+64]
add esi, ebx
ret
.ks: dd 0

62
x86_64-bios/initrd.asm Normal file
View file

@ -0,0 +1,62 @@
;*
;* x86_64-bios/initrd.asm
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief Option ROM for initrd. mkfs utility also can do this.
;*
;* This may seem odd, but works with BIOS (up to 96k gzipped
;* initrd), and makes much more sense on EFI, where Option ROMs
;* can be 16M in size.
;*
;------------header------------
USE16
ORG 0h
rom: db 55h,0AAh ;ROM magic
db (rom_end-rom)/512 ;size in 512 blocks
.executor: xor ax, ax ;entry point
retf
.checksum: dw 0 ;checksum
.name: db "INITRD"
db 0,0
dd initrd_end-initrd, 0
db 0,0
.pnpptr: dw 0
.flags: dd 0
;------------data------------
initrd:
file "../../bin/ESP/BOOTBOOT/INITRD"
initrd_end:
;-----------padding to be multiple of 512----------
db (511-($-rom+511) mod 512) dup 0
rom_end:
;-----------BIOS checksum------------
chksum = 0
repeat $-rom
load b byte from (rom+%-1)
chksum = (chksum + b) mod 100h
end repeat
store byte (100h-chksum) at (rom.checksum)

106
x86_64-bios/mkboot.c Normal file
View file

@ -0,0 +1,106 @@
/*
* x86_64-bios/mkboot.c
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief Little tool to install boot.bin in MBR or VBR
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
/* the BOOTBOOT 1st stage loader code */
extern unsigned char *_binary____boot_bin_start;
/* entry point */
int main(int argc, char** argv)
{
// variables
unsigned char bootrec[512], data[512];
int f, lba=0, lsn, bootlsn=-1;
// check arguments
if(argc < 2) {
printf( "BOOTBOOT mkboot utility - bztsrc@gitlab\n\nUsage:\n"
" ./mkboot <disk> [partition lba]\n\n"
"Installs boot record on a disk. Disk can be a local file, a disk or partition\n"
"device. If you want to install it on a partition, you'll have to specify the\n"
"starting LBA of that partition as well. Requires that bootboot.bin is already\n"
"copied on the disk in a contiguous area in order to work.\n\n"
"Examples:\n"
" ./mkboot diskimage.dd - installing on a disk image\n"
" ./mkboot /dev/sda - installing as MBR\n"
" ./mkboot /dev/sda1 123 - installing as VBR\n");
return 1;
}
if(argc > 2 || argv[2]!=NULL) {
lba = atoi(argv[2]);
}
// open file
f = open(argv[1], O_RDONLY);
if(f < 0) {
fprintf(stderr, "mkboot: file not found\n");
return 2;
}
// read the boot record
if(read(f, data, 512)==-1) {
close(f);
fprintf(stderr, "mkboot: unable to read file\n");
return 2;
}
// create the boot record. First copy the code then the data area from original sector on disk
memcpy((void*)&bootrec, (void*)&_binary____boot_bin_start, 512);
memcpy((void*)&bootrec+0xB, (void*)&data+0xB, 0x5A-0xB); // copy BPB (if any)
memcpy((void*)&bootrec+0x1B8, (void*)&data+0x1B8, 510-0x1B8); // copy WNTID and partitioning table (if any)
// now locate the second stage by magic bytes
for(lsn = 1; lsn < 1024*1024; lsn++) {
printf("Checking sector %d\r", lsn);
if(read(f, data, 512) != -1 &&
data[0] == 0x55 && data[1] == 0xAA && data[3] == 0xE9 && data[8] == 'B' && data[12] == 'B') {
bootlsn=lsn;
break;
}
}
close(f);
// add bootboot.bin's address to boot record
if(bootlsn == -1) {
fprintf(stderr, "mkboot: unable to locate 2nd stage (bootboot.bin) in the first 512 Mbyte\n");
return 2;
}
bootlsn += lba;
memcpy((void*)&bootrec+0x1B0, (void*)&bootlsn, 4);
// save boot record
f = open(argv[1], O_WRONLY);
if(f < 0 || write(f, bootrec, 512) <= 0) {
fprintf(stderr, "mkboot: unable to write boot record\n");
return 3;
}
close(f);
// all went well
printf("mkboot: BOOTBOOT installed, 2nd stage starts at LBA %d\n", bootlsn);
}

500
x86_64-bios/tinf.inc Normal file
View file

@ -0,0 +1,500 @@
;*
;* x86_64-bios/tinf.inc
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief Tiny inflate, ported after tinflate.c by bzt
;*
;IN:
; esi: gzipped initrd
; edi: output buffer (guaranteed to be big enough)
; ecx: output buffer size
tinf_uncompress:
push ecx
push edi
mov edi, tinf_bss_start
mov ecx, tinf_bss_end-tinf_bss_start
xor al, al
repnz stosb
pop edi
pop ecx
mov dword [d_end], ecx
add dword [d_end], edi
.again:
; start a new block
cmp byte [d_btype], 255
jne .notst
; read final block flag
.next_blk: call tinf_getbit
mov byte [d_bfinal], al
; read block type
xor ebx, ebx
mov cl, 2
call tinf_read_bits
mov byte [d_btype], al
; build fixed huffman trees
cmp al, 1
jne @f
call tinf_build_fixed_trees
xor al, al
; decode trees from stream
@@: cmp al, 2
jne @f
call tinf_decode_trees
@@:
.notst:
; process current block
cmp byte [d_btype], 0
jnz @f
; decompress uncompressed block
call tinf_inflate_uncompressed_block
JMP .procend
@@: cmp byte [d_btype], 1
je @f
cmp byte [d_btype], 2
jne tinf_err
; decompress block with fixed/dyanamic huffman trees
; trees were decoded previously, so it's the same routine for both
@@: call tinf_inflate_block_data
.procend: cmp al, 1
jne @f
cmp byte [d_bfinal], 0
; the block has ended (without producing more data), but we
; can't return without data, so start procesing next block
jz .next_blk
ret
@@: or al, al
jnz tinf_err
cmp edi, dword [d_end]
jbe .again
ret
; build the fixed huffman trees
tinf_build_fixed_trees:
push edi
xor ecx, ecx
xor eax, eax
; build fixed length tree
mov cl, 7
mov edi, d_ltree_table
repnz stosb
mov al, 24
stosb
mov al, 152
stosb
mov al, 112
stosb
mov edi, d_ltree_trans
mov cl, 24
mov ax, 256
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 144
xor ax, ax
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 8
mov ax, 280
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 112
mov ax, 144
@@: stosw
inc ax
dec cl
jnz @b
; build fixed distance tree
mov cl, 5
mov edi, d_dtree_table
xor al, al
repnz stosb
mov al, 32
stosb
mov edi, d_dtree_trans
mov cl, 32
xor ax, ax
@@: stosw
inc ax
dec cl
jnz @b
pop edi
ret
;IN:
; ebp: TINF_TREE
; ebx: lengths
; ecx: num
tinf_build_tree:
push edi
xor eax, eax
; clear code length count table
mov edi, ebp
stosd ; for(i=0;i<16;i++) table[i]=0;
stosd
stosd
stosd
; scan symbol lengths, and sum code length counts
push ebx
push ecx
@@: mov al, byte [ebx] ;lengths[i]
inc ebx
inc byte [ebp+eax] ;table[lengths[i]]++
dec cx
jnz @b
mov byte [ebp], 0
; compute offset table for distribution sort
mov cl, 16
xor edx, edx ;i
xor ebx, ebx ;sum
xor eax, eax
@@: mov word [offs+2*edx], bx
mov al, byte [ebp+edx]
add ebx, eax
inc edx
dec cl
jnz @b
pop ecx
pop ebx ;lengths
; create code->symbol translation table (symbols sorted by code)
xor eax, eax ;i
@@: cmp byte [ebx], 0
jz .null
xor edx, edx
mov dl, byte [ebx] ;lengths[i]
inc word [offs+2*edx]
mov dx, word [offs+2*edx]
dec dx
mov word [ebp+2*edx+16], ax
.null: inc ebx
inc eax
dec cx
jnz @b
pop edi
ret
tinf_decode_trees:
mov word [num], 0
; get 5 bits HLIT (257-286)
xor ecx, ecx
mov cl, 5
mov ebx, 257
call tinf_read_bits
mov word [hlit], ax
mov word [num], ax
; get 5 bits HDIST (1-32)
mov cl, 5
xor ebx, ebx
inc ebx
call tinf_read_bits
mov word [hdist], ax
add word [num], ax
; get 4 bits HCLEN (4-19)
mov cl, 4
mov ebx, ecx
call tinf_read_bits
mov word [hclen], ax
push edi
mov cl, 19
mov edi, lengths
xor ax, ax
repnz stosw
pop edi
; read code lengths for code length alphabet
mov edx, clcidx
; get 3 bits code length (0-7)
@@: mov cx, 3
xor ebx, ebx
call tinf_read_bits
xor ebx, ebx
mov bl, byte [edx] ;clcidx[i]
mov byte[ebx+lengths], al
inc edx
dec word [hclen]
jnz @b
; build code length tree, temporarily use length tree
mov ebp, d_ltree
mov ebx, lengths
xor ecx, ecx
mov cl, 19
call tinf_build_tree
; decode code lengths for the dynamic trees
mov edx, lengths
.decode: mov ebp, d_ltree
call tinf_decode_symbol
xor ebx, ebx
cmp al, 16
jne .not16
; copy previous code length 3-6 times (read 2 bits)
mov cl, 2
mov bl, 3
call tinf_read_bits
mov cx, ax
mov al, byte [edx-1] ;lengths[num-1]
@@: mov byte [edx], al
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not16: cmp al, 17
jne .not17
; repeat code length 0 for 3-10 times (read 3 bits)
mov cl, 3
mov bl, cl
call tinf_read_bits
mov cx, ax
@@: mov byte [edx], 0
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not17: cmp al, 18
jne .not18
; repeat code length 0 for 11-138 times (read 7 bits)
mov cl, 7
mov bl, 11
call tinf_read_bits
mov cx, ax
@@: mov byte [edx], 0
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not18: ; values 0-15 represent the actual code lengths
mov byte [edx], al
inc edx
dec word [num]
.next: cmp word [num], 0
jnz .decode
; build dynamic trees
mov ebp, d_ltree
mov ebx, lengths
xor ecx, ecx
mov cx, word [hlit]
call tinf_build_tree
mov ebp, d_dtree
mov ebx, lengths
xor ecx, ecx
mov cx, word [hlit]
add ebx, ecx
mov cx, word [hdist]
call tinf_build_tree
ret
;OUT:
; al: status
tinf_inflate_block_data:
cmp word [d_curlen], 0
jne .notnull
mov ebp, d_ltree
call tinf_decode_symbol
; literal byte
cmp ax, 256
jae @f
stosb
xor al, al
ret
@@: cmp ax, 256
jne @f
; end of block
mov al, 1
ret
@@: ; substring from sliding dictionary
sub eax, 257
; possibly get more bits from length code
xor ecx, ecx
mov cl, byte [length_bits+eax]
xor ebx, ebx
mov bx, word [length_base+2*eax]
call tinf_read_bits
mov word [d_curlen], ax
; possibly get more bits from distance code
mov ebp, d_dtree
call tinf_decode_symbol
xor ecx, ecx
mov cl, byte [dist_bits+eax]
xor ebx, ebx
mov bx, word [dists_base+2*eax]
call tinf_read_bits
cmp dword [d_dict_ring], 0
neg eax
mov dword [d_lzOff], eax
.notnull: mov eax, edi
add eax, dword [d_lzOff]
mov al, byte [eax]
stosb
@@: dec word [d_curlen]
xor al, al
ret
;OUT:
; al: status
tinf_inflate_uncompressed_block:
cmp word [d_curlen], 0
jne @f
; get length
lodsw
; get one's complement of length
add esi, 2
; increment length to properly return TINF_DONE below, without
; producing data at the same time
mov word [d_curlen], ax
inc word [d_curlen]
; make sure we start next block on a byte boundary
mov byte [d_bitcount], 0
@@: dec byte [d_curlen]
cmp byte [d_curlen], 0
jnz @f
mov al, 1
ret
@@: movsb
xor al, al
ret
;OUT:
; al,zeroflag bit
tinf_getbit:
mov al, byte [d_bitcount]
or al, al
jnz @f
lodsb
mov byte [d_tag], al
mov byte [d_bitcount], 8
@@: dec byte [d_bitcount]
xor ax, ax
shr byte [d_tag], 1
adc ax, 0
ret
;IN:
; ebx: base
; cl: num
;OUT:
; eax: bits
tinf_read_bits:
push edx
or cl, cl
jz .end
xor eax, eax
xor edx, edx
inc dl
.next: call tinf_getbit
jz @f
add ebx, edx
@@: shl edx, 1
dec cl
jnz .next
.end: pop edx
mov eax, ebx
ret
;IN:
; ebp: TINF_TREE
;OUT:
; eax: trans
tinf_decode_symbol:
push edx
xor eax, eax
xor ebx, ebx ;cur
xor ecx, ecx ;len
xor edx, edx ;sum
; get more bits while code value is above sum
@@: shl ebx, 1
call tinf_getbit
add ebx, eax
inc ecx
mov al, byte [ebp+ecx]
add edx, eax
sub ebx, eax
jns @b
add edx, ebx
mov ax, word [ebp+2*edx+16]
mov ebp, edx
pop edx
ret
tinf_err:
mov esi, nogzip
jmp prot_diefunc
length_bits:
db 0, 0, 0, 0, 0, 0, 0, 0
db 1, 1, 1, 1, 2, 2, 2, 2
db 3, 3, 3, 3, 4, 4, 4, 4
db 5, 5, 5, 5, 0, 0, 0, 0
length_base:
dw 3, 4, 5, 6, 7, 8, 9, 10
dw 11, 13, 15, 17, 19, 23, 27, 31
dw 35, 43, 51, 59, 67, 83, 99, 115
dw 131, 163, 195, 227, 258, 0, 0
dist_bits:
db 0, 0, 0, 0, 1, 1, 2, 2
db 3, 3, 4, 4, 5, 5, 6, 6
db 7, 7, 8, 8, 9, 9, 10, 10
db 11, 11, 12, 12, 13, 13, 0, 0
dists_base:
dw 1, 2, 3, 4, 5, 7, 9, 13
dw 17, 25, 33, 49, 65, 97, 129, 193
dw 257, 385, 513, 769, 1025, 1537, 2049, 3073
dw 4097, 6145, 8193, 12289, 16385, 24577, 0, 0
clcidx:
db 16, 17, 18, 0, 8, 7, 9, 6
db 10, 5, 11, 4, 12, 3, 13, 2
db 14, 1, 15
d_btype: db 255

35
x86_64-efi/Makefile Normal file
View file

@ -0,0 +1,35 @@
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
GNUEFI_INCLUDES = -I/usr/include -I. -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol
GNUEFI_CRT_OBJS = crt0-efi-$(ARCH).o
GNUEFI_LDS = elf_$(ARCH)_efi.lds
CFLAGS = -mno-red-zone -mno-mmx -mno-sse -O2 -fpic -Wall -Wextra -Werror -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -DCONFIG_$(ARCH) -DGNU_EFI_USE_MS_ABI -maccumulate-outgoing-args --std=c11
LDFLAGS = -nostdlib
LDFLAGS += -shared -Bsymbolic -L. $(GNUEFI_CRT_OBJS)
TARGET = bootboot.efi
all: tinflate.o $(TARGET)
%.efi: %.so
@echo " src x86_64-efi (UEFI)"
@objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-$(ARCH) --subsystem=13 $^ $@
@echo -n "BOOTBOOT Loader do not " | dd conv=notrunc of=$(TARGET) bs=1 seek=78 1>/dev/null 2>/dev/null
@gcc $(GNUEFI_INCLUDES) -Wall -fshort-wchar efirom.c -o efirom $(LIBS)
@./efirom $(TARGET) ../bootboot.rom || true
@mv $(TARGET) ../$(TARGET)
@rm tinflate.o efirom
%.so: %.o
@ld $(LDFLAGS) tinflate.o $^ -o $@ -lefi -lgnuefi -T $(GNUEFI_LDS)
%.o: %.c
@gcc $(GNUEFI_INCLUDES) $(CFLAGS) -c $< -o $@
%.o: %.S
@gcc $(GNUEFI_INCLUDES) $(CFLAGS) -c $< -o $@
clean:
@rm bootboot.o $(TARGET) ../$(TARGET) ../bootboot.rom *.so *.efi efirom tinflate.o 2>/dev/null || true

35
x86_64-efi/README.md Normal file
View file

@ -0,0 +1,35 @@
BOOTBOOT UEFI Implementation
============================
See [BOOTBOOT Protocol](https://gitlab.com/bztsrc/bootboot) for common details.
On [UEFI machines](http://www.uefi.org/), the PCI Option ROM is created from the standard EFI
OS loader application.
Machine state
-------------
IRQs masked. GDT unspecified, but valid, IDT unset. Code is running in supervisor mode in ring 0.
File system drivers
-------------------
For boot partition, UEFI version relies on any file system that's supported by EFI Simple File System Protocol.
Installation
------------
1. *UEFI disk*: copy __bootboot.efi__ to **_FS0:\EFI\BOOT\BOOTX64.EFI_**.
2. *UEFI ROM*: use __bootboot.rom__ which is a standard **_PCI Option ROM image_**.
3. *GRUB*, *UEFI Boot Manager*: add __bootboot.efi__ to boot options.
Limitations
-----------
Known limitations:
- Maps the first 16G of RAM.
- PCI Option ROM should be signed in order to work.
- Compressed initrd in ROM is limited to 16M.

1076
x86_64-efi/bootboot.c Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

273
x86_64-efi/efirom.c Normal file
View file

@ -0,0 +1,273 @@
/*
* Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* modifications for gnuefi by bzt (bztsrc@gitlab)
*/
//#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <getopt.h>
#include <efi.h>
#include <efilink.h>
#include <pe.h>
#include <pci22.h>
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
/** Command-line options */
struct options {
uint16_t vendor;
uint16_t device;
};
/**
* Allocate memory
*
* @v len Length of memory to allocate
* @ret ptr Pointer to allocated memory
*/
static void * xmalloc ( size_t len ) {
void *ptr;
ptr = malloc ( len );
if ( ! ptr ) {
eprintf ( "Could not allocate %zd bytes\n", len );
exit ( 1 );
}
return ptr;
}
/**
* Get file size
*
* @v file File
* @v len File size
*/
/*
static size_t file_size ( FILE *file ) {
ssize_t len;
return len;
}
*/
/**
* Read information from PE headers
*
* @v pe PE file
* @ret machine Machine type
* @ret subsystem EFI subsystem
*/
static void read_pe_info ( void *pe, uint16_t *machine,
uint16_t *subsystem ) {
IMAGE_DOS_HEADER *dos;
union {
IMAGE_NT_HEADERS nt64;
} *nt;
/* Locate NT header */
dos = pe;
nt = ( pe + dos->e_lfanew );
/* Parse out PE information */
*machine = nt->nt64.FileHeader.Machine;
*subsystem = nt->nt64.OptionalHeader.Subsystem;
}
/**
* Convert EFI image to ROM image
*
* @v pe EFI file
* @v rom ROM file
*/
static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
struct {
EFI_PCI_EXPANSION_ROM_HEADER rom;
PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
uint8_t checksum;
} *headers;
struct stat pe_stat;
size_t pe_size;
size_t rom_size;
void *buf;
void *payload;
unsigned int i;
uint8_t checksum;
/* Determine PE file size */
if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
eprintf ( "Could not stat PE file: %s\n",
strerror ( errno ) );
exit ( 1 );
}
pe_size = pe_stat.st_size;
/* Determine ROM file size */
rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
/* Allocate ROM buffer and read in PE file */
buf = xmalloc ( rom_size );
memset ( buf, 0, rom_size );
headers = buf;
payload = ( buf + sizeof ( *headers ) );
if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
eprintf ( "Could not read PE file: %s\n",
strerror ( errno ) );
exit ( 1 );
}
/* Construct ROM header */
headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
headers->rom.InitializationSize = ( rom_size / 512 );
headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
read_pe_info ( payload, &headers->rom.EfiMachineType,
&headers->rom.EfiSubsystem );
headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
headers->rom.PcirOffset =
offsetof ( typeof ( *headers ), pci );
headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
headers->pci.VendorId = opts->vendor ? opts->vendor : 0x8086;
headers->pci.DeviceId = opts->device ? opts->device : 0x100E;
headers->pci.Length = sizeof ( headers->pci );
headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
headers->pci.ImageLength = ( rom_size / 512 );
headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
/* Fix image checksum */
for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
checksum += *( ( uint8_t * ) buf + i );
headers->checksum -= checksum;
/* Write out ROM */
if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
eprintf ( "Could not write ROM file: %s\n",
strerror ( errno ) );
exit ( 1 );
}
}
/**
* Print help
*
* @v program_name Program name
*/
static void print_help ( const char *program_name ) {
eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] "
"infile outfile\n", program_name );
}
/**
* Parse command-line options
*
* @v argc Argument count
* @v argv Argument list
* @v opts Options structure to populate
*/
static int parse_options ( const int argc, char **argv,
struct options *opts ) {
char *end;
int c;
while (1) {
int option_index = 0;
static struct option long_options[] = {
{ "vendor", required_argument, NULL, 'v' },
{ "device", required_argument, NULL, 'd' },
{ "help", 0, NULL, 'h' },
{ 0, 0, 0, 0 }
};
if ( ( c = getopt_long ( argc, argv, "v:d:h",
long_options,
&option_index ) ) == -1 ) {
break;
}
switch ( c ) {
case 'v':
opts->vendor = strtoul ( optarg, &end, 16 );
if ( *end ) {
eprintf ( "Invalid vendor \"%s\"\n", optarg );
exit ( 2 );
}
break;
case 'd':
opts->device = strtoul ( optarg, &end, 16 );
if ( *end ) {
eprintf ( "Invalid device \"%s\"\n", optarg );
exit ( 2 );
}
break;
case 'h':
print_help ( argv[0] );
exit ( 0 );
case '?':
default:
exit ( 2 );
}
}
return optind;
}
int main ( int argc, char **argv ) {
struct options opts = {
};
unsigned int infile_index;
const char *infile_name;
const char *outfile_name;
FILE *infile;
FILE *outfile;
/* Parse command-line arguments */
infile_index = parse_options ( argc, argv, &opts );
if ( argc != ( infile_index + 2 ) ) {
print_help ( argv[0] );
exit ( 2 );
}
infile_name = argv[infile_index];
outfile_name = argv[infile_index + 1];
/* Open input and output files */
infile = fopen ( infile_name, "r" );
if ( ! infile ) {
eprintf ( "Could not open %s for reading: %s\n",
infile_name, strerror ( errno ) );
exit ( 1 );
}
outfile = fopen ( outfile_name, "w" );
if ( ! outfile ) {
eprintf ( "Could not open %s for writing: %s\n",
outfile_name, strerror ( errno ) );
exit ( 1 );
}
/* Convert file */
make_efi_rom ( infile, outfile, &opts );
fclose ( outfile );
fclose ( infile );
return 0;
}

View file

@ -0,0 +1,74 @@
/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
. = 0;
ImageBase = .;
.hash : { *(.hash) } /* this MUST come first! */
. = ALIGN(4096);
.eh_frame :
{
*(.eh_frame)
}
. = ALIGN(4096);
.text :
{
_text = .;
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
. = ALIGN(16);
}
_etext = .;
_text_size = . - _text;
. = ALIGN(4096);
.reloc :
{
*(.reloc)
}
. = ALIGN(4096);
.data :
{
_data = .;
*(.rodata*)
*(.got.plt)
*(.got)
*(.data*)
*(.sdata)
/* the EFI loader doesn't seem to like a .bss section, so we stick
it all into .data: */
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
*(.rel.local)
}
.note.gnu.build-id : { *(.note.gnu.build-id) }
_edata = .;
_data_size = . - _etext;
. = ALIGN(4096);
.dynamic : { *(.dynamic) }
. = ALIGN(4096);
.rela :
{
*(.rela.data*)
*(.rela.got)
*(.rela.stab)
}
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
. = ALIGN(4096);
.dynstr : { *(.dynstr) }
. = ALIGN(4096);
.ignored.reloc :
{
*(.rela.reloc)
*(.eh_frame)
*(.note.GNU-stack)
}
.comment 0 : { *(.comment) }
}

264
x86_64-efi/fs.h Normal file
View file

@ -0,0 +1,264 @@
/*
* x86_64-efi/fs.h
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief Filesystem drivers for initial ramdisk.
*
*/
/**
* return type for fs drivers
*/
typedef struct {
UINT8 *ptr;
UINTN size;
} file_t;
extern int oct2bin(unsigned char *str,int size);
extern int hex2bin(unsigned char *str,int size);
extern CHAR16 *a2u (char *str);
#ifdef _FS_Z_H_
/**
* FS/Z initrd (OS/Z's native file system)
*/
file_t fsz_initrd(unsigned char *initrd_p, char *kernel)
{
FSZ_SuperBlock *sb = (FSZ_SuperBlock *)initrd_p;
FSZ_DirEnt *ent;
FSZ_Inode *in=(FSZ_Inode *)(initrd_p+sb->rootdirfid*FSZ_SECSIZE);
file_t ret = { NULL, 0 };
if(initrd_p==NULL || CompareMem(sb->magic,FSZ_MAGIC,4) || kernel==NULL){
return ret;
}
DBG(L" * FS/Z %s\n",a2u(kernel));
// Get the inode
int i,ss=1<<(sb->logsec+11);
char *s,*e;
s=e=kernel;
i=0;
again:
while(*e!='/'&&*e!=0){e++;}
if(*e=='/'){e++;}
if(!CompareMem(in->magic,FSZ_IN_MAGIC,4)){
//is it inlined?
if(!CompareMem(in->inlinedata,FSZ_DIR_MAGIC,4)){
ent=(FSZ_DirEnt *)(in->inlinedata);
} else if(!CompareMem(initrd_p+in->sec*ss,FSZ_DIR_MAGIC,4)){
// go, get the sector pointed
ent=(FSZ_DirEnt *)(initrd_p+in->sec*ss);
} else {
return ret;
}
//skip header
FSZ_DirEntHeader *hdr=(FSZ_DirEntHeader *)ent; ent++;
//iterate on directory entries
int j=hdr->numentries;
while(j-->0){
if(!CompareMem(ent->name,s,e-s)) {
if(*e==0) {
i=ent->fid;
break;
} else {
s=e;
in=(FSZ_Inode *)(initrd_p+ent->fid*ss);
goto again;
}
}
ent++;
}
} else {
i=0;
}
if(i!=0) {
// fid -> inode ptr -> data ptr
FSZ_Inode *in=(FSZ_Inode *)(initrd_p+i*ss);
if(!CompareMem(in->magic,FSZ_IN_MAGIC,4)){
ret.size=in->size;
switch(FSZ_FLAG_TRANSLATION(in->flags)) {
case FSZ_IN_FLAG_INLINE:
// inline data
ret.ptr=(UINT8*)(initrd_p+i*ss+1024);
break;
case FSZ_IN_FLAG_SECLIST:
case FSZ_IN_FLAG_SDINLINE:
// sector directory or list inlined
ret.ptr=(UINT8*)(initrd_p + *((UINT64*)&in->inlinedata) * ss);
break;
case FSZ_IN_FLAG_DIRECT:
// direct data
ret.ptr=(UINT8*)(initrd_p + in->sec * ss);
break;
// sector directory (only one level supported here, and no holes in files)
case FSZ_IN_FLAG_SECLIST0:
case FSZ_IN_FLAG_SD:
ret.ptr=(UINT8*)(initrd_p + (unsigned int)(((FSZ_SectorList *)(initrd_p+in->sec*ss))->sec) * ss);
break;
default:
ret.size=0;
break;
}
}
}
return ret;
}
#endif
/**
* cpio archive
*/
file_t cpio_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p;
int k;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL ||
(CompareMem(initrd_p,"070701",6) && CompareMem(initrd_p,"070702",6) && CompareMem(initrd_p,"070707",6)))
return ret;
DBG(L" * cpio %s\n",a2u(kernel));
k=strlena((unsigned char*)kernel);
// hpodc archive
while(!CompareMem(ptr,"070707",6)){
int ns=oct2bin(ptr+8*6+11,6);
int fs=oct2bin(ptr+8*6+11+6,11);
if(!CompareMem(ptr+9*6+2*11,kernel,k+1)){
ret.size=fs;
ret.ptr=(UINT8*)(ptr+9*6+2*11+ns);
return ret;
}
ptr+=(76+ns+fs);
}
// newc and crc archive
while(!CompareMem(ptr,"07070",5)){
int fs=hex2bin(ptr+8*6+6,8);
int ns=hex2bin(ptr+8*11+6,8);
if(!CompareMem(ptr+110,kernel,k+1)){
ret.size=fs;
ret.ptr=(UINT8*)(ptr+((110+ns+3)/4)*4);
return ret;
}
ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4;
}
return ret;
}
/**
* ustar tarball archive
*/
file_t tar_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p;
int k;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL || CompareMem(initrd_p+257,"ustar",5))
return ret;
DBG(L" * tar %s\n",a2u(kernel));
k=strlena((unsigned char*)kernel);
while(!CompareMem(ptr+257,"ustar",5)){
int fs=oct2bin(ptr+0x7c,11);
if(!CompareMem(ptr,kernel,k+1)){
ret.size=fs;
ret.ptr=(UINT8*)(ptr+512);
return ret;
}
ptr+=(((fs+511)/512)+1)*512;
}
return ret;
}
/**
* Simple File System
*/
file_t sfs_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr, *end;
int k,bs,ver;
file_t ret = { NULL, 0 };
if(initrd_p==NULL || kernel==NULL || (CompareMem(initrd_p+0x1AC,"SFS",3) && CompareMem(initrd_p+0x1A6,"SFS",3)))
return ret;
// 1.0 Brendan's version, 1.10 BenLunt's version
ver=!CompareMem(initrd_p+0x1A6,"SFS",3)?10:0;
bs=1<<(7+(UINT8)initrd_p[ver?0x1B6:0x1BC]);
end=initrd_p + *((UINT64 *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize
// get index area
ptr=end - *((UINT64 *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area
// got a Starting Marker Entry?
if(ptr[0]!=2)
return ret;
DBG(L" * SFS 1.%d %s\n",ver,a2u(kernel));
k=strlena((unsigned char*)kernel);
// iterate on index until we reach the end or Volume Identifier
while(ptr<end && ptr[0]!=0x01){
ptr+=64;
// file entry?
if(ptr[0]!=0x12)
continue;
// filename match?
if(!CompareMem(ptr+(ver?0x23:0x22),kernel,k+1)){
ret.size=*((UINTN*)&ptr[ver?0x1B:0x1A]); // file_length
ret.ptr=initrd_p + *((UINT64*)&ptr[ver?0x0B:0x0A]) * bs; // base + start_block * blocksize
break;
}
}
return ret;
}
/**
* James Molloy's initrd (for some reason it's popular among hobby OS developers)
* http://www.jamesmolloy.co.uk/tutorial_html
*/
file_t jamesm_initrd(unsigned char *initrd_p, char *kernel)
{
unsigned char *ptr=initrd_p+4;
int i,k,nf=*((int*)initrd_p);
file_t ret = { NULL, 0 };
// no real magic, so we assume initrd contains at least 2 files...
if(initrd_p==NULL || kernel==NULL || initrd_p[2]!=0 || initrd_p[3]!=0 || initrd_p[4]!=0xBF || initrd_p[77]!=0xBF)
return ret;
DBG(L" * JamesM %s\n",a2u(kernel));
k=strlena((unsigned char*)kernel);
for(i=0;i<nf && ptr[0]==0xBF;i++) {
if(!CompareMem(ptr+1,kernel,k+1)){
ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
ret.size=*((uint32_t*)(ptr+69));
}
ptr+=73;
}
return ret;
}
/**
* Static file system drivers registry
*/
file_t (*fsdrivers[]) (unsigned char *, char *) = {
#ifdef _FS_Z_H_
fsz_initrd,
#endif
cpio_initrd,
tar_initrd,
sfs_initrd,
jamesm_initrd,
NULL
};

BIN
x86_64-efi/libefi.a Normal file

Binary file not shown.

BIN
x86_64-efi/libgnuefi.a Normal file

Binary file not shown.

117
x86_64-efi/tinf.h Normal file
View file

@ -0,0 +1,117 @@
/*
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
*
* Copyright (c) 2003 by Joergen Ibsen / Jibz
* All Rights Reserved
* http://www.ibsensoftware.com/
*
* Copyright (c) 2014-2016 by Paul Sokolovsky
*/
#ifndef TINF_H_INCLUDED
#define TINF_H_INCLUDED
#include <stdint.h>
/* calling convention */
#ifndef TINFCC
#ifdef __WATCOMC__
#define TINFCC __cdecl
#else
#define TINFCC
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* ok status, more data produced */
#define TINF_OK 0
/* end of compressed stream reached */
#define TINF_DONE 1
#define TINF_DATA_ERROR (-3)
#define TINF_CHKSUM_ERROR (-4)
#define TINF_DICT_ERROR (-5)
/* checksum types */
#define TINF_CHKSUM_NONE 0
#define TINF_CHKSUM_ADLER 1
#define TINF_CHKSUM_CRC 2
/* data structures */
typedef struct {
unsigned short table[16]; /* table of code length counts */
unsigned short trans[288]; /* code -> symbol translation table */
} TINF_TREE;
struct TINF_DATA;
typedef struct TINF_DATA {
const unsigned char *source;
/* If source above is NULL, this function will be used to read
next byte from source stream */
unsigned char (*readSource)(struct TINF_DATA *data);
unsigned int tag;
unsigned int bitcount;
/* Buffer start */
unsigned char *destStart;
/* Buffer total size */
unsigned int destSize;
/* Current pointer in buffer */
unsigned char *dest;
/* Remaining bytes in buffer */
unsigned int destRemaining;
/* Accumulating checksum */
unsigned int checksum;
char checksum_type;
int btype;
int bfinal;
unsigned int curlen;
int lzOff;
unsigned char *dict_ring;
unsigned int dict_size;
unsigned int dict_idx;
TINF_TREE ltree; /* dynamic length/symbol tree */
TINF_TREE dtree; /* dynamic distance tree */
} TINF_DATA;
#define TINF_PUT(d, c) \
{ \
*d->dest++ = c; \
if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \
}
unsigned char TINFCC uzlib_get_byte(TINF_DATA *d);
/* Decompression API */
void TINFCC uzlib_init(void);
void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);
int TINFCC uzlib_uncompress(TINF_DATA *d);
int TINFCC uzlib_uncompress_chksum(TINF_DATA *d);
int TINFCC uzlib_zlib_parse_header(TINF_DATA *d);
int TINFCC uzlib_gzip_parse_header(TINF_DATA *d);
/* Compression API */
void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen);
/* Checksum API */
/* prev_sum is previous value for incremental computation, 1 initially */
uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
/* crc is previous value for incremental computation, 0xffffffff initially */
uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* TINF_H_INCLUDED */

475
x86_64-efi/tinflate.c Normal file
View file

@ -0,0 +1,475 @@
/*
* tinflate - tiny inflate
*
* Copyright (c) 2003 by Joergen Ibsen / Jibz
* All Rights Reserved
* http://www.ibsensoftware.com/
*
* Copyright (c) 2014-2016 by Paul Sokolovsky
*
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software
* for any purpose, including commercial applications,
* and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be
* misrepresented; you must not claim that you
* wrote the original software. If you use this
* software in a product, an acknowledgment in
* the product documentation would be appreciated
* but is not required.
*
* 2. Altered source versions must be plainly marked
* as such, and must not be misrepresented as
* being the original software.
*
* 3. This notice may not be removed or altered from
* any source distribution.
*/
#include "tinf.h"
uint32_t tinf_get_le_uint32(TINF_DATA *d);
uint32_t tinf_get_be_uint32(TINF_DATA *d);
/* --------------------------------------------------- *
* -- uninitialized global data (static structures) -- *
* --------------------------------------------------- */
#ifdef RUNTIME_BITS_TABLES
/* extra bits and base tables for length codes */
unsigned char length_bits[30];
unsigned short length_base[30];
/* extra bits and base tables for distance codes */
unsigned char dist_bits[30];
unsigned short dist_base[30];
#else
const unsigned char length_bits[30] = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4,
5, 5, 5, 5
};
const unsigned short length_base[30] = {
3, 4, 5, 6, 7, 8, 9, 10,
11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115,
131, 163, 195, 227, 258
};
const unsigned char dist_bits[30] = {
0, 0, 0, 0, 1, 1, 2, 2,
3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10,
11, 11, 12, 12, 13, 13
};
const unsigned short dist_base[30] = {
1, 2, 3, 4, 5, 7, 9, 13,
17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073,
4097, 6145, 8193, 12289, 16385, 24577
};
#endif
/* special ordering of code length codes */
const unsigned char clcidx[] = {
16, 17, 18, 0, 8, 7, 9, 6,
10, 5, 11, 4, 12, 3, 13, 2,
14, 1, 15
};
/* ----------------------- *
* -- utility functions -- *
* ----------------------- */
#ifdef RUNTIME_BITS_TABLES
/* build extra bits and base tables */
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
{
int i, sum;
/* build bits table */
for (i = 0; i < delta; ++i) bits[i] = 0;
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
/* build base table */
for (sum = first, i = 0; i < 30; ++i)
{
base[i] = sum;
sum += 1 << bits[i];
}
}
#endif
/* build the fixed huffman trees */
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
{
int i;
/* build fixed length tree */
for (i = 0; i < 7; ++i) lt->table[i] = 0;
lt->table[7] = 24;
lt->table[8] = 152;
lt->table[9] = 112;
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
/* build fixed distance tree */
for (i = 0; i < 5; ++i) dt->table[i] = 0;
dt->table[5] = 32;
for (i = 0; i < 32; ++i) dt->trans[i] = i;
}
/* given an array of code lengths, build a tree */
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)
{
unsigned short offs[16];
unsigned int i, sum;
/* clear code length count table */
for (i = 0; i < 16; ++i) t->table[i] = 0;
/* scan symbol lengths, and sum code length counts */
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
t->table[0] = 0;
/* compute offset table for distribution sort */
for (sum = 0, i = 0; i < 16; ++i)
{
offs[i] = sum;
sum += t->table[i];
}
/* create code->symbol translation table (symbols sorted by code) */
for (i = 0; i < num; ++i)
{
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
}
}
/* ---------------------- *
* -- decode functions -- *
* ---------------------- */
unsigned char uzlib_get_byte(TINF_DATA *d)
{
if (d->source) {
return *d->source++;
}
return d->readSource(d);
}
uint32_t tinf_get_le_uint32(TINF_DATA *d)
{
uint32_t val = 0;
int i;
for (i = 4; i--;) {
val = val >> 8 | uzlib_get_byte(d) << 24;
}
return val;
}
uint32_t tinf_get_be_uint32(TINF_DATA *d)
{
uint32_t val = 0;
int i;
for (i = 4; i--;) {
val = val << 8 | uzlib_get_byte(d);
}
return val;
}
/* get one bit from source stream */
static int tinf_getbit(TINF_DATA *d)
{
unsigned int bit;
/* check if tag is empty */
if (!d->bitcount--)
{
/* load next tag */
d->tag = uzlib_get_byte(d);
d->bitcount = 7;
}
/* shift bit out of tag */
bit = d->tag & 0x01;
d->tag >>= 1;
return bit;
}
/* read a num bit value from a stream and add base */
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
{
unsigned int val = 0;
/* read num bits */
if (num)
{
unsigned int limit = 1 << (num);
unsigned int mask;
for (mask = 1; mask < limit; mask *= 2)
if (tinf_getbit(d)) val += mask;
}
return val + base;
}
/* given a data stream and a tree, decode a symbol */
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
{
int sum = 0, cur = 0, len = 0;
/* get more bits while code value is above sum */
do {
cur = 2*cur + tinf_getbit(d);
++len;
sum += t->table[len];
cur -= t->table[len];
} while (cur >= 0);
return t->trans[sum + cur];
}
/* given a data stream, decode dynamic trees from it */
static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
{
unsigned char lengths[288+32];
unsigned int hlit, hdist, hclen;
unsigned int i, num, length;
/* get 5 bits HLIT (257-286) */
hlit = tinf_read_bits(d, 5, 257);
/* get 5 bits HDIST (1-32) */
hdist = tinf_read_bits(d, 5, 1);
/* get 4 bits HCLEN (4-19) */
hclen = tinf_read_bits(d, 4, 4);
for (i = 0; i < 19; ++i) lengths[i] = 0;
/* read code lengths for code length alphabet */
for (i = 0; i < hclen; ++i)
{
/* get 3 bits code length (0-7) */
unsigned int clen = tinf_read_bits(d, 3, 0);
lengths[clcidx[i]] = clen;
}
/* build code length tree, temporarily use length tree */
tinf_build_tree(lt, lengths, 19);
/* decode code lengths for the dynamic trees */
for (num = 0; num < hlit + hdist; )
{
int sym = tinf_decode_symbol(d, lt);
switch (sym)
{
case 16:
/* copy previous code length 3-6 times (read 2 bits) */
{
unsigned char prev = lengths[num - 1];
for (length = tinf_read_bits(d, 2, 3); length; --length)
{
lengths[num++] = prev;
}
}
break;
case 17:
/* repeat code length 0 for 3-10 times (read 3 bits) */
for (length = tinf_read_bits(d, 3, 3); length; --length)
{
lengths[num++] = 0;
}
break;
case 18:
/* repeat code length 0 for 11-138 times (read 7 bits) */
for (length = tinf_read_bits(d, 7, 11); length; --length)
{
lengths[num++] = 0;
}
break;
default:
/* values 0-15 represent the actual code lengths */
lengths[num++] = sym;
break;
}
}
/* build dynamic trees */
tinf_build_tree(lt, lengths, hlit);
tinf_build_tree(dt, lengths + hlit, hdist);
}
/* ----------------------------- *
* -- block inflate functions -- *
* ----------------------------- */
/* given a stream and two trees, inflate a block of data */
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
{
if (d->curlen == 0) {
unsigned int offs;
int dist;
int sym = tinf_decode_symbol(d, lt);
//printf("huff sym: %02x\n", sym);
/* literal byte */
if (sym < 256) {
TINF_PUT(d, sym);
return TINF_OK;
}
/* end of block */
if (sym == 256) {
return TINF_DONE;
}
/* substring from sliding dictionary */
sym -= 257;
/* possibly get more bits from length code */
d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);
dist = tinf_decode_symbol(d, dt);
/* possibly get more bits from distance code */
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
d->lzOff = -offs;
}
/* copy next byte from dict substring */
d->dest[0] = d->dest[d->lzOff];
d->dest++;
d->curlen--;
return TINF_OK;
}
/* inflate an uncompressed block of data */
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
{
if (d->curlen == 0) {
unsigned int length, invlength;
/* get length */
length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
/* get one's complement of length */
invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
/* check length */
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
/* increment length to properly return TINF_DONE below, without
producing data at the same time */
d->curlen = length + 1;
/* make sure we start next block on a byte boundary */
d->bitcount = 0;
}
if (--d->curlen == 0) {
return TINF_DONE;
}
unsigned char c = uzlib_get_byte(d);
TINF_PUT(d, c);
return TINF_OK;
}
/* ---------------------- *
* -- public functions -- *
* ---------------------- */
/* initialize global (static) data */
void uzlib_init(void)
{
#ifdef RUNTIME_BITS_TABLES
/* build extra bits and base tables */
tinf_build_bits_base(length_bits, length_base, 4, 3);
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
/* fix a special case */
length_bits[28] = 0;
length_base[28] = 258;
#endif
}
/* inflate next byte of compressed stream */
int uzlib_uncompress(TINF_DATA *d)
{
do {
int res;
/* start a new block */
if (d->btype == -1) {
next_blk:
/* read final block flag */
d->bfinal = tinf_getbit(d);
/* read block type (2 bits) */
d->btype = tinf_read_bits(d, 2, 0);
//printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal);
if (d->btype == 1) {
/* build fixed huffman trees */
tinf_build_fixed_trees(&d->ltree, &d->dtree);
} else if (d->btype == 2) {
/* decode trees from stream */
tinf_decode_trees(d, &d->ltree, &d->dtree);
}
}
/* process current block */
switch (d->btype)
{
case 0:
/* decompress uncompressed block */
res = tinf_inflate_uncompressed_block(d);
break;
case 1:
case 2:
/* decompress block with fixed/dyanamic huffman trees */
/* trees were decoded previously, so it's the same routine for both */
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
break;
default:
return TINF_DATA_ERROR;
}
if (res == TINF_DONE && !d->bfinal) {
/* the block has ended (without producing more data), but we
can't return without data, so start procesing next block */
goto next_blk;
}
if (res != TINF_OK) {
return res;
}
} while (--d->destSize);
return TINF_OK;
}