xref: /plan9/sys/src/9/pc/memory.c (revision 00a4193c1e0554905f959f11961389c706f63ac9)
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