[PATCH makedumpfile V2 1/2] Add riscv64 support

Song Shuai songshuaishuai at tinylab.org
Tue Oct 10 07:12:43 PDT 2023


This patch adds support for riscv64 in makedumpfile.
It implements the "vtop" for kenrel memory regions
and supports Sv39/Sv48/Sv57 page modes for RV64.

Signed-off-by: Song Shuai <songshuaishuai at tinylab.org>
---
 Makefile       |   2 +-
 arch/riscv64.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++
 makedumpfile.c |  14 ++++
 makedumpfile.h | 107 ++++++++++++++++++++++++
 4 files changed, 341 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv64.c

diff --git a/Makefile b/Makefile
index 0608035..1d0644c 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ endif
 SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h
 SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c detect_cycle.c
 OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART))
-SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/loongarch64.c
+SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/loongarch64.c arch/riscv64.c
 OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH))
 
 LIBS = -ldw -lbz2 -ldl -lelf -lz
diff --git a/arch/riscv64.c b/arch/riscv64.c
new file mode 100644
index 0000000..b4101e7
--- /dev/null
+++ b/arch/riscv64.c
@@ -0,0 +1,219 @@
+/*
+ * riscv64.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifdef __riscv64__
+
+#include "../print_info.h"
+#include "../elf_info.h"
+#include "../makedumpfile.h"
+
+int
+get_phys_base_riscv64(void)
+{
+	if (NUMBER(phys_ram_base) != NOT_FOUND_NUMBER)
+		info->phys_base = NUMBER(phys_ram_base);
+	else
+		/* In case that you are using qemu rv64 env */
+		info->phys_base = 0x80200000;
+
+	DEBUG_MSG("phys_base    : %lx\n", info->phys_base);
+	return TRUE;
+}
+
+int
+get_machdep_info_riscv64(void)
+{
+
+	if(NUMBER(va_bits) == NOT_FOUND_NUMBER ||  NUMBER(page_offset) == NOT_FOUND_NUMBER ||
+	   NUMBER(vmalloc_start) == NOT_FOUND_NUMBER || NUMBER(vmalloc_end) == NOT_FOUND_NUMBER ||
+	   NUMBER(vmemmap_start) == NOT_FOUND_NUMBER ||  NUMBER(vmemmap_end) == NOT_FOUND_NUMBER ||
+	   NUMBER(modules_vaddr) == NOT_FOUND_NUMBER ||  NUMBER(modules_end) == NOT_FOUND_NUMBER ||
+	   NUMBER(kernel_link_addr) == NOT_FOUND_NUMBER || NUMBER(va_kernel_pa_offset) == NOT_FOUND_NUMBER)
+		return FALSE;
+
+	if (NUMBER(MAX_PHYSMEM_BITS) != NOT_FOUND_NUMBER)
+		info->max_physmem_bits = NUMBER(MAX_PHYSMEM_BITS);
+	else
+		info->max_physmem_bits = _MAX_PHYSMEM_BITS;
+
+	if (NUMBER(SECTION_SIZE_BITS) != NOT_FOUND_NUMBER)
+		info->section_size_bits = NUMBER(SECTION_SIZE_BITS);
+	else
+		info->section_size_bits = _SECTION_SIZE_BITS;
+
+	info->page_offset = NUMBER(page_offset);
+
+	DEBUG_MSG("va_bits    : %ld\n", NUMBER(va_bits));
+	DEBUG_MSG("page_offset    : %lx\n", NUMBER(page_offset));
+	DEBUG_MSG("vmalloc_start    : %lx\n", NUMBER(vmalloc_start));
+	DEBUG_MSG("vmalloc_end    : %lx\n", NUMBER(vmalloc_end));
+	DEBUG_MSG("vmemmap_start    : %lx\n", NUMBER(vmemmap_start));
+	DEBUG_MSG("vmemmap_end    : %lx\n", NUMBER(vmemmap_end));
+	DEBUG_MSG("modules_vaddr    : %lx\n", NUMBER(modules_vaddr));
+	DEBUG_MSG("modules_end    : %lx\n", NUMBER(modules_end));
+	DEBUG_MSG("kernel_link_addr    : %lx\n", NUMBER(kernel_link_addr));
+	DEBUG_MSG("va_kernel_pa_offset    : %lx\n", NUMBER(va_kernel_pa_offset));
+
+	return TRUE;
+}
+
+/*
+ * For direct memory mapping
+ */
+
+#define VTOP(X) ({ 									\
+	ulong _X = X;									\
+	(_X) >= NUMBER(kernel_link_addr) ? ((_X) - (NUMBER(va_kernel_pa_offset))):	\
+	((_X) - PAGE_OFFSET + (info->phys_base));					\
+	})
+
+static unsigned long long
+vtop_riscv64(pgd_t * pgd, unsigned long vaddr, long va_bits)
+{
+	unsigned long long paddr = NOT_PADDR;
+	pgd_t *pgda;
+	p4d_t *p4da;
+	pud_t *puda;
+	pmd_t *pmda;
+	pte_t *ptea;
+	ulong pt_val, pt_phys;
+
+#define pgd_index(X) ((va_bits == VA_BITS_SV57) ? pgd_index_l5(X) : 	\
+	((va_bits == VA_BITS_SV48) ? pgd_index_l4(X) : pgd_index_l3(X)))
+
+	/* PGD */
+	pgda = (pgd_t *)(pgd) + pgd_index(vaddr);
+	if (!readmem(PADDR, (unsigned long long)pgda, &pt_val, sizeof(pt_val))) {
+		ERRMSG("Can't read pgd\n");
+		goto invalid;
+	}
+
+	pt_val &= PTE_PFN_PROT_MASK;
+
+	if (!(pt_val & _PAGE_PRESENT)) {
+		ERRMSG("Can't get a valid pgd.\n");
+		goto invalid;
+	}
+
+	pt_phys = (pt_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
+
+	if(pt_val & _PAGE_LEAF)
+		goto out;
+
+	if(va_bits == VA_BITS_SV57)
+		goto p4d;
+	else if (va_bits == VA_BITS_SV48)
+		goto pud;
+	else
+		goto pmd;
+p4d:
+	/* P4D */
+	p4da = (p4d_t *)(pt_phys) + p4d_index(vaddr);
+	if (!readmem(PADDR, (unsigned long long)p4da, &pt_val, sizeof(pt_val))) {
+		ERRMSG("Can't read p4d\n");
+		goto invalid;
+	}
+
+	pt_val &= PTE_PFN_PROT_MASK;
+
+	if (!(pt_val & _PAGE_PRESENT)) {
+		ERRMSG("Can't get a valid p4d.\n");
+		goto invalid;
+	}
+
+	pt_phys = (pt_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
+
+	if(pt_val & _PAGE_LEAF)
+		goto out;
+pud:
+	/* PUD */
+	puda = (pud_t *)(pt_phys) + pud_index(vaddr);
+	if (!readmem(PADDR, (unsigned long long)puda, &pt_val, sizeof(pt_val))) {
+		ERRMSG("Can't read pud\n");
+		goto invalid;
+	}
+
+	pt_val &= PTE_PFN_PROT_MASK;
+
+	if (!(pt_val & _PAGE_PRESENT)) {
+		ERRMSG("Can't get a valid pud.\n");
+		goto invalid;
+	}
+
+	pt_phys = (pt_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
+
+	if(pt_val & _PAGE_LEAF)
+		goto out;
+pmd:
+	/* PMD */
+	pmda = (pmd_t *)(pt_phys) + pmd_index(vaddr);
+	if (!readmem(PADDR, (unsigned long long)pmda, &pt_val, sizeof(pt_val))) {
+		ERRMSG("Can't read pmd\n");
+		goto invalid;
+	}
+
+	pt_val &= PTE_PFN_PROT_MASK;
+
+	if (!(pt_val & _PAGE_PRESENT)) {
+		ERRMSG("Can't get a valid pmd.\n");
+		goto invalid;
+	}
+
+	pt_phys = (pt_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
+
+	if(pt_val & _PAGE_LEAF)
+		goto out;
+
+	/* PTE */
+	ptea = (pte_t *)(pt_phys) + pte_index(vaddr);
+	if (!readmem(PADDR, (unsigned long long)ptea, &pt_val, sizeof(pt_val))) {
+		ERRMSG("Can't read pte\n");
+		goto invalid;
+	}
+
+	pt_val &= PTE_PFN_PROT_MASK;
+
+	if (!(pt_val & _PAGE_PRESENT)) {
+		ERRMSG("Can't get a valid pte.\n");
+		goto invalid;
+	}
+
+	pt_phys = (pt_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
+
+out:
+	paddr = pt_phys + PAGEOFFSET(vaddr);
+invalid:
+	return paddr;
+}
+
+unsigned long long
+vaddr_to_paddr_riscv64(unsigned long vaddr)
+{
+	unsigned long long swapper_phys;
+
+	if (vaddr >= PAGE_OFFSET &&
+	    !(vaddr >= NUMBER(modules_vaddr) && vaddr <= NUMBER(modules_end))){
+		return VTOP(vaddr);
+	}
+
+	if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+		ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
+		return NOT_PADDR;
+	}
+
+	swapper_phys = VTOP(SYMBOL(swapper_pg_dir));
+
+	return vtop_riscv64((pgd_t *)swapper_phys, vaddr, NUMBER(va_bits));
+}
+
+#endif /* __riscv64__ */
diff --git a/makedumpfile.c b/makedumpfile.c
index cadc596..42d5565 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -2972,6 +2972,20 @@ read_vmcoreinfo(void)
 	READ_NUMBER_UNSIGNED("kimage_voffset", kimage_voffset);
 #endif
 
+#ifdef __riscv64__
+	READ_NUMBER("VA_BITS", va_bits);
+	READ_NUMBER_UNSIGNED("phys_ram_base", phys_ram_base);
+	READ_NUMBER_UNSIGNED("PAGE_OFFSET", page_offset);
+	READ_NUMBER_UNSIGNED("VMALLOC_START", vmalloc_start);
+	READ_NUMBER_UNSIGNED("VMALLOC_END", vmalloc_end);
+	READ_NUMBER_UNSIGNED("VMEMMAP_START", vmemmap_start);
+	READ_NUMBER_UNSIGNED("VMEMMAP_END", vmemmap_end);
+	READ_NUMBER_UNSIGNED("MODULES_VADDR", modules_vaddr);
+	READ_NUMBER_UNSIGNED("MODULES_END", modules_end);
+	READ_NUMBER_UNSIGNED("KERNEL_LINK_ADDR", kernel_link_addr);
+	READ_NUMBER_UNSIGNED("va_kernel_pa_offset", va_kernel_pa_offset);
+#endif
+
 	READ_NUMBER("HUGETLB_PAGE_DTOR", HUGETLB_PAGE_DTOR);
 
 	return TRUE;
diff --git a/makedumpfile.h b/makedumpfile.h
index 85e5a49..f021423 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1046,6 +1046,77 @@ typedef unsigned long pgd_t;
 
 #endif /* loongarch64 */
 
+#ifdef __riscv64__
+/*
+ * Referencing the riscv64_is_kvaddr() in Crash-utility,
+ * set the vmemmap start address as the lowest kernel virtual base.
+ * */
+#define KVBASE			(NUMBER(vmemmap_start))
+#define _SECTION_SIZE_BITS	(27)
+#define _MAX_PHYSMEM_BITS	(56)
+
+typedef ulong pgd_t;
+typedef ulong p4d_t;
+typedef ulong pud_t;
+typedef ulong pmd_t;
+typedef ulong pte_t;
+
+/* arch/riscv/include/asm/pgtable-64.h */
+
+#define PGD_SHIFT_L3		(30)
+#define PGD_SHIFT_L4		(39)
+#define PGD_SHIFT_L5		(48)
+
+#define P4D_SHIFT		(39)
+#define PUD_SHIFT		(30)
+#define PMD_SHIFT		(21)
+
+#define PTRS_PER_PGD		(512)
+#define PTRS_PER_P4D		(512)
+#define PTRS_PER_PUD		(512)
+#define PTRS_PER_PMD		(512)
+#define PTRS_PER_PTE		(512)
+
+/*
+ * 3/4/5-levels pg indexs
+ */
+#define pgd_index_l3(addr)	(((addr) >> PGD_SHIFT_L3) & (PTRS_PER_PGD - 1))
+#define pgd_index_l4(addr)	(((addr) >> PGD_SHIFT_L4) & (PTRS_PER_PGD - 1))
+#define pgd_index_l5(addr)	(((addr) >> PGD_SHIFT_L5) & (PTRS_PER_PGD - 1))
+#define p4d_index(addr)		(((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1))
+#define pud_index(addr)		(((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
+#define pmd_index(addr)		(((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+#define pte_index(addr)		(((addr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
+
+/* arch/riscv/include/asm/pgtable-bits.h */
+
+#define _PAGE_PRESENT	(1 << 0)
+#define _PAGE_READ	(1 << 1)	/* Readable */
+#define _PAGE_WRITE	(1 << 2)	/* Writable */
+#define _PAGE_EXEC	(1 << 3)	/* Executable */
+#define _PAGE_USER	(1 << 4)	/* User */
+#define _PAGE_GLOBAL	(1 << 5)	/* Global */
+#define _PAGE_ACCESSED	(1 << 6)	/* Set by hardware on any access */
+#define _PAGE_DIRTY	(1 << 7)	/* Set by hardware on any write */
+#define _PAGE_SOFT	(1 << 8)	/* Reserved for software */
+
+#define _PAGE_PFN_SHIFT	(10)
+#define _PAGE_LEAF	(_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
+
+/*
+ * Mask for bit 0~53(PROT and PPN) of PTE
+ * 63 6261  60    54  53 10  9 8 7 6 5 4 3 2 1 0
+ * N  PBMT  Reserved  P P N  RSW D A G U X W R V
+ */
+#define PTE_PFN_PROT_MASK	0x3FFFFFFFFFFFFF
+
+#define VA_BITS_SV39	(39)
+#define VA_BITS_SV48	(48)
+#define VA_BITS_SV57	(57)
+
+#endif /* riscv64 */
+
+
 /*
  * The function of dependence on machine
  */
@@ -1233,6 +1304,22 @@ unsigned long long vaddr_to_paddr_loongarch64(unsigned long vaddr);
 #define arch_crashkernel_mem_size()	stub_false()
 #endif /* loongarch64 */
 
+#ifdef __riscv64__
+int get_phys_base_riscv64(void);
+int get_machdep_info_riscv64(void);
+unsigned long long vaddr_to_paddr_riscv64(unsigned long vaddr);
+#define paddr_to_vaddr_riscv64(X) ((X) + PAGE_OFFSET - info->phys_base)
+#define find_vmemmap()		stub_false()
+#define get_phys_base()		get_phys_base_riscv64()
+#define get_machdep_info()	get_machdep_info_riscv64()
+#define get_versiondep_info()	stub_true()
+#define get_kaslr_offset(X)	stub_false()
+#define vaddr_to_paddr(X)	vaddr_to_paddr_riscv64(X)
+#define paddr_to_vaddr(X)	paddr_to_vaddr_riscv64(X)
+#define is_phys_addr(X)		stub_true_ul(X)
+#define arch_crashkernel_mem_size()	stub_false()
+#endif /* riscv64 */
+
 typedef unsigned long long mdf_pfn_t;
 
 #ifndef ARCH_PFN_OFFSET
@@ -2151,6 +2238,20 @@ struct number_table {
 	long	TCR_EL1_T1SZ;
 	unsigned long	PHYS_OFFSET;
 	unsigned long	kimage_voffset;
+#endif
+	/**/
+#ifdef __riscv64__
+	long va_bits;
+	unsigned long phys_ram_base;
+	unsigned long page_offset;
+	unsigned long vmalloc_start;
+	unsigned long vmalloc_end;
+	unsigned long vmemmap_start;
+	unsigned long vmemmap_end;
+	unsigned long modules_vaddr;
+	unsigned long modules_end;
+	unsigned long kernel_link_addr;
+	unsigned long va_kernel_pa_offset;
 #endif
 };
 
@@ -2390,6 +2491,12 @@ int get_xen_info_ia64(void);
 #define get_xen_info_arch(X) FALSE
 #endif /* loongarch64 */
 
+#ifdef __riscv64__ /* riscv64 */
+#define kvtop_xen(X)	FALSE
+#define get_xen_basic_info_arch(X) FALSE
+#define get_xen_info_arch(X) FALSE
+#endif /* riscv64 */
+
 struct cycle {
 	mdf_pfn_t start_pfn;
 	mdf_pfn_t end_pfn;
-- 
2.20.1




More information about the kexec mailing list