[PATCH] aarch64: kern_paddr_start calculation makes more accurate legacy check

Alexander Kamensky alexander.kamensky42 at gmail.com
Sat Aug 19 12:11:19 PDT 2023


In the latest openembedded with aarch64 image that uses 6.4.3 kernel on qemu I
tried to run makedumpfile in secondary kernel with /proc/vmcore. It failed as
follows:

> root at qemuarm64:~# makedumpfile -c -F /proc/vmcore > /dev/null
> read_from_vmcore: Can't seek the dump memory(/proc/vmcore). (offset: ffffffc0123fa000) Invalid argument
> readpage_elf: Can't read the dump memory(/proc/vmcore).
> <snip>

It turns out that not all parts for /proc/vmcore are readable:

> root at qemuarm64:~# cat /proc/vmcore > /dev/null
> [  136.394931] Internal error: synchronous external abort: 0000000096000010 [#1] PREEMPT SMP
> [  136.422434] Modules linked in:
> <snip>

Binary search of different kernel versions I found that the issue goes back to
5.11. It works fine with 5.10 version of the kernel.

After running secondary kernel under qemu gdb, I've found that the primary kernel
main memory segment in elfcorehdr has wrong address and size.

Looking at kexec output with debug enabled at the time when it loads secondary
crash kernel I saw the following:

> Kernel text Elf header: p_type = 1, p_offset = 0x4030200000 p_paddr = 0x4030200000 p_vaddr = 0xffffffffffffffff p_filesz = 0xffffffc011410000 p_memsz = 0xffffffc011410000

These values come from elf_info variable and are set in iomem_range_callback
function. The function gets the following input on my system:

root at qemuarm64:~# cat /proc/iomem | grep "Kernel code"
  40210000-40feffff : Kernel code
root at qemuarm64:~# cat /proc/kallsyms | grep -e ' _text$'
root at qemuarm64:~# cat /proc/kallsyms | grep -e ' _stext$'
ffffffc010010000 T _stext
root at qemuarm64:~# cat /proc/kallsyms | grep -e ' __init_begin$'
ffffffc010df0000 T __init_begin

the function calculates elf_info.kern_paddr_start address similar to
these manual steps:

base = 0x40210000
length = 0x40feffff - 0x40210000 + 0x1 = 0xde0000
kva_text_end - kva_stext = 0xffffffc010df0000 - 0xffffffc010010000 = 0xde0000

elf_info.kern_paddr_start = base - (kva_stext - kva_text) =
                      0x40210000 - 0xffffffc010010000 = 0x4030200000

since 'length' and 'kva_text_end - kva_stext' are equal the function calculate
elf_info.kern_paddr_start as in legacy case:

  if (kva_text_end - kva_stext == length)
     elf_info.kern_paddr_start = base - (kva_stext - kva_text); // <---------
  else
     elf_info.kern_paddr_start = base;

but my kernel is not legacy and kva_text is zero.

The fix is just to add a check for kva_text not being zero before following the
legacy case.

Signed-off-by: Alexander Kamensky <alexander.kamensky42 at gmail.com>
---
 kexec/arch/arm64/crashdump-arm64.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
index 3098315..639c82a 100644
--- a/kexec/arch/arm64/crashdump-arm64.c
+++ b/kexec/arch/arm64/crashdump-arm64.c
@@ -82,7 +82,7 @@ static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr),
 		 * For compatibility, deduce by comparing the gap "__init_begin - _stext"
 		 * and the res size of "Kernel code" in /proc/iomem
 		 */
-		if (kva_text_end - kva_stext == length)
+		if ((kva_text_end - kva_stext == length) && (kva_text != 0))
 			elf_info.kern_paddr_start = base - (kva_stext - kva_text);
 		else
 			elf_info.kern_paddr_start = base;
-- 
2.41.0




More information about the kexec mailing list