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:
parent
75c19f7043
commit
7b83ce1142
@ -20,6 +20,9 @@ struct vm_page_reservation;
|
||||
|
||||
|
||||
struct VMTranslationMap {
|
||||
struct ReverseMappingInfoCallback;
|
||||
|
||||
public:
|
||||
VMTranslationMap();
|
||||
virtual ~VMTranslationMap();
|
||||
|
||||
@ -72,6 +75,12 @@ struct VMTranslationMap {
|
||||
|
||||
virtual void Flush() = 0;
|
||||
|
||||
// backends for KDL commands
|
||||
virtual void DebugPrintMappingInfo(addr_t virtualAddress);
|
||||
virtual bool DebugGetReverseMappingInfo(
|
||||
phys_addr_t physicalAddress,
|
||||
ReverseMappingInfoCallback& callback);
|
||||
|
||||
protected:
|
||||
void PageUnmapped(VMArea* area,
|
||||
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 {
|
||||
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*
|
||||
X86VMTranslationMapPAE::PagingStructures() const
|
||||
{
|
||||
|
@ -59,6 +59,11 @@ struct X86VMTranslationMapPAE : X86VMTranslationMap {
|
||||
bool unmapIfUnaccessed,
|
||||
bool& _modified);
|
||||
|
||||
virtual void DebugPrintMappingInfo(addr_t virtualAddress);
|
||||
virtual bool DebugGetReverseMappingInfo(
|
||||
phys_addr_t physicalAddress,
|
||||
ReverseMappingInfoCallback& callback);
|
||||
|
||||
virtual X86PagingStructures* PagingStructures() const;
|
||||
inline X86PagingStructuresPAE* PagingStructuresPAE() const
|
||||
{ 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.
|
||||
Looks up the page, updates its flags, removes the page-area mapping, and
|
||||
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
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
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("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"));
|
||||
|
||||
vm_cache_init_post_heap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user