Annotation of lucent/sys/src/boot/pc/dosboot.c, revision 1.1.1.1

1.1       root        1: #include       "u.h"
                      2: #include       "lib.h"
                      3: #include       "mem.h"
                      4: #include       "dat.h"
                      5: #include       "fns.h"
                      6: #include       "dosfs.h"
                      7: 
                      8: /*
                      9:  *  predeclared
                     10:  */
                     11: static void    bootdump(Dosboot*);
                     12: static void    setname(Dosfile*, char*);
                     13: long           dosreadseg(Dosfile*, long, long);
                     14: 
                     15: /*
                     16:  *  debugging
                     17:  */
                     18: int chatty;
                     19: #define chat if(chatty)print
                     20: 
                     21: /*
                     22:  *  block io buffers
                     23:  */
                     24: enum
                     25: {
                     26:        Nbio=   16,
                     27: };
                     28: typedef struct Clustbuf        Clustbuf;
                     29: struct Clustbuf
                     30: {
                     31:        int     age;
                     32:        long    sector;
                     33:        uchar   *iobuf;
                     34:        Dos     *dos;
                     35:        int     size;
                     36: };
                     37: Clustbuf       bio[Nbio];
                     38: 
                     39: /*
                     40:  *  get an io block from an io buffer
                     41:  */
                     42: Clustbuf*
                     43: getclust(Dos *dos, long sector)
                     44: {
                     45:        Clustbuf *p, *oldest;
                     46:        int size;
                     47: 
                     48:        chat("getclust @ %d\n", sector);
                     49: 
                     50:        /*
                     51:         *  if we have it, just return it
                     52:         */
                     53:        for(p = bio; p < &bio[Nbio]; p++){
                     54:                if(sector == p->sector && dos == p->dos){
                     55:                        p->age = m->ticks;
                     56:                        chat("getclust %d in cache\n", sector);
                     57:                        return p;
                     58:                }
                     59:        }
                     60: 
                     61:        /*
                     62:         *  otherwise, reuse the oldest entry
                     63:         */
                     64:        oldest = bio;
                     65:        for(p = &bio[1]; p < &bio[Nbio]; p++){
                     66:                if(p->age <= oldest->age)
                     67:                        oldest = p;
                     68:        }
                     69:        p = oldest;
                     70: 
                     71:        /*
                     72:         *  make sure the buffer is big enough
                     73:         */
                     74:        size = dos->clustsize*dos->sectsize;
                     75:        if(p->iobuf==0 || p->size < size)
                     76:                p->iobuf = ialloc(size, 0);
                     77:        p->size = size;
                     78: 
                     79:        /*
                     80:         *  read in the cluster
                     81:         */
                     82:        chat("getclust addr %d\n", (sector+dos->start)*dos->sectsize);
                     83:        if((*dos->seek)(dos->dev, (sector+dos->start)*dos->sectsize) < 0){
                     84:                chat("can't seek block\n");
                     85:                return 0;
                     86:        }
                     87:        if((*dos->read)(dos->dev, p->iobuf, size) != size){
                     88:                chat("can't read block\n");
                     89:                return 0;
                     90:        }
                     91: 
                     92:        p->age = m->ticks;
                     93:        p->dos = dos;
                     94:        p->sector = sector;
                     95:        chat("getclust %d read\n", sector);
                     96:        return p;
                     97: }
                     98: 
                     99: /*
                    100:  *  walk the fat one level ( n is a current cluster number ).
                    101:  *  return the new cluster number or -1 if no more.
                    102:  */
                    103: static long
                    104: fatwalk(Dos *dos, int n)
                    105: {
                    106:        ulong k, sect;
                    107:        Clustbuf *p;
                    108:        int o;
                    109: 
                    110:        chat("fatwalk %d\n", n);
                    111: 
                    112:        if(n < 2 || n >= dos->fatclusters)
                    113:                return -1;
                    114: 
                    115:        switch(dos->fatbits){
                    116:        case 12:
                    117:                k = (3*n)/2; break;
                    118:        case 16:
                    119:                k = 2*n; break;
                    120:        default:
                    121:                return -1;
                    122:        }
                    123:        if(k >= dos->fatsize*dos->sectsize)
                    124:                panic("getfat");
                    125: 
                    126:        sect = (k/(dos->sectsize*dos->clustsize))*dos->clustsize + dos->fataddr;
                    127:        o = k%(dos->sectsize*dos->clustsize);
                    128:        p = getclust(dos, sect);
                    129:        k = p->iobuf[o++];
                    130:        if(o >= dos->sectsize*dos->clustsize){
                    131:                p = getclust(dos, sect+dos->clustsize);
                    132:                o = 0;
                    133:        }
                    134:        k |= p->iobuf[o]<<8;
                    135:        if(dos->fatbits == 12){
                    136:                if(n&1)
                    137:                        k >>= 4;
                    138:                else
                    139:                        k &= 0xfff;
                    140:                if(k >= 0xff8)
                    141:                        k |= 0xf000;
                    142:        }
                    143:        k = k < 0xfff8 ? k : -1;
                    144:        chat("fatwalk %d -> %d\n", n, k);
                    145:        return k;
                    146: }
                    147: 
                    148: /*
                    149:  *  map a file's logical cluster address to a physical sector address
                    150:  */
                    151: static long
                    152: fileaddr(Dosfile *fp, long ltarget)
                    153: {
                    154:        Dos *dos = fp->dos;
                    155:        long l;
                    156:        long p;
                    157: 
                    158:        chat("fileaddr %8.8s %d\n", fp->name, ltarget);
                    159:        /*
                    160:         *  root directory is contiguous and easy
                    161:         */
                    162:        if(fp->pstart == 0){
                    163:                if(ltarget*dos->sectsize*dos->clustsize >= dos->rootsize*sizeof(Dosdir))
                    164:                        return -1;
                    165:                l = dos->rootaddr + ltarget*dos->clustsize;
                    166:                chat("fileaddr %d -> %d\n", ltarget, l);
                    167:                return l;
                    168:        }
                    169: 
                    170:        /*
                    171:         *  anything else requires a walk through the fat
                    172:         */
                    173:        if(ltarget >= fp->lcurrent && fp->pcurrent){
                    174:                /* start at the currrent point */
                    175:                l = fp->lcurrent;
                    176:                p = fp->pcurrent;
                    177:        } else {
                    178:                /* go back to the beginning */
                    179:                l = 0;
                    180:                p = fp->pstart;
                    181:        }
                    182:        while(l != ltarget){
                    183:                /* walk the fat */
                    184:                p = fatwalk(dos, p);
                    185:                if(p < 0)
                    186:                        return -1;
                    187:                l++;
                    188:        }
                    189:        fp->lcurrent = l;
                    190:        fp->pcurrent = p;
                    191: 
                    192:        /*
                    193:         *  clusters start at 2 instead of 0 (why? - presotto)
                    194:         */
                    195:        l =  dos->dataaddr + (p-2)*dos->clustsize;
                    196:        chat("fileaddr %d -> %d\n", ltarget, l);
                    197:        return l;
                    198: }
                    199: 
                    200: /*
                    201:  *  read from a dos file
                    202:  */
                    203: long
                    204: dosread(Dosfile *fp, void *a, long n)
                    205: {
                    206:        long addr;
                    207:        long rv;
                    208:        int i;
                    209:        int off;
                    210:        Clustbuf *p;
                    211:        uchar *from, *to;
                    212: 
                    213:        if((fp->attr & DDIR) == 0){
                    214:                if(fp->offset >= fp->length)
                    215:                        return 0;
                    216:                if(fp->offset+n > fp->length)
                    217:                        n = fp->length - fp->offset;
                    218:        }
                    219: 
                    220:        to = a;
                    221:        for(rv = 0; rv < n; rv+=i){
                    222:                /*
                    223:                 *  read the cluster
                    224:                 */
                    225:                addr = fileaddr(fp, fp->offset/fp->dos->clustbytes);
                    226:                if(addr < 0)
                    227:                        return -1;
                    228:                p = getclust(fp->dos, addr);
                    229:                if(p == 0)
                    230:                        return -1;
                    231: 
                    232:                /*
                    233:                 *  copy the bytes we need
                    234:                 */
                    235:                off = fp->offset % fp->dos->clustbytes;
                    236:                from = &p->iobuf[off];
                    237:                i = n - rv;
                    238:                if(i > fp->dos->clustbytes - off)
                    239:                        i = fp->dos->clustbytes - off;
                    240:                memmove(to, from, i);
                    241:                to += i;
                    242:                fp->offset += i;
                    243:        }
                    244: 
                    245:        return rv;
                    246: }
                    247: 
                    248: /*
                    249:  *  walk a directory returns
                    250:  *     -1 if something went wrong
                    251:  *      0 if not found
                    252:  *      1 if found
                    253:  */
                    254: int
                    255: doswalk(Dosfile *file, char *name)
                    256: {
                    257:        Dosdir d;
                    258:        long n;
                    259: 
                    260:        if((file->attr & DDIR) == 0){
                    261:                chat("walking non-directory!\n");
                    262:                return -1;
                    263:        }
                    264: 
                    265:        setname(file, name);
                    266: 
                    267:        file->offset = 0;       /* start at the beginning */
                    268:        while((n = dosread(file, &d, sizeof(d))) == sizeof(d)){
                    269:                chat("comparing to %8.8s.%3.3s\n", d.name, d.ext);
                    270:                if(memcmp(file->name, d.name, sizeof(d.name)) != 0)
                    271:                        continue;
                    272:                if(memcmp(file->ext, d.ext, sizeof(d.ext)) != 0)
                    273:                        continue;
                    274:                if(d.attr & DVLABEL){
                    275:                        chat("%8.8s.%3.3s is a LABEL\n", d.name, d.ext);
                    276:                        continue;
                    277:                }
                    278:                file->attr = d.attr;
                    279:                file->pstart = GSHORT(d.start);
                    280:                file->length = GLONG(d.length);
                    281:                file->pcurrent = 0;
                    282:                file->lcurrent = 0;
                    283:                file->offset = 0;
                    284:                return 1;
                    285:        }
                    286:        return n >= 0 ? 0 : -1;
                    287: }
                    288: 
                    289: 
                    290: /*
                    291:  *  instructions that boot blocks can start with
                    292:  */
                    293: #define        JMPSHORT        0xeb
                    294: #define JMPNEAR                0xe9
                    295: 
                    296: /*
                    297:  *  read dos file system properties
                    298:  */
                    299: int
                    300: dosinit(Dos *dos)
                    301: {
                    302:        Dosboot *b;
                    303:        int i;
                    304:        Clustbuf *p;
                    305:        Dospart *dp;
                    306: 
                    307: 
                    308:        /* defaults till we know better */
                    309:        dos->start = 0;
                    310:        dos->sectsize = 512;
                    311:        dos->clustsize = 1;
                    312: 
                    313:        /* get first sector */
                    314:        p = getclust(dos, 0);
                    315:        if(p == 0){
                    316:                chat("can't read boot block\n");
                    317:                return -1;
                    318:        }
                    319:        p->dos = 0;
                    320: 
                    321:        /* if a hard disk format, look for an active partition */
                    322:        b = (Dosboot *)p->iobuf;
                    323:        if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){
                    324:                if(p->iobuf[0x1fe] != 0x55 || p->iobuf[0x1ff] != 0xaa){
                    325:                        /*print("no dos file system or partition table\n");*/
                    326:                        return -1;
                    327:                }
                    328:                dp = (Dospart*)&p->iobuf[0x1be];
                    329:                for(i = 0; i < 4; i++, dp++)
                    330:                        if(dp->type && dp->flag == 0x80)
                    331:                                break;
                    332:                if(i == 4)
                    333:                        return -1;
                    334:                dos->start = GLONG(dp->start);
                    335:                p = getclust(dos, 0);
                    336:                if(p == 0){
                    337:                        chat("can't read boot block\n");
                    338:                        return -1;
                    339:                }
                    340:                p->dos = 0;
                    341:        }
                    342: 
                    343:        b = (Dosboot *)p->iobuf;
                    344:        if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){
                    345:                print("no dos file system\n");
                    346:                return -1;
                    347:        }
                    348: 
                    349:        if(chatty)
                    350:                bootdump(b);/**/
                    351: 
                    352:        /*
                    353:         *  determine the systems' wondersous properties
                    354:         */
                    355:        dos->sectsize = GSHORT(b->sectsize);
                    356:        dos->clustsize = b->clustsize;
                    357:        dos->clustbytes = dos->sectsize*dos->clustsize;
                    358:        dos->nresrv = GSHORT(b->nresrv);
                    359:        dos->nfats = b->nfats;
                    360:        dos->rootsize = GSHORT(b->rootsize);
                    361:        dos->volsize = GSHORT(b->volsize);
                    362:        if(dos->volsize == 0)
                    363:                dos->volsize = GLONG(b->bigvolsize);
                    364:        dos->mediadesc = b->mediadesc;
                    365:        dos->fatsize = GSHORT(b->fatsize);
                    366:        dos->fataddr = dos->nresrv;
                    367:        dos->rootaddr = dos->fataddr + dos->nfats*dos->fatsize;
                    368:        i = dos->rootsize*sizeof(Dosdir) + dos->sectsize - 1;
                    369:        i = i/dos->sectsize;
                    370:        dos->dataaddr = dos->rootaddr + i;
                    371:        dos->fatclusters = 2+(dos->volsize - dos->dataaddr)/dos->clustsize;
                    372:        if(dos->fatclusters < 4087)
                    373:                dos->fatbits = 12;
                    374:        else
                    375:                dos->fatbits = 16;
                    376:        dos->freeptr = 2;
                    377: 
                    378:        /*
                    379:         *  set up the root
                    380:         */
                    381:        dos->root.dos = dos;
                    382:        dos->root.pstart = 0;
                    383:        dos->root.pcurrent = dos->root.lcurrent = 0;
                    384:        dos->root.offset = 0;
                    385:        dos->root.attr = DDIR;
                    386:        dos->root.length = dos->rootsize*sizeof(Dosdir);
                    387: 
                    388:        return 0;
                    389: }
                    390: 
                    391: static void
                    392: bootdump(Dosboot *b)
                    393: {
                    394:        print("magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
                    395:                b->magic[0], b->magic[1], b->magic[2]);
                    396:        print("version: \"%8.8s\"\n", b->version);
                    397:        print("sectsize: %d\n", GSHORT(b->sectsize));
                    398:        print("allocsize: %d\n", b->clustsize);
                    399:        print("nresrv: %d\n", GSHORT(b->nresrv));
                    400:        print("nfats: %d\n", b->nfats);
                    401:        print("rootsize: %d\n", GSHORT(b->rootsize));
                    402:        print("volsize: %d\n", GSHORT(b->volsize));
                    403:        print("mediadesc: 0x%2.2x\n", b->mediadesc);
                    404:        print("fatsize: %d\n", GSHORT(b->fatsize));
                    405:        print("trksize: %d\n", GSHORT(b->trksize));
                    406:        print("nheads: %d\n", GSHORT(b->nheads));
                    407:        print("nhidden: %d\n", GLONG(b->nhidden));
                    408:        print("bigvolsize: %d\n", GLONG(b->bigvolsize));
                    409:        print("driveno: %d\n", b->driveno);
                    410:        print("reserved0: 0x%2.2x\n", b->reserved0);
                    411:        print("bootsig: 0x%2.2x\n", b->bootsig);
                    412:        print("volid: 0x%8.8x\n", GLONG(b->volid));
                    413:        print("label: \"%11.11s\"\n", b->label);
                    414: }
                    415: 
                    416: /*
                    417:  *  grab next element from a path, return the pointer to unprocessed portion of
                    418:  *  path.
                    419:  */
                    420: static char *
                    421: nextelem(char *path, char *elem)
                    422: {
                    423:        int i;
                    424: 
                    425:        while(*path == '/')
                    426:                path++;
                    427:        if(*path==0 || *path==' ')
                    428:                return 0;
                    429:        for(i=0; *path!='\0' && *path!='/' && *path!=' '; i++){
                    430:                if(i==28){
                    431:                        print("name component too long\n");
                    432:                        return 0;
                    433:                }
                    434:                *elem++ = *path++;
                    435:        }
                    436:        *elem = '\0';
                    437:        return path;
                    438: }
                    439: 
                    440: int
                    441: dosstat(Dos *dos, char *path, Dosfile *f)
                    442: {
                    443:        char element[NAMELEN];
                    444: 
                    445:        *f = dos->root;
                    446:        while(path = nextelem(path, element)){
                    447:                switch(doswalk(f, element)){
                    448:                case -1:
                    449:                        return -1;
                    450:                case 0:
                    451:                        return 0;
                    452:                }
                    453:        }
                    454:        return 1;
                    455: }
                    456: 
                    457: /*
                    458:  *  boot
                    459:  */
                    460: int
                    461: dosboot(Dos *dos, char *path)
                    462: {
                    463:        Dosfile file;
                    464:        long n;
                    465:        long addr;
                    466:        Exec *ep;
                    467:        void (*b)(void);
                    468: 
                    469:        switch(dosstat(dos, path, &file)){
                    470: 
                    471:        case -1:
                    472:                print("error walking to %s\n", path);
                    473:                return -1;
                    474:        case 0:
                    475:                print("%s not found\n", path);
                    476:                return -1;
                    477:        case 1:
                    478:                print("found %8.8s.%3.3s attr 0x%ux start 0x%lux len %d\n", file.name,
                    479:                        file.ext, file.attr, file.pstart, file.length);
                    480:                break;
                    481:        }
                    482: 
                    483:        /*
                    484:         *  read header
                    485:         */
                    486:        ep = (Exec*)ialloc(sizeof(Exec), 0);
                    487:        n = sizeof(Exec);
                    488:        if(dosreadseg(&file, n, (ulong) ep) != n){
                    489:                print("premature EOF\n");
                    490:                return -1;
                    491:        }
                    492:        if(GLLONG(ep->magic) != I_MAGIC){
                    493:                print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic));
                    494:                return -1;
                    495:        }
                    496: 
                    497:        /*
                    498:         *  read text
                    499:         */
                    500:        addr = PADDR(GLLONG(ep->entry));
                    501:        n = GLLONG(ep->text);
                    502:        print("+%d", n);
                    503:        if(dosreadseg(&file, n, addr) != n){
                    504:                print("premature EOF\n");
                    505:                return -1;
                    506:        }
                    507: 
                    508:        /*
                    509:         *  read data (starts at first page after kernel)
                    510:         */
                    511:        addr = PGROUND(addr+n);
                    512:        n = GLLONG(ep->data);
                    513:        print("+%d", n);
                    514:        if(dosreadseg(&file, n, addr) != n){
                    515:                print("premature EOF\n");
                    516:                return -1;
                    517:        }
                    518: 
                    519:        /*
                    520:         *  bss and entry point
                    521:         */
                    522:        print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry));
                    523: 
                    524:        /*
                    525:         *  Go to new code. It's up to the program to get its PC relocated to
                    526:         *  the right place.
                    527:         */
                    528:        b = (void (*)(void))(PADDR(GLLONG(ep->entry)));
                    529:        (*b)();
                    530:        return 0;
                    531: }
                    532: 
                    533: /*
                    534:  *  read in a segment
                    535:  */
                    536: long
                    537: dosreadseg(Dosfile *fp, long len, long addr)
                    538: {
                    539:        char *a;
                    540:        long n, sofar;
                    541: 
                    542:        a = (char *)addr;
                    543:        for(sofar = 0; sofar < len; sofar += n){
                    544:                n = 8*1024;
                    545:                if(len - sofar < n)
                    546:                        n = len - sofar;
                    547:                n = dosread(fp, a + sofar, n);
                    548:                if(n <= 0)
                    549:                        break;
                    550:                print(".");
                    551:        }
                    552:        return sofar;
                    553: }
                    554: 
                    555: /*
                    556:  *  set up a dos file name
                    557:  */
                    558: static void
                    559: setname(Dosfile *fp, char *from)
                    560: {
                    561:        char *to;
                    562: 
                    563:        to = fp->name;
                    564:        for(; *from && to-fp->name < 8; from++, to++){
                    565:                if(*from == '.'){
                    566:                        from++;
                    567:                        break;
                    568:                }
                    569:                if(*from >= 'a' && *from <= 'z')
                    570:                        *to = *from + 'A' - 'a';
                    571:                else
                    572:                        *to = *from;
                    573:        }
                    574:        while(to - fp->name < 8)
                    575:                *to++ = ' ';
                    576:        
                    577:        to = fp->ext;
                    578:        for(; *from && to-fp->ext < 3; from++, to++){
                    579:                if(*from >= 'a' && *from <= 'z')
                    580:                        *to = *from + 'A' - 'a';
                    581:                else
                    582:                        *to = *from;
                    583:        }
                    584:        while(to-fp->ext < 3)
                    585:                *to++ = ' ';
                    586: 
                    587:        chat("name is %8.8s %3.3s\n", fp->name, fp->ext);
                    588: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.