Introduction
The ARM64 Image is the uncompressed Linux kernel for 64-bit ARM, with a 64-byte header at the start. A 64-bit Raspberry Pi
loads kernel8.img, which is this format; Raspberry Pi OS ships the file gzip-compressed and the firmware unpacks it, so a
kernel8.img that starts with the bytes 1F 8B is a gzip file whose content is
this format: the explorer opens an Image.gz as gzip and reads the unpacked bytes as an Image; a gzip file with another
name is found by Identify. The header is described by the Linux documentation “Booting AArch64 Linux”; the fields
below follow it, in our own words.
Header
All numbers are little-endian (from Linux 3.17; before that their byte order was not stated).
| Offset | Size | Field | What it holds |
|---|---|---|---|
0x00 | 4 | code0 | Executable code: the first instruction. The documentation says it branches to stext. It is skipped when the image is started through EFI. |
0x04 | 4 | code1 | Executable code. |
0x08 | 8 | text_offset | The offset from a 2 MiB-aligned base address at which the image must be placed. Before Linux 3.17 it was 0x80000. |
0x10 | 8 | image_size | The effective size of the image, including memory the kernel clears after the file (the bss), so it can be larger than the file. Zero in kernels before 3.17: assume a text_offset of 0x80000. |
0x18 | 8 | flags | Kernel flags, below. |
0x20 | 8 | res2 | Reserved, zero. |
0x28 | 8 | res3 | Reserved, zero. |
0x30 | 8 | res4 | Reserved, zero. |
0x38 | 4 | magic | 0x644D5241, the bytes 41 52 4D 64: “ARMd”, written ARM\x64. |
0x3C | 4 | res5 | Reserved; used as the offset of the PE header when the image is also an EFI application. |
Flags
| Bits | Meaning |
|---|---|
| 0 | Kernel endianness: 0 little-endian, 1 big-endian. |
| 1–2 | Page size: 0 not specified, 1 4 KiB, 2 16 KiB, 3 64 KiB. |
| 3 | Physical placement: 0, the 2 MiB-aligned base should be as close as possible to the base of DRAM (memory below it cannot be used through the linear mapping); 1, any 2 MiB-aligned base that keeps all image_size bytes inside the 48-bit physical range. |
| 4–63 | Reserved. |
What a boot loader does
- Places the image
text_offsetbytes above a 2 MiB-aligned address in usable RAM, with at leastimage_sizebytes free from its start. - Puts the devicetree on an 8-byte boundary (not larger than 2 MiB) and its physical address in
x0;x1,x2andx3are zero. - Enters with all interrupts masked, in non-secure state at EL2 (recommended) or EL1, with the MMU off, the data caches cleaned for the image’s range and DMA quiesced, and jumps to the first byte of the image.
The documentation lists further requirements for system registers and secondary CPUs; the page itself is the reference for those.
The EFI stub
A kernel built with the EFI stub is also an EFI application. Its first two bytes spell MZ, which AArch64 decodes as an instruction
that is harmless to run, and res5 is the offset of the PE header, which holds the EFI entry point. In the real file below it is
0x40, the byte after the header, where PE\0\0 and the machine type 0xAA64 (ARM64) stand.
Example
The header of kernel8.img from Raspberry Pi OS (kernel 6.18.34, for the Raspberry Pi Zero 2 W), after unpacking:
00000000: 4d5a 40fa 1904 4f14 0000 0000 0000 0000
00000010: 0000 8c01 0000 0000 0a00 0000 0000 0000
00000020: 0000 0000 0000 0000 0000 0000 0000 0000
00000030: 0000 0000 0000 0000 4152 4d64 4000 0000
code0 is 0xFA405A4D, which the viewer decodes as ccmp x18, #0, #0xd, pl, and code1 is
0x144F0419, a branch to 0x13C1068. The text offset is 0, the image size 0x18C0000 (25,952,256 bytes: larger
than the 25,373,184-byte file), the flags 0xA (little-endian, 4 KiB pages, placement bit 3 set), and res5 is
0x40. The kernel’s version banner, Linux version 6.18.34+rpt-rpi-v8 …, is a string inside the file; the viewer
finds and shows it, but it is not a field of the header.
What the viewer shows
The header field by field; the flags decoded; the PE header checked (signature and machine); the checks that image_size is not
below the file size, that text_offset is a multiple of 4 KiB, that the reserved fields and flag bits are zero, and that a PE
offset points at a PE header; the first 4,096 bytes (an option) disassembled with the AArch64 decoder, the target of the branch named
stext; and the kernel’s version banner if there is one. The rest of the kernel is not explained.
Not described
Known, not yet covered
- Viewer: the kernel proper after the first bytes: it shows as bytes and a disassembly you can scroll. Code and data are not told apart and no function is named.
- Reference and viewer: the PE/COFF headers and sections of an EFI-stub kernel beyond the signature and machine type.
- Reference: the register requirements of the booting document beyond those summarised here.