[PATCH] arm: use the zImage tag's real TEXT_OFFSET for kernel placement
Tom Fitzhenry
tom at tom-fitzhenry.me.uk
Mon Aug 31 05:58:27 PDT 2026
The zImage loader assumes TEXT_OFFSET is 0x8000 and sizes the kernel
reservation as if the decompressed kernel lands at RAM base + 0x8000.
Multiplatform armv7 kernels, however, are built with a per-platform
TEXT_OFFSET: arch/arm/Makefile warns that "this offset is critical to
the functioning of kexec-tools", and e.g. ARCH_MESON uses 0x00208000.
With such a kernel the decompressor places the inflated kernel ~2 MB
higher than kexec-tools assumed, so the initrd placed at the estimated
end of the kernel image lands inside the decompressor's scratch area
or the new kernel's own reservation. The kexec'd kernel then fails
with "RAMDISK: Couldn't find valid RAM disk image" or "INITRD: ...
overlaps in-use memory region", as seen kexec'ing an armv7 NixOS
kernel on a Netgear RN102 (its multiplatform config selects
ARCH_MESON).
The zImage extension tag has recorded TEXT_OFFSET since v5.10 (commit
83dfeedb6663, "ARM: add TEXT_OFFSET to decompressor kexec image
structure"), but the loader only reads size_ptr and bss_size from it.
Read the real value and place the zImage there. Older kernels do not
carry it and keep the historical 0x8000 default, just as the arm64
loader falls back to 0x80000 for older kernels (commit 522df5f7217f,
"arm64: Add arm64 kexec support").
Note on tooling: this patch was developed with assistance from
DeepSeek LLM, which helped diagnose the failure and draft the fix.
Tested by kexec'ing arm zImages with non-default TEXT_OFFSET under
QEMU with both a synthetic config and the affected RN102's config,
asserting the kexec'd initrd runs.
Signed-off-by: Tom Fitzhenry <tom at tom-fitzhenry.me.uk>
Link: https://git.kernel.org/torvalds/c/83dfeedb6663
Link: https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=522df5f7217fda01ece3f6ac3e9987b0320c2bb0
---
kexec/arch/arm/kexec-zImage-arm.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
index 8b474dd..892fca0 100644
--- a/kexec/arch/arm/kexec-zImage-arm.c
+++ b/kexec/arch/arm/kexec-zImage-arm.c
@@ -131,6 +131,7 @@ struct zimage_tag {
struct zimage_krnl_size {
uint32_t size_ptr;
uint32_t bss_size;
+ uint32_t text_offset;
} krnl_size;
} u;
};
@@ -478,7 +479,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
unsigned long page_size = getpagesize();
unsigned long base, kernel_base;
unsigned int atag_offset = 0x1000; /* 4k offset from memory start */
- unsigned int extra_size = 0x8000; /* TEXT_OFFSET */
+ unsigned int text_offset;
uint32_t address_cells, size_cells;
const struct zimage_tag *tag;
size_t kernel_buf_size;
@@ -661,6 +662,21 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
*/
tag = find_extension_tag(buf, len, ZIMAGE_TAG_KRNL_SIZE);
+ /*
+ * The decompressor places the inflated kernel at
+ * (zImage address & 0xf8000000) + TEXT_OFFSET, so load the
+ * zImage at a 128 MiB-aligned base + TEXT_OFFSET. The tag
+ * table records the real value since v5.10 (commit
+ * 83dfeedb6663, "ARM: add TEXT_OFFSET to decompressor kexec
+ * image structure"); TEXT_OFFSET is the third payload word,
+ * so a tag size of at least 5 means it is present. Older
+ * kernels keep the historical 0x8000 default.
+ */
+ if (tag && le32_to_cpu(tag->hdr.size) >= 5)
+ text_offset = le32_to_cpu(tag->u.krnl_size.text_offset);
+ else
+ text_offset = 0x8000;
+
/*
* The zImage length does not include its stack (4k) or its
* malloc space (64k). Include this.
@@ -748,14 +764,14 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
}
base = start;
} else {
- base = locate_hole(info, len + extra_size, 0, 0,
+ base = locate_hole(info, len + text_offset, 0, 0,
ULONG_MAX, INT_MAX);
}
if (base == ULONG_MAX)
return -1;
- kernel_base = base + extra_size;
+ kernel_base = base + text_offset;
/*
* Calculate the minimum address of the initrd, which must be
base-commit: 43c5cba85ad23cc69c423527d9587c59b89fa437
--
2.55.0
More information about the kexec
mailing list