diff options
Diffstat (limited to 'os/boot/pc/load.c')
| -rw-r--r-- | os/boot/pc/load.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/os/boot/pc/load.c b/os/boot/pc/load.c new file mode 100644 index 00000000..575c1205 --- /dev/null +++ b/os/boot/pc/load.c @@ -0,0 +1,563 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "fs.h" + +static char *diskparts[] = { "dos", "9fat", "fs", "data", "cdboot", 0 }; +static char *etherparts[] = { "*", 0 }; + +static char *diskinis[] = { + "plan9/plan9.ini", + "plan9.ini", + 0 +}; +static char *etherinis[] = { + "/cfg/pxe/%E", + 0 +}; + +Type types[] = { + { Tfloppy, + Fini|Ffs, + floppyinit, floppyinitdev, + floppygetfspart, 0, floppyboot, + floppyprintdevs, + diskparts, + diskinis, + }, + { Tcd, + Fini|Ffs, + cdinit, sdinitdev, + sdgetfspart, sdaddconf, sdboot, + sdprintdevs, + diskparts, + diskinis, + }, + { Tether, + Fini|Fbootp, + etherinit, etherinitdev, + pxegetfspart, 0, bootpboot, + etherprintdevs, + etherparts, + etherinis, + }, + { Tsd, + Fini|Ffs, + sdinit, sdinitdev, + sdgetfspart, sdaddconf, sdboot, + sdprintdevs, + diskparts, + diskinis, + }, + { Tnil, + 0, + nil, nil, nil, nil, nil, nil, + nil, + nil, + 0, + nil, + }, +}; + +#include "sd.h" + +extern SDifc sdataifc; + +#ifdef NOSCSI + +SDifc* sdifc[] = { + &sdataifc, + nil, +}; + +#else + +extern SDifc sdmylexifc; +extern SDifc sd53c8xxifc; +SDifc* sdifc[] = { + &sdataifc, + &sdmylexifc, + &sd53c8xxifc, + nil, +}; + +#endif NOSCSI + +typedef struct Mode Mode; + +enum { + Maxdev = 7, + Dany = -1, + Nmedia = 16, + Nini = 10, +}; + +enum { /* mode */ + Mauto = 0x00, + Mlocal = 0x01, + Manual = 0x02, + NMode = 0x03, +}; + +typedef struct Medium Medium; +struct Medium { + Type* type; + int flag; + int dev; + char name[NAMELEN]; + + Fs *inifs; + char *part; + char *ini; + + Medium* next; +}; + +typedef struct Mode { + char* name; + int mode; +} Mode; + +static Medium media[Nmedia]; +static Medium *curmedium = media; + +static Mode modes[NMode+1] = { + [Mauto] { "auto", Mauto, }, + [Mlocal] { "local", Mlocal, }, + [Manual] { "manual", Manual, }, +}; + +char **ini; + +int scsi0port; +char *defaultpartition; +int iniread; + +static Medium* +parse(char *line, char **file) +{ + char *p; + Type *tp; + Medium *mp; + + if(p = strchr(line, '!')) { + *p++ = 0; + *file = p; + } else + *file = ""; + + for(tp = types; tp->type != Tnil; tp++) + for(mp = tp->media; mp; mp = mp->next) + if(strcmp(mp->name, line) == 0) + return mp; + if(p) + *--p = '!'; + return nil; +} + +static int +boot(Medium *mp, char *file) +{ + Type *tp; + Medium *xmp; + static int didaddconf; + Boot b; + + memset(&b, 0, sizeof b); + b.state = INITKERNEL; + + if(didaddconf == 0) { + didaddconf = 1; + for(tp = types; tp->type != Tnil; tp++) + if(tp->addconf) + for(xmp = tp->media; xmp; xmp = xmp->next) + (*tp->addconf)(xmp->dev); + } + + sprint(BOOTLINE, "%s!%s", mp->name, file); + return (*mp->type->boot)(mp->dev, file, &b); +} + +static Medium* +allocm(Type *tp) +{ + Medium **l; + + if(curmedium >= &media[Nmedia]) + return 0; + + for(l = &tp->media; *l; l = &(*l)->next) + ; + *l = curmedium++; + return *l; +} + +Medium* +probe(int type, int flag, int dev) +{ + Type *tp; + int i; + Medium *mp; + File f; + Fs *fs; + char **partp; + + for(tp = types; tp->type != Tnil; tp++){ + if(type != Tany && type != tp->type) + continue; + + if(flag != Fnone){ + for(mp = tp->media; mp; mp = mp->next){ + if((flag & mp->flag) && (dev == Dany || dev == mp->dev)) + return mp; + } + } + + if((tp->flag & Fprobe) == 0){ + tp->flag |= Fprobe; + tp->mask = (*tp->init)(); + } + + for(i = 0; tp->mask; i++){ + if((tp->mask & (1<<i)) == 0) + continue; + tp->mask &= ~(1<<i); + + if((mp = allocm(tp)) == 0) + continue; + + mp->dev = i; + mp->flag = tp->flag; + mp->type = tp; + (*tp->initdev)(i, mp->name); + + if(mp->flag & Fini){ + mp->flag &= ~Fini; + for(partp = tp->parts; *partp; partp++){ + if((fs = (*tp->getfspart)(i, *partp, 0)) == nil) + continue; + + for(ini = tp->inis; *ini; ini++){ + if(fswalk(fs, *ini, &f) > 0){ + mp->inifs = fs; + mp->part = *partp; + mp->ini = f.path; + mp->flag |= Fini; + goto Break2; + } + } + } + } + Break2: + if((flag & mp->flag) && (dev == Dany || dev == i)) + return mp; + } + } + + return 0; +} + +void +main(void) +{ + Medium *mp; + int flag, i, mode, tried; + char def[2*NAMELEN], line[80], *p, *file; + Type *tp; + + i8042a20(); + memset(m, 0, sizeof(Mach)); + trapinit(); + clockinit(); + alarminit(); + meminit(0); + spllo(); + kbdinit(); + + if((ulong)&end > (KZERO|(640*1024))) + panic("i'm too big\n"); + + readlsconf(); + for(tp = types; tp->type != Tnil; tp++){ + //if(tp->type == Tether) + // continue; + if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){ + print("using %s!%s!%s\n", mp->name, mp->part, mp->ini); + iniread = !dotini(mp->inifs); + break; + } + } + apminit(); + + if((p = getconf("console")) != nil) + consinit(p, getconf("baud")); + devpccardlink(); + devi82365link(); + + /* + * Even after we find the ini file, we keep probing disks, + * because we have to collect the partition tables and + * have boot devices for parse. + */ + probe(Tany, Fnone, Dany); + tried = 0; + mode = Mauto; + + p = getconf("bootfile"); + + if(p != 0) { + mode = Manual; + for(i = 0; i < NMode; i++){ + if(strcmp(p, modes[i].name) == 0){ + mode = modes[i].mode; + goto done; + } + } + if((mp = parse(p, &file)) == nil) { + print("Unknown boot device: %s\n", p); + goto done; + } + tried = boot(mp, file); + } +done: + if(tried == 0 && mode != Manual){ + flag = Fany; + if(mode == Mlocal) + flag &= ~Fbootp; + if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy) + boot(mp, ""); + } + + def[0] = 0; + probe(Tany, Fnone, Dany); + if(p = getconf("bootdef")) + strcpy(def, p); + + flag = 0; + for(tp = types; tp->type != Tnil; tp++){ + for(mp = tp->media; mp; mp = mp->next){ + if(flag == 0){ + flag = 1; + print("Boot devices:"); + } + (*tp->printdevs)(mp->dev); + } + } + if(flag) + print("\n"); + + for(;;){ + if(getstr("boot from", line, sizeof(line), def, (mode != Manual)*15) >= 0) + if(mp = parse(line, &file)) + boot(mp, file); + def[0] = 0; + } +} + +int +getfields(char *lp, char **fields, int n, char sep) +{ + int i; + + for(i = 0; lp && *lp && i < n; i++){ + while(*lp == sep) + *lp++ = 0; + if(*lp == 0) + break; + fields[i] = lp; + while(*lp && *lp != sep){ + if(*lp == '\\' && *(lp+1) == '\n') + *lp++ = ' '; + lp++; + } + } + return i; +} + +int +cistrcmp(char *a, char *b) +{ + int ac, bc; + + for(;;){ + ac = *a++; + bc = *b++; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + return 0; +} + +int +cistrncmp(char *a, char *b, int n) +{ + unsigned ac, bc; + + while(n > 0){ + ac = *a++; + bc = *b++; + n--; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + + return 0; +} + +#define PSTART (12*1024*1024) +#define PEND (16*1024*1024) + +ulong palloc = PSTART; + +void* +ialloc(ulong n, int align) +{ + ulong p; + int a; + + p = palloc; + if(align <= 0) + align = 4; + if(a = n % align) + n += align - a; + if(a = p % align) + p += align - a; + + + palloc = p+n; + if(palloc > PEND) + panic("ialloc(%lud, %d) called from 0x%lux\n", + n, align, getcallerpc(&n)); + return memset((void*)(p|KZERO), 0, n); +} + +void* +xspanalloc(ulong size, int align, ulong span) +{ + ulong a, v; + + if((palloc + (size+align+span)) > PEND) + panic("xspanalloc(%lud, %d, 0x%lux) called from 0x%lux\n", + size, align, span, getcallerpc(&size)); + + a = (ulong)ialloc(size+align+span, 0); + + if(span > 2) + v = (a + span) & ~(span-1); + else + v = a; + + if(align > 1) + v = (v + align) & ~(align-1); + + return (void*)v; +} + +static Block *allocbp; + +Block* +allocb(int size) +{ + Block *bp, **lbp; + ulong addr; + + lbp = &allocbp; + for(bp = *lbp; bp; bp = bp->next){ + if((bp->lim - bp->base) >= size){ + *lbp = bp->next; + break; + } + lbp = &bp->next; + } + if(bp == 0){ + if((palloc + (sizeof(Block)+size+64)) > PEND) + panic("allocb(%d) called from 0x%lux\n", + size, getcallerpc(&size)); + bp = ialloc(sizeof(Block)+size+64, 0); + addr = (ulong)bp; + addr = ROUNDUP(addr + sizeof(Block), 8); + bp->base = (uchar*)addr; + bp->lim = ((uchar*)bp) + sizeof(Block)+size+64; + } + + if(bp->flag) + panic("allocb reuse\n"); + + bp->rp = bp->base; + bp->wp = bp->rp; + bp->next = 0; + bp->flag = 1; + + return bp; +} + +void +freeb(Block* bp) +{ + bp->next = allocbp; + allocbp = bp; + + bp->flag = 0; +} + +enum { + Paddr= 0x70, /* address port */ + Pdata= 0x71, /* data port */ +}; + +uchar +nvramread(int offset) +{ + outb(Paddr, offset); + return inb(Pdata); +} + +void (*etherdetach)(void); +void (*floppydetach)(void); +void (*sddetach)(void); + +void +warp9(ulong entry) +{ + if(etherdetach) + etherdetach(); + if(floppydetach) + floppydetach(); + if(sddetach) + sddetach(); + + consdrain(); + + splhi(); + trapdisable(); + + /* + * This is where to push things on the stack to + * boot *BSD systems, e.g. + (*(void(*)(void*, void*, void*, void*, ulong, ulong))(PADDR(entry)))(0, 0, 0, 0, 8196, 640); + * will enable NetBSD boot (the real memory size needs to + * go in the 5th argument). + */ + (*(void(*)(void))(PADDR(entry)))(); +} |
