Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F172245180
D59743.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D59743.id.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D59743: powerpc/radix: add minidump support
Attached
Detach File
Event Timeline
Log In to Comment