Add KDL command "mapping"
* VMTranslationMap:
- Add DebugPrintMappingInfo(): Given a virtual address it is supposed
to print the paging structure information for that address. To be
implemented by derived classes.
- Add DebugGetReverseMappingInfo(): Given a physical addresss it is
supposed to find all virtual addresses mapped to it. To be
implemented by derived classes.
* X86VMTranslationMapPAE: Implement the new methods
DebugPrintMappingInfo() and DebugGetReverseMappingInfo().
* Add KDL command "mapping". It supports both virtual address lookups
and reverse lookups.
This commit is contained in:
@@ -20,6 +20,9 @@ struct vm_page_reservation;
|
|||||||
|
|
||||||
|
|
||||||
struct VMTranslationMap {
|
struct VMTranslationMap {
|
||||||
|
struct ReverseMappingInfoCallback;
|
||||||
|
|
||||||
|
public:
|
||||||
VMTranslationMap();
|
VMTranslationMap();
|
||||||
virtual ~VMTranslationMap();
|
virtual ~VMTranslationMap();
|
||||||
|
|
||||||
@@ -72,6 +75,12 @@ struct VMTranslationMap {
|
|||||||
|
|
||||||
virtual void Flush() = 0;
|
virtual void Flush() = 0;
|
||||||
|
|
||||||
|
// backends for KDL commands
|
||||||
|
virtual void DebugPrintMappingInfo(addr_t virtualAddress);
|
||||||
|
virtual bool DebugGetReverseMappingInfo(
|
||||||
|
phys_addr_t physicalAddress,
|
||||||
|
ReverseMappingInfoCallback& callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void PageUnmapped(VMArea* area,
|
void PageUnmapped(VMArea* area,
|
||||||
page_num_t pageNumber, bool accessed,
|
page_num_t pageNumber, bool accessed,
|
||||||
@@ -85,6 +94,13 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VMTranslationMap::ReverseMappingInfoCallback {
|
||||||
|
virtual ~ReverseMappingInfoCallback();
|
||||||
|
|
||||||
|
virtual bool HandleVirtualAddress(addr_t virtualAddress) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct VMPhysicalPageMapper {
|
struct VMPhysicalPageMapper {
|
||||||
VMPhysicalPageMapper();
|
VMPhysicalPageMapper();
|
||||||
virtual ~VMPhysicalPageMapper();
|
virtual ~VMPhysicalPageMapper();
|
||||||
|
|||||||
@@ -1091,6 +1091,137 @@ X86VMTranslationMapPAE::ClearAccessedAndModified(VMArea* area, addr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
X86VMTranslationMapPAE::DebugPrintMappingInfo(addr_t virtualAddress)
|
||||||
|
{
|
||||||
|
// get the page directory
|
||||||
|
pae_page_directory_entry* const* pdpt
|
||||||
|
= fPagingStructures->VirtualPageDirs();
|
||||||
|
pae_page_directory_entry* pageDirectory = pdpt[virtualAddress >> 30];
|
||||||
|
kprintf("page directory: %p (PDPT[%zu])\n", pageDirectory,
|
||||||
|
virtualAddress >> 30);
|
||||||
|
|
||||||
|
// get the page directory entry
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(pdpt, virtualAddress);
|
||||||
|
kprintf("page directory entry %zu (%p): %#" B_PRIx64 "\n",
|
||||||
|
pageDirEntry - pageDirectory, pageDirEntry, *pageDirEntry);
|
||||||
|
|
||||||
|
kprintf(" access: ");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) != 0)
|
||||||
|
kprintf(" present");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_WRITABLE) != 0)
|
||||||
|
kprintf(" writable");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_USER) != 0)
|
||||||
|
kprintf(" user");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_NOT_EXECUTABLE) == 0)
|
||||||
|
kprintf(" executable");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_LARGE_PAGE) != 0)
|
||||||
|
kprintf(" large");
|
||||||
|
|
||||||
|
kprintf("\n caching:");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_WRITE_THROUGH) != 0)
|
||||||
|
kprintf(" write-through");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_CACHING_DISABLED) != 0)
|
||||||
|
kprintf(" uncached");
|
||||||
|
|
||||||
|
kprintf("\n flags: ");
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_ACCESSED) != 0)
|
||||||
|
kprintf(" accessed");
|
||||||
|
kprintf("\n");
|
||||||
|
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get the page table entry
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)X86PagingMethodPAE::Method()
|
||||||
|
->PhysicalPageMapper()->InterruptGetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
kprintf("page table: %#" B_PRIx64 "\n",
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
size_t pteIndex = virtualAddress / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
pae_page_table_entry entry = pageTable[pteIndex];
|
||||||
|
kprintf("page table entry %zu (phys: %#" B_PRIx64 "): %#" B_PRIx64 "\n",
|
||||||
|
pteIndex,
|
||||||
|
(*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK)
|
||||||
|
+ pteIndex * sizeof(pae_page_table_entry),
|
||||||
|
entry);
|
||||||
|
|
||||||
|
kprintf(" access: ");
|
||||||
|
if ((entry & X86_PAE_PTE_PRESENT) != 0)
|
||||||
|
kprintf(" present");
|
||||||
|
if ((entry & X86_PAE_PTE_WRITABLE) != 0)
|
||||||
|
kprintf(" writable");
|
||||||
|
if ((entry & X86_PAE_PTE_USER) != 0)
|
||||||
|
kprintf(" user");
|
||||||
|
if ((entry & X86_PAE_PTE_NOT_EXECUTABLE) == 0)
|
||||||
|
kprintf(" executable");
|
||||||
|
if ((entry & X86_PAE_PTE_GLOBAL) == 0)
|
||||||
|
kprintf(" global");
|
||||||
|
|
||||||
|
kprintf("\n caching:");
|
||||||
|
if ((entry & X86_PAE_PTE_WRITE_THROUGH) != 0)
|
||||||
|
kprintf(" write-through");
|
||||||
|
if ((entry & X86_PAE_PTE_CACHING_DISABLED) != 0)
|
||||||
|
kprintf(" uncached");
|
||||||
|
if ((entry & X86_PAE_PTE_PAT) != 0)
|
||||||
|
kprintf(" PAT");
|
||||||
|
|
||||||
|
kprintf("\n flags: ");
|
||||||
|
if ((entry & X86_PAE_PTE_ACCESSED) != 0)
|
||||||
|
kprintf(" accessed");
|
||||||
|
if ((entry & X86_PAE_PTE_DIRTY) != 0)
|
||||||
|
kprintf(" dirty");
|
||||||
|
kprintf("\n");
|
||||||
|
|
||||||
|
if ((entry & X86_PAE_PTE_PRESENT) != 0) {
|
||||||
|
kprintf(" address: %#" B_PRIx64 "\n",
|
||||||
|
entry & X86_PAE_PTE_ADDRESS_MASK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
X86VMTranslationMapPAE::DebugGetReverseMappingInfo(phys_addr_t physicalAddress,
|
||||||
|
ReverseMappingInfoCallback& callback)
|
||||||
|
{
|
||||||
|
pae_page_directory_entry* const* pdpt
|
||||||
|
= fPagingStructures->VirtualPageDirs();
|
||||||
|
for (uint32 pageDirIndex = fIsKernelMap ? 2 : 0;
|
||||||
|
pageDirIndex < (fIsKernelMap ? 4 : 2); pageDirIndex++) {
|
||||||
|
// iterate through the page directory
|
||||||
|
pae_page_directory_entry* pageDirectory = pdpt[pageDirIndex];
|
||||||
|
for (uint32 pdeIndex = 0; pdeIndex < kPAEPageDirEntryCount;
|
||||||
|
pdeIndex++) {
|
||||||
|
pae_page_directory_entry& pageDirEntry = pageDirectory[pdeIndex];
|
||||||
|
if ((pageDirEntry & X86_PAE_PDE_ADDRESS_MASK) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// get and iterate through the page table
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)X86PagingMethodPAE::Method()
|
||||||
|
->PhysicalPageMapper()->InterruptGetPageTableAt(
|
||||||
|
pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
for (uint32 pteIndex = 0; pteIndex < kPAEPageTableEntryCount;
|
||||||
|
pteIndex++) {
|
||||||
|
pae_page_table_entry entry = pageTable[pteIndex];
|
||||||
|
if ((entry & X86_PAE_PTE_PRESENT) != 0
|
||||||
|
&& (entry & X86_PAE_PTE_ADDRESS_MASK) == physicalAddress) {
|
||||||
|
addr_t virtualAddress = pageDirIndex * kPAEPageDirRange
|
||||||
|
+ pdeIndex * kPAEPageTableRange
|
||||||
|
+ pteIndex * B_PAGE_SIZE;
|
||||||
|
if (callback.HandleVirtualAddress(virtualAddress))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
X86PagingStructures*
|
X86PagingStructures*
|
||||||
X86VMTranslationMapPAE::PagingStructures() const
|
X86VMTranslationMapPAE::PagingStructures() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ struct X86VMTranslationMapPAE : X86VMTranslationMap {
|
|||||||
bool unmapIfUnaccessed,
|
bool unmapIfUnaccessed,
|
||||||
bool& _modified);
|
bool& _modified);
|
||||||
|
|
||||||
|
virtual void DebugPrintMappingInfo(addr_t virtualAddress);
|
||||||
|
virtual bool DebugGetReverseMappingInfo(
|
||||||
|
phys_addr_t physicalAddress,
|
||||||
|
ReverseMappingInfoCallback& callback);
|
||||||
|
|
||||||
virtual X86PagingStructures* PagingStructures() const;
|
virtual X86PagingStructures* PagingStructures() const;
|
||||||
inline X86PagingStructuresPAE* PagingStructuresPAE() const
|
inline X86PagingStructuresPAE* PagingStructuresPAE() const
|
||||||
{ return fPagingStructures; }
|
{ return fPagingStructures; }
|
||||||
|
|||||||
@@ -116,6 +116,39 @@ VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Print mapping information for a virtual address.
|
||||||
|
The method navigates the paging structures and prints all relevant
|
||||||
|
information on the way.
|
||||||
|
The method is invoked from a KDL command. The default implementation is a
|
||||||
|
no-op.
|
||||||
|
\param virtualAddress The virtual address to look up.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
VMTranslationMap::DebugPrintMappingInfo(addr_t virtualAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Find virtual addresses mapped to the given physical address.
|
||||||
|
For each virtual address the method finds, it invokes the callback object's
|
||||||
|
HandleVirtualAddress() method. When that method returns \c true, the search
|
||||||
|
is terminated and \c true is returned.
|
||||||
|
The method is invoked from a KDL command. The default implementation is a
|
||||||
|
no-op.
|
||||||
|
\param physicalAddress The physical address to search for.
|
||||||
|
\param callback Callback object to be notified of each found virtual
|
||||||
|
address.
|
||||||
|
\return \c true, if for a found virtual address the callback's
|
||||||
|
HandleVirtualAddress() returned \c true, \c false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
VMTranslationMap::DebugGetReverseMappingInfo(phys_addr_t physicalAddress,
|
||||||
|
ReverseMappingInfoCallback& callback)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Called by UnmapPage() after performing the architecture specific part.
|
/*! Called by UnmapPage() after performing the architecture specific part.
|
||||||
Looks up the page, updates its flags, removes the page-area mapping, and
|
Looks up the page, updates its flags, removes the page-area mapping, and
|
||||||
requeues the page, if necessary.
|
requeues the page, if necessary.
|
||||||
@@ -227,6 +260,14 @@ VMTranslationMap::UnaccessedPageUnmapped(VMArea* area, page_num_t pageNumber)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ReverseMappingInfoCallback
|
||||||
|
|
||||||
|
|
||||||
|
VMTranslationMap::ReverseMappingInfoCallback::~ReverseMappingInfoCallback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - VMPhysicalPageMapper
|
// #pragma mark - VMPhysicalPageMapper
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3410,6 +3410,147 @@ dump_available_memory(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
dump_mapping_info(int argc, char** argv)
|
||||||
|
{
|
||||||
|
bool reverseLookup = false;
|
||||||
|
bool pageLookup = false;
|
||||||
|
|
||||||
|
int argi = 1;
|
||||||
|
for (; argi < argc && argv[argi][0] == '-'; argi++) {
|
||||||
|
const char* arg = argv[argi];
|
||||||
|
if (strcmp(arg, "-r") == 0) {
|
||||||
|
reverseLookup = true;
|
||||||
|
} else if (strcmp(arg, "-p") == 0) {
|
||||||
|
reverseLookup = true;
|
||||||
|
pageLookup = true;
|
||||||
|
} else {
|
||||||
|
print_debugger_command_usage(argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need at least one argument, the address. Optionally a team ID can be
|
||||||
|
// specified.
|
||||||
|
if (argi >= argc || argi + 1 < argc) {
|
||||||
|
print_debugger_command_usage(argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 addressValue;
|
||||||
|
if (!evaluate_debug_expression(argv[argi++], &addressValue, false))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint64 teamID = B_CURRENT_TEAM;
|
||||||
|
bool teamSpecified = argi < argc;
|
||||||
|
if (teamSpecified) {
|
||||||
|
if (!evaluate_debug_expression(argv[argi++], &teamID, false))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverseLookup) {
|
||||||
|
phys_addr_t physicalAddress;
|
||||||
|
if (pageLookup) {
|
||||||
|
vm_page* page = (vm_page*)(addr_t)addressValue;
|
||||||
|
physicalAddress = page->physical_page_number * B_PAGE_SIZE;
|
||||||
|
} else {
|
||||||
|
physicalAddress = (phys_addr_t)addressValue;
|
||||||
|
physicalAddress -= physicalAddress % B_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf(" Team Virtual Address Area\n");
|
||||||
|
kprintf("--------------------------------------\n");
|
||||||
|
|
||||||
|
struct Callback : VMTranslationMap::ReverseMappingInfoCallback {
|
||||||
|
Callback()
|
||||||
|
:
|
||||||
|
fAddressSpace(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAddressSpace(VMAddressSpace* addressSpace)
|
||||||
|
{
|
||||||
|
fAddressSpace = addressSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool HandleVirtualAddress(addr_t virtualAddress)
|
||||||
|
{
|
||||||
|
kprintf("%8" B_PRId32 " %#18" B_PRIxADDR, fAddressSpace->ID(),
|
||||||
|
virtualAddress);
|
||||||
|
if (VMArea* area = fAddressSpace->LookupArea(virtualAddress))
|
||||||
|
kprintf(" %8" B_PRId32 " %s\n", area->id, area->name);
|
||||||
|
else
|
||||||
|
kprintf("\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VMAddressSpace* fAddressSpace;
|
||||||
|
} callback;
|
||||||
|
|
||||||
|
if (teamSpecified) {
|
||||||
|
// team specified -- get its address space
|
||||||
|
VMAddressSpace* addressSpace;
|
||||||
|
if (teamID == B_CURRENT_TEAM) {
|
||||||
|
Thread* thread = debug_get_debugged_thread();
|
||||||
|
if (thread == NULL || thread->team == NULL) {
|
||||||
|
kprintf("Failed to get team!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addressSpace = thread->team->address_space;
|
||||||
|
} else
|
||||||
|
addressSpace = VMAddressSpace::DebugGet(teamID);
|
||||||
|
|
||||||
|
if (addressSpace == NULL) {
|
||||||
|
kprintf("Failed to get address space!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.SetAddressSpace(addressSpace);
|
||||||
|
addressSpace->TranslationMap()->DebugGetReverseMappingInfo(
|
||||||
|
physicalAddress, callback);
|
||||||
|
} else {
|
||||||
|
// no team specified -- iterate through all address spaces
|
||||||
|
for (VMAddressSpace* addressSpace = VMAddressSpace::DebugFirst();
|
||||||
|
addressSpace != NULL;
|
||||||
|
addressSpace = VMAddressSpace::DebugNext(addressSpace)) {
|
||||||
|
callback.SetAddressSpace(addressSpace);
|
||||||
|
addressSpace->TranslationMap()->DebugGetReverseMappingInfo(
|
||||||
|
physicalAddress, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get the address space
|
||||||
|
addr_t virtualAddress = (addr_t)addressValue;
|
||||||
|
virtualAddress -= virtualAddress % B_PAGE_SIZE;
|
||||||
|
VMAddressSpace* addressSpace;
|
||||||
|
if (IS_KERNEL_ADDRESS(virtualAddress)) {
|
||||||
|
addressSpace = VMAddressSpace::Kernel();
|
||||||
|
} else if (!teamSpecified || teamID == B_CURRENT_TEAM) {
|
||||||
|
Thread* thread = debug_get_debugged_thread();
|
||||||
|
if (thread == NULL || thread->team == NULL) {
|
||||||
|
kprintf("Failed to get team!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addressSpace = thread->team->address_space;
|
||||||
|
} else
|
||||||
|
addressSpace = VMAddressSpace::DebugGet(teamID);
|
||||||
|
|
||||||
|
if (addressSpace == NULL) {
|
||||||
|
kprintf("Failed to get address space!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let the translation map implementation do the job
|
||||||
|
addressSpace->TranslationMap()->DebugPrintMappingInfo(virtualAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Deletes all areas and reserved regions in the given address space.
|
/*! Deletes all areas and reserved regions in the given address space.
|
||||||
|
|
||||||
The caller must ensure that none of the areas has any wired ranges.
|
The caller must ensure that none of the areas has any wired ranges.
|
||||||
@@ -3935,6 +4076,20 @@ vm_init(kernel_args* args)
|
|||||||
add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)");
|
add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)");
|
||||||
add_debugger_command("string", &display_mem, "dump strings");
|
add_debugger_command("string", &display_mem, "dump strings");
|
||||||
|
|
||||||
|
add_debugger_command_etc("mapping", &dump_mapping_info,
|
||||||
|
"Print address mapping information",
|
||||||
|
"[ \"-r\" | \"-p\" ] <address> [ <team ID> ]\n"
|
||||||
|
"Prints low-level page mapping information for a given address. If\n"
|
||||||
|
"neither \"-r\" nor \"-p\" are specified, <address> is a virtual\n"
|
||||||
|
"address that is looked up in the translation map of the current\n"
|
||||||
|
"team, respectively the team specified by ID <team ID>. If \"-r\" is\n"
|
||||||
|
"specified, <address> is a physical address that is searched in the\n"
|
||||||
|
"translation map of all teams, respectively the team specified by ID\n"
|
||||||
|
" <team ID>. If \"-p\" is specified, <address> is the address of a\n"
|
||||||
|
"vm_page structure. The behavior is equivalent to specifying \"-r\"\n"
|
||||||
|
"with the physical address of that page.\n",
|
||||||
|
0);
|
||||||
|
|
||||||
TRACE(("vm_init: exit\n"));
|
TRACE(("vm_init: exit\n"));
|
||||||
|
|
||||||
vm_cache_init_post_heap();
|
vm_cache_init_post_heap();
|
||||||
|
|||||||
Reference in New Issue
Block a user