* Added tlbia() and tlbie() macros. Replaced ptesync() by ppc_sync();
the fact that I couldn't find ptesync in an otherwise more complete documentation I downloaded yesterday made me suspicious. * arch_cpu_global_TLB_invalidate() uses tlbia now. The instruction is optional, but so is tlbie (how I understood it is that both exist, when the architecture implementation has a TLB). And the former loop looked just scary. * Implemented arch_cpu_user_TLB_invalidate(). It does just the same as arch_cpu_global_TLB_invalidate(). * Some changes with respect to synchronization required on page table and segment register updates. * Some more minor renaming. Pulled a new function remove_page_table_entry() out of unmap_tmap(). * In arch_vm_translation_map_init_post_area() we do now remap the page table into the kernel address space, if it was without before. The page table might actually be a good application for BAT, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15773 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -113,6 +113,8 @@ extern void ppc_context_switch(void **_oldStackPointer, void *newStackPointer);
|
|||||||
#define eieio() asm volatile("eieio")
|
#define eieio() asm volatile("eieio")
|
||||||
#define isync() asm volatile("isync")
|
#define isync() asm volatile("isync")
|
||||||
#define tlbsync() asm volatile("tlbsync")
|
#define tlbsync() asm volatile("tlbsync")
|
||||||
#define ptesync() asm volatile("ptesync")
|
#define ppc_sync() asm volatile("sync")
|
||||||
|
#define tlbia() asm volatile("tlbia")
|
||||||
|
#define tlbie(addr) asm volatile("tlbie %0" :: "r" (addr))
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_PPC_CPU_H */
|
#endif /* _KERNEL_ARCH_PPC_CPU_H */
|
||||||
|
|||||||
@@ -101,26 +101,18 @@ arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
|
|||||||
void
|
void
|
||||||
arch_cpu_global_TLB_invalidate(void)
|
arch_cpu_global_TLB_invalidate(void)
|
||||||
{
|
{
|
||||||
addr_t address = 0;
|
ppc_sync();
|
||||||
unsigned long i;
|
tlbia();
|
||||||
|
ppc_sync();
|
||||||
asm volatile("sync");
|
|
||||||
for (i = 0; i < 0x100000; i++) {
|
|
||||||
asm volatile("tlbie %0" :: "r" (address));
|
|
||||||
eieio();
|
|
||||||
asm volatile("sync");
|
|
||||||
|
|
||||||
address += B_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
tlbsync();
|
|
||||||
asm volatile("sync");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_cpu_user_TLB_invalidate(void)
|
arch_cpu_user_TLB_invalidate(void)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
ppc_sync();
|
||||||
|
tlbia();
|
||||||
|
ppc_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
static struct page_table_entry_group *sPageTable;
|
static struct page_table_entry_group *sPageTable;
|
||||||
static size_t sPageTableSize;
|
static size_t sPageTableSize;
|
||||||
static uint32 sPageTableHashMask;
|
static uint32 sPageTableHashMask;
|
||||||
static area_id sPageTableRegion;
|
static area_id sPageTableArea;
|
||||||
|
|
||||||
|
|
||||||
// 512 MB of iospace
|
// 512 MB of iospace
|
||||||
@@ -125,6 +125,7 @@ ppc_translation_map_change_asid(vm_translation_map *map)
|
|||||||
#endif
|
#endif
|
||||||
int vsidBase = map->arch_data->vsid_base;
|
int vsidBase = map->arch_data->vsid_base;
|
||||||
|
|
||||||
|
isync(); // synchronize context
|
||||||
asm("mtsr 0,%0" : : "g"(vsidBase));
|
asm("mtsr 0,%0" : : "g"(vsidBase));
|
||||||
asm("mtsr 1,%0" : : "g"(vsidBase + 1));
|
asm("mtsr 1,%0" : : "g"(vsidBase + 1));
|
||||||
asm("mtsr 2,%0" : : "g"(vsidBase + 2));
|
asm("mtsr 2,%0" : : "g"(vsidBase + 2));
|
||||||
@@ -133,6 +134,7 @@ ppc_translation_map_change_asid(vm_translation_map *map)
|
|||||||
asm("mtsr 5,%0" : : "g"(vsidBase + 5));
|
asm("mtsr 5,%0" : : "g"(vsidBase + 5));
|
||||||
asm("mtsr 6,%0" : : "g"(vsidBase + 6));
|
asm("mtsr 6,%0" : : "g"(vsidBase + 6));
|
||||||
asm("mtsr 7,%0" : : "g"(vsidBase + 7));
|
asm("mtsr 7,%0" : : "g"(vsidBase + 7));
|
||||||
|
isync(); // synchronize context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +161,7 @@ destroy_tmap(vm_translation_map *map)
|
|||||||
panic("vm_translation_map.destroy_tmap: map %p has positive map count %d\n", map, map->map_count);
|
panic("vm_translation_map.destroy_tmap: map %p has positive map count %d\n", map, map->map_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the asid not in use
|
// mark the vsid base not in use
|
||||||
int baseBit = map->arch_data->vsid_base >> VSID_BASE_SHIFT;
|
int baseBit = map->arch_data->vsid_base >> VSID_BASE_SHIFT;
|
||||||
atomic_and((vint32 *)&sVSIDBaseBitmap[baseBit / 32],
|
atomic_and((vint32 *)&sVSIDBaseBitmap[baseBit / 32],
|
||||||
~(1 << (baseBit % 32)));
|
~(1 << (baseBit % 32)));
|
||||||
@@ -195,7 +197,7 @@ fill_page_table_entry(page_table_entry *entry, uint32 virtualSegmentID,
|
|||||||
entry->abbr_page_index = (virtualAddress >> 22) & 0x3f;
|
entry->abbr_page_index = (virtualAddress >> 22) & 0x3f;
|
||||||
entry->valid = true;
|
entry->valid = true;
|
||||||
|
|
||||||
ptesync();
|
ppc_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -253,12 +255,12 @@ map_tmap(vm_translation_map *map, addr_t virtualAddress, addr_t physicalAddress,
|
|||||||
|
|
||||||
|
|
||||||
static page_table_entry *
|
static page_table_entry *
|
||||||
lookup_pagetable_entry(vm_translation_map *map, addr_t virtualAddress)
|
lookup_page_table_entry(vm_translation_map *map, addr_t virtualAddress)
|
||||||
{
|
{
|
||||||
// lookup the vsid based off the va
|
// lookup the vsid based off the va
|
||||||
uint32 virtualSegmentID = VADDR_TO_VSID(map, virtualAddress);
|
uint32 virtualSegmentID = VADDR_TO_VSID(map, virtualAddress);
|
||||||
|
|
||||||
// dprintf("vm_translation_map.lookup_pagetable_entry: vsid %d, va 0x%lx\n", vsid, va);
|
// dprintf("vm_translation_map.lookup_page_table_entry: vsid %d, va 0x%lx\n", vsid, va);
|
||||||
|
|
||||||
|
|
||||||
// Search for the page table entry using the primary hash value
|
// Search for the page table entry using the primary hash value
|
||||||
@@ -293,6 +295,23 @@ lookup_pagetable_entry(vm_translation_map *map, addr_t virtualAddress)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
remove_page_table_entry(vm_translation_map *map, addr_t virtualAddress)
|
||||||
|
{
|
||||||
|
page_table_entry *entry = lookup_page_table_entry(map, virtualAddress);
|
||||||
|
if (entry) {
|
||||||
|
entry->valid = 0;
|
||||||
|
ppc_sync();
|
||||||
|
tlbie(virtualAddress);
|
||||||
|
eieio();
|
||||||
|
tlbsync();
|
||||||
|
ppc_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
unmap_tmap(vm_translation_map *map, addr_t start, addr_t end)
|
unmap_tmap(vm_translation_map *map, addr_t start, addr_t end)
|
||||||
{
|
{
|
||||||
@@ -304,13 +323,8 @@ unmap_tmap(vm_translation_map *map, addr_t start, addr_t end)
|
|||||||
dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end);
|
dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end);
|
||||||
|
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
entry = lookup_pagetable_entry(map, start);
|
if (remove_page_table_entry(map, start))
|
||||||
if (entry) {
|
|
||||||
// unmap this page
|
|
||||||
entry->valid = 0;
|
|
||||||
arch_cpu_global_TLB_invalidate();
|
|
||||||
map->map_count--;
|
map->map_count--;
|
||||||
}
|
|
||||||
|
|
||||||
start += B_PAGE_SIZE;
|
start += B_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
@@ -328,7 +342,7 @@ query_tmap(vm_translation_map *map, addr_t va, addr_t *_outPhysical, uint32 *_ou
|
|||||||
*_outFlags = 0;
|
*_outFlags = 0;
|
||||||
*_outPhysical = 0;
|
*_outPhysical = 0;
|
||||||
|
|
||||||
entry = lookup_pagetable_entry(map, va);
|
entry = lookup_page_table_entry(map, va);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
|
|
||||||
@@ -366,16 +380,29 @@ protect_tmap(vm_translation_map *map, addr_t base, addr_t top, uint32 attributes
|
|||||||
static status_t
|
static status_t
|
||||||
clear_flags_tmap(vm_translation_map *map, addr_t virtualAddress, uint32 flags)
|
clear_flags_tmap(vm_translation_map *map, addr_t virtualAddress, uint32 flags)
|
||||||
{
|
{
|
||||||
page_table_entry *entry = lookup_pagetable_entry(map, virtualAddress);
|
page_table_entry *entry = lookup_page_table_entry(map, virtualAddress);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
|
|
||||||
if (flags & PAGE_MODIFIED)
|
bool modified = false;
|
||||||
entry->changed = false;
|
|
||||||
if (flags & PAGE_ACCESSED)
|
|
||||||
entry->referenced = false;
|
|
||||||
|
|
||||||
arch_cpu_global_TLB_invalidate();
|
// clear the bits
|
||||||
|
if (flags & PAGE_MODIFIED && entry->changed) {
|
||||||
|
entry->changed = false;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
if (flags & PAGE_ACCESSED && entry->referenced) {
|
||||||
|
entry->referenced = false;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// synchronize
|
||||||
|
if (modified) {
|
||||||
|
tlbie(virtualAddress);
|
||||||
|
eieio();
|
||||||
|
tlbsync();
|
||||||
|
ppc_sync();
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -458,13 +485,13 @@ arch_vm_translation_map_init_map(vm_translation_map *map, bool kernel)
|
|||||||
cpu_status state = disable_interrupts();
|
cpu_status state = disable_interrupts();
|
||||||
acquire_spinlock(&sVSIDBaseBitmapLock);
|
acquire_spinlock(&sVSIDBaseBitmapLock);
|
||||||
|
|
||||||
// allocate a ASID base for this one
|
// allocate a VSID base for this one
|
||||||
if (kernel) {
|
if (kernel) {
|
||||||
// The boot loader (respectively the Open Firmware) should has set up
|
// The boot loader has set up the segment registers for identical
|
||||||
// the segment registers for identical mapping. Two VSID bases are
|
// mapping. Two VSID bases are reserved for the kernel: 0 and 8. The
|
||||||
// reserved for the kernel: 0 and 8. The latter one for mapping the
|
// latter one for mapping the kernel address space (0x80000000...), the
|
||||||
// kernel address space (0x80000000...), the former one for the lower
|
// former one for the lower addresses required by the Open Firmware
|
||||||
// addresses required by the Open Firmware services.
|
// services.
|
||||||
map->arch_data->vsid_base = 0;
|
map->arch_data->vsid_base = 0;
|
||||||
sVSIDBaseBitmap[0] |= 0x3;
|
sVSIDBaseBitmap[0] |= 0x3;
|
||||||
} else {
|
} else {
|
||||||
@@ -525,8 +552,63 @@ arch_vm_translation_map_init_post_sem(kernel_args *args)
|
|||||||
status_t
|
status_t
|
||||||
arch_vm_translation_map_init_post_area(kernel_args *args)
|
arch_vm_translation_map_init_post_area(kernel_args *args)
|
||||||
{
|
{
|
||||||
// create a region to cover the page table
|
// If the page table doesn't lie within the kernel address space, we
|
||||||
sPageTableRegion = create_area("page_table", (void **)&sPageTable, B_EXACT_ADDRESS,
|
// remap it.
|
||||||
|
if (!IS_KERNEL_ADDRESS(sPageTable)) {
|
||||||
|
vm_address_space *addressSpace = vm_kernel_address_space();
|
||||||
|
|
||||||
|
// reserve space in the address space
|
||||||
|
void *newAddress = NULL;
|
||||||
|
status_t error = vm_reserve_address_range(addressSpace->id,
|
||||||
|
&newAddress, B_ANY_KERNEL_ADDRESS, sPageTableSize,
|
||||||
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
if (error != B_OK) {
|
||||||
|
panic("arch_vm_translation_map_init_post_area(): Failed to reserve "
|
||||||
|
"space for the page table!");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table page's first physical page
|
||||||
|
page_table_entry *entry = lookup_page_table_entry(
|
||||||
|
&addressSpace->translation_map, (addr_t)sPageTable);
|
||||||
|
if (!entry) {
|
||||||
|
panic("arch_vm_translation_map_init_post_area(): Couldn't find "
|
||||||
|
"the physical address of the page table!");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
addr_t physicalBase = entry->physical_page_number << 12;
|
||||||
|
|
||||||
|
// map the pages
|
||||||
|
for (addr_t i = 0; i < sPageTableSize; i += B_PAGE_SIZE) {
|
||||||
|
addr_t virtualAddress = (addr_t)newAddress + i;
|
||||||
|
addr_t physicalAddress = physicalBase + i;
|
||||||
|
|
||||||
|
error = map_tmap(&addressSpace->translation_map, virtualAddress,
|
||||||
|
physicalAddress, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
if (error != B_OK) {
|
||||||
|
panic("arch_vm_translation_map_init_post_area(): Failed to "
|
||||||
|
"remap the page table!");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the new page table address
|
||||||
|
addr_t oldVirtualBase = (addr_t)(sPageTable);
|
||||||
|
sPageTable = (page_table_entry_group*)newAddress;
|
||||||
|
|
||||||
|
// unmap the old pages
|
||||||
|
for (addr_t i = 0; i < sPageTableSize; i += B_PAGE_SIZE) {
|
||||||
|
remove_page_table_entry(&addressSpace->translation_map,
|
||||||
|
oldVirtualBase + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We should probably map the page table via BAT. It is relatively large,
|
||||||
|
// and due to being a hash table the access patterns might look sporadic, which
|
||||||
|
// certainly isn't to the liking of the TLB.
|
||||||
|
}
|
||||||
|
|
||||||
|
// create an area to cover the page table
|
||||||
|
sPageTableArea = create_area("page_table", (void **)&sPageTable, B_EXACT_ADDRESS,
|
||||||
sPageTableSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
sPageTableSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
Reference in New Issue
Block a user