Page MenuHomeFreeBSD

D59743.id.diff
No OneTemporary

D59743.id.diff

diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile
--- a/lib/libkvm/Makefile
+++ b/lib/libkvm/Makefile
@@ -13,7 +13,8 @@
kvm_i386.c kvm_minidump_i386.c \
kvm_powerpc.c kvm_powerpc64.c \
kvm_minidump_riscv.c \
- kvm_minidump_powerpc64.c kvm_minidump_powerpc64_hpt.c
+ kvm_minidump_powerpc64.c kvm_minidump_powerpc64_hpt.c \
+ kvm_minidump_powerpc64_radix.c
INCS= kvm.h
LIBADD= elf
diff --git a/lib/libkvm/kvm_minidump_powerpc64.c b/lib/libkvm/kvm_minidump_powerpc64.c
--- a/lib/libkvm/kvm_minidump_powerpc64.c
+++ b/lib/libkvm/kvm_minidump_powerpc64.c
@@ -131,6 +131,8 @@
if (strcmp(mmu_name, PPC64_MMU_G5) == 0 ||
strcmp(mmu_name, PPC64_MMU_PHYP) == 0)
PPC64_MMU_OPS(kd) = ppc64_mmu_ops_hpt;
+ else if (strcmp(mmu_name, PPC64_MMU_RADIX) == 0)
+ PPC64_MMU_OPS(kd) = ppc64_mmu_ops_radix;
else {
_kvm_err(kd, kd->program, "unsupported MMU: %s", mmu_name);
goto failed;
diff --git a/lib/libkvm/kvm_minidump_powerpc64_radix.c b/lib/libkvm/kvm_minidump_powerpc64_radix.c
new file mode 100644
--- /dev/null
+++ b/lib/libkvm/kvm_minidump_powerpc64_radix.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2026 FreeBSD Foundation
+ *
+ * This software was developed by Minsoo Choo under sponsorship from the
+ * FreeBSD Foundation.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <vm/vm.h>
+
+#include <kvm.h>
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "../../sys/powerpc/include/minidump.h"
+#include "kvm_private.h"
+#include "kvm_powerpc64.h"
+
+/* Radix tree geometry. */
+#define RADIX_ROOT_SHIFT 16
+#define RADIX_ROOT_SIZE (1UL << RADIX_ROOT_SHIFT)
+#define RADIX_ROOT_ENTRIES (RADIX_ROOT_SIZE / sizeof(uint64_t))
+#define RADIX_ENTRIES (PPC64_PAGE_SIZE / sizeof(uint64_t))
+#define RADIX_INDEX_MASK (RADIX_ENTRIES - 1)
+
+#define RADIX_L1_SHIFT 39
+#define RADIX_L2_SHIFT 30
+#define RADIX_L3_SHIFT 21
+
+/* Radix PTE fields. Radix PTEs are stored in big-endian byte order. */
+#define RPTE_VALID 0x8000000000000000ULL
+#define RPTE_LEAF 0x4000000000000000ULL
+#define RPTE_RPN_MASK 0x00fffffffffff000ULL
+#define RPDE_NLB_MASK 0x00ffffffffffff00ULL
+#define RPTE_EAA_R 0x0000000000000004ULL
+#define RPTE_EAA_W 0x0000000000000002ULL
+#define RPTE_EAA_X 0x0000000000000001ULL
+
+static int
+radix_root_entry(kvm_t *kd, u_long index, uint64_t *entry)
+{
+ uint64_t *p;
+
+ p = _kvm_pmap_get(kd, index, sizeof(*p));
+ if (p == NULL)
+ return (-1);
+ *entry = be64toh(*p);
+ return (0);
+}
+
+static int
+radix_table_entry(kvm_t *kd, uint64_t pa, u_long index, uint64_t *entry)
+{
+ uint64_t *table;
+
+ table = _kvm_map_get(kd, pa, PPC64_PAGE_SIZE);
+ if (table == NULL) {
+ _kvm_err(kd, kd->program,
+ "radix page table page at 0x%jx was not dumped",
+ (uintmax_t)pa);
+ return (-1);
+ }
+ *entry = be64toh(table[index]);
+ return (0);
+}
+
+static int
+radix_lookup(kvm_t *kd, kvaddr_t va, uint64_t *pap, uint64_t *entryp,
+ uint64_t *pageszp)
+{
+ static const int shifts[] = {
+ RADIX_L1_SHIFT, RADIX_L2_SHIFT, RADIX_L3_SHIFT,
+ PPC64_PAGE_SHIFT
+ };
+ uint64_t entry, pa, pagesz;
+ u_long index;
+ u_int level;
+
+ index = (va >> RADIX_L1_SHIFT) & (RADIX_ROOT_ENTRIES - 1);
+ if (radix_root_entry(kd, index, &entry) != 0)
+ return (-1);
+ for (level = 0; level < nitems(shifts); level++) {
+ if ((entry & RPTE_VALID) == 0)
+ return (0);
+ pagesz = 1ULL << shifts[level];
+ if ((entry & RPTE_LEAF) != 0) {
+ pa = (entry & RPTE_RPN_MASK) & ~(pagesz - 1);
+ *pap = pa | (va & (pagesz - 1));
+ *entryp = entry;
+ *pageszp = pagesz;
+ return (1);
+ }
+ if (level == nitems(shifts) - 1)
+ return (0);
+ pa = entry & RPDE_NLB_MASK;
+ index = (va >> shifts[level + 1]) & RADIX_INDEX_MASK;
+ if (radix_table_entry(kd, pa, index, &entry) != 0)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+ppc64mmu_radix_init(kvm_t *kd)
+{
+ struct minidumphdr *hdr;
+
+ hdr = &kd->vmst->hdr;
+ if (hdr->pmapsize == 0) {
+ _kvm_err(kd, kd->program,
+ "radix minidump does not contain a page map");
+ return (-1);
+ }
+ if (hdr->pmapsize != RADIX_ROOT_SIZE) {
+ _kvm_err(kd, kd->program,
+ "unexpected radix page map size: %u", hdr->pmapsize);
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+ppc64mmu_radix_cleanup(kvm_t *kd __unused)
+{
+}
+
+static int
+ppc64mmu_radix_kvatop(kvm_t *kd, kvaddr_t va, off_t *offp)
+{
+ struct minidumphdr *hdr;
+ uint64_t entry, pa, pagesz;
+ off_t off;
+ int found;
+
+ hdr = &kd->vmst->hdr;
+ if (va < hdr->dmapbase)
+ va += hdr->startkernel - PPC64_KERNBASE;
+
+ if (va >= hdr->dmapbase && va <= hdr->dmapend)
+ pa = va - hdr->dmapbase;
+ else if (va >= hdr->kernbase) {
+ found = radix_lookup(kd, va, &pa, &entry, &pagesz);
+ if (found < 0)
+ return (0);
+ if (found == 0)
+ goto invalid;
+ } else
+ goto invalid;
+
+ off = _kvm_pt_find(kd, trunc_page(pa), PPC64_PAGE_SIZE);
+ if (off == -1)
+ goto invalid;
+ *offp = off + (pa & PPC64_PAGE_MASK);
+ return (PPC64_PAGE_SIZE - (pa & PPC64_PAGE_MASK));
+
+invalid:
+ _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va);
+ return (0);
+}
+
+#if ULONG_MAX > UINT32_MAX
+static vm_prot_t
+radix_entry_to_prot(uint64_t entry)
+{
+ vm_prot_t prot;
+
+ prot = 0;
+ if ((entry & (RPTE_EAA_R | RPTE_EAA_W)) != 0)
+ prot |= VM_PROT_READ;
+ if ((entry & RPTE_EAA_W) != 0)
+ prot |= VM_PROT_WRITE;
+ if ((entry & RPTE_EAA_X) != 0)
+ prot |= VM_PROT_EXECUTE;
+ return (prot);
+}
+
+static int
+radix_walk_table(kvm_t *kd, kvm_walk_pages_cb_t *cb, void *arg,
+ uint64_t table_pa, uint64_t va, u_int level)
+{
+ static const int shifts[] = {
+ RADIX_L2_SHIFT, RADIX_L3_SHIFT, PPC64_PAGE_SHIFT
+ };
+ struct minidumphdr *hdr;
+ uint64_t dva, entry, pa, pagesz, subva;
+ u_long i;
+
+ hdr = &kd->vmst->hdr;
+ for (i = 0; i < RADIX_ENTRIES; i++) {
+ if (radix_table_entry(kd, table_pa, i, &entry) != 0)
+ return (0);
+ if ((entry & RPTE_VALID) == 0)
+ continue;
+ subva = va | (i << shifts[level]);
+ if ((entry & RPTE_LEAF) == 0) {
+ if (level == nitems(shifts) - 1)
+ continue;
+ if (!radix_walk_table(kd, cb, arg,
+ entry & RPDE_NLB_MASK, subva, level + 1))
+ return (0);
+ continue;
+ }
+ if (subva < hdr->kernbase)
+ continue;
+ pagesz = 1ULL << shifts[level];
+ pa = (entry & RPTE_RPN_MASK) & ~(pagesz - 1);
+ dva = hdr->dmapbase + pa;
+ if (!_kvm_visit_cb(kd, cb, arg, pa, subva, dva,
+ radix_entry_to_prot(entry), pagesz, PPC64_PAGE_SIZE))
+ return (0);
+ }
+ return (1);
+}
+
+static int
+ppc64mmu_radix_walk_pages(kvm_t *kd, kvm_walk_pages_cb_t *cb, void *arg)
+{
+ struct minidumphdr *hdr;
+ uint64_t entry, pa, va;
+ u_long i;
+
+ hdr = &kd->vmst->hdr;
+ for (i = 0; i < RADIX_ROOT_ENTRIES; i++) {
+ if (radix_root_entry(kd, i, &entry) != 0)
+ return (0);
+ if ((entry & RPTE_VALID) == 0)
+ continue;
+ va = hdr->dmapbase | ((uint64_t)i << RADIX_L1_SHIFT);
+ if (va < hdr->kernbase)
+ continue;
+ if ((entry & RPTE_LEAF) != 0) {
+ pa = (entry & RPTE_RPN_MASK) &
+ ~((1ULL << RADIX_L1_SHIFT) - 1);
+ if (!_kvm_visit_cb(kd, cb, arg,
+ pa, va, hdr->dmapbase + pa,
+ radix_entry_to_prot(entry),
+ 1ULL << RADIX_L1_SHIFT, PPC64_PAGE_SIZE))
+ return (0);
+ continue;
+ }
+ if (!radix_walk_table(kd, cb, arg, entry & RPDE_NLB_MASK,
+ va, 0))
+ return (0);
+ }
+ return (1);
+}
+#else
+static int
+ppc64mmu_radix_walk_pages(kvm_t *kd, kvm_walk_pages_cb_t *cb __unused,
+ void *arg __unused)
+{
+
+ _kvm_err(kd, kd->program,
+ "walking powerpc64 radix pages requires a 64-bit host");
+ return (0);
+}
+#endif
+
+static struct ppc64_mmu_ops ops = {
+ .init = ppc64mmu_radix_init,
+ .cleanup = ppc64mmu_radix_cleanup,
+ .kvatop = ppc64mmu_radix_kvatop,
+ .walk_pages = ppc64mmu_radix_walk_pages,
+};
+
+struct ppc64_mmu_ops *ppc64_mmu_ops_radix = &ops;
diff --git a/lib/libkvm/kvm_powerpc64.h b/lib/libkvm/kvm_powerpc64.h
--- a/lib/libkvm/kvm_powerpc64.h
+++ b/lib/libkvm/kvm_powerpc64.h
@@ -49,6 +49,7 @@
#define PPC64_MMU_G5 "mmu_g5"
#define PPC64_MMU_PHYP "mmu_phyp"
+#define PPC64_MMU_RADIX "mmu_radix"
/* MMU interface */
#define PPC64_MMU_OPS(kd) (kd)->vmst->mmu.ops
@@ -75,5 +76,6 @@
};
extern struct ppc64_mmu_ops *ppc64_mmu_ops_hpt;
+extern struct ppc64_mmu_ops *ppc64_mmu_ops_radix;
#endif /* !__KVM_POWERPC64_H__ */
diff --git a/lib/libkvm/tests/kvm_open2_test.c b/lib/libkvm/tests/kvm_open2_test.c
--- a/lib/libkvm/tests/kvm_open2_test.c
+++ b/lib/libkvm/tests/kvm_open2_test.c
@@ -39,8 +39,18 @@
#include <atf-c.h>
+#include "../../../sys/powerpc/include/minidump.h"
#include "kvm_test_common.h"
+#define PPC64_DMAP_BASE 0xc000000000000000ULL
+#define PPC64_KERN_BASE 0xc008000000000000ULL
+#define RADIX_ROOT_SIZE (1UL << 16)
+#define RADIX_ROOT_ENTRIES (RADIX_ROOT_SIZE / sizeof(uint64_t))
+#define RADIX_VALID 0x8000000000000000ULL
+#define RADIX_LEAF 0x4000000000000000ULL
+#define RADIX_READ 0x4
+#define RADIX_WRITE 0x2
+
static int
unresolved_symbol(const char *name __unused, kvaddr_t *value __unused)
{
@@ -90,6 +100,91 @@
ATF_REQUIRE(close(fd) == 0);
}
+static void
+write_all(int fd, const void *buf, size_t len)
+{
+ const char *p;
+ ssize_t n;
+
+ p = buf;
+ while (len != 0) {
+ n = write(fd, p, len);
+ ATF_REQUIRE(n > 0);
+ p += n;
+ len -= n;
+ }
+}
+
+static void
+create_powerpc64le_radix_minidump(const char *path)
+{
+ struct minidumphdr hdr;
+ uint64_t entry, *dump_avail, *root;
+ uint8_t *page;
+ size_t root_index;
+ int fd, i;
+
+ dump_avail = calloc(1, PAGE_SIZE);
+ root = calloc(1, RADIX_ROOT_SIZE);
+ page = calloc(1, PAGE_SIZE);
+ ATF_REQUIRE(dump_avail != NULL);
+ ATF_REQUIRE(root != NULL);
+ ATF_REQUIRE(page != NULL);
+
+ memset(&hdr, 0, sizeof(hdr));
+ strlcpy(hdr.magic, MINIDUMP_MAGIC, sizeof(hdr.magic));
+ strlcpy(hdr.mmu_name, "mmu_radix", sizeof(hdr.mmu_name));
+ hdr.version = htole32(MINIDUMP_VERSION);
+ hdr.bitmapsize = htole32(PAGE_SIZE);
+ hdr.pmapsize = htole32(RADIX_ROOT_SIZE);
+ hdr.kernbase = htole64(PPC64_KERN_BASE);
+ hdr.kernend = htole64(PPC64_KERN_BASE + PAGE_SIZE);
+ hdr.dmapbase = htole64(PPC64_DMAP_BASE);
+ hdr.dmapend = htole64(PPC64_DMAP_BASE + 0x10000);
+ hdr.startkernel = htole64(PPC64_DMAP_BASE + 0x4000);
+ hdr.endkernel = htole64(PPC64_DMAP_BASE + 0x5000);
+ hdr.dumpavailsize = htole32(PAGE_SIZE);
+
+ dump_avail[0] = htole64(0);
+ dump_avail[1] = htole64(0x10000);
+
+ root_index = (PPC64_KERN_BASE >> 39) & (RADIX_ROOT_ENTRIES - 1);
+ root[root_index] = htobe64(RADIX_VALID | 0x1000 | 9);
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ ATF_REQUIRE(fd != -1);
+ memset(page, 0, PAGE_SIZE);
+ memcpy(page, &hdr, sizeof(hdr));
+ write_all(fd, page, PAGE_SIZE);
+ write_all(fd, dump_avail, PAGE_SIZE);
+ memset(page, 0, PAGE_SIZE);
+ for (i = 1; i <= 4; i++)
+ page[i / NBBY] |= 1U << (i % NBBY);
+ write_all(fd, page, PAGE_SIZE);
+ write_all(fd, root, RADIX_ROOT_SIZE);
+
+ /* L2, L3, and PTE pages, followed by the mapped data page. */
+ for (i = 1; i <= 3; i++) {
+ memset(page, 0, PAGE_SIZE);
+ if (i != 3)
+ entry = htobe64(RADIX_VALID | ((i + 1) * 0x1000) |
+ 9);
+ else
+ entry = htobe64(RADIX_VALID | RADIX_LEAF |
+ RADIX_READ | RADIX_WRITE | 0x4000);
+ memcpy(page, &entry, sizeof(entry));
+ write_all(fd, page, PAGE_SIZE);
+ }
+ memset(page, 0, PAGE_SIZE);
+ memcpy(page, "radix minidump", sizeof("radix minidump"));
+ write_all(fd, page, PAGE_SIZE);
+ ATF_REQUIRE(close(fd) == 0);
+
+ free(page);
+ free(root);
+ free(dump_avail);
+}
+
ATF_TC_WITHOUT_HEAD(kvm_open2_negative_test_nonexistent_corefile);
ATF_TC_BODY(kvm_open2_negative_test_nonexistent_corefile, tc)
{
@@ -167,6 +262,28 @@
ATF_CHECK_MATCH("wrong minidump version", errbuf);
}
+ATF_TC_WITHOUT_HEAD(kvm_open2_powerpc64le_radix_minidump);
+ATF_TC_BODY(kvm_open2_powerpc64le_radix_minidump, tc)
+{
+ char buf[sizeof("radix minidump")];
+ kvm_t *kd;
+
+ create_powerpc64le_kernel("kernel-radix");
+ create_powerpc64le_radix_minidump("vmcore-radix");
+ errbuf_clear();
+ kd = kvm_open2("kernel-radix", "vmcore-radix", O_RDONLY, errbuf,
+ unresolved_symbol);
+ ATF_REQUIRE_MSG(kd != NULL, "kvm_open2 failed: %s", errbuf);
+ ATF_REQUIRE_EQ(kvm_read2(kd, PPC64_KERN_BASE, buf, sizeof(buf)),
+ (ssize_t)sizeof(buf));
+ ATF_CHECK_STREQ(buf, "radix minidump");
+ memset(buf, 0, sizeof(buf));
+ ATF_REQUIRE_EQ(kvm_read2(kd, PPC64_DMAP_BASE + 0x4000, buf,
+ sizeof(buf)), (ssize_t)sizeof(buf));
+ ATF_CHECK_STREQ(buf, "radix minidump");
+ ATF_REQUIRE(kvm_close(kd) == 0);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -175,6 +292,7 @@
ATF_TP_ADD_TC(tp, kvm_open2_negative_test_nonexistent_corefile);
ATF_TP_ADD_TC(tp, kvm_open2_negative_test_nonexistent_execfile);
ATF_TP_ADD_TC(tp, kvm_open2_powerpc64le_minidump_probe);
+ ATF_TP_ADD_TC(tp, kvm_open2_powerpc64le_radix_minidump);
return (atf_no_error());
}
diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c
--- a/sys/powerpc/aim/mmu_radix.c
+++ b/sys/powerpc/aim/mmu_radix.c
@@ -121,6 +121,8 @@
extern int nkpt;
extern caddr_t crashdumpmap;
+extern unsigned char _etext[];
+extern unsigned char _end[];
#define RIC_FLUSH_TLB 0
#define RIC_FLUSH_PWC 1
@@ -493,6 +495,9 @@
static int mmu_radix_dev_direct_mapped(vm_paddr_t, vm_size_t);
static void mmu_radix_dumpsys_map(vm_paddr_t pa, size_t sz, void **va);
static void mmu_radix_scan_init(void);
+static size_t mmu_radix_scan_pmap(struct bitset *dump_bitset);
+static void *mmu_radix_dump_pmap_init(unsigned blkpgs);
+static void *mmu_radix_dump_pmap(void *ctx, void *buf, u_long *nbytes);
static void mmu_radix_cpu_bootstrap(int ap);
static void mmu_radix_tlbie_all(void);
@@ -515,6 +520,9 @@
.dev_direct_mapped = mmu_radix_dev_direct_mapped,
.dumpsys_pa_init = mmu_radix_scan_init,
.dumpsys_map_chunk = mmu_radix_dumpsys_map,
+ .dumpsys_scan_pmap = mmu_radix_scan_pmap,
+ .dumpsys_dump_pmap_init = mmu_radix_dump_pmap_init,
+ .dumpsys_dump_pmap = mmu_radix_dump_pmap,
.page_is_mapped = mmu_radix_page_is_mapped,
.ps_enabled = mmu_radix_ps_enabled,
.align_superpage = mmu_radix_align_superpage,
@@ -6171,6 +6179,155 @@
return (mem_valid(pa, size));
}
+static void
+mmu_radix_dump_add_range(struct bitset *dump_bitset, vm_paddr_t pa,
+ vm_size_t size)
+{
+ vm_paddr_t end;
+
+ end = pa + size;
+ for (; pa < end; pa += PAGE_SIZE) {
+ if (vm_phys_is_dumpable(pa))
+ vm_page_dump_add(dump_bitset, pa);
+ }
+}
+
+static void
+mmu_radix_dump_add_leaf(struct bitset *dump_bitset, vm_offset_t va,
+ vm_paddr_t pa, vm_size_t size, vm_offset_t kstart, vm_offset_t kend)
+{
+ vm_offset_t end, start;
+
+ /*
+ * Most DMAP mappings only provide aliases for memory already selected
+ * by the minidump bitmap. The relocated kernel image is the exception:
+ * its pages were allocated before regular minidump page tracking began.
+ */
+ if (va < VM_MIN_KERNEL_ADDRESS) {
+ end = va + size;
+ if (end <= kstart || va >= kend)
+ return;
+ start = MAX(va, kstart);
+ end = MIN(end, kend);
+ pa += start - va;
+ size = end - start;
+ }
+ mmu_radix_dump_add_range(dump_bitset, pa, size);
+}
+
+static size_t
+mmu_radix_scan_pmap(struct bitset *dump_bitset)
+{
+ pt_entry_t *l1, *l2, *l3, *pt;
+ pt_entry_t l1e, l2e, l3e, pte;
+ vm_offset_t kstart, kend, va1, va2, va3, va;
+ vm_paddr_t pa;
+ u_int i, j, k, l;
+
+ kstart = trunc_page((vm_offset_t)_etext);
+ kend = round_page((vm_offset_t)_end);
+ l1 = kernel_pmap->pm_pml1;
+
+ PMAP_LOCK(kernel_pmap);
+ for (i = 0; i < RADIX_PGD_SIZE / sizeof(*l1); i++) {
+ l1e = be64toh(l1[i]);
+ if ((l1e & RPTE_VALID) == 0)
+ continue;
+ va1 = DMAP_BASE_ADDRESS | ((vm_offset_t)i <<
+ L1_PAGE_SIZE_SHIFT);
+ if ((l1e & RPTE_LEAF) != 0) {
+ mmu_radix_dump_add_leaf(dump_bitset, va1,
+ l1e & RPTE_RPN_MASK, L1_PAGE_SIZE, kstart, kend);
+ continue;
+ }
+
+ pa = l1e & RPDE_NLB_MASK;
+ mmu_radix_dump_add_range(dump_bitset, pa, PAGE_SIZE);
+ l2 = PHYS_TO_DMAP(pa);
+ for (j = 0; j < NL2EPG; j++) {
+ l2e = be64toh(l2[j]);
+ if ((l2e & RPTE_VALID) == 0)
+ continue;
+ va2 = va1 | ((vm_offset_t)j << L2_PAGE_SIZE_SHIFT);
+ if ((l2e & RPTE_LEAF) != 0) {
+ mmu_radix_dump_add_leaf(dump_bitset, va2,
+ l2e & RPTE_RPN_MASK, L2_PAGE_SIZE, kstart,
+ kend);
+ continue;
+ }
+
+ pa = l2e & RPDE_NLB_MASK;
+ mmu_radix_dump_add_range(dump_bitset, pa, PAGE_SIZE);
+ l3 = PHYS_TO_DMAP(pa);
+ for (k = 0; k < NL3EPG; k++) {
+ l3e = be64toh(l3[k]);
+ if ((l3e & RPTE_VALID) == 0)
+ continue;
+ va3 = va2 | ((vm_offset_t)k <<
+ L3_PAGE_SIZE_SHIFT);
+ if ((l3e & RPTE_LEAF) != 0) {
+ mmu_radix_dump_add_leaf(dump_bitset, va3,
+ l3e & RPTE_RPN_MASK, L3_PAGE_SIZE,
+ kstart, kend);
+ continue;
+ }
+
+ pa = l3e & RPDE_NLB_MASK;
+ mmu_radix_dump_add_range(dump_bitset, pa,
+ PAGE_SIZE);
+ pt = PHYS_TO_DMAP(pa);
+ for (l = 0; l < RPTE_ENTRIES; l++) {
+ pte = be64toh(pt[l]);
+ if ((pte & (RPTE_VALID | RPTE_LEAF)) !=
+ (RPTE_VALID | RPTE_LEAF))
+ continue;
+ va = va3 | ((vm_offset_t)l << PAGE_SHIFT);
+ mmu_radix_dump_add_leaf(dump_bitset, va,
+ pte & RPTE_RPN_MASK, PAGE_SIZE,
+ kstart, kend);
+ }
+ }
+ }
+ }
+ PMAP_UNLOCK(kernel_pmap);
+
+ return (RADIX_PGD_SIZE);
+}
+
+struct radix_dump_context {
+ size_t off;
+ size_t blksz;
+};
+
+static struct radix_dump_context radix_dump_ctx;
+
+static void *
+mmu_radix_dump_pmap_init(unsigned blkpgs)
+{
+
+ radix_dump_ctx.off = 0;
+ radix_dump_ctx.blksz = blkpgs * PAGE_SIZE;
+ return (&radix_dump_ctx);
+}
+
+static void *
+mmu_radix_dump_pmap(void *ctx, void *buf __unused, u_long *nbytes)
+{
+ struct radix_dump_context *dctx;
+ void *p;
+
+ dctx = ctx;
+ if (dctx->off == RADIX_PGD_SIZE) {
+ *nbytes = 0;
+ return (NULL);
+ }
+
+ *nbytes = MIN(dctx->blksz, RADIX_PGD_SIZE - dctx->off);
+ p = (char *)kernel_pmap->pm_pml1 + dctx->off;
+ dctx->off += *nbytes;
+ return (p);
+}
+
static void
mmu_radix_scan_init(void)
{

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 18, 5:21 AM (12 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39108835
Default Alt Text
D59743.id.diff (17 KB)

Event Timeline