i86mmu.c revision a85a673364d59fb5396bc0ebbbde90862626fc0b
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This part of the file contains the mdb support for dcmds:
* ::memseg_list
* ::page_num2pp
* and walkers for:
* memseg - a memseg list walker for ::memseg_list
*
*/
#include <sys/machparam.h>
#include <sys/controlregs.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_target.h>
struct pfn2pp {
};
static void get_mmu(void);
int
{
return (DCMD_ERR);
/*
* The kernel has to at least have made it thru mmu_init()
*/
get_mmu();
return (DCMD_ERR);
}
/*ARGSUSED*/
int
{
return (DCMD_ERR);
}
return (WALK_DONE);
}
return (WALK_NEXT);
}
/*
* ::page_num2pp dcmd
*/
/*ARGSUSED*/
int
{
if ((flags & DCMD_ADDRSPEC) == 0) {
mdb_warn("page frame number missing\n");
return (DCMD_USAGE);
}
(void *)&pfn2pp) == -1) {
mdb_warn("can't walk memseg");
return (DCMD_ERR);
}
return (DCMD_ERR);
return (DCMD_ERR);
}
mdb_warn("WARNING! Found page structure contains "
}
return (DCMD_OK);
}
/*
* ::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
{
}
/*
* HAT related dcmds:
*
* ::pte [-p XXXXXXXX] [-l 0/1/2/3]
*
* dcmd that interprets the -p argument as a page table entry and
* prints it in more human readable form. The PTE is assumed to be in
* a level 0 page table, unless -l specifies another level.
*
* ::vatopfn [-v] [-a as]
*
* Given a virtual address, returns the PFN, if any, mapped at the address.
* mapping. By default the virtual address is assumed to be in the kernel's
* address space. -a is used to specify a different address space.
*/
struct hat_mmu_info mmu;
/*
* read mmu parameters from kernel
*/
static void
get_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");
}
/*
* 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;
/*
* The kernel has to at least have made it thru mmu_init()
*/
get_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 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
*/
*pap = 0;
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;
/*
* found - read the page table entry
*/
return (DCMD_ERR);
else
if (!found) {
else
found = 1;
}
if (print_level == 0)
continue;
mdb_printf("\tlevel=%d htable=%p pte=%llx\n",
}
}
}
done:
if (!found)
return (DCMD_ERR);
return (DCMD_OK);
}
int
{
char *addrspace_str = NULL;
int rc;
/*
* The kernel has to at least have made it thru mmu_init()
*/
get_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);
}
/*
* 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;
++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
{
/*
* The kernel has to at least have made it thru mmu_init()
*/
get_mmu();
return (DCMD_ERR);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
}
/*
* Dump the page table at the given 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);
}
/*
* given a PFN as its address argument, prints out the uses of it
*/
/*ARGSUSED*/
int
{
/*
* The kernel has to at least have made it thru mmu_init()
*/
get_mmu();
return (DCMD_ERR);
if ((flags & DCMD_ADDRSPEC) == 0)
return (DCMD_USAGE);
}