17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5a85a6733Sjosephb * Common Development and Distribution License (the "License").
6a85a6733Sjosephb * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22cbdcbd05SJonathan Adams * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
2474ecdb51SJohn Levon *
253b442230SJordan Paige Hendricks * Copyright 2019 Joyent, Inc.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * This part of the file contains the mdb support for dcmds:
307c478bd9Sstevel@tonic-gate * ::memseg_list
317c478bd9Sstevel@tonic-gate * and walkers for:
327c478bd9Sstevel@tonic-gate * memseg - a memseg list walker for ::memseg_list
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
387c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
39ae115bc7Smrj #include <sys/mach_mmu.h>
40843e1988Sjohnlev #ifdef __xpv
41843e1988Sjohnlev #include <sys/hypervisor.h>
42843e1988Sjohnlev #endif
437c478bd9Sstevel@tonic-gate #include <vm/as.h>
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
467c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h>
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #include <vm/page.h>
497c478bd9Sstevel@tonic-gate #include <vm/hat_i86.h>
507c478bd9Sstevel@tonic-gate
5174ecdb51SJohn Levon #define VA_SIGN_BIT (1UL << 47)
52*dea210b5SKeith M Wesolowski #define VA_LOW_BITS ((1UL << 48) - 1)
53*dea210b5SKeith M Wesolowski #define VA_SIGN_EXTEND(va) ((((va) & VA_LOW_BITS) ^ VA_SIGN_BIT) - VA_SIGN_BIT)
5474ecdb51SJohn Levon
557c478bd9Sstevel@tonic-gate struct pfn2pp {
567c478bd9Sstevel@tonic-gate pfn_t pfn;
577c478bd9Sstevel@tonic-gate page_t *pp;
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate
60ae115bc7Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
61843e1988Sjohnlev static void init_mmu(void);
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate int
platform_vtop(uintptr_t addr,struct as * asp,physaddr_t * pap)647c478bd9Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate if (asp == NULL)
677c478bd9Sstevel@tonic-gate return (DCMD_ERR);
687c478bd9Sstevel@tonic-gate
69843e1988Sjohnlev init_mmu();
70843e1988Sjohnlev
717c478bd9Sstevel@tonic-gate if (mmu.num_level == 0)
727c478bd9Sstevel@tonic-gate return (DCMD_ERR);
737c478bd9Sstevel@tonic-gate
74ae115bc7Smrj return (do_va2pa(addr, asp, 0, pap, NULL));
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate * ::memseg_list dcmd and walker to implement it.
797c478bd9Sstevel@tonic-gate */
807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
817c478bd9Sstevel@tonic-gate int
memseg_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)827c478bd9Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate struct memseg ms;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) {
877c478bd9Sstevel@tonic-gate if (mdb_pwalk_dcmd("memseg", "memseg_list",
887c478bd9Sstevel@tonic-gate 0, NULL, 0) == -1) {
897c478bd9Sstevel@tonic-gate mdb_warn("can't walk memseg");
907c478bd9Sstevel@tonic-gate return (DCMD_ERR);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate return (DCMD_OK);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags))
967c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
977c478bd9Sstevel@tonic-gate "PAGES", "EPAGES", "BASE", "END");
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
1007c478bd9Sstevel@tonic-gate mdb_warn("can't read memseg at %#lx", addr);
1017c478bd9Sstevel@tonic-gate return (DCMD_ERR);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
1057c478bd9Sstevel@tonic-gate ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate return (DCMD_OK);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate * walk the memseg structures
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate int
memseg_walk_init(mdb_walk_state_t * wsp)1147c478bd9Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1157c478bd9Sstevel@tonic-gate {
116892ad162SToomas Soome if (wsp->walk_addr != 0) {
1177c478bd9Sstevel@tonic-gate mdb_warn("memseg only supports global walks\n");
1187c478bd9Sstevel@tonic-gate return (WALK_ERR);
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1227c478bd9Sstevel@tonic-gate mdb_warn("symbol 'memsegs' not found");
1237c478bd9Sstevel@tonic-gate return (WALK_ERR);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1277c478bd9Sstevel@tonic-gate return (WALK_NEXT);
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate int
memseg_walk_step(mdb_walk_state_t * wsp)1327c478bd9Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate int status;
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate if (wsp->walk_addr == 0) {
1377c478bd9Sstevel@tonic-gate return (WALK_DONE);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
1417c478bd9Sstevel@tonic-gate wsp->walk_addr) == -1) {
1427c478bd9Sstevel@tonic-gate mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
1437c478bd9Sstevel@tonic-gate return (WALK_DONE);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1477c478bd9Sstevel@tonic-gate wsp->walk_cbdata);
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate return (status);
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate void
memseg_walk_fini(mdb_walk_state_t * wsp)1557c478bd9Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (struct memseg));
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate /*
161ae115bc7Smrj * Now HAT related dcmds.
1627c478bd9Sstevel@tonic-gate */
1637c478bd9Sstevel@tonic-gate
164843e1988Sjohnlev static struct hat *khat; /* value of kas.a_hat */
1657c478bd9Sstevel@tonic-gate struct hat_mmu_info mmu;
1667c478bd9Sstevel@tonic-gate uintptr_t kernelbase;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
169843e1988Sjohnlev * stuff for i86xpv images
170843e1988Sjohnlev */
171843e1988Sjohnlev static int is_xpv;
172843e1988Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */
173843e1988Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
174843e1988Sjohnlev ulong_t mfn_count; /* number of pfn's in the MFN list */
175843e1988Sjohnlev pfn_t *mfn_list; /* local MFN list copy */
176843e1988Sjohnlev
177843e1988Sjohnlev /*
1787c478bd9Sstevel@tonic-gate * read mmu parameters from kernel
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate static void
init_mmu(void)181843e1988Sjohnlev init_mmu(void)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate struct as kas;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate if (mmu.num_level != 0)
1867c478bd9Sstevel@tonic-gate return;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
1897c478bd9Sstevel@tonic-gate mdb_warn("Can't use HAT information before mmu_init()\n");
1907c478bd9Sstevel@tonic-gate if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
1917c478bd9Sstevel@tonic-gate mdb_warn("Couldn't find kas - kernel's struct as\n");
1927c478bd9Sstevel@tonic-gate if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
1937c478bd9Sstevel@tonic-gate mdb_warn("Couldn't find kernelbase\n");
1947c478bd9Sstevel@tonic-gate khat = kas.a_hat;
195843e1988Sjohnlev
196843e1988Sjohnlev /*
197843e1988Sjohnlev * Is this a paravirtualized domain image?
198843e1988Sjohnlev */
199843e1988Sjohnlev if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
200843e1988Sjohnlev "mfn_list") == -1 ||
201843e1988Sjohnlev mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
202843e1988Sjohnlev "xen_virt_start") == -1 ||
203843e1988Sjohnlev mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
204892ad162SToomas Soome mfn_list_addr = 0;
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate
207892ad162SToomas Soome is_xpv = mfn_list_addr != 0;
208843e1988Sjohnlev
209843e1988Sjohnlev #ifndef _KMDB
210843e1988Sjohnlev /*
211843e1988Sjohnlev * recreate the local mfn_list
212843e1988Sjohnlev */
213843e1988Sjohnlev if (is_xpv) {
214843e1988Sjohnlev size_t sz = mfn_count * sizeof (pfn_t);
215843e1988Sjohnlev mfn_list = mdb_zalloc(sz, UM_SLEEP);
216843e1988Sjohnlev
217843e1988Sjohnlev if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
218843e1988Sjohnlev mdb_warn("Failed to read MFN list\n");
219843e1988Sjohnlev mdb_free(mfn_list, sz);
220843e1988Sjohnlev mfn_list = NULL;
221843e1988Sjohnlev }
222843e1988Sjohnlev }
223843e1988Sjohnlev #endif
224843e1988Sjohnlev }
225843e1988Sjohnlev
226843e1988Sjohnlev void
free_mmu(void)227843e1988Sjohnlev free_mmu(void)
228843e1988Sjohnlev {
229843e1988Sjohnlev #ifdef __xpv
230843e1988Sjohnlev if (mfn_list != NULL)
231843e1988Sjohnlev mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
232843e1988Sjohnlev #endif
233843e1988Sjohnlev }
234843e1988Sjohnlev
235843e1988Sjohnlev #ifdef __xpv
236843e1988Sjohnlev
237843e1988Sjohnlev #ifdef _KMDB
238843e1988Sjohnlev
239843e1988Sjohnlev /*
240843e1988Sjohnlev * Convert between MFNs and PFNs. Since we're in kmdb we can go directly
241843e1988Sjohnlev * through the machine to phys mapping and the MFN list.
242843e1988Sjohnlev */
243843e1988Sjohnlev
244843e1988Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)245843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
246843e1988Sjohnlev {
247843e1988Sjohnlev pfn_t pfn;
248843e1988Sjohnlev mfn_t tmp;
249843e1988Sjohnlev pfn_t *pfn_list;
250843e1988Sjohnlev
251892ad162SToomas Soome if (mfn_list_addr == 0)
252843e1988Sjohnlev return (-(pfn_t)1);
253843e1988Sjohnlev
254843e1988Sjohnlev pfn_list = (pfn_t *)xen_virt_start;
255843e1988Sjohnlev if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
256843e1988Sjohnlev return (-(pfn_t)1);
257843e1988Sjohnlev
258843e1988Sjohnlev if (mdb_vread(&tmp, sizeof (tmp),
259843e1988Sjohnlev (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
260843e1988Sjohnlev return (-(pfn_t)1);
261843e1988Sjohnlev
262843e1988Sjohnlev if (pfn >= mfn_count || tmp != mfn)
263843e1988Sjohnlev return (-(pfn_t)1);
264843e1988Sjohnlev
265843e1988Sjohnlev return (pfn);
266843e1988Sjohnlev }
267843e1988Sjohnlev
268843e1988Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)269843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
270843e1988Sjohnlev {
271843e1988Sjohnlev mfn_t mfn;
272843e1988Sjohnlev
273843e1988Sjohnlev init_mmu();
274843e1988Sjohnlev
275892ad162SToomas Soome if (mfn_list_addr == 0 || pfn >= mfn_count)
276843e1988Sjohnlev return (-(mfn_t)1);
277843e1988Sjohnlev
278843e1988Sjohnlev if (mdb_vread(&mfn, sizeof (mfn),
279843e1988Sjohnlev (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
280843e1988Sjohnlev return (-(mfn_t)1);
281843e1988Sjohnlev
282843e1988Sjohnlev return (mfn);
283843e1988Sjohnlev }
284843e1988Sjohnlev
285843e1988Sjohnlev #else /* _KMDB */
286843e1988Sjohnlev
287843e1988Sjohnlev /*
288843e1988Sjohnlev * Convert between MFNs and PFNs. Since a crash dump doesn't include the
289843e1988Sjohnlev * MFN->PFN translation table (it's part of the hypervisor, not our image)
290843e1988Sjohnlev * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
291843e1988Sjohnlev * table, if it's there.
292843e1988Sjohnlev */
293843e1988Sjohnlev
294843e1988Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)295843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
296843e1988Sjohnlev {
297843e1988Sjohnlev pfn_t pfn;
298843e1988Sjohnlev
299843e1988Sjohnlev init_mmu();
300843e1988Sjohnlev
301843e1988Sjohnlev if (mfn_list == NULL)
302843e1988Sjohnlev return (-(pfn_t)1);
303843e1988Sjohnlev
304843e1988Sjohnlev for (pfn = 0; pfn < mfn_count; ++pfn) {
305843e1988Sjohnlev if (mfn_list[pfn] != mfn)
306843e1988Sjohnlev continue;
307843e1988Sjohnlev return (pfn);
308843e1988Sjohnlev }
309843e1988Sjohnlev
310843e1988Sjohnlev return (-(pfn_t)1);
311843e1988Sjohnlev }
312843e1988Sjohnlev
313843e1988Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)314843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
315843e1988Sjohnlev {
316843e1988Sjohnlev init_mmu();
317843e1988Sjohnlev
318843e1988Sjohnlev if (mfn_list == NULL || pfn >= mfn_count)
319843e1988Sjohnlev return (-(mfn_t)1);
320843e1988Sjohnlev
321843e1988Sjohnlev return (mfn_list[pfn]);
322843e1988Sjohnlev }
323843e1988Sjohnlev
324843e1988Sjohnlev #endif /* _KMDB */
325843e1988Sjohnlev
326843e1988Sjohnlev static paddr_t
mdb_ma_to_pa(uint64_t ma)327843e1988Sjohnlev mdb_ma_to_pa(uint64_t ma)
328843e1988Sjohnlev {
329843e1988Sjohnlev pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
330843e1988Sjohnlev if (pfn == -(pfn_t)1)
331843e1988Sjohnlev return (-(paddr_t)1);
332843e1988Sjohnlev
333843e1988Sjohnlev return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
334843e1988Sjohnlev }
335843e1988Sjohnlev
336843e1988Sjohnlev #else /* __xpv */
337843e1988Sjohnlev
338ae115bc7Smrj #define mdb_ma_to_pa(ma) (ma)
339ae115bc7Smrj #define mdb_mfn_to_pfn(mfn) (mfn)
340ae115bc7Smrj #define mdb_pfn_to_mfn(pfn) (pfn)
341ae115bc7Smrj
342843e1988Sjohnlev #endif /* __xpv */
343843e1988Sjohnlev
344843e1988Sjohnlev /*
345843e1988Sjohnlev * ::mfntopfn dcmd translates hypervisor machine page number
346843e1988Sjohnlev * to physical page number
347843e1988Sjohnlev */
348843e1988Sjohnlev /*ARGSUSED*/
349843e1988Sjohnlev int
mfntopfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)350843e1988Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
351843e1988Sjohnlev {
352843e1988Sjohnlev pfn_t pfn;
353843e1988Sjohnlev
354843e1988Sjohnlev if ((flags & DCMD_ADDRSPEC) == 0) {
355843e1988Sjohnlev mdb_warn("MFN missing\n");
356843e1988Sjohnlev return (DCMD_USAGE);
357843e1988Sjohnlev }
358843e1988Sjohnlev
359843e1988Sjohnlev if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
360843e1988Sjohnlev mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
361843e1988Sjohnlev return (DCMD_ERR);
362843e1988Sjohnlev }
363843e1988Sjohnlev
364843e1988Sjohnlev mdb_printf("%lr\n", pfn);
365843e1988Sjohnlev
366843e1988Sjohnlev return (DCMD_OK);
367843e1988Sjohnlev }
368843e1988Sjohnlev
369843e1988Sjohnlev /*
370843e1988Sjohnlev * ::pfntomfn dcmd translates physical page number to
371843e1988Sjohnlev * hypervisor machine page number
372843e1988Sjohnlev */
373843e1988Sjohnlev /*ARGSUSED*/
374843e1988Sjohnlev int
pfntomfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)375843e1988Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
376843e1988Sjohnlev {
377843e1988Sjohnlev pfn_t mfn;
378843e1988Sjohnlev
379843e1988Sjohnlev if ((flags & DCMD_ADDRSPEC) == 0) {
380843e1988Sjohnlev mdb_warn("PFN missing\n");
381843e1988Sjohnlev return (DCMD_USAGE);
382843e1988Sjohnlev }
383843e1988Sjohnlev
384843e1988Sjohnlev if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
385843e1988Sjohnlev mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
386843e1988Sjohnlev return (DCMD_ABORT);
387843e1988Sjohnlev }
388843e1988Sjohnlev
389843e1988Sjohnlev mdb_printf("%lr\n", mfn);
390843e1988Sjohnlev
391843e1988Sjohnlev if (flags & DCMD_LOOP)
392843e1988Sjohnlev mdb_set_dot(addr + 1);
393843e1988Sjohnlev return (DCMD_OK);
394843e1988Sjohnlev }
395843e1988Sjohnlev
396ae115bc7Smrj static pfn_t
pte2mfn(x86pte_t pte,uint_t level)397ae115bc7Smrj pte2mfn(x86pte_t pte, uint_t level)
398ae115bc7Smrj {
399ae115bc7Smrj pfn_t mfn;
400ae115bc7Smrj if (level > 0 && (pte & PT_PAGESIZE))
401ae115bc7Smrj mfn = mmu_btop(pte & PT_PADDR_LGPG);
402ae115bc7Smrj else
403ae115bc7Smrj mfn = mmu_btop(pte & PT_PADDR);
404ae115bc7Smrj return (mfn);
405ae115bc7Smrj }
406ae115bc7Smrj
4077c478bd9Sstevel@tonic-gate static int
do_pte_dcmd(int level,uint64_t pte)4087c478bd9Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate static char *attr[] = {
4117c478bd9Sstevel@tonic-gate "wrback", "wrthru", "uncached", "uncached",
4127c478bd9Sstevel@tonic-gate "wrback", "wrthru", "wrcombine", "uncached"};
4137c478bd9Sstevel@tonic-gate int pat_index = 0;
414ae115bc7Smrj pfn_t mfn;
4157c478bd9Sstevel@tonic-gate
41674ecdb51SJohn Levon mdb_printf("pte=0x%llr: ", pte);
4177c478bd9Sstevel@tonic-gate
418ae115bc7Smrj mfn = pte2mfn(pte, level);
419843e1988Sjohnlev mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
4207c478bd9Sstevel@tonic-gate
42174ecdb51SJohn Levon if (PTE_GET(pte, mmu.pt_nx))
42274ecdb51SJohn Levon mdb_printf("noexec ");
42374ecdb51SJohn Levon
4247c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCONSIST))
4257c478bd9Sstevel@tonic-gate mdb_printf("noconsist ");
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOSYNC))
4287c478bd9Sstevel@tonic-gate mdb_printf("nosync ");
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate if (PTE_GET(pte, mmu.pt_global))
4317c478bd9Sstevel@tonic-gate mdb_printf("global ");
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
4347c478bd9Sstevel@tonic-gate mdb_printf("largepage ");
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_MOD))
4377c478bd9Sstevel@tonic-gate mdb_printf("mod ");
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_REF))
4407c478bd9Sstevel@tonic-gate mdb_printf("ref ");
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_USER))
4437c478bd9Sstevel@tonic-gate mdb_printf("user ");
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITABLE))
4467c478bd9Sstevel@tonic-gate mdb_printf("write ");
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate * Report non-standard cacheability
4507c478bd9Sstevel@tonic-gate */
4517c478bd9Sstevel@tonic-gate pat_index = 0;
4527c478bd9Sstevel@tonic-gate if (level > 0) {
4537c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
4547c478bd9Sstevel@tonic-gate pat_index += 4;
4557c478bd9Sstevel@tonic-gate } else {
4567c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_PAT_4K))
4577c478bd9Sstevel@tonic-gate pat_index += 4;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCACHE))
4617c478bd9Sstevel@tonic-gate pat_index += 2;
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITETHRU))
4647c478bd9Sstevel@tonic-gate pat_index += 1;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (pat_index != 0)
4677c478bd9Sstevel@tonic-gate mdb_printf("%s", attr[pat_index]);
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_VALID) == 0)
4707c478bd9Sstevel@tonic-gate mdb_printf(" !VALID ");
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate mdb_printf("\n");
4737c478bd9Sstevel@tonic-gate return (DCMD_OK);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate * Print a PTE in more human friendly way. The PTE is assumed to be in
4787c478bd9Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4817c478bd9Sstevel@tonic-gate int
pte_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4827c478bd9Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4837c478bd9Sstevel@tonic-gate {
48474ecdb51SJohn Levon uint64_t level = 0;
4857c478bd9Sstevel@tonic-gate
486843e1988Sjohnlev init_mmu();
487843e1988Sjohnlev
4887c478bd9Sstevel@tonic-gate if (mmu.num_level == 0)
4897c478bd9Sstevel@tonic-gate return (DCMD_ERR);
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0)
4927c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
4937c478bd9Sstevel@tonic-gate
49474ecdb51SJohn Levon if (mdb_getopts(argc, argv,
4953b442230SJordan Paige Hendricks 'l', MDB_OPT_UINT64, &level, NULL) != argc)
49674ecdb51SJohn Levon return (DCMD_USAGE);
49774ecdb51SJohn Levon
49874ecdb51SJohn Levon if (level > mmu.max_level) {
49974ecdb51SJohn Levon mdb_warn("invalid level %lu\n", level);
5007c478bd9Sstevel@tonic-gate return (DCMD_ERR);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate
50374ecdb51SJohn Levon if (addr == 0)
50474ecdb51SJohn Levon return (DCMD_OK);
50574ecdb51SJohn Levon
50674ecdb51SJohn Levon return (do_pte_dcmd((int)level, addr));
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
509ae115bc7Smrj static size_t
va2entry(htable_t * htable,uintptr_t addr)510ae115bc7Smrj va2entry(htable_t *htable, uintptr_t addr)
511ae115bc7Smrj {
512ae115bc7Smrj size_t entry = (addr - htable->ht_vaddr);
513ae115bc7Smrj
514ae115bc7Smrj entry >>= mmu.level_shift[htable->ht_level];
515ae115bc7Smrj return (entry & HTABLE_NUM_PTES(htable) - 1);
516ae115bc7Smrj }
517ae115bc7Smrj
518ae115bc7Smrj static x86pte_t
get_pte(hat_t * hat,htable_t * htable,uintptr_t addr)519ae115bc7Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
520ae115bc7Smrj {
521ae115bc7Smrj x86pte_t buf;
522ae115bc7Smrj
52374ecdb51SJohn Levon if (htable->ht_flags & HTABLE_COPIED) {
52474ecdb51SJohn Levon uintptr_t ptr = (uintptr_t)hat->hat_copied_ptes;
525ae115bc7Smrj ptr += va2entry(htable, addr) << mmu.pte_size_shift;
52674ecdb51SJohn Levon return (*(x86pte_t *)ptr);
527ae115bc7Smrj }
528ae115bc7Smrj
52974ecdb51SJohn Levon paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
53074ecdb51SJohn Levon paddr += va2entry(htable, addr) << mmu.pte_size_shift;
531ae115bc7Smrj
53274ecdb51SJohn Levon if ((mdb_pread(&buf, mmu.pte_size, paddr)) == mmu.pte_size)
533ae115bc7Smrj return (buf);
53474ecdb51SJohn Levon
53574ecdb51SJohn Levon return (0);
536ae115bc7Smrj }
537ae115bc7Smrj
5387c478bd9Sstevel@tonic-gate static int
do_va2pa(uintptr_t addr,struct as * asp,int print_level,physaddr_t * pap,pfn_t * mfnp)539ae115bc7Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
540ae115bc7Smrj pfn_t *mfnp)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate struct as as;
5437c478bd9Sstevel@tonic-gate struct hat *hatp;
5447c478bd9Sstevel@tonic-gate struct hat hat;
5457c478bd9Sstevel@tonic-gate htable_t *ht;
5467c478bd9Sstevel@tonic-gate htable_t htable;
5477c478bd9Sstevel@tonic-gate uintptr_t base;
5487c478bd9Sstevel@tonic-gate int h;
5497c478bd9Sstevel@tonic-gate int level;
5507c478bd9Sstevel@tonic-gate int found = 0;
5517c478bd9Sstevel@tonic-gate x86pte_t pte;
5527c478bd9Sstevel@tonic-gate physaddr_t paddr;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate if (asp != NULL) {
5557c478bd9Sstevel@tonic-gate if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
5567c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct as\n");
5577c478bd9Sstevel@tonic-gate return (DCMD_ERR);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate hatp = as.a_hat;
5607c478bd9Sstevel@tonic-gate } else {
5617c478bd9Sstevel@tonic-gate hatp = khat;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate * read the hat and its hash table
5667c478bd9Sstevel@tonic-gate */
5677c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
5687c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n");
5697c478bd9Sstevel@tonic-gate return (DCMD_ERR);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate * read the htable hashtable
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate for (level = 0; level <= mmu.max_level; ++level) {
576ae115bc7Smrj if (level == TOP_LEVEL(&hat))
5777c478bd9Sstevel@tonic-gate base = 0;
5787c478bd9Sstevel@tonic-gate else
5797c478bd9Sstevel@tonic-gate base = addr & mmu.level_mask[level + 1];
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) {
5827c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *),
5837c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
5847c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
5857c478bd9Sstevel@tonic-gate return (DCMD_ERR);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) {
5887c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t),
5897c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) {
5907c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
5917c478bd9Sstevel@tonic-gate return (DCMD_ERR);
5927c478bd9Sstevel@tonic-gate }
593ae115bc7Smrj
5947c478bd9Sstevel@tonic-gate if (htable.ht_vaddr != base ||
5957c478bd9Sstevel@tonic-gate htable.ht_level != level)
5967c478bd9Sstevel@tonic-gate continue;
5977c478bd9Sstevel@tonic-gate
598ae115bc7Smrj pte = get_pte(&hat, &htable, addr);
5997c478bd9Sstevel@tonic-gate
600ae115bc7Smrj if (print_level) {
60174ecdb51SJohn Levon mdb_printf("\tlevel=%d htable=0x%p "
60274ecdb51SJohn Levon "pte=0x%llr\n", level, ht, pte);
6037c478bd9Sstevel@tonic-gate }
604ae115bc7Smrj
605ae115bc7Smrj if (!PTE_ISVALID(pte)) {
606ae115bc7Smrj mdb_printf("Address %p is unmapped.\n",
607ae115bc7Smrj addr);
608ae115bc7Smrj return (DCMD_ERR);
609ae115bc7Smrj }
610ae115bc7Smrj
611ae115bc7Smrj if (found)
6127c478bd9Sstevel@tonic-gate continue;
613ae115bc7Smrj
614ae115bc7Smrj if (PTE_IS_LGPG(pte, level))
615ae115bc7Smrj paddr = mdb_ma_to_pa(pte &
616ae115bc7Smrj PT_PADDR_LGPG);
617ae115bc7Smrj else
618ae115bc7Smrj paddr = mdb_ma_to_pa(pte & PT_PADDR);
619ae115bc7Smrj paddr += addr & mmu.level_offset[level];
620ae115bc7Smrj if (pap != NULL)
621ae115bc7Smrj *pap = paddr;
622ae115bc7Smrj if (mfnp != NULL)
623ae115bc7Smrj *mfnp = pte2mfn(pte, level);
624ae115bc7Smrj found = 1;
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate done:
6307c478bd9Sstevel@tonic-gate if (!found)
6317c478bd9Sstevel@tonic-gate return (DCMD_ERR);
6327c478bd9Sstevel@tonic-gate return (DCMD_OK);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate int
va2pfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6367c478bd9Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate uintptr_t addrspace;
6397c478bd9Sstevel@tonic-gate char *addrspace_str = NULL;
640ae115bc7Smrj int piped = flags & DCMD_PIPE_OUT;
641ae115bc7Smrj pfn_t pfn;
642ae115bc7Smrj pfn_t mfn;
6437c478bd9Sstevel@tonic-gate int rc;
6447c478bd9Sstevel@tonic-gate
645843e1988Sjohnlev init_mmu();
646843e1988Sjohnlev
6477c478bd9Sstevel@tonic-gate if (mmu.num_level == 0)
6487c478bd9Sstevel@tonic-gate return (DCMD_ERR);
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv,
6513b442230SJordan Paige Hendricks 'a', MDB_OPT_STR, &addrspace_str, NULL) != argc)
6527c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0)
6557c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate /*
6587c478bd9Sstevel@tonic-gate * parse the address space
6597c478bd9Sstevel@tonic-gate */
6607c478bd9Sstevel@tonic-gate if (addrspace_str != NULL)
6617c478bd9Sstevel@tonic-gate addrspace = mdb_strtoull(addrspace_str);
6627c478bd9Sstevel@tonic-gate else
6637c478bd9Sstevel@tonic-gate addrspace = 0;
6647c478bd9Sstevel@tonic-gate
665ae115bc7Smrj rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
6667c478bd9Sstevel@tonic-gate
667ae115bc7Smrj if (rc != DCMD_OK)
6687c478bd9Sstevel@tonic-gate return (rc);
669ae115bc7Smrj
670ae115bc7Smrj if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
671ae115bc7Smrj mdb_warn("Invalid mfn %lr\n", mfn);
672ae115bc7Smrj return (DCMD_ERR);
673ae115bc7Smrj }
674ae115bc7Smrj
675ae115bc7Smrj if (piped) {
676ae115bc7Smrj mdb_printf("0x%lr\n", pfn);
677ae115bc7Smrj return (DCMD_OK);
678ae115bc7Smrj }
679ae115bc7Smrj
680ae115bc7Smrj mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
681ae115bc7Smrj
682843e1988Sjohnlev if (is_xpv)
683843e1988Sjohnlev mdb_printf(" (mfn 0x%lr)", mfn);
684843e1988Sjohnlev
685ae115bc7Smrj mdb_printf("\n");
686ae115bc7Smrj
687ae115bc7Smrj return (DCMD_OK);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate * Report all hat's that either use PFN as a page table or that map the page.
6927c478bd9Sstevel@tonic-gate */
6937c478bd9Sstevel@tonic-gate static int
do_report_maps(pfn_t pfn)6947c478bd9Sstevel@tonic-gate do_report_maps(pfn_t pfn)
6957c478bd9Sstevel@tonic-gate {
696a85a6733Sjosephb struct hat *hatp;
6977c478bd9Sstevel@tonic-gate struct hat hat;
6987c478bd9Sstevel@tonic-gate htable_t *ht;
6997c478bd9Sstevel@tonic-gate htable_t htable;
7007c478bd9Sstevel@tonic-gate uintptr_t base;
7017c478bd9Sstevel@tonic-gate int h;
7027c478bd9Sstevel@tonic-gate int level;
7037c478bd9Sstevel@tonic-gate int entry;
7047c478bd9Sstevel@tonic-gate x86pte_t pte;
7057c478bd9Sstevel@tonic-gate physaddr_t paddr;
7067c478bd9Sstevel@tonic-gate size_t len;
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /*
709a85a6733Sjosephb * The hats are kept in a list with khat at the head.
7107c478bd9Sstevel@tonic-gate */
711a85a6733Sjosephb for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
7127c478bd9Sstevel@tonic-gate /*
7137c478bd9Sstevel@tonic-gate * read the hat and its hash table
7147c478bd9Sstevel@tonic-gate */
7157c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
7167c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n");
7177c478bd9Sstevel@tonic-gate return (DCMD_ERR);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate * read the htable hashtable
7227c478bd9Sstevel@tonic-gate */
7237c478bd9Sstevel@tonic-gate paddr = 0;
7247c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) {
7257c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *),
7267c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7277c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
7287c478bd9Sstevel@tonic-gate return (DCMD_ERR);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) {
7317c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t),
7327c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) {
7337c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
7347c478bd9Sstevel@tonic-gate return (DCMD_ERR);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate * only report kernel addresses once
7397c478bd9Sstevel@tonic-gate */
7407c478bd9Sstevel@tonic-gate if (hatp != khat &&
7417c478bd9Sstevel@tonic-gate htable.ht_vaddr >= kernelbase)
7427c478bd9Sstevel@tonic-gate continue;
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate * Is the PFN a pagetable itself?
7467c478bd9Sstevel@tonic-gate */
7477c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn) {
7487c478bd9Sstevel@tonic-gate mdb_printf("Pagetable for "
7497c478bd9Sstevel@tonic-gate "hat=%p htable=%p\n", hatp, ht);
7507c478bd9Sstevel@tonic-gate continue;
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate /*
7547c478bd9Sstevel@tonic-gate * otherwise, examine page mappings
7557c478bd9Sstevel@tonic-gate */
7567c478bd9Sstevel@tonic-gate level = htable.ht_level;
7577c478bd9Sstevel@tonic-gate if (level > mmu.max_page_level)
7587c478bd9Sstevel@tonic-gate continue;
759ae115bc7Smrj paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
760ae115bc7Smrj for (entry = 0;
761ae115bc7Smrj entry < HTABLE_NUM_PTES(&htable);
7627c478bd9Sstevel@tonic-gate ++entry) {
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate base = htable.ht_vaddr + entry *
7657c478bd9Sstevel@tonic-gate mmu.level_size[level];
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /*
7687c478bd9Sstevel@tonic-gate * only report kernel addresses once
7697c478bd9Sstevel@tonic-gate */
7707c478bd9Sstevel@tonic-gate if (hatp != khat &&
7717c478bd9Sstevel@tonic-gate base >= kernelbase)
7727c478bd9Sstevel@tonic-gate continue;
7737c478bd9Sstevel@tonic-gate
77474ecdb51SJohn Levon len = mdb_pread(&pte, mmu.pte_size,
7757c478bd9Sstevel@tonic-gate paddr + entry * mmu.pte_size);
7767c478bd9Sstevel@tonic-gate if (len != mmu.pte_size)
7777c478bd9Sstevel@tonic-gate return (DCMD_ERR);
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate if ((pte & PT_VALID) == 0)
7807c478bd9Sstevel@tonic-gate continue;
7817c478bd9Sstevel@tonic-gate if (level == 0 || !(pte & PT_PAGESIZE))
7827c478bd9Sstevel@tonic-gate pte &= PT_PADDR;
7837c478bd9Sstevel@tonic-gate else
7847c478bd9Sstevel@tonic-gate pte &= PT_PADDR_LGPG;
785ae115bc7Smrj if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
7867c478bd9Sstevel@tonic-gate continue;
7877c478bd9Sstevel@tonic-gate mdb_printf("hat=%p maps addr=%p\n",
7887c478bd9Sstevel@tonic-gate hatp, (caddr_t)base);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate done:
7957c478bd9Sstevel@tonic-gate return (DCMD_OK);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate * given a PFN as its address argument, prints out the uses of it
8007c478bd9Sstevel@tonic-gate */
8017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8027c478bd9Sstevel@tonic-gate int
report_maps_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)8037c478bd9Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8047c478bd9Sstevel@tonic-gate {
805ae115bc7Smrj pfn_t pfn;
806ae115bc7Smrj uint_t mflag = 0;
807ae115bc7Smrj
808843e1988Sjohnlev init_mmu();
809843e1988Sjohnlev
8107c478bd9Sstevel@tonic-gate if (mmu.num_level == 0)
8117c478bd9Sstevel@tonic-gate return (DCMD_ERR);
8127c478bd9Sstevel@tonic-gate
8137c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0)
8147c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
8157c478bd9Sstevel@tonic-gate
816ae115bc7Smrj if (mdb_getopts(argc, argv,
817ae115bc7Smrj 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
818ae115bc7Smrj return (DCMD_USAGE);
819ae115bc7Smrj
820ae115bc7Smrj pfn = (pfn_t)addr;
821ae115bc7Smrj if (mflag)
822ae115bc7Smrj pfn = mdb_mfn_to_pfn(pfn);
823ae115bc7Smrj
824ae115bc7Smrj return (do_report_maps(pfn));
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate static int
do_ptable_dcmd(pfn_t pfn,uint64_t level)82874ecdb51SJohn Levon do_ptable_dcmd(pfn_t pfn, uint64_t level)
8297c478bd9Sstevel@tonic-gate {
830a85a6733Sjosephb struct hat *hatp;
8317c478bd9Sstevel@tonic-gate struct hat hat;
8327c478bd9Sstevel@tonic-gate htable_t *ht;
8337c478bd9Sstevel@tonic-gate htable_t htable;
8347c478bd9Sstevel@tonic-gate uintptr_t base;
8357c478bd9Sstevel@tonic-gate int h;
8367c478bd9Sstevel@tonic-gate int entry;
8377c478bd9Sstevel@tonic-gate uintptr_t pagesize;
8387c478bd9Sstevel@tonic-gate x86pte_t pte;
8397c478bd9Sstevel@tonic-gate physaddr_t paddr;
8407c478bd9Sstevel@tonic-gate size_t len;
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate /*
843a85a6733Sjosephb * The hats are kept in a list with khat at the head.
8447c478bd9Sstevel@tonic-gate */
845a85a6733Sjosephb for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
8467c478bd9Sstevel@tonic-gate /*
8477c478bd9Sstevel@tonic-gate * read the hat and its hash table
8487c478bd9Sstevel@tonic-gate */
8497c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
8507c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n");
8517c478bd9Sstevel@tonic-gate return (DCMD_ERR);
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate /*
8557c478bd9Sstevel@tonic-gate * read the htable hashtable
8567c478bd9Sstevel@tonic-gate */
8577c478bd9Sstevel@tonic-gate paddr = 0;
8587c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) {
8597c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *),
8607c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
8617c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
8627c478bd9Sstevel@tonic-gate return (DCMD_ERR);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) {
8657c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t),
8667c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) {
8677c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n");
8687c478bd9Sstevel@tonic-gate return (DCMD_ERR);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate * Is this the PFN for this htable
8737c478bd9Sstevel@tonic-gate */
8747c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn)
8757c478bd9Sstevel@tonic-gate goto found_it;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate found_it:
8817c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn) {
8827c478bd9Sstevel@tonic-gate mdb_printf("htable=%p\n", ht);
88374ecdb51SJohn Levon if (level == (uint64_t)-1) {
8847c478bd9Sstevel@tonic-gate level = htable.ht_level;
88574ecdb51SJohn Levon } else if (htable.ht_level != level) {
88674ecdb51SJohn Levon mdb_warn("htable has level %d but forcing level %lu\n",
88774ecdb51SJohn Levon htable.ht_level, level);
88874ecdb51SJohn Levon }
8897c478bd9Sstevel@tonic-gate base = htable.ht_vaddr;
8907c478bd9Sstevel@tonic-gate pagesize = mmu.level_size[level];
8917c478bd9Sstevel@tonic-gate } else {
89274ecdb51SJohn Levon if (level == (uint64_t)-1)
89374ecdb51SJohn Levon level = 0;
89474ecdb51SJohn Levon mdb_warn("couldn't find matching htable, using level=%lu, "
89574ecdb51SJohn Levon "base address=0x0\n", level);
8967c478bd9Sstevel@tonic-gate base = 0;
89774ecdb51SJohn Levon pagesize = mmu.level_size[level];
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate
900ae115bc7Smrj paddr = mmu_ptob((physaddr_t)pfn);
9017c478bd9Sstevel@tonic-gate for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
902ff9e88ceSJohn Levon len = mdb_pread(&pte, mmu.pte_size,
9037c478bd9Sstevel@tonic-gate paddr + entry * mmu.pte_size);
9047c478bd9Sstevel@tonic-gate if (len != mmu.pte_size)
9057c478bd9Sstevel@tonic-gate return (DCMD_ERR);
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate if (pte == 0)
9087c478bd9Sstevel@tonic-gate continue;
9097c478bd9Sstevel@tonic-gate
91074ecdb51SJohn Levon mdb_printf("[%3d] va=0x%p ", entry,
91174ecdb51SJohn Levon VA_SIGN_EXTEND(base + entry * pagesize));
9127c478bd9Sstevel@tonic-gate do_pte_dcmd(level, pte);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate done:
9167c478bd9Sstevel@tonic-gate return (DCMD_OK);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate /*
920ae115bc7Smrj * Dump the page table at the given PFN
9217c478bd9Sstevel@tonic-gate */
9227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9237c478bd9Sstevel@tonic-gate int
ptable_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)9247c478bd9Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9257c478bd9Sstevel@tonic-gate {
926ae115bc7Smrj pfn_t pfn;
927ae115bc7Smrj uint_t mflag = 0;
92874ecdb51SJohn Levon uint64_t level = (uint64_t)-1;
929ae115bc7Smrj
930843e1988Sjohnlev init_mmu();
931843e1988Sjohnlev
9327c478bd9Sstevel@tonic-gate if (mmu.num_level == 0)
9337c478bd9Sstevel@tonic-gate return (DCMD_ERR);
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0)
9367c478bd9Sstevel@tonic-gate return (DCMD_USAGE);
9377c478bd9Sstevel@tonic-gate
938ae115bc7Smrj if (mdb_getopts(argc, argv,
93974ecdb51SJohn Levon 'm', MDB_OPT_SETBITS, TRUE, &mflag,
94074ecdb51SJohn Levon 'l', MDB_OPT_UINT64, &level, NULL) != argc)
941ae115bc7Smrj return (DCMD_USAGE);
942ae115bc7Smrj
94374ecdb51SJohn Levon if (level != (uint64_t)-1 && level > mmu.max_level) {
94474ecdb51SJohn Levon mdb_warn("invalid level %lu\n", level);
94574ecdb51SJohn Levon return (DCMD_ERR);
94674ecdb51SJohn Levon }
94774ecdb51SJohn Levon
948ae115bc7Smrj pfn = (pfn_t)addr;
949ae115bc7Smrj if (mflag)
950ae115bc7Smrj pfn = mdb_mfn_to_pfn(pfn);
951ae115bc7Smrj
95274ecdb51SJohn Levon return (do_ptable_dcmd(pfn, level));
953ae115bc7Smrj }
954ae115bc7Smrj
955ae115bc7Smrj static int
do_htables_dcmd(hat_t * hatp)956ae115bc7Smrj do_htables_dcmd(hat_t *hatp)
957ae115bc7Smrj {
958ae115bc7Smrj struct hat hat;
959ae115bc7Smrj htable_t *ht;
960ae115bc7Smrj htable_t htable;
961ae115bc7Smrj int h;
962ae115bc7Smrj
963ae115bc7Smrj /*
964ae115bc7Smrj * read the hat and its hash table
965ae115bc7Smrj */
966ae115bc7Smrj if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
967ae115bc7Smrj mdb_warn("Couldn't read struct hat\n");
968ae115bc7Smrj return (DCMD_ERR);
969ae115bc7Smrj }
970ae115bc7Smrj
971ae115bc7Smrj /*
972ae115bc7Smrj * read the htable hashtable
973ae115bc7Smrj */
974ae115bc7Smrj for (h = 0; h < hat.hat_num_hash; ++h) {
975ae115bc7Smrj if (mdb_vread(&ht, sizeof (htable_t *),
976ae115bc7Smrj (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
977ae115bc7Smrj mdb_warn("Couldn't read htable ptr\\n");
978ae115bc7Smrj return (DCMD_ERR);
979ae115bc7Smrj }
980ae115bc7Smrj for (; ht != NULL; ht = htable.ht_next) {
981ae115bc7Smrj mdb_printf("%p\n", ht);
982ae115bc7Smrj if (mdb_vread(&htable, sizeof (htable_t),
983ae115bc7Smrj (uintptr_t)ht) == -1) {
984ae115bc7Smrj mdb_warn("Couldn't read htable\n");
985ae115bc7Smrj return (DCMD_ERR);
986ae115bc7Smrj }
987ae115bc7Smrj }
988ae115bc7Smrj }
989ae115bc7Smrj return (DCMD_OK);
990ae115bc7Smrj }
991ae115bc7Smrj
992ae115bc7Smrj /*
993ae115bc7Smrj * Dump the htables for the given hat
994ae115bc7Smrj */
995ae115bc7Smrj /*ARGSUSED*/
996ae115bc7Smrj int
htables_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)997ae115bc7Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
998ae115bc7Smrj {
999ae115bc7Smrj hat_t *hat;
1000ae115bc7Smrj
1001843e1988Sjohnlev init_mmu();
1002843e1988Sjohnlev
1003ae115bc7Smrj if (mmu.num_level == 0)
1004ae115bc7Smrj return (DCMD_ERR);
1005ae115bc7Smrj
1006ae115bc7Smrj if ((flags & DCMD_ADDRSPEC) == 0)
1007ae115bc7Smrj return (DCMD_USAGE);
1008ae115bc7Smrj
1009ae115bc7Smrj hat = (hat_t *)addr;
1010ae115bc7Smrj
1011ae115bc7Smrj return (do_htables_dcmd(hat));
10127c478bd9Sstevel@tonic-gate }
101374ecdb51SJohn Levon
101474ecdb51SJohn Levon static uintptr_t
entry2va(size_t * entries)101574ecdb51SJohn Levon entry2va(size_t *entries)
101674ecdb51SJohn Levon {
101774ecdb51SJohn Levon uintptr_t va = 0;
101874ecdb51SJohn Levon
101974ecdb51SJohn Levon for (level_t l = mmu.max_level; l >= 0; l--)
102074ecdb51SJohn Levon va += entries[l] << mmu.level_shift[l];
102174ecdb51SJohn Levon
102274ecdb51SJohn Levon return (VA_SIGN_EXTEND(va));
102374ecdb51SJohn Levon }
102474ecdb51SJohn Levon
102574ecdb51SJohn Levon static void
ptmap_report(size_t * entries,uintptr_t start,boolean_t user,boolean_t writable,boolean_t wflag)102674ecdb51SJohn Levon ptmap_report(size_t *entries, uintptr_t start,
102774ecdb51SJohn Levon boolean_t user, boolean_t writable, boolean_t wflag)
102874ecdb51SJohn Levon {
102974ecdb51SJohn Levon uint64_t curva = entry2va(entries);
103074ecdb51SJohn Levon
103174ecdb51SJohn Levon mdb_printf("mapped %s,%s range of %lu bytes: %a-%a\n",
103274ecdb51SJohn Levon user ? "user" : "kernel", writable ? "writable" : "read-only",
103374ecdb51SJohn Levon curva - start, start, curva - 1);
103474ecdb51SJohn Levon if (wflag && start >= kernelbase)
103574ecdb51SJohn Levon (void) mdb_call_dcmd("whatis", start, DCMD_ADDRSPEC, 0, NULL);
103674ecdb51SJohn Levon }
103774ecdb51SJohn Levon
103874ecdb51SJohn Levon int
ptmap_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)103974ecdb51SJohn Levon ptmap_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
104074ecdb51SJohn Levon {
104174ecdb51SJohn Levon physaddr_t paddrs[MAX_NUM_LEVEL] = { 0, };
104274ecdb51SJohn Levon size_t entry[MAX_NUM_LEVEL] = { 0, };
104374ecdb51SJohn Levon uintptr_t start = (uintptr_t)-1;
104474ecdb51SJohn Levon boolean_t writable = B_FALSE;
104574ecdb51SJohn Levon boolean_t user = B_FALSE;
104674ecdb51SJohn Levon boolean_t wflag = B_FALSE;
104774ecdb51SJohn Levon level_t curlevel;
104874ecdb51SJohn Levon
104974ecdb51SJohn Levon if ((flags & DCMD_ADDRSPEC) == 0)
105074ecdb51SJohn Levon return (DCMD_USAGE);
105174ecdb51SJohn Levon
105274ecdb51SJohn Levon if (mdb_getopts(argc, argv,
105374ecdb51SJohn Levon 'w', MDB_OPT_SETBITS, TRUE, &wflag, NULL) != argc)
105474ecdb51SJohn Levon return (DCMD_USAGE);
105574ecdb51SJohn Levon
105674ecdb51SJohn Levon init_mmu();
105774ecdb51SJohn Levon
105874ecdb51SJohn Levon if (mmu.num_level == 0)
105974ecdb51SJohn Levon return (DCMD_ERR);
106074ecdb51SJohn Levon
106174ecdb51SJohn Levon curlevel = mmu.max_level;
106274ecdb51SJohn Levon
106374ecdb51SJohn Levon paddrs[curlevel] = addr & MMU_PAGEMASK;
106474ecdb51SJohn Levon
106574ecdb51SJohn Levon for (;;) {
106674ecdb51SJohn Levon physaddr_t pte_addr;
106774ecdb51SJohn Levon x86pte_t pte;
106874ecdb51SJohn Levon
106974ecdb51SJohn Levon pte_addr = paddrs[curlevel] +
107074ecdb51SJohn Levon (entry[curlevel] << mmu.pte_size_shift);
107174ecdb51SJohn Levon
107274ecdb51SJohn Levon if (mdb_pread(&pte, sizeof (pte), pte_addr) != sizeof (pte)) {
107374ecdb51SJohn Levon mdb_warn("couldn't read pte at %p", pte_addr);
107474ecdb51SJohn Levon return (DCMD_ERR);
107574ecdb51SJohn Levon }
107674ecdb51SJohn Levon
107774ecdb51SJohn Levon if (PTE_GET(pte, PT_VALID) == 0) {
107874ecdb51SJohn Levon if (start != (uintptr_t)-1) {
107974ecdb51SJohn Levon ptmap_report(entry, start,
108074ecdb51SJohn Levon user, writable, wflag);
108174ecdb51SJohn Levon start = (uintptr_t)-1;
108274ecdb51SJohn Levon }
108374ecdb51SJohn Levon } else if (curlevel == 0 || PTE_GET(pte, PT_PAGESIZE)) {
108474ecdb51SJohn Levon if (start == (uintptr_t)-1) {
108574ecdb51SJohn Levon start = entry2va(entry);
108674ecdb51SJohn Levon user = PTE_GET(pte, PT_USER);
108774ecdb51SJohn Levon writable = PTE_GET(pte, PT_WRITABLE);
108874ecdb51SJohn Levon } else if (user != PTE_GET(pte, PT_USER) ||
108974ecdb51SJohn Levon writable != PTE_GET(pte, PT_WRITABLE)) {
109074ecdb51SJohn Levon ptmap_report(entry, start,
109174ecdb51SJohn Levon user, writable, wflag);
109274ecdb51SJohn Levon start = entry2va(entry);
109374ecdb51SJohn Levon user = PTE_GET(pte, PT_USER);
109474ecdb51SJohn Levon writable = PTE_GET(pte, PT_WRITABLE);
109574ecdb51SJohn Levon }
109674ecdb51SJohn Levon } else {
109774ecdb51SJohn Levon /* Descend a level. */
109874ecdb51SJohn Levon physaddr_t pa = mmu_ptob(pte2mfn(pte, curlevel));
109974ecdb51SJohn Levon paddrs[--curlevel] = pa;
110074ecdb51SJohn Levon entry[curlevel] = 0;
110174ecdb51SJohn Levon continue;
110274ecdb51SJohn Levon }
110374ecdb51SJohn Levon
110474ecdb51SJohn Levon while (++entry[curlevel] == mmu.ptes_per_table) {
110574ecdb51SJohn Levon /* Ascend back up. */
110674ecdb51SJohn Levon entry[curlevel] = 0;
110774ecdb51SJohn Levon if (curlevel == mmu.max_level) {
110874ecdb51SJohn Levon if (start != (uintptr_t)-1) {
110974ecdb51SJohn Levon ptmap_report(entry, start,
111074ecdb51SJohn Levon user, writable, wflag);
111174ecdb51SJohn Levon }
111274ecdb51SJohn Levon goto out;
111374ecdb51SJohn Levon }
111474ecdb51SJohn Levon
111574ecdb51SJohn Levon curlevel++;
111674ecdb51SJohn Levon }
111774ecdb51SJohn Levon }
111874ecdb51SJohn Levon
111974ecdb51SJohn Levon out:
112074ecdb51SJohn Levon return (DCMD_OK);
112174ecdb51SJohn Levon }
1122