]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc64/memory.c
pc, pc64: state dependency to usbehci.h in mkfiles
[plan9front.git] / sys / src / 9 / pc64 / 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  */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "ureg.h"
14
15 u32int  MemMin;         /* set by l.s */
16
17 #define MEMDEBUG        0
18
19 enum {
20         MemUPA          = 0,            /* unbacked physical address */
21         MemRAM          = 1,            /* physical memory */
22         MemUMB          = 2,            /* upper memory block (<16MB) */
23         MemReserved     = 3,
24         NMemType        = 4,
25
26         KB              = 1024,
27 };
28
29 typedef struct Map Map;
30 struct Map {
31         uintptr size;
32         uintptr addr;
33 };
34
35 typedef struct RMap RMap;
36 struct RMap {
37         char*   name;
38         Map*    map;
39         Map*    mapend;
40
41         Lock;
42 };
43
44 /* 
45  * Memory allocation tracking.
46  */
47 static Map mapupa[64];
48 static RMap rmapupa = {
49         "unallocated unbacked physical memory",
50         mapupa,
51         &mapupa[nelem(mapupa)-1],
52 };
53
54 static Map mapram[16];
55 static RMap rmapram = {
56         "physical memory",
57         mapram,
58         &mapram[nelem(mapram)-1],
59 };
60
61 static Map mapumb[64];
62 static RMap rmapumb = {
63         "upper memory block",
64         mapumb,
65         &mapumb[nelem(mapumb)-1],
66 };
67
68 static Map mapumbrw[16];
69 static RMap rmapumbrw = {
70         "UMB device memory",
71         mapumbrw,
72         &mapumbrw[nelem(mapumbrw)-1],
73 };
74
75 void
76 mapprint(RMap *rmap)
77 {
78         Map *mp;
79
80         print("%s\n", rmap->name);      
81         for(mp = rmap->map; mp->size; mp++)
82                 print("\t%#p %#p (%#p)\n", mp->addr, mp->addr+mp->size, mp->size);
83 }
84
85
86 void
87 memdebug(void)
88 {
89         ulong maxpa, maxpa1, maxpa2;
90
91         maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
92         maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
93         maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
94         print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
95                 maxpa, MB+maxpa*KB, maxpa1, maxpa2);
96
97         mapprint(&rmapram);
98         mapprint(&rmapumb);
99         mapprint(&rmapumbrw);
100         mapprint(&rmapupa);
101 }
102
103 void
104 mapfree(RMap* rmap, uintptr addr, uintptr size)
105 {
106         Map *mp;
107         uintptr t;
108
109         if(size <= 0)
110                 return;
111
112         lock(rmap);
113         for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
114                 ;
115
116         if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
117                 (mp-1)->size += size;
118                 if(addr+size == mp->addr){
119                         (mp-1)->size += mp->size;
120                         while(mp->size){
121                                 mp++;
122                                 (mp-1)->addr = mp->addr;
123                                 (mp-1)->size = mp->size;
124                         }
125                 }
126         }
127         else{
128                 if(addr+size == mp->addr && mp->size){
129                         mp->addr -= size;
130                         mp->size += size;
131                 }
132                 else do{
133                         if(mp >= rmap->mapend){
134                                 print("mapfree: %s: losing %#p, %#p\n",
135                                         rmap->name, addr, size);
136                                 break;
137                         }
138                         t = mp->addr;
139                         mp->addr = addr;
140                         addr = t;
141                         t = mp->size;
142                         mp->size = size;
143                         mp++;
144                 }while(size = t);
145         }
146         unlock(rmap);
147 }
148
149 uintptr
150 mapalloc(RMap* rmap, uintptr addr, int size, int align)
151 {
152         Map *mp;
153         uintptr maddr, oaddr;
154
155         lock(rmap);
156         for(mp = rmap->map; mp->size; mp++){
157                 maddr = mp->addr;
158
159                 if(addr){
160                         /*
161                          * A specific address range has been given:
162                          *   if the current map entry is greater then
163                          *   the address is not in the map;
164                          *   if the current map entry does not overlap
165                          *   the beginning of the requested range then
166                          *   continue on to the next map entry;
167                          *   if the current map entry does not entirely
168                          *   contain the requested range then the range
169                          *   is not in the map.
170                          */
171                         if(maddr > addr)
172                                 break;
173                         if(mp->size < addr - maddr)     /* maddr+mp->size < addr, but no overflow */
174                                 continue;
175                         if(addr - maddr > mp->size - size)      /* addr+size > maddr+mp->size, but no overflow */
176                                 break;
177                         maddr = addr;
178                 }
179
180                 if(align > 0)
181                         maddr = ((maddr+align-1)/align)*align;
182                 if(mp->addr+mp->size-maddr < size)
183                         continue;
184
185                 oaddr = mp->addr;
186                 mp->addr = maddr+size;
187                 mp->size -= maddr-oaddr+size;
188                 if(mp->size == 0){
189                         do{
190                                 mp++;
191                                 (mp-1)->addr = mp->addr;
192                         }while((mp-1)->size = mp->size);
193                 }
194
195                 unlock(rmap);
196                 if(oaddr != maddr)
197                         mapfree(rmap, oaddr, maddr-oaddr);
198
199                 return maddr;
200         }
201         unlock(rmap);
202
203         return 0;
204 }
205
206 /*
207  * Allocate from the ram map directly to make page tables.
208  * Called by mmuwalk during e820scan.
209  */
210 void*
211 rampage(void)
212 {
213         uintptr m;
214         
215         m = mapalloc(&rmapram, 0, BY2PG, BY2PG);
216         if(m == 0)
217                 return nil;
218         return KADDR(m);
219 }
220
221 static void
222 umbexclude(void)
223 {
224         int size;
225         ulong addr;
226         char *op, *p, *rptr;
227
228         if((p = getconf("umbexclude")) == nil)
229                 return;
230
231         while(p && *p != '\0' && *p != '\n'){
232                 op = p;
233                 addr = strtoul(p, &rptr, 0);
234                 if(rptr == nil || rptr == p || *rptr != '-'){
235                         print("umbexclude: invalid argument <%s>\n", op);
236                         break;
237                 }
238                 p = rptr+1;
239
240                 size = strtoul(p, &rptr, 0) - addr + 1;
241                 if(size <= 0){
242                         print("umbexclude: bad range <%s>\n", op);
243                         break;
244                 }
245                 if(rptr != nil && *rptr == ',')
246                         *rptr++ = '\0';
247                 p = rptr;
248
249                 mapalloc(&rmapumb, addr, size, 0);
250         }
251 }
252
253 static void
254 umbscan(void)
255 {
256         uchar *p;
257
258         /*
259          * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
260          * which aren't used; they can be used later for devices which
261          * want to allocate some virtual address space.
262          * Check for two things:
263          * 1) device BIOS ROM. This should start with a two-byte header
264          *    of 0x55 0xAA, followed by a byte giving the size of the ROM
265          *    in 512-byte chunks. These ROM's must start on a 2KB boundary.
266          * 2) device memory. This is read-write.
267          * There are some assumptions: there's VGA memory at 0xA0000 and
268          * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
269          * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up
270          * for grabs; check anyway.
271          */
272         p = KADDR(0xD0000);
273         while(p < (uchar*)KADDR(0xE0000)){
274                 /*
275                  * Test for 0x55 0xAA before poking obtrusively,
276                  * some machines (e.g. Thinkpad X20) seem to map
277                  * something dynamic here (cardbus?) causing weird
278                  * problems if it is changed.
279                  */
280                 if(p[0] == 0x55 && p[1] == 0xAA){
281                         p += p[2]*512;
282                         continue;
283                 }
284
285                 p[0] = 0xCC;
286                 p[2*KB-1] = 0xCC;
287                 if(p[0] != 0xCC || p[2*KB-1] != 0xCC){
288                         p[0] = 0x55;
289                         p[1] = 0xAA;
290                         p[2] = 4;
291                         if(p[0] == 0x55 && p[1] == 0xAA){
292                                 p += p[2]*512;
293                                 continue;
294                         }
295                         if(p[0] == 0xFF && p[1] == 0xFF)
296                                 mapfree(&rmapumb, PADDR(p), 2*KB);
297                 }
298                 else
299                         mapfree(&rmapumbrw, PADDR(p), 2*KB);
300                 p += 2*KB;
301         }
302
303         p = KADDR(0xE0000);
304         if(p[0] != 0x55 || p[1] != 0xAA){
305                 p[0] = 0xCC;
306                 p[64*KB-1] = 0xCC;
307                 if(p[0] != 0xCC && p[64*KB-1] != 0xCC)
308                         mapfree(&rmapumb, PADDR(p), 64*KB);
309         }
310
311         umbexclude();
312 }
313
314 int
315 checksum(void *v, int n)
316 {
317         uchar *p, s;
318
319         s = 0;
320         p = v;
321         while(n-- > 0)
322                 s += *p++;
323         return s;
324 }
325
326 static void*
327 sigscan(uchar* addr, int len, char* signature)
328 {
329         int sl;
330         uchar *e, *p;
331
332         e = addr+len;
333         sl = strlen(signature);
334         for(p = addr; p+sl < e; p += 16)
335                 if(memcmp(p, signature, sl) == 0)
336                         return p;
337         return nil;
338 }
339
340 static uintptr
341 convmemsize(void)
342 {
343         uintptr top;
344         uchar *bda;
345
346         bda = KADDR(0x400);
347         top = ((bda[0x14]<<8) | bda[0x13])*KB;
348
349         if(top < 64*KB || top > 640*KB)
350                 top = 640*KB;   /* sanity */
351
352         /* reserved for bios tables (EBDA) */
353         top -= 1*KB;
354
355         return top;
356 }
357
358 void*
359 sigsearch(char* signature)
360 {
361         uintptr p;
362         uchar *bda;
363         void *r;
364
365         /*
366          * Search for the data structure:
367          * 1) within the first KiB of the Extended BIOS Data Area (EBDA), or
368          * 2) within the last KiB of system base memory if the EBDA segment
369          *    is undefined, or
370          * 3) within the BIOS ROM address space between 0xf0000 and 0xfffff
371          *    (but will actually check 0xe0000 to 0xfffff).
372          */
373         bda = KADDR(0x400);
374         if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){
375                 if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){
376                         if((r = sigscan(KADDR(p<<4), 1024, signature)) != nil)
377                                 return r;
378                 }
379         }
380         if((r = sigscan(KADDR(convmemsize()), 1024, signature)) != nil)
381                 return r;
382
383         /* hack for virtualbox: look in KiB below 0xa0000 */
384         if((r = sigscan(KADDR(0xa0000-1024), 1024, signature)) != nil)
385                 return r;
386
387         return sigscan(KADDR(0xe0000), 0x20000, signature);
388 }
389
390 static void
391 lowraminit(void)
392 {
393         uintptr pa, x;
394
395         /*
396          * Initialise the memory bank information for conventional memory
397          * (i.e. less than 640KB). The base is the first location after the
398          * bootstrap processor MMU information and the limit is obtained from
399          * the BIOS data area.
400          */
401         x = PADDR(CPU0END);
402         pa = convmemsize();
403         if(x < pa){
404                 mapfree(&rmapram, x, pa-x);
405                 memset(KADDR(x), 0, pa-x);              /* keep us honest */
406         }
407
408         x = PADDR(PGROUND((uintptr)end));
409         pa = MemMin;
410         if(x > pa)
411                 panic("kernel too big");
412         mapfree(&rmapram, x, pa-x);
413         memset(KADDR(x), 0, pa-x);              /* keep us honest */
414 }
415
416 typedef struct Emap Emap;
417 struct Emap
418 {
419         int type;
420         uvlong base;
421         uvlong top;
422 };
423 static Emap emap[128];
424 int nemap;
425
426 static int
427 emapcmp(const void *va, const void *vb)
428 {
429         Emap *a, *b;
430         
431         a = (Emap*)va;
432         b = (Emap*)vb;
433         if(a->top < b->top)
434                 return -1;
435         if(a->top > b->top)
436                 return 1;
437         if(a->base < b->base)
438                 return -1;
439         if(a->base > b->base)
440                 return 1;
441         return 0;
442 }
443
444 static void
445 map(uintptr base, uintptr len, int type)
446 {
447         uintptr n, flags, maxkpa;
448
449         /*
450          * Split any call crossing MemMin to make below simpler.
451          */
452         if(base < MemMin && len > MemMin-base){
453                 n = MemMin - base;
454                 map(base, n, type);
455                 map(MemMin, len-n, type);
456         }
457         
458         /*
459          * Let umbscan hash out the low MemMin.
460          */
461         if(base < MemMin)
462                 return;
463
464         /*
465          * Any non-memory below 16*MB is used as upper mem blocks.
466          */
467         if(type == MemUPA && base < 16*MB && len > 16*MB-base){
468                 map(base, 16*MB-base, MemUMB);
469                 map(16*MB, len-(16*MB-base), MemUPA);
470                 return;
471         }
472         
473         /*
474          * Memory below CPU0END is reserved for the kernel
475          * and already mapped.
476          */
477         if(base < PADDR(CPU0END)){
478                 n = PADDR(CPU0END) - base;
479                 if(len <= n)
480                         return;
481                 map(PADDR(CPU0END), len-n, type);
482                 return;
483         }
484         
485         /*
486          * Memory between KTZERO and end is the kernel itself
487          * and is already mapped.
488          */
489         if(base < PADDR(KTZERO) && len > PADDR(KTZERO)-base){
490                 map(base, PADDR(KTZERO)-base, type);
491                 return;
492         }
493         if(PADDR(KTZERO) < base && base < PADDR(PGROUND((uintptr)end))){
494                 n = PADDR(PGROUND((uintptr)end));
495                 if(len <= n)
496                         return;
497                 map(PADDR(PGROUND((uintptr)end)), len-n, type);
498                 return;
499         }
500         
501         /*
502          * Now we have a simple case.
503          */
504         switch(type){
505         case MemRAM:
506                 mapfree(&rmapram, base, len);
507                 flags = PTEWRITE|PTEVALID;
508                 break;
509         case MemUMB:
510                 mapfree(&rmapumb, base, len);
511                 flags = PTEWRITE|PTEUNCACHED|PTEVALID;
512                 break;
513         case MemUPA:
514                 mapfree(&rmapupa, base, len);
515                 flags = 0;
516                 break;
517         default:
518         case MemReserved:
519                 flags = 0;
520                 break;
521         }
522         
523         if(flags){
524                 maxkpa = -KZERO;
525                 if(base >= maxkpa)
526                         return;
527                 if(len > maxkpa-base)
528                         len = maxkpa - base;
529                 pmap(m->pml4, base|flags, base+KZERO, len);
530         }
531 }
532
533 static int
534 e820scan(void)
535 {
536         uintptr base, len, last;
537         Emap *e;
538         char *s;
539         int i;
540
541         /* passed by bootloader */
542         if((s = getconf("*e820")) == nil)
543                 if((s = getconf("e820")) == nil)
544                         return -1;
545         nemap = 0;
546         while(nemap < nelem(emap)){
547                 while(*s == ' ')
548                         s++;
549                 if(*s == 0)
550                         break;
551                 e = emap + nemap;
552                 e->type = 1;
553                 if(s[1] == ' '){        /* new format */
554                         e->type = s[0] - '0';
555                         s += 2;
556                 }
557                 e->base = strtoull(s, &s, 16);
558                 if(*s != ' ')
559                         break;
560                 e->top  = strtoull(s, &s, 16);
561                 if(*s != ' ' && *s != 0)
562                         break;
563                 if(e->base < e->top)
564                         nemap++;
565         }
566         if(nemap == 0)
567                 return -1;
568         qsort(emap, nemap, sizeof emap[0], emapcmp);
569         last = 0;
570         for(i=0; i<nemap; i++){ 
571                 e = &emap[i];
572                 /*
573                  * pull out the info but only about the low 32 bits...
574                  */
575                 if(e->top <= last)
576                         continue;
577                 if(e->base < last)
578                         base = last;
579                 else
580                         base = e->base;
581                 len = e->top - base;
582                 /*
583                  * If the map skips addresses, mark them available.
584                  */
585                 if(last < base)
586                         map(last, base-last, MemUPA);
587                 map(base, len, (e->type == 1) ? MemRAM : MemReserved);
588                 last = base + len;
589                 if(last == 0)
590                         break;
591         }
592         if(last != 0)
593                 map(last, -last, MemUPA);
594         return 0;
595 }
596
597 void
598 meminit(void)
599 {
600         int i;
601         Map *mp;
602         Confmem *cm;
603         uintptr lost;
604
605         umbscan();
606         lowraminit();
607         e820scan();
608
609         /*
610          * Set the conf entries describing banks of allocatable memory.
611          */
612         for(i=0; i<nelem(mapram) && i<nelem(conf.mem); i++){
613                 mp = &rmapram.map[i];
614                 cm = &conf.mem[i];
615                 cm->base = mp->addr;
616                 cm->npage = mp->size/BY2PG;
617         }
618
619         lost = 0;
620         for(; i<nelem(mapram); i++)
621                 lost += rmapram.map[i].size;
622         if(lost)
623                 print("meminit - lost %llud bytes\n", lost);
624
625         if(MEMDEBUG)
626                 memdebug();
627 }
628
629 /*
630  * Allocate memory from the upper memory blocks.
631  */
632 uintptr
633 umbmalloc(uintptr addr, int size, int align)
634 {
635         uintptr a;
636
637         if(a = mapalloc(&rmapumb, addr, size, align))
638                 return (uintptr)KADDR(a);
639
640         return 0;
641 }
642
643 void
644 umbfree(uintptr addr, int size)
645 {
646         mapfree(&rmapumb, PADDR(addr), size);
647 }
648
649 uintptr
650 umbrwmalloc(uintptr addr, int size, int align)
651 {
652         uintptr a;
653         uchar *p;
654
655         if(a = mapalloc(&rmapumbrw, addr, size, align))
656                 return (uintptr)KADDR(a);
657
658         /*
659          * Perhaps the memory wasn't visible before
660          * the interface is initialised, so try again.
661          */
662         if((a = umbmalloc(addr, size, align)) == 0)
663                 return 0;
664         p = (uchar*)a;
665         p[0] = 0xCC;
666         p[size-1] = 0xCC;
667         if(p[0] == 0xCC && p[size-1] == 0xCC)
668                 return a;
669         umbfree(a, size);
670
671         return 0;
672 }
673
674 void
675 umbrwfree(uintptr addr, int size)
676 {
677         mapfree(&rmapumbrw, PADDR(addr), size);
678 }
679
680 /*
681  * Give out otherwise-unused physical address space
682  * for use in configuring devices.  Note that upaalloc
683  * does not map the physical address into virtual memory.
684  * Call vmap to do that.
685  */
686 uintptr
687 upaalloc(int size, int align)
688 {
689         uintptr a;
690
691         a = mapalloc(&rmapupa, 0, size, align);
692         if(a == 0){
693                 print("out of physical address space allocating %d\n", size);
694                 mapprint(&rmapupa);
695         }
696         return a;
697 }
698
699 void
700 upafree(uintptr pa, int size)
701 {
702         mapfree(&rmapupa, pa, size);
703 }
704
705 void
706 upareserve(uintptr pa, int size)
707 {
708         uintptr a;
709         
710         a = mapalloc(&rmapupa, pa, size, 0);
711         if(a != pa){
712                 /*
713                  * This can happen when we're using the E820
714                  * map, which might have already reserved some
715                  * of the regions claimed by the pci devices.
716                  */
717         //      print("upareserve: cannot reserve pa=%#p size=%d\n", pa, size);
718                 if(a != 0)
719                         mapfree(&rmapupa, a, size);
720         }
721 }
722
723 void
724 memorysummary(void)
725 {
726         memdebug();
727 }
728