| cross | Add empty project copied from stem | |
| src | Rename stub2 to multistub | |
| test | Rename stub2 to multistub | |
| tools | Rename stub2 to multistub | |
| .gitignore | Rename stub2 to multistub | |
| meson.build | Rename stub2 to multistub | |
| meson.options | Rename stub2 to multistub | |
| README.md | Add support for multiboot1 | |
stub2
A UEFI stub that boots Multiboot2 kernel images. The kernel and optional
modules are embedded into PE sections of the stub binary, creating a
single self-contained .efi executable that can be placed on an EFI System
Partition and booted by firmware without any external bootloader.
Building
Requires: GCC, meson (>= 1.1.0), python3.
meson setup build --cross-file cross/x86_64.txt
meson compile -C build
Produces build/stub2x64.efi.
Embedding a kernel
Use tools/mkstub.py to produce a ready-to-boot EFI binary:
python3 tools/mkstub.py kernel.elf -o my-stub.efi
With a command line and modules:
python3 tools/mkstub.py kernel.elf -o my-stub.efi \
--cmdline "console=ttyS0 root=/dev/sda1" \
--module initramfs.img:initrd \
--module config.cfg
Module syntax is PATH or PATH:CMDLINE. Up to 10 modules are supported.
By default the script looks for build/stub2x64.efi; override with --stub.
Place the resulting my-stub.efi on an ESP (e.g. as
EFI/BOOT/BOOTX64.EFI) and boot it from UEFI firmware.
Manual embedding
Sections can also be added individually with objcopy. Use tools/pesvma.py
to compute the correct PE section VMA (must be called after each addition):
cp build/stub2x64.efi my-stub.efi
VMA=$(python3 tools/pesvma.py my-stub.efi)
objcopy \
--add-section .kernel=kernel.elf \
--change-section-vma ".kernel=$VMA" \
--set-section-flags .kernel=alloc,load,readonly,data \
my-stub.efi
Each call to pesvma.py returns the next available VMA for the PE as it
currently is, so call it again before adding another section.
Kernel requirements
The embedded kernel must contain a valid Multiboot2 header within the first
32768 bytes, declaring architecture = 0 (i386).
ELF kernels
ELF kernels (32-bit or 64-bit) are loaded by their PT_LOAD segments to the
p_paddr physical addresses. All segments must fit in the first 4GB.
The entry point defaults to the ELF e_entry, but can be overridden with
MB2 header tags:
ENTRY_ADDRESS(type 3): overridese_entryENTRY_ADDRESS_EFI64(type 9): preferred when present (since we boot from UEFI64)
The entry point virtual address is converted to a physical address via the PT_LOAD segment mapping.
Flat binary kernels
Non-ELF kernels are loaded using the ADDRESS header tag (type 2), which
must be present along with ENTRY_ADDRESS (type 3) or ENTRY_ADDRESS_EFI64
(type 9). The ADDRESS tag fields specify where and how much to load:
header_addr: address corresponding to the MB2 header in memoryload_addr: start of the load regionload_end_addr: end of file data (0 = load entire file)bss_end_addr: end of BSS region (0 = no BSS)
The stub calculates the file offset to load from:
load_file_offset = header_file_offset - (header_addr - load_addr)
python3 tools/mkstub.py kernel.bin -o my-stub.efi
Machine state at kernel entry
- 32-bit protected mode, paging disabled
EAX= 0x36d76289 (Multiboot2 magic)EBX= physical address of the Multiboot2 Information structureCS= 32-bit code segment (base 0, limit 4GB)DS/ES/FS/GS/SS= 32-bit data segment (base 0, limit 4GB)ESP= 0 (kernel must set up its own stack before usingcall/push)- All other general-purpose registers = 0
- Interrupts disabled
Kernel command line
Pass --cmdline to mkstub.py. The string is passed to the kernel as
the CMDLINE MBI tag (type 1). If omitted, an empty string is used.
Modules
Pass --module (up to 10 times) to mkstub.py. Each module is a raw binary
blob loaded to a page-aligned physical address below 4GB and passed as a
MODULE MBI tag (type 3). Use PATH:CMDLINE syntax to set per-module
command lines.
MBI tags provided
The Multiboot2 Information structure passed to the kernel contains these tags (in order):
| Tag | Type | Description |
|---|---|---|
| CMDLINE | 1 | Kernel command line from .cmdline section (empty string if absent) |
| BOOT_LOADER_NAME | 2 | "stub2" |
| MODULE | 3 | One per embedded .moduleN section, with cmdline from .modcfg |
| LOAD_BASE_ADDR | 21 | Physical base address of the lowest loaded ELF segment |
| ELF_SECTIONS | 9 | ELF section headers (ELF only, when requested via information request tag) |
| FRAMEBUFFER | 8 | GOP framebuffer info (if GOP is available) |
| ACPI_OLD | 14 | RSDP v1 (if present in EFI configuration tables) |
| ACPI_NEW | 15 | RSDP v2 (if present in EFI configuration tables) |
| EFI64 | 12 | EFI system table pointer |
| BASIC_MEMINFO | 4 | Conventional memory below 640K and above 1MB |
| MMAP | 6 | Memory map (EFI memory map converted to MB2 types) |
| EFI_MMAP | 17 | Raw EFI memory map |
| END | 0 | Terminator |