Introduction
A zImage is the self-extracting Linux kernel for 32-bit ARM: a small decompressor stub, then the compressed kernel. The boot loader
jumps to its first byte, the stub unpacks the kernel in memory and starts it. On a 32-bit Raspberry Pi the files are kernel.img,
kernel7.img and the like. The first 64 bytes are laid out as described by the kernel’s own source, arch/arm/boot/compressed/head.S
(read through a page summary; the words below are in our own description), and the file command’s magic database tests the same
fields. The Linux document “Booting ARM Linux” says how to start one but does not describe this header.
Header
| Offset | Size | Field | What it holds |
|---|---|---|---|
0x00 | 32 | Entry words | Eight instructions that do nothing (a no-op such as mov r0, r0). They are there for old boot loaders that skipped the 32 bytes of an a.out header, and some loaders patch them. In a Thumb-2 kernel the last of them, at 0x1C, is sub pc, pc, #3, which switches to Thumb state. |
0x20 | 4 | Branch | A branch past the header words to where the stub really begins (a Thumb branch in a Thumb-2 kernel). |
0x24 | 4 | Magic | 0x016F2818. file(1) tests it little-endian, and big-endian for a pure big-endian kernel. |
0x28 | 4 | Start address | The address the zImage was linked to run at. Zero when it can run wherever it is loaded. |
0x2C | 4 | End address | The address of the end of the zImage. End minus start is the size of the image proper; a devicetree may follow it. |
0x30 | 4 | Endianness flag | 0x04030201, written in the kernel’s own byte order: the bytes 01 02 03 04 mean a little-endian kernel, 04 03 02 01 a big-endian one. Older kernels have no flag. |
0x34 | 4 | Second magic | 0x45454545 in newer kernels (“another magic number”). |
0x38 | 4 | Table address | The address of an additional data table, in kernels that have one. |
0x3C | 4 | Code | The first bytes after the header block. |
The words after the magic are in the kernel’s endianness. file(1) separates three cases: a little-endian kernel, a big-endian kernel with a magic that reads little-endian (a boot loader that is little-endian can still find it), and a pure big-endian kernel. The viewer takes the endianness from the flag word, or from the magic when only the big-endian reading matches.
What a boot loader does
- Puts the image in RAM in the first 128 MiB; above 32 MiB avoids a relocation before the stub decompresses.
- Sets
r0to 0,r1to the machine type (all ones for a platform that boots from a devicetree) andr2to the physical address of the devicetree or tag list. - Enters in SVC mode (HYP mode where the CPU has it and nothing else uses it) with IRQs and FIQs off, the MMU off and the data cache off, in ARM state on a CPU that has it, even for a Thumb-2 kernel.
- Puts the devicetree on a 64-bit aligned address where the decompressor will not overwrite it; the kernel recognises it by
0xD00DFEED.
This is from the Linux document “Booting ARM Linux”.
Appended devicetree
A kernel built with the option for an appended devicetree has a devicetree blob after the zImage. The viewer
looks at the bytes right after the end address; if they begin with 0xD00DFEED it shows them as an appended devicetree that
can be opened. It does not search anywhere else.
What the viewer shows
The header word by word with the entry words decoded as ARM code; the endianness; the start and end addresses and the size they give; any
appended devicetree; the first 1,024 bytes (an option) disassembled with the ARM decoder, ARMv7-A by default. The file does not say whether the
stub is ARM or Thumb-2 or which architecture, so those are choices in the options bar: ARM throughout, ARM then Thumb-2 from an offset
(0x20 for a Thumb-2 kernel), or Thumb-2 throughout. The words from 0x24 to 0x3B are shown as data. It
reports an end address below the start or beyond the file, bytes after the end address that are not a devicetree, and a missing endianness flag or
second magic.
No real zImage was available for these pages: the header was checked against the kernel source’s description and the file command, on images built for the tests (little-endian, big-endian with either magic order, with and without an appended devicetree).
Not described
Known, not yet covered
- Viewer: the decompressor stub past the first bytes and the compressed kernel are bytes and a scrollable disassembly. The format does not record where the compressed kernel starts or how it is compressed (gzip, lzma, xz, lzo, lz4 or zstd), and no search is made for it.
- Reference: the contents of the additional data table at
0x38, and the EFI header some zImages carry (the source has an EFI header macro after the header words).
Unknown
- Viewer: whether the stub is ARM or Thumb-2, and its architecture: nothing in the file says, so the options bar does. This can never be decided by the viewer alone.