2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
57 #include <platforms.h>
61 #include <mach/i386/vm_param.h>
64 #include <mach/vm_param.h>
65 #include <mach/vm_prot.h>
66 #include <mach/machine.h>
67 #include <mach/time_value.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>
76 #include <vm/vm_kern.h>
77 #include <i386/pmap.h>
80 #include <i386/misc_protos.h>
81 #include <i386/mp_slave_boot.h>
82 #include <i386/cpuid.h>
84 #include <mach/thread_status.h>
87 vm_size_t mem_size
= 0;
88 vm_offset_t first_avail
= 0;/* first after page tables */
89 vm_offset_t last_addr
;
92 uint64_t sane_size
= 0; /* we are going to use the booter memory
93 table info to construct this */
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;
101 extern char edata
, end
;
105 #include <mach-o/loader.h>
106 vm_offset_t edata
, etext
, end
;
109 * _mh_execute_header is the mach_header for the currently executing
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
;
120 extern void *getsegdatafromheader(struct mach_header
*, const char *, int *);
124 * Basic VM initialization.
127 i386_vm_init(unsigned int maxmem
, KernelBootArgs_t
*args
)
129 pmap_memory_region_t
*pmptr
;
133 ppnum_t maxpg
= (maxmem
>> I386_PGSHIFT
);
136 /* Now retrieve addresses for end, edata, and etext
137 * from MACH-O headers.
140 sectTEXTB
= (void *) getsegdatafromheader(
141 &_mh_execute_header
, "__TEXT", §SizeTEXT
);
142 sectDATAB
= (void *) getsegdatafromheader(
143 &_mh_execute_header
, "__DATA", §SizeDATA
);
144 sectOBJCB
= (void *) getsegdatafromheader(
145 &_mh_execute_header
, "__OBJC", §SizeOBJC
);
146 sectLINKB
= (void *) getsegdatafromheader(
147 &_mh_execute_header
, "__LINKEDIT", §SizeLINK
);
148 sectHIBB
= (void *)getsegdatafromheader(
149 &_mh_execute_header
, "__HIB", §SizeHIB
);
150 sectPRELINKB
= (void *) getsegdatafromheader(
151 &_mh_execute_header
, "__PRELINK", §SizePRELINK
);
153 etext
= (vm_offset_t
) sectTEXTB
+ sectSizeTEXT
;
154 edata
= (vm_offset_t
) sectDATAB
+ sectSizeDATA
;
161 bzero((char *)&edata
,(unsigned)(&end
- &edata
));
165 * Initialize the pic prior to any possible call to an spl.
172 * Compute the memory size.
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
;
183 #define FOURGIG 0x0000000100000000ULL
184 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
187 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
188 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
191 if (base
>= maxpg
) break;
192 top
= (top
> maxpg
)? maxpg
: top
;
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 */
199 /* entire range below first_avail */
201 } else if (mptr
->base
>= FOURGIG
) {
202 /* entire range above 4GB (pre PAE) */
204 } else if ( (base
< fap
) &&
206 /* spans first_avail */
207 /* put mem below first avail in table but
208 mark already allocated */
210 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
211 pmptr
->type
= mptr
->type
;
212 /* we bump these here inline so the accounting below works
215 pmap_memory_region_count
++;
216 pmptr
->alloc
= pmptr
->base
= fap
;
217 pmptr
->type
= mptr
->type
;
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;
226 /* entire range useable */
227 pmptr
->alloc
= pmptr
->base
= base
;
228 pmptr
->type
= mptr
->type
;
233 /* entire range below first_avail */
235 } else if ( (base
< fap
) &&
237 /* spans first_avail */
238 pmptr
->alloc
= pmptr
->base
= fap
;
239 pmptr
->type
= mptr
->type
;
242 /* entire range useable */
243 pmptr
->alloc
= pmptr
->base
= base
;
244 pmptr
->type
= mptr
->type
;
248 if (i386_ptob(pmptr
->end
) > avail_end
) {
249 avail_end
= i386_ptob(pmptr
->end
);
251 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
252 pmap_memory_region_count
++;
255 #else /* non PAE follows */
256 #define FOURGIG 0x0000000100000000ULL
257 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
260 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
261 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
264 if (base
>= maxpg
) break;
265 top
= (top
> maxpg
)? maxpg
: top
;
268 if (kMemoryRangeUsable
!= mptr
->type
) continue;
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
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
) {
282 // Usable memory region
283 sane_size
+= (uint64_t)(mptr
->length
);
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) */
295 } else if ( (base
< fap
) &&
297 /* spans first_avail */
298 /* put mem below first avail in table but
299 mark already allocated */
301 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
302 pmptr
->type
= mptr
->type
;
303 /* we bump these here inline so the accounting below works
306 pmap_memory_region_count
++;
307 pmptr
->alloc
= pmptr
->base
= fap
;
308 pmptr
->type
= mptr
->type
;
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;
317 /* entire range useable */
318 pmptr
->alloc
= pmptr
->base
= base
;
319 pmptr
->type
= mptr
->type
;
323 if (i386_ptob(pmptr
->end
) > avail_end
) {
324 avail_end
= i386_ptob(pmptr
->end
);
327 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
328 pmap_memory_region_count
++;
334 #ifdef PRINT_PMAP_MEMORY_TABLE
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
);
345 avail_start
= first_avail
;
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
) ) {
355 // round up to a megabyte - mostly accounting for the
357 sane_size
+= ( 0x100000ULL
- 1);
358 sane_size
&= ~0xFFFFFULL
;
361 if (sane_size
< FOURGIG
)
362 mem_size
= (unsigned long) sane_size
;
364 mem_size
= (unsigned long) (FOURGIG
>> 1);
366 mem_size
= (unsigned long) sane_size
;
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
);
376 kprintf("Physical memory %d MB\n",
380 * Initialize kernel physical map.
381 * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
389 pmap_free_pages(void)
391 return avail_remaining
;
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
++;
405 *pn
= pmap_memory_regions
[pmap_memory_region_current
].alloc
++;
418 pmap_memory_region_t
*pmptr
= pmap_memory_regions
;
421 for (i
=0; i
<pmap_memory_region_count
; i
++, pmptr
++) {
422 if ( (pn
>= pmptr
->base
) && (pn
<= pmptr
->end
) ) {
423 if (pmptr
->type
== kMemoryRangeUsable
)