]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/pc/fat.c
missing realemu manpage
[plan9front.git] / sys / src / boot / pc / fat.c
1 #include <u.h>
2 #include "fns.h"
3
4 enum {
5         Sectsz = 0x200,
6         Dirsz = 0x20,
7         Maxpath = 64,
8 };
9
10 typedef struct Extend Extend;
11 typedef struct Dir Dir;
12 typedef struct Pbs Pbs;
13
14 struct Extend
15 {
16         int drive;
17         ulong lba;
18         ulong len;
19         uchar *rp;
20         uchar *ep;
21         uchar buf[Sectsz];
22 };
23
24 struct Dir
25 {
26         char name[11];
27         uchar attr;
28         uchar reserved;
29         uchar ctime;
30         uchar ctime[2];
31         uchar cdate[2];
32         uchar adate[2];
33         uchar starthi[2];
34         uchar mtime[2];
35         uchar mdate[2];
36         uchar startlo[2];
37         uchar len[4];
38 };
39
40 struct Pbs
41 {
42         uchar magic[3];
43         uchar version[8];
44         uchar sectsize[2];
45         uchar clustsize;
46         uchar nreserv[2];
47         uchar nfats;
48         uchar rootsize[2];
49         uchar volsize[2];
50         uchar mediadesc;
51         uchar fatsize[2];
52         uchar trksize[2];
53         uchar nheads[2];
54         uchar nhidden[4];
55         uchar bigvolsize[4];
56         uchar driveno;
57         uchar reserved0;
58         uchar bootsig;
59         uchar volid[4];
60         uchar label[11];
61         uchar type[8];
62 };
63
64 int readsect(ulong drive, ulong lba, void *buf);
65
66 int
67 read(void *f, void *data, int len)
68 {
69         Extend *ex = f;
70
71         if(ex->len > 0 && ex->rp >= ex->ep)
72                 if(readsect(ex->drive, ex->lba++, ex->rp = ex->buf))
73                         return -1;
74         if(ex->len < len)
75                 len = ex->len;
76         if(len > (ex->ep - ex->rp))
77                 len = ex->ep - ex->rp;
78         memmove(data, ex->rp, len);
79         ex->rp += len;
80         ex->len -= len;
81         return len;
82 }
83
84 void
85 close(void *f)
86 {
87         Extend *ex = f;
88
89         ex->drive = 0;
90         ex->lba = 0;
91         ex->len = 0;
92         ex->rp = ex->ep = ex->buf + Sectsz;
93 }
94
95 static ulong
96 rootlba(Extend *fat)
97 {
98         ulong lba;
99         Pbs *p = (Pbs*)fat->buf;
100
101         lba = fat->lba;
102         lba += *((ushort*)p->nreserv);
103         lba += *((ushort*)p->fatsize) * p->nfats;
104         return lba;
105 }
106
107 static ulong
108 dirlba(Extend *fat, Dir *d)
109 {
110         ulong clust;
111         ulong dirs;
112         ulong lba;
113         Pbs *p = (Pbs*)fat->buf;
114
115         lba = rootlba(fat);
116         dirs = *((ushort*)p->rootsize);
117         lba += (dirs * Dirsz + Sectsz-1) / Sectsz;
118         clust = *((ushort*)d->starthi)<<16 | *((ushort*)d->startlo);
119         lba += (clust - 2) * p->clustsize;
120         return lba;
121 }
122
123 static int
124 dirname(Dir *d, char buf[Maxpath])
125 {
126         char c, *x;
127
128         if(d->attr == 0x0F || *d->name <= 0)
129                 return -1;
130         memmove(buf, d->name, 8);
131         x = buf+8;
132         while(x > buf && x[-1] == ' ')
133                 x--;
134         if(d->name[8] != ' '){
135                 *x++ = '.';
136                 memmove(x, d->name+8, 3);
137                 x += 3;
138         }
139         while(x > buf && x[-1] == ' ')
140                 x--;
141         *x = 0;
142         x = buf;
143         while(c = *x){
144                 if(c >= 'A' && c <= 'Z'){
145                         c -= 'A';
146                         c += 'a';
147                 }
148                 *x++ = c;
149         }
150         return x - buf;
151 }
152
153 static int
154 fatwalk(Extend *ex, Extend *fat, char *path)
155 {
156         char name[Maxpath], *end;
157         Pbs *pbs = (Pbs*)fat->buf;
158         int i, j;
159         Dir d;
160
161         close(ex);
162         ex->drive = fat->drive;
163         ex->lba = rootlba(fat);
164         ex->len = *((ushort*)pbs->rootsize) * Dirsz;
165         for(;;){
166                 if(readn(ex, &d, Dirsz) != Dirsz)
167                         break;
168                 if((i = dirname(&d, name)) <= 0)
169                         continue;
170                 while(*path == '/')
171                         path++;
172                 if((end = strchr(path, '/')) == 0)
173                         end = path + strlen(path);
174                 j = end - path;
175                 if(i == j && memcmp(name, path, j) == 0){
176                         ex->rp = ex->ep;
177                         ex->lba = dirlba(fat, &d);
178                         ex->len = *((ulong*)d.len);
179                         if(*end == 0)
180                                 return 0;
181                         else if(d.attr & 0x10){
182                                 ex->len = pbs->clustsize * Sectsz;
183                                 path = end;
184                                 continue;
185                         }
186                         break;
187                 }
188         }
189         close(ex);
190         return -1;
191 }
192
193 static int
194 findfat(Extend *fat, int drive)
195 {
196         struct {
197                 uchar status;
198                 uchar bchs[3];
199                 uchar typ;
200                 uchar echs[3];
201                 uchar lba[4];
202                 uchar len[4];
203         } *p;
204         int i;
205
206         if(readsect(drive, 0, fat->buf))
207                 return -1;
208         if(fat->buf[0x1fe] != 0x55 || fat->buf[0x1ff] != 0xAA)
209                 return -1;
210         p = (void*)&fat->buf[0x1be];
211         for(i=0; i<4; i++){
212                 if(p[i].status != 0x80)
213                         continue;
214                 close(fat);
215                 fat->drive = drive;
216                 fat->lba = *((ulong*)p[i].lba);
217                 if(readsect(drive, fat->lba, fat->buf))
218                         continue;
219                 return 0;
220         }
221         return -1;
222 }
223
224 void
225 start(void *sp)
226 {
227         char path[Maxpath], *kern;
228         int drive;
229         Extend fat, ex;
230         void *f;
231
232         /* drive passed in DL */
233         drive = ((ushort*)sp)[5] & 0xFF;
234
235         if(findfat(&fat, drive)){
236                 print("no fat\r\n");
237                 halt();
238         }
239         if(fatwalk(f = &ex, &fat, "plan9.ini")){
240                 print("no config\r\n");
241                 f = 0;
242         }
243         for(;;){
244                 kern = configure(f, path); f = 0;
245                 if(fatwalk(&ex, &fat, kern)){
246                         print("not found\r\n");
247                         continue;
248                 }
249                 print(bootkern(&ex));
250                 print(crnl);
251         }
252 }
253