|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.