From owner-svn-src-all@freebsd.org Mon Dec 2 15:56:02 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 0BB3A1AE6BA; Mon, 2 Dec 2019 15:56:02 +0000 (UTC) (envelope-from markj@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) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 47RV8K6Y7dz41pq; Mon, 2 Dec 2019 15:56:01 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C40D914C2; Mon, 2 Dec 2019 15:56:01 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id xB2Fu1RI001301; Mon, 2 Dec 2019 15:56:01 GMT (envelope-from markj@FreeBSD.org) Received: (from markj@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id xB2Fu14t001300; Mon, 2 Dec 2019 15:56:01 GMT (envelope-from markj@FreeBSD.org) Message-Id: <201912021556.xB2Fu14t001300@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: markj set sender to markj@FreeBSD.org using -f From: Mark Johnston Date: Mon, 2 Dec 2019 15:56:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r355293 - stable/12/sys/arm64/arm64 X-SVN-Group: stable-12 X-SVN-Commit-Author: markj X-SVN-Commit-Paths: stable/12/sys/arm64/arm64 X-SVN-Commit-Revision: 355293 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Dec 2019 15:56:02 -0000 Author: markj Date: Mon Dec 2 15:56:01 2019 New Revision: 355293 URL: https://svnweb.freebsd.org/changeset/base/355293 Log: MFC r354816: Implement vm.pmap.kernel_maps for arm64. Modified: stable/12/sys/arm64/arm64/pmap.c Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/arm64/arm64/pmap.c ============================================================================== --- stable/12/sys/arm64/arm64/pmap.c Mon Dec 2 15:44:36 2019 (r355292) +++ stable/12/sys/arm64/arm64/pmap.c Mon Dec 2 15:56:01 2019 (r355293) @@ -120,6 +120,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -5972,3 +5973,212 @@ pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr return (mode >= VM_MEMATTR_DEVICE && mode <= VM_MEMATTR_WRITE_THROUGH); } + +/* + * Track a range of the kernel's virtual address space that is contiguous + * in various mapping attributes. + */ +struct pmap_kernel_map_range { + vm_offset_t sva; + pt_entry_t attrs; + int l3pages; + int l3contig; + int l2blocks; + int l1blocks; +}; + +static void +sysctl_kmaps_dump(struct sbuf *sb, struct pmap_kernel_map_range *range, + vm_offset_t eva) +{ + const char *mode; + int index; + + if (eva <= range->sva) + return; + + index = range->attrs & ATTR_IDX_MASK; + switch (index) { + case ATTR_IDX(VM_MEMATTR_DEVICE): + mode = "DEV"; + break; + case ATTR_IDX(VM_MEMATTR_UNCACHEABLE): + mode = "UC"; + break; + case ATTR_IDX(VM_MEMATTR_WRITE_BACK): + mode = "WB"; + break; + case ATTR_IDX(VM_MEMATTR_WRITE_THROUGH): + mode = "WT"; + break; + default: + printf( + "%s: unknown memory type %x for range 0x%016lx-0x%016lx\n", + __func__, index, range->sva, eva); + mode = "??"; + break; + } + + sbuf_printf(sb, "0x%016lx-0x%016lx r%c%c%c %3s %d %d %d %d\n", + range->sva, eva, + (range->attrs & ATTR_AP_RW_BIT) == ATTR_AP_RW ? 'w' : '-', + (range->attrs & ATTR_PXN) != 0 ? '-' : 'x', + (range->attrs & ATTR_AP_USER) != 0 ? 'u' : 's', + mode, range->l1blocks, range->l2blocks, range->l3contig, + range->l3pages); + + /* Reset to sentinel value. */ + range->sva = 0xfffffffffffffffful; +} + +/* + * Determine whether the attributes specified by a page table entry match those + * being tracked by the current range. + */ +static bool +sysctl_kmaps_match(struct pmap_kernel_map_range *range, pt_entry_t attrs) +{ + + return (range->attrs == attrs); +} + +static void +sysctl_kmaps_reinit(struct pmap_kernel_map_range *range, vm_offset_t va, + pt_entry_t attrs) +{ + + memset(range, 0, sizeof(*range)); + range->sva = va; + range->attrs = attrs; +} + +/* + * Given a leaf PTE, derive the mapping's attributes. If they do not match + * those of the current run, dump the address range and its attributes, and + * begin a new run. + */ +static void +sysctl_kmaps_check(struct sbuf *sb, struct pmap_kernel_map_range *range, + vm_offset_t va, pd_entry_t l0e, pd_entry_t l1e, pd_entry_t l2e, + pt_entry_t l3e) +{ + pt_entry_t attrs; + + attrs = l0e & (ATTR_AP_MASK | ATTR_XN); + attrs |= l1e & (ATTR_AP_MASK | ATTR_XN); + if ((l1e & ATTR_DESCR_MASK) == L1_BLOCK) + attrs |= l1e & ATTR_IDX_MASK; + attrs |= l2e & (ATTR_AP_MASK | ATTR_XN); + if ((l2e & ATTR_DESCR_MASK) == L2_BLOCK) + attrs |= l2e & ATTR_IDX_MASK; + attrs |= l3e & (ATTR_AP_MASK | ATTR_XN | ATTR_IDX_MASK); + + if (range->sva > va || !sysctl_kmaps_match(range, attrs)) { + sysctl_kmaps_dump(sb, range, va); + sysctl_kmaps_reinit(range, va, attrs); + } +} + +static int +sysctl_kmaps(SYSCTL_HANDLER_ARGS) +{ + struct pmap_kernel_map_range range; + struct sbuf sbuf, *sb; + pd_entry_t l0e, *l1, l1e, *l2, l2e; + pt_entry_t *l3, l3e; + vm_offset_t sva; + vm_paddr_t pa; + int error, i, j, k, l; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + sb = &sbuf; + sbuf_new_for_sysctl(sb, NULL, PAGE_SIZE, req); + + /* Sentinel value. */ + range.sva = 0xfffffffffffffffful; + + /* + * Iterate over the kernel page tables without holding the kernel pmap + * lock. Kernel page table pages are never freed, so at worst we will + * observe inconsistencies in the output. + */ + for (sva = 0xffff000000000000ul, i = pmap_l0_index(sva); i < Ln_ENTRIES; + i++) { + if (i == pmap_l0_index(DMAP_MIN_ADDRESS)) + sbuf_printf(sb, "\nDirect map:\n"); + else if (i == pmap_l0_index(VM_MIN_KERNEL_ADDRESS)) + sbuf_printf(sb, "\nKernel map:\n"); + + l0e = kernel_pmap->pm_l0[i]; + if ((l0e & ATTR_DESCR_VALID) == 0) { + sysctl_kmaps_dump(sb, &range, sva); + sva += L0_SIZE; + continue; + } + pa = l0e & ~ATTR_MASK; + l1 = (pd_entry_t *)PHYS_TO_DMAP(pa); + + for (j = pmap_l1_index(sva); j < Ln_ENTRIES; j++) { + l1e = l1[j]; + if ((l1e & ATTR_DESCR_VALID) == 0) { + sysctl_kmaps_dump(sb, &range, sva); + sva += L1_SIZE; + continue; + } + if ((l1e & ATTR_DESCR_MASK) == L1_BLOCK) { + sysctl_kmaps_check(sb, &range, sva, l0e, l1e, + 0, 0); + range.l1blocks++; + sva += L1_SIZE; + continue; + } + pa = l1e & ~ATTR_MASK; + l2 = (pd_entry_t *)PHYS_TO_DMAP(pa); + + for (k = pmap_l2_index(sva); k < Ln_ENTRIES; k++) { + l2e = l2[k]; + if ((l2e & ATTR_DESCR_VALID) == 0) { + sysctl_kmaps_dump(sb, &range, sva); + sva += L2_SIZE; + continue; + } + if ((l2e & ATTR_DESCR_MASK) == L2_BLOCK) { + sysctl_kmaps_check(sb, &range, sva, + l0e, l1e, l2e, 0); + range.l2blocks++; + sva += L2_SIZE; + continue; + } + pa = l2e & ~ATTR_MASK; + l3 = (pt_entry_t *)PHYS_TO_DMAP(pa); + + for (l = pmap_l3_index(sva); l < Ln_ENTRIES; + l++, sva += L3_SIZE) { + l3e = l3[l]; + if ((l3e & ATTR_DESCR_VALID) == 0) { + sysctl_kmaps_dump(sb, &range, + sva); + continue; + } + sysctl_kmaps_check(sb, &range, sva, + l0e, l1e, l2e, l3e); + if ((l3e & ATTR_CONTIGUOUS) != 0) + range.l3contig += l % 16 == 0 ? + 1 : 0; + else + range.l3pages++; + } + } + } + } + + error = sbuf_finish(sb); + sbuf_delete(sb); + return (error); +} +SYSCTL_OID(_vm_pmap, OID_AUTO, kernel_maps, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, sysctl_kmaps, "A", + "Dump kernel address layout");