#include <platforms.h>
#include <mach_kdb.h>
#include <himem.h>
#include <mach/i386/vm_param.h>
#include <string.h>
#include <mach/vm_param.h>
#include <mach/vm_prot.h>
#include <mach/machine.h>
#include <mach/time_value.h>
#include <kern/spl.h>
#include <kern/assert.h>
#include <kern/debug.h>
#include <kern/misc_protos.h>
#include <kern/cpu_data.h>
#include <kern/processor.h>
#include <vm/vm_page.h>
#include <vm/pmap.h>
#include <vm/vm_kern.h>
#include <i386/pmap.h>
#include <i386/ipl.h>
#include <i386/pio.h>
#include <i386/misc_protos.h>
#include <i386/mp_slave_boot.h>
#include <i386/cpuid.h>
#ifdef __MACHO__
#include <mach/thread_status.h>
#endif
vm_size_t mem_size = 0;
vm_offset_t first_avail = 0;
vm_offset_t last_addr;
uint64_t max_mem;
uint64_t sane_size = 0;
pmap_paddr_t avail_start, avail_end;
vm_offset_t virtual_avail, virtual_end;
pmap_paddr_t avail_remaining;
vm_offset_t static_memory_end = 0;
#ifndef __MACHO__
extern char edata, end;
#endif
#ifdef __MACHO__
#include <mach-o/loader.h>
vm_offset_t edata, etext, end;
extern struct mach_header _mh_execute_header;
void *sectTEXTB; int sectSizeTEXT;
void *sectDATAB; int sectSizeDATA;
void *sectOBJCB; int sectSizeOBJC;
void *sectLINKB; int sectSizeLINK;
void *sectPRELINKB; int sectSizePRELINK;
void *sectHIBB; int sectSizeHIB;
extern void *getsegdatafromheader(struct mach_header *, const char *, int *);
#endif
void
i386_vm_init(unsigned int maxmem, KernelBootArgs_t *args)
{
pmap_memory_region_t *pmptr;
MemoryRange *mptr;
ppnum_t fap;
unsigned int i;
ppnum_t maxpg = (maxmem >> I386_PGSHIFT);
#ifdef __MACHO__
sectTEXTB = (void *) getsegdatafromheader(
&_mh_execute_header, "__TEXT", §SizeTEXT);
sectDATAB = (void *) getsegdatafromheader(
&_mh_execute_header, "__DATA", §SizeDATA);
sectOBJCB = (void *) getsegdatafromheader(
&_mh_execute_header, "__OBJC", §SizeOBJC);
sectLINKB = (void *) getsegdatafromheader(
&_mh_execute_header, "__LINKEDIT", §SizeLINK);
sectHIBB = (void *)getsegdatafromheader(
&_mh_execute_header, "__HIB", §SizeHIB);
sectPRELINKB = (void *) getsegdatafromheader(
&_mh_execute_header, "__PRELINK", §SizePRELINK);
etext = (vm_offset_t) sectTEXTB + sectSizeTEXT;
edata = (vm_offset_t) sectDATAB + sectSizeDATA;
#endif
#ifndef __MACHO__
bzero((char *)&edata,(unsigned)(&end - &edata));
#endif
set_cpu_model();
vm_set_page_size();
avail_remaining = 0;
avail_end = 0;
pmptr = pmap_memory_regions;
pmap_memory_region_count = pmap_memory_region_current = 0;
fap = (ppnum_t) i386_btop(first_avail);
mptr = args->memoryMap;
#ifdef PAE
#define FOURGIG 0x0000000100000000ULL
for (i=0; i < args->memoryMapCount; i++,mptr++) {
ppnum_t base, top;
base = (ppnum_t) (mptr->base >> I386_PGSHIFT);
top = (ppnum_t) ((mptr->base + mptr->length) >> I386_PGSHIFT) - 1;
if (maxmem) {
if (base >= maxpg) break;
top = (top > maxpg)? maxpg : top;
}
if (kMemoryRangeUsable != mptr->type) continue;
sane_size += (uint64_t)(mptr->length);
#ifdef DEVICES_HANDLE_64BIT_IO
if (top < fap) {
continue;
} else if (mptr->base >= FOURGIG) {
continue;
} else if ( (base < fap) &&
(top > fap)) {
pmptr->base = base;
pmptr->alloc = pmptr->end = (fap - 1);
pmptr->type = mptr->type;
pmptr++;
pmap_memory_region_count++;
pmptr->alloc = pmptr->base = fap;
pmptr->type = mptr->type;
pmptr->end = top;
} else if ( (mptr->base < FOURGIG) &&
((mptr->base+mptr->length) > FOURGIG) ) {
pmptr->alloc = pmptr->base = base;
pmptr->type = mptr->type;
pmptr->end = (FOURGIG >> I386_PGSHIFT) - 1;
} else {
pmptr->alloc = pmptr->base = base;
pmptr->type = mptr->type;
pmptr->end = top;
}
#else
if (top < fap) {
continue;
} else if ( (base < fap) &&
(top > fap)) {
pmptr->alloc = pmptr->base = fap;
pmptr->type = mptr->type;
pmptr->end = top;
} else {
pmptr->alloc = pmptr->base = base;
pmptr->type = mptr->type;
pmptr->end = top;
}
#endif
if (i386_ptob(pmptr->end) > avail_end ) {
avail_end = i386_ptob(pmptr->end);
}
avail_remaining += (pmptr->end - pmptr->base);
pmap_memory_region_count++;
pmptr++;
}
#else
#define FOURGIG 0x0000000100000000ULL
for (i=0; i < args->memoryMapCount; i++,mptr++) {
ppnum_t base, top;
base = (ppnum_t) (mptr->base >> I386_PGSHIFT);
top = (ppnum_t) ((mptr->base + mptr->length) >> I386_PGSHIFT) - 1;
if (maxmem) {
if (base >= maxpg) break;
top = (top > maxpg)? maxpg : top;
}
if (kMemoryRangeUsable != mptr->type) continue;
if (kMemoryRangeNVS == mptr->type) {
pmptr->base = base;
pmptr->end = ((mptr->base + mptr->length + I386_PGBYTES - 1) >> I386_PGSHIFT) - 1;
pmptr->alloc = pmptr->end;
pmptr->type = mptr->type;
kprintf("NVS region: 0x%x ->0x%x\n", pmptr->base, pmptr->end);
} else if (kMemoryRangeUsable != mptr->type) {
continue;
} else {
sane_size += (uint64_t)(mptr->length);
if (top < fap) {
pmptr->base = 0x18;
pmptr->alloc = pmptr->end = top;
pmptr->type = mptr->type;
} else if (mptr->base >= FOURGIG) {
continue;
} else if ( (base < fap) &&
(top > fap)) {
pmptr->base = base;
pmptr->alloc = pmptr->end = (fap - 1);
pmptr->type = mptr->type;
pmptr++;
pmap_memory_region_count++;
pmptr->alloc = pmptr->base = fap;
pmptr->type = mptr->type;
pmptr->end = top;
} else if ( (mptr->base < FOURGIG) &&
((mptr->base+mptr->length) > FOURGIG) ) {
pmptr->alloc = pmptr->base = base;
pmptr->type = mptr->type;
pmptr->end = (FOURGIG >> I386_PGSHIFT) - 1;
} else {
pmptr->alloc = pmptr->base = base;
pmptr->type = mptr->type;
pmptr->end = top;
}
if (i386_ptob(pmptr->end) > avail_end ) {
avail_end = i386_ptob(pmptr->end);
}
avail_remaining += (pmptr->end - pmptr->base);
pmap_memory_region_count++;
pmptr++;
}
}
#endif
#ifdef PRINT_PMAP_MEMORY_TABLE
{
unsigned int j;
pmap_memory_region_t *p = pmap_memory_regions;
for (j=0;j<pmap_memory_region_count;j++, p++) {
kprintf("%d base 0x%x alloc 0x%x top 0x%x\n",j,
p->base, p->alloc, p->end);
}
}
#endif
avail_start = first_avail;
if (maxmem) {
uint64_t tmp = (uint64_t)maxmem;
if ( (maxmem > first_avail) && (tmp < sane_size) ) {
sane_size = tmp;
avail_end = maxmem;
}
}
sane_size += ( 0x100000ULL - 1);
sane_size &= ~0xFFFFFULL;
#ifndef PAE
if (sane_size < FOURGIG)
mem_size = (unsigned long) sane_size;
else
mem_size = (unsigned long) (FOURGIG >> 1);
#else
mem_size = (unsigned long) sane_size;
#endif
max_mem = sane_size;
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MEG (1024*1024)
sane_size = MIN(sane_size, 256*MEG);
kprintf("Physical memory %d MB\n",
mem_size/MEG);
pmap_bootstrap(0);
}
unsigned int
pmap_free_pages(void)
{
return avail_remaining;
}
boolean_t
pmap_next_page(
ppnum_t *pn)
{
while (pmap_memory_region_current < pmap_memory_region_count) {
if (pmap_memory_regions[pmap_memory_region_current].alloc ==
pmap_memory_regions[pmap_memory_region_current].end) {
pmap_memory_region_current++;
continue;
}
*pn = pmap_memory_regions[pmap_memory_region_current].alloc++;
avail_remaining--;
return TRUE;
}
return FALSE;
}
boolean_t
pmap_valid_page(
ppnum_t pn)
{
unsigned int i;
pmap_memory_region_t *pmptr = pmap_memory_regions;
assert(pn);
for (i=0; i<pmap_memory_region_count; i++, pmptr++) {
if ( (pn >= pmptr->base) && (pn <= pmptr->end) ) {
if (pmptr->type == kMemoryRangeUsable)
return TRUE;
else
return FALSE;
}
}
return FALSE;
}