From nobody Mon Sep 28 15:54:55 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4htm8w292kz6WrB4 for ; Mon, 28 Sep 2026 15:54:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4htm8w19sKz4S06 for ; Mon, 28 Sep 2026 15:54:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790610896; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=92pmyK1YQnjIosIgF5bZW6WDHh8BxKKUyfuf27BWHlk=; b=f2MzC6hAU20+hY/NJnlmzztru2fKAuJNIGPXlInEdF2sM6ZGbJ0hSDeh9Ui6CIeY2PNMvS nKeCe5m7avqRpAIVCZvMXj6EfkW5O7vhOZ7iKF1p3T9svJgV7CdFVtwvlFcXmFbnDCqaIh AhcP2g6F162Wo5q3NrsnCqU7c9m3XayNHhuLKCVSShitUv4iSBCfW3591oAtJbOrcmSm2j 1LEE0CzFskLTUrWj+Ep2nfY/NmPwY+alVqoF3JVQ6ckxOoXUJ8GiKYDjjxcLnkfFo2ApiZ bHUL5KioIEEFOBuidviqVOgoSxsWZfP1suKh5NsGAjH6J9Hybyr1IIA7mkungQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1790610896; b=nfBfgXPPIZVMs2sZhiqsyNW46NoNvwBWC3deJzKdlL9WHKoiE4hu3vkUCZFBxsbQURF+Zz eyDhJrA7pxVwYMseejCPlFa3UNhyjOx6B2sc4gmEMk8h7BpRqBdrWkFTNVQQ0hVTHQk9dZ sa5CKv78/wOc4osat+zQkzzzHoDFo6kNsTPFBOaupPwq6hxbE48SArpdijg1l2MF6U6Fjh 7/i6IniNlNjeygLEcS5Cmvt+LFRcqrp3unuwi8nePsKIBInVUnwMPBA7jE0UeuofYNZo2u 2yocXuHU8QKxoMyRF9UOcUsw9CJ4PqVLLuUD6geIW5Yp7ETy3S72hfCD/4Dkfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790610896; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=92pmyK1YQnjIosIgF5bZW6WDHh8BxKKUyfuf27BWHlk=; b=a+V/O3zhtFum6bZdD2F7+CevR+hb5mbs7IcnI3bsgp0+15JnYW+pP1+r+JeDBFHeeQo9bw fzPTkrit8uawxFHPA7Ai3/qIGEDAWNU/VxD6ic+Qihh+B9Vziq5r9njEA9Nzc3DVkgKsId poP1I8Zz1po24QynAD4Z7srW96aCbUhsRGeYUxO0/F96ASoph2vZKn7yfkRik6WktpoilH cLdFBwnPMSrZK4KVTH1dnhRnPFZAVYMPvMgepuSY70LLrfdT9BRRWWWSZ7ded/lnFo8K83 YiSFA1OnrDM/DzHxHZUqAIo6XhcZwxlPKMXdwJJ+QWCgkAwqNoDoR9zF0bTN1A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4htm8v6xh5zbY2 for ; Mon, 28 Sep 2026 15:54:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 2563e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 28 Sep 2026 15:54:55 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Minsoo Choo Subject: git: 592ede65bd48 - main - libkvm: support powerpc64 radix minidumps List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mchoo X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 592ede65bd48f16e5c46a016e92b732ed90094d2 Auto-Submitted: auto-generated Date: Mon, 28 Sep 2026 15:54:55 +0000 Message-Id: <6aba8dcf.2563e.455fd4a1@gitrepo.freebsd.org> The branch main has been updated by mchoo: URL: https://cgit.FreeBSD.org/src/commit/?id=592ede65bd48f16e5c46a016e92b732ed90094d2 commit 592ede65bd48f16e5c46a016e92b732ed90094d2 Author: Minsoo Choo AuthorDate: 2026-09-16 04:20:45 +0000 Commit: Minsoo Choo CommitDate: 2026-09-28 15:54:20 +0000 libkvm: support powerpc64 radix minidumps PowerPC64 radix minidumps use a 64KB root directory followed by three levels of 4KB page tables. Add an MMU backend which walks those tables, handles large-page leaves, and decodes their always-big-endian entries on both powerpc64 and powerpc64le. Reject old radix minidumps whose pmap section is empty with a specific diagnostic. Add a synthetic powerpc64le dump test which reads a page through both its kernel and direct-map addresses. PR: 298532 Reviewed by: jhb Approved by: jhb (mentor) MFC after: 2 weeks Sponsored by: FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D59743 --- lib/libkvm/Makefile | 3 +- lib/libkvm/kvm_minidump_powerpc64.c | 2 + lib/libkvm/kvm_minidump_powerpc64_radix.c | 270 ++++++++++++++++++++++++++++++ lib/libkvm/kvm_powerpc64.h | 2 + lib/libkvm/tests/kvm_open2_test.c | 118 +++++++++++++ 5 files changed, 394 insertions(+), 1 deletion(-) diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile index 94a1173010a4..725491e1edac 100644 --- a/lib/libkvm/Makefile +++ b/lib/libkvm/Makefile @@ -13,7 +13,8 @@ SRCS= kvm.c kvm_cptime.c kvm_getloadavg.c \ 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 index f39a6ed9393b..7de5d8c0d458 100644 --- a/lib/libkvm/kvm_minidump_powerpc64.c +++ b/lib/libkvm/kvm_minidump_powerpc64.c @@ -131,6 +131,8 @@ _powerpc64_minidump_initvtop(kvm_t *kd) 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 index 000000000000..1d187e0e55e5 --- /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 +#include +#include + +#include + +#include +#include + +#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 index efd7ce0d3e7f..591e87364453 100644 --- 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 @@ struct vmstate { }; 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 index 5f882578c1f2..52e5c2f21d0f 100644 --- a/lib/libkvm/tests/kvm_open2_test.c +++ b/lib/libkvm/tests/kvm_open2_test.c @@ -39,8 +39,18 @@ #include +#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 @@ create_invalid_powerpc64_minidump(const char *path) 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_TC_BODY(kvm_open2_powerpc64le_minidump_probe, tc) 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_TCS(tp) 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()); }