diff --git a/lib/libkvm/kvm_arm.h b/lib/libkvm/kvm_arm.h index 844e158d84c6..096a6b1fbc6a 100644 --- a/lib/libkvm/kvm_arm.h +++ b/lib/libkvm/kvm_arm.h @@ -67,13 +67,16 @@ typedef uint32_t arm_pt_entry_t; #define ARM_L1_C_ADDR_MASK 0xfffffc00 /* phys address of L2 Table */ #define ARM_L2_TYPE_INV 0x00 /* Invalid (fault) */ -#define ARM_L2_TYPE_L 0x01 /* Large Page - 64k - not used yet*/ -#define ARM_L2_TYPE_S 0x02 /* Small Page - 4 */ +#define ARM_L2_TYPE_L 0x01 /* Large Page - 64k */ +#define ARM_L2_TYPE_S 0x02 /* Small Page - 4k */ +#define ARM_L2_TYPE_T 0x03 /* Tiny Page - 1k - not used */ #define ARM_L2_TYPE_MASK 0x03 #define ARM_L2_ADDR_BITS 0x000ff000 /* L2 PTE address bits */ #ifdef __arm__ +#include + _Static_assert(PAGE_SHIFT == ARM_PAGE_SHIFT, "PAGE_SHIFT mismatch"); _Static_assert(PAGE_SIZE == ARM_PAGE_SIZE, "PAGE_SIZE mismatch"); _Static_assert(PAGE_MASK == ARM_PAGE_MASK, "PAGE_MASK mismatch"); @@ -99,6 +102,9 @@ _Static_assert(L1_C_ADDR_MASK == ARM_L1_C_ADDR_MASK, "L1_C_ADDR_MASK mismatch"); _Static_assert(L2_TYPE_INV == ARM_L2_TYPE_INV, "L2_TYPE_INV mismatch"); _Static_assert(L2_TYPE_L == ARM_L2_TYPE_L, "L2_TYPE_L mismatch"); _Static_assert(L2_TYPE_S == ARM_L2_TYPE_S, "L2_TYPE_S mismatch"); +#if __ARM_ARCH < 6 +_Static_assert(L2_TYPE_T == ARM_L2_TYPE_T, "L2_TYPE_T mismatch"); +#endif _Static_assert(L2_TYPE_MASK == ARM_L2_TYPE_MASK, "L2_TYPE_MASK mismatch"); _Static_assert(L2_ADDR_BITS == ARM_L2_ADDR_BITS, "L2_ADDR_BITS mismatch"); #endif diff --git a/lib/libkvm/kvm_minidump_arm.c b/lib/libkvm/kvm_minidump_arm.c index 9e9cd6726804..4d7666666626 100644 --- a/lib/libkvm/kvm_minidump_arm.c +++ b/lib/libkvm/kvm_minidump_arm.c @@ -112,6 +112,12 @@ _arm_minidump_initvtop(kvm_t *kd) vmst->hdr.bitmapsize = _kvm32toh(kd, vmst->hdr.bitmapsize); vmst->hdr.ptesize = _kvm32toh(kd, vmst->hdr.ptesize); vmst->hdr.kernbase = _kvm32toh(kd, vmst->hdr.kernbase); + vmst->hdr.arch = _kvm32toh(kd, vmst->hdr.arch); + vmst->hdr.mmuformat = _kvm32toh(kd, vmst->hdr.mmuformat); + if (vmst->hdr.mmuformat == MINIDUMP_MMU_FORMAT_UNKNOWN) { + /* This is a safe default as 1K pages are not used. */ + vmst->hdr.mmuformat = MINIDUMP_MMU_FORMAT_V6; + } /* Skip header and msgbuf */ off = ARM_PAGE_SIZE + arm_round_page(vmst->hdr.msgbufsize); @@ -179,19 +185,27 @@ _arm_minidump_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) if (va >= vm->hdr.kernbase) { pteindex = (va - vm->hdr.kernbase) >> ARM_PAGE_SHIFT; pte = _kvm32toh(kd, ptemap[pteindex]); - if (!pte) { + if ((pte & ARM_L2_TYPE_MASK) == ARM_L2_TYPE_INV) { _kvm_err(kd, kd->program, "_arm_minidump_kvatop: pte not valid"); goto invalid; } if ((pte & ARM_L2_TYPE_MASK) == ARM_L2_TYPE_L) { - offset = va & ARM_L2_L_OFFSET; - a = pte & ARM_L2_L_FRAME; - } else if ((pte & ARM_L2_TYPE_MASK) == ARM_L2_TYPE_S) { + /* 64K page -> convert to be like 4K page */ + offset = va & ARM_L2_S_OFFSET; + a = (pte & ARM_L2_L_FRAME) + + (va & ARM_L2_L_OFFSET & ARM_L2_S_FRAME); + } else { + if (kd->vmst->hdr.mmuformat == MINIDUMP_MMU_FORMAT_V4 && + (pte & ARM_L2_TYPE_MASK) == ARM_L2_TYPE_T) { + _kvm_err(kd, kd->program, + "_arm_minidump_kvatop: pte not supported"); + goto invalid; + } + /* 4K page */ offset = va & ARM_L2_S_OFFSET; a = pte & ARM_L2_S_FRAME; - } else - goto invalid; + } ofs = _kvm_hpt_find(&vm->hpt, a); if (ofs == -1) { @@ -203,7 +217,6 @@ _arm_minidump_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) *pa = ofs + offset; return (ARM_PAGE_SIZE - offset); - } else _kvm_err(kd, kd->program, "_arm_minidump_kvatop: virtual " "address 0x%jx not minidumped", (uintmax_t)va); diff --git a/sys/arm/arm/minidump_machdep.c b/sys/arm/arm/minidump_machdep.c index 71e732ed929c..7a4abe467429 100644 --- a/sys/arm/arm/minidump_machdep.c +++ b/sys/arm/arm/minidump_machdep.c @@ -312,7 +312,12 @@ minidumpsys(struct dumperinfo *di) mdhdr.bitmapsize = vm_page_dump_size; mdhdr.ptesize = ptesize; mdhdr.kernbase = KERNBASE; - + mdhdr.arch = __ARM_ARCH; +#if __ARM_ARCH >= 6 + mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V6; +#else + mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V4; +#endif mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize, di->blocksize); diff --git a/sys/arm/include/minidump.h b/sys/arm/include/minidump.h index ad7a90a00edc..aea9ec470f43 100644 --- a/sys/arm/include/minidump.h +++ b/sys/arm/include/minidump.h @@ -28,11 +28,18 @@ */ #ifndef _MACHINE_MINIDUMP_H_ -#define _MACHINE_MINIDUMP_H_ 1 +#define _MACHINE_MINIDUMP_H_ #define MINIDUMP_MAGIC "minidump FreeBSD/arm" #define MINIDUMP_VERSION 1 +/* + * The first page of vmcore is dedicated to the following header. + * As the rest of the page is zeroed, any header extension can be + * done without version bumping. It should be taken into account + * only that new entries will be zero in old vmcores. + */ + struct minidumphdr { char magic[24]; uint32_t version; @@ -40,6 +47,13 @@ struct minidumphdr { uint32_t bitmapsize; uint32_t ptesize; uint32_t kernbase; + uint32_t arch; + uint32_t mmuformat; }; +#define MINIDUMP_MMU_FORMAT_UNKNOWN 0 +#define MINIDUMP_MMU_FORMAT_V4 1 +#define MINIDUMP_MMU_FORMAT_V6 2 +#define MINIDUMP_MMU_FORMAT_V6_LPAE 3 + #endif /* _MACHINE_MINIDUMP_H_ */