The Neutron bootloader expects the kernel to be stored as a packed image with a 64-byte header (NKRN) followed by the raw AArch64 binary payload. The header is defined in include/bootloader.h and must match the layout used by pack_kernel.py.
Header Layout
All fields are little-endian. The structure is kernel_header_t in the bootloader.
| Offset | Size | Field | Description |
|---|---|---|---|
| 0x00 | 4 | magic | Must be 0x4E4B524E (“NKRN” in ASCII). |
| 0x04 | 4 | version | Version as (major << 16) | minor. Not enforced by bootloader. |
| 0x08 | 4 | load_addr | Physical address where the bootloader will copy the payload. |
| 0x0C | 4 | entry_addr | Physical address of the first instruction to execute (kernel entry). |
| 0x10 | 4 | image_size | Size of the payload in bytes (does not include the 64-byte header). |
| 0x14 | 4 | crc32 | IEEE 802.3 CRC32 of the payload bytes only. |
| 0x18 | 40 | name | Null-terminated string (e.g. kernel name). Padded with zeros. |
| 0x40 | (image_size) | payload | Raw AArch64 executable (e.g. from objcopy -O binary). |
Constants: KERNEL_MAGIC = 0x4E4B524EU, KERNEL_HEADER_SIZE = 0x40.
Validation Performed by the Bootloader
-
Magic: The first word at the staging address (0x100000) must equal
KERNEL_MAGIC. If not, the bootloader prints an error and halts (often suggesting that the image was not packed withpack_kernel.py). -
Size:
image_sizemust be non-zero and must not exceedKERNEL_MAX_SIZE(4 MiB). Otherwise the bootloader returnsBL_ERR_TOO_LARGE. -
CRC32: The bootloader computes the CRC32 over the payload (bytes at offset 0x40, length
image_size) using the same polynomial aspack_kernel.py(IEEE 802.3). If the computed value does not match thecrc32field, the bootloader returnsBL_ERR_BAD_CHECKSUMand halts. -
Copy: The payload is copied to the physical address given in
load_addr. Typically this is 0x200000. The kernel must be linked so that its code and data are correct when placed at that address. -
Jump: After filling the boot info at 0x1000, the bootloader jumps to
entry_addrwith x0 set to the address of the boot info structure (0x1000). Usuallyentry_addrequalsload_addr(e.g. 0x200000).
Payload Requirements
- The payload must be a flat AArch64 binary (no ELF headers in the payload). Produce it by linking the kernel with a linker script that sets the load address (e.g. 0x200000) and then running
objcopy -O binary kernel.elf kernel.bin. - The first instruction of the payload will be executed at
entry_addr. That instruction must be the kernel entry point (e.g. a symbol such askernel_start). - The kernel runs at EL1 with MMU and caches disabled. It receives in x0 the physical address of
boot_info_t(see Boot Info Structure).
The bootloader does not parse ELF. Only the raw binary is copied. Do not pack an ELF file as the payload; use the binary produced by objcopy.
For the tool that builds this format from a raw binary, see Packing and Deploying.