]>
Commit | Line | Data |
---|---|---|
55e303ae A |
1 | /* |
2 | * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. | |
3 | * | |
6601e61a | 4 | * @APPLE_LICENSE_HEADER_START@ |
55e303ae | 5 | * |
6601e61a 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. | |
8f6c56a5 | 11 | * |
6601e61a 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 | |
8f6c56a5 A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
6601e61a 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. | |
8f6c56a5 | 19 | * |
6601e61a | 20 | * @APPLE_LICENSE_HEADER_END@ |
55e303ae A |
21 | */ |
22 | /* | |
23 | * @OSF_COPYRIGHT@ | |
24 | */ | |
25 | /* | |
26 | * Mach Operating System | |
27 | * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University | |
28 | * All Rights Reserved. | |
29 | * | |
30 | * Permission to use, copy, modify and distribute this software and its | |
31 | * documentation is hereby granted, provided that both the copyright | |
32 | * notice and this permission notice appear in all copies of the | |
33 | * software, derivative works or modified versions, and any portions | |
34 | * thereof, and that both notices appear in supporting documentation. | |
35 | * | |
36 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
37 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
38 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
39 | * | |
40 | * Carnegie Mellon requests users of this software to return to | |
41 | * | |
42 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
43 | * School of Computer Science | |
44 | * Carnegie Mellon University | |
45 | * Pittsburgh PA 15213-3890 | |
46 | * | |
47 | * any improvements or extensions that they make and grant Carnegie Mellon | |
48 | * the rights to redistribute these changes. | |
49 | */ | |
50 | ||
55e303ae A |
51 | #include <platforms.h> |
52 | #include <mach_kdb.h> | |
6601e61a | 53 | #include <himem.h> |
55e303ae A |
54 | |
55 | #include <mach/i386/vm_param.h> | |
56 | ||
57 | #include <string.h> | |
58 | #include <mach/vm_param.h> | |
59 | #include <mach/vm_prot.h> | |
60 | #include <mach/machine.h> | |
61 | #include <mach/time_value.h> | |
55e303ae A |
62 | #include <kern/spl.h> |
63 | #include <kern/assert.h> | |
64 | #include <kern/debug.h> | |
65 | #include <kern/misc_protos.h> | |
66 | #include <kern/cpu_data.h> | |
67 | #include <kern/processor.h> | |
68 | #include <vm/vm_page.h> | |
69 | #include <vm/pmap.h> | |
70 | #include <vm/vm_kern.h> | |
71 | #include <i386/pmap.h> | |
72 | #include <i386/ipl.h> | |
6601e61a | 73 | #include <i386/pio.h> |
55e303ae A |
74 | #include <i386/misc_protos.h> |
75 | #include <i386/mp_slave_boot.h> | |
91447636 | 76 | #include <i386/cpuid.h> |
6601e61a | 77 | #ifdef __MACHO__ |
55e303ae | 78 | #include <mach/thread_status.h> |
6601e61a | 79 | #endif |
55e303ae A |
80 | |
81 | vm_size_t mem_size = 0; | |
55e303ae A |
82 | vm_offset_t first_avail = 0;/* first after page tables */ |
83 | vm_offset_t last_addr; | |
84 | ||
6601e61a A |
85 | uint64_t max_mem; |
86 | uint64_t sane_size = 0; /* we are going to use the booter memory | |
87 | table info to construct this */ | |
4452a7af | 88 | |
6601e61a | 89 | pmap_paddr_t avail_start, avail_end; |
55e303ae | 90 | vm_offset_t virtual_avail, virtual_end; |
6601e61a | 91 | pmap_paddr_t avail_remaining; |
91447636 | 92 | vm_offset_t static_memory_end = 0; |
55e303ae | 93 | |
6601e61a A |
94 | #ifndef __MACHO__ |
95 | extern char edata, end; | |
96 | #endif | |
97 | ||
98 | #ifdef __MACHO__ | |
55e303ae A |
99 | #include <mach-o/loader.h> |
100 | vm_offset_t edata, etext, end; | |
101 | ||
91447636 A |
102 | /* |
103 | * _mh_execute_header is the mach_header for the currently executing | |
104 | * 32 bit kernel | |
105 | */ | |
55e303ae A |
106 | extern struct mach_header _mh_execute_header; |
107 | void *sectTEXTB; int sectSizeTEXT; | |
108 | void *sectDATAB; int sectSizeDATA; | |
109 | void *sectOBJCB; int sectSizeOBJC; | |
110 | void *sectLINKB; int sectSizeLINK; | |
111 | void *sectPRELINKB; int sectSizePRELINK; | |
91447636 | 112 | void *sectHIBB; int sectSizeHIB; |
55e303ae | 113 | |
91447636 | 114 | extern void *getsegdatafromheader(struct mach_header *, const char *, int *); |
6601e61a | 115 | #endif |
55e303ae A |
116 | |
117 | /* | |
118 | * Basic VM initialization. | |
119 | */ | |
120 | void | |
6601e61a | 121 | i386_vm_init(unsigned int maxmem, KernelBootArgs_t *args) |
55e303ae | 122 | { |
91447636 | 123 | pmap_memory_region_t *pmptr; |
6601e61a | 124 | MemoryRange *mptr; |
91447636 A |
125 | ppnum_t fap; |
126 | unsigned int i; | |
6601e61a | 127 | ppnum_t maxpg = (maxmem >> I386_PGSHIFT); |
55e303ae | 128 | |
6601e61a A |
129 | #ifdef __MACHO__ |
130 | /* Now retrieve addresses for end, edata, and etext | |
55e303ae A |
131 | * from MACH-O headers. |
132 | */ | |
133 | ||
134 | sectTEXTB = (void *) getsegdatafromheader( | |
135 | &_mh_execute_header, "__TEXT", §SizeTEXT); | |
136 | sectDATAB = (void *) getsegdatafromheader( | |
137 | &_mh_execute_header, "__DATA", §SizeDATA); | |
138 | sectOBJCB = (void *) getsegdatafromheader( | |
139 | &_mh_execute_header, "__OBJC", §SizeOBJC); | |
140 | sectLINKB = (void *) getsegdatafromheader( | |
141 | &_mh_execute_header, "__LINKEDIT", §SizeLINK); | |
91447636 A |
142 | sectHIBB = (void *)getsegdatafromheader( |
143 | &_mh_execute_header, "__HIB", §SizeHIB); | |
55e303ae A |
144 | sectPRELINKB = (void *) getsegdatafromheader( |
145 | &_mh_execute_header, "__PRELINK", §SizePRELINK); | |
146 | ||
147 | etext = (vm_offset_t) sectTEXTB + sectSizeTEXT; | |
148 | edata = (vm_offset_t) sectDATAB + sectSizeDATA; | |
6601e61a A |
149 | #endif |
150 | #ifndef __MACHO__ | |
151 | /* | |
152 | * Zero the BSS. | |
153 | */ | |
154 | ||
155 | bzero((char *)&edata,(unsigned)(&end - &edata)); | |
156 | #endif | |
157 | ||
158 | /* | |
159 | * Initialize the pic prior to any possible call to an spl. | |
160 | */ | |
55e303ae | 161 | |
6601e61a | 162 | set_cpu_model(); |
55e303ae A |
163 | vm_set_page_size(); |
164 | ||
55e303ae A |
165 | /* |
166 | * Compute the memory size. | |
167 | */ | |
168 | ||
91447636 A |
169 | avail_remaining = 0; |
170 | avail_end = 0; | |
171 | pmptr = pmap_memory_regions; | |
172 | pmap_memory_region_count = pmap_memory_region_current = 0; | |
173 | fap = (ppnum_t) i386_btop(first_avail); | |
6601e61a | 174 | mptr = args->memoryMap; |
91447636 | 175 | |
6601e61a | 176 | #ifdef PAE |
21362eb3 | 177 | #define FOURGIG 0x0000000100000000ULL |
6601e61a A |
178 | for (i=0; i < args->memoryMapCount; i++,mptr++) { |
179 | ppnum_t base, top; | |
180 | ||
181 | base = (ppnum_t) (mptr->base >> I386_PGSHIFT); | |
182 | top = (ppnum_t) ((mptr->base + mptr->length) >> I386_PGSHIFT) - 1; | |
183 | ||
184 | if (maxmem) { | |
185 | if (base >= maxpg) break; | |
186 | top = (top > maxpg)? maxpg : top; | |
187 | } | |
188 | ||
189 | if (kMemoryRangeUsable != mptr->type) continue; | |
190 | sane_size += (uint64_t)(mptr->length); | |
191 | #ifdef DEVICES_HANDLE_64BIT_IO /* XXX enable else clause when I/O to high memory works */ | |
192 | if (top < fap) { | |
193 | /* entire range below first_avail */ | |
194 | continue; | |
195 | } else if (mptr->base >= FOURGIG) { | |
196 | /* entire range above 4GB (pre PAE) */ | |
197 | continue; | |
198 | } else if ( (base < fap) && | |
199 | (top > fap)) { | |
200 | /* spans first_avail */ | |
201 | /* put mem below first avail in table but | |
202 | mark already allocated */ | |
203 | pmptr->base = base; | |
204 | pmptr->alloc = pmptr->end = (fap - 1); | |
205 | pmptr->type = mptr->type; | |
206 | /* we bump these here inline so the accounting below works | |
207 | correctly */ | |
208 | pmptr++; | |
209 | pmap_memory_region_count++; | |
210 | pmptr->alloc = pmptr->base = fap; | |
211 | pmptr->type = mptr->type; | |
212 | pmptr->end = top; | |
213 | } else if ( (mptr->base < FOURGIG) && | |
214 | ((mptr->base+mptr->length) > FOURGIG) ) { | |
215 | /* spans across 4GB (pre PAE) */ | |
216 | pmptr->alloc = pmptr->base = base; | |
217 | pmptr->type = mptr->type; | |
218 | pmptr->end = (FOURGIG >> I386_PGSHIFT) - 1; | |
219 | } else { | |
220 | /* entire range useable */ | |
221 | pmptr->alloc = pmptr->base = base; | |
222 | pmptr->type = mptr->type; | |
223 | pmptr->end = top; | |
224 | } | |
225 | #else | |
226 | if (top < fap) { | |
227 | /* entire range below first_avail */ | |
228 | continue; | |
229 | } else if ( (base < fap) && | |
230 | (top > fap)) { | |
231 | /* spans first_avail */ | |
232 | pmptr->alloc = pmptr->base = fap; | |
233 | pmptr->type = mptr->type; | |
234 | pmptr->end = top; | |
235 | } else { | |
236 | /* entire range useable */ | |
237 | pmptr->alloc = pmptr->base = base; | |
238 | pmptr->type = mptr->type; | |
239 | pmptr->end = top; | |
240 | } | |
241 | #endif | |
242 | if (i386_ptob(pmptr->end) > avail_end ) { | |
243 | avail_end = i386_ptob(pmptr->end); | |
244 | } | |
245 | avail_remaining += (pmptr->end - pmptr->base); | |
246 | pmap_memory_region_count++; | |
247 | pmptr++; | |
21362eb3 | 248 | } |
6601e61a A |
249 | #else /* non PAE follows */ |
250 | #define FOURGIG 0x0000000100000000ULL | |
251 | for (i=0; i < args->memoryMapCount; i++,mptr++) { | |
252 | ppnum_t base, top; | |
253 | ||
254 | base = (ppnum_t) (mptr->base >> I386_PGSHIFT); | |
255 | top = (ppnum_t) ((mptr->base + mptr->length) >> I386_PGSHIFT) - 1; | |
256 | ||
257 | if (maxmem) { | |
258 | if (base >= maxpg) break; | |
259 | top = (top > maxpg)? maxpg : top; | |
260 | } | |
261 | ||
262 | if (kMemoryRangeUsable != mptr->type) continue; | |
263 | ||
264 | // save other regions | |
265 | if (kMemoryRangeNVS == mptr->type) { | |
266 | // Mark this as a memory range (for hibernation), | |
267 | // but don't count as usable memory | |
268 | pmptr->base = base; | |
269 | pmptr->end = ((mptr->base + mptr->length + I386_PGBYTES - 1) >> I386_PGSHIFT) - 1; | |
270 | pmptr->alloc = pmptr->end; | |
271 | pmptr->type = mptr->type; | |
272 | kprintf("NVS region: 0x%x ->0x%x\n", pmptr->base, pmptr->end); | |
273 | } else if (kMemoryRangeUsable != mptr->type) { | |
274 | continue; | |
275 | } else { | |
276 | // Usable memory region | |
277 | sane_size += (uint64_t)(mptr->length); | |
278 | if (top < fap) { | |
279 | /* entire range below first_avail */ | |
280 | /* salvage some low memory pages */ | |
281 | /* we use some very low memory at startup */ | |
282 | /* mark as already allocated here */ | |
283 | pmptr->base = 0x18; /* PAE and HIB use below this */ | |
284 | pmptr->alloc = pmptr->end = top; /* mark as already mapped */ | |
285 | pmptr->type = mptr->type; | |
286 | } else if (mptr->base >= FOURGIG) { | |
287 | /* entire range above 4GB (pre PAE) */ | |
288 | continue; | |
289 | } else if ( (base < fap) && | |
290 | (top > fap)) { | |
291 | /* spans first_avail */ | |
292 | /* put mem below first avail in table but | |
293 | mark already allocated */ | |
294 | pmptr->base = base; | |
295 | pmptr->alloc = pmptr->end = (fap - 1); | |
296 | pmptr->type = mptr->type; | |
297 | /* we bump these here inline so the accounting below works | |
298 | correctly */ | |
299 | pmptr++; | |
300 | pmap_memory_region_count++; | |
301 | pmptr->alloc = pmptr->base = fap; | |
302 | pmptr->type = mptr->type; | |
303 | pmptr->end = top; | |
304 | } else if ( (mptr->base < FOURGIG) && | |
305 | ((mptr->base+mptr->length) > FOURGIG) ) { | |
306 | /* spans across 4GB (pre PAE) */ | |
307 | pmptr->alloc = pmptr->base = base; | |
308 | pmptr->type = mptr->type; | |
309 | pmptr->end = (FOURGIG >> I386_PGSHIFT) - 1; | |
310 | } else { | |
311 | /* entire range useable */ | |
312 | pmptr->alloc = pmptr->base = base; | |
313 | pmptr->type = mptr->type; | |
314 | pmptr->end = top; | |
315 | } | |
316 | ||
317 | if (i386_ptob(pmptr->end) > avail_end ) { | |
318 | avail_end = i386_ptob(pmptr->end); | |
319 | } | |
320 | ||
321 | avail_remaining += (pmptr->end - pmptr->base); | |
322 | pmap_memory_region_count++; | |
323 | pmptr++; | |
324 | } | |
325 | } | |
326 | #endif | |
55e303ae | 327 | |
91447636 | 328 | #ifdef PRINT_PMAP_MEMORY_TABLE |
6601e61a A |
329 | { |
330 | unsigned int j; | |
331 | pmap_memory_region_t *p = pmap_memory_regions; | |
332 | for (j=0;j<pmap_memory_region_count;j++, p++) { | |
333 | kprintf("%d base 0x%x alloc 0x%x top 0x%x\n",j, | |
334 | p->base, p->alloc, p->end); | |
335 | } | |
336 | } | |
91447636 | 337 | #endif |
55e303ae | 338 | |
91447636 | 339 | avail_start = first_avail; |
4452a7af | 340 | |
6601e61a A |
341 | if (maxmem) { /* if user set maxmem try to use it */ |
342 | uint64_t tmp = (uint64_t)maxmem; | |
343 | /* can't set below first_avail or above actual memory */ | |
344 | if ( (maxmem > first_avail) && (tmp < sane_size) ) { | |
345 | sane_size = tmp; | |
346 | avail_end = maxmem; | |
347 | } | |
55e303ae | 348 | } |
6601e61a A |
349 | // round up to a megabyte - mostly accounting for the |
350 | // low mem madness | |
351 | sane_size += ( 0x100000ULL - 1); | |
352 | sane_size &= ~0xFFFFFULL; | |
353 | ||
354 | #ifndef PAE | |
355 | if (sane_size < FOURGIG) | |
356 | mem_size = (unsigned long) sane_size; | |
4452a7af | 357 | else |
6601e61a A |
358 | mem_size = (unsigned long) (FOURGIG >> 1); |
359 | #else | |
360 | mem_size = (unsigned long) sane_size; | |
361 | #endif | |
4452a7af | 362 | |
6601e61a | 363 | max_mem = sane_size; |
5d5c5d0d | 364 | |
6601e61a A |
365 | /* now make sane size sane */ |
366 | #define MIN(a,b) (((a)<(b))?(a):(b)) | |
367 | #define MEG (1024*1024) | |
368 | sane_size = MIN(sane_size, 256*MEG); | |
4452a7af | 369 | |
6601e61a A |
370 | kprintf("Physical memory %d MB\n", |
371 | mem_size/MEG); | |
89b3af67 | 372 | |
4452a7af A |
373 | /* |
374 | * Initialize kernel physical map. | |
375 | * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS. | |
376 | */ | |
6601e61a | 377 | pmap_bootstrap(0); |
21362eb3 | 378 | |
4452a7af | 379 | |
6601e61a A |
380 | } |
381 | ||
55e303ae A |
382 | unsigned int |
383 | pmap_free_pages(void) | |
384 | { | |
385 | return avail_remaining; | |
386 | } | |
387 | ||
388 | boolean_t | |
389 | pmap_next_page( | |
390 | ppnum_t *pn) | |
391 | { | |
6601e61a A |
392 | |
393 | while (pmap_memory_region_current < pmap_memory_region_count) { | |
394 | if (pmap_memory_regions[pmap_memory_region_current].alloc == | |
395 | pmap_memory_regions[pmap_memory_region_current].end) { | |
396 | pmap_memory_region_current++; | |
397 | continue; | |
398 | } | |
399 | *pn = pmap_memory_regions[pmap_memory_region_current].alloc++; | |
400 | avail_remaining--; | |
401 | ||
402 | return TRUE; | |
91447636 A |
403 | } |
404 | return FALSE; | |
55e303ae A |
405 | } |
406 | ||
407 | boolean_t | |
408 | pmap_valid_page( | |
91447636 | 409 | ppnum_t pn) |
55e303ae | 410 | { |
6601e61a A |
411 | unsigned int i; |
412 | pmap_memory_region_t *pmptr = pmap_memory_regions; | |
413 | ||
414 | assert(pn); | |
415 | for (i=0; i<pmap_memory_region_count; i++, pmptr++) { | |
416 | if ( (pn >= pmptr->base) && (pn <= pmptr->end) ) { | |
417 | if (pmptr->type == kMemoryRangeUsable) | |
418 | return TRUE; | |
419 | else | |
420 | return FALSE; | |
421 | } | |
422 | } | |
423 | return FALSE; | |
55e303ae | 424 | } |