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