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