zephyr/arch/arm/core/zimage_header.ld

18 lines
629 B
Text
Raw Permalink Normal View History

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