arch: arm: aarch32: Add ability to generate zImage header
The image header is compatible for zImage(32) protocol.
Offset Value Description
0x24 0x016F2818 Magic number to identify ARM Linux zImage
0x28 start address The address the zImage starts at
0x2C end address The address the zImage ends at
As Zephyr can be built with a fixed load address, Xen/Uboot can read
the image header and decide where to copy the Zephyr image.
Also, it is to be noted that for AArch32 A/R, the vector table should
be aligned to 0x20 address. Refer ARM DDI 0487I.a ID081822, G8-9815,
G8.2.168, VBAR, Vector Base Address Register :-
Bits[4:0] = RES0.
For AArch32 M (Refer DDI0553B.v ID16122022, D1.2.269, VTOR, Vector Table
Offset Register), Bits [6:0] = RES0.
As zImage header occupies 0x30 bytes, thus it is necessary to align
the vector table base address to 0x80 (which satisfies both VBAR and
VTOR requirements).
Also, it is to be noted that not all the AArch32 M class have VTOR, thus
ARM_ZIMAGE_HEADER header depends on
CPU_AARCH32_CORTEX_R || CPU_AARCH32_CORTEX_A || CPU_CORTEX_M_HAS_VTOR.
The reason being the processors which does not have VBAR or VTOR, needs
to have exception vector table at a fixed address in the beginning of
ROM (Refer the comment in arch/arm/core/aarch32/cortex_m/CMakeLists.txt)
. They cannot support any headers.
Also, the first instruction in zImage header is to branch to the kernel
start address. This is to support booting in situations where the zImage
header need not be parsed.
In case of Arm v8M, the first two entries in the reset vector should be
"Initial value for the main stack pointer on reset" and "Start address
for the reset handler" (Refer Armv8M DDI0553B.vID16122022, B3.30,
Vector tables).
In case of Armv7M (ARM DDI 0403E. ID021621, B1.5.3 The vector table),
the first entry is "SP_main. This is the reset value of the Main stack
pointer.".
Thus when v7M or v8M starts from reset, it expects to see these values
at the default reset vector location.
See the following text from Armv7M (ARM DDI 0403E. ID021621, B1-526)
"On powerup or reset, the processor uses the entry at offset 0 as the
initial value for SP_main..."
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
2022-12-14 12:46:53 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2023, Advanced Micro Devices, Inc.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_ARM_ZIMAGE_HEADER)
|
|
|
|
|
KEEP(*(.image_header))
|
|
|
|
|
KEEP(*(.".image_header.*"))
|
arch: arm: zimage_header: emit end-of-image LMA in zImage header
The ARM zImage header (header.S) ends with three words that follow
the Linux self-decompressor convention:
.long 0x016f2818 // Magic number
.long __rom_region_start // start address of zImage
.long __end // end address of zImage
A standard ARM zImage consumer (e.g. U-Boot bootz, or the Xen arm32
kernel loader) reads the third word and computes the on-disk file
size of the zImage as (__end - __rom_region_start). Linux establishes
the same invariant in arch/arm/boot/compressed/head.S, where the
analogous field is encoded as "_edata - start", i.e. the LMA of the
last byte of the image relative to its load address.
The current zimage_header.ld emits __end with:
KEEP(*(.image_header))
KEEP(*(.".image_header.*"))
__end = .;
zimage_header.ld is plugged into the linker script via the ROM_START
hook (see arch/arm/core/CMakeLists.txt) and runs immediately after
the 48-byte .image_header section is placed. At that point '.' is
still just past the header, so __end ends up only 0x30 bytes past
__rom_region_start regardless of how large the actual image is.
Every zImage built with CONFIG_ARM_ZIMAGE_HEADER=y therefore
advertises a size of 48 bytes in its header.
For Zephyr standalone this is invisible: the FVP / debugger loads
the whole file unconditionally and never consults the header. It
breaks any consumer that honours the header, though. On a Cortex-R52
FVP under Xen dom0less, the guest fails to boot:
(XEN) Loading zImage from 11000000 to 30000000-30000030
(XEN) CPU0: Unexpected Trap: Undefined Instruction
Xen copied only the 48 header bytes into the DomU and the guest
branched into uninitialised memory.
Fix it by computing __end the way Linux's head.S computes _edata:
take the LMA of the very last output section. Zephyr already exposes
that anchor as .last_section, and uses
LOADADDR(.last_section) + SIZEOF(.last_section)
elsewhere for the same purpose (e.g. _flash_used in
include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld and the
equivalent cortex_m / arm64 / riscv linker scripts). The expression
is resolved lazily by the linker at final link time, so referring
to it from a ROM_START fragment that runs before .last_section is
emitted is safe.
After this change, a build of samples/hello_world for
fvp_baser_aemv8r/fvp_aemv8r_aarch32 with -DCONFIG_ARM_ZIMAGE_HEADER=y
produces a 27268-byte zephyr.bin whose header reads:
magic = 0x016f2818
start = 0x30000000
end = 0x30006a84 (end - start == file size)
`file(1)` now identifies it as "Linux kernel ARM boot executable
zImage", U-Boot bootz accepts it without complaint, and the same
binary boots cleanly as a Xen R52 dom0less DomU using Xen's standard
zImage loader path (no special payload-only handling required).
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Signed-off-by: Satya Sri <satyasri.katru@amd.com>
2026-05-19 17:29:06 +00:00
|
|
|
/*
|
|
|
|
|
* The zImage header at offset 0x2c must hold the end-of-image LMA so that
|
|
|
|
|
* (end - start) equals the file size of the produced binary, matching the
|
|
|
|
|
* Linux ARM zImage convention. '.' here is only just past the 48-byte
|
|
|
|
|
* header (rom_start is one of the first sections emitted), so use the
|
|
|
|
|
* .last_section LMA which the linker resolves lazily at final link time.
|
|
|
|
|
*/
|
|
|
|
|
__end = LOADADDR(.last_section) + SIZEOF(.last_section);
|
arch: arm: aarch32: Add ability to generate zImage header
The image header is compatible for zImage(32) protocol.
Offset Value Description
0x24 0x016F2818 Magic number to identify ARM Linux zImage
0x28 start address The address the zImage starts at
0x2C end address The address the zImage ends at
As Zephyr can be built with a fixed load address, Xen/Uboot can read
the image header and decide where to copy the Zephyr image.
Also, it is to be noted that for AArch32 A/R, the vector table should
be aligned to 0x20 address. Refer ARM DDI 0487I.a ID081822, G8-9815,
G8.2.168, VBAR, Vector Base Address Register :-
Bits[4:0] = RES0.
For AArch32 M (Refer DDI0553B.v ID16122022, D1.2.269, VTOR, Vector Table
Offset Register), Bits [6:0] = RES0.
As zImage header occupies 0x30 bytes, thus it is necessary to align
the vector table base address to 0x80 (which satisfies both VBAR and
VTOR requirements).
Also, it is to be noted that not all the AArch32 M class have VTOR, thus
ARM_ZIMAGE_HEADER header depends on
CPU_AARCH32_CORTEX_R || CPU_AARCH32_CORTEX_A || CPU_CORTEX_M_HAS_VTOR.
The reason being the processors which does not have VBAR or VTOR, needs
to have exception vector table at a fixed address in the beginning of
ROM (Refer the comment in arch/arm/core/aarch32/cortex_m/CMakeLists.txt)
. They cannot support any headers.
Also, the first instruction in zImage header is to branch to the kernel
start address. This is to support booting in situations where the zImage
header need not be parsed.
In case of Arm v8M, the first two entries in the reset vector should be
"Initial value for the main stack pointer on reset" and "Start address
for the reset handler" (Refer Armv8M DDI0553B.vID16122022, B3.30,
Vector tables).
In case of Armv7M (ARM DDI 0403E. ID021621, B1.5.3 The vector table),
the first entry is "SP_main. This is the reset value of the Main stack
pointer.".
Thus when v7M or v8M starts from reset, it expects to see these values
at the default reset vector location.
See the following text from Armv7M (ARM DDI 0403E. ID021621, B1-526)
"On powerup or reset, the processor uses the entry at offset 0 as the
initial value for SP_main..."
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
2022-12-14 12:46:53 +00:00
|
|
|
#endif
|