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