#include "all.h" #include "mem.h" #include "io.h" #include "ureg.h" /* * Where configuration info is left for the loaded programme. * This will turn into a structure as more is done by the boot loader * (e.g. why parse the .ini file twice?). * There are 1024 bytes available at CONFADDR. */ #define BOOTLINE ((char*)CONFADDR) #define BOOTLINELEN 64 #define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) #define BOOTARGSLEN (1024-BOOTLINELEN) #define MAXCONF 32 char bootdisk[NAMELEN]; char *confname[MAXCONF]; char *confval[MAXCONF]; int nconf; int getcfields(char* lp, char** fields, int n, char* sep) { int i; for(i = 0; lp && *lp && i < n; i++){ while(*lp && strchr(sep, *lp) != 0) *lp++ = 0; if(*lp == 0) break; fields[i] = lp; while(*lp && strchr(sep, *lp) == 0){ if(*lp == '\\' && *(lp+1) == '\n') *lp++ = ' '; lp++; } } return i; } static void options(void) { long i, n; char *cp, *line[MAXCONF], *p, *q; /* * parse configuration args from dos file plan9.ini */ cp = BOOTARGS; /* where b.com leaves its config */ cp[BOOTARGSLEN-1] = 0; /* * Strip out '\r', change '\t' -> ' '. */ p = cp; for(q = cp; *q; q++){ if(*q == '\r') continue; if(*q == '\t') *q = ' '; *p++ = *q; } *p = 0; n = getcfields(cp, line, MAXCONF, "\n"); for(i = 0; i < n; i++){ if(*line[i] == '#') continue; cp = strchr(line[i], '='); if(cp == 0) continue; *cp++ = 0; if(cp - line[i] >= NAMELEN+1) *(line[i]+NAMELEN-1) = 0; confname[nconf] = line[i]; confval[nconf] = cp; nconf++; } } /* * Vecinit is the first hook we have into configuring the machine, * so we do it all here. A pox on special fileserver code. * We do more in meminit below. */ void vecinit(void) { options(); } char* getconf(char *name) { int i; for(i = 0; i < nconf; i++) if(cistrcmp(confname[i], name) == 0) return confval[i]; return 0; } /* * old memory scan. if no e820 information is available, * this kernel will see MAXMEG megabytes of RAM at most. * maxmeg is limited due the the fact the page table might be too large * for our temporary mapping to hold and depends on the size of * our kernel. */ #ifndef MAXMEG #define MAXMEG 2015 #endif char mmap[MAXMEG+2]; Mconf mconf; static void mconfscan(void) { ulong x, i, j, ktop; Mbank *b; /* * size memory above 4 meg. Kernel sits at 1 meg. We * only recognize MB size chunks. */ x = 0x12345678; for(i = 4; i <= MAXMEG; i++){ /* * write the first & last word in a megabyte of memory */ *mapaddr(i*MB) = x; *mapaddr((i+1)*MB-BY2WD) = x; /* * write the first and last word in all previous megs to * handle address wrap around */ for(j = 4; j < i; j++){ *mapaddr(j*MB) = ~x; *mapaddr((j+1)*MB-BY2WD) = ~x; } /* * check for correct value */ if(*mapaddr(i*MB) == x && *mapaddr((i+1)*MB-BY2WD) == x) mmap[i] = 'x'; x += 0x3141526; } b = mconf.bank; ktop = PGROUND((ulong)end); ktop = PADDR(ktop); b->base = ktop; /* careful with that ax, eugene */ for(i = 4; mmap[i] == 'x'; i++) ; b->limit = i*MB; mconf.topofmem = b->limit; b++; /* * Look for any other chunks of memory. */ for(; i <= MAXMEG; i++){ if(mmap[i] == 'x'){ b->base = i*MB; for(j = i+1; mmap[j] == 'x'; j++) ; b->limit = j*MB; mconf.topofmem = j*MB; b++; if(b - mconf.bank == MAXBANK) break; } } mconf.nbank = b - mconf.bank; } typedef struct { uvlong base; uvlong len; ulong type; }Emap; static char *etypes[] = { "type=0", "memory", "reserved", "acpi reclaim", "acpi nvs", }; #define smap 0x534d4150 #define e820tab 0x2d0 #define e820sz 20 #define e820end (16*e820sz+e820tab) /* debugging crap */ ulong n820; ulong n820m; static Emap emap[16]; int mconf820(void) { ulong i; Emap *e, *t; Mbank *b; uchar *a; vlong sz; a = (uchar*)mapaddr(0); i = *(ulong*)(a+e820end); if(i == 0 || i > 16) return -1; e = (Emap*)(a+e820tab); t = e+i; b = mconf.bank; mconf.topofmem = MB; // this is used to calculate pgtable sz; allow pci space. for(; e<=t; e++){ emap[n820].base = e->base; emap[n820].len = e->len; emap[n820++].type = e->type; if(e->type != 1) continue; if(e->base >= 1ULL<<32 || e->base == 0) continue; sz = e->len; b->base = e->base; b->limit = e->base+sz; mconf.topofmem += sz; if(++b-mconf.bank == MAXBANK) break; } mconf.topofmem &= ~(4*MB-1); n820m = b-mconf.bank; if(b-mconf.bank < 1) return 0; mconf.nbank = b-mconf.bank; /* careful with that axe, eugene */ mconf.bank[0].base += PADDR(PGROUND((ulong)end)); return mconf.nbank; } /* debugging aide -- please remove */ void cmd_e820(int, char **) { ulong n; Emap *e, *end; vlong sz, ex, lim; print("found %uld e820 entries %uld banks\n", n820, n820m); e = emap; end = e+n820; n = 0; sz = 0; ex = 0; for(; ebase, e->base+e->len); if(e->type < nelem(etypes)) print("%s\n", etypes[e->type]); else print("type=%lud\n", e->type); if(e->type != 1 || e->base == 0) continue; if(e->base >= 1ULL<<32){ ex += e->len; continue; } lim = e->base+e->len; sz += e->len; if(++n == MAXBANK) continue; print("\t" "bank %ullx %ullx\n", e->base, lim); } print("found %ld e820 memory banks %ulldMB+%ulldMB\n", n, sz/MB, ex/MB); print(" topofmem = %p\n", mconf.topofmem); print(" cpuiddx %p; cycles %p\n", MACHP(0)->cpuiddx, cycles); if((MACHP(0)->cpuiddx & 0x08) && (getcr4() & 0x10)) print(" pse: yes\n"); } ulong meminit(void) { ulong i, sz; conf.nmach = 1; if(mconf820() <= 0) mconfscan(); mmuinit(); trapinit(); sz = 0; for(i = 0; i < mconf.nbank; i++) sz += mconf.bank[i].limit-mconf.bank[i].base; return sz; } void userinit(void (*f)(void), void *arg, char *text) { User *p; p = newproc(); /* * Kernel Stack. * The -4 is because the path sched()->gotolabel()->init0()->f() * uses a stack location without creating any local space. */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->stack + sizeof(p->stack) - 4; p->start = f; p->text = text; p->arg = arg; dofilter(&p->time); ready(p); } static int useuart; static void (*intrputs)(char*, int); static int pcgetc(void) { int c; if(c = kbdgetc()) return c; if(c = cecgetc()) return c; if(useuart) return uartgetc(); return 0; } static void pcputc(int c) { if(predawn) cgaputc(c); if(useuart) uartputc(c); } static void pcputs(char* s, int n) { if(!predawn){ cgaputs(s, n); cecputs(s, n); } if(intrputs) (*intrputs)(s, n); } void consinit(void (*puts)(char*, int)) { char *p; int baud, port; kbdinit(); consgetc = pcgetc; consputc = pcputc; consputs = pcputs; intrputs = puts; if((p = getconf("console")) == 0 || cistrcmp(p, "cga") == 0) return; port = strtoul(p, &p, 0); if(port < 0 || port > 1) return; while(*p == ' ' || *p == '\t') p++; if(*p != 'b' || (baud = strtoul(p+1, 0, 0)) == 0) baud = 9600; uartspecial(port, kbdchar, conschar, baud); useuart = 1; } void consreset(void) { } void firmware(void) { char *p; /* * Always called splhi(). */ if((p = getconf("reset")) && cistrcmp(p, "manual") == 0){ predawn = 1; print("\nHit Reset\n"); for(;;); } pcireset(); i8042reset(); } int isaconfig(char *class, int ctlrno, ISAConf *isa) { char cc[NAMELEN], *p, *q, *r; int n; sprint(cc, "%s%d", class, ctlrno); for(n = 0; n < nconf; n++){ if(cistrncmp(confname[n], cc, NAMELEN)) continue; isa->nopt = 0; p = confval[n]; while(*p){ while(*p == ' ' || *p == '\t') p++; if(*p == '\0') break; if(cistrncmp(p, "type=", 5) == 0){ p += 5; for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ if(*p == '\0' || *p == ' ' || *p == '\t') break; *q = *p++; } *q = '\0'; } else if(cistrncmp(p, "port=", 5) == 0) isa->port = strtoul(p+5, &p, 0); else if(cistrncmp(p, "irq=", 4) == 0) isa->irq = strtoul(p+4, &p, 0); else if(cistrncmp(p, "dma=", 4) == 0) isa->dma = strtoul(p+4, &p, 0); else if(cistrncmp(p, "mem=", 4) == 0) isa->mem = strtoul(p+4, &p, 0); else if(cistrncmp(p, "size=", 5) == 0) isa->size = strtoul(p+5, &p, 0); else if(cistrncmp(p, "freq=", 5) == 0) isa->freq = strtoul(p+5, &p, 0); else if(isa->nopt < NISAOPT){ r = isa->opt[isa->nopt]; while(*p && *p != ' ' && *p != '\t'){ *r++ = *p++; if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1) break; } *r = '\0'; isa->nopt++; } while(*p && *p != ' ' && *p != '\t') p++; } return 1; } return 0; } void lockinit(void) { } void launchinit(void) { } void lights(int, int) { } /* in assembly language Float famd(Float a, int b, int c, int d) { return ((a+b) * c) / d; } ulong fdf(Float a, int b) { return a / b; } */