mirror of
https://gitlab.com/bztsrc/bootboot.git
synced 2023-02-13 20:54:32 -05:00
Initial commit
This commit is contained in:
commit
52c96a7d88
50 changed files with 9920 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal 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
21
LICENSE
Normal 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
390
README.md
Normal 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
27
aarch64-rpi/Makefile
Normal 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
49
aarch64-rpi/README.md
Normal 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
154
aarch64-rpi/boot.S
Normal 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
1574
aarch64-rpi/bootboot.c
Normal file
File diff suppressed because it is too large
Load diff
BIN
aarch64-rpi/font.psf
Normal file
BIN
aarch64-rpi/font.psf
Normal file
Binary file not shown.
274
aarch64-rpi/fs.h
Normal file
274
aarch64-rpi/fs.h
Normal 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
36
aarch64-rpi/link.ld
Normal 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
112
aarch64-rpi/mkboot.c
Normal 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
379
aarch64-rpi/raspbootcom.c
Normal 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
120
aarch64-rpi/tinf.h
Normal 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
475
aarch64-rpi/tinflate.c
Normal 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
BIN
boot.bin
Normal file
Binary file not shown.
BIN
bootboot.bin
Normal file
BIN
bootboot.bin
Normal file
Binary file not shown.
BIN
bootboot.efi
Executable file
BIN
bootboot.efi
Executable file
Binary file not shown.
142
bootboot.h
Normal file
142
bootboot.h
Normal 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
BIN
bootboot.img
Executable file
Binary file not shown.
BIN
bootboot.rom
Normal file
BIN
bootboot.rom
Normal file
Binary file not shown.
BIN
bootboot_spec_1st_ed.pdf
Normal file
BIN
bootboot_spec_1st_ed.pdf
Normal file
Binary file not shown.
50
mykernel/Makefile
Normal file
50
mykernel/Makefile
Normal 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
BIN
mykernel/font.psf
Normal file
Binary file not shown.
106
mykernel/kernel.c
Normal file
106
mykernel/kernel.c
Normal 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
48
mykernel/link.ld
Normal 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
BIN
mykernel/mykernel.aarch64.elf
Executable file
Binary file not shown.
42
mykernel/mykernel.aarch64.txt
Normal file
42
mykernel/mykernel.aarch64.txt
Normal 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
BIN
mykernel/mykernel.x86_64.elf
Executable file
Binary file not shown.
42
mykernel/mykernel.x86_64.txt
Normal file
42
mykernel/mykernel.x86_64.txt
Normal 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
BIN
mykernel/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
15
x86_64-bios/Makefile
Normal file
15
x86_64-bios/Makefile
Normal 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
34
x86_64-bios/README.md
Normal 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
218
x86_64-bios/boot.asm
Normal 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
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
121
x86_64-bios/bootboot.inc
Normal 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
502
x86_64-bios/fs.inc
Normal 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
62
x86_64-bios/initrd.asm
Normal 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
106
x86_64-bios/mkboot.c
Normal 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
500
x86_64-bios/tinf.inc
Normal 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
35
x86_64-efi/Makefile
Normal 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
35
x86_64-efi/README.md
Normal 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
1076
x86_64-efi/bootboot.c
Normal file
File diff suppressed because it is too large
Load diff
BIN
x86_64-efi/crt0-efi-x86_64.o
Normal file
BIN
x86_64-efi/crt0-efi-x86_64.o
Normal file
Binary file not shown.
273
x86_64-efi/efirom.c
Normal file
273
x86_64-efi/efirom.c
Normal 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;
|
||||
}
|
74
x86_64-efi/elf_x86_64_efi.lds
Normal file
74
x86_64-efi/elf_x86_64_efi.lds
Normal 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
264
x86_64-efi/fs.h
Normal 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
BIN
x86_64-efi/libefi.a
Normal file
Binary file not shown.
BIN
x86_64-efi/libgnuefi.a
Normal file
BIN
x86_64-efi/libgnuefi.a
Normal file
Binary file not shown.
117
x86_64-efi/tinf.h
Normal file
117
x86_64-efi/tinf.h
Normal 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
475
x86_64-efi/tinflate.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue