xref: /haiku/src/system/kernel/arch/ppc/paging/classic/PPCPagingMethodClassic.cpp (revision 5c1f231967bbf06af56728b86ad70f266c99f64d)
162caef87SFrançois Revol /*
262caef87SFrançois Revol  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
362caef87SFrançois Revol  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
462caef87SFrançois Revol  * Distributed under the terms of the MIT License.
562caef87SFrançois Revol  *
662caef87SFrançois Revol  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
762caef87SFrançois Revol  * Distributed under the terms of the NewOS License.
862caef87SFrançois Revol  */
962caef87SFrançois Revol 
1062caef87SFrançois Revol 
1162caef87SFrançois Revol #include "paging/classic/PPCPagingMethodClassic.h"
1262caef87SFrançois Revol 
1362caef87SFrançois Revol #include <stdlib.h>
1462caef87SFrançois Revol #include <string.h>
1562caef87SFrançois Revol 
1662caef87SFrançois Revol #include <AutoDeleter.h>
1762caef87SFrançois Revol 
1862caef87SFrançois Revol #include <arch/cpu.h>
1962caef87SFrançois Revol #include <arch_mmu.h>
2062caef87SFrançois Revol #include <arch_system_info.h>
2162caef87SFrançois Revol #include <boot/kernel_args.h>
2262caef87SFrançois Revol #include <int.h>
2362caef87SFrançois Revol #include <thread.h>
2462caef87SFrançois Revol #include <vm/vm.h>
2562caef87SFrançois Revol #include <vm/VMAddressSpace.h>
2662caef87SFrançois Revol 
2762caef87SFrançois Revol #include "paging/classic/PPCPagingStructuresClassic.h"
2862caef87SFrançois Revol #include "paging/classic/PPCVMTranslationMapClassic.h"
2962caef87SFrançois Revol #include "generic_vm_physical_page_mapper.h"
3062caef87SFrançois Revol #include "generic_vm_physical_page_ops.h"
3162caef87SFrançois Revol #include "GenericVMPhysicalPageMapper.h"
3262caef87SFrançois Revol 
3362caef87SFrançois Revol 
3462caef87SFrançois Revol //#define TRACE_PPC_PAGING_METHOD_CLASSIC
3562caef87SFrançois Revol #ifdef TRACE_PPC_PAGING_METHOD_CLASSIC
3662caef87SFrançois Revol #	define TRACE(x...) dprintf(x)
3762caef87SFrançois Revol #else
3862caef87SFrançois Revol #	define TRACE(x...) ;
3962caef87SFrançois Revol #endif
4062caef87SFrançois Revol 
4162caef87SFrançois Revol // 64 MB of iospace
4262caef87SFrançois Revol #define IOSPACE_SIZE (64*1024*1024)
4362caef87SFrançois Revol // We only have small (4 KB) pages. The only reason for choosing greater chunk
4462caef87SFrançois Revol // size is to keep the waste of memory limited, since the generic page mapper
4562caef87SFrançois Revol // allocates structures per physical/virtual chunk.
4662caef87SFrançois Revol // TODO: Implement a page mapper more suitable for small pages!
4762caef87SFrançois Revol #define IOSPACE_CHUNK_SIZE (16 * B_PAGE_SIZE)
4862caef87SFrançois Revol 
4962caef87SFrançois Revol static addr_t sIOSpaceBase;
5062caef87SFrançois Revol 
5162caef87SFrançois Revol 
5262caef87SFrançois Revol static status_t
map_iospace_chunk(addr_t va,phys_addr_t pa,uint32 flags)5362caef87SFrançois Revol map_iospace_chunk(addr_t va, phys_addr_t pa, uint32 flags)
5462caef87SFrançois Revol {
5562caef87SFrançois Revol 	pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
5662caef87SFrançois Revol 	va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
5762caef87SFrançois Revol 	if (va < sIOSpaceBase || va >= (sIOSpaceBase + IOSPACE_SIZE))
5862caef87SFrançois Revol 		panic("map_iospace_chunk: passed invalid va 0x%lx\n", va);
5962caef87SFrançois Revol 
6062caef87SFrançois Revol 	// map the pages
6162caef87SFrançois Revol 	return ppc_map_address_range(va, pa, IOSPACE_CHUNK_SIZE);
6262caef87SFrançois Revol }
6362caef87SFrançois Revol 
6462caef87SFrançois Revol 
6562caef87SFrançois Revol // #pragma mark - PPCPagingMethodClassic
6662caef87SFrançois Revol 
6762caef87SFrançois Revol 
PPCPagingMethodClassic()6862caef87SFrançois Revol PPCPagingMethodClassic::PPCPagingMethodClassic()
6962caef87SFrançois Revol /*
7062caef87SFrançois Revol 	:
7162caef87SFrançois Revol 	fPageHole(NULL),
7262caef87SFrançois Revol 	fPageHolePageDir(NULL),
7362caef87SFrançois Revol 	fKernelPhysicalPageDirectory(0),
7462caef87SFrançois Revol 	fKernelVirtualPageDirectory(NULL),
7562caef87SFrançois Revol 	fPhysicalPageMapper(NULL),
7662caef87SFrançois Revol 	fKernelPhysicalPageMapper(NULL)
7762caef87SFrançois Revol */
7862caef87SFrançois Revol {
7962caef87SFrançois Revol }
8062caef87SFrançois Revol 
8162caef87SFrançois Revol 
~PPCPagingMethodClassic()8262caef87SFrançois Revol PPCPagingMethodClassic::~PPCPagingMethodClassic()
8362caef87SFrançois Revol {
8462caef87SFrançois Revol }
8562caef87SFrançois Revol 
8662caef87SFrançois Revol 
8762caef87SFrançois Revol status_t
Init(kernel_args * args,VMPhysicalPageMapper ** _physicalPageMapper)8862caef87SFrançois Revol PPCPagingMethodClassic::Init(kernel_args* args,
8962caef87SFrançois Revol 	VMPhysicalPageMapper** _physicalPageMapper)
9062caef87SFrançois Revol {
9162caef87SFrançois Revol 	TRACE("PPCPagingMethodClassic::Init(): entry\n");
9262caef87SFrançois Revol 
9362caef87SFrançois Revol 	fPageTable = (page_table_entry_group *)args->arch_args.page_table.start;
9462caef87SFrançois Revol 	fPageTableSize = args->arch_args.page_table.size;
9562caef87SFrançois Revol 	fPageTableHashMask = fPageTableSize / sizeof(page_table_entry_group) - 1;
9662caef87SFrançois Revol 
9762caef87SFrançois Revol 	// init physical page mapper
9862caef87SFrançois Revol 	status_t error = generic_vm_physical_page_mapper_init(args,
9962caef87SFrançois Revol 		map_iospace_chunk, &sIOSpaceBase, IOSPACE_SIZE, IOSPACE_CHUNK_SIZE);
10062caef87SFrançois Revol 	if (error != B_OK)
10162caef87SFrançois Revol 		return error;
10262caef87SFrançois Revol 
10362caef87SFrançois Revol 	new(&fPhysicalPageMapper) GenericVMPhysicalPageMapper;
10462caef87SFrançois Revol 
10562caef87SFrançois Revol 	*_physicalPageMapper = &fPhysicalPageMapper;
10662caef87SFrançois Revol 	return B_OK;
10762caef87SFrançois Revol 
10862caef87SFrançois Revol #if 0//X86
10962caef87SFrançois Revol 	fKernelPhysicalPageDirectory = args->arch_args.phys_pgdir;
11062caef87SFrançois Revol 	fKernelVirtualPageDirectory = (page_directory_entry*)(addr_t)
11162caef87SFrançois Revol 		args->arch_args.vir_pgdir;
11262caef87SFrançois Revol 
11362caef87SFrançois Revol #ifdef TRACE_PPC_PAGING_METHOD_CLASSIC
11462caef87SFrançois Revol 	TRACE("page hole: %p, page dir: %p\n", fPageHole, fPageHolePageDir);
11562caef87SFrançois Revol 	TRACE("page dir: %p (physical: %#" B_PRIx32 ")\n",
11662caef87SFrançois Revol 		fKernelVirtualPageDirectory, fKernelPhysicalPageDirectory);
11762caef87SFrançois Revol #endif
11862caef87SFrançois Revol 
11962caef87SFrançois Revol 	PPCPagingStructuresClassic::StaticInit();
12062caef87SFrançois Revol 
12162caef87SFrançois Revol 	// create the initial pool for the physical page mapper
12262caef87SFrançois Revol 	PhysicalPageSlotPool* pool
12362caef87SFrançois Revol 		= new(&PhysicalPageSlotPool::sInitialPhysicalPagePool)
12462caef87SFrançois Revol 			PhysicalPageSlotPool;
12562caef87SFrançois Revol 	status_t error = pool->InitInitial(args);
12662caef87SFrançois Revol 	if (error != B_OK) {
12762caef87SFrançois Revol 		panic("PPCPagingMethodClassic::Init(): Failed to create initial pool "
12862caef87SFrançois Revol 			"for physical page mapper!");
12962caef87SFrançois Revol 		return error;
13062caef87SFrançois Revol 	}
13162caef87SFrançois Revol 
13262caef87SFrançois Revol 	// create physical page mapper
13362caef87SFrançois Revol 	large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper,
13462caef87SFrançois Revol 		fKernelPhysicalPageMapper);
13562caef87SFrançois Revol 		// TODO: Select the best page mapper!
13662caef87SFrançois Revol 
13762caef87SFrançois Revol 	// enable global page feature if available
13862caef87SFrançois Revol 	if (x86_check_feature(IA32_FEATURE_PGE, FEATURE_COMMON)) {
13962caef87SFrançois Revol 		// this prevents kernel pages from being flushed from TLB on
14062caef87SFrançois Revol 		// context-switch
14162caef87SFrançois Revol 		x86_write_cr4(x86_read_cr4() | IA32_CR4_GLOBAL_PAGES);
14262caef87SFrançois Revol 	}
14362caef87SFrançois Revol 
14462caef87SFrançois Revol 	TRACE("PPCPagingMethodClassic::Init(): done\n");
14562caef87SFrançois Revol 
14662caef87SFrançois Revol 	*_physicalPageMapper = fPhysicalPageMapper;
14762caef87SFrançois Revol 	return B_OK;
14862caef87SFrançois Revol #endif
14962caef87SFrançois Revol }
15062caef87SFrançois Revol 
15162caef87SFrançois Revol 
15262caef87SFrançois Revol status_t
InitPostArea(kernel_args * args)15362caef87SFrançois Revol PPCPagingMethodClassic::InitPostArea(kernel_args* args)
15462caef87SFrançois Revol {
15562caef87SFrançois Revol 
15662caef87SFrançois Revol 	// If the page table doesn't lie within the kernel address space, we
15762caef87SFrançois Revol 	// remap it.
15862caef87SFrançois Revol 	if (!IS_KERNEL_ADDRESS(fPageTable)) {
15962caef87SFrançois Revol 		addr_t newAddress = (addr_t)fPageTable;
16062caef87SFrançois Revol 		status_t error = ppc_remap_address_range(&newAddress, fPageTableSize,
16162caef87SFrançois Revol 			false);
16262caef87SFrançois Revol 		if (error != B_OK) {
16362caef87SFrançois Revol 			panic("arch_vm_translation_map_init_post_area(): Failed to remap "
16462caef87SFrançois Revol 				"the page table!");
16562caef87SFrançois Revol 			return error;
16662caef87SFrançois Revol 		}
16762caef87SFrançois Revol 
16862caef87SFrançois Revol 		// set the new page table address
16962caef87SFrançois Revol 		addr_t oldVirtualBase = (addr_t)(fPageTable);
17062caef87SFrançois Revol 		fPageTable = (page_table_entry_group*)newAddress;
17162caef87SFrançois Revol 
17262caef87SFrançois Revol 		// unmap the old pages
17362caef87SFrançois Revol 		ppc_unmap_address_range(oldVirtualBase, fPageTableSize);
17462caef87SFrançois Revol 
17562caef87SFrançois Revol // TODO: We should probably map the page table via BAT. It is relatively large,
17662caef87SFrançois Revol // and due to being a hash table the access patterns might look sporadic, which
17762caef87SFrançois Revol // certainly isn't to the liking of the TLB.
17862caef87SFrançois Revol 	}
17962caef87SFrançois Revol 
18062caef87SFrançois Revol 	// create an area to cover the page table
18162caef87SFrançois Revol 	fPageTableArea = create_area("page_table", (void **)&fPageTable, B_EXACT_ADDRESS,
18262caef87SFrançois Revol 		fPageTableSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
18362caef87SFrançois Revol 
18462caef87SFrançois Revol 	// init physical page mapper
18562caef87SFrançois Revol 	status_t error = generic_vm_physical_page_mapper_init_post_area(args);
18662caef87SFrançois Revol 	if (error != B_OK)
18762caef87SFrançois Revol 		return error;
18862caef87SFrançois Revol 
18962caef87SFrançois Revol 	return B_OK;
19062caef87SFrançois Revol 
19162caef87SFrançois Revol #if 0//X86
19262caef87SFrançois Revol 	// now that the vm is initialized, create an area that represents
19362caef87SFrançois Revol 	// the page hole
19462caef87SFrançois Revol 	void *temp;
19562caef87SFrançois Revol 	status_t error;
19662caef87SFrançois Revol 	area_id area;
19762caef87SFrançois Revol 
19862caef87SFrançois Revol 	// unmap the page hole hack we were using before
19962caef87SFrançois Revol 	fKernelVirtualPageDirectory[1023] = 0;
20062caef87SFrançois Revol 	fPageHolePageDir = NULL;
20162caef87SFrançois Revol 	fPageHole = NULL;
20262caef87SFrançois Revol 
20362caef87SFrançois Revol 	temp = (void*)fKernelVirtualPageDirectory;
20462caef87SFrançois Revol 	area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE,
20562caef87SFrançois Revol 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
20662caef87SFrançois Revol 	if (area < B_OK)
20762caef87SFrançois Revol 		return area;
20862caef87SFrançois Revol 
20962caef87SFrançois Revol 	error = PhysicalPageSlotPool::sInitialPhysicalPagePool
21062caef87SFrançois Revol 		.InitInitialPostArea(args);
21162caef87SFrançois Revol 	if (error != B_OK)
21262caef87SFrançois Revol 		return error;
21362caef87SFrançois Revol 
21462caef87SFrançois Revol 	return B_OK;
21562caef87SFrançois Revol #endif//X86
21662caef87SFrançois Revol }
21762caef87SFrançois Revol 
21862caef87SFrançois Revol 
21962caef87SFrançois Revol status_t
CreateTranslationMap(bool kernel,VMTranslationMap ** _map)22062caef87SFrançois Revol PPCPagingMethodClassic::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
22162caef87SFrançois Revol {
22262caef87SFrançois Revol 	PPCVMTranslationMapClassic* map = new(std::nothrow) PPCVMTranslationMapClassic;
22362caef87SFrançois Revol 	if (map == NULL)
22462caef87SFrançois Revol 		return B_NO_MEMORY;
22562caef87SFrançois Revol 
22662caef87SFrançois Revol 	status_t error = map->Init(kernel);
22762caef87SFrançois Revol 	if (error != B_OK) {
22862caef87SFrançois Revol 		delete map;
22962caef87SFrançois Revol 		return error;
23062caef87SFrançois Revol 	}
23162caef87SFrançois Revol 
23262caef87SFrançois Revol 	*_map = map;
23362caef87SFrançois Revol 	return B_OK;
23462caef87SFrançois Revol }
23562caef87SFrançois Revol 
23662caef87SFrançois Revol 
23762caef87SFrançois Revol status_t
MapEarly(kernel_args * args,addr_t virtualAddress,phys_addr_t physicalAddress,uint8 attributes,page_num_t (* get_free_page)(kernel_args *))23862caef87SFrançois Revol PPCPagingMethodClassic::MapEarly(kernel_args* args, addr_t virtualAddress,
23962caef87SFrançois Revol 	phys_addr_t physicalAddress, uint8 attributes,
24062caef87SFrançois Revol 	page_num_t (*get_free_page)(kernel_args*))
24162caef87SFrançois Revol {
24262caef87SFrançois Revol 	uint32 virtualSegmentID = get_sr((void *)virtualAddress) & 0xffffff;
24362caef87SFrançois Revol 
24462caef87SFrançois Revol 	uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, (uint32)virtualAddress);
24562caef87SFrançois Revol 	page_table_entry_group *group = &fPageTable[hash & fPageTableHashMask];
24662caef87SFrançois Revol 
24762caef87SFrançois Revol 	for (int32 i = 0; i < 8; i++) {
24862caef87SFrançois Revol 		// 8 entries in a group
24962caef87SFrançois Revol 		if (group->entry[i].valid)
25062caef87SFrançois Revol 			continue;
25162caef87SFrançois Revol 
25262caef87SFrançois Revol 		FillPageTableEntry(&group->entry[i], virtualSegmentID,
25362caef87SFrançois Revol 			virtualAddress, physicalAddress, PTE_READ_WRITE, 0, false);
25462caef87SFrançois Revol 		return B_OK;
25562caef87SFrançois Revol 	}
25662caef87SFrançois Revol 
25762caef87SFrançois Revol 	hash = page_table_entry::SecondaryHash(hash);
25862caef87SFrançois Revol 	group = &fPageTable[hash & fPageTableHashMask];
25962caef87SFrançois Revol 
26062caef87SFrançois Revol 	for (int32 i = 0; i < 8; i++) {
26162caef87SFrançois Revol 		if (group->entry[i].valid)
26262caef87SFrançois Revol 			continue;
26362caef87SFrançois Revol 
26462caef87SFrançois Revol 		FillPageTableEntry(&group->entry[i], virtualSegmentID,
26562caef87SFrançois Revol 			virtualAddress, physicalAddress, PTE_READ_WRITE, 0, true);
26662caef87SFrançois Revol 		return B_OK;
26762caef87SFrançois Revol 	}
26862caef87SFrançois Revol 
26962caef87SFrançois Revol 	return B_ERROR;
27062caef87SFrançois Revol }
27162caef87SFrançois Revol 
27262caef87SFrançois Revol 
27362caef87SFrançois Revol bool
IsKernelPageAccessible(addr_t virtualAddress,uint32 protection)27462caef87SFrançois Revol PPCPagingMethodClassic::IsKernelPageAccessible(addr_t virtualAddress,
27562caef87SFrançois Revol 	uint32 protection)
27662caef87SFrançois Revol {
27762caef87SFrançois Revol 	// TODO:factor out to baseclass
27862caef87SFrançois Revol 	VMAddressSpace *addressSpace = VMAddressSpace::Kernel();
27962caef87SFrançois Revol 
28062caef87SFrançois Revol //XXX:
28162caef87SFrançois Revol //	PPCVMTranslationMap* map = static_cast<PPCVMTranslationMap*>(
28262caef87SFrançois Revol //		addressSpace->TranslationMap());
28362caef87SFrançois Revol //	VMTranslationMap* map = addressSpace->TranslationMap();
28462caef87SFrançois Revol 	PPCVMTranslationMapClassic* map = static_cast<PPCVMTranslationMapClassic*>(
28562caef87SFrançois Revol 		addressSpace->TranslationMap());
28662caef87SFrançois Revol 
28762caef87SFrançois Revol 	phys_addr_t physicalAddress;
28862caef87SFrançois Revol 	uint32 flags;
28962caef87SFrançois Revol 	if (map->Query(virtualAddress, &physicalAddress, &flags) != B_OK)
29062caef87SFrançois Revol 		return false;
29162caef87SFrançois Revol 
29262caef87SFrançois Revol 	if ((flags & PAGE_PRESENT) == 0)
29362caef87SFrançois Revol 		return false;
29462caef87SFrançois Revol 
29562caef87SFrançois Revol 	// present means kernel-readable, so check for writable
29662caef87SFrançois Revol 	return (protection & B_KERNEL_WRITE_AREA) == 0
29762caef87SFrançois Revol 		|| (flags & B_KERNEL_WRITE_AREA) != 0;
29862caef87SFrançois Revol }
29962caef87SFrançois Revol 
30062caef87SFrançois Revol 
30162caef87SFrançois Revol void
FillPageTableEntry(page_table_entry * entry,uint32 virtualSegmentID,addr_t virtualAddress,phys_addr_t physicalAddress,uint8 protection,uint32 memoryType,bool secondaryHash)30262caef87SFrançois Revol PPCPagingMethodClassic::FillPageTableEntry(page_table_entry *entry,
30362caef87SFrançois Revol 	uint32 virtualSegmentID, addr_t virtualAddress, phys_addr_t physicalAddress,
30462caef87SFrançois Revol 	uint8 protection, uint32 memoryType, bool secondaryHash)
30562caef87SFrançois Revol {
30662caef87SFrançois Revol 	// lower 32 bit - set at once
30762caef87SFrançois Revol 	entry->physical_page_number = physicalAddress / B_PAGE_SIZE;
30862caef87SFrançois Revol 	entry->_reserved0 = 0;
30962caef87SFrançois Revol 	entry->referenced = false;
31062caef87SFrançois Revol 	entry->changed = false;
311*5c1f2319SAugustin Cavalier 	entry->write_through = (memoryType == B_UNCACHED_MEMORY) || (memoryType == B_WRITE_THROUGH_MEMORY);
312*5c1f2319SAugustin Cavalier 	entry->caching_inhibited = (memoryType == B_UNCACHED_MEMORY);
31362caef87SFrançois Revol 	entry->memory_coherent = false;
31462caef87SFrançois Revol 	entry->guarded = false;
31562caef87SFrançois Revol 	entry->_reserved1 = 0;
31662caef87SFrançois Revol 	entry->page_protection = protection & 0x3;
31762caef87SFrançois Revol 	eieio();
31862caef87SFrançois Revol 		// we need to make sure that the lower 32 bit were
31962caef87SFrançois Revol 		// already written when the entry becomes valid
32062caef87SFrançois Revol 
32162caef87SFrançois Revol 	// upper 32 bit
32262caef87SFrançois Revol 	entry->virtual_segment_id = virtualSegmentID;
32362caef87SFrançois Revol 	entry->secondary_hash = secondaryHash;
32462caef87SFrançois Revol 	entry->abbr_page_index = (virtualAddress >> 22) & 0x3f;
32562caef87SFrançois Revol 	entry->valid = true;
32662caef87SFrançois Revol 
32762caef87SFrançois Revol 	ppc_sync();
32862caef87SFrançois Revol }
32962caef87SFrançois Revol 
33062caef87SFrançois Revol 
33162caef87SFrançois Revol #if 0//X86
33262caef87SFrançois Revol /*static*/ void
33362caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableInPageDir(page_directory_entry* entry,
33462caef87SFrançois Revol 	phys_addr_t pgtablePhysical, uint32 attributes)
33562caef87SFrançois Revol {
33662caef87SFrançois Revol 	*entry = (pgtablePhysical & PPC_PDE_ADDRESS_MASK)
33762caef87SFrançois Revol 		| PPC_PDE_PRESENT
33862caef87SFrançois Revol 		| PPC_PDE_WRITABLE
33962caef87SFrançois Revol 		| PPC_PDE_USER;
34062caef87SFrançois Revol 		// TODO: we ignore the attributes of the page table - for compatibility
34162caef87SFrançois Revol 		// with BeOS we allow having user accessible areas in the kernel address
34262caef87SFrançois Revol 		// space. This is currently being used by some drivers, mainly for the
34362caef87SFrançois Revol 		// frame buffer. Our current real time data implementation makes use of
34462caef87SFrançois Revol 		// this fact, too.
34562caef87SFrançois Revol 		// We might want to get rid of this possibility one day, especially if
34662caef87SFrançois Revol 		// we intend to port it to a platform that does not support this.
34762caef87SFrançois Revol }
34862caef87SFrançois Revol 
34962caef87SFrançois Revol 
35062caef87SFrançois Revol /*static*/ void
35162caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableEntryInTable(page_table_entry* entry,
35262caef87SFrançois Revol 	phys_addr_t physicalAddress, uint32 attributes, uint32 memoryType,
35362caef87SFrançois Revol 	bool globalPage)
35462caef87SFrançois Revol {
35562caef87SFrançois Revol 	page_table_entry page = (physicalAddress & PPC_PTE_ADDRESS_MASK)
35662caef87SFrançois Revol 		| PPC_PTE_PRESENT | (globalPage ? PPC_PTE_GLOBAL : 0)
35762caef87SFrançois Revol 		| MemoryTypeToPageTableEntryFlags(memoryType);
35862caef87SFrançois Revol 
35962caef87SFrançois Revol 	// if the page is user accessible, it's automatically
36062caef87SFrançois Revol 	// accessible in kernel space, too (but with the same
36162caef87SFrançois Revol 	// protection)
36262caef87SFrançois Revol 	if ((attributes & B_USER_PROTECTION) != 0) {
36362caef87SFrançois Revol 		page |= PPC_PTE_USER;
36462caef87SFrançois Revol 		if ((attributes & B_WRITE_AREA) != 0)
36562caef87SFrançois Revol 			page |= PPC_PTE_WRITABLE;
36662caef87SFrançois Revol 	} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
36762caef87SFrançois Revol 		page |= PPC_PTE_WRITABLE;
36862caef87SFrançois Revol 
36962caef87SFrançois Revol 	// put it in the page table
37062caef87SFrançois Revol 	*(volatile page_table_entry*)entry = page;
37162caef87SFrançois Revol }
37262caef87SFrançois Revol 
37362caef87SFrançois Revol 
37462caef87SFrançois Revol /*static*/ void
37562caef87SFrançois Revol PPCPagingMethodClassic::_EarlyPreparePageTables(page_table_entry* pageTables,
37662caef87SFrançois Revol 	addr_t address, size_t size)
37762caef87SFrançois Revol {
37862caef87SFrançois Revol 	memset(pageTables, 0, B_PAGE_SIZE * (size / (B_PAGE_SIZE * 1024)));
37962caef87SFrançois Revol 
38062caef87SFrançois Revol 	// put the array of pgtables directly into the kernel pagedir
38162caef87SFrançois Revol 	// these will be wired and kept mapped into virtual space to be easy to get
38262caef87SFrançois Revol 	// to
38362caef87SFrançois Revol 	{
38462caef87SFrançois Revol 		addr_t virtualTable = (addr_t)pageTables;
38562caef87SFrançois Revol 
38662caef87SFrançois Revol 		page_directory_entry* pageHolePageDir
38762caef87SFrançois Revol 			= PPCPagingMethodClassic::Method()->PageHolePageDir();
38862caef87SFrançois Revol 
38962caef87SFrançois Revol 		for (size_t i = 0; i < (size / (B_PAGE_SIZE * 1024));
39062caef87SFrançois Revol 				i++, virtualTable += B_PAGE_SIZE) {
39162caef87SFrançois Revol 			phys_addr_t physicalTable = 0;
39262caef87SFrançois Revol 			_EarlyQuery(virtualTable, &physicalTable);
39362caef87SFrançois Revol 			page_directory_entry* entry = &pageHolePageDir[
39462caef87SFrançois Revol 				(address / (B_PAGE_SIZE * 1024)) + i];
39562caef87SFrançois Revol 			PutPageTableInPageDir(entry, physicalTable,
39662caef87SFrançois Revol 				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
39762caef87SFrançois Revol 		}
39862caef87SFrançois Revol 	}
39962caef87SFrançois Revol }
40062caef87SFrançois Revol 
40162caef87SFrançois Revol 
40262caef87SFrançois Revol //! TODO: currently assumes this translation map is active
40362caef87SFrançois Revol /*static*/ status_t
40462caef87SFrançois Revol PPCPagingMethodClassic::_EarlyQuery(addr_t virtualAddress,
40562caef87SFrançois Revol 	phys_addr_t *_physicalAddress)
40662caef87SFrançois Revol {
40762caef87SFrançois Revol 	PPCPagingMethodClassic* method = PPCPagingMethodClassic::Method();
40862caef87SFrançois Revol 	int index = VADDR_TO_PDENT(virtualAddress);
40962caef87SFrançois Revol 	if ((method->PageHolePageDir()[index] & PPC_PDE_PRESENT) == 0) {
41062caef87SFrançois Revol 		// no pagetable here
41162caef87SFrançois Revol 		return B_ERROR;
41262caef87SFrançois Revol 	}
41362caef87SFrançois Revol 
41462caef87SFrançois Revol 	page_table_entry* entry = method->PageHole() + virtualAddress / B_PAGE_SIZE;
41562caef87SFrançois Revol 	if ((*entry & PPC_PTE_PRESENT) == 0) {
41662caef87SFrançois Revol 		// page mapping not valid
41762caef87SFrançois Revol 		return B_ERROR;
41862caef87SFrançois Revol 	}
41962caef87SFrançois Revol 
42062caef87SFrançois Revol 	*_physicalAddress = *entry & PPC_PTE_ADDRESS_MASK;
42162caef87SFrançois Revol 	return B_OK;
42262caef87SFrançois Revol }
42362caef87SFrançois Revol #endif
424