2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
51 #include <platforms.h>
55 #include <mach/i386/vm_param.h>
58 #include <mach/vm_param.h>
59 #include <mach/vm_prot.h>
60 #include <mach/machine.h>
61 #include <mach/time_value.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>
70 #include <vm/vm_kern.h>
71 #include <i386/pmap.h>
74 #include <i386/misc_protos.h>
75 #include <i386/mp_slave_boot.h>
76 #include <i386/cpuid.h>
78 #include <mach/thread_status.h>
81 vm_size_t mem_size
= 0;
82 vm_offset_t first_avail
= 0;/* first after page tables */
83 vm_offset_t last_addr
;
86 uint64_t sane_size
= 0; /* we are going to use the booter memory
87 table info to construct this */
89 pmap_paddr_t avail_start
, avail_end
;
90 vm_offset_t virtual_avail
, virtual_end
;
91 pmap_paddr_t avail_remaining
;
92 vm_offset_t static_memory_end
= 0;
95 extern char edata
, end
;
99 #include <mach-o/loader.h>
100 vm_offset_t edata
, etext
, end
;
103 * _mh_execute_header is the mach_header for the currently executing
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
;
112 void *sectHIBB
; int sectSizeHIB
;
114 extern void *getsegdatafromheader(struct mach_header
*, const char *, int *);
118 * Basic VM initialization.
121 i386_vm_init(unsigned int maxmem
, KernelBootArgs_t
*args
)
123 pmap_memory_region_t
*pmptr
;
127 ppnum_t maxpg
= (maxmem
>> I386_PGSHIFT
);
130 /* Now retrieve addresses for end, edata, and etext
131 * from MACH-O headers.
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
);
142 sectHIBB
= (void *)getsegdatafromheader(
143 &_mh_execute_header
, "__HIB", §SizeHIB
);
144 sectPRELINKB
= (void *) getsegdatafromheader(
145 &_mh_execute_header
, "__PRELINK", §SizePRELINK
);
147 etext
= (vm_offset_t
) sectTEXTB
+ sectSizeTEXT
;
148 edata
= (vm_offset_t
) sectDATAB
+ sectSizeDATA
;
155 bzero((char *)&edata
,(unsigned)(&end
- &edata
));
159 * Initialize the pic prior to any possible call to an spl.
166 * Compute the memory size.
171 pmptr
= pmap_memory_regions
;
172 pmap_memory_region_count
= pmap_memory_region_current
= 0;
173 fap
= (ppnum_t
) i386_btop(first_avail
);
174 mptr
= args
->memoryMap
;
177 #define FOURGIG 0x0000000100000000ULL
178 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
181 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
182 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
185 if (base
>= maxpg
) break;
186 top
= (top
> maxpg
)? maxpg
: top
;
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 */
193 /* entire range below first_avail */
195 } else if (mptr
->base
>= FOURGIG
) {
196 /* entire range above 4GB (pre PAE) */
198 } else if ( (base
< fap
) &&
200 /* spans first_avail */
201 /* put mem below first avail in table but
202 mark already allocated */
204 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
205 pmptr
->type
= mptr
->type
;
206 /* we bump these here inline so the accounting below works
209 pmap_memory_region_count
++;
210 pmptr
->alloc
= pmptr
->base
= fap
;
211 pmptr
->type
= mptr
->type
;
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;
220 /* entire range useable */
221 pmptr
->alloc
= pmptr
->base
= base
;
222 pmptr
->type
= mptr
->type
;
227 /* entire range below first_avail */
229 } else if ( (base
< fap
) &&
231 /* spans first_avail */
232 pmptr
->alloc
= pmptr
->base
= fap
;
233 pmptr
->type
= mptr
->type
;
236 /* entire range useable */
237 pmptr
->alloc
= pmptr
->base
= base
;
238 pmptr
->type
= mptr
->type
;
242 if (i386_ptob(pmptr
->end
) > avail_end
) {
243 avail_end
= i386_ptob(pmptr
->end
);
245 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
246 pmap_memory_region_count
++;
249 #else /* non PAE follows */
250 #define FOURGIG 0x0000000100000000ULL
251 for (i
=0; i
< args
->memoryMapCount
; i
++,mptr
++) {
254 base
= (ppnum_t
) (mptr
->base
>> I386_PGSHIFT
);
255 top
= (ppnum_t
) ((mptr
->base
+ mptr
->length
) >> I386_PGSHIFT
) - 1;
258 if (base
>= maxpg
) break;
259 top
= (top
> maxpg
)? maxpg
: top
;
262 if (kMemoryRangeUsable
!= mptr
->type
) continue;
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
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
) {
276 // Usable memory region
277 sane_size
+= (uint64_t)(mptr
->length
);
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) */
289 } else if ( (base
< fap
) &&
291 /* spans first_avail */
292 /* put mem below first avail in table but
293 mark already allocated */
295 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
296 pmptr
->type
= mptr
->type
;
297 /* we bump these here inline so the accounting below works
300 pmap_memory_region_count
++;
301 pmptr
->alloc
= pmptr
->base
= fap
;
302 pmptr
->type
= mptr
->type
;
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;
311 /* entire range useable */
312 pmptr
->alloc
= pmptr
->base
= base
;
313 pmptr
->type
= mptr
->type
;
317 if (i386_ptob(pmptr
->end
) > avail_end
) {
318 avail_end
= i386_ptob(pmptr
->end
);
321 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
322 pmap_memory_region_count
++;
328 #ifdef PRINT_PMAP_MEMORY_TABLE
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
);
339 avail_start
= first_avail
;
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
) ) {
349 // round up to a megabyte - mostly accounting for the
351 sane_size
+= ( 0x100000ULL
- 1);
352 sane_size
&= ~0xFFFFFULL
;
355 if (sane_size
< FOURGIG
)
356 mem_size
= (unsigned long) sane_size
;
358 mem_size
= (unsigned long) (FOURGIG
>> 1);
360 mem_size
= (unsigned long) sane_size
;
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
);
370 kprintf("Physical memory %d MB\n",
374 * Initialize kernel physical map.
375 * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
383 pmap_free_pages(void)
385 return avail_remaining
;
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
++;
399 *pn
= pmap_memory_regions
[pmap_memory_region_current
].alloc
++;
412 pmap_memory_region_t
*pmptr
= pmap_memory_regions
;
415 for (i
=0; i
<pmap_memory_region_count
; i
++, pmptr
++) {
416 if ( (pn
>= pmptr
->base
) && (pn
<= pmptr
->end
) ) {
417 if (pmptr
->type
== kMemoryRangeUsable
)