git: f2e36d47e3be - main - Make page size dynamic in libkvm for arm64
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 15 Mar 2022 11:10:03 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=f2e36d47e3be31ce819e28d8178b6695556a9e53 commit f2e36d47e3be31ce819e28d8178b6695556a9e53 Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2022-03-14 12:40:25 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2022-03-15 09:52:15 +0000 Make page size dynamic in libkvm for arm64 To allow for a future 16k or 64k page size we need to tell libkvm which is being used. Add a flag field in unused space in minidumphdr and use it to signal between the different options. Reviewed by: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D34548 --- lib/libkvm/kvm_aarch64.h | 15 ++++---- lib/libkvm/kvm_minidump_aarch64.c | 79 ++++++++++++++++++++++++++------------ sys/arm64/arm64/minidump_machdep.c | 1 + sys/arm64/include/minidump.h | 7 +++- 4 files changed, 69 insertions(+), 33 deletions(-) diff --git a/lib/libkvm/kvm_aarch64.h b/lib/libkvm/kvm_aarch64.h index fbbd869ab425..fdbdafde025b 100644 --- a/lib/libkvm/kvm_aarch64.h +++ b/lib/libkvm/kvm_aarch64.h @@ -35,9 +35,11 @@ typedef uint64_t aarch64_physaddr_t; typedef uint64_t aarch64_pte_t; -#define AARCH64_PAGE_SHIFT 12 -#define AARCH64_PAGE_SIZE (1 << AARCH64_PAGE_SHIFT) -#define AARCH64_PAGE_MASK (AARCH64_PAGE_SIZE - 1) +#define AARCH64_PAGE_SHIFT_4K 12 +#define AARCH64_PAGE_SIZE_4K (1 << AARCH64_PAGE_SHIFT_4K) + +#define AARCH64_PAGE_SHIFT_16K 14 +#define AARCH64_PAGE_SIZE_16K (1 << AARCH64_PAGE_SHIFT_16K) /* Source: arm64/include/pte.h */ #define AARCH64_ATTR_MASK 0xfffc000000000fff @@ -49,17 +51,14 @@ typedef uint64_t aarch64_pte_t; #define AARCH64_ATTR_DESCR_MASK 3 -#define AARCH64_L3_SHIFT 12 +#define AARCH64_L3_SHIFT_4K 12 +#define AARCH64_L3_SHIFT_16K 14 #define AARCH64_L3_PAGE 0x3 #ifdef __aarch64__ -_Static_assert(PAGE_SHIFT == AARCH64_PAGE_SHIFT, "PAGE_SHIFT mismatch"); -_Static_assert(PAGE_SIZE == AARCH64_PAGE_SIZE, "PAGE_SIZE mismatch"); -_Static_assert(PAGE_MASK == AARCH64_PAGE_MASK, "PAGE_MASK mismatch"); _Static_assert(ATTR_MASK == AARCH64_ATTR_MASK, "ATTR_MASK mismatch"); _Static_assert(ATTR_DESCR_MASK == AARCH64_ATTR_DESCR_MASK, "ATTR_DESCR_MASK mismatch"); -_Static_assert(L3_SHIFT == AARCH64_L3_SHIFT, "L3_SHIFT mismatch"); _Static_assert(L3_PAGE == AARCH64_L3_PAGE, "L3_PAGE mismatch"); #endif diff --git a/lib/libkvm/kvm_minidump_aarch64.c b/lib/libkvm/kvm_minidump_aarch64.c index 7fd4219fbf21..5e9ac739406f 100644 --- a/lib/libkvm/kvm_minidump_aarch64.c +++ b/lib/libkvm/kvm_minidump_aarch64.c @@ -47,10 +47,13 @@ __FBSDID("$FreeBSD$"); #include "kvm_private.h" #include "kvm_aarch64.h" -#define aarch64_round_page(x) roundup2((kvaddr_t)(x), AARCH64_PAGE_SIZE) +#define aarch64_round_page(x, size) roundup2((kvaddr_t)(x), size) +#define aarch64_trunc_page(x, size) rounddown2((kvaddr_t)(x), size) struct vmstate { struct minidumphdr hdr; + size_t page_size; + u_int l3_shift; }; static aarch64_pte_t @@ -102,7 +105,7 @@ _aarch64_minidump_initvtop(kvm_t *kd) } vmst->hdr.version = le32toh(vmst->hdr.version); - if (vmst->hdr.version != MINIDUMP_VERSION && vmst->hdr.version != 1) { + if (vmst->hdr.version > MINIDUMP_VERSION || vmst->hdr.version < 1) { _kvm_err(kd, kd->program, "wrong minidump version. " "Expected %d got %d", MINIDUMP_VERSION, vmst->hdr.version); return (-1); @@ -114,28 +117,56 @@ _aarch64_minidump_initvtop(kvm_t *kd) vmst->hdr.dmapphys = le64toh(vmst->hdr.dmapphys); vmst->hdr.dmapbase = le64toh(vmst->hdr.dmapbase); vmst->hdr.dmapend = le64toh(vmst->hdr.dmapend); - vmst->hdr.dumpavailsize = vmst->hdr.version == MINIDUMP_VERSION ? - le32toh(vmst->hdr.dumpavailsize) : 0; + /* dumpavailsize added in version 2 */ + if (vmst->hdr.version >= 2) { + vmst->hdr.dumpavailsize = le32toh(vmst->hdr.dumpavailsize); + } else { + vmst->hdr.dumpavailsize = 0; + } + /* flags added in version 3 */ + if (vmst->hdr.version >= 3) { + vmst->hdr.flags = le32toh(vmst->hdr.flags); + } else { + vmst->hdr.flags = MINIDUMP_FLAG_PS_4K; + } + + switch (vmst->hdr.flags & MINIDUMP_FLAG_PS_MASK) { + case MINIDUMP_FLAG_PS_4K: + vmst->page_size = AARCH64_PAGE_SIZE_4K; + vmst->l3_shift = AARCH64_L3_SHIFT_4K; + break; + case MINIDUMP_FLAG_PS_16K: + vmst->page_size = AARCH64_PAGE_SIZE_16K; + vmst->l3_shift = AARCH64_L3_SHIFT_16K; + break; + default: + _kvm_err(kd, kd->program, "unknown page size flag %x", + vmst->hdr.flags & MINIDUMP_FLAG_PS_MASK); + return (-1); + } /* Skip header and msgbuf */ - dump_avail_off = AARCH64_PAGE_SIZE + aarch64_round_page(vmst->hdr.msgbufsize); + dump_avail_off = vmst->page_size + + aarch64_round_page(vmst->hdr.msgbufsize, vmst->page_size); /* Skip dump_avail */ - off = dump_avail_off + aarch64_round_page(vmst->hdr.dumpavailsize); + off = dump_avail_off + + aarch64_round_page(vmst->hdr.dumpavailsize, vmst->page_size); /* build physical address lookup table for sparse pages */ - sparse_off = off + aarch64_round_page(vmst->hdr.bitmapsize) + - aarch64_round_page(vmst->hdr.pmapsize); + sparse_off = off + + aarch64_round_page(vmst->hdr.bitmapsize, vmst->page_size) + + aarch64_round_page(vmst->hdr.pmapsize, vmst->page_size); if (_kvm_pt_init(kd, vmst->hdr.dumpavailsize, dump_avail_off, - vmst->hdr.bitmapsize, off, sparse_off, AARCH64_PAGE_SIZE) == -1) { + vmst->hdr.bitmapsize, off, sparse_off, vmst->page_size) == -1) { return (-1); } - off += aarch64_round_page(vmst->hdr.bitmapsize); + off += aarch64_round_page(vmst->hdr.bitmapsize, vmst->page_size); if (_kvm_pmap_init(kd, vmst->hdr.pmapsize, off) == -1) { return (-1); } - off += aarch64_round_page(vmst->hdr.pmapsize); + off += aarch64_round_page(vmst->hdr.pmapsize, vmst->page_size); return (0); } @@ -151,12 +182,12 @@ _aarch64_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) off_t ofs; vm = kd->vmst; - offset = va & AARCH64_PAGE_MASK; + offset = va & (kd->vmst->page_size - 1); if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) { - a = (va - vm->hdr.dmapbase + vm->hdr.dmapphys) & - ~AARCH64_PAGE_MASK; - ofs = _kvm_pt_find(kd, a, AARCH64_PAGE_SIZE); + a = aarch64_trunc_page(va - vm->hdr.dmapbase + vm->hdr.dmapphys, + kd->vmst->page_size); + ofs = _kvm_pt_find(kd, a, kd->vmst->page_size); if (ofs == -1) { _kvm_err(kd, kd->program, "_aarch64_minidump_vatop: " "direct map address 0x%jx not in minidump", @@ -164,9 +195,9 @@ _aarch64_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) goto invalid; } *pa = ofs + offset; - return (AARCH64_PAGE_SIZE - offset); + return (kd->vmst->page_size - offset); } else if (va >= vm->hdr.kernbase) { - l3_index = (va - vm->hdr.kernbase) >> AARCH64_L3_SHIFT; + l3_index = (va - vm->hdr.kernbase) >> kd->vmst->l3_shift; if (l3_index >= vm->hdr.pmapsize / sizeof(l3)) goto invalid; l3 = _aarch64_pte_get(kd, l3_index); @@ -176,7 +207,7 @@ _aarch64_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) goto invalid; } a = l3 & ~AARCH64_ATTR_MASK; - ofs = _kvm_pt_find(kd, a, AARCH64_PAGE_SIZE); + ofs = _kvm_pt_find(kd, a, kd->vmst->page_size); if (ofs == -1) { _kvm_err(kd, kd->program, "_aarch64_minidump_vatop: " "physical address 0x%jx not in minidump", @@ -184,7 +215,7 @@ _aarch64_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) goto invalid; } *pa = ofs + offset; - return (AARCH64_PAGE_SIZE - offset); + return (kd->vmst->page_size - offset); } else { _kvm_err(kd, kd->program, "_aarch64_minidump_vatop: virtual address 0x%jx not minidumped", @@ -252,26 +283,26 @@ _aarch64_minidump_walk_pages(kvm_t *kd, kvm_walk_pages_cb_t *cb, void *arg) if ((pte & AARCH64_ATTR_DESCR_MASK) != AARCH64_L3_PAGE) continue; - va = vm->hdr.kernbase + (pteindex << AARCH64_L3_SHIFT); + va = vm->hdr.kernbase + (pteindex << kd->vmst->l3_shift); pa = pte & ~AARCH64_ATTR_MASK; dva = vm->hdr.dmapbase + pa; if (!_kvm_visit_cb(kd, cb, arg, pa, va, dva, - _aarch64_entry_to_prot(pte), AARCH64_PAGE_SIZE, 0)) { + _aarch64_entry_to_prot(pte), kd->vmst->page_size, 0)) { goto out; } } while (_kvm_bitmap_next(&bm, &bmindex)) { - pa = _kvm_bit_id_pa(kd, bmindex, AARCH64_PAGE_SIZE); + pa = _kvm_bit_id_pa(kd, bmindex, kd->vmst->page_size); if (pa == _KVM_PA_INVALID) break; dva = vm->hdr.dmapbase + pa; - if (vm->hdr.dmapend < (dva + AARCH64_PAGE_SIZE)) + if (vm->hdr.dmapend < (dva + kd->vmst->page_size)) break; va = 0; prot = VM_PROT_READ | VM_PROT_WRITE; if (!_kvm_visit_cb(kd, cb, arg, pa, va, dva, - prot, AARCH64_PAGE_SIZE, 0)) { + prot, kd->vmst->page_size, 0)) { goto out; } } diff --git a/sys/arm64/arm64/minidump_machdep.c b/sys/arm64/arm64/minidump_machdep.c index ac5a7b271b85..e05a19fc1c41 100644 --- a/sys/arm64/arm64/minidump_machdep.c +++ b/sys/arm64/arm64/minidump_machdep.c @@ -239,6 +239,7 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state) mdhdr.dmapbase = DMAP_MIN_ADDRESS; mdhdr.dmapend = DMAP_MAX_ADDRESS; mdhdr.dumpavailsize = round_page(sizeof(dump_avail)); + mdhdr.flags = MINIDUMP_FLAG_PS_4K; dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_AARCH64_VERSION, dumpsize); diff --git a/sys/arm64/include/minidump.h b/sys/arm64/include/minidump.h index 87aaffc5ec87..c27d2c71bc12 100644 --- a/sys/arm64/include/minidump.h +++ b/sys/arm64/include/minidump.h @@ -31,7 +31,7 @@ #define _MACHINE_MINIDUMP_H_ 1 #define MINIDUMP_MAGIC "minidump FreeBSD/arm64" -#define MINIDUMP_VERSION 2 +#define MINIDUMP_VERSION 3 struct minidumphdr { char magic[24]; @@ -44,6 +44,11 @@ struct minidumphdr { uint64_t dmapbase; uint64_t dmapend; uint32_t dumpavailsize; +#define MINIDUMP_FLAG_PS_MASK (3 << 0) +#define MINIDUMP_FLAG_PS_4K (0 << 0) +#define MINIDUMP_FLAG_PS_16K (1 << 0) +/* MINIDUMP_FLAG_PS_64K (2 << 0) */ + uint32_t flags; }; #endif /* _MACHINE_MINIDUMP_H_ */