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.

OffsetSizeFieldDescription
0x004magicMust be 0x4E4B524E (“NKRN” in ASCII).
0x044versionVersion as (major << 16) | minor. Not enforced by bootloader.
0x084load_addrPhysical address where the bootloader will copy the payload.
0x0C4entry_addrPhysical address of the first instruction to execute (kernel entry).
0x104image_sizeSize of the payload in bytes (does not include the 64-byte header).
0x144crc32IEEE 802.3 CRC32 of the payload bytes only.
0x1840nameNull-terminated string (e.g. kernel name). Padded with zeros.
0x40(image_size)payloadRaw AArch64 executable (e.g. from objcopy -O binary).

Constants: KERNEL_MAGIC = 0x4E4B524EU, KERNEL_HEADER_SIZE = 0x40.

Validation Performed by the Bootloader

  1. 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 with pack_kernel.py).

  2. Size: image_size must be non-zero and must not exceed KERNEL_MAX_SIZE (4 MiB). Otherwise the bootloader returns BL_ERR_TOO_LARGE.

  3. CRC32: The bootloader computes the CRC32 over the payload (bytes at offset 0x40, length image_size) using the same polynomial as pack_kernel.py (IEEE 802.3). If the computed value does not match the crc32 field, the bootloader returns BL_ERR_BAD_CHECKSUM and halts.

  4. 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.

  5. Jump: After filling the boot info at 0x1000, the bootloader jumps to entry_addr with x0 set to the address of the boot info structure (0x1000). Usually entry_addr equals load_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 as kernel_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.