|
|
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.