Annotation of lucent/sys/src/boot/pc/dosboot.c, revision 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.