1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * @APPLE_FREE_COPYRIGHT@ 33 */ 34 35#include <mach_debug.h> 36#include <mach_kdb.h> 37#include <mach_kdp.h> 38#include <debug.h> 39 40#include <mach/vm_types.h> 41#include <mach/vm_param.h> 42#include <mach/thread_status.h> 43#include <kern/misc_protos.h> 44#include <kern/assert.h> 45#include <kern/cpu_number.h> 46#include <kern/thread.h> 47#include <console/serial_protos.h> 48 49#include <ppc/proc_reg.h> 50#include <ppc/Firmware.h> 51#include <ppc/boot.h> 52#include <ppc/misc_protos.h> 53#include <ppc/pmap.h> 54#include <ppc/mem.h> 55#include <ppc/mappings.h> 56#include <ppc/exception.h> 57#include <ppc/lowglobals.h> 58#include <ppc/serial_io.h> 59 60#include <mach-o/mach_header.h> 61 62extern const char version[]; 63extern const char version_variant[]; 64 65addr64_t hash_table_base; /* Hash table base */ 66unsigned int hash_table_size; /* Hash table size */ 67int hash_table_shift; /* "ht_shift" boot arg, used to scale hash_table_size */ 68vm_offset_t taproot_addr; /* (BRINGUP) */ 69unsigned int taproot_size; /* (BRINGUP) */ 70extern int disableConsoleOutput; 71 72struct shadowBAT shadow_BAT; 73 74 75 76/* 77 * NOTE: mem_size is bogus on large memory machines. We will pin it to 0x80000000 if there is more than 2 GB 78 * This is left only for compatibility and max_mem should be used. 79 */ 80vm_offset_t mem_size; /* Size of actual physical memory present 81 minus any performance buffer and possibly limited 82 by mem_limit in bytes */ 83uint64_t mem_actual; /* The "One True" physical memory size 84 actually, it's the highest physical address + 1 */ 85uint64_t max_mem; /* Size of physical memory (bytes), adjusted by maxmem */ 86uint64_t sane_size; /* Memory size to use for defaults calculations */ 87 88 89mem_region_t pmap_mem_regions[PMAP_MEM_REGION_MAX + 1]; 90unsigned int pmap_mem_regions_count; /* Assume no non-contiguous memory regions */ 91 92unsigned int avail_remaining = 0; 93vm_offset_t first_avail; 94vm_offset_t static_memory_end; 95addr64_t vm_last_addr = VM_MAX_KERNEL_ADDRESS; /* Highest kernel virtual address known to the VM system */ 96 97extern struct mach_header _mh_execute_header; 98vm_offset_t sectTEXTB; 99int sectSizeTEXT; 100vm_offset_t sectDATAB; 101int sectSizeDATA; 102vm_offset_t sectLINKB; 103int sectSizeLINK; 104vm_offset_t sectKLDB; 105int sectSizeKLD; 106vm_offset_t sectPRELINKB; 107int sectSizePRELINK; 108vm_offset_t sectHIBB; 109int sectSizeHIB; 110 111vm_offset_t end, etext, edata; 112 113extern unsigned long exception_entry; 114extern unsigned long exception_end; 115 116 117void ppc_vm_init(uint64_t mem_limit, boot_args *args) 118{ 119 unsigned int i, kmapsize, pvr; 120 vm_offset_t addr; 121 unsigned int *xtaproot, bank_shift; 122 uint64_t cbsize, xhid0; 123 124 125/* 126 * Invalidate all shadow BATs 127 */ 128 129 /* Initialize shadow IBATs */ 130 shadow_BAT.IBATs[0].upper=BAT_INVALID; 131 shadow_BAT.IBATs[0].lower=BAT_INVALID; 132 shadow_BAT.IBATs[1].upper=BAT_INVALID; 133 shadow_BAT.IBATs[1].lower=BAT_INVALID; 134 shadow_BAT.IBATs[2].upper=BAT_INVALID; 135 shadow_BAT.IBATs[2].lower=BAT_INVALID; 136 shadow_BAT.IBATs[3].upper=BAT_INVALID; 137 shadow_BAT.IBATs[3].lower=BAT_INVALID; 138 139 /* Initialize shadow DBATs */ 140 shadow_BAT.DBATs[0].upper=BAT_INVALID; 141 shadow_BAT.DBATs[0].lower=BAT_INVALID; 142 shadow_BAT.DBATs[1].upper=BAT_INVALID; 143 shadow_BAT.DBATs[1].lower=BAT_INVALID; 144 shadow_BAT.DBATs[2].upper=BAT_INVALID; 145 shadow_BAT.DBATs[2].lower=BAT_INVALID; 146 shadow_BAT.DBATs[3].upper=BAT_INVALID; 147 shadow_BAT.DBATs[3].lower=BAT_INVALID; 148 149 150 /* 151 * Go through the list of memory regions passed in via the boot_args 152 * and copy valid entries into the pmap_mem_regions table, adding 153 * further calculated entries. 154 * 155 * boot_args version 1 has address instead of page numbers 156 * in the PhysicalDRAM banks, set bank_shift accordingly. 157 */ 158 159 bank_shift = 0; 160 if (args->Version == kBootArgsVersion1) bank_shift = 12; 161 162 pmap_mem_regions_count = 0; 163 max_mem = 0; /* Will use to total memory found so far */ 164 mem_actual = 0; /* Actual size of memory */ 165 166 if (mem_limit == 0) mem_limit = 0xFFFFFFFFFFFFFFFFULL; /* If there is no set limit, use all */ 167 168 for (i = 0; i < kMaxDRAMBanks; i++) { /* Look at all of the banks */ 169 170 cbsize = (uint64_t)args->PhysicalDRAM[i].size << (12 - bank_shift); /* Remember current size */ 171 172 if (!cbsize) continue; /* Skip if the bank is empty */ 173 174 mem_actual = mem_actual + cbsize; /* Get true memory size */ 175 176 if(mem_limit == 0) continue; /* If we hit restriction, just keep counting */ 177 178 if (cbsize > mem_limit) cbsize = mem_limit; /* Trim to max allowed */ 179 max_mem += cbsize; /* Total up what we have so far */ 180 mem_limit = mem_limit - cbsize; /* Calculate amount left to do */ 181 182 pmap_mem_regions[pmap_mem_regions_count].mrStart = args->PhysicalDRAM[i].base >> bank_shift; /* Set the start of the bank */ 183 pmap_mem_regions[pmap_mem_regions_count].mrAStart = pmap_mem_regions[pmap_mem_regions_count].mrStart; /* Set the start of allocatable area */ 184 pmap_mem_regions[pmap_mem_regions_count].mrEnd = ((uint64_t)args->PhysicalDRAM[i].base >> bank_shift) + (cbsize >> 12) - 1; /* Set the end address of bank */ 185 pmap_mem_regions[pmap_mem_regions_count].mrAEnd = pmap_mem_regions[pmap_mem_regions_count].mrEnd; /* Set the end address of allocatable area */ 186 187 /* Regions must be provided in ascending order */ 188 assert ((pmap_mem_regions_count == 0) || 189 pmap_mem_regions[pmap_mem_regions_count].mrStart > 190 pmap_mem_regions[pmap_mem_regions_count-1].mrStart); 191 192 pmap_mem_regions_count++; /* Count this region */ 193 } 194 195 mem_size = (unsigned int)max_mem; /* Get size of memory */ 196 if(max_mem > 0x0000000080000000ULL) mem_size = 0x80000000; /* Pin at 2 GB */ 197 198 sane_size = max_mem; /* Calculate a sane value to use for init */ 199 if(sane_size > (addr64_t)(VM_MAX_KERNEL_ADDRESS + 1)) 200 sane_size = (addr64_t)(VM_MAX_KERNEL_ADDRESS + 1); /* If flush with ram, use addressible portion */ 201 202 203/* 204 * Initialize the pmap system, using space above `first_avail' 205 * for the necessary data structures. 206 * NOTE : assume that we'll have enough space mapped in already 207 */ 208 209 first_avail = static_memory_end; 210 211 /* 212 * Now retrieve addresses for end, edata, and etext 213 * from MACH-O headers for the currently running 32 bit kernel. 214 */ 215 /* XXX fix double casts for 64 bit kernel */ 216 sectTEXTB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 217 &_mh_execute_header, "__TEXT", §SizeTEXT); 218 sectDATAB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 219 &_mh_execute_header, "__DATA", §SizeDATA); 220 sectLINKB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 221 &_mh_execute_header, "__LINKEDIT", §SizeLINK); 222 sectKLDB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 223 &_mh_execute_header, "__KLD", §SizeKLD); 224 sectHIBB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 225 &_mh_execute_header, "__HIB", §SizeHIB); 226 sectPRELINKB = (vm_offset_t)(uint32_t *)getsegdatafromheader( 227 &_mh_execute_header, "__PRELINK", §SizePRELINK); 228 229 etext = (vm_offset_t) sectTEXTB + sectSizeTEXT; 230 edata = (vm_offset_t) sectDATAB + sectSizeDATA; 231 end = round_page(getlastaddr()); /* Force end to next page */ 232 233 kmapsize = (round_page(exception_end) - trunc_page(exception_entry)) + /* Get size we will map later */ 234 (round_page(sectTEXTB+sectSizeTEXT) - trunc_page(sectTEXTB)) + 235 (round_page(sectDATAB+sectSizeDATA) - trunc_page(sectDATAB)) + 236 (round_page(sectLINKB+sectSizeLINK) - trunc_page(sectLINKB)) + 237 (round_page(sectKLDB+sectSizeKLD) - trunc_page(sectKLDB)) + 238 (round_page_32(sectKLDB+sectSizeHIB) - trunc_page_32(sectHIBB)) + 239 (round_page(sectPRELINKB+sectSizePRELINK) - trunc_page(sectPRELINKB)) + 240 (round_page(static_memory_end) - trunc_page(end)); 241 242 pmap_bootstrap(max_mem, &first_avail, kmapsize); 243 244 pmap_map(trunc_page(exception_entry), trunc_page(exception_entry), 245 round_page(exception_end), VM_PROT_READ|VM_PROT_EXECUTE, VM_WIMG_USE_DEFAULT); 246 247 pmap_map(trunc_page(sectTEXTB), trunc_page(sectTEXTB), 248 round_page(sectTEXTB+sectSizeTEXT), VM_PROT_READ|VM_PROT_EXECUTE, VM_WIMG_USE_DEFAULT); 249 250 pmap_map(trunc_page(sectDATAB), trunc_page(sectDATAB), 251 round_page(sectDATAB+sectSizeDATA), VM_PROT_READ|VM_PROT_WRITE, VM_WIMG_USE_DEFAULT); 252 253/* The KLD and LINKEDIT segments are unloaded in toto after boot completes, 254* but via ml_static_mfree(), through IODTFreeLoaderInfo(). Hence, we have 255* to map both segments page-by-page. 256*/ 257 258 for (addr = trunc_page(sectPRELINKB); 259 addr < round_page(sectPRELINKB+sectSizePRELINK); 260 addr += PAGE_SIZE) { 261 262 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, (ppnum_t)(addr>>12), 263 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, 264 VM_WIMG_USE_DEFAULT, TRUE); 265 266 } 267 268 for (addr = trunc_page(sectKLDB); 269 addr < round_page(sectKLDB+sectSizeKLD); 270 addr += PAGE_SIZE) { 271 272 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, (ppnum_t)(addr>>12), 273 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, 274 VM_WIMG_USE_DEFAULT, TRUE); 275 276 } 277 278 for (addr = trunc_page(sectLINKB); 279 addr < round_page(sectLINKB+sectSizeLINK); 280 addr += PAGE_SIZE) { 281 282 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, 283 (ppnum_t)(addr>>12), 284 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, 285 VM_WIMG_USE_DEFAULT, TRUE); 286 287 } 288 289 for (addr = trunc_page_32(sectHIBB); 290 addr < round_page_32(sectHIBB+sectSizeHIB); 291 addr += PAGE_SIZE) { 292 293 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, (ppnum_t)(addr>>12), 294 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, 295 VM_WIMG_USE_DEFAULT, TRUE); 296 297 } 298 299 pmap_enter(kernel_pmap, (vm_map_offset_t)(uintptr_t)&sharedPage, 300 (ppnum_t)&sharedPage >> 12, /* Make sure the sharedPage is mapped */ 301 VM_PROT_READ|VM_PROT_WRITE, 302 VM_WIMG_USE_DEFAULT, TRUE); 303 304 pmap_enter(kernel_pmap, (vm_map_offset_t)(uintptr_t)&lowGlo.lgVerCode, 305 (ppnum_t)&lowGlo.lgVerCode >> 12, /* Make sure the low memory globals are mapped */ 306 VM_PROT_READ|VM_PROT_WRITE, 307 VM_WIMG_USE_DEFAULT, TRUE); 308 309/* 310 * We need to map the remainder page-by-page because some of this will 311 * be released later, but not all. Ergo, no block mapping here 312 */ 313 314 for(addr = trunc_page(end); addr < round_page(static_memory_end); addr += PAGE_SIZE) { 315 316 pmap_enter(kernel_pmap, (vm_map_address_t)addr, (ppnum_t)addr>>12, 317 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, 318 VM_WIMG_USE_DEFAULT, TRUE); 319 320 } 321 322/* 323 * Here we map a window into the kernel address space that will be used to 324 * access a slice of a user address space. Clients for this service include 325 * copyin/out and copypv. 326 */ 327 328 lowGlo.lgUMWvaddr = USER_MEM_WINDOW_VADDR; 329 /* Initialize user memory window base address */ 330 MapUserMemoryWindowInit(); /* Go initialize user memory window */ 331 332/* 333 * At this point, there is enough mapped memory and all hw mapping structures are 334 * allocated and initialized. Here is where we turn on translation for the 335 * VERY first time.... 336 * 337 * NOTE: Here is where our very first interruption will happen. 338 * 339 */ 340 341 hw_start_trans(); /* Start translating */ 342 PE_init_platform(TRUE, args); /* Initialize this right off the bat */ 343 344 345#if 0 346 GratefulDebInit((bootBumbleC *)&(args->Video)); /* Initialize the GratefulDeb debugger */ 347#endif 348 349 350 printf_init(); /* Init this in case we need debugger */ 351 panic_init(); /* Init this in case we need debugger */ 352 PE_init_kprintf(TRUE); /* Note on PPC we only call this after VM is set up */ 353 354 kprintf("kprintf initialized\n"); 355 356 serialmode = 0; /* Assume normal keyboard and console */ 357 if(PE_parse_boot_argn("serial", &serialmode, sizeof (serialmode))) { /* Do we want a serial keyboard and/or console? */ 358 kprintf("Serial mode specified: %08X\n", serialmode); 359 } 360 if(serialmode & 1) { /* Start serial if requested */ 361 (void)switch_to_serial_console(); /* Switch into serial mode */ 362 disableConsoleOutput = FALSE; /* Allow printfs to happen */ 363 } 364 365 kprintf("max_mem: %ld M\n", (unsigned long)(max_mem >> 20)); 366 kprintf("version_variant = %s\n", version_variant); 367 kprintf("version = %s\n\n", version); 368 __asm__ ("mfpvr %0" : "=r" (pvr)); 369 kprintf("proc version = %08x\n", pvr); 370 if(getPerProc()->pf.Available & pf64Bit) { /* 64-bit processor? */ 371 xhid0 = hid0get64(); /* Get the hid0 */ 372 if(xhid0 & (1ULL << (63 - 19))) kprintf("Time base is externally clocked\n"); 373 else kprintf("Time base is internally clocked\n"); 374 } 375 376 377 taproot_size = PE_init_taproot(&taproot_addr); /* (BRINGUP) See if there is a taproot */ 378 if(taproot_size) { /* (BRINGUP) */ 379 kprintf("TapRoot card configured to use vaddr = %08X, size = %08X\n", taproot_addr, taproot_size); 380 bcopy_nc(version, (void *)(taproot_addr + 16), strlen(version)); /* (BRINGUP) Pass it our kernel version */ 381 __asm__ volatile("eieio"); /* (BRINGUP) */ 382 xtaproot = (unsigned int *)taproot_addr; /* (BRINGUP) */ 383 xtaproot[0] = 1; /* (BRINGUP) */ 384 __asm__ volatile("eieio"); /* (BRINGUP) */ 385 } 386 387 PE_create_console(); /* create the console for verbose or pretty mode */ 388 389 /* setup console output */ 390 PE_init_printf(FALSE); 391 392#if DEBUG 393 printf("\n\n\nThis program was compiled using gcc %d.%d for powerpc\n", 394 __GNUC__,__GNUC_MINOR__); 395 396 397 /* Processor version information */ 398 __asm__ ("mfpvr %0" : "=r" (pvr)); 399 printf("processor version register : %08X\n", pvr); 400 401 kprintf("Args at %p\n", args); 402 for (i = 0; i < pmap_mem_regions_count; i++) { 403 printf("DRAM at %08lX size %08lX\n", 404 args->PhysicalDRAM[i].base, 405 args->PhysicalDRAM[i].size); 406 } 407#endif /* DEBUG */ 408 409#if DEBUG 410 kprintf("Mapped memory:\n"); 411 kprintf(" exception vector: %08X, %08X - %08X\n", trunc_page(exception_entry), 412 trunc_page(exception_entry), round_page(exception_end)); 413 kprintf(" sectTEXTB: %08X, %08X - %08X\n", trunc_page(sectTEXTB), 414 trunc_page(sectTEXTB), round_page(sectTEXTB+sectSizeTEXT)); 415 kprintf(" sectDATAB: %08X, %08X - %08X\n", trunc_page(sectDATAB), 416 trunc_page(sectDATAB), round_page(sectDATAB+sectSizeDATA)); 417 kprintf(" sectLINKB: %08X, %08X - %08X\n", trunc_page(sectLINKB), 418 trunc_page(sectLINKB), round_page(sectLINKB+sectSizeLINK)); 419 kprintf(" sectKLDB: %08X, %08X - %08X\n", trunc_page(sectKLDB), 420 trunc_page(sectKLDB), round_page(sectKLDB+sectSizeKLD)); 421 kprintf(" end: %08X, %08X - %08X\n", trunc_page(end), 422 trunc_page(end), static_memory_end); 423 424#endif 425 426 return; 427} 428 429