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