]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/memory.c
33121d647faff5d7043425a96696c82a423ad693
[plan9front.git] / sys / src / 9 / pc / memory.c
1 /*
2  * Size memory and create the kernel page-tables on the fly while doing so.
3  * Called from main(), this code should only be run by the bootstrap processor.
4  *
5  * MemMin is what the bootstrap code in l.s has already mapped;
6  * MemMax is the limit of physical memory to scan.
7  */
8 #include "u.h"
9 #include "../port/lib.h"
10 #include "mem.h"
11 #include "dat.h"
12 #include "fns.h"
13 #include "io.h"
14 #include "ureg.h"
15
16 #define MEMDEBUG        0
17
18 enum {
19         MemUPA          = 0,            /* unbacked physical address */
20         MemRAM          = 1,            /* physical memory */
21         MemUMB          = 2,            /* upper memory block (<16MB) */
22         MemReserved     = 3,
23         NMemType        = 4,
24
25         KB              = 1024,
26
27         MemMin          = 8*MB,
28         MemMax          = (3*1024+768)*MB,
29 };
30
31 typedef struct Map Map;
32 struct Map {
33         ulong   size;
34         ulong   addr;
35 };
36
37 typedef struct RMap RMap;
38 struct RMap {
39         char*   name;
40         Map*    map;
41         Map*    mapend;
42
43         Lock;
44 };
45
46 /* 
47  * Memory allocation tracking.
48  */
49 static Map mapupa[16];
50 static RMap rmapupa = {
51         "unallocated unbacked physical memory",
52         mapupa,
53         &mapupa[nelem(mapupa)-1],
54 };
55
56 static Map xmapupa[16];
57 static RMap xrmapupa = {
58         "unbacked physical memory",
59         xmapupa,
60         &xmapupa[nelem(xmapupa)-1],
61 };
62
63 static Map mapram[16];
64 static RMap rmapram = {
65         "physical memory",
66         mapram,
67         &mapram[nelem(mapram)-1],
68 };
69
70 static Map mapumb[64];
71 static RMap rmapumb = {
72         "upper memory block",
73         mapumb,
74         &mapumb[nelem(mapumb)-1],
75 };
76
77 static Map mapumbrw[16];
78 static RMap rmapumbrw = {
79         "UMB device memory",
80         mapumbrw,
81         &mapumbrw[nelem(mapumbrw)-1],
82 };
83
84 void
85 mapprint(RMap *rmap)
86 {
87         Map *mp;
88
89         print("%s\n", rmap->name);      
90         for(mp = rmap->map; mp->size; mp++)
91                 print("\t%8.8luX %8.8luX (%lud)\n", mp->addr, mp->addr+mp->size, mp->size);
92 }
93
94
95 void
96 memdebug(void)
97 {
98         ulong maxpa, maxpa1, maxpa2;
99
100         maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
101         maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
102         maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
103         print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
104                 maxpa, MB+maxpa*KB, maxpa1, maxpa2);
105
106         mapprint(&rmapram);
107         mapprint(&rmapumb);
108         mapprint(&rmapumbrw);
109         mapprint(&rmapupa);
110 }
111
112 void
113 mapfree(RMap* rmap, ulong addr, ulong size)
114 {
115         Map *mp;
116         ulong t;
117
118         if(size <= 0)
119                 return;
120
121         lock(rmap);
122         for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
123                 ;
124
125         if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
126                 (mp-1)->size += size;
127                 if(addr+size == mp->addr){
128                         (mp-1)->size += mp->size;
129                         while(mp->size){
130                                 mp++;
131                                 (mp-1)->addr = mp->addr;
132                                 (mp-1)->size = mp->size;
133                         }
134                 }
135         }
136         else{
137                 if(addr+size == mp->addr && mp->size){
138                         mp->addr -= size;
139                         mp->size += size;
140                 }
141                 else do{
142                         if(mp >= rmap->mapend){
143                                 print("mapfree: %s: losing 0x%luX, %ld\n",
144                                         rmap->name, addr, size);
145                                 break;
146                         }
147                         t = mp->addr;
148                         mp->addr = addr;
149                         addr = t;
150                         t = mp->size;
151                         mp->size = size;
152                         mp++;
153                 }while(size = t);
154         }
155         unlock(rmap);
156 }
157
158 ulong
159 mapalloc(RMap* rmap, ulong addr, int size, int align)
160 {
161         Map *mp;
162         ulong maddr, oaddr;
163
164         lock(rmap);
165         for(mp = rmap->map; mp->size; mp++){
166                 maddr = mp->addr;
167
168                 if(addr){
169                         /*
170                          * A specific address range has been given:
171                          *   if the current map entry is greater then
172                          *   the address is not in the map;
173                          *   if the current map entry does not overlap
174                          *   the beginning of the requested range then
175                          *   continue on to the next map entry;
176                          *   if the current map entry does not entirely
177                          *   contain the requested range then the range
178                          *   is not in the map.
179                          */
180                         if(maddr > addr)
181                                 break;
182                         if(mp->size < addr - maddr)     /* maddr+mp->size < addr, but no overflow */
183                                 continue;
184                         if(addr - maddr > mp->size - size)      /* addr+size > maddr+mp->size, but no overflow */
185                                 break;
186                         maddr = addr;
187                 }
188
189                 if(align > 0)
190                         maddr = ((maddr+align-1)/align)*align;
191                 if(mp->addr+mp->size-maddr < size)
192                         continue;
193
194                 oaddr = mp->addr;
195                 mp->addr = maddr+size;
196                 mp->size -= maddr-oaddr+size;
197                 if(mp->size == 0){
198                         do{
199                                 mp++;
200                                 (mp-1)->addr = mp->addr;
201                         }while((mp-1)->size = mp->size);
202                 }
203
204                 unlock(rmap);
205                 if(oaddr != maddr)
206                         mapfree(rmap, oaddr, maddr-oaddr);
207
208                 return maddr;
209         }
210         unlock(rmap);
211
212         return 0;
213 }
214
215 /*
216  * Allocate from the ram map directly to make page tables.
217  * Called by mmuwalk during e820scan.
218  */
219 void*
220 rampage(void)
221 {
222         ulong m;
223         
224         m = mapalloc(&rmapram, 0, BY2PG, BY2PG);
225         if(m == 0)
226                 return nil;
227         return KADDR(m);
228 }
229
230 static void
231 umbexclude(void)
232 {
233         int size;
234         ulong addr;
235         char *op, *p, *rptr;
236
237         if((p = getconf("umbexclude")) == nil)
238                 return;
239
240         while(p && *p != '\0' && *p != '\n'){
241                 op = p;
242                 addr = strtoul(p, &rptr, 0);
243                 if(rptr == nil || rptr == p || *rptr != '-'){
244                         print("umbexclude: invalid argument <%s>\n", op);
245                         break;
246                 }
247                 p = rptr+1;
248
249                 size = strtoul(p, &rptr, 0) - addr + 1;
250                 if(size <= 0){
251                         print("umbexclude: bad range <%s>\n", op);
252                         break;
253                 }
254                 if(rptr != nil && *rptr == ',')
255                         *rptr++ = '\0';
256                 p = rptr;
257
258                 mapalloc(&rmapumb, addr, size, 0);
259         }
260 }
261
262 static void
263 umbscan(void)
264 {
265         uchar *p;
266
267         /*
268          * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
269          * which aren't used; they can be used later for devices which
270          * want to allocate some virtual address space.
271          * Check for two things:
272          * 1) device BIOS ROM. This should start with a two-byte header
273          *    of 0x55 0xAA, followed by a byte giving the size of the ROM
274          *    in 512-byte chunks. These ROM's must start on a 2KB boundary.
275          * 2) device memory. This is read-write.
276          * There are some assumptions: there's VGA memory at 0xA0000 and
277          * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
278          * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up
279          * for grabs; check anyway.
280          */
281         p = KADDR(0xD0000);
282         while(p < (uchar*)KADDR(0xE0000)){
283                 /*
284                  * Test for 0x55 0xAA before poking obtrusively,
285                  * some machines (e.g. Thinkpad X20) seem to map
286                  * something dynamic here (cardbus?) causing weird
287                  * problems if it is changed.
288                  */
289                 if(p[0] == 0x55 && p[1] == 0xAA){
290                         p += p[2]*512;
291                         continue;
292                 }
293
294                 p[0] = 0xCC;
295                 p[2*KB-1] = 0xCC;
296                 if(p[0] != 0xCC || p[2*KB-1] != 0xCC){
297                         p[0] = 0x55;
298                         p[1] = 0xAA;
299                         p[2] = 4;
300                         if(p[0] == 0x55 && p[1] == 0xAA){
301                                 p += p[2]*512;
302                                 continue;
303                         }
304                         if(p[0] == 0xFF && p[1] == 0xFF)
305                                 mapfree(&rmapumb, PADDR(p), 2*KB);
306                 }
307                 else
308                         mapfree(&rmapumbrw, PADDR(p), 2*KB);
309                 p += 2*KB;
310         }
311
312         p = KADDR(0xE0000);
313         if(p[0] != 0x55 || p[1] != 0xAA){
314                 p[0] = 0xCC;
315                 p[64*KB-1] = 0xCC;
316                 if(p[0] != 0xCC && p[64*KB-1] != 0xCC)
317                         mapfree(&rmapumb, PADDR(p), 64*KB);
318         }
319
320         umbexclude();
321 }
322
323 static void
324 lowraminit(void)
325 {
326         ulong n, pa, x;
327         uchar *bda;
328
329         /*
330          * Initialise the memory bank information for conventional memory
331          * (i.e. less than 640KB). The base is the first location after the
332          * bootstrap processor MMU information and the limit is obtained from
333          * the BIOS data area.
334          */
335         x = PADDR(CPU0END);
336         bda = (uchar*)KADDR(0x400);
337         n = ((bda[0x14]<<8)|bda[0x13])*KB-x;
338         mapfree(&rmapram, x, n);
339         memset(KADDR(x), 0, n);                 /* keep us honest */
340
341         x = PADDR(PGROUND((ulong)end));
342         pa = MemMin;
343         if(x > pa)
344                 panic("kernel too big");
345         mapfree(&rmapram, x, pa-x);
346         memset(KADDR(x), 0, pa-x);              /* keep us honest */
347 }
348
349 static void
350 ramscan(ulong maxmem)
351 {
352         ulong *k0, kzero, map, maxkpa, maxpa, pa, *pte, *table, *va, vbase, x;
353         int nvalid[NMemType];
354
355         /*
356          * The bootstrap code has has created a prototype page
357          * table which maps the first MemMin of physical memory to KZERO.
358          * The page directory is at m->pdb and the first page of
359          * free memory is after the per-processor MMU information.
360          */
361         pa = MemMin;
362
363         /*
364          * Check if the extended memory size can be obtained from the CMOS.
365          * If it's 0 then it's either not known or >= 64MB. Always check
366          * at least 24MB in case there's a memory gap (up to 8MB) below 16MB;
367          * in this case the memory from the gap is remapped to the top of
368          * memory.
369          * The value in CMOS is supposed to be the number of KB above 1MB.
370          */
371         if(maxmem == 0){
372                 x = (nvramread(0x18)<<8)|nvramread(0x17);
373                 if(x == 0 || x >= (63*KB))
374                         maxpa = MemMax;
375                 else
376                         maxpa = MB+x*KB;
377                 if(maxpa < 24*MB)
378                         maxpa = 24*MB;
379         }else
380                 maxpa = maxmem;
381         maxkpa = (u32int)-KZERO;        /* 2^32 - KZERO */
382
383         /*
384          * March up memory from MemMin to maxpa 1MB at a time,
385          * mapping the first page and checking the page can
386          * be written and read correctly. The page tables are created here
387          * on the fly, allocating from low memory as necessary.
388          */
389         k0 = (ulong*)KADDR(0);
390         kzero = *k0;
391         map = 0;
392         x = 0x12345678;
393         memset(nvalid, 0, sizeof(nvalid));
394         
395         /*
396          * Can't map memory to KADDR(pa) when we're walking because
397          * can only use KADDR for relatively low addresses.
398          * Instead, map each 4MB we scan to the virtual address range
399          * MemMin->MemMin+4MB while we are scanning.
400          */
401         vbase = MemMin;
402         while(pa < maxpa){
403                 /*
404                  * Map the page. Use mapalloc(&rmapram, ...) to make
405                  * the page table if necessary, it will be returned to the
406                  * pool later if it isn't needed.  Map in a fixed range (the second 4M)
407                  * because high physical addresses cannot be passed to KADDR.
408                  */
409                 va = (void*)(vbase + pa%(4*MB));
410                 table = &m->pdb[PDX(va)];
411                 if(pa%(4*MB) == 0){
412                         if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
413                                 break;
414                         memset(KADDR(map), 0, BY2PG);
415                         *table = map|PTEWRITE|PTEVALID;
416                         memset(nvalid, 0, sizeof(nvalid));
417                 }
418                 table = KADDR(PPN(*table));
419                 pte = &table[PTX(va)];
420
421                 *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
422                 mmuflushtlb(PADDR(m->pdb));
423                 /*
424                  * Write a pattern to the page and write a different
425                  * pattern to a possible mirror at KZERO. If the data
426                  * reads back correctly the chunk is some type of RAM (possibly
427                  * a linearly-mapped VGA framebuffer, for instance...) and
428                  * can be cleared and added to the memory pool. If not, the
429                  * chunk is marked uncached and added to the UMB pool if <16MB
430                  * or is marked invalid and added to the UPA pool.
431                  */
432                 *va = x;
433                 *k0 = ~x;
434                 if(*va == x){
435                         nvalid[MemRAM] += MB/BY2PG;
436                         mapfree(&rmapram, pa, MB);
437
438                         do{
439                                 *pte++ = pa|PTEWRITE|PTEVALID;
440                                 pa += BY2PG;
441                         }while(pa % MB);
442                         mmuflushtlb(PADDR(m->pdb));
443                         /* memset(va, 0, MB); so damn slow to memset all of memory */
444                 }
445                 else if(pa < 16*MB){
446                         nvalid[MemUMB] += MB/BY2PG;
447                         mapfree(&rmapumb, pa, MB);
448
449                         do{
450                                 *pte++ = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
451                                 pa += BY2PG;
452                         }while(pa % MB);
453                 }
454                 else{
455                         nvalid[MemUPA] += MB/BY2PG;
456                         mapfree(&rmapupa, pa, MB);
457
458                         *pte = 0;
459                         pa += MB;
460                 }
461                 /*
462                  * Done with this 4MB chunk, review the options:
463                  * 1) not physical memory and >=16MB - invalidate the PDB entry;
464                  * 2) physical memory - use the 4MB page extension if possible;
465                  * 3) not physical memory and <16MB - use the 4MB page extension
466                  *    if possible;
467                  * 4) mixed or no 4MB page extension - commit the already
468                  *    initialised space for the page table.
469                  */
470                 if(pa%(4*MB) == 0 && pa >= 32*MB && nvalid[MemUPA] == (4*MB)/BY2PG){
471                         /*
472                          * If we encounter a 4MB chunk of missing memory
473                          * at a sufficiently high offset, call it the end of
474                          * memory.  Otherwise we run the risk of thinking
475                          * that video memory is real RAM.
476                          */
477                         break;
478                 }
479                 if(pa <= maxkpa && pa%(4*MB) == 0){
480                         table = &m->pdb[PDX(KADDR(pa - 4*MB))];
481                         if(nvalid[MemUPA] == (4*MB)/BY2PG)
482                                 *table = 0;
483                         else if(nvalid[MemRAM] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
484                                 *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEVALID;
485                         else if(nvalid[MemUMB] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
486                                 *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
487                         else{
488                                 *table = map|PTEWRITE|PTEVALID;
489                                 map = 0;
490                         }
491                 }
492                 mmuflushtlb(PADDR(m->pdb));
493                 x += 0x3141526;
494         }
495         /*
496          * If we didn't reach the end of the 4MB chunk, that part won't
497          * be mapped.  Commit the already initialised space for the page table.
498          */
499         if(pa % (4*MB) && pa <= maxkpa){
500                 m->pdb[PDX(KADDR(pa))] = map|PTEWRITE|PTEVALID;
501                 map = 0;
502         }
503         if(map)
504                 mapfree(&rmapram, map, BY2PG);
505
506         m->pdb[PDX(vbase)] = 0;
507         mmuflushtlb(PADDR(m->pdb));
508
509         mapfree(&rmapupa, pa, (u32int)-pa);
510         *k0 = kzero;
511 }
512
513 /*
514  * BIOS Int 0x15 E820 memory map.
515  */
516 enum
517 {
518         SMAP = ('S'<<24)|('M'<<16)|('A'<<8)|'P',
519         Ememory = 1,
520         Ereserved = 2,
521         Carry = 1,
522 };
523
524 typedef struct Emap Emap;
525 struct Emap
526 {
527         uvlong base;
528         uvlong len;
529         ulong type;
530 };
531 static Emap emap[16];
532 int nemap;
533
534 static char *etypes[] =
535 {
536         "type=0",
537         "memory",
538         "reserved",
539         "acpi reclaim",
540         "acpi nvs",
541 };
542
543 static int
544 emapcmp(const void *va, const void *vb)
545 {
546         Emap *a, *b;
547         
548         a = (Emap*)va;
549         b = (Emap*)vb;
550         if(a->base < b->base)
551                 return -1;
552         if(a->base > b->base)
553                 return 1;
554         if(a->len < b->len)
555                 return -1;
556         if(a->len > b->len)
557                 return 1;
558         return a->type - b->type;
559 }
560
561 static void
562 map(ulong base, ulong len, int type)
563 {
564         ulong e, n;
565         ulong *table, flags, maxkpa;
566         
567         /*
568          * Split any call crossing MemMin to make below simpler.
569          */
570         if(base < MemMin && len > MemMin-base){
571                 n = MemMin - base;
572                 map(base, n, type);
573                 map(MemMin, len-n, type);
574         }
575         
576         /*
577          * Let lowraminit and umbscan hash out the low MemMin.
578          */
579         if(base < MemMin)
580                 return;
581
582         /*
583          * Any non-memory below 16*MB is used as upper mem blocks.
584          */
585         if(type == MemUPA && base < 16*MB && base+len > 16*MB){
586                 map(base, 16*MB-base, MemUMB);
587                 map(16*MB, len-(16*MB-base), MemUPA);
588                 return;
589         }
590         
591         /*
592          * Memory below CPU0END is reserved for the kernel
593          * and already mapped.
594          */
595         if(base < PADDR(CPU0END)){
596                 n = PADDR(CPU0END) - base;
597                 if(len <= n)
598                         return;
599                 map(PADDR(CPU0END), len-n, type);
600                 return;
601         }
602         
603         /*
604          * Memory between KTZERO and end is the kernel itself
605          * and is already mapped.
606          */
607         if(base < PADDR(KTZERO) && base+len > PADDR(KTZERO)){
608                 map(base, PADDR(KTZERO)-base, type);
609                 return;
610         }
611         if(PADDR(KTZERO) < base && base < PADDR(PGROUND((ulong)end))){
612                 n = PADDR(PGROUND((ulong)end));
613                 if(len <= n)
614                         return;
615                 map(PADDR(PGROUND((ulong)end)), len-n, type);
616                 return;
617         }
618         
619         /*
620          * Now we have a simple case.
621          */
622         // print("map %.8lux %.8lux %d\n", base, base+len, type);
623         switch(type){
624         case MemRAM:
625                 mapfree(&rmapram, base, len);
626                 flags = PTEWRITE|PTEVALID;
627                 break;
628         case MemUMB:
629                 mapfree(&rmapumb, base, len);
630                 flags = PTEWRITE|PTEUNCACHED|PTEVALID;
631                 break;
632         case MemUPA:
633                 mapfree(&rmapupa, base, len);
634                 flags = 0;
635                 break;
636         default:
637         case MemReserved:
638                 flags = 0;
639                 break;
640         }
641         
642         /*
643          * bottom MemMin is already mapped - just twiddle flags.
644          * (not currently used - see above)
645          */
646         if(base < MemMin){
647                 table = KADDR(PPN(m->pdb[PDX(base)]));
648                 e = base+len;
649                 base = PPN(base);
650                 for(; base<e; base+=BY2PG)
651                         table[PTX(base)] |= flags;
652                 return;
653         }
654         
655         /*
656          * Only map from KZERO to 2^32.
657          */
658         if(flags){
659                 maxkpa = -KZERO;
660                 if(base >= maxkpa)
661                         return;
662                 if(len > maxkpa-base)
663                         len = maxkpa - base;
664                 pdbmap(m->pdb, base|flags, base+KZERO, len);
665         }
666 }
667
668 static int
669 e820scan(void)
670 {
671         int i;
672         Ureg u;
673         ulong cont, base, len;
674         uvlong last;
675         Emap *e;
676         char *s;
677
678         if((s = getconf("e820")) != nil){
679                 for(nemap = 0; nemap < nelem(emap); nemap++){
680                         if(*s == 0)
681                                 break;
682                         e = emap + nemap;
683                         e->base = strtoull(s, &s, 16);
684                         if(*s != ' ')
685                                 break;
686                         e->len = strtoull(s, &s, 16) - e->base;
687                         if(*s != ' ' && *s != 0 || e->len >= 1ull<<32 || e->len == 0)
688                                 break;
689                         e->type = Ememory;
690                 }
691         }else{
692                 if(getconf("*norealmode") || getconf("*noe820scan"))
693                         return -1;
694                 cont = 0;
695                 for(i=0; i<nelem(emap); i++){
696                         memset(&u, 0, sizeof u);
697                         u.ax = 0xE820;
698                         u.bx = cont;
699                         u.cx = 20;
700                         u.dx = SMAP;
701                         u.es = (PADDR(RMBUF)>>4)&0xF000;
702                         u.di = PADDR(RMBUF)&0xFFFF;
703                         u.trap = 0x15;
704                         realmode(&u);
705                         cont = u.bx;
706                         if((u.flags&Carry) || u.ax != SMAP || u.cx != 20)
707                                 break;
708                         e = &emap[nemap++];
709                         *e = *(Emap*)RMBUF;
710                         if(u.bx == 0)
711                                 break;
712                 }
713         }
714
715         if(nemap == 0)
716                 return -1;
717         
718         qsort(emap, nemap, sizeof emap[0], emapcmp);
719
720         if(s == nil && getconf("*noe820print") == nil){
721                 for(i=0; i<nemap; i++){
722                         e = &emap[i];
723                         print("E820: %.8llux %.8llux ", e->base, e->base+e->len);
724                         if(e->type < nelem(etypes))
725                                 print("%s\n", etypes[e->type]);
726                         else
727                                 print("type=%lud\n", e->type);
728                 }
729         }
730
731         last = 0;
732         for(i=0; i<nemap; i++){ 
733                 e = &emap[i];
734                 /*
735                  * pull out the info but only about the low 32 bits...
736                  */
737                 if(e->base >= (1LL<<32))
738                         break;
739                 base = e->base;
740                 if(base+e->len > (1LL<<32))
741                         len = -base;
742                 else
743                         len = e->len;
744                 /*
745                  * If the map skips addresses, mark them available.
746                  */
747                 if(last < e->base)
748                         map(last, e->base-last, MemUPA);
749                 last = base+len;
750                 if(e->type == Ememory)
751                         map(base, len, MemRAM);
752                 else
753                         map(base, len, MemReserved);
754         }
755         if(last < (1LL<<32))
756                 map(last, (u32int)-last, MemUPA);
757         return 0;
758 }
759
760 void
761 meminit(void)
762 {
763         int i;
764         Map *mp;
765         Confmem *cm;
766         ulong pa, *pte;
767         ulong maxmem, lost;
768         char *p;
769
770         if(p = getconf("*maxmem"))
771                 maxmem = strtoul(p, 0, 0);
772         else
773                 maxmem = 0;
774
775         /*
776          * Set special attributes for memory between 640KB and 1MB:
777          *   VGA memory is writethrough;
778          *   BIOS ROM's/UMB's are uncached;
779          * then scan for useful memory.
780          */
781         for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){
782                 pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
783                 *pte |= PTEWT;
784         }
785         for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){
786                 pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
787                 *pte |= PTEUNCACHED;
788         }
789         mmuflushtlb(PADDR(m->pdb));
790
791         umbscan();
792         lowraminit();
793         if(e820scan() < 0)
794                 ramscan(maxmem);
795
796         /*
797          * Set the conf entries describing banks of allocatable memory.
798          */
799         for(i=0; i<nelem(mapram) && i<nelem(conf.mem); i++){
800                 mp = &rmapram.map[i];
801                 cm = &conf.mem[i];
802                 cm->base = mp->addr;
803                 cm->npage = mp->size/BY2PG;
804         }
805         
806         lost = 0;
807         for(; i<nelem(mapram); i++)
808                 lost += rmapram.map[i].size;
809         if(lost)
810                 print("meminit - lost %lud bytes\n", lost);
811
812         if(MEMDEBUG)
813                 memdebug();
814 }
815
816 /*
817  * Allocate memory from the upper memory blocks.
818  */
819 ulong
820 umbmalloc(ulong addr, int size, int align)
821 {
822         ulong a;
823
824         if(a = mapalloc(&rmapumb, addr, size, align))
825                 return (ulong)KADDR(a);
826
827         return 0;
828 }
829
830 void
831 umbfree(ulong addr, int size)
832 {
833         mapfree(&rmapumb, PADDR(addr), size);
834 }
835
836 ulong
837 umbrwmalloc(ulong addr, int size, int align)
838 {
839         ulong a;
840         uchar *p;
841
842         if(a = mapalloc(&rmapumbrw, addr, size, align))
843                 return(ulong)KADDR(a);
844
845         /*
846          * Perhaps the memory wasn't visible before
847          * the interface is initialised, so try again.
848          */
849         if((a = umbmalloc(addr, size, align)) == 0)
850                 return 0;
851         p = (uchar*)a;
852         p[0] = 0xCC;
853         p[size-1] = 0xCC;
854         if(p[0] == 0xCC && p[size-1] == 0xCC)
855                 return a;
856         umbfree(a, size);
857
858         return 0;
859 }
860
861 void
862 umbrwfree(ulong addr, int size)
863 {
864         mapfree(&rmapumbrw, PADDR(addr), size);
865 }
866
867 /*
868  * Give out otherwise-unused physical address space
869  * for use in configuring devices.  Note that unlike upamalloc
870  * before it, upaalloc does not map the physical address
871  * into virtual memory.  Call vmap to do that.
872  */
873 ulong
874 upaalloc(int size, int align)
875 {
876         ulong a;
877
878         a = mapalloc(&rmapupa, 0, size, align);
879         if(a == 0){
880                 print("out of physical address space allocating %d\n", size);
881                 mapprint(&rmapupa);
882         }
883         return a;
884 }
885
886 void
887 upafree(ulong pa, int size)
888 {
889         mapfree(&rmapupa, pa, size);
890 }
891
892 void
893 upareserve(ulong pa, int size)
894 {
895         ulong a;
896         
897         a = mapalloc(&rmapupa, pa, size, 0);
898         if(a != pa){
899                 /*
900                  * This can happen when we're using the E820
901                  * map, which might have already reserved some
902                  * of the regions claimed by the pci devices.
903                  */
904         //      print("upareserve: cannot reserve pa=%#.8lux size=%d\n", pa, size);
905                 if(a != 0)
906                         mapfree(&rmapupa, a, size);
907         }
908 }
909
910 void
911 memorysummary(void)
912 {
913         memdebug();
914 }
915