2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
59 #include <platforms.h>
63 #include <mach/i386/vm_param.h>
66 #include <mach/vm_param.h>
67 #include <mach/vm_prot.h>
68 #include <mach/machine.h>
69 #include <mach/time_value.h>
71 #include <kern/assert.h>
72 #include <kern/debug.h>
73 #include <kern/misc_protos.h>
74 #include <kern/cpu_data.h>
75 #include <kern/processor.h>
76 #include <vm/vm_page.h>
78 #include <vm/vm_kern.h>
79 #include <i386/pmap.h>
82 #include <i386/misc_protos.h>
83 #include <i386/mp_slave_boot.h>
84 #include <i386/cpuid.h>
86 #include <mach/thread_status.h>
89 vm_size_t mem_size
= 0;
90 vm_offset_t first_avail
= 0;/* first after page tables */
91 vm_offset_t last_addr
;
94 uint64_t sane_size
= 0; /* we are going to use the booter memory
95 table info to construct this */
97 pmap_paddr_t avail_start
, avail_end
;
98 vm_offset_t virtual_avail
, virtual_end
;
99 pmap_paddr_t avail_remaining
;
100 vm_offset_t static_memory_end
= 0;
103 extern char edata
, end
;
107 #include <mach-o/loader.h>
108 vm_offset_t edata
, etext
, end
;
111 * _mh_execute_header is the mach_header for the currently executing
114 extern struct mach_header _mh_execute_header
;
115 void *sectTEXTB
; int sectSizeTEXT
;
116 void *sectDATAB
; int sectSizeDATA
;
117 void *sectOBJCB
; int sectSizeOBJC
;
118 void *sectLINKB
; int sectSizeLINK
;
119 void *sectPRELINKB
; int sectSizePRELINK
;
120 void *sectHIBB
; int sectSizeHIB
;
122 extern void *getsegdatafromheader(struct mach_header
*, const char *, int *);
126 * Basic VM initialization.
129 i386_vm_init(unsigned int maxmem
, KernelBootArgs_t
*args
)
131 pmap_memory_region_t
*pmptr
;
135 ppnum_t maxpg
= (maxmem
>> I386_PGSHIFT
);
138 /* Now retrieve addresses for end, edata, and etext
139 * from MACH-O headers.
142 sectTEXTB
= (void *) getsegdatafromheader(
143 &_mh_execute_header
, "__TEXT", §SizeTEXT
);
144 sectDATAB
= (void *) getsegdatafromheader(
145 &_mh_execute_header
, "__DATA", §SizeDATA
);
146 sectOBJCB
= (void *) getsegdatafromheader(
147 &_mh_execute_header
, "__OBJC", §SizeOBJC
);
148 sectLINKB
= (void *) getsegdatafromheader(
149 &_mh_execute_header
, "__LINKEDIT", §SizeLINK
);
150 sectHIBB
= (void *)getsegdatafromheader(
151 &_mh_execute_header
, "__HIB", §SizeHIB
);
152 sectPRELINKB
= (void *) getsegdatafromheader(
153 &_mh_execute_header
, "__PRELINK", §SizePRELINK
);
155 etext
= (vm_offset_t
) sectTEXTB
+ sectSizeTEXT
;
156 edata
= (vm_offset_t
) sectDATAB
+ sectSizeDATA
;
163 bzero((char *)&edata
,(unsigned)(&end
- &edata
));
167 * Initialize the pic prior to any possible call to an spl.
174 * Compute the memory size.
179 pmptr
= pmap_memory_regions
;
180 pmap_memory_region_count
= pmap_memory_region_current
= 0;
181 fap
= (ppnum_t
) i386_btop(first_avail
);
182 mptr
= args
->memoryMap
;
185 #define FOURGIG 0x0000000100000000ULL
186 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
189 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
190 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
193 if (base
>= maxpg
) break;
194 top
= (top
> maxpg
)? maxpg
: top
;
197 if (kMemoryRangeUsable
!= mptr
->type
) continue;
198 sane_size
+= (uint64_t)(mptr
->length
);
199 #ifdef DEVICES_HANDLE_64BIT_IO /* XXX enable else clause when I/O to high memory works */
201 /* entire range below first_avail */
203 } else if (mptr
->base
>= FOURGIG
) {
204 /* entire range above 4GB (pre PAE) */
206 } else if ( (base
< fap
) &&
208 /* spans first_avail */
209 /* put mem below first avail in table but
210 mark already allocated */
212 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
213 pmptr
->type
= mptr
->type
;
214 /* we bump these here inline so the accounting below works
217 pmap_memory_region_count
++;
218 pmptr
->alloc
= pmptr
->base
= fap
;
219 pmptr
->type
= mptr
->type
;
221 } else if ( (mptr
->base
< FOURGIG
) &&
222 ((mptr
->base
+mptr
->length
) > FOURGIG
) ) {
223 /* spans across 4GB (pre PAE) */
224 pmptr
->alloc
= pmptr
->base
= base
;
225 pmptr
->type
= mptr
->type
;
226 pmptr
->end
= (FOURGIG
>> I386_PGSHIFT
) - 1;
228 /* entire range useable */
229 pmptr
->alloc
= pmptr
->base
= base
;
230 pmptr
->type
= mptr
->type
;
235 /* entire range below first_avail */
237 } else if ( (base
< fap
) &&
239 /* spans first_avail */
240 pmptr
->alloc
= pmptr
->base
= fap
;
241 pmptr
->type
= mptr
->type
;
244 /* entire range useable */
245 pmptr
->alloc
= pmptr
->base
= base
;
246 pmptr
->type
= mptr
->type
;
250 if (i386_ptob(pmptr
->end
) > avail_end
) {
251 avail_end
= i386_ptob(pmptr
->end
);
253 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
254 pmap_memory_region_count
++;
257 #else /* non PAE follows */
258 #define FOURGIG 0x0000000100000000ULL
259 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
262 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
263 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
266 if (base
>= maxpg
) break;
267 top
= (top
> maxpg
)? maxpg
: top
;
270 if (kMemoryRangeUsable
!= mptr
->type
) continue;
272 // save other regions
273 if (kMemoryRangeNVS
== mptr
->type
) {
274 // Mark this as a memory range (for hibernation),
275 // but don't count as usable memory
277 pmptr
->end
= ((mptr
->base
+ mptr
->length
+ I386_PGBYTES
- 1) >> I386_PGSHIFT
) - 1;
278 pmptr
->alloc
= pmptr
->end
;
279 pmptr
->type
= mptr
->type
;
280 kprintf("NVS region: 0x%x ->0x%x\n", pmptr
->base
, pmptr
->end
);
281 } else if (kMemoryRangeUsable
!= mptr
->type
) {
284 // Usable memory region
285 sane_size
+= (uint64_t)(mptr
->length
);
287 /* entire range below first_avail */
288 /* salvage some low memory pages */
289 /* we use some very low memory at startup */
290 /* mark as already allocated here */
291 pmptr
->base
= 0x18; /* PAE and HIB use below this */
292 pmptr
->alloc
= pmptr
->end
= top
; /* mark as already mapped */
293 pmptr
->type
= mptr
->type
;
294 } else if (mptr
->base
>= FOURGIG
) {
295 /* entire range above 4GB (pre PAE) */
297 } else if ( (base
< fap
) &&
299 /* spans first_avail */
300 /* put mem below first avail in table but
301 mark already allocated */
303 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
304 pmptr
->type
= mptr
->type
;
305 /* we bump these here inline so the accounting below works
308 pmap_memory_region_count
++;
309 pmptr
->alloc
= pmptr
->base
= fap
;
310 pmptr
->type
= mptr
->type
;
312 } else if ( (mptr
->base
< FOURGIG
) &&
313 ((mptr
->base
+mptr
->length
) > FOURGIG
) ) {
314 /* spans across 4GB (pre PAE) */
315 pmptr
->alloc
= pmptr
->base
= base
;
316 pmptr
->type
= mptr
->type
;
317 pmptr
->end
= (FOURGIG
>> I386_PGSHIFT
) - 1;
319 /* entire range useable */
320 pmptr
->alloc
= pmptr
->base
= base
;
321 pmptr
->type
= mptr
->type
;
325 if (i386_ptob(pmptr
->end
) > avail_end
) {
326 avail_end
= i386_ptob(pmptr
->end
);
329 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
330 pmap_memory_region_count
++;
336 #ifdef PRINT_PMAP_MEMORY_TABLE
339 pmap_memory_region_t
*p
= pmap_memory_regions
;
340 for (j
=0;j
<pmap_memory_region_count
;j
++, p
++) {
341 kprintf("%d base 0x%x alloc 0x%x top 0x%x\n",j
,
342 p
->base
, p
->alloc
, p
->end
);
347 avail_start
= first_avail
;
349 if (maxmem
) { /* if user set maxmem try to use it */
350 uint64_t tmp
= (uint64_t)maxmem
;
351 /* can't set below first_avail or above actual memory */
352 if ( (maxmem
> first_avail
) && (tmp
< sane_size
) ) {
357 // round up to a megabyte - mostly accounting for the
359 sane_size
+= ( 0x100000ULL
- 1);
360 sane_size
&= ~0xFFFFFULL
;
363 if (sane_size
< FOURGIG
)
364 mem_size
= (unsigned long) sane_size
;
366 mem_size
= (unsigned long) (FOURGIG
>> 1);
368 mem_size
= (unsigned long) sane_size
;
373 /* now make sane size sane */
374 #define MIN(a,b) (((a)<(b))?(a):(b))
375 #define MEG (1024*1024)
376 sane_size
= MIN(sane_size
, 256*MEG
);
378 kprintf("Physical memory %d MB\n",
382 * Initialize kernel physical map.
383 * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
391 pmap_free_pages(void)
393 return avail_remaining
;
401 while (pmap_memory_region_current
< pmap_memory_region_count
) {
402 if (pmap_memory_regions
[pmap_memory_region_current
].alloc
==
403 pmap_memory_regions
[pmap_memory_region_current
].end
) {
404 pmap_memory_region_current
++;
407 *pn
= pmap_memory_regions
[pmap_memory_region_current
].alloc
++;
420 pmap_memory_region_t
*pmptr
= pmap_memory_regions
;
423 for (i
=0; i
<pmap_memory_region_count
; i
++, pmptr
++) {
424 if ( (pn
>= pmptr
->base
) && (pn
<= pmptr
->end
) ) {
425 if (pmptr
->type
== kMemoryRangeUsable
)