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