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