]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/ppc_vm_init.c
xnu-1228.9.59.tar.gz
[apple/xnu.git] / osfmk / ppc / ppc_vm_init.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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>
1c79356b
A
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>
91447636 46#include <kern/thread.h>
0c530ab8 47#include <console/serial_protos.h>
1c79356b
A
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>
1c79356b
A
54#include <ppc/mem.h>
55#include <ppc/mappings.h>
56#include <ppc/exception.h>
55e303ae 57#include <ppc/lowglobals.h>
2d21ac55 58#include <ppc/serial_io.h>
1c79356b 59
1c79356b 60#include <mach-o/mach_header.h>
1c79356b 61
55e303ae
A
62extern const char version[];
63extern const char version_variant[];
1c79356b 64
55e303ae
A
65addr64_t hash_table_base; /* Hash table base */
66unsigned int hash_table_size; /* Hash table size */
91447636 67int hash_table_shift; /* "ht_shift" boot arg, used to scale hash_table_size */
55e303ae
A
68vm_offset_t taproot_addr; /* (BRINGUP) */
69unsigned int taproot_size; /* (BRINGUP) */
55e303ae 70extern int disableConsoleOutput;
1c79356b 71
55e303ae 72struct shadowBAT shadow_BAT;
d7e50217 73
3a60a9f5
A
74
75
55e303ae
A
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];
2d21ac55 90unsigned int pmap_mem_regions_count; /* Assume no non-contiguous memory regions */
1c79356b
A
91
92unsigned int avail_remaining = 0;
93vm_offset_t first_avail;
94vm_offset_t static_memory_end;
55e303ae 95addr64_t vm_last_addr = VM_MAX_KERNEL_ADDRESS; /* Highest kernel virtual address known to the VM system */
1c79356b 96
1c79356b
A
97extern struct mach_header _mh_execute_header;
98vm_offset_t sectTEXTB;
99int sectSizeTEXT;
100vm_offset_t sectDATAB;
101int sectSizeDATA;
1c79356b
A
102vm_offset_t sectLINKB;
103int sectSizeLINK;
104vm_offset_t sectKLDB;
105int sectSizeKLD;
55e303ae
A
106vm_offset_t sectPRELINKB;
107int sectSizePRELINK;
91447636
A
108vm_offset_t sectHIBB;
109int sectSizeHIB;
1c79356b
A
110
111vm_offset_t end, etext, edata;
1c79356b
A
112
113extern unsigned long exception_entry;
114extern unsigned long exception_end;
115
116
55e303ae 117void ppc_vm_init(uint64_t mem_limit, boot_args *args)
1c79356b 118{
91447636
A
119 unsigned int i, kmapsize, pvr;
120 vm_offset_t addr;
55e303ae
A
121 unsigned int *xtaproot, bank_shift;
122 uint64_t cbsize, xhid0;
1c79356b 123
de355530 124
55e303ae
A
125/*
126 * Invalidate all shadow BATs
1c79356b 127 */
1c79356b 128
55e303ae
A
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
1c79356b
A
152 * and copy valid entries into the pmap_mem_regions table, adding
153 * further calculated entries.
55e303ae
A
154 *
155 * boot_args version 1 has address instead of page numbers
156 * in the PhysicalDRAM banks, set bank_shift accordingly.
1c79356b
A
157 */
158
55e303ae
A
159 bank_shift = 0;
160 if (args->Version == kBootArgsVersion1) bank_shift = 12;
161
1c79356b 162 pmap_mem_regions_count = 0;
55e303ae
A
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 */
1c79356b 175
55e303ae 176 if(mem_limit == 0) continue; /* If we hit restriction, just keep counting */
1c79356b 177
55e303ae
A
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 */
1c79356b 186
de355530
A
187 /* Regions must be provided in ascending order */
188 assert ((pmap_mem_regions_count == 0) ||
55e303ae
A
189 pmap_mem_regions[pmap_mem_regions_count].mrStart >
190 pmap_mem_regions[pmap_mem_regions_count-1].mrStart);
1c79356b 191
55e303ae 192 pmap_mem_regions_count++; /* Count this region */
de355530 193 }
91447636 194
55e303ae
A
195 mem_size = (unsigned int)max_mem; /* Get size of memory */
196 if(max_mem > 0x0000000080000000ULL) mem_size = 0x80000000; /* Pin at 2 GB */
d7e50217 197
55e303ae
A
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 */
43866e37 201
d7e50217 202
55e303ae
A
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;
d7e50217 210
2d21ac55
A
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(
55e303ae 217 &_mh_execute_header, "__TEXT", &sectSizeTEXT);
2d21ac55 218 sectDATAB = (vm_offset_t)(uint32_t *)getsegdatafromheader(
55e303ae 219 &_mh_execute_header, "__DATA", &sectSizeDATA);
2d21ac55 220 sectLINKB = (vm_offset_t)(uint32_t *)getsegdatafromheader(
55e303ae 221 &_mh_execute_header, "__LINKEDIT", &sectSizeLINK);
2d21ac55 222 sectKLDB = (vm_offset_t)(uint32_t *)getsegdatafromheader(
55e303ae 223 &_mh_execute_header, "__KLD", &sectSizeKLD);
2d21ac55 224 sectHIBB = (vm_offset_t)(uint32_t *)getsegdatafromheader(
91447636 225 &_mh_execute_header, "__HIB", &sectSizeHIB);
2d21ac55 226 sectPRELINKB = (vm_offset_t)(uint32_t *)getsegdatafromheader(
55e303ae
A
227 &_mh_execute_header, "__PRELINK", &sectSizePRELINK);
228
229 etext = (vm_offset_t) sectTEXTB + sectSizeTEXT;
230 edata = (vm_offset_t) sectDATAB + sectSizeDATA;
91447636 231 end = round_page(getlastaddr()); /* Force end to next page */
1c79356b 232
91447636
A
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));
d7e50217 241
55e303ae 242 pmap_bootstrap(max_mem, &first_avail, kmapsize);
d7e50217 243
91447636 244 pmap_map(trunc_page(exception_entry), trunc_page(exception_entry),
0c530ab8 245 round_page(exception_end), VM_PROT_READ|VM_PROT_EXECUTE, VM_WIMG_USE_DEFAULT);
55e303ae 246
91447636 247 pmap_map(trunc_page(sectTEXTB), trunc_page(sectTEXTB),
0c530ab8 248 round_page(sectTEXTB+sectSizeTEXT), VM_PROT_READ|VM_PROT_EXECUTE, VM_WIMG_USE_DEFAULT);
55e303ae 249
91447636 250 pmap_map(trunc_page(sectDATAB), trunc_page(sectDATAB),
0c530ab8 251 round_page(sectDATAB+sectSizeDATA), VM_PROT_READ|VM_PROT_WRITE, VM_WIMG_USE_DEFAULT);
55e303ae
A
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
91447636
A
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),
0c530ab8 263 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
91447636
A
264 VM_WIMG_USE_DEFAULT, TRUE);
265
266 }
267
268 for (addr = trunc_page(sectKLDB);
269 addr < round_page(sectKLDB+sectSizeKLD);
1c79356b
A
270 addr += PAGE_SIZE) {
271
91447636 272 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, (ppnum_t)(addr>>12),
0c530ab8 273 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
9bccf70c 274 VM_WIMG_USE_DEFAULT, TRUE);
55e303ae 275
1c79356b
A
276 }
277
91447636
A
278 for (addr = trunc_page(sectLINKB);
279 addr < round_page(sectLINKB+sectSizeLINK);
1c79356b
A
280 addr += PAGE_SIZE) {
281
91447636
A
282 pmap_enter(kernel_pmap, (vm_map_offset_t)addr,
283 (ppnum_t)(addr>>12),
0c530ab8 284 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
9bccf70c 285 VM_WIMG_USE_DEFAULT, TRUE);
55e303ae 286
1c79356b
A
287 }
288
91447636
A
289 for (addr = trunc_page_32(sectHIBB);
290 addr < round_page_32(sectHIBB+sectSizeHIB);
55e303ae
A
291 addr += PAGE_SIZE) {
292
91447636 293 pmap_enter(kernel_pmap, (vm_map_offset_t)addr, (ppnum_t)(addr>>12),
0c530ab8 294 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
55e303ae
A
295 VM_WIMG_USE_DEFAULT, TRUE);
296
297 }
298
cf7d32b8 299 pmap_enter(kernel_pmap, (vm_map_offset_t)(uintptr_t)&sharedPage,
91447636 300 (ppnum_t)&sharedPage >> 12, /* Make sure the sharedPage is mapped */
55e303ae
A
301 VM_PROT_READ|VM_PROT_WRITE,
302 VM_WIMG_USE_DEFAULT, TRUE);
303
cf7d32b8 304 pmap_enter(kernel_pmap, (vm_map_offset_t)(uintptr_t)&lowGlo.lgVerCode,
91447636 305 (ppnum_t)&lowGlo.lgVerCode >> 12, /* Make sure the low memory globals are mapped */
55e303ae
A
306 VM_PROT_READ|VM_PROT_WRITE,
307 VM_WIMG_USE_DEFAULT, TRUE);
308
1c79356b
A
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 */
55e303ae 313
91447636 314 for(addr = trunc_page(end); addr < round_page(static_memory_end); addr += PAGE_SIZE) {
55e303ae 315
91447636 316 pmap_enter(kernel_pmap, (vm_map_address_t)addr, (ppnum_t)addr>>12,
0c530ab8 317 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
9bccf70c 318 VM_WIMG_USE_DEFAULT, TRUE);
d7e50217 319
de355530 320 }
91447636
A
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 */
55e303ae 327
91447636
A
328 lowGlo.lgUMWvaddr = USER_MEM_WINDOW_VADDR;
329 /* Initialize user memory window base address */
330 MapUserMemoryWindowInit(); /* Go initialize user memory window */
1c79356b 331
d52fe63f 332/*
55e303ae
A
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 *
d52fe63f 339 */
1c79356b 340
55e303ae 341 hw_start_trans(); /* Start translating */
3a60a9f5
A
342 PE_init_platform(TRUE, args); /* Initialize this right off the bat */
343
55e303ae
A
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 */
593a1d5f 357 if(PE_parse_boot_argn("serial", &serialmode, sizeof (serialmode))) { /* Do we want a serial keyboard and/or console? */
55e303ae
A
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);
91447636 370 if(getPerProc()->pf.Available & pf64Bit) { /* 64-bit processor? */
55e303ae
A
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);
2d21ac55 380 bcopy_nc(version, (void *)(taproot_addr + 16), strlen(version)); /* (BRINGUP) Pass it our kernel version */
55e303ae
A
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 */
1c79356b 388
55e303ae
A
389 /* setup console output */
390 PE_init_printf(FALSE);
1c79356b 391
1c79356b 392#if DEBUG
55e303ae
A
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 */
2d21ac55
A
398 __asm__ ("mfpvr %0" : "=r" (pvr));
399 printf("processor version register : %08X\n", pvr);
55e303ae 400
2d21ac55 401 kprintf("Args at %p\n", args);
55e303ae 402 for (i = 0; i < pmap_mem_regions_count; i++) {
2d21ac55 403 printf("DRAM at %08lX size %08lX\n",
55e303ae
A
404 args->PhysicalDRAM[i].base,
405 args->PhysicalDRAM[i].size);
406 }
407#endif /* DEBUG */
408
409#if DEBUG
410 kprintf("Mapped memory:\n");
91447636
A
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);
55e303ae 423
1c79356b 424#endif
55e303ae
A
425
426 return;
1c79356b
A
427}
428