/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This part of the file contains the mdb support for dcmds:
* ::memseg_list
* and walkers for:
* memseg - a memseg list walker for ::memseg_list
*
*/
#include <sys/machparam.h>
#include <sys/controlregs.h>
#include <sys/mach_mmu.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#endif
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_target.h>
struct pfn2pp {
};
static void init_mmu(void);
int
{
return (DCMD_ERR);
init_mmu();
return (DCMD_ERR);
}
/*
* ::memseg_list dcmd and walker to implement it.
*/
/*ARGSUSED*/
int
{
if (!(flags & DCMD_ADDRSPEC)) {
0, NULL, 0) == -1) {
mdb_warn("can't walk memseg");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags))
"PAGES", "EPAGES", "BASE", "END");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* walk the memseg structures
*/
int
{
mdb_warn("memseg only supports global walks\n");
return (WALK_ERR);
}
mdb_warn("symbol 'memsegs' not found");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int status;
return (WALK_DONE);
}
return (WALK_DONE);
}
wsp->walk_cbdata);
return (status);
}
void
{
}
/*
* Now HAT related dcmds.
*/
/*
* stuff for i86xpv images
*/
static int is_xpv;
/*
* read mmu parameters from kernel
*/
static void
init_mmu(void)
{
return;
mdb_warn("Can't use HAT information before mmu_init()\n");
mdb_warn("Couldn't find kas - kernel's struct as\n");
mdb_warn("Couldn't find kernelbase\n");
/*
* Is this a paravirtualized domain image?
*/
"mfn_list") == -1 ||
"xen_virt_start") == -1 ||
}
#ifndef _KMDB
/*
* recreate the local mfn_list
*/
if (is_xpv) {
mdb_warn("Failed to read MFN list\n");
}
}
#endif
}
void
free_mmu(void)
{
#ifdef __xpv
#endif
}
#ifdef __xpv
#ifdef _KMDB
/*
* Convert between MFNs and PFNs. Since we're in kmdb we can go directly
* through the machine to phys mapping and the MFN list.
*/
{
if (mfn_list_addr == NULL)
return (-(pfn_t)1);
return (-(pfn_t)1);
return (-(pfn_t)1);
return (-(pfn_t)1);
return (pfn);
}
{
init_mmu();
return (-(mfn_t)1);
return (-(mfn_t)1);
return (mfn);
}
#else /* _KMDB */
/*
* Convert between MFNs and PFNs. Since a crash dump doesn't include the
* MFN->PFN translation table (it's part of the hypervisor, not our image)
* we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
* table, if it's there.
*/
{
init_mmu();
return (-(pfn_t)1);
continue;
return (pfn);
}
return (-(pfn_t)1);
}
{
init_mmu();
return (-(mfn_t)1);
}
#endif /* _KMDB */
static paddr_t
{
return (-(paddr_t)1);
}
#else /* __xpv */
#endif /* __xpv */
/*
* ::mfntopfn dcmd translates hypervisor machine page number
* to physical page number
*/
/*ARGSUSED*/
int
{
if ((flags & DCMD_ADDRSPEC) == 0) {
mdb_warn("MFN missing\n");
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* ::pfntomfn dcmd translates physical page number to
* hypervisor machine page number
*/
/*ARGSUSED*/
int
{
if ((flags & DCMD_ADDRSPEC) == 0) {
mdb_warn("PFN missing\n");
return (DCMD_USAGE);
}
return (DCMD_ABORT);
}
return (DCMD_OK);
}
static pfn_t
{
else
return (mfn);
}
/*
* Print a PTE in more human friendly way. The PTE is assumed to be in
* a level 0 page table, unless -l specifies another level.
*
* The PTE value can be specified as the -p option, since on a 32 bit kernel
* with PAE running it's larger than a uintptr_t.
*/
static int
{
static char *attr[] = {
"wrback", "wrthru", "uncached", "uncached",
"wrback", "wrthru", "wrcombine", "uncached"};
int pat_index = 0;
mdb_printf("noexec ");
mdb_printf("noconsist ");
mdb_printf("nosync ");
mdb_printf("global ");
mdb_printf("largepage ");
mdb_printf("mod ");
mdb_printf("ref ");
mdb_printf("user ");
mdb_printf("write ");
/*
* Report non-standard cacheability
*/
pat_index = 0;
if (level > 0) {
pat_index += 4;
} else {
pat_index += 4;
}
pat_index += 2;
pat_index += 1;
if (pat_index != 0)
mdb_printf(" !VALID ");
mdb_printf("\n");
return (DCMD_OK);
}
/*
* Print a PTE in more human friendly way. The PTE is assumed to be in
* a level 0 page table, unless -l specifies another level.
*
* The PTE value can be specified as the -p option, since on a 32 bit kernel
* with PAE running it's larger than a uintptr_t.
*/
/*ARGSUSED*/
int
{
int level = 0;
init_mmu();
return (DCMD_ERR);
return (DCMD_USAGE);
/*
* parse the PTE to decode, if it's 0, we don't do anything
*/
} else {
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
}
if (pte == 0)
return (DCMD_OK);
/*
* parse the level if supplied
*/
return (DCMD_ERR);
}
}
static size_t
{
}
static x86pte_t
{
} else {
}
return (0);
return (buf);
return (*pte32);
}
static int
{
int h;
int level;
int found = 0;
mdb_warn("Couldn't read struct as\n");
return (DCMD_ERR);
}
} else {
}
/*
* read the hat and its hash table
*/
mdb_warn("Couldn't read struct hat\n");
return (DCMD_ERR);
}
/*
* read the htable hashtable
*/
base = 0;
else
for (h = 0; h < hat.hat_num_hash; ++h) {
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
continue;
if (print_level) {
mdb_printf("\tlevel=%d htable=%p "
}
if (!PTE_ISVALID(pte)) {
mdb_printf("Address %p is unmapped.\n",
addr);
return (DCMD_ERR);
}
if (found)
continue;
else
found = 1;
}
}
}
done:
if (!found)
return (DCMD_ERR);
return (DCMD_OK);
}
int
{
int rc;
init_mmu();
return (DCMD_ERR);
return (DCMD_USAGE);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
/*
* parse the address space
*/
if (addrspace_str != NULL)
else
addrspace = 0;
return (rc);
return (DCMD_ERR);
}
if (piped) {
return (DCMD_OK);
}
if (is_xpv)
mdb_printf("\n");
return (DCMD_OK);
}
/*
* Report all hat's that either use PFN as a page table or that map the page.
*/
static int
{
int h;
int level;
int entry;
/*
* The hats are kept in a list with khat at the head.
*/
/*
* read the hat and its hash table
*/
mdb_warn("Couldn't read struct hat\n");
return (DCMD_ERR);
}
/*
* read the htable hashtable
*/
paddr = 0;
for (h = 0; h < hat.hat_num_hash; ++h) {
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
/*
* only report kernel addresses once
*/
continue;
/*
* Is the PFN a pagetable itself?
*/
mdb_printf("Pagetable for "
continue;
}
/*
* otherwise, examine page mappings
*/
continue;
for (entry = 0;
++entry) {
/*
* only report kernel addresses once
*/
base >= kernelbase)
continue;
return (DCMD_ERR);
else
continue;
else
pte &= PT_PADDR_LGPG;
continue;
mdb_printf("hat=%p maps addr=%p\n",
}
}
}
}
done:
return (DCMD_OK);
}
/*
* given a PFN as its address argument, prints out the uses of it
*/
/*ARGSUSED*/
int
{
init_mmu();
return (DCMD_ERR);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
return (DCMD_USAGE);
if (mflag)
return (do_report_maps(pfn));
}
static int
{
int h;
int level;
int entry;
/*
* The hats are kept in a list with khat at the head.
*/
/*
* read the hat and its hash table
*/
mdb_warn("Couldn't read struct hat\n");
return (DCMD_ERR);
}
/*
* read the htable hashtable
*/
paddr = 0;
for (h = 0; h < hat.hat_num_hash; ++h) {
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
/*
* Is this the PFN for this htable
*/
goto found_it;
}
}
}
} else {
mdb_printf("Unknown pagetable - assuming level/addr 0");
level = 0; /* assume level == 0 for PFN */
base = 0;
}
return (DCMD_ERR);
else
if (pte == 0)
continue;
}
done:
return (DCMD_OK);
}
/*
* Dump the page table at the given PFN
*/
/*ARGSUSED*/
int
{
init_mmu();
return (DCMD_ERR);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
return (DCMD_USAGE);
if (mflag)
return (do_ptable_dcmd(pfn));
}
static int
{
int h;
/*
* read the hat and its hash table
*/
mdb_warn("Couldn't read struct hat\n");
return (DCMD_ERR);
}
/*
* read the htable hashtable
*/
for (h = 0; h < hat.hat_num_hash; ++h) {
mdb_warn("Couldn't read htable ptr\\n");
return (DCMD_ERR);
}
mdb_warn("Couldn't read htable\n");
return (DCMD_ERR);
}
}
}
return (DCMD_OK);
}
/*
* Dump the htables for the given hat
*/
/*ARGSUSED*/
int
{
init_mmu();
return (DCMD_ERR);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
return (do_htables_dcmd(hat));
}