17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Size memory and create the kernel page-tables on the fly while doing so.
37dd7cddfSDavid du Colombier * Called from main(), this code should only be run by the bootstrap processor.
48f5875f3SDavid du Colombier *
58f5875f3SDavid du Colombier * MemMin is what the bootstrap code in l.s has already mapped;
68f5875f3SDavid du Colombier * MemMax is the limit of physical memory to scan.
77dd7cddfSDavid du Colombier */
87dd7cddfSDavid du Colombier #include "u.h"
97dd7cddfSDavid du Colombier #include "../port/lib.h"
107dd7cddfSDavid du Colombier #include "mem.h"
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
137dd7cddfSDavid du Colombier #include "io.h"
144de34a7eSDavid du Colombier #include "ureg.h"
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier #define MEMDEBUG 0
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier enum {
197dd7cddfSDavid du Colombier MemUPA = 0, /* unbacked physical address */
207dd7cddfSDavid du Colombier MemRAM = 1, /* physical memory */
217dd7cddfSDavid du Colombier MemUMB = 2, /* upper memory block (<16MB) */
224de34a7eSDavid du Colombier MemReserved = 3,
234de34a7eSDavid du Colombier NMemType = 4,
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier KB = 1024,
267dd7cddfSDavid du Colombier
278f5875f3SDavid du Colombier MemMin = 8*MB,
288f5875f3SDavid du Colombier MemMax = (3*1024+768)*MB,
297dd7cddfSDavid du Colombier };
307dd7cddfSDavid du Colombier
3159c21d95SDavid du Colombier typedef struct Map Map;
3259c21d95SDavid du Colombier struct Map {
334de34a7eSDavid du Colombier ulong size;
347dd7cddfSDavid du Colombier ulong addr;
3559c21d95SDavid du Colombier };
367dd7cddfSDavid du Colombier
3759c21d95SDavid du Colombier typedef struct RMap RMap;
3859c21d95SDavid du Colombier struct RMap {
397dd7cddfSDavid du Colombier char* name;
407dd7cddfSDavid du Colombier Map* map;
417dd7cddfSDavid du Colombier Map* mapend;
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier Lock;
4459c21d95SDavid du Colombier };
457dd7cddfSDavid du Colombier
464de34a7eSDavid du Colombier /*
474de34a7eSDavid du Colombier * Memory allocation tracking.
484de34a7eSDavid du Colombier */
497dd7cddfSDavid du Colombier static Map mapupa[16];
507dd7cddfSDavid du Colombier static RMap rmapupa = {
517dd7cddfSDavid du Colombier "unallocated unbacked physical memory",
527dd7cddfSDavid du Colombier mapupa,
537dd7cddfSDavid du Colombier &mapupa[nelem(mapupa)-1],
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier static Map mapram[16];
577dd7cddfSDavid du Colombier static RMap rmapram = {
587dd7cddfSDavid du Colombier "physical memory",
597dd7cddfSDavid du Colombier mapram,
607dd7cddfSDavid du Colombier &mapram[nelem(mapram)-1],
617dd7cddfSDavid du Colombier };
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier static Map mapumb[64];
647dd7cddfSDavid du Colombier static RMap rmapumb = {
657dd7cddfSDavid du Colombier "upper memory block",
667dd7cddfSDavid du Colombier mapumb,
677dd7cddfSDavid du Colombier &mapumb[nelem(mapumb)-1],
687dd7cddfSDavid du Colombier };
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier static Map mapumbrw[16];
717dd7cddfSDavid du Colombier static RMap rmapumbrw = {
727dd7cddfSDavid du Colombier "UMB device memory",
737dd7cddfSDavid du Colombier mapumbrw,
747dd7cddfSDavid du Colombier &mapumbrw[nelem(mapumbrw)-1],
757dd7cddfSDavid du Colombier };
767dd7cddfSDavid du Colombier
777dd7cddfSDavid du Colombier void
mapprint(RMap * rmap)789a747e4fSDavid du Colombier mapprint(RMap *rmap)
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier Map *mp;
819a747e4fSDavid du Colombier
829a747e4fSDavid du Colombier print("%s\n", rmap->name);
839a747e4fSDavid du Colombier for(mp = rmap->map; mp->size; mp++)
844de34a7eSDavid du Colombier print("\t%8.8luX %8.8luX (%lud)\n", mp->addr, mp->addr+mp->size, mp->size);
859a747e4fSDavid du Colombier }
869a747e4fSDavid du Colombier
879a747e4fSDavid du Colombier
889a747e4fSDavid du Colombier void
memdebug(void)899a747e4fSDavid du Colombier memdebug(void)
909a747e4fSDavid du Colombier {
917dd7cddfSDavid du Colombier ulong maxpa, maxpa1, maxpa2;
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
947dd7cddfSDavid du Colombier maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
957dd7cddfSDavid du Colombier maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
967dd7cddfSDavid du Colombier print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
977dd7cddfSDavid du Colombier maxpa, MB+maxpa*KB, maxpa1, maxpa2);
987dd7cddfSDavid du Colombier
999a747e4fSDavid du Colombier mapprint(&rmapram);
1009a747e4fSDavid du Colombier mapprint(&rmapumb);
1019a747e4fSDavid du Colombier mapprint(&rmapumbrw);
1029a747e4fSDavid du Colombier mapprint(&rmapupa);
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier void
mapfree(RMap * rmap,ulong addr,ulong size)1067dd7cddfSDavid du Colombier mapfree(RMap* rmap, ulong addr, ulong size)
1077dd7cddfSDavid du Colombier {
1087dd7cddfSDavid du Colombier Map *mp;
1097dd7cddfSDavid du Colombier ulong t;
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier if(size <= 0)
1127dd7cddfSDavid du Colombier return;
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier lock(rmap);
1157dd7cddfSDavid du Colombier for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
1167dd7cddfSDavid du Colombier ;
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
1197dd7cddfSDavid du Colombier (mp-1)->size += size;
1207dd7cddfSDavid du Colombier if(addr+size == mp->addr){
1217dd7cddfSDavid du Colombier (mp-1)->size += mp->size;
1227dd7cddfSDavid du Colombier while(mp->size){
1237dd7cddfSDavid du Colombier mp++;
1247dd7cddfSDavid du Colombier (mp-1)->addr = mp->addr;
1257dd7cddfSDavid du Colombier (mp-1)->size = mp->size;
1267dd7cddfSDavid du Colombier }
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier else{
1307dd7cddfSDavid du Colombier if(addr+size == mp->addr && mp->size){
1317dd7cddfSDavid du Colombier mp->addr -= size;
1327dd7cddfSDavid du Colombier mp->size += size;
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier else do{
1357dd7cddfSDavid du Colombier if(mp >= rmap->mapend){
1367dd7cddfSDavid du Colombier print("mapfree: %s: losing 0x%luX, %ld\n",
1377dd7cddfSDavid du Colombier rmap->name, addr, size);
1387dd7cddfSDavid du Colombier break;
1397dd7cddfSDavid du Colombier }
1407dd7cddfSDavid du Colombier t = mp->addr;
1417dd7cddfSDavid du Colombier mp->addr = addr;
1427dd7cddfSDavid du Colombier addr = t;
1437dd7cddfSDavid du Colombier t = mp->size;
1447dd7cddfSDavid du Colombier mp->size = size;
1457dd7cddfSDavid du Colombier mp++;
1467dd7cddfSDavid du Colombier }while(size = t);
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier unlock(rmap);
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier ulong
mapalloc(RMap * rmap,ulong addr,int size,int align)1527dd7cddfSDavid du Colombier mapalloc(RMap* rmap, ulong addr, int size, int align)
1537dd7cddfSDavid du Colombier {
1547dd7cddfSDavid du Colombier Map *mp;
1557dd7cddfSDavid du Colombier ulong maddr, oaddr;
1567dd7cddfSDavid du Colombier
1577dd7cddfSDavid du Colombier lock(rmap);
1587dd7cddfSDavid du Colombier for(mp = rmap->map; mp->size; mp++){
1597dd7cddfSDavid du Colombier maddr = mp->addr;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier if(addr){
1627dd7cddfSDavid du Colombier /*
1637dd7cddfSDavid du Colombier * A specific address range has been given:
1647dd7cddfSDavid du Colombier * if the current map entry is greater then
1657dd7cddfSDavid du Colombier * the address is not in the map;
1667dd7cddfSDavid du Colombier * if the current map entry does not overlap
1677dd7cddfSDavid du Colombier * the beginning of the requested range then
1687dd7cddfSDavid du Colombier * continue on to the next map entry;
1697dd7cddfSDavid du Colombier * if the current map entry does not entirely
1707dd7cddfSDavid du Colombier * contain the requested range then the range
1717dd7cddfSDavid du Colombier * is not in the map.
1727dd7cddfSDavid du Colombier */
1737dd7cddfSDavid du Colombier if(maddr > addr)
1747dd7cddfSDavid du Colombier break;
17559cc4ca5SDavid du Colombier if(mp->size < addr - maddr) /* maddr+mp->size < addr, but no overflow */
1767dd7cddfSDavid du Colombier continue;
17759cc4ca5SDavid du Colombier if(addr - maddr > mp->size - size) /* addr+size > maddr+mp->size, but no overflow */
1787dd7cddfSDavid du Colombier break;
1797dd7cddfSDavid du Colombier maddr = addr;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier if(align > 0)
1837dd7cddfSDavid du Colombier maddr = ((maddr+align-1)/align)*align;
1847dd7cddfSDavid du Colombier if(mp->addr+mp->size-maddr < size)
1857dd7cddfSDavid du Colombier continue;
1867dd7cddfSDavid du Colombier
1877dd7cddfSDavid du Colombier oaddr = mp->addr;
1887dd7cddfSDavid du Colombier mp->addr = maddr+size;
1897dd7cddfSDavid du Colombier mp->size -= maddr-oaddr+size;
1907dd7cddfSDavid du Colombier if(mp->size == 0){
1917dd7cddfSDavid du Colombier do{
1927dd7cddfSDavid du Colombier mp++;
1937dd7cddfSDavid du Colombier (mp-1)->addr = mp->addr;
1947dd7cddfSDavid du Colombier }while((mp-1)->size = mp->size);
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier unlock(rmap);
1987dd7cddfSDavid du Colombier if(oaddr != maddr)
1997dd7cddfSDavid du Colombier mapfree(rmap, oaddr, maddr-oaddr);
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier return maddr;
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier unlock(rmap);
2047dd7cddfSDavid du Colombier
2057dd7cddfSDavid du Colombier return 0;
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier
2084de34a7eSDavid du Colombier /*
2094de34a7eSDavid du Colombier * Allocate from the ram map directly to make page tables.
2104de34a7eSDavid du Colombier * Called by mmuwalk during e820scan.
2114de34a7eSDavid du Colombier */
2124de34a7eSDavid du Colombier void*
rampage(void)2134de34a7eSDavid du Colombier rampage(void)
2144de34a7eSDavid du Colombier {
2154de34a7eSDavid du Colombier ulong m;
2164de34a7eSDavid du Colombier
2174de34a7eSDavid du Colombier m = mapalloc(&rmapram, 0, BY2PG, BY2PG);
2184de34a7eSDavid du Colombier if(m == 0)
2194de34a7eSDavid du Colombier return nil;
2204de34a7eSDavid du Colombier return KADDR(m);
2214de34a7eSDavid du Colombier }
2224de34a7eSDavid du Colombier
2237dd7cddfSDavid du Colombier static void
umbexclude(void)2240ef97810SDavid du Colombier umbexclude(void)
2250ef97810SDavid du Colombier {
2260ef97810SDavid du Colombier int size;
2270ef97810SDavid du Colombier ulong addr;
2280ef97810SDavid du Colombier char *op, *p, *rptr;
2290ef97810SDavid du Colombier
2300ef97810SDavid du Colombier if((p = getconf("umbexclude")) == nil)
2310ef97810SDavid du Colombier return;
2320ef97810SDavid du Colombier
2330ef97810SDavid du Colombier while(p && *p != '\0' && *p != '\n'){
2340ef97810SDavid du Colombier op = p;
2350ef97810SDavid du Colombier addr = strtoul(p, &rptr, 0);
2360ef97810SDavid du Colombier if(rptr == nil || rptr == p || *rptr != '-'){
2370ef97810SDavid du Colombier print("umbexclude: invalid argument <%s>\n", op);
2380ef97810SDavid du Colombier break;
2390ef97810SDavid du Colombier }
2400ef97810SDavid du Colombier p = rptr+1;
2410ef97810SDavid du Colombier
2420ef97810SDavid du Colombier size = strtoul(p, &rptr, 0) - addr + 1;
2430ef97810SDavid du Colombier if(size <= 0){
2440ef97810SDavid du Colombier print("umbexclude: bad range <%s>\n", op);
2450ef97810SDavid du Colombier break;
2460ef97810SDavid du Colombier }
2470ef97810SDavid du Colombier if(rptr != nil && *rptr == ',')
2480ef97810SDavid du Colombier *rptr++ = '\0';
2490ef97810SDavid du Colombier p = rptr;
2500ef97810SDavid du Colombier
2510ef97810SDavid du Colombier mapalloc(&rmapumb, addr, size, 0);
2520ef97810SDavid du Colombier }
2530ef97810SDavid du Colombier }
2540ef97810SDavid du Colombier
2550ef97810SDavid du Colombier static void
umbscan(void)2567dd7cddfSDavid du Colombier umbscan(void)
2577dd7cddfSDavid du Colombier {
258f7db6155SDavid du Colombier uchar o[2], *p;
2597dd7cddfSDavid du Colombier
2607dd7cddfSDavid du Colombier /*
2617dd7cddfSDavid du Colombier * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
2627dd7cddfSDavid du Colombier * which aren't used; they can be used later for devices which
2637dd7cddfSDavid du Colombier * want to allocate some virtual address space.
2647dd7cddfSDavid du Colombier * Check for two things:
2657dd7cddfSDavid du Colombier * 1) device BIOS ROM. This should start with a two-byte header
2667dd7cddfSDavid du Colombier * of 0x55 0xAA, followed by a byte giving the size of the ROM
2677dd7cddfSDavid du Colombier * in 512-byte chunks. These ROM's must start on a 2KB boundary.
2687dd7cddfSDavid du Colombier * 2) device memory. This is read-write.
2697dd7cddfSDavid du Colombier * There are some assumptions: there's VGA memory at 0xA0000 and
2707dd7cddfSDavid du Colombier * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
2717dd7cddfSDavid du Colombier * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up
2727dd7cddfSDavid du Colombier * for grabs; check anyway.
2737dd7cddfSDavid du Colombier */
2743ff48bf5SDavid du Colombier p = KADDR(0xD0000);
2757dd7cddfSDavid du Colombier while(p < (uchar*)KADDR(0xE0000)){
2769a747e4fSDavid du Colombier /*
277f7db6155SDavid du Colombier * Check for the ROM signature, skip if valid.
2789a747e4fSDavid du Colombier */
2799a747e4fSDavid du Colombier if(p[0] == 0x55 && p[1] == 0xAA){
2809a747e4fSDavid du Colombier p += p[2]*512;
2819a747e4fSDavid du Colombier continue;
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier
284f7db6155SDavid du Colombier /*
285f7db6155SDavid du Colombier * Is it writeable? If yes, then stick it in
286f7db6155SDavid du Colombier * the UMB device memory map. A floating bus will
287f7db6155SDavid du Colombier * return 0xff, so add that to the map of the
288f7db6155SDavid du Colombier * UMB space available for allocation.
289f7db6155SDavid du Colombier * If it is neither of those, ignore it.
290f7db6155SDavid du Colombier */
291f7db6155SDavid du Colombier o[0] = p[0];
2927dd7cddfSDavid du Colombier p[0] = 0xCC;
293f7db6155SDavid du Colombier o[1] = p[2*KB-1];
2947dd7cddfSDavid du Colombier p[2*KB-1] = 0xCC;
295f7db6155SDavid du Colombier if(p[0] == 0xCC && p[2*KB-1] == 0xCC){
296f7db6155SDavid du Colombier p[0] = o[0];
297f7db6155SDavid du Colombier p[2*KB-1] = o[1];
2987dd7cddfSDavid du Colombier mapfree(&rmapumbrw, PADDR(p), 2*KB);
299f7db6155SDavid du Colombier }
300f7db6155SDavid du Colombier else if(p[0] == 0xFF && p[1] == 0xFF)
301f7db6155SDavid du Colombier mapfree(&rmapumb, PADDR(p), 2*KB);
3027dd7cddfSDavid du Colombier p += 2*KB;
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier
3057dd7cddfSDavid du Colombier p = KADDR(0xE0000);
3067dd7cddfSDavid du Colombier if(p[0] != 0x55 || p[1] != 0xAA){
3077dd7cddfSDavid du Colombier p[0] = 0xCC;
3087dd7cddfSDavid du Colombier p[64*KB-1] = 0xCC;
3097dd7cddfSDavid du Colombier if(p[0] != 0xCC && p[64*KB-1] != 0xCC)
3107dd7cddfSDavid du Colombier mapfree(&rmapumb, PADDR(p), 64*KB);
3117dd7cddfSDavid du Colombier }
3120ef97810SDavid du Colombier
3130ef97810SDavid du Colombier umbexclude();
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier
316*00a4193cSDavid du Colombier static void*
sigscan(uchar * addr,int len,char * signature)317*00a4193cSDavid du Colombier sigscan(uchar* addr, int len, char* signature)
318*00a4193cSDavid du Colombier {
319*00a4193cSDavid du Colombier int sl;
320*00a4193cSDavid du Colombier uchar *e, *p;
321*00a4193cSDavid du Colombier
322*00a4193cSDavid du Colombier e = addr+len;
323*00a4193cSDavid du Colombier sl = strlen(signature);
324*00a4193cSDavid du Colombier for(p = addr; p+sl < e; p += 16)
325*00a4193cSDavid du Colombier if(memcmp(p, signature, sl) == 0)
326*00a4193cSDavid du Colombier return p;
327*00a4193cSDavid du Colombier return nil;
328*00a4193cSDavid du Colombier }
329*00a4193cSDavid du Colombier
330*00a4193cSDavid du Colombier void*
sigsearch(char * signature)331*00a4193cSDavid du Colombier sigsearch(char* signature)
332*00a4193cSDavid du Colombier {
333*00a4193cSDavid du Colombier uintptr p;
334*00a4193cSDavid du Colombier uchar *bda;
335*00a4193cSDavid du Colombier void *r;
336*00a4193cSDavid du Colombier
337*00a4193cSDavid du Colombier /*
338*00a4193cSDavid du Colombier * Search for the data structure:
339*00a4193cSDavid du Colombier * 1) within the first KiB of the Extended BIOS Data Area (EBDA), or
340*00a4193cSDavid du Colombier * 2) within the last KiB of system base memory if the EBDA segment
341*00a4193cSDavid du Colombier * is undefined, or
342*00a4193cSDavid du Colombier * 3) within the BIOS ROM address space between 0xf0000 and 0xfffff
343*00a4193cSDavid du Colombier * (but will actually check 0xe0000 to 0xfffff).
344*00a4193cSDavid du Colombier */
345*00a4193cSDavid du Colombier bda = BIOSSEG(0x40);
346*00a4193cSDavid du Colombier if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){
347*00a4193cSDavid du Colombier if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){
348*00a4193cSDavid du Colombier if((r = sigscan(BIOSSEG(p), 1024, signature)) != nil)
349*00a4193cSDavid du Colombier return r;
350*00a4193cSDavid du Colombier }
351*00a4193cSDavid du Colombier }
352*00a4193cSDavid du Colombier
353*00a4193cSDavid du Colombier if((p = ((bda[0x14]<<8)|bda[0x13])*1024) != 0){
354*00a4193cSDavid du Colombier if((r = sigscan(KADDR(p-1024), 1024, signature)) != nil)
355*00a4193cSDavid du Colombier return r;
356*00a4193cSDavid du Colombier }
357*00a4193cSDavid du Colombier /* hack for virtualbox: look in KiB below 0xa0000 */
358*00a4193cSDavid du Colombier if((r = sigscan(KADDR(0xa0000-1024), 1024, signature)) != nil)
359*00a4193cSDavid du Colombier return r;
360*00a4193cSDavid du Colombier
361*00a4193cSDavid du Colombier return sigscan(BIOSSEG(0xe000), 0x20000, signature);
362*00a4193cSDavid du Colombier }
363*00a4193cSDavid du Colombier
3647dd7cddfSDavid du Colombier static void
lowraminit(void)3654de34a7eSDavid du Colombier lowraminit(void)
3667dd7cddfSDavid du Colombier {
3674de34a7eSDavid du Colombier ulong n, pa, x;
3687dd7cddfSDavid du Colombier uchar *bda;
3697dd7cddfSDavid du Colombier
3707dd7cddfSDavid du Colombier /*
3717dd7cddfSDavid du Colombier * Initialise the memory bank information for conventional memory
3727dd7cddfSDavid du Colombier * (i.e. less than 640KB). The base is the first location after the
3737dd7cddfSDavid du Colombier * bootstrap processor MMU information and the limit is obtained from
3747dd7cddfSDavid du Colombier * the BIOS data area.
3757dd7cddfSDavid du Colombier */
3768f5875f3SDavid du Colombier x = PADDR(CPU0END);
3777dd7cddfSDavid du Colombier bda = (uchar*)KADDR(0x400);
3789a747e4fSDavid du Colombier n = ((bda[0x14]<<8)|bda[0x13])*KB-x;
3799a747e4fSDavid du Colombier mapfree(&rmapram, x, n);
3809a747e4fSDavid du Colombier memset(KADDR(x), 0, n); /* keep us honest */
3817dd7cddfSDavid du Colombier
3827dd7cddfSDavid du Colombier x = PADDR(PGROUND((ulong)end));
3838f5875f3SDavid du Colombier pa = MemMin;
3848f5875f3SDavid du Colombier if(x > pa)
3858f5875f3SDavid du Colombier panic("kernel too big");
3867dd7cddfSDavid du Colombier mapfree(&rmapram, x, pa-x);
3879a747e4fSDavid du Colombier memset(KADDR(x), 0, pa-x); /* keep us honest */
3884de34a7eSDavid du Colombier }
3894de34a7eSDavid du Colombier
3904de34a7eSDavid du Colombier static void
ramscan(ulong maxmem)3914de34a7eSDavid du Colombier ramscan(ulong maxmem)
3924de34a7eSDavid du Colombier {
3934de34a7eSDavid du Colombier ulong *k0, kzero, map, maxkpa, maxpa, pa, *pte, *table, *va, vbase, x;
3944de34a7eSDavid du Colombier int nvalid[NMemType];
3954de34a7eSDavid du Colombier
3964de34a7eSDavid du Colombier /*
3974de34a7eSDavid du Colombier * The bootstrap code has has created a prototype page
3988f5875f3SDavid du Colombier * table which maps the first MemMin of physical memory to KZERO.
3994de34a7eSDavid du Colombier * The page directory is at m->pdb and the first page of
4004de34a7eSDavid du Colombier * free memory is after the per-processor MMU information.
4014de34a7eSDavid du Colombier */
4028f5875f3SDavid du Colombier pa = MemMin;
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier /*
4057dd7cddfSDavid du Colombier * Check if the extended memory size can be obtained from the CMOS.
4067dd7cddfSDavid du Colombier * If it's 0 then it's either not known or >= 64MB. Always check
4077dd7cddfSDavid du Colombier * at least 24MB in case there's a memory gap (up to 8MB) below 16MB;
4087dd7cddfSDavid du Colombier * in this case the memory from the gap is remapped to the top of
4097dd7cddfSDavid du Colombier * memory.
4107dd7cddfSDavid du Colombier * The value in CMOS is supposed to be the number of KB above 1MB.
4117dd7cddfSDavid du Colombier */
4127dd7cddfSDavid du Colombier if(maxmem == 0){
4137dd7cddfSDavid du Colombier x = (nvramread(0x18)<<8)|nvramread(0x17);
4147dd7cddfSDavid du Colombier if(x == 0 || x >= (63*KB))
4158f5875f3SDavid du Colombier maxpa = MemMax;
4167dd7cddfSDavid du Colombier else
4177dd7cddfSDavid du Colombier maxpa = MB+x*KB;
4187dd7cddfSDavid du Colombier if(maxpa < 24*MB)
4197dd7cddfSDavid du Colombier maxpa = 24*MB;
4204de34a7eSDavid du Colombier }else
4217dd7cddfSDavid du Colombier maxpa = maxmem;
4224de34a7eSDavid du Colombier maxkpa = (u32int)-KZERO; /* 2^32 - KZERO */
4237dd7cddfSDavid du Colombier
4247dd7cddfSDavid du Colombier /*
4258f5875f3SDavid du Colombier * March up memory from MemMin to maxpa 1MB at a time,
4267dd7cddfSDavid du Colombier * mapping the first page and checking the page can
4277dd7cddfSDavid du Colombier * be written and read correctly. The page tables are created here
4287dd7cddfSDavid du Colombier * on the fly, allocating from low memory as necessary.
4297dd7cddfSDavid du Colombier */
4307dd7cddfSDavid du Colombier k0 = (ulong*)KADDR(0);
4317dd7cddfSDavid du Colombier kzero = *k0;
4327dd7cddfSDavid du Colombier map = 0;
4337dd7cddfSDavid du Colombier x = 0x12345678;
4347dd7cddfSDavid du Colombier memset(nvalid, 0, sizeof(nvalid));
4354de34a7eSDavid du Colombier
4364de34a7eSDavid du Colombier /*
4374de34a7eSDavid du Colombier * Can't map memory to KADDR(pa) when we're walking because
4388f5875f3SDavid du Colombier * can only use KADDR for relatively low addresses.
4398f5875f3SDavid du Colombier * Instead, map each 4MB we scan to the virtual address range
4408f5875f3SDavid du Colombier * MemMin->MemMin+4MB while we are scanning.
4414de34a7eSDavid du Colombier */
4428f5875f3SDavid du Colombier vbase = MemMin;
4437dd7cddfSDavid du Colombier while(pa < maxpa){
4447dd7cddfSDavid du Colombier /*
4457dd7cddfSDavid du Colombier * Map the page. Use mapalloc(&rmapram, ...) to make
4467dd7cddfSDavid du Colombier * the page table if necessary, it will be returned to the
4474de34a7eSDavid du Colombier * pool later if it isn't needed. Map in a fixed range (the second 4M)
4484de34a7eSDavid du Colombier * because high physical addresses cannot be passed to KADDR.
4497dd7cddfSDavid du Colombier */
4504de34a7eSDavid du Colombier va = (void*)(vbase + pa%(4*MB));
4517dd7cddfSDavid du Colombier table = &m->pdb[PDX(va)];
4524de34a7eSDavid du Colombier if(pa%(4*MB) == 0){
4537dd7cddfSDavid du Colombier if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
4547dd7cddfSDavid du Colombier break;
4557dd7cddfSDavid du Colombier memset(KADDR(map), 0, BY2PG);
4567dd7cddfSDavid du Colombier *table = map|PTEWRITE|PTEVALID;
4577dd7cddfSDavid du Colombier memset(nvalid, 0, sizeof(nvalid));
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier table = KADDR(PPN(*table));
4607dd7cddfSDavid du Colombier pte = &table[PTX(va)];
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
4637dd7cddfSDavid du Colombier mmuflushtlb(PADDR(m->pdb));
4647dd7cddfSDavid du Colombier /*
4657dd7cddfSDavid du Colombier * Write a pattern to the page and write a different
4664de34a7eSDavid du Colombier * pattern to a possible mirror at KZERO. If the data
4677dd7cddfSDavid du Colombier * reads back correctly the chunk is some type of RAM (possibly
4687dd7cddfSDavid du Colombier * a linearly-mapped VGA framebuffer, for instance...) and
4697dd7cddfSDavid du Colombier * can be cleared and added to the memory pool. If not, the
4707dd7cddfSDavid du Colombier * chunk is marked uncached and added to the UMB pool if <16MB
4717dd7cddfSDavid du Colombier * or is marked invalid and added to the UPA pool.
4727dd7cddfSDavid du Colombier */
4737dd7cddfSDavid du Colombier *va = x;
4747dd7cddfSDavid du Colombier *k0 = ~x;
4757dd7cddfSDavid du Colombier if(*va == x){
4767dd7cddfSDavid du Colombier nvalid[MemRAM] += MB/BY2PG;
4777dd7cddfSDavid du Colombier mapfree(&rmapram, pa, MB);
4787dd7cddfSDavid du Colombier
4797dd7cddfSDavid du Colombier do{
4807dd7cddfSDavid du Colombier *pte++ = pa|PTEWRITE|PTEVALID;
4817dd7cddfSDavid du Colombier pa += BY2PG;
4827dd7cddfSDavid du Colombier }while(pa % MB);
4837dd7cddfSDavid du Colombier mmuflushtlb(PADDR(m->pdb));
4849a747e4fSDavid du Colombier /* memset(va, 0, MB); so damn slow to memset all of memory */
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier else if(pa < 16*MB){
4877dd7cddfSDavid du Colombier nvalid[MemUMB] += MB/BY2PG;
4887dd7cddfSDavid du Colombier mapfree(&rmapumb, pa, MB);
4897dd7cddfSDavid du Colombier
4907dd7cddfSDavid du Colombier do{
4917dd7cddfSDavid du Colombier *pte++ = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
4927dd7cddfSDavid du Colombier pa += BY2PG;
4937dd7cddfSDavid du Colombier }while(pa % MB);
4947dd7cddfSDavid du Colombier }
4957dd7cddfSDavid du Colombier else{
4967dd7cddfSDavid du Colombier nvalid[MemUPA] += MB/BY2PG;
4977dd7cddfSDavid du Colombier mapfree(&rmapupa, pa, MB);
4987dd7cddfSDavid du Colombier
4997dd7cddfSDavid du Colombier *pte = 0;
5007dd7cddfSDavid du Colombier pa += MB;
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier /*
5037dd7cddfSDavid du Colombier * Done with this 4MB chunk, review the options:
5047dd7cddfSDavid du Colombier * 1) not physical memory and >=16MB - invalidate the PDB entry;
5057dd7cddfSDavid du Colombier * 2) physical memory - use the 4MB page extension if possible;
5067dd7cddfSDavid du Colombier * 3) not physical memory and <16MB - use the 4MB page extension
5077dd7cddfSDavid du Colombier * if possible;
5087dd7cddfSDavid du Colombier * 4) mixed or no 4MB page extension - commit the already
5097dd7cddfSDavid du Colombier * initialised space for the page table.
5107dd7cddfSDavid du Colombier */
5114de34a7eSDavid du Colombier if(pa%(4*MB) == 0 && pa >= 32*MB && nvalid[MemUPA] == (4*MB)/BY2PG){
5124de34a7eSDavid du Colombier /*
5134de34a7eSDavid du Colombier * If we encounter a 4MB chunk of missing memory
5144de34a7eSDavid du Colombier * at a sufficiently high offset, call it the end of
5154de34a7eSDavid du Colombier * memory. Otherwise we run the risk of thinking
5164de34a7eSDavid du Colombier * that video memory is real RAM.
5174de34a7eSDavid du Colombier */
5184de34a7eSDavid du Colombier break;
5194de34a7eSDavid du Colombier }
5204de34a7eSDavid du Colombier if(pa <= maxkpa && pa%(4*MB) == 0){
5214de34a7eSDavid du Colombier table = &m->pdb[PDX(KADDR(pa - 4*MB))];
5227dd7cddfSDavid du Colombier if(nvalid[MemUPA] == (4*MB)/BY2PG)
5237dd7cddfSDavid du Colombier *table = 0;
5247dd7cddfSDavid du Colombier else if(nvalid[MemRAM] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
5257dd7cddfSDavid du Colombier *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEVALID;
5267dd7cddfSDavid du Colombier else if(nvalid[MemUMB] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
5277dd7cddfSDavid du Colombier *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
5284de34a7eSDavid du Colombier else{
5294de34a7eSDavid du Colombier *table = map|PTEWRITE|PTEVALID;
5307dd7cddfSDavid du Colombier map = 0;
5317dd7cddfSDavid du Colombier }
5324de34a7eSDavid du Colombier }
5337dd7cddfSDavid du Colombier mmuflushtlb(PADDR(m->pdb));
5347dd7cddfSDavid du Colombier x += 0x3141526;
5357dd7cddfSDavid du Colombier }
5369a747e4fSDavid du Colombier /*
5379a747e4fSDavid du Colombier * If we didn't reach the end of the 4MB chunk, that part won't
5389a747e4fSDavid du Colombier * be mapped. Commit the already initialised space for the page table.
5399a747e4fSDavid du Colombier */
5404de34a7eSDavid du Colombier if(pa % (4*MB) && pa <= maxkpa){
5414de34a7eSDavid du Colombier m->pdb[PDX(KADDR(pa))] = map|PTEWRITE|PTEVALID;
5429a747e4fSDavid du Colombier map = 0;
5434de34a7eSDavid du Colombier }
5447dd7cddfSDavid du Colombier if(map)
5457dd7cddfSDavid du Colombier mapfree(&rmapram, map, BY2PG);
5464de34a7eSDavid du Colombier
5474de34a7eSDavid du Colombier m->pdb[PDX(vbase)] = 0;
5484de34a7eSDavid du Colombier mmuflushtlb(PADDR(m->pdb));
5494de34a7eSDavid du Colombier
5504de34a7eSDavid du Colombier mapfree(&rmapupa, pa, (u32int)-pa);
5517dd7cddfSDavid du Colombier *k0 = kzero;
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier
5544de34a7eSDavid du Colombier /*
5554de34a7eSDavid du Colombier * BIOS Int 0x15 E820 memory map.
5564de34a7eSDavid du Colombier */
5574de34a7eSDavid du Colombier enum
5584de34a7eSDavid du Colombier {
5594de34a7eSDavid du Colombier SMAP = ('S'<<24)|('M'<<16)|('A'<<8)|'P',
5604de34a7eSDavid du Colombier Ememory = 1,
5614de34a7eSDavid du Colombier Ereserved = 2,
5624de34a7eSDavid du Colombier Carry = 1,
5634de34a7eSDavid du Colombier };
5644de34a7eSDavid du Colombier
5654de34a7eSDavid du Colombier typedef struct Emap Emap;
5664de34a7eSDavid du Colombier struct Emap
5674de34a7eSDavid du Colombier {
5684de34a7eSDavid du Colombier uvlong base;
5694de34a7eSDavid du Colombier uvlong len;
5704de34a7eSDavid du Colombier ulong type;
5714de34a7eSDavid du Colombier };
5724de34a7eSDavid du Colombier static Emap emap[16];
5734de34a7eSDavid du Colombier int nemap;
5744de34a7eSDavid du Colombier
5754de34a7eSDavid du Colombier static char *etypes[] =
5764de34a7eSDavid du Colombier {
5774de34a7eSDavid du Colombier "type=0",
5784de34a7eSDavid du Colombier "memory",
5794de34a7eSDavid du Colombier "reserved",
5804de34a7eSDavid du Colombier "acpi reclaim",
5814de34a7eSDavid du Colombier "acpi nvs",
5824de34a7eSDavid du Colombier };
5834de34a7eSDavid du Colombier
5844de34a7eSDavid du Colombier static int
emapcmp(const void * va,const void * vb)5854de34a7eSDavid du Colombier emapcmp(const void *va, const void *vb)
5864de34a7eSDavid du Colombier {
5874de34a7eSDavid du Colombier Emap *a, *b;
5884de34a7eSDavid du Colombier
5894de34a7eSDavid du Colombier a = (Emap*)va;
5904de34a7eSDavid du Colombier b = (Emap*)vb;
5914de34a7eSDavid du Colombier if(a->base < b->base)
5924de34a7eSDavid du Colombier return -1;
5934de34a7eSDavid du Colombier if(a->base > b->base)
5944de34a7eSDavid du Colombier return 1;
5954de34a7eSDavid du Colombier if(a->len < b->len)
5964de34a7eSDavid du Colombier return -1;
5974de34a7eSDavid du Colombier if(a->len > b->len)
5984de34a7eSDavid du Colombier return 1;
5994de34a7eSDavid du Colombier return a->type - b->type;
6004de34a7eSDavid du Colombier }
6014de34a7eSDavid du Colombier
6024de34a7eSDavid du Colombier static void
map(ulong base,ulong len,int type)6034de34a7eSDavid du Colombier map(ulong base, ulong len, int type)
6044de34a7eSDavid du Colombier {
6054de34a7eSDavid du Colombier ulong e, n;
6064de34a7eSDavid du Colombier ulong *table, flags, maxkpa;
6074de34a7eSDavid du Colombier
6084de34a7eSDavid du Colombier /*
6098f5875f3SDavid du Colombier * Split any call crossing MemMin to make below simpler.
6104de34a7eSDavid du Colombier */
6118f5875f3SDavid du Colombier if(base < MemMin && len > MemMin-base){
6128f5875f3SDavid du Colombier n = MemMin - base;
6134de34a7eSDavid du Colombier map(base, n, type);
6148f5875f3SDavid du Colombier map(MemMin, len-n, type);
6154de34a7eSDavid du Colombier }
6164de34a7eSDavid du Colombier
6174de34a7eSDavid du Colombier /*
6188f5875f3SDavid du Colombier * Let lowraminit and umbscan hash out the low MemMin.
6194de34a7eSDavid du Colombier */
6208f5875f3SDavid du Colombier if(base < MemMin)
6214de34a7eSDavid du Colombier return;
6224de34a7eSDavid du Colombier
6234de34a7eSDavid du Colombier /*
6244de34a7eSDavid du Colombier * Any non-memory below 16*MB is used as upper mem blocks.
6254de34a7eSDavid du Colombier */
6264de34a7eSDavid du Colombier if(type == MemUPA && base < 16*MB && base+len > 16*MB){
6274de34a7eSDavid du Colombier map(base, 16*MB-base, MemUMB);
6284de34a7eSDavid du Colombier map(16*MB, len-(16*MB-base), MemUPA);
6294de34a7eSDavid du Colombier return;
6304de34a7eSDavid du Colombier }
6314de34a7eSDavid du Colombier
6324de34a7eSDavid du Colombier /*
6338f5875f3SDavid du Colombier * Memory below CPU0END is reserved for the kernel
6344de34a7eSDavid du Colombier * and already mapped.
6354de34a7eSDavid du Colombier */
6368f5875f3SDavid du Colombier if(base < PADDR(CPU0END)){
6378f5875f3SDavid du Colombier n = PADDR(CPU0END) - base;
6384de34a7eSDavid du Colombier if(len <= n)
6394de34a7eSDavid du Colombier return;
6408f5875f3SDavid du Colombier map(PADDR(CPU0END), len-n, type);
6414de34a7eSDavid du Colombier return;
6424de34a7eSDavid du Colombier }
6434de34a7eSDavid du Colombier
6444de34a7eSDavid du Colombier /*
6454de34a7eSDavid du Colombier * Memory between KTZERO and end is the kernel itself
6464de34a7eSDavid du Colombier * and is already mapped.
6474de34a7eSDavid du Colombier */
6484de34a7eSDavid du Colombier if(base < PADDR(KTZERO) && base+len > PADDR(KTZERO)){
6494de34a7eSDavid du Colombier map(base, PADDR(KTZERO)-base, type);
6504de34a7eSDavid du Colombier return;
6514de34a7eSDavid du Colombier }
6524de34a7eSDavid du Colombier if(PADDR(KTZERO) < base && base < PADDR(PGROUND((ulong)end))){
6534de34a7eSDavid du Colombier n = PADDR(PGROUND((ulong)end));
6544de34a7eSDavid du Colombier if(len <= n)
6554de34a7eSDavid du Colombier return;
6564de34a7eSDavid du Colombier map(PADDR(PGROUND((ulong)end)), len-n, type);
6574de34a7eSDavid du Colombier return;
6584de34a7eSDavid du Colombier }
6594de34a7eSDavid du Colombier
6604de34a7eSDavid du Colombier /*
6614de34a7eSDavid du Colombier * Now we have a simple case.
6624de34a7eSDavid du Colombier */
6634de34a7eSDavid du Colombier // print("map %.8lux %.8lux %d\n", base, base+len, type);
6644de34a7eSDavid du Colombier switch(type){
6654de34a7eSDavid du Colombier case MemRAM:
6664de34a7eSDavid du Colombier mapfree(&rmapram, base, len);
6675f61b043SDavid du Colombier flags = PTEWRITE|PTEVALID;
6684de34a7eSDavid du Colombier break;
6694de34a7eSDavid du Colombier case MemUMB:
6704de34a7eSDavid du Colombier mapfree(&rmapumb, base, len);
6715f61b043SDavid du Colombier flags = PTEWRITE|PTEUNCACHED|PTEVALID;
6724de34a7eSDavid du Colombier break;
6734de34a7eSDavid du Colombier case MemUPA:
6744de34a7eSDavid du Colombier mapfree(&rmapupa, base, len);
6755f61b043SDavid du Colombier flags = 0;
6764de34a7eSDavid du Colombier break;
6774de34a7eSDavid du Colombier default:
6784de34a7eSDavid du Colombier case MemReserved:
6795f61b043SDavid du Colombier flags = 0;
6804de34a7eSDavid du Colombier break;
6814de34a7eSDavid du Colombier }
6824de34a7eSDavid du Colombier
6834de34a7eSDavid du Colombier /*
6848f5875f3SDavid du Colombier * bottom MemMin is already mapped - just twiddle flags.
6854de34a7eSDavid du Colombier * (not currently used - see above)
6864de34a7eSDavid du Colombier */
6878f5875f3SDavid du Colombier if(base < MemMin){
6884de34a7eSDavid du Colombier table = KADDR(PPN(m->pdb[PDX(base)]));
6894de34a7eSDavid du Colombier e = base+len;
6904de34a7eSDavid du Colombier base = PPN(base);
6914de34a7eSDavid du Colombier for(; base<e; base+=BY2PG)
6924de34a7eSDavid du Colombier table[PTX(base)] |= flags;
6934de34a7eSDavid du Colombier return;
6944de34a7eSDavid du Colombier }
6954de34a7eSDavid du Colombier
6964de34a7eSDavid du Colombier /*
6974de34a7eSDavid du Colombier * Only map from KZERO to 2^32.
6984de34a7eSDavid du Colombier */
6995f61b043SDavid du Colombier if(flags){
7004de34a7eSDavid du Colombier maxkpa = -KZERO;
7014de34a7eSDavid du Colombier if(base >= maxkpa)
7024de34a7eSDavid du Colombier return;
7034de34a7eSDavid du Colombier if(len > maxkpa-base)
7044de34a7eSDavid du Colombier len = maxkpa - base;
7054de34a7eSDavid du Colombier pdbmap(m->pdb, base|flags, base+KZERO, len);
7064de34a7eSDavid du Colombier }
7075f61b043SDavid du Colombier }
7084de34a7eSDavid du Colombier
7094de34a7eSDavid du Colombier static int
e820scan(void)7104de34a7eSDavid du Colombier e820scan(void)
7114de34a7eSDavid du Colombier {
7124de34a7eSDavid du Colombier int i;
7134de34a7eSDavid du Colombier Ureg u;
714ea15f0ccSDavid du Colombier ulong cont, base, len;
715ea15f0ccSDavid du Colombier uvlong last;
7164de34a7eSDavid du Colombier Emap *e;
7174de34a7eSDavid du Colombier
7184de34a7eSDavid du Colombier if(getconf("*norealmode") || getconf("*noe820scan"))
7194de34a7eSDavid du Colombier return -1;
7204de34a7eSDavid du Colombier
7214de34a7eSDavid du Colombier cont = 0;
7224de34a7eSDavid du Colombier for(i=0; i<nelem(emap); i++){
7234de34a7eSDavid du Colombier memset(&u, 0, sizeof u);
7244de34a7eSDavid du Colombier u.ax = 0xE820;
7254de34a7eSDavid du Colombier u.bx = cont;
7264de34a7eSDavid du Colombier u.cx = 20;
7274de34a7eSDavid du Colombier u.dx = SMAP;
7284de34a7eSDavid du Colombier u.es = (PADDR(RMBUF)>>4)&0xF000;
7294de34a7eSDavid du Colombier u.di = PADDR(RMBUF)&0xFFFF;
7304de34a7eSDavid du Colombier u.trap = 0x15;
7314de34a7eSDavid du Colombier realmode(&u);
7324de34a7eSDavid du Colombier cont = u.bx;
7334de34a7eSDavid du Colombier if((u.flags&Carry) || u.ax != SMAP || u.cx != 20)
7344de34a7eSDavid du Colombier break;
7354de34a7eSDavid du Colombier e = &emap[nemap++];
7364de34a7eSDavid du Colombier *e = *(Emap*)RMBUF;
7374de34a7eSDavid du Colombier if(u.bx == 0)
7384de34a7eSDavid du Colombier break;
7394de34a7eSDavid du Colombier }
7404de34a7eSDavid du Colombier if(nemap == 0)
7414de34a7eSDavid du Colombier return -1;
7424de34a7eSDavid du Colombier
7434de34a7eSDavid du Colombier qsort(emap, nemap, sizeof emap[0], emapcmp);
7444de34a7eSDavid du Colombier
745225077b0SDavid du Colombier if(getconf("*noe820print") == nil){
7464de34a7eSDavid du Colombier for(i=0; i<nemap; i++){
7474de34a7eSDavid du Colombier e = &emap[i];
7484de34a7eSDavid du Colombier print("E820: %.8llux %.8llux ", e->base, e->base+e->len);
7494de34a7eSDavid du Colombier if(e->type < nelem(etypes))
7504de34a7eSDavid du Colombier print("%s\n", etypes[e->type]);
7514de34a7eSDavid du Colombier else
7524de34a7eSDavid du Colombier print("type=%lud\n", e->type);
7534de34a7eSDavid du Colombier }
754225077b0SDavid du Colombier }
7554de34a7eSDavid du Colombier
7564de34a7eSDavid du Colombier last = 0;
7574de34a7eSDavid du Colombier for(i=0; i<nemap; i++){
7584de34a7eSDavid du Colombier e = &emap[i];
7594de34a7eSDavid du Colombier /*
7604de34a7eSDavid du Colombier * pull out the info but only about the low 32 bits...
7614de34a7eSDavid du Colombier */
7624de34a7eSDavid du Colombier if(e->base >= (1LL<<32))
7634de34a7eSDavid du Colombier break;
7644de34a7eSDavid du Colombier base = e->base;
7654de34a7eSDavid du Colombier if(base+e->len > (1LL<<32))
7664de34a7eSDavid du Colombier len = -base;
7674de34a7eSDavid du Colombier else
7684de34a7eSDavid du Colombier len = e->len;
7694de34a7eSDavid du Colombier /*
7704de34a7eSDavid du Colombier * If the map skips addresses, mark them available.
7714de34a7eSDavid du Colombier */
7724de34a7eSDavid du Colombier if(last < e->base)
7734de34a7eSDavid du Colombier map(last, e->base-last, MemUPA);
7744de34a7eSDavid du Colombier last = base+len;
7754de34a7eSDavid du Colombier if(e->type == Ememory)
7764de34a7eSDavid du Colombier map(base, len, MemRAM);
7774de34a7eSDavid du Colombier else
7784de34a7eSDavid du Colombier map(base, len, MemReserved);
7794de34a7eSDavid du Colombier }
780ea15f0ccSDavid du Colombier if(last < (1LL<<32))
781ea15f0ccSDavid du Colombier map(last, (u32int)-last, MemUPA);
7824de34a7eSDavid du Colombier return 0;
7834de34a7eSDavid du Colombier }
7844de34a7eSDavid du Colombier
7857dd7cddfSDavid du Colombier void
meminit(void)7869a747e4fSDavid du Colombier meminit(void)
7877dd7cddfSDavid du Colombier {
7884de34a7eSDavid du Colombier int i;
7894de34a7eSDavid du Colombier Map *mp;
7904de34a7eSDavid du Colombier Confmem *cm;
7917dd7cddfSDavid du Colombier ulong pa, *pte;
7924de34a7eSDavid du Colombier ulong maxmem, lost;
7939a747e4fSDavid du Colombier char *p;
7949a747e4fSDavid du Colombier
7959a747e4fSDavid du Colombier if(p = getconf("*maxmem"))
7969a747e4fSDavid du Colombier maxmem = strtoul(p, 0, 0);
7979a747e4fSDavid du Colombier else
7989a747e4fSDavid du Colombier maxmem = 0;
7997dd7cddfSDavid du Colombier
8007dd7cddfSDavid du Colombier /*
8017dd7cddfSDavid du Colombier * Set special attributes for memory between 640KB and 1MB:
8027dd7cddfSDavid du Colombier * VGA memory is writethrough;
8037dd7cddfSDavid du Colombier * BIOS ROM's/UMB's are uncached;
8047dd7cddfSDavid du Colombier * then scan for useful memory.
8057dd7cddfSDavid du Colombier */
8067dd7cddfSDavid du Colombier for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){
8077dd7cddfSDavid du Colombier pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
8087dd7cddfSDavid du Colombier *pte |= PTEWT;
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){
8117dd7cddfSDavid du Colombier pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
8127dd7cddfSDavid du Colombier *pte |= PTEUNCACHED;
8137dd7cddfSDavid du Colombier }
8147dd7cddfSDavid du Colombier mmuflushtlb(PADDR(m->pdb));
8157dd7cddfSDavid du Colombier
8167dd7cddfSDavid du Colombier umbscan();
8174de34a7eSDavid du Colombier lowraminit();
8184de34a7eSDavid du Colombier if(e820scan() < 0)
8197dd7cddfSDavid du Colombier ramscan(maxmem);
8207dd7cddfSDavid du Colombier
8217dd7cddfSDavid du Colombier /*
8224de34a7eSDavid du Colombier * Set the conf entries describing banks of allocatable memory.
8237dd7cddfSDavid du Colombier */
8244de34a7eSDavid du Colombier for(i=0; i<nelem(mapram) && i<nelem(conf.mem); i++){
8254de34a7eSDavid du Colombier mp = &rmapram.map[i];
8264de34a7eSDavid du Colombier cm = &conf.mem[i];
8274de34a7eSDavid du Colombier cm->base = mp->addr;
8284de34a7eSDavid du Colombier cm->npage = mp->size/BY2PG;
8297dd7cddfSDavid du Colombier }
8307dd7cddfSDavid du Colombier
8314de34a7eSDavid du Colombier lost = 0;
8324de34a7eSDavid du Colombier for(; i<nelem(mapram); i++)
8334de34a7eSDavid du Colombier lost += rmapram.map[i].size;
8344de34a7eSDavid du Colombier if(lost)
8354de34a7eSDavid du Colombier print("meminit - lost %lud bytes\n", lost);
8364de34a7eSDavid du Colombier
8377dd7cddfSDavid du Colombier if(MEMDEBUG)
8387dd7cddfSDavid du Colombier memdebug();
8397dd7cddfSDavid du Colombier }
8407dd7cddfSDavid du Colombier
8414de34a7eSDavid du Colombier /*
8424de34a7eSDavid du Colombier * Allocate memory from the upper memory blocks.
8434de34a7eSDavid du Colombier */
8447dd7cddfSDavid du Colombier ulong
umbmalloc(ulong addr,int size,int align)8457dd7cddfSDavid du Colombier umbmalloc(ulong addr, int size, int align)
8467dd7cddfSDavid du Colombier {
8477dd7cddfSDavid du Colombier ulong a;
8487dd7cddfSDavid du Colombier
8497dd7cddfSDavid du Colombier if(a = mapalloc(&rmapumb, addr, size, align))
8507dd7cddfSDavid du Colombier return (ulong)KADDR(a);
8517dd7cddfSDavid du Colombier
8527dd7cddfSDavid du Colombier return 0;
8537dd7cddfSDavid du Colombier }
8547dd7cddfSDavid du Colombier
8557dd7cddfSDavid du Colombier void
umbfree(ulong addr,int size)8567dd7cddfSDavid du Colombier umbfree(ulong addr, int size)
8577dd7cddfSDavid du Colombier {
8587dd7cddfSDavid du Colombier mapfree(&rmapumb, PADDR(addr), size);
8597dd7cddfSDavid du Colombier }
8607dd7cddfSDavid du Colombier
8617dd7cddfSDavid du Colombier ulong
umbrwmalloc(ulong addr,int size,int align)8627dd7cddfSDavid du Colombier umbrwmalloc(ulong addr, int size, int align)
8637dd7cddfSDavid du Colombier {
8647dd7cddfSDavid du Colombier ulong a;
865f7db6155SDavid du Colombier uchar o[2], *p;
8667dd7cddfSDavid du Colombier
8677dd7cddfSDavid du Colombier if(a = mapalloc(&rmapumbrw, addr, size, align))
8687dd7cddfSDavid du Colombier return(ulong)KADDR(a);
8697dd7cddfSDavid du Colombier
8707dd7cddfSDavid du Colombier /*
8717dd7cddfSDavid du Colombier * Perhaps the memory wasn't visible before
8727dd7cddfSDavid du Colombier * the interface is initialised, so try again.
8737dd7cddfSDavid du Colombier */
8747dd7cddfSDavid du Colombier if((a = umbmalloc(addr, size, align)) == 0)
8757dd7cddfSDavid du Colombier return 0;
8767dd7cddfSDavid du Colombier p = (uchar*)a;
877f7db6155SDavid du Colombier o[0] = p[0];
8787dd7cddfSDavid du Colombier p[0] = 0xCC;
879f7db6155SDavid du Colombier o[1] = p[size-1];
8807dd7cddfSDavid du Colombier p[size-1] = 0xCC;
881f7db6155SDavid du Colombier if(p[0] == 0xCC && p[size-1] == 0xCC){
882f7db6155SDavid du Colombier p[0] = o[0];
883f7db6155SDavid du Colombier p[size-1] = o[1];
8847dd7cddfSDavid du Colombier return a;
885f7db6155SDavid du Colombier }
8867dd7cddfSDavid du Colombier umbfree(a, size);
8877dd7cddfSDavid du Colombier
8887dd7cddfSDavid du Colombier return 0;
8897dd7cddfSDavid du Colombier }
8907dd7cddfSDavid du Colombier
8917dd7cddfSDavid du Colombier void
umbrwfree(ulong addr,int size)8927dd7cddfSDavid du Colombier umbrwfree(ulong addr, int size)
8937dd7cddfSDavid du Colombier {
8947dd7cddfSDavid du Colombier mapfree(&rmapumbrw, PADDR(addr), size);
8957dd7cddfSDavid du Colombier }
8967dd7cddfSDavid du Colombier
8974de34a7eSDavid du Colombier /*
8984de34a7eSDavid du Colombier * Give out otherwise-unused physical address space
8994de34a7eSDavid du Colombier * for use in configuring devices. Note that unlike upamalloc
9004de34a7eSDavid du Colombier * before it, upaalloc does not map the physical address
9014de34a7eSDavid du Colombier * into virtual memory. Call vmap to do that.
9024de34a7eSDavid du Colombier */
9037dd7cddfSDavid du Colombier ulong
upaalloc(int size,int align)9044de34a7eSDavid du Colombier upaalloc(int size, int align)
9057dd7cddfSDavid du Colombier {
9064de34a7eSDavid du Colombier ulong a;
9077dd7cddfSDavid du Colombier
9084de34a7eSDavid du Colombier a = mapalloc(&rmapupa, 0, size, align);
9094de34a7eSDavid du Colombier if(a == 0){
9104de34a7eSDavid du Colombier print("out of physical address space allocating %d\n", size);
9114de34a7eSDavid du Colombier mapprint(&rmapupa);
9127dd7cddfSDavid du Colombier }
9137dd7cddfSDavid du Colombier return a;
9147dd7cddfSDavid du Colombier }
9157dd7cddfSDavid du Colombier
9167dd7cddfSDavid du Colombier void
upafree(ulong pa,int size)9177dd7cddfSDavid du Colombier upafree(ulong pa, int size)
9187dd7cddfSDavid du Colombier {
9194de34a7eSDavid du Colombier mapfree(&rmapupa, pa, size);
9204de34a7eSDavid du Colombier }
9214de34a7eSDavid du Colombier
9224de34a7eSDavid du Colombier void
upareserve(ulong pa,int size)9234de34a7eSDavid du Colombier upareserve(ulong pa, int size)
9244de34a7eSDavid du Colombier {
9254de34a7eSDavid du Colombier ulong a;
9264de34a7eSDavid du Colombier
9274de34a7eSDavid du Colombier a = mapalloc(&rmapupa, pa, size, 0);
9284de34a7eSDavid du Colombier if(a != pa){
9294de34a7eSDavid du Colombier /*
9304de34a7eSDavid du Colombier * This can happen when we're using the E820
9314de34a7eSDavid du Colombier * map, which might have already reserved some
9324de34a7eSDavid du Colombier * of the regions claimed by the pci devices.
9334de34a7eSDavid du Colombier */
9344de34a7eSDavid du Colombier // print("upareserve: cannot reserve pa=%#.8lux size=%d\n", pa, size);
9354de34a7eSDavid du Colombier if(a != 0)
9364de34a7eSDavid du Colombier mapfree(&rmapupa, a, size);
9374de34a7eSDavid du Colombier }
9384de34a7eSDavid du Colombier }
9394de34a7eSDavid du Colombier
9404de34a7eSDavid du Colombier void
memorysummary(void)9414de34a7eSDavid du Colombier memorysummary(void)
9424de34a7eSDavid du Colombier {
9434de34a7eSDavid du Colombier memdebug();
9447dd7cddfSDavid du Colombier }
9457dd7cddfSDavid du Colombier
946