Fleshed out most of the unimplemented methods. The kernel boots up to the
creation of the initial shell, now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37085 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, Ingo Weinhold, [email protected].
|
* Copyright 2008-2010, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2002-2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -57,9 +61,11 @@ struct X86PagingMethodPAE::ToPAESwitcher {
|
|||||||
fPageHolePageDir, fPhysicalPageDir);
|
fPageHolePageDir, fPhysicalPageDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Switch(void*& _pageStructures, size_t& _pageStructuresSize,
|
void Switch(pae_page_directory_pointer_table_entry*& _virtualPDPT,
|
||||||
pae_page_directory_entry** pageDirs, phys_addr_t* physicalPageDirs,
|
phys_addr_t& _physicalPDPT, void*& _pageStructures,
|
||||||
addr_t& _freeVirtualSlot, pae_page_table_entry*& _freeVirtualSlotPTE)
|
size_t& _pageStructuresSize, pae_page_directory_entry** pageDirs,
|
||||||
|
phys_addr_t* physicalPageDirs, addr_t& _freeVirtualSlot,
|
||||||
|
pae_page_table_entry*& _freeVirtualSlotPTE)
|
||||||
{
|
{
|
||||||
// count the page tables we have to translate
|
// count the page tables we have to translate
|
||||||
uint32 pageTableCount = 0;
|
uint32 pageTableCount = 0;
|
||||||
@@ -134,6 +140,8 @@ struct X86PagingMethodPAE::ToPAESwitcher {
|
|||||||
x86_write_cr4(x86_read_cr4() | IA32_CR4_PAE | IA32_CR4_GLOBAL_PAGES);
|
x86_write_cr4(x86_read_cr4() | IA32_CR4_PAE | IA32_CR4_GLOBAL_PAGES);
|
||||||
|
|
||||||
// set return values
|
// set return values
|
||||||
|
_virtualPDPT = pdpt;
|
||||||
|
_physicalPDPT = physicalPDPT;
|
||||||
_pageStructures = fAllocatedPages;
|
_pageStructures = fAllocatedPages;
|
||||||
_pageStructuresSize = (size_t)fUsedPagesCount * B_PAGE_SIZE;
|
_pageStructuresSize = (size_t)fUsedPagesCount * B_PAGE_SIZE;
|
||||||
memcpy(pageDirs, fPageDirs, sizeof(fPageDirs));
|
memcpy(pageDirs, fPageDirs, sizeof(fPageDirs));
|
||||||
@@ -439,8 +447,12 @@ void
|
|||||||
X86PagingMethodPAE::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress,
|
X86PagingMethodPAE::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress,
|
||||||
addr_t virtualAddress)
|
addr_t virtualAddress)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
pae_page_table_entry& pte = fPageTable[
|
||||||
panic("X86PagingMethodPAE::PhysicalPageSlotPool::Map(): not implemented");
|
(virtualAddress - fVirtualBase) / B_PAGE_SIZE];
|
||||||
|
pte = (physicalAddress & X86_PAE_PTE_ADDRESS_MASK)
|
||||||
|
| X86_PAE_PTE_WRITABLE | X86_PAE_PTE_GLOBAL | X86_PAE_PTE_PRESENT;
|
||||||
|
|
||||||
|
invalidate_TLB(virtualAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -475,9 +487,10 @@ X86PagingMethodPAE::Init(kernel_args* args,
|
|||||||
VMPhysicalPageMapper** _physicalPageMapper)
|
VMPhysicalPageMapper** _physicalPageMapper)
|
||||||
{
|
{
|
||||||
// switch to PAE
|
// switch to PAE
|
||||||
ToPAESwitcher(args).Switch(fEarlyPageStructures, fEarlyPageStructuresSize,
|
ToPAESwitcher(args).Switch(fKernelVirtualPageDirPointerTable,
|
||||||
fKernelVirtualPageDirs, fKernelPhysicalPageDirs, fFreeVirtualSlot,
|
fKernelPhysicalPageDirPointerTable, fEarlyPageStructures,
|
||||||
fFreeVirtualSlotPTE);
|
fEarlyPageStructuresSize, fKernelVirtualPageDirs,
|
||||||
|
fKernelPhysicalPageDirs, fFreeVirtualSlot, fFreeVirtualSlotPTE);
|
||||||
|
|
||||||
// create the initial pool for the physical page mapper
|
// create the initial pool for the physical page mapper
|
||||||
PhysicalPageSlotPool* pool
|
PhysicalPageSlotPool* pool
|
||||||
@@ -502,18 +515,38 @@ X86PagingMethodPAE::Init(kernel_args* args,
|
|||||||
status_t
|
status_t
|
||||||
X86PagingMethodPAE::InitPostArea(kernel_args* args)
|
X86PagingMethodPAE::InitPostArea(kernel_args* args)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// wrap the kernel paging structures in an area
|
||||||
panic("X86PagingMethodPAE::InitPostArea(): not implemented");
|
area_id area = create_area("kernel paging structs", &fEarlyPageStructures,
|
||||||
return B_UNSUPPORTED;
|
B_EXACT_ADDRESS, fEarlyPageStructuresSize, B_ALREADY_WIRED,
|
||||||
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
if (area < B_OK)
|
||||||
|
return area;
|
||||||
|
|
||||||
|
// let the initial page pool create areas for its structures
|
||||||
|
status_t error = PhysicalPageSlotPool::sInitialPhysicalPagePool
|
||||||
|
.InitInitialPostArea(args);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86PagingMethodPAE::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
|
X86PagingMethodPAE::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
X86VMTranslationMapPAE* map = new(std::nothrow) X86VMTranslationMapPAE;
|
||||||
panic("X86PagingMethodPAE::CreateTranslationMap(): not implemented");
|
if (map == NULL)
|
||||||
return B_UNSUPPORTED;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = map->Init(kernel);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete map;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
*_map = map;
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -533,7 +566,7 @@ X86PagingMethodPAE::MapEarly(kernel_args* args, addr_t virtualAddress,
|
|||||||
TRACE("X86PagingMethodPAE::MapEarly(): asked for free page for "
|
TRACE("X86PagingMethodPAE::MapEarly(): asked for free page for "
|
||||||
"page table: %#" B_PRIxPHYSADDR "\n", physicalPageTable);
|
"page table: %#" B_PRIxPHYSADDR "\n", physicalPageTable);
|
||||||
|
|
||||||
// put it in the pgdir
|
// put it in the page dir
|
||||||
PutPageTableInPageDir(pageDirEntry, physicalPageTable, attributes);
|
PutPageTableInPageDir(pageDirEntry, physicalPageTable, attributes);
|
||||||
|
|
||||||
// zero it out
|
// zero it out
|
||||||
|
|||||||
@@ -46,8 +46,13 @@ public:
|
|||||||
inline TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const
|
inline TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const
|
||||||
{ return fKernelPhysicalPageMapper; }
|
{ return fKernelPhysicalPageMapper; }
|
||||||
|
|
||||||
|
inline pae_page_directory_pointer_table_entry*
|
||||||
|
KernelVirtualPageDirPointerTable() const;
|
||||||
|
inline phys_addr_t KernelPhysicalPageDirPointerTable() const;
|
||||||
inline pae_page_directory_entry* const* KernelVirtualPageDirs() const
|
inline pae_page_directory_entry* const* KernelVirtualPageDirs() const
|
||||||
{ return fKernelVirtualPageDirs; }
|
{ return fKernelVirtualPageDirs; }
|
||||||
|
inline const phys_addr_t* KernelPhysicalPageDirs() const
|
||||||
|
{ return fKernelPhysicalPageDirs; }
|
||||||
|
|
||||||
static X86PagingMethodPAE* Method();
|
static X86PagingMethodPAE* Method();
|
||||||
|
|
||||||
@@ -60,6 +65,18 @@ public:
|
|||||||
phys_addr_t physicalAddress,
|
phys_addr_t physicalAddress,
|
||||||
uint32 attributes, uint32 memoryType,
|
uint32 attributes, uint32 memoryType,
|
||||||
bool globalPage);
|
bool globalPage);
|
||||||
|
static pae_page_table_entry SetPageTableEntry(pae_page_table_entry* entry,
|
||||||
|
pae_page_table_entry newEntry);
|
||||||
|
static pae_page_table_entry SetPageTableEntryFlags(
|
||||||
|
pae_page_table_entry* entry, uint64 flags);
|
||||||
|
static pae_page_table_entry TestAndSetPageTableEntry(
|
||||||
|
pae_page_table_entry* entry,
|
||||||
|
pae_page_table_entry newEntry,
|
||||||
|
pae_page_table_entry oldEntry);
|
||||||
|
static pae_page_table_entry ClearPageTableEntry(
|
||||||
|
pae_page_table_entry* entry);
|
||||||
|
static pae_page_table_entry ClearPageTableEntryFlags(
|
||||||
|
pae_page_table_entry* entry, uint64 flags);
|
||||||
|
|
||||||
static pae_page_directory_entry* PageDirEntryForAddress(
|
static pae_page_directory_entry* PageDirEntryForAddress(
|
||||||
pae_page_directory_entry* const* pdpt,
|
pae_page_directory_entry* const* pdpt,
|
||||||
@@ -84,6 +101,9 @@ private:
|
|||||||
|
|
||||||
void* fEarlyPageStructures;
|
void* fEarlyPageStructures;
|
||||||
size_t fEarlyPageStructuresSize;
|
size_t fEarlyPageStructuresSize;
|
||||||
|
pae_page_directory_pointer_table_entry*
|
||||||
|
fKernelVirtualPageDirPointerTable;
|
||||||
|
phys_addr_t fKernelPhysicalPageDirPointerTable;
|
||||||
pae_page_directory_entry* fKernelVirtualPageDirs[4];
|
pae_page_directory_entry* fKernelVirtualPageDirs[4];
|
||||||
phys_addr_t fKernelPhysicalPageDirs[4];
|
phys_addr_t fKernelPhysicalPageDirs[4];
|
||||||
addr_t fFreeVirtualSlot;
|
addr_t fFreeVirtualSlot;
|
||||||
@@ -91,6 +111,20 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
pae_page_directory_pointer_table_entry*
|
||||||
|
X86PagingMethodPAE::KernelVirtualPageDirPointerTable() const
|
||||||
|
{
|
||||||
|
return fKernelVirtualPageDirPointerTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
phys_addr_t
|
||||||
|
X86PagingMethodPAE::KernelPhysicalPageDirPointerTable() const
|
||||||
|
{
|
||||||
|
return fKernelPhysicalPageDirPointerTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ inline X86PagingMethodPAE*
|
/*static*/ inline X86PagingMethodPAE*
|
||||||
X86PagingMethodPAE::Method()
|
X86PagingMethodPAE::Method()
|
||||||
{
|
{
|
||||||
@@ -107,6 +141,45 @@ X86PagingMethodPAE::PageDirEntryForAddress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline pae_page_table_entry
|
||||||
|
X86PagingMethodPAE::SetPageTableEntry(pae_page_table_entry* entry,
|
||||||
|
pae_page_table_entry newEntry)
|
||||||
|
{
|
||||||
|
return atomic_set64((int64*)entry, newEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline pae_page_table_entry
|
||||||
|
X86PagingMethodPAE::SetPageTableEntryFlags(pae_page_table_entry* entry,
|
||||||
|
uint64 flags)
|
||||||
|
{
|
||||||
|
return atomic_or64((int64*)entry, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline pae_page_table_entry
|
||||||
|
X86PagingMethodPAE::TestAndSetPageTableEntry(pae_page_table_entry* entry,
|
||||||
|
pae_page_table_entry newEntry, pae_page_table_entry oldEntry)
|
||||||
|
{
|
||||||
|
return atomic_test_and_set64((int64*)entry, newEntry, oldEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline pae_page_table_entry
|
||||||
|
X86PagingMethodPAE::ClearPageTableEntry(pae_page_table_entry* entry)
|
||||||
|
{
|
||||||
|
return SetPageTableEntry(entry, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline pae_page_table_entry
|
||||||
|
X86PagingMethodPAE::ClearPageTableEntryFlags(pae_page_table_entry* entry,
|
||||||
|
uint64 flags)
|
||||||
|
{
|
||||||
|
return atomic_and64((int64*)entry, ~flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ inline uint32
|
/*static*/ inline uint32
|
||||||
X86PagingMethodPAE::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
|
X86PagingMethodPAE::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "paging/pae/X86PagingStructuresPAE.h"
|
#include "paging/pae/X86PagingStructuresPAE.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -19,14 +21,21 @@ X86PagingStructuresPAE::X86PagingStructuresPAE()
|
|||||||
|
|
||||||
X86PagingStructuresPAE::~X86PagingStructuresPAE()
|
X86PagingStructuresPAE::~X86PagingStructuresPAE()
|
||||||
{
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
panic("X86PagingStructuresPAE::~X86PagingStructuresPAE(): not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
X86PagingStructuresPAE::Init()
|
X86PagingStructuresPAE::Init(
|
||||||
|
pae_page_directory_pointer_table_entry* virtualPDPT,
|
||||||
|
phys_addr_t physicalPDPT, pae_page_directory_entry* const* virtualPageDirs,
|
||||||
|
const phys_addr_t* physicalPageDirs)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
fPageDirPointerTable = virtualPDPT;
|
||||||
panic("X86PagingStructuresPAE::Init(): not implemented");
|
pgdir_phys = physicalPDPT;
|
||||||
|
memcpy(fVirtualPageDirs, virtualPageDirs, sizeof(fVirtualPageDirs));
|
||||||
|
memcpy(fPhysicalPageDirs, physicalPageDirs, sizeof(fPhysicalPageDirs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,12 +47,4 @@ X86PagingStructuresPAE::Delete()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ void
|
|
||||||
X86PagingStructuresPAE::StaticInit()
|
|
||||||
{
|
|
||||||
// TODO: Implement!
|
|
||||||
panic("X86PagingStructuresPAE::StaticInit(): not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // B_HAIKU_PHYSICAL_BITS == 64
|
#endif // B_HAIKU_PHYSICAL_BITS == 64
|
||||||
|
|||||||
@@ -17,11 +17,22 @@ struct X86PagingStructuresPAE : X86PagingStructures {
|
|||||||
X86PagingStructuresPAE();
|
X86PagingStructuresPAE();
|
||||||
virtual ~X86PagingStructuresPAE();
|
virtual ~X86PagingStructuresPAE();
|
||||||
|
|
||||||
void Init();
|
void Init(pae_page_directory_pointer_table_entry*
|
||||||
|
virtualPDPT,
|
||||||
|
phys_addr_t physicalPDPT,
|
||||||
|
pae_page_directory_entry* const*
|
||||||
|
virtualPageDirs,
|
||||||
|
const phys_addr_t* physicalPageDirs);
|
||||||
|
|
||||||
virtual void Delete();
|
virtual void Delete();
|
||||||
|
|
||||||
static void StaticInit();
|
pae_page_directory_entry* const* VirtualPageDirs() const
|
||||||
|
{ return fVirtualPageDirs; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pae_page_directory_pointer_table_entry* fPageDirPointerTable;
|
||||||
|
pae_page_directory_entry* fVirtualPageDirs[4];
|
||||||
|
phys_addr_t fPhysicalPageDirs[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, Ingo Weinhold, [email protected].
|
* Copyright 2008-2010, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2002-2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "paging/pae/X86VMTranslationMapPAE.h"
|
#include "paging/pae/X86VMTranslationMapPAE.h"
|
||||||
|
|
||||||
|
#include <int.h>
|
||||||
|
#include <slab/Slab.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
#include <vm/vm_page.h>
|
||||||
#include <vm/VMAddressSpace.h>
|
#include <vm/VMAddressSpace.h>
|
||||||
#include <vm/VMCache.h>
|
#include <vm/VMCache.h>
|
||||||
|
|
||||||
@@ -45,37 +54,184 @@ X86VMTranslationMapPAE::Init(bool kernel)
|
|||||||
|
|
||||||
X86VMTranslationMap::Init(kernel);
|
X86VMTranslationMap::Init(kernel);
|
||||||
|
|
||||||
// TODO: Implement!
|
fPagingStructures = new(std::nothrow) X86PagingStructuresPAE;
|
||||||
panic("unsupported");
|
if (fPagingStructures == NULL)
|
||||||
return B_UNSUPPORTED;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
X86PagingMethodPAE* method = X86PagingMethodPAE::Method();
|
||||||
|
|
||||||
|
if (kernel) {
|
||||||
|
// kernel
|
||||||
|
// get the physical page mapper
|
||||||
|
fPageMapper = method->KernelPhysicalPageMapper();
|
||||||
|
|
||||||
|
// we already know the kernel pgdir mapping
|
||||||
|
fPagingStructures->Init(method->KernelVirtualPageDirPointerTable(),
|
||||||
|
method->KernelPhysicalPageDirPointerTable(),
|
||||||
|
method->KernelVirtualPageDirs(), method->KernelPhysicalPageDirs());
|
||||||
|
} else {
|
||||||
|
panic("X86VMTranslationMapPAE::Init(): user init not implemented");
|
||||||
|
#if 0
|
||||||
|
// user
|
||||||
|
// allocate a physical page mapper
|
||||||
|
status_t error = method->PhysicalPageMapper()
|
||||||
|
->CreateTranslationMapPhysicalPageMapper(&fPageMapper);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// allocate the page directory
|
||||||
|
page_directory_entry* virtualPageDir = (page_directory_entry*)memalign(
|
||||||
|
B_PAGE_SIZE, B_PAGE_SIZE);
|
||||||
|
if (virtualPageDir == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// look up the page directory's physical address
|
||||||
|
phys_addr_t physicalPageDir;
|
||||||
|
vm_get_page_mapping(VMAddressSpace::KernelID(),
|
||||||
|
(addr_t)virtualPageDir, &physicalPageDir);
|
||||||
|
|
||||||
|
fPagingStructures->Init(virtualPageDir, physicalPageDir,
|
||||||
|
method->KernelVirtualPageDirectory());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
X86VMTranslationMapPAE::MaxPagesNeededToMap(addr_t start, addr_t end) const
|
X86VMTranslationMapPAE::MaxPagesNeededToMap(addr_t start, addr_t end) const
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// If start == 0, the actual base address is not yet known to the caller and
|
||||||
panic("unsupported");
|
// we shall assume the worst case.
|
||||||
return 0;
|
if (start == 0) {
|
||||||
|
// offset the range so it has the worst possible alignment
|
||||||
|
start = kPAEPageTableRange - B_PAGE_SIZE;
|
||||||
|
end += kPAEPageTableRange - B_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return end / kPAEPageTableRange + 1 - start / kPAEPageTableRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::Map(addr_t va, phys_addr_t pa, uint32 attributes,
|
X86VMTranslationMapPAE::Map(addr_t virtualAddress, phys_addr_t physicalAddress,
|
||||||
uint32 memoryType, vm_page_reservation* reservation)
|
uint32 attributes, uint32 memoryType, vm_page_reservation* reservation)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
TRACE("X86VMTranslationMapPAE::Map(): %#" B_PRIxADDR " -> %#" B_PRIxPHYSADDR
|
||||||
panic("unsupported");
|
"\n", virtualAddress, physicalAddress);
|
||||||
return B_UNSUPPORTED;
|
|
||||||
|
// check to see if a page table exists for this range
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), virtualAddress);
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0) {
|
||||||
|
// we need to allocate a page table
|
||||||
|
vm_page *page = vm_page_allocate_page(reservation,
|
||||||
|
PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
|
||||||
|
|
||||||
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
|
|
||||||
|
phys_addr_t physicalPageTable
|
||||||
|
= (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Map(): asked for free page for "
|
||||||
|
"page table: %#" B_PRIxPHYSADDR "\n", physicalPageTable);
|
||||||
|
|
||||||
|
// put it in the page dir
|
||||||
|
X86PagingMethodPAE::PutPageTableInPageDir(pageDirEntry,
|
||||||
|
physicalPageTable,
|
||||||
|
attributes
|
||||||
|
| ((attributes & B_USER_PROTECTION) != 0
|
||||||
|
? B_WRITE_AREA : B_KERNEL_WRITE_AREA));
|
||||||
|
|
||||||
|
fMapCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now, fill in the page table entry
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
ThreadCPUPinner pinner(thread);
|
||||||
|
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
pae_page_table_entry* entry = pageTable
|
||||||
|
+ virtualAddress / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
|
||||||
|
ASSERT_PRINT((*entry & X86_PAE_PTE_PRESENT) == 0,
|
||||||
|
"virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx64,
|
||||||
|
virtualAddress, *entry);
|
||||||
|
|
||||||
|
X86PagingMethodPAE::PutPageTableEntryInTable(entry, physicalAddress,
|
||||||
|
attributes, memoryType, fIsKernelMap);
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
|
||||||
|
// Note: We don't need to invalidate the TLB for this address, as previously
|
||||||
|
// the entry was not present and the TLB doesn't cache those entries.
|
||||||
|
|
||||||
|
fMapCount++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::Unmap(addr_t start, addr_t end)
|
X86VMTranslationMapPAE::Unmap(addr_t start, addr_t end)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
start = ROUNDDOWN(start, B_PAGE_SIZE);
|
||||||
panic("unsupported");
|
if (start >= end)
|
||||||
return B_UNSUPPORTED;
|
return B_OK;
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Unmap(): %#" B_PRIxADDR " - %#" B_PRIxADDR
|
||||||
|
"\n", start, end);
|
||||||
|
|
||||||
|
do {
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), start);
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0) {
|
||||||
|
// no page table here, move the start up to access the next page
|
||||||
|
// table
|
||||||
|
start = ROUNDUP(start + 1, kPAEPageTableRange);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
ThreadCPUPinner pinner(thread);
|
||||||
|
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
|
||||||
|
uint32 index = start / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
for (; index < kPAEPageTableEntryCount && start < end;
|
||||||
|
index++, start += B_PAGE_SIZE) {
|
||||||
|
if ((pageTable[index] & X86_PAE_PTE_PRESENT) == 0) {
|
||||||
|
// page mapping not valid
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Unmap(): removing page %#"
|
||||||
|
B_PRIxADDR "\n", start);
|
||||||
|
|
||||||
|
pae_page_table_entry oldEntry
|
||||||
|
= X86PagingMethodPAE::ClearPageTableEntryFlags(
|
||||||
|
&pageTable[index], X86_PAE_PTE_PRESENT);
|
||||||
|
fMapCount--;
|
||||||
|
|
||||||
|
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0) {
|
||||||
|
// Note, that we only need to invalidate the address, if the
|
||||||
|
// accessed flags was set, since only then the entry could have
|
||||||
|
// been in any TLB.
|
||||||
|
InvalidatePage(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
} while (start != 0 && start < end);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -86,9 +242,113 @@ status_t
|
|||||||
X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
panic("unsupported");
|
|
||||||
return B_UNSUPPORTED;
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), address);
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
||||||
|
|
||||||
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
ThreadCPUPinner pinner(thread_get_current_thread());
|
||||||
|
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
|
||||||
|
pae_page_table_entry oldEntry = X86PagingMethodPAE::ClearPageTableEntry(
|
||||||
|
&pageTable[address / B_PAGE_SIZE % kPAEPageTableEntryCount]);
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
|
||||||
|
if ((oldEntry & X86_PAE_PTE_PRESENT) == 0) {
|
||||||
|
// page mapping not valid
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
fMapCount--;
|
||||||
|
|
||||||
|
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0) {
|
||||||
|
// Note, that we only need to invalidate the address, if the
|
||||||
|
// accessed flags was set, since only then the entry could have been
|
||||||
|
// in any TLB.
|
||||||
|
InvalidatePage(address);
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
|
// processors (actually even this processor with another thread of the
|
||||||
|
// same team) could still access the page in question via their cached
|
||||||
|
// entry. We can obviously lose a modified flag in this case, with the
|
||||||
|
// effect that the page looks unmodified (and might thus be recycled),
|
||||||
|
// but is actually modified.
|
||||||
|
// In most cases this is harmless, but for vm_remove_all_page_mappings()
|
||||||
|
// this is actually a problem.
|
||||||
|
// Interestingly FreeBSD seems to ignore this problem as well
|
||||||
|
// (cf. pmap_remove_all()), unless I've missed something.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area->cache_type == CACHE_TYPE_DEVICE)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// get the page
|
||||||
|
vm_page* page = vm_lookup_page(
|
||||||
|
(oldEntry & X86_PAE_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
|
||||||
|
ASSERT(page != NULL);
|
||||||
|
|
||||||
|
// transfer the accessed/dirty flags to the page
|
||||||
|
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0)
|
||||||
|
page->accessed = true;
|
||||||
|
if ((oldEntry & X86_PAE_PTE_DIRTY) != 0)
|
||||||
|
page->modified = true;
|
||||||
|
|
||||||
|
// TODO: Here comes a lot of paging method and even architecture independent
|
||||||
|
// code. Refactor!
|
||||||
|
|
||||||
|
// remove the mapping object/decrement the wired_count of the page
|
||||||
|
vm_page_mapping* mapping = NULL;
|
||||||
|
if (area->wiring == B_NO_LOCK) {
|
||||||
|
vm_page_mappings::Iterator iterator = page->mappings.GetIterator();
|
||||||
|
while ((mapping = iterator.Next()) != NULL) {
|
||||||
|
if (mapping->area == area) {
|
||||||
|
area->mappings.Remove(mapping);
|
||||||
|
page->mappings.Remove(mapping);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(mapping != NULL);
|
||||||
|
} else
|
||||||
|
page->wired_count--;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
||||||
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
|
if (updatePageQueue) {
|
||||||
|
if (page->Cache()->temporary)
|
||||||
|
vm_page_set_state(page, PAGE_STATE_INACTIVE);
|
||||||
|
else if (page->modified)
|
||||||
|
vm_page_set_state(page, PAGE_STATE_MODIFIED);
|
||||||
|
else
|
||||||
|
vm_page_set_state(page, PAGE_STATE_CACHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping != NULL) {
|
||||||
|
bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
|
||||||
|
object_cache_free(gPageMappingsObjectCache, mapping,
|
||||||
|
CACHE_DONT_WAIT_FOR_MEMORY
|
||||||
|
| (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -96,8 +356,8 @@ void
|
|||||||
X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// TODO: Implement for real!
|
||||||
panic("unsupported");
|
X86VMTranslationMap::UnmapPages(area, base, size, updatePageQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -105,18 +365,59 @@ void
|
|||||||
X86VMTranslationMapPAE::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
X86VMTranslationMapPAE::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
||||||
bool ignoreTopCachePageFlags)
|
bool ignoreTopCachePageFlags)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// TODO: Implement for real!
|
||||||
panic("unsupported");
|
X86VMTranslationMap::UnmapArea(area, deletingAddressSpace,
|
||||||
|
ignoreTopCachePageFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::Query(addr_t va, phys_addr_t *_physical,
|
X86VMTranslationMapPAE::Query(addr_t virtualAddress,
|
||||||
uint32 *_flags)
|
phys_addr_t* _physicalAddress, uint32* _flags)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// default the flags to not present
|
||||||
panic("unsupported");
|
*_flags = 0;
|
||||||
return B_UNSUPPORTED;
|
*_physicalAddress = 0;
|
||||||
|
|
||||||
|
// get the page directory entry
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), virtualAddress);
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0) {
|
||||||
|
// no pagetable here
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the page table entry
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
ThreadCPUPinner pinner(thread);
|
||||||
|
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
pae_page_table_entry entry
|
||||||
|
= pageTable[virtualAddress / B_PAGE_SIZE % kPAEPageTableEntryCount];
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
|
||||||
|
*_physicalAddress = entry & X86_PAE_PTE_ADDRESS_MASK;
|
||||||
|
|
||||||
|
// translate the page state flags
|
||||||
|
if ((entry & X86_PAE_PTE_USER) != 0) {
|
||||||
|
*_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
|
||||||
|
| B_READ_AREA;
|
||||||
|
}
|
||||||
|
|
||||||
|
*_flags |= ((entry & X86_PAE_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
|
||||||
|
| B_KERNEL_READ_AREA
|
||||||
|
| ((entry & X86_PAE_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
|
||||||
|
| ((entry & X86_PAE_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
|
||||||
|
| ((entry & X86_PAE_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Query(%#" B_PRIxADDR ") -> %#"
|
||||||
|
B_PRIxPHYSADDR ":\n", *_physicalAddress, virtualAddress);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -125,7 +426,7 @@ X86VMTranslationMapPAE::QueryInterrupt(addr_t va, phys_addr_t *_physical,
|
|||||||
uint32 *_flags)
|
uint32 *_flags)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
// TODO: Implement!
|
||||||
panic("unsupported");
|
panic("X86VMTranslationMapPAE::QueryInterrupt(): not implemented");
|
||||||
return B_UNSUPPORTED;
|
return B_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,18 +435,116 @@ status_t
|
|||||||
X86VMTranslationMapPAE::Protect(addr_t start, addr_t end, uint32 attributes,
|
X86VMTranslationMapPAE::Protect(addr_t start, addr_t end, uint32 attributes,
|
||||||
uint32 memoryType)
|
uint32 memoryType)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
start = ROUNDDOWN(start, B_PAGE_SIZE);
|
||||||
panic("unsupported");
|
if (start >= end)
|
||||||
return B_UNSUPPORTED;
|
return B_OK;
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Protect(): %#" B_PRIxADDR " - %#" B_PRIxADDR
|
||||||
|
", attributes: %#" B_PRIx32 "\n", start, end, attributes);
|
||||||
|
|
||||||
|
// compute protection flags
|
||||||
|
uint64 newProtectionFlags = 0;
|
||||||
|
if ((attributes & B_USER_PROTECTION) != 0) {
|
||||||
|
newProtectionFlags = X86_PAE_PTE_USER;
|
||||||
|
if ((attributes & B_WRITE_AREA) != 0)
|
||||||
|
newProtectionFlags |= X86_PAE_PTE_WRITABLE;
|
||||||
|
} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
|
||||||
|
newProtectionFlags = X86_PAE_PTE_WRITABLE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), start);
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0) {
|
||||||
|
// no page table here, move the start up to access the next page
|
||||||
|
// table
|
||||||
|
start = ROUNDUP(start + 1, kPAEPageTableRange);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
ThreadCPUPinner pinner(thread);
|
||||||
|
|
||||||
|
pae_page_table_entry* pageTable
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
||||||
|
|
||||||
|
uint32 index = start / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
for (; index < kPAEPageTableEntryCount && start < end;
|
||||||
|
index++, start += B_PAGE_SIZE) {
|
||||||
|
pae_page_table_entry entry = pageTable[index];
|
||||||
|
if ((pageTable[index] & X86_PAE_PTE_PRESENT) == 0) {
|
||||||
|
// page mapping not valid
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::Protect(): protect page %#"
|
||||||
|
B_PRIxADDR "\n", start);
|
||||||
|
|
||||||
|
// set the new protection flags -- we want to do that atomically,
|
||||||
|
// without changing the accessed or dirty flag
|
||||||
|
pae_page_table_entry oldEntry;
|
||||||
|
while (true) {
|
||||||
|
oldEntry = X86PagingMethodPAE::TestAndSetPageTableEntry(
|
||||||
|
&pageTable[index],
|
||||||
|
(entry & ~(X86_PAE_PTE_PROTECTION_MASK
|
||||||
|
| X86_PAE_PTE_MEMORY_TYPE_MASK))
|
||||||
|
| newProtectionFlags
|
||||||
|
| X86PagingMethodPAE::MemoryTypeToPageTableEntryFlags(
|
||||||
|
memoryType),
|
||||||
|
entry);
|
||||||
|
if (oldEntry == entry)
|
||||||
|
break;
|
||||||
|
entry = oldEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0) {
|
||||||
|
// Note, that we only need to invalidate the address, if the
|
||||||
|
// accessed flag was set, since only then the entry could have been
|
||||||
|
// in any TLB.
|
||||||
|
InvalidatePage(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
} while (start != 0 && start < end);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::ClearFlags(addr_t va, uint32 flags)
|
X86VMTranslationMapPAE::ClearFlags(addr_t address, uint32 flags)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
pae_page_directory_entry* pageDirEntry
|
||||||
panic("unsupported");
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
return B_UNSUPPORTED;
|
fPagingStructures->VirtualPageDirs(), address);
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0) {
|
||||||
|
// no pagetable here
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 flagsToClear = ((flags & PAGE_MODIFIED) ? X86_PAE_PTE_DIRTY : 0)
|
||||||
|
| ((flags & PAGE_ACCESSED) ? X86_PAE_PTE_ACCESSED : 0);
|
||||||
|
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
ThreadCPUPinner pinner(thread);
|
||||||
|
|
||||||
|
pae_page_table_entry* entry
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK)
|
||||||
|
+ address / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
|
||||||
|
// clear out the flags we've been requested to clear
|
||||||
|
pae_page_table_entry oldEntry
|
||||||
|
= X86PagingMethodPAE::ClearPageTableEntryFlags(entry, flagsToClear);
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
|
||||||
|
if ((oldEntry & flagsToClear) != 0)
|
||||||
|
InvalidatePage(address);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -153,8 +552,118 @@ bool
|
|||||||
X86VMTranslationMapPAE::ClearAccessedAndModified(VMArea* area, addr_t address,
|
X86VMTranslationMapPAE::ClearAccessedAndModified(VMArea* area, addr_t address,
|
||||||
bool unmapIfUnaccessed, bool& _modified)
|
bool unmapIfUnaccessed, bool& _modified)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
panic("unsupported");
|
|
||||||
|
TRACE("X86VMTranslationMap32Bit::ClearAccessedAndModified(%#" B_PRIxADDR
|
||||||
|
")\n", address);
|
||||||
|
|
||||||
|
pae_page_directory_entry* pageDirEntry
|
||||||
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
|
fPagingStructures->VirtualPageDirs(), address);
|
||||||
|
|
||||||
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ThreadCPUPinner pinner(thread_get_current_thread());
|
||||||
|
|
||||||
|
pae_page_table_entry* entry
|
||||||
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
|
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK)
|
||||||
|
+ address / B_PAGE_SIZE % kPAEPageTableEntryCount;
|
||||||
|
|
||||||
|
// perform the deed
|
||||||
|
pae_page_table_entry oldEntry;
|
||||||
|
|
||||||
|
if (unmapIfUnaccessed) {
|
||||||
|
while (true) {
|
||||||
|
oldEntry = *entry;
|
||||||
|
if ((oldEntry & X86_PAE_PTE_PRESENT) == 0) {
|
||||||
|
// page mapping not valid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldEntry & X86_PAE_PTE_ACCESSED) {
|
||||||
|
// page was accessed -- just clear the flags
|
||||||
|
oldEntry = X86PagingMethodPAE::ClearPageTableEntryFlags(entry,
|
||||||
|
X86_PAE_PTE_ACCESSED | X86_PAE_PTE_DIRTY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// page hasn't been accessed -- unmap it
|
||||||
|
if (X86PagingMethodPAE::TestAndSetPageTableEntry(entry, 0, oldEntry)
|
||||||
|
== oldEntry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// something changed -- check again
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oldEntry = X86PagingMethodPAE::ClearPageTableEntryFlags(entry,
|
||||||
|
X86_PAE_PTE_ACCESSED | X86_PAE_PTE_DIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
pinner.Unlock();
|
||||||
|
|
||||||
|
_modified = (oldEntry & X86_PAE_PTE_DIRTY) != 0;
|
||||||
|
|
||||||
|
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0) {
|
||||||
|
// Note, that we only need to invalidate the address, if the
|
||||||
|
// accessed flags was set, since only then the entry could have been
|
||||||
|
// in any TLB.
|
||||||
|
InvalidatePage(address);
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unmapIfUnaccessed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We have unmapped the address. Do the "high level" stuff.
|
||||||
|
|
||||||
|
fMapCount--;
|
||||||
|
|
||||||
|
if (area->cache_type == CACHE_TYPE_DEVICE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// get the page
|
||||||
|
vm_page* page = vm_lookup_page(
|
||||||
|
(oldEntry & X86_PAE_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
|
||||||
|
ASSERT(page != NULL);
|
||||||
|
|
||||||
|
// TODO: Here comes a lot of paging method and even architecture independent
|
||||||
|
// code. Refactor!
|
||||||
|
|
||||||
|
// remove the mapping object/decrement the wired_count of the page
|
||||||
|
vm_page_mapping* mapping = NULL;
|
||||||
|
if (area->wiring == B_NO_LOCK) {
|
||||||
|
vm_page_mappings::Iterator iterator = page->mappings.GetIterator();
|
||||||
|
while ((mapping = iterator.Next()) != NULL) {
|
||||||
|
if (mapping->area == area) {
|
||||||
|
area->mappings.Remove(mapping);
|
||||||
|
page->mappings.Remove(mapping);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(mapping != NULL);
|
||||||
|
} else
|
||||||
|
page->wired_count--;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (page->wired_count == 0 && page->mappings.IsEmpty())
|
||||||
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
|
if (mapping != NULL) {
|
||||||
|
object_cache_free(gPageMappingsObjectCache, mapping,
|
||||||
|
CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE);
|
||||||
|
// Since this is called by the page daemon, we never want to lock
|
||||||
|
// the kernel address space.
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user