xref: /plan9/sys/src/9/pcboot/memory.c (revision 25210b069a6ed8c047fa67220cf1dff32812f121)
1*25210b06SDavid du Colombier /*
2*25210b06SDavid du Colombier  * Size memory and create the kernel page-tables on the fly while doing so.
3*25210b06SDavid du Colombier  * Called from main(), this code should only be run by the bootstrap processor.
4*25210b06SDavid du Colombier  *
5*25210b06SDavid du Colombier  * MemMin is what the bootstrap code in l.s has already mapped;
6*25210b06SDavid du Colombier  * MemMax is the limit of physical memory to scan.
7*25210b06SDavid du Colombier  */
8*25210b06SDavid du Colombier #include "u.h"
9*25210b06SDavid du Colombier #include "../port/lib.h"
10*25210b06SDavid du Colombier #include "mem.h"
11*25210b06SDavid du Colombier #include "dat.h"
12*25210b06SDavid du Colombier #include "fns.h"
13*25210b06SDavid du Colombier #include "io.h"
14*25210b06SDavid du Colombier #include "ureg.h"
15*25210b06SDavid du Colombier 
16*25210b06SDavid du Colombier #define MEMDEBUG	0
17*25210b06SDavid du Colombier 
18*25210b06SDavid du Colombier enum {
19*25210b06SDavid du Colombier 	MemUPA		= 0,		/* unbacked physical address */
20*25210b06SDavid du Colombier 	MemRAM		= 1,		/* physical memory */
21*25210b06SDavid du Colombier 	MemUMB		= 2,		/* upper memory block (<16MB) */
22*25210b06SDavid du Colombier 	MemReserved	= 3,
23*25210b06SDavid du Colombier 	NMemType	= 4,
24*25210b06SDavid du Colombier 
25*25210b06SDavid du Colombier 	KB		= 1024,
26*25210b06SDavid du Colombier };
27*25210b06SDavid du Colombier 
28*25210b06SDavid du Colombier typedef struct Map Map;
29*25210b06SDavid du Colombier struct Map {
30*25210b06SDavid du Colombier 	ulong	size;
31*25210b06SDavid du Colombier 	ulong	addr;
32*25210b06SDavid du Colombier };
33*25210b06SDavid du Colombier 
34*25210b06SDavid du Colombier typedef struct RMap RMap;
35*25210b06SDavid du Colombier struct RMap {
36*25210b06SDavid du Colombier 	char*	name;
37*25210b06SDavid du Colombier 	Map*	map;
38*25210b06SDavid du Colombier 	Map*	mapend;
39*25210b06SDavid du Colombier 
40*25210b06SDavid du Colombier 	Lock;
41*25210b06SDavid du Colombier };
42*25210b06SDavid du Colombier 
43*25210b06SDavid du Colombier /*
44*25210b06SDavid du Colombier  * Memory allocation tracking.
45*25210b06SDavid du Colombier  */
46*25210b06SDavid du Colombier static Map mapupa[16];
47*25210b06SDavid du Colombier static RMap rmapupa = {
48*25210b06SDavid du Colombier 	"unallocated unbacked physical addresses",
49*25210b06SDavid du Colombier 	mapupa,
50*25210b06SDavid du Colombier 	&mapupa[nelem(mapupa)-1],
51*25210b06SDavid du Colombier };
52*25210b06SDavid du Colombier 
53*25210b06SDavid du Colombier static Map mapram[16];
54*25210b06SDavid du Colombier static RMap rmapram = {
55*25210b06SDavid du Colombier 	"physical memory",
56*25210b06SDavid du Colombier 	mapram,
57*25210b06SDavid du Colombier 	&mapram[nelem(mapram)-1],
58*25210b06SDavid du Colombier };
59*25210b06SDavid du Colombier 
60*25210b06SDavid du Colombier static Map mapumb[64];
61*25210b06SDavid du Colombier static RMap rmapumb = {
62*25210b06SDavid du Colombier 	"upper memory block",
63*25210b06SDavid du Colombier 	mapumb,
64*25210b06SDavid du Colombier 	&mapumb[nelem(mapumb)-1],
65*25210b06SDavid du Colombier };
66*25210b06SDavid du Colombier 
67*25210b06SDavid du Colombier static Map mapumbrw[16];
68*25210b06SDavid du Colombier static RMap rmapumbrw = {
69*25210b06SDavid du Colombier 	"UMB device memory",
70*25210b06SDavid du Colombier 	mapumbrw,
71*25210b06SDavid du Colombier 	&mapumbrw[nelem(mapumbrw)-1],
72*25210b06SDavid du Colombier };
73*25210b06SDavid du Colombier 
74*25210b06SDavid du Colombier static void map(ulong base, ulong len, int type);
75*25210b06SDavid du Colombier 
76*25210b06SDavid du Colombier void
mapprint(RMap * rmap)77*25210b06SDavid du Colombier mapprint(RMap *rmap)
78*25210b06SDavid du Colombier {
79*25210b06SDavid du Colombier 	Map *mp;
80*25210b06SDavid du Colombier 
81*25210b06SDavid du Colombier 	print("%s\n", rmap->name);
82*25210b06SDavid du Colombier 	for(mp = rmap->map; mp->size; mp++)
83*25210b06SDavid du Colombier 		print("\t%8.8luX %8.8luX (%lud)\n", mp->addr, mp->addr+mp->size, mp->size);
84*25210b06SDavid du Colombier }
85*25210b06SDavid du Colombier 
86*25210b06SDavid du Colombier 
87*25210b06SDavid du Colombier void
memdebug(void)88*25210b06SDavid du Colombier memdebug(void)
89*25210b06SDavid du Colombier {
90*25210b06SDavid du Colombier 	ulong maxpa, maxpa1, maxpa2;
91*25210b06SDavid du Colombier 
92*25210b06SDavid du Colombier 	maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
93*25210b06SDavid du Colombier 	maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
94*25210b06SDavid du Colombier 	maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
95*25210b06SDavid du Colombier 	print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
96*25210b06SDavid du Colombier 		maxpa, MB+maxpa*KB, maxpa1, maxpa2);
97*25210b06SDavid du Colombier 
98*25210b06SDavid du Colombier 	mapprint(&rmapram);
99*25210b06SDavid du Colombier 	mapprint(&rmapumb);
100*25210b06SDavid du Colombier 	mapprint(&rmapumbrw);
101*25210b06SDavid du Colombier 	mapprint(&rmapupa);
102*25210b06SDavid du Colombier }
103*25210b06SDavid du Colombier 
104*25210b06SDavid du Colombier void
mapfree(RMap * rmap,ulong addr,ulong size)105*25210b06SDavid du Colombier mapfree(RMap* rmap, ulong addr, ulong size)
106*25210b06SDavid du Colombier {
107*25210b06SDavid du Colombier 	Map *mp;
108*25210b06SDavid du Colombier 	ulong t;
109*25210b06SDavid du Colombier 
110*25210b06SDavid du Colombier 	if(size <= 0)
111*25210b06SDavid du Colombier 		return;
112*25210b06SDavid du Colombier 
113*25210b06SDavid du Colombier 	lock(rmap);
114*25210b06SDavid du Colombier 	for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
115*25210b06SDavid du Colombier 		;
116*25210b06SDavid du Colombier 
117*25210b06SDavid du Colombier 	if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
118*25210b06SDavid du Colombier 		(mp-1)->size += size;
119*25210b06SDavid du Colombier 		if(addr+size == mp->addr){
120*25210b06SDavid du Colombier 			(mp-1)->size += mp->size;
121*25210b06SDavid du Colombier 			while(mp->size){
122*25210b06SDavid du Colombier 				mp++;
123*25210b06SDavid du Colombier 				(mp-1)->addr = mp->addr;
124*25210b06SDavid du Colombier 				(mp-1)->size = mp->size;
125*25210b06SDavid du Colombier 			}
126*25210b06SDavid du Colombier 		}
127*25210b06SDavid du Colombier 	}
128*25210b06SDavid du Colombier 	else{
129*25210b06SDavid du Colombier 		if(addr+size == mp->addr && mp->size){
130*25210b06SDavid du Colombier 			mp->addr -= size;
131*25210b06SDavid du Colombier 			mp->size += size;
132*25210b06SDavid du Colombier 		}
133*25210b06SDavid du Colombier 		else do{
134*25210b06SDavid du Colombier 			if(mp >= rmap->mapend){
135*25210b06SDavid du Colombier 				print("mapfree: %s: losing %#luX, %ld\n",
136*25210b06SDavid du Colombier 					rmap->name, addr, size);
137*25210b06SDavid du Colombier 				break;
138*25210b06SDavid du Colombier 			}
139*25210b06SDavid du Colombier 			t = mp->addr;
140*25210b06SDavid du Colombier 			mp->addr = addr;
141*25210b06SDavid du Colombier 			addr = t;
142*25210b06SDavid du Colombier 			t = mp->size;
143*25210b06SDavid du Colombier 			mp->size = size;
144*25210b06SDavid du Colombier 			mp++;
145*25210b06SDavid du Colombier 		}while(size = t);
146*25210b06SDavid du Colombier 	}
147*25210b06SDavid du Colombier 	unlock(rmap);
148*25210b06SDavid du Colombier }
149*25210b06SDavid du Colombier 
150*25210b06SDavid du Colombier ulong
mapalloc(RMap * rmap,ulong addr,int size,int align)151*25210b06SDavid du Colombier mapalloc(RMap* rmap, ulong addr, int size, int align)
152*25210b06SDavid du Colombier {
153*25210b06SDavid du Colombier 	Map *mp;
154*25210b06SDavid du Colombier 	ulong maddr, oaddr;
155*25210b06SDavid du Colombier 
156*25210b06SDavid du Colombier 	lock(rmap);
157*25210b06SDavid du Colombier 	for(mp = rmap->map; mp->size; mp++){
158*25210b06SDavid du Colombier 		maddr = mp->addr;
159*25210b06SDavid du Colombier 
160*25210b06SDavid du Colombier 		if(addr){
161*25210b06SDavid du Colombier 			/*
162*25210b06SDavid du Colombier 			 * A specific address range has been given:
163*25210b06SDavid du Colombier 			 *   if the current map entry is greater then
164*25210b06SDavid du Colombier 			 *   the address is not in the map;
165*25210b06SDavid du Colombier 			 *   if the current map entry does not overlap
166*25210b06SDavid du Colombier 			 *   the beginning of the requested range then
167*25210b06SDavid du Colombier 			 *   continue on to the next map entry;
168*25210b06SDavid du Colombier 			 *   if the current map entry does not entirely
169*25210b06SDavid du Colombier 			 *   contain the requested range then the range
170*25210b06SDavid du Colombier 			 *   is not in the map.
171*25210b06SDavid du Colombier 			 */
172*25210b06SDavid du Colombier 			if(maddr > addr)
173*25210b06SDavid du Colombier 				break;
174*25210b06SDavid du Colombier 			if(mp->size < addr - maddr)	/* maddr+mp->size < addr, but no overflow */
175*25210b06SDavid du Colombier 				continue;
176*25210b06SDavid du Colombier 			if(addr - maddr > mp->size - size)	/* addr+size > maddr+mp->size, but no overflow */
177*25210b06SDavid du Colombier 				break;
178*25210b06SDavid du Colombier 			maddr = addr;
179*25210b06SDavid du Colombier 		}
180*25210b06SDavid du Colombier 
181*25210b06SDavid du Colombier 		if(align > 0)
182*25210b06SDavid du Colombier 			maddr = ((maddr+align-1)/align)*align;
183*25210b06SDavid du Colombier 		if(mp->addr+mp->size-maddr < size)
184*25210b06SDavid du Colombier 			continue;
185*25210b06SDavid du Colombier 
186*25210b06SDavid du Colombier 		oaddr = mp->addr;
187*25210b06SDavid du Colombier 		mp->addr = maddr+size;
188*25210b06SDavid du Colombier 		mp->size -= maddr-oaddr+size;
189*25210b06SDavid du Colombier 		if(mp->size == 0){
190*25210b06SDavid du Colombier 			do{
191*25210b06SDavid du Colombier 				mp++;
192*25210b06SDavid du Colombier 				(mp-1)->addr = mp->addr;
193*25210b06SDavid du Colombier 			}while((mp-1)->size = mp->size);
194*25210b06SDavid du Colombier 		}
195*25210b06SDavid du Colombier 
196*25210b06SDavid du Colombier 		unlock(rmap);
197*25210b06SDavid du Colombier 		if(oaddr != maddr)
198*25210b06SDavid du Colombier 			mapfree(rmap, oaddr, maddr-oaddr);
199*25210b06SDavid du Colombier 
200*25210b06SDavid du Colombier 		return maddr;
201*25210b06SDavid du Colombier 	}
202*25210b06SDavid du Colombier 	unlock(rmap);
203*25210b06SDavid du Colombier 
204*25210b06SDavid du Colombier 	return 0;
205*25210b06SDavid du Colombier }
206*25210b06SDavid du Colombier 
207*25210b06SDavid du Colombier /*
208*25210b06SDavid du Colombier  * Allocate from the ram map directly to make page tables.
209*25210b06SDavid du Colombier  * Called by mmuwalk during e820scan.
210*25210b06SDavid du Colombier  */
211*25210b06SDavid du Colombier void*
rampage(void)212*25210b06SDavid du Colombier rampage(void)
213*25210b06SDavid du Colombier {
214*25210b06SDavid du Colombier 	ulong m;
215*25210b06SDavid du Colombier 
216*25210b06SDavid du Colombier 	m = mapalloc(&rmapram, 0, BY2PG, BY2PG);
217*25210b06SDavid du Colombier 	if(m == 0)
218*25210b06SDavid du Colombier 		return nil;
219*25210b06SDavid du Colombier 	return KADDR(m);
220*25210b06SDavid du Colombier }
221*25210b06SDavid du Colombier 
222*25210b06SDavid du Colombier static void
umbexclude(void)223*25210b06SDavid du Colombier umbexclude(void)
224*25210b06SDavid du Colombier {
225*25210b06SDavid du Colombier 	int size;
226*25210b06SDavid du Colombier 	ulong addr;
227*25210b06SDavid du Colombier 	char *op, *p, *rptr;
228*25210b06SDavid du Colombier 
229*25210b06SDavid du Colombier 	if((p = getconf("umbexclude")) == nil)
230*25210b06SDavid du Colombier 		return;
231*25210b06SDavid du Colombier 
232*25210b06SDavid du Colombier 	while(p && *p != '\0' && *p != '\n'){
233*25210b06SDavid du Colombier 		op = p;
234*25210b06SDavid du Colombier 		addr = strtoul(p, &rptr, 0);
235*25210b06SDavid du Colombier 		if(rptr == nil || rptr == p || *rptr != '-'){
236*25210b06SDavid du Colombier 			print("umbexclude: invalid argument <%s>\n", op);
237*25210b06SDavid du Colombier 			break;
238*25210b06SDavid du Colombier 		}
239*25210b06SDavid du Colombier 		p = rptr+1;
240*25210b06SDavid du Colombier 
241*25210b06SDavid du Colombier 		size = strtoul(p, &rptr, 0) - addr + 1;
242*25210b06SDavid du Colombier 		if(size <= 0){
243*25210b06SDavid du Colombier 			print("umbexclude: bad range <%s>\n", op);
244*25210b06SDavid du Colombier 			break;
245*25210b06SDavid du Colombier 		}
246*25210b06SDavid du Colombier 		if(rptr != nil && *rptr == ',')
247*25210b06SDavid du Colombier 			*rptr++ = '\0';
248*25210b06SDavid du Colombier 		p = rptr;
249*25210b06SDavid du Colombier 
250*25210b06SDavid du Colombier 		mapalloc(&rmapumb, addr, size, 0);
251*25210b06SDavid du Colombier 	}
252*25210b06SDavid du Colombier }
253*25210b06SDavid du Colombier 
254*25210b06SDavid du Colombier static void
umbscan(void)255*25210b06SDavid du Colombier umbscan(void)
256*25210b06SDavid du Colombier {
257*25210b06SDavid du Colombier 	uchar o[2], *p;
258*25210b06SDavid du Colombier 
259*25210b06SDavid du Colombier 	/*
260*25210b06SDavid du Colombier 	 * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
261*25210b06SDavid du Colombier 	 * which aren't used; they can be used later for devices which
262*25210b06SDavid du Colombier 	 * want to allocate some virtual address space.
263*25210b06SDavid du Colombier 	 * Check for two things:
264*25210b06SDavid du Colombier 	 * 1) device BIOS ROM. This should start with a two-byte header
265*25210b06SDavid du Colombier 	 *    of 0x55 0xAA, followed by a byte giving the size of the ROM
266*25210b06SDavid du Colombier 	 *    in 512-byte chunks. These ROM's must start on a 2KB boundary.
267*25210b06SDavid du Colombier 	 * 2) device memory. This is read-write.
268*25210b06SDavid du Colombier 	 * There are some assumptions: there's VGA memory at 0xA0000 and
269*25210b06SDavid du Colombier 	 * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
270*25210b06SDavid du Colombier 	 * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up
271*25210b06SDavid du Colombier 	 * for grabs; check anyway.
272*25210b06SDavid du Colombier 	 */
273*25210b06SDavid du Colombier 	p = KADDR(0xD0000);
274*25210b06SDavid du Colombier 	while(p < (uchar*)KADDR(0xE0000)){
275*25210b06SDavid du Colombier 		/*
276*25210b06SDavid du Colombier 		 * Check for the ROM signature, skip if valid.
277*25210b06SDavid du Colombier 		 */
278*25210b06SDavid du Colombier 		if(p[0] == 0x55 && p[1] == 0xAA){
279*25210b06SDavid du Colombier 			p += p[2]*512;
280*25210b06SDavid du Colombier 			continue;
281*25210b06SDavid du Colombier 		}
282*25210b06SDavid du Colombier 
283*25210b06SDavid du Colombier 		/*
284*25210b06SDavid du Colombier 		 * Is it writeable? If yes, then stick it in
285*25210b06SDavid du Colombier 		 * the UMB device memory map. A floating bus will
286*25210b06SDavid du Colombier 		 * return 0xff, so add that to the map of the
287*25210b06SDavid du Colombier 		 * UMB space available for allocation.
288*25210b06SDavid du Colombier 		 * If it is neither of those, ignore it.
289*25210b06SDavid du Colombier 		 */
290*25210b06SDavid du Colombier 		o[0] = p[0];
291*25210b06SDavid du Colombier 		p[0] = 0xCC;
292*25210b06SDavid du Colombier 		o[1] = p[2*KB-1];
293*25210b06SDavid du Colombier 		p[2*KB-1] = 0xCC;
294*25210b06SDavid du Colombier 		if(p[0] == 0xCC && p[2*KB-1] == 0xCC){
295*25210b06SDavid du Colombier 			p[0] = o[0];
296*25210b06SDavid du Colombier 			p[2*KB-1] = o[1];
297*25210b06SDavid du Colombier 			mapfree(&rmapumbrw, PADDR(p), 2*KB);
298*25210b06SDavid du Colombier 		}
299*25210b06SDavid du Colombier 		else if(p[0] == 0xFF && p[1] == 0xFF)
300*25210b06SDavid du Colombier 			mapfree(&rmapumb, PADDR(p), 2*KB);
301*25210b06SDavid du Colombier 		p += 2*KB;
302*25210b06SDavid du Colombier 	}
303*25210b06SDavid du Colombier 
304*25210b06SDavid du Colombier 	p = KADDR(0xE0000);
305*25210b06SDavid du Colombier 	if(p[0] != 0x55 || p[1] != 0xAA){
306*25210b06SDavid du Colombier 		p[0] = 0xCC;
307*25210b06SDavid du Colombier 		p[64*KB-1] = 0xCC;
308*25210b06SDavid du Colombier 		if(p[0] != 0xCC && p[64*KB-1] != 0xCC)
309*25210b06SDavid du Colombier 			mapfree(&rmapumb, PADDR(p), 64*KB);
310*25210b06SDavid du Colombier 	}
311*25210b06SDavid du Colombier 
312*25210b06SDavid du Colombier 	umbexclude();
313*25210b06SDavid du Colombier }
314*25210b06SDavid du Colombier 
315*25210b06SDavid du Colombier enum {
316*25210b06SDavid du Colombier 	Pteflags = (1<<12) - 1,
317*25210b06SDavid du Colombier };
318*25210b06SDavid du Colombier 
319*25210b06SDavid du Colombier void
dumppdb(ulong * pdb)320*25210b06SDavid du Colombier dumppdb(ulong *pdb)
321*25210b06SDavid du Colombier {
322*25210b06SDavid du Colombier 	ulong *pp;
323*25210b06SDavid du Colombier 
324*25210b06SDavid du Colombier 	pdb = (ulong *)((uintptr)pdb & ~Pteflags);
325*25210b06SDavid du Colombier 	iprint("pdb at phys %#8.8p:\n", PADDR(pdb));
326*25210b06SDavid du Colombier 	for (pp = pdb; pp < pdb + 1024; pp++)
327*25210b06SDavid du Colombier 		if (*pp)
328*25210b06SDavid du Colombier 			iprint("pdb[%3ld]: %#8.8lux\n", pp - pdb, *pp);
329*25210b06SDavid du Colombier }
330*25210b06SDavid du Colombier 
331*25210b06SDavid du Colombier void
dumppte(ulong * pdb,int sub,int first)332*25210b06SDavid du Colombier dumppte(ulong *pdb, int sub, int first)
333*25210b06SDavid du Colombier {
334*25210b06SDavid du Colombier 	ulong *pp, *pte;
335*25210b06SDavid du Colombier 
336*25210b06SDavid du Colombier 	pte = KADDR(pdb[sub]);
337*25210b06SDavid du Colombier 	pte = (ulong *)((uintptr)pte & ~Pteflags);
338*25210b06SDavid du Colombier 	if (PADDR(pte) == 0) {
339*25210b06SDavid du Colombier 		iprint("pdb[%d] unmapped\n", sub);
340*25210b06SDavid du Colombier 		return;
341*25210b06SDavid du Colombier 	}
342*25210b06SDavid du Colombier 	iprint("pdb[%d] pte at phys %#8.8p:\n", sub, PADDR(pte));
343*25210b06SDavid du Colombier 	for (pp = pte; pp < pte + first; pp++)
344*25210b06SDavid du Colombier 		if (*pp)
345*25210b06SDavid du Colombier 			iprint("pte[%3ld]: %#8.8lux\n", pp - pte, *pp);
346*25210b06SDavid du Colombier 	iprint("...\n");
347*25210b06SDavid du Colombier }
348*25210b06SDavid du Colombier 
349*25210b06SDavid du Colombier uintptr
mapping(uintptr va)350*25210b06SDavid du Colombier mapping(uintptr va)
351*25210b06SDavid du Colombier {
352*25210b06SDavid du Colombier 	ulong *pte;
353*25210b06SDavid du Colombier 
354*25210b06SDavid du Colombier 	pte = KADDR(m->pdb[PDX(va)] & ~Pteflags);
355*25210b06SDavid du Colombier 	return pte[PTX(va)] & ~Pteflags;
356*25210b06SDavid du Colombier }
357*25210b06SDavid du Colombier 
358*25210b06SDavid du Colombier /*
359*25210b06SDavid du Colombier  * adjust the maps and make the mmu mappings match the maps
360*25210b06SDavid du Colombier  */
361*25210b06SDavid du Colombier static void
lowraminit(void)362*25210b06SDavid du Colombier lowraminit(void)
363*25210b06SDavid du Colombier {
364*25210b06SDavid du Colombier 	/*
365*25210b06SDavid du Colombier 	 * low memory is in use by bootstrap kernels and ROMs.
366*25210b06SDavid du Colombier 	 * MemReserved is untouchable, so use MemRAM.
367*25210b06SDavid du Colombier 	 * address zero is special to mapalloc, and thus to map, so avoid it.
368*25210b06SDavid du Colombier 	 * we can thus load the new kernel directly at 1MB and up.
369*25210b06SDavid du Colombier 	 */
370*25210b06SDavid du Colombier //	map(BY2PG, MB - BY2PG, MemRAM)	/* executing this map call is fatal */
371*25210b06SDavid du Colombier 	mapalloc(&rmapram, BY2PG, Mallocbase - BY2PG, 0);
372*25210b06SDavid du Colombier 
373*25210b06SDavid du Colombier 	/*
374*25210b06SDavid du Colombier 	 * declare all RAM above Mallocbase to be free.
375*25210b06SDavid du Colombier 	 */
376*25210b06SDavid du Colombier 	map(Mallocbase, MemMax - Mallocbase, MemRAM);
377*25210b06SDavid du Colombier 
378*25210b06SDavid du Colombier 	/* declare rest of physical address space above RAM to be available */
379*25210b06SDavid du Colombier 	map(MemMax, KZERO-MemMax, MemUPA);
380*25210b06SDavid du Colombier 
381*25210b06SDavid du Colombier 	/* force the new mappings to take effect */
382*25210b06SDavid du Colombier 	mmuflushtlb(PADDR(m->pdb));
383*25210b06SDavid du Colombier }
384*25210b06SDavid du Colombier 
385*25210b06SDavid du Colombier /*
386*25210b06SDavid du Colombier  * add region at physical base of len bytes to map for `type', and
387*25210b06SDavid du Colombier  * set up page tables to map virtual KZERO|base to physical base.
388*25210b06SDavid du Colombier  */
389*25210b06SDavid du Colombier static void
map(ulong base,ulong len,int type)390*25210b06SDavid du Colombier map(ulong base, ulong len, int type)
391*25210b06SDavid du Colombier {
392*25210b06SDavid du Colombier 	ulong n, flags, maxkpa;
393*25210b06SDavid du Colombier 
394*25210b06SDavid du Colombier //	iprint("map %.8lux %.8lux %d (", base, base+len, type);
395*25210b06SDavid du Colombier 	/*
396*25210b06SDavid du Colombier 	 * Split any call crossing MemMin to make below simpler.
397*25210b06SDavid du Colombier 	 */
398*25210b06SDavid du Colombier 	if(base < MemMin && len > MemMin-base){
399*25210b06SDavid du Colombier 		n = MemMin - base;
400*25210b06SDavid du Colombier 		map(base, n, type);
401*25210b06SDavid du Colombier 		map(MemMin, len-n, type);
402*25210b06SDavid du Colombier 		return;
403*25210b06SDavid du Colombier 	}
404*25210b06SDavid du Colombier 
405*25210b06SDavid du Colombier 	switch(type){
406*25210b06SDavid du Colombier 	case MemRAM:
407*25210b06SDavid du Colombier 		mapfree(&rmapram, base, len);
408*25210b06SDavid du Colombier 		flags = PTEWRITE|PTEVALID;
409*25210b06SDavid du Colombier 		break;
410*25210b06SDavid du Colombier 	case MemUMB:
411*25210b06SDavid du Colombier 		mapfree(&rmapumb, base, len);
412*25210b06SDavid du Colombier 		flags = PTEWRITE|PTEUNCACHED|PTEVALID;
413*25210b06SDavid du Colombier 		break;
414*25210b06SDavid du Colombier 	case MemUPA:
415*25210b06SDavid du Colombier 		mapfree(&rmapupa, base, len);
416*25210b06SDavid du Colombier 		flags = 0;
417*25210b06SDavid du Colombier 		break;
418*25210b06SDavid du Colombier 	default:
419*25210b06SDavid du Colombier 	case MemReserved:
420*25210b06SDavid du Colombier 		flags = 0;
421*25210b06SDavid du Colombier 		break;
422*25210b06SDavid du Colombier 	}
423*25210b06SDavid du Colombier 
424*25210b06SDavid du Colombier 	/*
425*25210b06SDavid du Colombier 	 * Only map from KZERO to 2^32.
426*25210b06SDavid du Colombier 	 */
427*25210b06SDavid du Colombier 	if(flags){
428*25210b06SDavid du Colombier 		maxkpa = -KZERO;
429*25210b06SDavid du Colombier 		if(base >= maxkpa)
430*25210b06SDavid du Colombier 			return;
431*25210b06SDavid du Colombier 		if(len > maxkpa-base)
432*25210b06SDavid du Colombier 			len = maxkpa - base;
433*25210b06SDavid du Colombier 		pdbmap(m->pdb, base|flags, base+KZERO, len);
434*25210b06SDavid du Colombier 	}
435*25210b06SDavid du Colombier }
436*25210b06SDavid du Colombier 
437*25210b06SDavid du Colombier void
meminit(void)438*25210b06SDavid du Colombier meminit(void)
439*25210b06SDavid du Colombier {
440*25210b06SDavid du Colombier 	int i, kzsub;
441*25210b06SDavid du Colombier 	Map *mp;
442*25210b06SDavid du Colombier 	Confmem *cm;
443*25210b06SDavid du Colombier 	ulong pa, *pte;
444*25210b06SDavid du Colombier 	ulong lost, physpte;
445*25210b06SDavid du Colombier 
446*25210b06SDavid du Colombier 	/* no need to size memory, we don't need much. */
447*25210b06SDavid du Colombier 	pte = m->pdb + BY2PG/BY2WD;		/* see l*.s */
448*25210b06SDavid du Colombier 
449*25210b06SDavid du Colombier 	/* populate pdb with double-mapping of low memory */
450*25210b06SDavid du Colombier 	kzsub = ((uintptr)KZERO >> (2*PGSHIFT - 4)) / sizeof(ulong);
451*25210b06SDavid du Colombier 	physpte = (uintptr)PADDR(pte);
452*25210b06SDavid du Colombier 	for (i = 0; i < LOWPTEPAGES; i++)
453*25210b06SDavid du Colombier 		m->pdb[kzsub + i] = m->pdb[i] =
454*25210b06SDavid du Colombier 			PTEVALID | PTEKERNEL | PTEWRITE | (physpte + i * BY2PG);
455*25210b06SDavid du Colombier 
456*25210b06SDavid du Colombier 	/*
457*25210b06SDavid du Colombier 	 * Set special attributes for memory between 640KB and 1MB:
458*25210b06SDavid du Colombier 	 *   VGA memory is writethrough;
459*25210b06SDavid du Colombier 	 *   BIOS ROM's/UMB's are uncached;
460*25210b06SDavid du Colombier 	 * then scan for useful memory.
461*25210b06SDavid du Colombier 	 */
462*25210b06SDavid du Colombier 	for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){
463*25210b06SDavid du Colombier 		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
464*25210b06SDavid du Colombier 		*pte |= PTEWT;
465*25210b06SDavid du Colombier 	}
466*25210b06SDavid du Colombier 	for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){
467*25210b06SDavid du Colombier 		pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
468*25210b06SDavid du Colombier 		*pte |= PTEUNCACHED;
469*25210b06SDavid du Colombier 	}
470*25210b06SDavid du Colombier 	mmuflushtlb(PADDR(m->pdb));
471*25210b06SDavid du Colombier 
472*25210b06SDavid du Colombier 	umbscan();
473*25210b06SDavid du Colombier 	lowraminit();
474*25210b06SDavid du Colombier 
475*25210b06SDavid du Colombier 	/*
476*25210b06SDavid du Colombier 	 * Set the conf entries describing banks of allocatable memory.
477*25210b06SDavid du Colombier 	 */
478*25210b06SDavid du Colombier 	for(i=0; i<nelem(mapram) && i<nelem(conf.mem); i++){
479*25210b06SDavid du Colombier 		mp = &rmapram.map[i];
480*25210b06SDavid du Colombier 		cm = &conf.mem[i];
481*25210b06SDavid du Colombier 		cm->base = mp->addr;
482*25210b06SDavid du Colombier 		cm->npage = mp->size/BY2PG;
483*25210b06SDavid du Colombier 		if (i == 0 && cm->npage == 0)
484*25210b06SDavid du Colombier 			panic("meminit: no memory in conf.mem");
485*25210b06SDavid du Colombier 	}
486*25210b06SDavid du Colombier 	lost = 0;
487*25210b06SDavid du Colombier 	for(; i<nelem(mapram); i++)
488*25210b06SDavid du Colombier 		lost += rmapram.map[i].size;
489*25210b06SDavid du Colombier 	if(lost)
490*25210b06SDavid du Colombier 		print("meminit - lost %lud bytes\n", lost);
491*25210b06SDavid du Colombier 
492*25210b06SDavid du Colombier 	if(MEMDEBUG)
493*25210b06SDavid du Colombier 		memdebug();
494*25210b06SDavid du Colombier }
495*25210b06SDavid du Colombier 
496*25210b06SDavid du Colombier /*
497*25210b06SDavid du Colombier  * Allocate memory from the upper memory blocks.
498*25210b06SDavid du Colombier  */
499*25210b06SDavid du Colombier ulong
umbmalloc(ulong addr,int size,int align)500*25210b06SDavid du Colombier umbmalloc(ulong addr, int size, int align)
501*25210b06SDavid du Colombier {
502*25210b06SDavid du Colombier 	ulong a;
503*25210b06SDavid du Colombier 
504*25210b06SDavid du Colombier 	if(a = mapalloc(&rmapumb, addr, size, align))
505*25210b06SDavid du Colombier 		return (ulong)KADDR(a);
506*25210b06SDavid du Colombier 
507*25210b06SDavid du Colombier 	return 0;
508*25210b06SDavid du Colombier }
509*25210b06SDavid du Colombier 
510*25210b06SDavid du Colombier void
umbfree(ulong addr,int size)511*25210b06SDavid du Colombier umbfree(ulong addr, int size)
512*25210b06SDavid du Colombier {
513*25210b06SDavid du Colombier 	mapfree(&rmapumb, PADDR(addr), size);
514*25210b06SDavid du Colombier }
515*25210b06SDavid du Colombier 
516*25210b06SDavid du Colombier ulong
umbrwmalloc(ulong addr,int size,int align)517*25210b06SDavid du Colombier umbrwmalloc(ulong addr, int size, int align)
518*25210b06SDavid du Colombier {
519*25210b06SDavid du Colombier 	ulong a;
520*25210b06SDavid du Colombier 	uchar o[2], *p;
521*25210b06SDavid du Colombier 
522*25210b06SDavid du Colombier 	if(a = mapalloc(&rmapumbrw, addr, size, align))
523*25210b06SDavid du Colombier 		return(ulong)KADDR(a);
524*25210b06SDavid du Colombier 
525*25210b06SDavid du Colombier 	/*
526*25210b06SDavid du Colombier 	 * Perhaps the memory wasn't visible before
527*25210b06SDavid du Colombier 	 * the interface is initialised, so try again.
528*25210b06SDavid du Colombier 	 */
529*25210b06SDavid du Colombier 	if((a = umbmalloc(addr, size, align)) == 0)
530*25210b06SDavid du Colombier 		return 0;
531*25210b06SDavid du Colombier 	p = (uchar*)a;
532*25210b06SDavid du Colombier 	o[0] = p[0];
533*25210b06SDavid du Colombier 	p[0] = 0xCC;
534*25210b06SDavid du Colombier 	o[1] = p[size-1];
535*25210b06SDavid du Colombier 	p[size-1] = 0xCC;
536*25210b06SDavid du Colombier 	if(p[0] == 0xCC && p[size-1] == 0xCC){
537*25210b06SDavid du Colombier 		p[0] = o[0];
538*25210b06SDavid du Colombier 		p[size-1] = o[1];
539*25210b06SDavid du Colombier 		return a;
540*25210b06SDavid du Colombier 	}
541*25210b06SDavid du Colombier 	umbfree(a, size);
542*25210b06SDavid du Colombier 
543*25210b06SDavid du Colombier 	return 0;
544*25210b06SDavid du Colombier }
545*25210b06SDavid du Colombier 
546*25210b06SDavid du Colombier void
umbrwfree(ulong addr,int size)547*25210b06SDavid du Colombier umbrwfree(ulong addr, int size)
548*25210b06SDavid du Colombier {
549*25210b06SDavid du Colombier 	mapfree(&rmapumbrw, PADDR(addr), size);
550*25210b06SDavid du Colombier }
551*25210b06SDavid du Colombier 
552*25210b06SDavid du Colombier /*
553*25210b06SDavid du Colombier  * Give out otherwise-unused physical address space
554*25210b06SDavid du Colombier  * for use in configuring devices.  Note that unlike upamalloc
555*25210b06SDavid du Colombier  * before it, upaalloc does not map the physical address
556*25210b06SDavid du Colombier  * into virtual memory.  Call vmap to do that.
557*25210b06SDavid du Colombier  */
558*25210b06SDavid du Colombier ulong
upaalloc(int size,int align)559*25210b06SDavid du Colombier upaalloc(int size, int align)
560*25210b06SDavid du Colombier {
561*25210b06SDavid du Colombier 	ulong a;
562*25210b06SDavid du Colombier 
563*25210b06SDavid du Colombier 	a = mapalloc(&rmapupa, 0, size, align);
564*25210b06SDavid du Colombier 	if(a == 0){
565*25210b06SDavid du Colombier 		print("out of physical address space allocating %d\n", size);
566*25210b06SDavid du Colombier 		mapprint(&rmapupa);
567*25210b06SDavid du Colombier 	}
568*25210b06SDavid du Colombier 	return a;
569*25210b06SDavid du Colombier }
570*25210b06SDavid du Colombier 
571*25210b06SDavid du Colombier void
upafree(ulong pa,int size)572*25210b06SDavid du Colombier upafree(ulong pa, int size)
573*25210b06SDavid du Colombier {
574*25210b06SDavid du Colombier 	mapfree(&rmapupa, pa, size);
575*25210b06SDavid du Colombier }
576*25210b06SDavid du Colombier 
577*25210b06SDavid du Colombier void
upareserve(ulong pa,int size)578*25210b06SDavid du Colombier upareserve(ulong pa, int size)
579*25210b06SDavid du Colombier {
580*25210b06SDavid du Colombier 	ulong a;
581*25210b06SDavid du Colombier 
582*25210b06SDavid du Colombier 	a = mapalloc(&rmapupa, pa, size, 0);
583*25210b06SDavid du Colombier 	if(a != pa){
584*25210b06SDavid du Colombier 		/*
585*25210b06SDavid du Colombier 		 * This can happen when we're using the E820
586*25210b06SDavid du Colombier 		 * map, which might have already reserved some
587*25210b06SDavid du Colombier 		 * of the regions claimed by the pci devices.
588*25210b06SDavid du Colombier 		 */
589*25210b06SDavid du Colombier 	//	print("upareserve: cannot reserve pa=%#.8lux size=%d\n", pa, size);
590*25210b06SDavid du Colombier 		if(a != 0)
591*25210b06SDavid du Colombier 			mapfree(&rmapupa, a, size);
592*25210b06SDavid du Colombier 	}
593*25210b06SDavid du Colombier }
594*25210b06SDavid du Colombier 
595*25210b06SDavid du Colombier void
memorysummary(void)596*25210b06SDavid du Colombier memorysummary(void)
597*25210b06SDavid du Colombier {
598*25210b06SDavid du Colombier 	memdebug();
599*25210b06SDavid du Colombier }
600*25210b06SDavid du Colombier 
601