* 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 isync() asm volatile("isync")
|
||||
#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 */
|
||||
|
||||
@@ -101,26 +101,18 @@ arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
|
||||
void
|
||||
arch_cpu_global_TLB_invalidate(void)
|
||||
{
|
||||
addr_t address = 0;
|
||||
unsigned long i;
|
||||
|
||||
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");
|
||||
ppc_sync();
|
||||
tlbia();
|
||||
ppc_sync();
|
||||
}
|
||||
|
||||
|
||||
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 size_t sPageTableSize;
|
||||
static uint32 sPageTableHashMask;
|
||||
static area_id sPageTableRegion;
|
||||
static area_id sPageTableArea;
|
||||
|
||||
|
||||
// 512 MB of iospace
|
||||
@@ -125,6 +125,7 @@ ppc_translation_map_change_asid(vm_translation_map *map)
|
||||
#endif
|
||||
int vsidBase = map->arch_data->vsid_base;
|
||||
|
||||
isync(); // synchronize context
|
||||
asm("mtsr 0,%0" : : "g"(vsidBase));
|
||||
asm("mtsr 1,%0" : : "g"(vsidBase + 1));
|
||||
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 6,%0" : : "g"(vsidBase + 6));
|
||||
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);
|
||||
}
|
||||
|
||||
// mark the asid not in use
|
||||
// mark the vsid base not in use
|
||||
int baseBit = map->arch_data->vsid_base >> VSID_BASE_SHIFT;
|
||||
atomic_and((vint32 *)&sVSIDBaseBitmap[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->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 *
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
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);
|
||||
|
||||
while (start < end) {
|
||||
entry = lookup_pagetable_entry(map, start);
|
||||
if (entry) {
|
||||
// unmap this page
|
||||
entry->valid = 0;
|
||||
arch_cpu_global_TLB_invalidate();
|
||||
if (remove_page_table_entry(map, start))
|
||||
map->map_count--;
|
||||
}
|
||||
|
||||
start += B_PAGE_SIZE;
|
||||
}
|
||||
@@ -328,7 +342,7 @@ query_tmap(vm_translation_map *map, addr_t va, addr_t *_outPhysical, uint32 *_ou
|
||||
*_outFlags = 0;
|
||||
*_outPhysical = 0;
|
||||
|
||||
entry = lookup_pagetable_entry(map, va);
|
||||
entry = lookup_page_table_entry(map, va);
|
||||
if (entry == NULL)
|
||||
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
|
||||
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)
|
||||
return B_NO_ERROR;
|
||||
|
||||
if (flags & PAGE_MODIFIED)
|
||||
entry->changed = false;
|
||||
if (flags & PAGE_ACCESSED)
|
||||
entry->referenced = false;
|
||||
bool modified = 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;
|
||||
}
|
||||
@@ -458,13 +485,13 @@ arch_vm_translation_map_init_map(vm_translation_map *map, bool kernel)
|
||||
cpu_status state = disable_interrupts();
|
||||
acquire_spinlock(&sVSIDBaseBitmapLock);
|
||||
|
||||
// allocate a ASID base for this one
|
||||
// allocate a VSID base for this one
|
||||
if (kernel) {
|
||||
// The boot loader (respectively the Open Firmware) should has set up
|
||||
// the segment registers for identical mapping. Two VSID bases are
|
||||
// reserved for the kernel: 0 and 8. The latter one for mapping the
|
||||
// kernel address space (0x80000000...), the former one for the lower
|
||||
// addresses required by the Open Firmware services.
|
||||
// The boot loader has set up the segment registers for identical
|
||||
// mapping. Two VSID bases are reserved for the kernel: 0 and 8. The
|
||||
// latter one for mapping the kernel address space (0x80000000...), the
|
||||
// former one for the lower addresses required by the Open Firmware
|
||||
// services.
|
||||
map->arch_data->vsid_base = 0;
|
||||
sVSIDBaseBitmap[0] |= 0x3;
|
||||
} else {
|
||||
@@ -525,8 +552,63 @@ arch_vm_translation_map_init_post_sem(kernel_args *args)
|
||||
status_t
|
||||
arch_vm_translation_map_init_post_area(kernel_args *args)
|
||||
{
|
||||
// create a region to cover the page table
|
||||
sPageTableRegion = create_area("page_table", (void **)&sPageTable, B_EXACT_ADDRESS,
|
||||
// If the page table doesn't lie within the kernel address space, we
|
||||
// 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);
|
||||
|
||||
#if 0
|
||||
|
||||
Reference in New Issue
Block a user