xref: /haiku/src/system/boot/platform/openfirmware/arch/ppc/mmu.cpp (revision 56f9c76088b8146faec4a37a3d77e5cd3047d202)
15af32e75SAxel Dörfler /*
2bdee97bcSAxel Dörfler  * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3bf0e980dSAlexander von Gluck IV  * Copyright 2010-2011, Haiku, Inc. All Rights Reserved.
4bf0e980dSAlexander von Gluck IV  * All rights reserved. Distributed under the terms of the MIT License.
5bf0e980dSAlexander von Gluck IV  *
6bf0e980dSAlexander von Gluck IV  * Authors:
7bf0e980dSAlexander von Gluck IV  *		Axel Dörfler, axeld@pinc-software.de.
8bf0e980dSAlexander von Gluck IV  *		Alexander von Gluck, kallisti5@unixzen.com
95af32e75SAxel Dörfler  */
105af32e75SAxel Dörfler 
115af32e75SAxel Dörfler 
12884432c2SAndreas Färber #include <OS.h>
13884432c2SAndreas Färber 
145af32e75SAxel Dörfler #include <platform_arch.h>
15d73ddac5SIngo Weinhold #include <boot/addr_range.h>
16d73ddac5SIngo Weinhold #include <boot/kernel_args.h>
175af32e75SAxel Dörfler #include <boot/platform.h>
185af32e75SAxel Dörfler #include <boot/stage2.h>
195af32e75SAxel Dörfler #include <boot/stdio.h>
20957a1b17SIngo Weinhold #include <platform/openfirmware/openfirmware.h>
215af32e75SAxel Dörfler #include <arch_cpu.h>
225af32e75SAxel Dörfler #include <arch_mmu.h>
235af32e75SAxel Dörfler #include <kernel.h>
245af32e75SAxel Dörfler 
2540a5a5a0SAlexander von Gluck IV #include "support.h"
265af32e75SAxel Dörfler 
27bf0e980dSAlexander von Gluck IV 
28a268fbfeSAxel Dörfler // set protection to WIMGNPP: -----PP
29a268fbfeSAxel Dörfler // PP:	00 - no access
30a268fbfeSAxel Dörfler //		01 - read only
31a268fbfeSAxel Dörfler //		10 - read/write
32a268fbfeSAxel Dörfler //		11 - read only
33a268fbfeSAxel Dörfler #define PAGE_READ_ONLY	0x01
34a268fbfeSAxel Dörfler #define PAGE_READ_WRITE	0x02
35a268fbfeSAxel Dörfler 
363b148e53SFrançois Revol // NULL is actually a possible physical address...
373b148e53SFrançois Revol //#define PHYSINVAL ((void *)-1)
383b148e53SFrançois Revol #define PHYSINVAL NULL
39a268fbfeSAxel Dörfler 
402e3b6c53SAlexander von Gluck IV //#define TRACE_MMU
412e3b6c53SAlexander von Gluck IV #ifdef TRACE_MMU
422e3b6c53SAlexander von Gluck IV #   define TRACE(x...) dprintf(x)
432e3b6c53SAlexander von Gluck IV #else
442e3b6c53SAlexander von Gluck IV #   define TRACE(x...) ;
452e3b6c53SAlexander von Gluck IV #endif
462e3b6c53SAlexander von Gluck IV 
472e3b6c53SAlexander von Gluck IV 
485af32e75SAxel Dörfler segment_descriptor sSegments[16];
495af32e75SAxel Dörfler page_table_entry_group *sPageTable;
505af32e75SAxel Dörfler uint32 sPageTableHashMask;
515af32e75SAxel Dörfler 
525af32e75SAxel Dörfler 
53a1bcf2c8SIngo Weinhold // begin and end of the boot loader
54a1bcf2c8SIngo Weinhold extern "C" uint8 __text_begin;
55a1bcf2c8SIngo Weinhold extern "C" uint8 _end;
56a1bcf2c8SIngo Weinhold 
57a1bcf2c8SIngo Weinhold 
585af32e75SAxel Dörfler static status_t
insert_virtual_range_to_keep(void * start,uint32 size)59a1bcf2c8SIngo Weinhold insert_virtual_range_to_keep(void *start, uint32 size)
60a1bcf2c8SIngo Weinhold {
6131bce167SAndreas Färber 	return insert_address_range(gKernelArgs.arch_args.virtual_ranges_to_keep,
6231bce167SAndreas Färber 		&gKernelArgs.arch_args.num_virtual_ranges_to_keep,
6331bce167SAndreas Färber 		MAX_VIRTUAL_RANGES_TO_KEEP, (addr_t)start, size);
64a1bcf2c8SIngo Weinhold }
65a1bcf2c8SIngo Weinhold 
66a1bcf2c8SIngo Weinhold 
67a1bcf2c8SIngo Weinhold static status_t
remove_virtual_range_to_keep(void * start,uint32 size)68a1bcf2c8SIngo Weinhold remove_virtual_range_to_keep(void *start, uint32 size)
69a1bcf2c8SIngo Weinhold {
70d73ddac5SIngo Weinhold 	return remove_address_range(gKernelArgs.arch_args.virtual_ranges_to_keep,
71d73ddac5SIngo Weinhold 		&gKernelArgs.arch_args.num_virtual_ranges_to_keep,
72d73ddac5SIngo Weinhold 		MAX_VIRTUAL_RANGES_TO_KEEP, (addr_t)start, size);
73a1bcf2c8SIngo Weinhold }
74a1bcf2c8SIngo Weinhold 
75a1bcf2c8SIngo Weinhold 
76a1bcf2c8SIngo Weinhold static status_t
find_physical_memory_ranges(size_t & total)775af32e75SAxel Dörfler find_physical_memory_ranges(size_t &total)
785af32e75SAxel Dörfler {
79d24ddec4SAlexander von Gluck IV 	int memory;
802e3b6c53SAlexander von Gluck IV 	dprintf("checking for memory...\n");
815af32e75SAxel Dörfler 	if (of_getprop(gChosen, "memory", &memory, sizeof(int)) == OF_FAILED)
825af32e75SAxel Dörfler 		return B_ERROR;
83d24ddec4SAlexander von Gluck IV 	int package = of_instance_to_package(memory);
845af32e75SAxel Dörfler 
855af32e75SAxel Dörfler 	total = 0;
865af32e75SAxel Dörfler 
87bf0e980dSAlexander von Gluck IV 	// Memory base addresses are provided in 32 or 64 bit flavors
88bf0e980dSAlexander von Gluck IV 	// #address-cells and #size-cells matches the number of 32-bit 'cells'
89bf0e980dSAlexander von Gluck IV 	// representing the length of the base address and size fields
90d24ddec4SAlexander von Gluck IV 	int root = of_finddevice("/");
91bf0e980dSAlexander von Gluck IV 	int32 regAddressCells = of_address_cells(root);
92bf0e980dSAlexander von Gluck IV 	int32 regSizeCells = of_size_cells(root);
93bf0e980dSAlexander von Gluck IV 	if (regAddressCells == OF_FAILED || regSizeCells == OF_FAILED) {
94d24ddec4SAlexander von Gluck IV 		dprintf("finding base/size length counts failed, assume 32-bit.\n");
95bf0e980dSAlexander von Gluck IV 		regAddressCells = 1;
96bf0e980dSAlexander von Gluck IV 		regSizeCells = 1;
97d24ddec4SAlexander von Gluck IV 	}
98d24ddec4SAlexander von Gluck IV 
99bf0e980dSAlexander von Gluck IV 	// NOTE : Size Cells of 2 is possible in theory... but I haven't seen it yet.
100bf0e980dSAlexander von Gluck IV 	if (regAddressCells > 2 || regSizeCells > 1) {
101bf0e980dSAlexander von Gluck IV 		panic("%s: Unsupported OpenFirmware cell count detected.\n"
102bf0e980dSAlexander von Gluck IV 		"Address Cells: %" B_PRId32 "; Size Cells: %" B_PRId32
103bf0e980dSAlexander von Gluck IV 		" (CPU > 64bit?).\n", __func__, regAddressCells, regSizeCells);
104d24ddec4SAlexander von Gluck IV 		return B_ERROR;
105d24ddec4SAlexander von Gluck IV 	}
106d24ddec4SAlexander von Gluck IV 
107d24ddec4SAlexander von Gluck IV 	// On 64-bit PowerPC systems (G5), our mem base range address is larger
108bf0e980dSAlexander von Gluck IV 	if (regAddressCells == 2) {
109*56f9c760SPulkoMandy 		struct of_region<uint64, uint32> regions[64];
110d24ddec4SAlexander von Gluck IV 		int count = of_getprop(package, "reg", regions, sizeof(regions));
1113b148e53SFrançois Revol 		if (count == OF_FAILED)
1123b148e53SFrançois Revol 			count = of_getprop(memory, "reg", regions, sizeof(regions));
1135af32e75SAxel Dörfler 		if (count == OF_FAILED)
1145af32e75SAxel Dörfler 			return B_ERROR;
115d24ddec4SAlexander von Gluck IV 		count /= sizeof(regions[0]);
1165af32e75SAxel Dörfler 
1175af32e75SAxel Dörfler 		for (int32 i = 0; i < count; i++) {
1185af32e75SAxel Dörfler 			if (regions[i].size <= 0) {
1192e3b6c53SAlexander von Gluck IV 				dprintf("%ld: empty region\n", i);
1205af32e75SAxel Dörfler 				continue;
1215af32e75SAxel Dörfler 			}
122d24ddec4SAlexander von Gluck IV 			dprintf("%" B_PRIu32 ": base = %" B_PRIu64 ","
123d24ddec4SAlexander von Gluck IV 				"size = %" B_PRIu32 "\n", i, regions[i].base, regions[i].size);
124d24ddec4SAlexander von Gluck IV 
125d24ddec4SAlexander von Gluck IV 			total += regions[i].size;
126d24ddec4SAlexander von Gluck IV 
127d24ddec4SAlexander von Gluck IV 			if (insert_physical_memory_range((addr_t)regions[i].base,
128d24ddec4SAlexander von Gluck IV 					regions[i].size) != B_OK) {
129d24ddec4SAlexander von Gluck IV 				dprintf("cannot map physical memory range "
130d24ddec4SAlexander von Gluck IV 					"(num ranges = %" B_PRIu32 ")!\n",
131d24ddec4SAlexander von Gluck IV 					gKernelArgs.num_physical_memory_ranges);
132d24ddec4SAlexander von Gluck IV 				return B_ERROR;
133d24ddec4SAlexander von Gluck IV 			}
134d24ddec4SAlexander von Gluck IV 		}
135d24ddec4SAlexander von Gluck IV 		return B_OK;
136d24ddec4SAlexander von Gluck IV 	}
137d24ddec4SAlexander von Gluck IV 
138d24ddec4SAlexander von Gluck IV 	// Otherwise, normal 32-bit PowerPC G3 or G4 have a smaller 32-bit one
139*56f9c760SPulkoMandy 	struct of_region<uint32, uint32> regions[64];
140d24ddec4SAlexander von Gluck IV 	int count = of_getprop(package, "reg", regions, sizeof(regions));
141d24ddec4SAlexander von Gluck IV 	if (count == OF_FAILED)
142d24ddec4SAlexander von Gluck IV 		count = of_getprop(memory, "reg", regions, sizeof(regions));
143d24ddec4SAlexander von Gluck IV 	if (count == OF_FAILED)
144d24ddec4SAlexander von Gluck IV 		return B_ERROR;
145d24ddec4SAlexander von Gluck IV 	count /= sizeof(regions[0]);
146d24ddec4SAlexander von Gluck IV 
147d24ddec4SAlexander von Gluck IV 	for (int32 i = 0; i < count; i++) {
148d24ddec4SAlexander von Gluck IV 		if (regions[i].size <= 0) {
149d24ddec4SAlexander von Gluck IV 			dprintf("%ld: empty region\n", i);
150d24ddec4SAlexander von Gluck IV 			continue;
151d24ddec4SAlexander von Gluck IV 		}
152d24ddec4SAlexander von Gluck IV 		dprintf("%" B_PRIu32 ": base = %" B_PRIu32 ","
153d24ddec4SAlexander von Gluck IV 			"size = %" B_PRIu32 "\n", i, regions[i].base, regions[i].size);
1545af32e75SAxel Dörfler 
1555af32e75SAxel Dörfler 		total += regions[i].size;
1565af32e75SAxel Dörfler 
157d73ddac5SIngo Weinhold 		if (insert_physical_memory_range((addr_t)regions[i].base,
158d73ddac5SIngo Weinhold 				regions[i].size) != B_OK) {
1592e3b6c53SAlexander von Gluck IV 			dprintf("cannot map physical memory range "
1602e3b6c53SAlexander von Gluck IV 				"(num ranges = %" B_PRIu32 ")!\n",
161bdee97bcSAxel Dörfler 				gKernelArgs.num_physical_memory_ranges);
1625af32e75SAxel Dörfler 			return B_ERROR;
1635af32e75SAxel Dörfler 		}
1645af32e75SAxel Dörfler 	}
1655af32e75SAxel Dörfler 
1665af32e75SAxel Dörfler 	return B_OK;
1675af32e75SAxel Dörfler }
1685af32e75SAxel Dörfler 
1695af32e75SAxel Dörfler 
1705af32e75SAxel Dörfler static bool
is_virtual_allocated(void * address,size_t size)1715af32e75SAxel Dörfler is_virtual_allocated(void *address, size_t size)
1725af32e75SAxel Dörfler {
173192af9e0SAlex Smith 	uint64 foundBase;
174d73ddac5SIngo Weinhold 	return !get_free_address_range(gKernelArgs.virtual_allocated_range,
175d73ddac5SIngo Weinhold 		gKernelArgs.num_virtual_allocated_ranges, (addr_t)address, size,
176a1a978ffSAlexander von Gluck IV 		&foundBase) || foundBase != (addr_t)address;
1775af32e75SAxel Dörfler }
1785af32e75SAxel Dörfler 
1795af32e75SAxel Dörfler 
1805af32e75SAxel Dörfler static bool
is_physical_allocated(void * address,size_t size)1815af32e75SAxel Dörfler is_physical_allocated(void *address, size_t size)
1825af32e75SAxel Dörfler {
18317a33898SAlex Smith 	uint64 foundBase;
18417a33898SAlex Smith 	return !get_free_address_range(gKernelArgs.physical_allocated_range,
185d73ddac5SIngo Weinhold 		gKernelArgs.num_physical_allocated_ranges, (addr_t)address, size,
186a1a978ffSAlexander von Gluck IV 		&foundBase) || foundBase != (addr_t)address;
1875af32e75SAxel Dörfler }
1885af32e75SAxel Dörfler 
1895af32e75SAxel Dörfler 
1905af32e75SAxel Dörfler static bool
is_physical_memory(void * address,size_t size)1915af32e75SAxel Dörfler is_physical_memory(void *address, size_t size)
1925af32e75SAxel Dörfler {
19317a33898SAlex Smith 	return is_address_range_covered(gKernelArgs.physical_memory_range,
194d73ddac5SIngo Weinhold 		gKernelArgs.num_physical_memory_ranges, (addr_t)address, size);
1955af32e75SAxel Dörfler }
1965af32e75SAxel Dörfler 
1975af32e75SAxel Dörfler 
1985af32e75SAxel Dörfler static bool
is_physical_memory(void * address)1995af32e75SAxel Dörfler is_physical_memory(void *address)
2005af32e75SAxel Dörfler {
201d73ddac5SIngo Weinhold 	return is_physical_memory(address, 1);
2025af32e75SAxel Dörfler }
2035af32e75SAxel Dörfler 
2045af32e75SAxel Dörfler 
2055af32e75SAxel Dörfler static void
fill_page_table_entry(page_table_entry * entry,uint32 virtualSegmentID,void * virtualAddress,void * physicalAddress,uint8 mode,bool secondaryHash)206bdee97bcSAxel Dörfler fill_page_table_entry(page_table_entry *entry, uint32 virtualSegmentID,
207bdee97bcSAxel Dörfler 	void *virtualAddress, void *physicalAddress, uint8 mode, bool secondaryHash)
2085af32e75SAxel Dörfler {
2095af32e75SAxel Dörfler 	// lower 32 bit - set at once
210bdee97bcSAxel Dörfler 	((uint32 *)entry)[1]
211bdee97bcSAxel Dörfler 		= (((uint32)physicalAddress / B_PAGE_SIZE) << 12) | mode;
2125af32e75SAxel Dörfler 	/*entry->physical_page_number = (uint32)physicalAddress / B_PAGE_SIZE;
2135af32e75SAxel Dörfler 	entry->_reserved0 = 0;
2145af32e75SAxel Dörfler 	entry->referenced = false;
2155af32e75SAxel Dörfler 	entry->changed = false;
2165af32e75SAxel Dörfler 	entry->write_through = (mode >> 6) & 1;
2175af32e75SAxel Dörfler 	entry->caching_inhibited = (mode >> 5) & 1;
2185af32e75SAxel Dörfler 	entry->memory_coherent = (mode >> 4) & 1;
2195af32e75SAxel Dörfler 	entry->guarded = (mode >> 3) & 1;
2205af32e75SAxel Dörfler 	entry->_reserved1 = 0;
2215af32e75SAxel Dörfler 	entry->page_protection = mode & 0x3;*/
2225af32e75SAxel Dörfler 	eieio();
2235af32e75SAxel Dörfler 		// we need to make sure that the lower 32 bit were
2245af32e75SAxel Dörfler 		// already written when the entry becomes valid
2255af32e75SAxel Dörfler 
2265af32e75SAxel Dörfler 	// upper 32 bit
2275af32e75SAxel Dörfler 	entry->virtual_segment_id = virtualSegmentID;
2285af32e75SAxel Dörfler 	entry->secondary_hash = secondaryHash;
2295af32e75SAxel Dörfler 	entry->abbr_page_index = ((uint32)virtualAddress >> 22) & 0x3f;
2305af32e75SAxel Dörfler 	entry->valid = true;
2315af32e75SAxel Dörfler }
2325af32e75SAxel Dörfler 
2335af32e75SAxel Dörfler 
2345af32e75SAxel Dörfler static void
map_page(void * virtualAddress,void * physicalAddress,uint8 mode)2355af32e75SAxel Dörfler map_page(void *virtualAddress, void *physicalAddress, uint8 mode)
2365af32e75SAxel Dörfler {
237bdee97bcSAxel Dörfler 	uint32 virtualSegmentID
238bdee97bcSAxel Dörfler 		= sSegments[addr_t(virtualAddress) >> 28].virtual_segment_id;
2395af32e75SAxel Dörfler 
240bdee97bcSAxel Dörfler 	uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID,
241bdee97bcSAxel Dörfler 		(uint32)virtualAddress);
2425af32e75SAxel Dörfler 	page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask];
2435af32e75SAxel Dörfler 
2445af32e75SAxel Dörfler 	for (int32 i = 0; i < 8; i++) {
2455af32e75SAxel Dörfler 		// 8 entries in a group
2465af32e75SAxel Dörfler 		if (group->entry[i].valid)
2475af32e75SAxel Dörfler 			continue;
2485af32e75SAxel Dörfler 
249bdee97bcSAxel Dörfler 		fill_page_table_entry(&group->entry[i], virtualSegmentID,
250bdee97bcSAxel Dörfler 			virtualAddress, physicalAddress, mode, false);
2512e3b6c53SAlexander von Gluck IV 		//TRACE("map: va = %p -> %p, mode = %d, hash = %lu\n",
2522e3b6c53SAlexander von Gluck IV 		//	virtualAddress, physicalAddress, mode, hash);
2535af32e75SAxel Dörfler 		return;
2545af32e75SAxel Dörfler 	}
2555af32e75SAxel Dörfler 
2565af32e75SAxel Dörfler 	hash = page_table_entry::SecondaryHash(hash);
2575af32e75SAxel Dörfler 	group = &sPageTable[hash & sPageTableHashMask];
2585af32e75SAxel Dörfler 
2595af32e75SAxel Dörfler 	for (int32 i = 0; i < 8; i++) {
2605af32e75SAxel Dörfler 		if (group->entry[i].valid)
2615af32e75SAxel Dörfler 			continue;
2625af32e75SAxel Dörfler 
263bdee97bcSAxel Dörfler 		fill_page_table_entry(&group->entry[i], virtualSegmentID,
264bdee97bcSAxel Dörfler 			virtualAddress, physicalAddress, mode, true);
2652e3b6c53SAlexander von Gluck IV 		//TRACE("map: va = %p -> %p, mode = %d, second hash = %lu\n",
2662e3b6c53SAlexander von Gluck IV 		//	virtualAddress, physicalAddress, mode, hash);
2675af32e75SAxel Dörfler 		return;
2685af32e75SAxel Dörfler 	}
2695af32e75SAxel Dörfler 
2702e3b6c53SAlexander von Gluck IV 	panic("%s: out of page table entries!\n", __func__);
2715af32e75SAxel Dörfler }
2725af32e75SAxel Dörfler 
2735af32e75SAxel Dörfler 
2745af32e75SAxel Dörfler static void
map_range(void * virtualAddress,void * physicalAddress,size_t size,uint8 mode)2755af32e75SAxel Dörfler map_range(void *virtualAddress, void *physicalAddress, size_t size, uint8 mode)
2765af32e75SAxel Dörfler {
2775af32e75SAxel Dörfler 	for (uint32 offset = 0; offset < size; offset += B_PAGE_SIZE) {
2785af32e75SAxel Dörfler 		map_page((void *)(uint32(virtualAddress) + offset),
2795af32e75SAxel Dörfler 			(void *)(uint32(physicalAddress) + offset), mode);
2805af32e75SAxel Dörfler 	}
2815af32e75SAxel Dörfler }
2825af32e75SAxel Dörfler 
2835af32e75SAxel Dörfler 
2845af32e75SAxel Dörfler static status_t
find_allocated_ranges(void * oldPageTable,void * pageTable,page_table_entry_group ** _physicalPageTable,void ** _exceptionHandlers)285a1bcf2c8SIngo Weinhold find_allocated_ranges(void *oldPageTable, void *pageTable,
286a1bcf2c8SIngo Weinhold 	page_table_entry_group **_physicalPageTable, void **_exceptionHandlers)
2875af32e75SAxel Dörfler {
2885af32e75SAxel Dörfler 	// we have to preserve the OpenFirmware established mappings
2895af32e75SAxel Dörfler 	// if we want to continue to use its service after we've
2905af32e75SAxel Dörfler 	// taken over (we will probably need less translations once
2915af32e75SAxel Dörfler 	// we have proper driver support for the target hardware).
2925af32e75SAxel Dörfler 	int mmu;
2935af32e75SAxel Dörfler 	if (of_getprop(gChosen, "mmu", &mmu, sizeof(int)) == OF_FAILED) {
2942e3b6c53SAlexander von Gluck IV 		dprintf("%s: Error: no OpenFirmware mmu\n", __func__);
2955af32e75SAxel Dörfler 		return B_ERROR;
2965af32e75SAxel Dörfler 	}
2975af32e75SAxel Dörfler 	mmu = of_instance_to_package(mmu);
2985af32e75SAxel Dörfler 
2995af32e75SAxel Dörfler 	struct translation_map {
3005af32e75SAxel Dörfler 		void	*virtual_address;
3015af32e75SAxel Dörfler 		int		length;
3025af32e75SAxel Dörfler 		void	*physical_address;
3035af32e75SAxel Dörfler 		int		mode;
3045af32e75SAxel Dörfler 	} translations[64];
305bdee97bcSAxel Dörfler 
306bdee97bcSAxel Dörfler 	int length = of_getprop(mmu, "translations", &translations,
307bdee97bcSAxel Dörfler 		sizeof(translations));
3085af32e75SAxel Dörfler 	if (length == OF_FAILED) {
3092e3b6c53SAlexander von Gluck IV 		dprintf("Error: no OF translations.\n");
3105af32e75SAxel Dörfler 		return B_ERROR;
3115af32e75SAxel Dörfler 	}
3125af32e75SAxel Dörfler 	length = length / sizeof(struct translation_map);
3135af32e75SAxel Dörfler 	uint32 total = 0;
3142e3b6c53SAlexander von Gluck IV 	dprintf("found %d translations\n", length);
3155af32e75SAxel Dörfler 
3165af32e75SAxel Dörfler 	for (int i = 0; i < length; i++) {
3175af32e75SAxel Dörfler 		struct translation_map *map = &translations[i];
318a1bcf2c8SIngo Weinhold 		bool keepRange = true;
3192e3b6c53SAlexander von Gluck IV 		TRACE("%i: map: %p, length %d -> physical: %p, mode %d\n", i,
3202e3b6c53SAlexander von Gluck IV 			map->virtual_address, map->length,
3212e3b6c53SAlexander von Gluck IV 			map->physical_address, map->mode);
3225af32e75SAxel Dörfler 
3235af32e75SAxel Dörfler 		// insert range in physical allocated, if it points to physical memory
3245af32e75SAxel Dörfler 
3255af32e75SAxel Dörfler 		if (is_physical_memory(map->physical_address)
326d73ddac5SIngo Weinhold 			&& insert_physical_allocated_range((addr_t)map->physical_address,
327bdee97bcSAxel Dörfler 				map->length) != B_OK) {
3282e3b6c53SAlexander von Gluck IV 			dprintf("cannot map physical allocated range "
3292e3b6c53SAlexander von Gluck IV 				"(num ranges = %" B_PRIu32 ")!\n",
330bdee97bcSAxel Dörfler 				gKernelArgs.num_physical_allocated_ranges);
3315af32e75SAxel Dörfler 			return B_ERROR;
3325af32e75SAxel Dörfler 		}
3335af32e75SAxel Dörfler 
3345af32e75SAxel Dörfler 		if (map->virtual_address == pageTable) {
335a1a978ffSAlexander von Gluck IV 			dprintf("%i: found page table at va %p\n", i,
336a1a978ffSAlexander von Gluck IV 				map->virtual_address);
337bdee97bcSAxel Dörfler 			*_physicalPageTable
338bdee97bcSAxel Dörfler 				= (page_table_entry_group *)map->physical_address;
3395c9bd9d6SStephan Aßmus 			keepRange = false;
3405c9bd9d6SStephan Aßmus 				// we keep it explicitely anyway
3415af32e75SAxel Dörfler 		}
3425af32e75SAxel Dörfler 		if ((addr_t)map->physical_address <= 0x100
3435af32e75SAxel Dörfler 			&& (addr_t)map->physical_address + map->length >= 0x1000) {
344a1a978ffSAlexander von Gluck IV 			dprintf("%i: found exception handlers at va %p\n", i,
345a1a978ffSAlexander von Gluck IV 				map->virtual_address);
3465af32e75SAxel Dörfler 			*_exceptionHandlers = map->virtual_address;
3475c9bd9d6SStephan Aßmus 			keepRange = false;
3485c9bd9d6SStephan Aßmus 				// we keep it explicitely anyway
3495af32e75SAxel Dörfler 		}
350a1bcf2c8SIngo Weinhold 		if (map->virtual_address == oldPageTable)
351a1bcf2c8SIngo Weinhold 			keepRange = false;
3525af32e75SAxel Dörfler 
3535af32e75SAxel Dörfler 		// insert range in virtual allocated
3545af32e75SAxel Dörfler 
355d73ddac5SIngo Weinhold 		if (insert_virtual_allocated_range((addr_t)map->virtual_address,
356bdee97bcSAxel Dörfler 				map->length) != B_OK) {
3572e3b6c53SAlexander von Gluck IV 			dprintf("cannot map virtual allocated range "
3582e3b6c53SAlexander von Gluck IV 				"(num ranges = %" B_PRIu32 ")!\n",
359bdee97bcSAxel Dörfler 				gKernelArgs.num_virtual_allocated_ranges);
3605af32e75SAxel Dörfler 		}
3615af32e75SAxel Dörfler 
3625af32e75SAxel Dörfler 		// map range into the page table
3635af32e75SAxel Dörfler 
364bdee97bcSAxel Dörfler 		map_range(map->virtual_address, map->physical_address, map->length,
365bdee97bcSAxel Dörfler 			map->mode);
3665af32e75SAxel Dörfler 
367a1bcf2c8SIngo Weinhold 		// insert range in virtual ranges to keep
368a1bcf2c8SIngo Weinhold 
369a1bcf2c8SIngo Weinhold 		if (keepRange) {
370a1a978ffSAlexander von Gluck IV 			TRACE("%i: keeping free range starting at va %p\n", i,
371a1a978ffSAlexander von Gluck IV 				map->virtual_address);
372a1a978ffSAlexander von Gluck IV 
373a1bcf2c8SIngo Weinhold 			if (insert_virtual_range_to_keep(map->virtual_address,
374bdee97bcSAxel Dörfler 					map->length) != B_OK) {
3752e3b6c53SAlexander von Gluck IV 				dprintf("cannot map virtual range to keep "
3762e3b6c53SAlexander von Gluck IV 					"(num ranges = %" B_PRIu32 ")\n",
377a1bcf2c8SIngo Weinhold 					gKernelArgs.num_virtual_allocated_ranges);
378a1bcf2c8SIngo Weinhold 			}
379a1bcf2c8SIngo Weinhold 		}
380a1bcf2c8SIngo Weinhold 
3815af32e75SAxel Dörfler 		total += map->length;
3825af32e75SAxel Dörfler 	}
383a1a978ffSAlexander von Gluck IV 	dprintf("total size kept: %" B_PRIu32 "\n", total);
3845af32e75SAxel Dörfler 
385a1bcf2c8SIngo Weinhold 	// remove the boot loader code from the virtual ranges to keep in the
386a1bcf2c8SIngo Weinhold 	// kernel
387a1bcf2c8SIngo Weinhold 	if (remove_virtual_range_to_keep(&__text_begin, &_end - &__text_begin)
388a1bcf2c8SIngo Weinhold 			!= B_OK) {
389a1a978ffSAlexander von Gluck IV 		dprintf("%s: Failed to remove boot loader range "
390a1a978ffSAlexander von Gluck IV 			"from virtual ranges to keep.\n", __func__);
391a1bcf2c8SIngo Weinhold 	}
392a1bcf2c8SIngo Weinhold 
3935af32e75SAxel Dörfler 	return B_OK;
3945af32e75SAxel Dörfler }
3955af32e75SAxel Dörfler 
3965af32e75SAxel Dörfler 
397bdee97bcSAxel Dörfler /*!	Computes the recommended minimal page table size as
398bdee97bcSAxel Dörfler 	described in table 7-22 of the PowerPC "Programming
399bdee97bcSAxel Dörfler 	Environment for 32-Bit Microprocessors".
400bdee97bcSAxel Dörfler 	The page table size ranges from 64 kB (for 8 MB RAM)
401bdee97bcSAxel Dörfler 	to 32 MB (for 4 GB RAM).
4025af32e75SAxel Dörfler */
4035af32e75SAxel Dörfler static size_t
suggested_page_table_size(size_t total)4045af32e75SAxel Dörfler suggested_page_table_size(size_t total)
4055af32e75SAxel Dörfler {
4065af32e75SAxel Dörfler 	uint32 max = 23;
4075af32e75SAxel Dörfler 		// 2^23 == 8 MB
4085af32e75SAxel Dörfler 
4095af32e75SAxel Dörfler 	while (max < 32) {
4105af32e75SAxel Dörfler 		if (total <= (1UL << max))
4115af32e75SAxel Dörfler 			break;
4125af32e75SAxel Dörfler 
4135af32e75SAxel Dörfler 		max++;
4145af32e75SAxel Dörfler 	}
4155af32e75SAxel Dörfler 
4165af32e75SAxel Dörfler 	return 1UL << (max - 7);
4175af32e75SAxel Dörfler 		// 2^(23 - 7) == 64 kB
4185af32e75SAxel Dörfler }
4195af32e75SAxel Dörfler 
4205af32e75SAxel Dörfler 
4215af32e75SAxel Dörfler static void *
find_physical_memory_range(size_t size)4225af32e75SAxel Dörfler find_physical_memory_range(size_t size)
4235af32e75SAxel Dörfler {
4245af32e75SAxel Dörfler 	for (uint32 i = 0; i < gKernelArgs.num_physical_memory_ranges; i++) {
4255af32e75SAxel Dörfler 		if (gKernelArgs.physical_memory_range[i].size > size)
42617a33898SAlex Smith 			return (void *)(addr_t)gKernelArgs.physical_memory_range[i].start;
4275af32e75SAxel Dörfler 	}
4283b148e53SFrançois Revol 	return PHYSINVAL;
4295af32e75SAxel Dörfler }
4305af32e75SAxel Dörfler 
4315af32e75SAxel Dörfler 
4325af32e75SAxel Dörfler static void *
find_free_physical_range(size_t size)4335af32e75SAxel Dörfler find_free_physical_range(size_t size)
4345af32e75SAxel Dörfler {
4355af32e75SAxel Dörfler 	// just do a simple linear search at the end of the allocated
4365af32e75SAxel Dörfler 	// ranges (dumb memory allocation)
4375af32e75SAxel Dörfler 	if (gKernelArgs.num_physical_allocated_ranges == 0) {
4385af32e75SAxel Dörfler 		if (gKernelArgs.num_physical_memory_ranges == 0)
4393b148e53SFrançois Revol 			return PHYSINVAL;
4405af32e75SAxel Dörfler 
4415af32e75SAxel Dörfler 		return find_physical_memory_range(size);
4425af32e75SAxel Dörfler 	}
4435af32e75SAxel Dörfler 
4445af32e75SAxel Dörfler 	for (uint32 i = 0; i < gKernelArgs.num_physical_allocated_ranges; i++) {
4456b87898aSAlex Smith 		void *address
4466b87898aSAlex Smith 			= (void *)(addr_t)(gKernelArgs.physical_allocated_range[i].start
447bdee97bcSAxel Dörfler 				+ gKernelArgs.physical_allocated_range[i].size);
448bdee97bcSAxel Dörfler 		if (!is_physical_allocated(address, size)
449bdee97bcSAxel Dörfler 			&& is_physical_memory(address, size))
4505af32e75SAxel Dörfler 			return address;
4515af32e75SAxel Dörfler 	}
4523b148e53SFrançois Revol 	return PHYSINVAL;
4535af32e75SAxel Dörfler }
4545af32e75SAxel Dörfler 
4555af32e75SAxel Dörfler 
4565af32e75SAxel Dörfler static void *
find_free_virtual_range(void * base,size_t size)457c83d9dadSIngo Weinhold find_free_virtual_range(void *base, size_t size)
4585af32e75SAxel Dörfler {
459c83d9dadSIngo Weinhold 	if (base && !is_virtual_allocated(base, size))
460c83d9dadSIngo Weinhold 		return base;
461c83d9dadSIngo Weinhold 
462c83d9dadSIngo Weinhold 	void *firstFound = NULL;
463c83d9dadSIngo Weinhold 	void *firstBaseFound = NULL;
4645af32e75SAxel Dörfler 	for (uint32 i = 0; i < gKernelArgs.num_virtual_allocated_ranges; i++) {
4656b87898aSAlex Smith 		void *address
4666b87898aSAlex Smith 			= (void *)(addr_t)(gKernelArgs.virtual_allocated_range[i].start
467bdee97bcSAxel Dörfler 				+ gKernelArgs.virtual_allocated_range[i].size);
468c83d9dadSIngo Weinhold 		if (!is_virtual_allocated(address, size)) {
469c83d9dadSIngo Weinhold 			if (!base)
4705af32e75SAxel Dörfler 				return address;
471c83d9dadSIngo Weinhold 
472c83d9dadSIngo Weinhold 			if (firstFound == NULL)
473c83d9dadSIngo Weinhold 				firstFound = address;
474c83d9dadSIngo Weinhold 			if (address >= base
475c83d9dadSIngo Weinhold 				&& (firstBaseFound == NULL || address < firstBaseFound)) {
476c83d9dadSIngo Weinhold 				firstBaseFound = address;
4775af32e75SAxel Dörfler 			}
478c83d9dadSIngo Weinhold 		}
479c83d9dadSIngo Weinhold 	}
480c83d9dadSIngo Weinhold 	return (firstBaseFound ? firstBaseFound : firstFound);
4815af32e75SAxel Dörfler }
4825af32e75SAxel Dörfler 
4835af32e75SAxel Dörfler 
4845af32e75SAxel Dörfler extern "C" void *
arch_mmu_allocate(void * _virtualAddress,size_t size,uint8 _protection,bool exactAddress)485957a1b17SIngo Weinhold arch_mmu_allocate(void *_virtualAddress, size_t size, uint8 _protection,
486c83d9dadSIngo Weinhold 	bool exactAddress)
4875af32e75SAxel Dörfler {
4885af32e75SAxel Dörfler 	// we only know page sizes
4895af32e75SAxel Dörfler 	size = ROUNDUP(size, B_PAGE_SIZE);
4905af32e75SAxel Dörfler 
491957a1b17SIngo Weinhold 	uint8 protection = 0;
492957a1b17SIngo Weinhold 	if (_protection & B_WRITE_AREA)
493a268fbfeSAxel Dörfler 		protection = PAGE_READ_WRITE;
49422bc93e3SIngo Weinhold 	else
495a268fbfeSAxel Dörfler 		protection = PAGE_READ_ONLY;
4965af32e75SAxel Dörfler 
497a1bcf2c8SIngo Weinhold 	// If no address is given, use the KERNEL_BASE as base address, since
498a1bcf2c8SIngo Weinhold 	// that avoids trouble in the kernel, when we decide to keep the region.
499a1bcf2c8SIngo Weinhold 	void *virtualAddress = _virtualAddress;
500a1bcf2c8SIngo Weinhold 	if (!virtualAddress)
501a1bcf2c8SIngo Weinhold 		virtualAddress = (void*)KERNEL_BASE;
502a1bcf2c8SIngo Weinhold 
5035af32e75SAxel Dörfler 	// find free address large enough to hold "size"
504a1bcf2c8SIngo Weinhold 	virtualAddress = find_free_virtual_range(virtualAddress, size);
5055af32e75SAxel Dörfler 	if (virtualAddress == NULL)
5065af32e75SAxel Dörfler 		return NULL;
507c83d9dadSIngo Weinhold 
508c83d9dadSIngo Weinhold 	// fail if the exact address was requested, but is not free
509c83d9dadSIngo Weinhold 	if (exactAddress && _virtualAddress && virtualAddress != _virtualAddress) {
510c83d9dadSIngo Weinhold 		dprintf("arch_mmu_allocate(): exact address requested, but virtual "
5112e3b6c53SAlexander von Gluck IV 			"range (base: %p, size: %" B_PRIuSIZE ") is not free.\n",
512c83d9dadSIngo Weinhold 			_virtualAddress, size);
5135af32e75SAxel Dörfler 		return NULL;
5145af32e75SAxel Dörfler 	}
5155af32e75SAxel Dörfler 
5165af32e75SAxel Dörfler 	// we have a free virtual range for the allocation, now
5175af32e75SAxel Dörfler 	// have a look for free physical memory as well (we assume
5185af32e75SAxel Dörfler 	// that a) there is enough memory, and b) failing is fatal
5195af32e75SAxel Dörfler 	// so that we don't have to optimize for these cases :)
5205af32e75SAxel Dörfler 
5215af32e75SAxel Dörfler 	void *physicalAddress = find_free_physical_range(size);
5223b148e53SFrançois Revol 	if (physicalAddress == PHYSINVAL) {
5232e3b6c53SAlexander von Gluck IV 		dprintf("arch_mmu_allocate(base: %p, size: %" B_PRIuSIZE ") "
5242e3b6c53SAlexander von Gluck IV 			"no free physical address\n", virtualAddress, size);
5255af32e75SAxel Dörfler 		return NULL;
526c83d9dadSIngo Weinhold 	}
5275af32e75SAxel Dörfler 
5285af32e75SAxel Dörfler 	// everything went fine, so lets mark the space as used.
5295af32e75SAxel Dörfler 
5302e3b6c53SAlexander von Gluck IV 	dprintf("mmu_alloc: va %p, pa %p, size %" B_PRIuSIZE "\n", virtualAddress,
531bdee97bcSAxel Dörfler 		physicalAddress, size);
532d73ddac5SIngo Weinhold 	insert_virtual_allocated_range((addr_t)virtualAddress, size);
533d73ddac5SIngo Weinhold 	insert_physical_allocated_range((addr_t)physicalAddress, size);
5345af32e75SAxel Dörfler 
5355af32e75SAxel Dörfler 	map_range(virtualAddress, physicalAddress, size, protection);
5365af32e75SAxel Dörfler 
5375af32e75SAxel Dörfler 	return virtualAddress;
5385af32e75SAxel Dörfler }
5395af32e75SAxel Dörfler 
5405af32e75SAxel Dörfler 
5415af32e75SAxel Dörfler extern "C" status_t
arch_mmu_free(void * address,size_t size)5425af32e75SAxel Dörfler arch_mmu_free(void *address, size_t size)
5435af32e75SAxel Dörfler {
544bdee97bcSAxel Dörfler 	// TODO: implement freeing a region!
5455af32e75SAxel Dörfler 	return B_OK;
5465af32e75SAxel Dörfler }
5475af32e75SAxel Dörfler 
5485af32e75SAxel Dörfler 
5495af32e75SAxel Dörfler static inline void
invalidate_tlb(void)5505af32e75SAxel Dörfler invalidate_tlb(void)
5515af32e75SAxel Dörfler {
5525af32e75SAxel Dörfler 	//asm volatile("tlbia");
5535af32e75SAxel Dörfler 		// "tlbia" is obviously not available on every CPU...
5545af32e75SAxel Dörfler 
5555af32e75SAxel Dörfler 	// Note: this flushes the whole 4 GB address space - it
5565af32e75SAxel Dörfler 	//		would probably be a good idea to do less here
5575af32e75SAxel Dörfler 
5585af32e75SAxel Dörfler 	addr_t address = 0;
5595af32e75SAxel Dörfler 	for (uint32 i = 0; i < 0x100000; i++) {
5605af32e75SAxel Dörfler 		asm volatile("tlbie %0" : : "r" (address));
5615af32e75SAxel Dörfler 		address += B_PAGE_SIZE;
5625af32e75SAxel Dörfler 	}
5635af32e75SAxel Dörfler 	tlbsync();
5645af32e75SAxel Dörfler }
5655af32e75SAxel Dörfler 
5665af32e75SAxel Dörfler 
567bdee97bcSAxel Dörfler //	#pragma mark - OpenFirmware callbacks and public API
5685af32e75SAxel Dörfler 
5695af32e75SAxel Dörfler 
5705af32e75SAxel Dörfler static int
map_callback(struct of_arguments * args)5715af32e75SAxel Dörfler map_callback(struct of_arguments *args)
5725af32e75SAxel Dörfler {
5735af32e75SAxel Dörfler 	void *physicalAddress = (void *)args->Argument(0);
5745af32e75SAxel Dörfler 	void *virtualAddress = (void *)args->Argument(1);
5755af32e75SAxel Dörfler 	int length = args->Argument(2);
5765af32e75SAxel Dörfler 	int mode = args->Argument(3);
57709b40d16SYnoga 	intptr_t &error = args->ReturnValue(0);
5785af32e75SAxel Dörfler 
5795af32e75SAxel Dörfler 	// insert range in physical allocated if needed
5805af32e75SAxel Dörfler 
5815af32e75SAxel Dörfler 	if (is_physical_memory(physicalAddress)
582d73ddac5SIngo Weinhold 		&& insert_physical_allocated_range((addr_t)physicalAddress, length)
583d73ddac5SIngo Weinhold 			!= B_OK) {
5845af32e75SAxel Dörfler 		error = -1;
5855af32e75SAxel Dörfler 		return OF_FAILED;
5865af32e75SAxel Dörfler 	}
5875af32e75SAxel Dörfler 
5885af32e75SAxel Dörfler 	// insert range in virtual allocated
5895af32e75SAxel Dörfler 
590d73ddac5SIngo Weinhold 	if (insert_virtual_allocated_range((addr_t)virtualAddress, length)
591d73ddac5SIngo Weinhold 			!= B_OK) {
5925af32e75SAxel Dörfler 		error = -2;
5935af32e75SAxel Dörfler 		return OF_FAILED;
5945af32e75SAxel Dörfler 	}
5955af32e75SAxel Dörfler 
5965af32e75SAxel Dörfler 	// map range into the page table
5975af32e75SAxel Dörfler 
5985af32e75SAxel Dörfler 	map_range(virtualAddress, physicalAddress, length, mode);
5995af32e75SAxel Dörfler 
6005af32e75SAxel Dörfler 	return B_OK;
6015af32e75SAxel Dörfler }
6025af32e75SAxel Dörfler 
6035af32e75SAxel Dörfler 
6045af32e75SAxel Dörfler static int
unmap_callback(struct of_arguments * args)6055af32e75SAxel Dörfler unmap_callback(struct of_arguments *args)
6065af32e75SAxel Dörfler {
6075af32e75SAxel Dörfler /*	void *address = (void *)args->Argument(0);
6085af32e75SAxel Dörfler 	int length = args->Argument(1);
6095af32e75SAxel Dörfler 	int &error = args->ReturnValue(0);
6105af32e75SAxel Dörfler */
611bdee97bcSAxel Dörfler 	// TODO: to be implemented
6125af32e75SAxel Dörfler 
6135af32e75SAxel Dörfler 	return OF_FAILED;
6145af32e75SAxel Dörfler }
6155af32e75SAxel Dörfler 
6165af32e75SAxel Dörfler 
6175af32e75SAxel Dörfler static int
translate_callback(struct of_arguments * args)6185af32e75SAxel Dörfler translate_callback(struct of_arguments *args)
6195af32e75SAxel Dörfler {
6205af32e75SAxel Dörfler 	addr_t virtualAddress = (addr_t)args->Argument(0);
62109b40d16SYnoga 	intptr_t &error = args->ReturnValue(0);
62209b40d16SYnoga 	intptr_t &physicalAddress = args->ReturnValue(1);
62309b40d16SYnoga 	intptr_t &mode = args->ReturnValue(2);
6245af32e75SAxel Dörfler 
6255af32e75SAxel Dörfler 	// Find page table entry for this address
6265af32e75SAxel Dörfler 
627bdee97bcSAxel Dörfler 	uint32 virtualSegmentID
628bdee97bcSAxel Dörfler 		= sSegments[addr_t(virtualAddress) >> 28].virtual_segment_id;
6295af32e75SAxel Dörfler 
630bdee97bcSAxel Dörfler 	uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID,
631bdee97bcSAxel Dörfler 		(uint32)virtualAddress);
6325af32e75SAxel Dörfler 	page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask];
6335af32e75SAxel Dörfler 	page_table_entry *entry = NULL;
6345af32e75SAxel Dörfler 
6355af32e75SAxel Dörfler 	for (int32 i = 0; i < 8; i++) {
6365af32e75SAxel Dörfler 		entry = &group->entry[i];
6375af32e75SAxel Dörfler 
6385af32e75SAxel Dörfler 		if (entry->valid
6395af32e75SAxel Dörfler 			&& entry->virtual_segment_id == virtualSegmentID
6405af32e75SAxel Dörfler 			&& entry->secondary_hash == false
6415af32e75SAxel Dörfler 			&& entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f))
6425af32e75SAxel Dörfler 			goto success;
6435af32e75SAxel Dörfler 	}
6445af32e75SAxel Dörfler 
6455af32e75SAxel Dörfler 	hash = page_table_entry::SecondaryHash(hash);
6465af32e75SAxel Dörfler 	group = &sPageTable[hash & sPageTableHashMask];
6475af32e75SAxel Dörfler 
6485af32e75SAxel Dörfler 	for (int32 i = 0; i < 8; i++) {
6495af32e75SAxel Dörfler 		entry = &group->entry[i];
6505af32e75SAxel Dörfler 
6515af32e75SAxel Dörfler 		if (entry->valid
6525af32e75SAxel Dörfler 			&& entry->virtual_segment_id == virtualSegmentID
6535af32e75SAxel Dörfler 			&& entry->secondary_hash == true
6545af32e75SAxel Dörfler 			&& entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f))
6555af32e75SAxel Dörfler 			goto success;
6565af32e75SAxel Dörfler 	}
6575af32e75SAxel Dörfler 
6585af32e75SAxel Dörfler 	// could not find the translation
6595af32e75SAxel Dörfler 	error = B_ENTRY_NOT_FOUND;
6605af32e75SAxel Dörfler 	return OF_FAILED;
6615af32e75SAxel Dörfler 
6625af32e75SAxel Dörfler success:
6635af32e75SAxel Dörfler 	// we found the entry in question
6645af32e75SAxel Dörfler 	physicalAddress = (int)(entry->physical_page_number * B_PAGE_SIZE);
6655af32e75SAxel Dörfler 	mode = (entry->write_through << 6)		// WIMGxPP
6665af32e75SAxel Dörfler 		| (entry->caching_inhibited << 5)
6675af32e75SAxel Dörfler 		| (entry->memory_coherent << 4)
6685af32e75SAxel Dörfler 		| (entry->guarded << 3)
6695af32e75SAxel Dörfler 		| entry->page_protection;
6705af32e75SAxel Dörfler 	error = B_OK;
6715af32e75SAxel Dörfler 
6725af32e75SAxel Dörfler 	return B_OK;
6735af32e75SAxel Dörfler }
6745af32e75SAxel Dörfler 
6755af32e75SAxel Dörfler 
6765af32e75SAxel Dörfler static int
alloc_real_mem_callback(struct of_arguments * args)6775af32e75SAxel Dörfler alloc_real_mem_callback(struct of_arguments *args)
6785af32e75SAxel Dörfler {
6795af32e75SAxel Dörfler /*	addr_t minAddress = (addr_t)args->Argument(0);
6805af32e75SAxel Dörfler 	addr_t maxAddress = (addr_t)args->Argument(1);
6815af32e75SAxel Dörfler 	int length = args->Argument(2);
6825af32e75SAxel Dörfler 	int mode = args->Argument(3);
6835af32e75SAxel Dörfler 	int &error = args->ReturnValue(0);
6845af32e75SAxel Dörfler 	int &physicalAddress = args->ReturnValue(1);
6855af32e75SAxel Dörfler */
6865af32e75SAxel Dörfler 	// ToDo: to be implemented
6875af32e75SAxel Dörfler 
6885af32e75SAxel Dörfler 	return OF_FAILED;
6895af32e75SAxel Dörfler }
6905af32e75SAxel Dörfler 
6915af32e75SAxel Dörfler 
6925af32e75SAxel Dörfler /** Dispatches the callback to the responsible function */
6935af32e75SAxel Dörfler 
6945af32e75SAxel Dörfler static int
callback(struct of_arguments * args)6955af32e75SAxel Dörfler callback(struct of_arguments *args)
6965af32e75SAxel Dörfler {
6975af32e75SAxel Dörfler 	const char *name = args->name;
6982e3b6c53SAlexander von Gluck IV 	TRACE("OF CALLBACK: %s\n", name);
6995af32e75SAxel Dörfler 
7005af32e75SAxel Dörfler 	if (!strcmp(name, "map"))
7015af32e75SAxel Dörfler 		return map_callback(args);
7025af32e75SAxel Dörfler 	else if (!strcmp(name, "unmap"))
7035af32e75SAxel Dörfler 		return unmap_callback(args);
7045af32e75SAxel Dörfler 	else if (!strcmp(name, "translate"))
7055af32e75SAxel Dörfler 		return translate_callback(args);
7065af32e75SAxel Dörfler 	else if (!strcmp(name, "alloc-real-mem"))
7075af32e75SAxel Dörfler 		return alloc_real_mem_callback(args);
7085af32e75SAxel Dörfler 
7095af32e75SAxel Dörfler 	return OF_FAILED;
7105af32e75SAxel Dörfler }
7115af32e75SAxel Dörfler 
7125af32e75SAxel Dörfler 
7135af32e75SAxel Dörfler extern "C" status_t
arch_set_callback(void)7145af32e75SAxel Dörfler arch_set_callback(void)
7155af32e75SAxel Dörfler {
7165af32e75SAxel Dörfler 	// set OpenFirmware callbacks - it will ask us for memory after that
7175af32e75SAxel Dörfler 	// instead of maintaining it itself
7185af32e75SAxel Dörfler 
7195af32e75SAxel Dörfler 	void *oldCallback = NULL;
72022a65222SIngo Weinhold 	if (of_call_client_function("set-callback", 1, 1, &callback, &oldCallback)
72122a65222SIngo Weinhold 			== OF_FAILED) {
7222e3b6c53SAlexander von Gluck IV 		dprintf("Error: OpenFirmware set-callback failed\n");
7235af32e75SAxel Dörfler 		return B_ERROR;
7245af32e75SAxel Dörfler 	}
7252e3b6c53SAlexander von Gluck IV 	TRACE("old callback = %p; new callback = %p\n", oldCallback, callback);
7265af32e75SAxel Dörfler 
7275af32e75SAxel Dörfler 	return B_OK;
7285af32e75SAxel Dörfler }
7295af32e75SAxel Dörfler 
7305af32e75SAxel Dörfler 
7315af32e75SAxel Dörfler extern "C" status_t
arch_mmu_init(void)7325af32e75SAxel Dörfler arch_mmu_init(void)
7335af32e75SAxel Dörfler {
7345af32e75SAxel Dörfler 	// get map of physical memory (fill in kernel_args structure)
7355af32e75SAxel Dörfler 
7365af32e75SAxel Dörfler 	size_t total;
737bdee97bcSAxel Dörfler 	if (find_physical_memory_ranges(total) != B_OK) {
7382e3b6c53SAlexander von Gluck IV 		dprintf("Error: could not find physical memory ranges!\n");
7395af32e75SAxel Dörfler 		return B_ERROR;
7405af32e75SAxel Dörfler 	}
7412e3b6c53SAlexander von Gluck IV 	dprintf("total physical memory = %" B_PRId32 "MB\n", total / (1024 * 1024));
7425af32e75SAxel Dörfler 
7435af32e75SAxel Dörfler 	// get OpenFirmware's current page table
7445af32e75SAxel Dörfler 
745a1bcf2c8SIngo Weinhold 	page_table_entry_group *oldTable;
7465af32e75SAxel Dörfler 	page_table_entry_group *table;
7475af32e75SAxel Dörfler 	size_t tableSize;
7485af32e75SAxel Dörfler 	ppc_get_page_table(&table, &tableSize);
749a268fbfeSAxel Dörfler 
750a1bcf2c8SIngo Weinhold 	oldTable = table;
7515af32e75SAxel Dörfler 
752a268fbfeSAxel Dörfler 	bool realMode = false;
753a1a978ffSAlexander von Gluck IV 
754a268fbfeSAxel Dörfler 	// TODO: read these values out of the OF settings
755a1a978ffSAlexander von Gluck IV 	// NOTE: I've only ever seen -1 (0xffffffff) for these values in
756a1a978ffSAlexander von Gluck IV 	//       OpenFirmware.. even after loading the bootloader -- Alex
757a268fbfeSAxel Dörfler 	addr_t realBase = 0;
758a268fbfeSAxel Dörfler 	addr_t realSize = 0x400000;
759a268fbfeSAxel Dörfler 
7605af32e75SAxel Dörfler 	// can we just keep the page table?
7615af32e75SAxel Dörfler 	size_t suggestedTableSize = suggested_page_table_size(total);
7623b60bc6bSAlexander von Gluck IV 	dprintf("current page table size = %" B_PRIuSIZE "\n", tableSize);
7632e3b6c53SAlexander von Gluck IV 	dprintf("suggested page table size = %" B_PRIuSIZE "\n",
7642e3b6c53SAlexander von Gluck IV 		suggestedTableSize);
7655af32e75SAxel Dörfler 	if (tableSize < suggestedTableSize) {
7665af32e75SAxel Dörfler 		// nah, we need a new one!
7672e3b6c53SAlexander von Gluck IV 		dprintf("need new page table, size = %" B_PRIuSIZE "!\n",
7682e3b6c53SAlexander von Gluck IV 			suggestedTableSize);
769bdee97bcSAxel Dörfler 		table = (page_table_entry_group *)of_claim(NULL, suggestedTableSize,
770bdee97bcSAxel Dörfler 			suggestedTableSize);
7715af32e75SAxel Dörfler 			// KERNEL_BASE would be better as virtual address, but
7725af32e75SAxel Dörfler 			// at least with Apple's OpenFirmware, it makes no
7735af32e75SAxel Dörfler 			// difference - we will have to remap it later
7745af32e75SAxel Dörfler 		if (table == (void *)OF_FAILED) {
7752e3b6c53SAlexander von Gluck IV 			panic("Could not allocate new page table "
7762e3b6c53SAlexander von Gluck IV 				"(size = %" B_PRIuSIZE ")!!\n", suggestedTableSize);
7775af32e75SAxel Dörfler 			return B_NO_MEMORY;
7785af32e75SAxel Dörfler 		}
779a268fbfeSAxel Dörfler 		if (table == NULL) {
780a268fbfeSAxel Dörfler 			// work-around for the broken Pegasos OpenFirmware
7812e3b6c53SAlexander von Gluck IV 			dprintf("broken OpenFirmware detected (claim doesn't work)\n");
782a268fbfeSAxel Dörfler 			realMode = true;
783a268fbfeSAxel Dörfler 
784a268fbfeSAxel Dörfler 			addr_t tableBase = 0;
785a268fbfeSAxel Dörfler 			for (int32 i = 0; tableBase < realBase + realSize * 3; i++) {
786a268fbfeSAxel Dörfler 				tableBase = suggestedTableSize * i;
787a268fbfeSAxel Dörfler 			}
788a268fbfeSAxel Dörfler 
789a268fbfeSAxel Dörfler 			table = (page_table_entry_group *)tableBase;
790a268fbfeSAxel Dörfler 		}
791a268fbfeSAxel Dörfler 
7923b60bc6bSAlexander von Gluck IV 		dprintf("OpenFirmware gave us a new page table at: %p\n", table);
793a268fbfeSAxel Dörfler 		sPageTable = table;
7945af32e75SAxel Dörfler 		tableSize = suggestedTableSize;
7955af32e75SAxel Dörfler 	} else {
7965af32e75SAxel Dörfler 		// ToDo: we could check if the page table is much too large
7975af32e75SAxel Dörfler 		//	and create a smaller one in this case (in order to save
7985af32e75SAxel Dörfler 		//	memory).
7993b60bc6bSAlexander von Gluck IV 		dprintf("using original OpenFirmware page table at: %p\n", table);
800a268fbfeSAxel Dörfler 		sPageTable = table;
8015af32e75SAxel Dörfler 	}
802a268fbfeSAxel Dörfler 
8035af32e75SAxel Dörfler 	sPageTableHashMask = tableSize / sizeof(page_table_entry_group) - 1;
804a268fbfeSAxel Dörfler 	if (sPageTable != oldTable)
8055af32e75SAxel Dörfler 		memset(sPageTable, 0, tableSize);
8065af32e75SAxel Dörfler 
8075af32e75SAxel Dörfler 	// turn off address translation via the page table/segment mechanism,
8085af32e75SAxel Dörfler 	// identity map the first 256 MB (where our code/data reside)
8095af32e75SAxel Dörfler 
8102e3b6c53SAlexander von Gluck IV 	dprintf("MSR: %p\n", (void *)get_msr());
8115af32e75SAxel Dörfler 
8123b148e53SFrançois Revol 	#if 0
8133b148e53SFrançois Revol 	block_address_translation bat;
8145af32e75SAxel Dörfler 
8153b148e53SFrançois Revol 	bat.length = BAT_LENGTH_256MB;
8165af32e75SAxel Dörfler 	bat.kernel_valid = true;
8175af32e75SAxel Dörfler 	bat.memory_coherent = true;
8185af32e75SAxel Dörfler 	bat.protection = BAT_READ_WRITE;
8195af32e75SAxel Dörfler 
8205af32e75SAxel Dörfler 	set_ibat0(&bat);
8215af32e75SAxel Dörfler 	set_dbat0(&bat);
8225af32e75SAxel Dörfler 	isync();
8233b148e53SFrançois Revol 	#endif
8245af32e75SAxel Dörfler 
8255af32e75SAxel Dörfler 	// initialize segment descriptors, but don't set the registers
8265af32e75SAxel Dörfler 	// until we're about to take over the page table - we're mapping
8275af32e75SAxel Dörfler 	// pages into our table using these values
8285af32e75SAxel Dörfler 
8295af32e75SAxel Dörfler 	for (int32 i = 0; i < 16; i++)
8305af32e75SAxel Dörfler 		sSegments[i].virtual_segment_id = i;
8315af32e75SAxel Dörfler 
8325af32e75SAxel Dörfler 	// find already allocated ranges of physical memory
8335af32e75SAxel Dörfler 	// and the virtual address space
8345af32e75SAxel Dörfler 
835a1bcf2c8SIngo Weinhold 	page_table_entry_group *physicalTable = NULL;
8365af32e75SAxel Dörfler 	void *exceptionHandlers = (void *)-1;
837a1bcf2c8SIngo Weinhold 	if (find_allocated_ranges(oldTable, table, &physicalTable,
838bdee97bcSAxel Dörfler 			&exceptionHandlers) != B_OK) {
8392e3b6c53SAlexander von Gluck IV 		dprintf("Error: find_allocated_ranges() failed\n");
8402e3b6c53SAlexander von Gluck IV 		return B_ERROR;
841a1bcf2c8SIngo Weinhold 	}
842a1bcf2c8SIngo Weinhold 
843a268fbfeSAxel Dörfler #if 0
844a268fbfeSAxel Dörfler 	block_address_translation bats[8];
845a268fbfeSAxel Dörfler 	getibats(bats);
846bdee97bcSAxel Dörfler 	for (int32 i = 0; i < 8; i++) {
847bdee97bcSAxel Dörfler 		printf("page index %u, length %u, ppn %u\n", bats[i].page_index,
848bdee97bcSAxel Dörfler 			bats[i].length, bats[i].physical_block_number);
849bdee97bcSAxel Dörfler 	}
850a268fbfeSAxel Dörfler #endif
851a268fbfeSAxel Dörfler 
852a1bcf2c8SIngo Weinhold 	if (physicalTable == NULL) {
8532e3b6c53SAlexander von Gluck IV 		dprintf("%s: Didn't find physical address of page table\n", __func__);
854a268fbfeSAxel Dörfler 		if (!realMode)
855a1bcf2c8SIngo Weinhold 			return B_ERROR;
856a268fbfeSAxel Dörfler 
857a268fbfeSAxel Dörfler 		// Pegasos work-around
8582e3b6c53SAlexander von Gluck IV 		#if 0
8592e3b6c53SAlexander von Gluck IV 		map_range((void *)realBase, (void *)realBase,
8602e3b6c53SAlexander von Gluck IV 			realSize * 2, PAGE_READ_WRITE);
8612e3b6c53SAlexander von Gluck IV 		map_range((void *)(total - realSize), (void *)(total - realSize),
8622e3b6c53SAlexander von Gluck IV 			realSize, PAGE_READ_WRITE);
8632e3b6c53SAlexander von Gluck IV 		map_range((void *)table, (void *)table, tableSize, PAGE_READ_WRITE);
8642e3b6c53SAlexander von Gluck IV 		#endif
865d73ddac5SIngo Weinhold 		insert_physical_allocated_range(realBase, realSize * 2);
866d73ddac5SIngo Weinhold 		insert_virtual_allocated_range(realBase, realSize * 2);
867d73ddac5SIngo Weinhold 		insert_physical_allocated_range(total - realSize, realSize);
868d73ddac5SIngo Weinhold 		insert_virtual_allocated_range(total - realSize, realSize);
869d73ddac5SIngo Weinhold 		insert_physical_allocated_range((addr_t)table, tableSize);
870d73ddac5SIngo Weinhold 		insert_virtual_allocated_range((addr_t)table, tableSize);
871a268fbfeSAxel Dörfler 
8723b148e53SFrançois Revol 		// QEMU OpenHackware work-around
873d73ddac5SIngo Weinhold 		insert_physical_allocated_range(0x05800000, 0x06000000 - 0x05800000);
874d73ddac5SIngo Weinhold 		insert_virtual_allocated_range(0x05800000, 0x06000000 - 0x05800000);
8753b148e53SFrançois Revol 
876a268fbfeSAxel Dörfler 		physicalTable = table;
8775af32e75SAxel Dörfler 	}
8785af32e75SAxel Dörfler 
8795af32e75SAxel Dörfler 	if (exceptionHandlers == (void *)-1) {
880bdee97bcSAxel Dörfler 		// TODO: create mapping for the exception handlers
8812e3b6c53SAlexander von Gluck IV 		dprintf("Error: no mapping for the exception handlers!\n");
8825af32e75SAxel Dörfler 	}
8835af32e75SAxel Dörfler 
884a1bcf2c8SIngo Weinhold 	// Set the Open Firmware memory callback. From now on the Open Firmware
885a1bcf2c8SIngo Weinhold 	// will ask us for memory.
886a1bcf2c8SIngo Weinhold 	arch_set_callback();
887a1bcf2c8SIngo Weinhold 
8885af32e75SAxel Dörfler 	// set up new page table and turn on translation again
8895af32e75SAxel Dörfler 
8903b60bc6bSAlexander von Gluck IV 	for (uint32 i = 0; i < 16; i++) {
8915af32e75SAxel Dörfler 		ppc_set_segment_register((void *)(i * 0x10000000), sSegments[i]);
8925af32e75SAxel Dörfler 			// one segment describes 256 MB of memory
8935af32e75SAxel Dörfler 	}
8945af32e75SAxel Dörfler 
8955af32e75SAxel Dörfler 	ppc_set_page_table(physicalTable, tableSize);
8965af32e75SAxel Dörfler 	invalidate_tlb();
8975af32e75SAxel Dörfler 
898a268fbfeSAxel Dörfler 	if (!realMode) {
8995af32e75SAxel Dörfler 		// clear BATs
9005af32e75SAxel Dörfler 		reset_ibats();
9015af32e75SAxel Dörfler 		reset_dbats();
902bdee97bcSAxel Dörfler 		ppc_sync();
903bdee97bcSAxel Dörfler 		isync();
904a268fbfeSAxel Dörfler 	}
9055af32e75SAxel Dörfler 
9065af32e75SAxel Dörfler 	set_msr(MSR_MACHINE_CHECK_ENABLED | MSR_FP_AVAILABLE
907bdee97bcSAxel Dörfler 		| MSR_INST_ADDRESS_TRANSLATION | MSR_DATA_ADDRESS_TRANSLATION);
9085af32e75SAxel Dörfler 
9095af32e75SAxel Dörfler 	// set kernel args
9105af32e75SAxel Dörfler 
9112e3b6c53SAlexander von Gluck IV 	dprintf("virt_allocated: %" B_PRIu32 "\n",
9122e3b6c53SAlexander von Gluck IV 		gKernelArgs.num_virtual_allocated_ranges);
9132e3b6c53SAlexander von Gluck IV 	dprintf("phys_allocated: %" B_PRIu32 "\n",
9142e3b6c53SAlexander von Gluck IV 		gKernelArgs.num_physical_allocated_ranges);
9152e3b6c53SAlexander von Gluck IV 	dprintf("phys_memory: %" B_PRIu32 "\n",
9162e3b6c53SAlexander von Gluck IV 		gKernelArgs.num_physical_memory_ranges);
9175af32e75SAxel Dörfler 
9185af32e75SAxel Dörfler 	gKernelArgs.arch_args.page_table.start = (addr_t)sPageTable;
9195af32e75SAxel Dörfler 	gKernelArgs.arch_args.page_table.size = tableSize;
9205af32e75SAxel Dörfler 
9215af32e75SAxel Dörfler 	gKernelArgs.arch_args.exception_handlers.start = (addr_t)exceptionHandlers;
9225af32e75SAxel Dörfler 	gKernelArgs.arch_args.exception_handlers.size = B_PAGE_SIZE;
9235af32e75SAxel Dörfler 
9245af32e75SAxel Dörfler 	return B_OK;
9255af32e75SAxel Dörfler }
9265af32e75SAxel Dörfler 
927