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