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
) {
267 pmptr
->end
= ((mptr
->base
+ mptr
->length
+ I386_PGBYTES
- 1) >> I386_PGSHIFT
) - 1;
268 pmptr
->alloc
= pmptr
->end
;
269 pmptr
->type
= mptr
->type
;
270 kprintf("NVS region: 0x%x ->0x%x\n", pmptr
->base
, pmptr
->end
);
271 } else if (kMemoryRangeUsable
!= mptr
->type
) {
274 // Usable memory region
275 sane_size
+= (uint64_t)(mptr
->length
);
277 /* entire range below first_avail */
278 /* salvage some low memory pages */
279 /* we use some very low memory at startup */
280 /* mark as already allocated here */
281 pmptr
->base
= 0x18; /* PAE and HIB use below this */
282 pmptr
->alloc
= pmptr
->end
= top
; /* mark as already mapped */
283 pmptr
->type
= mptr
->type
;
284 } else if (mptr
->base
>= FOURGIG
) {
285 /* entire range above 4GB (pre PAE) */
287 } else if ( (base
< fap
) &&
289 /* spans first_avail */
290 /* put mem below first avail in table but
291 mark already allocated */
293 pmptr
->alloc
= pmptr
->end
= (fap
- 1);
294 pmptr
->type
= mptr
->type
;
295 /* we bump these here inline so the accounting below works
298 pmap_memory_region_count
++;
299 pmptr
->alloc
= pmptr
->base
= fap
;
300 pmptr
->type
= mptr
->type
;
302 } else if ( (mptr
->base
< FOURGIG
) &&
303 ((mptr
->base
+mptr
->length
) > FOURGIG
) ) {
304 /* spans across 4GB (pre PAE) */
305 pmptr
->alloc
= pmptr
->base
= base
;
306 pmptr
->type
= mptr
->type
;
307 pmptr
->end
= (FOURGIG
>> I386_PGSHIFT
) - 1;
309 /* entire range useable */
310 pmptr
->alloc
= pmptr
->base
= base
;
311 pmptr
->type
= mptr
->type
;
315 if (i386_ptob(pmptr
->end
) > avail_end
) {
316 avail_end
= i386_ptob(pmptr
->end
);
319 avail_remaining
+= (pmptr
->end
- pmptr
->base
);
320 pmap_memory_region_count
++;
326 #ifdef PRINT_PMAP_MEMORY_TABLE
329 pmap_memory_region_t
*p
= pmap_memory_regions
;
330 for (j
=0;j
<pmap_memory_region_count
;j
++, p
++) {
331 kprintf("%d base 0x%x alloc 0x%x top 0x%x\n",j
,
332 p
->base
, p
->alloc
, p
->end
);
337 avail_start
= first_avail
;
339 if (maxmem
) { /* if user set maxmem try to use it */
340 uint64_t tmp
= (uint64_t)maxmem
;
341 /* can't set below first_avail or above actual memory */
342 if ( (maxmem
> first_avail
) && (tmp
< sane_size
) ) {
347 // round up to a megabyte - mostly accounting for the
349 sane_size
+= ( 0x100000ULL
- 1);
350 sane_size
&= ~0xFFFFFULL
;
353 if (sane_size
< FOURGIG
)
354 mem_size
= (unsigned long) sane_size
;
356 mem_size
= (unsigned long) (FOURGIG
>> 1);
358 mem_size
= (unsigned long) sane_size
;
363 /* now make sane size sane */
364 #define MIN(a,b) (((a)<(b))?(a):(b))
365 #define MEG (1024*1024)
366 sane_size
= MIN(sane_size
, 256*MEG
);
368 kprintf("Physical memory %d MB\n",
372 * Initialize kernel physical map.
373 * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
381 pmap_free_pages(void)
383 return avail_remaining
;
391 while (pmap_memory_region_current
< pmap_memory_region_count
) {
392 if (pmap_memory_regions
[pmap_memory_region_current
].alloc
==
393 pmap_memory_regions
[pmap_memory_region_current
].end
) {
394 pmap_memory_region_current
++;
397 *pn
= pmap_memory_regions
[pmap_memory_region_current
].alloc
++;
410 pmap_memory_region_t
*pmptr
= pmap_memory_regions
;
413 for (i
=0; i
<pmap_memory_region_count
; i
++, pmptr
++) {
414 if ( (pn
>= pmptr
->base
) && (pn
<= pmptr
->end
) ) {
415 if (pmptr
->type
== kMemoryRangeUsable
)