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