1 #include <u.h>
2 #include "dat.h"
3 #include "fns.h"
4 #include "mem.h"
5
6 enum {
7 Sectsz = 0x200,
8 Dirsz = 0x20,
9 Maxpath = 64,
10 Fat12 = 1,
11 Fat16 = 2,
12 Fat32 = 4,
13 };
14
15 typedef struct File File;
16 typedef struct Dir Dir;
17 typedef struct Pbs Pbs;
18 typedef struct Pbs32 Pbs32;
19 typedef struct Fat Fat;
20
21 struct Fat
22 {
23 ulong ver;
24 ulong clustsize;
25 ulong eofmark;
26 ulong partlba;
27 ulong fatlba;
28 ulong dirstart; /* LBA for FAT16, cluster for FAT32 */
29 ulong dirents;
30 ulong datalba;
31 };
32
33 struct File
34 {
35 Fat *fat;
36 ulong lba;
37 ulong clust;
38 ulong lbaoff;
39 ulong len;
40 uchar *rp;
41 uchar *ep;
42 uchar buf[Sectsz];
43 };
44
45 struct Dir
46 {
47 char name[11];
48 uchar attr;
49 uchar reserved;
50 uchar ctime;
51 uchar ctime[2];
52 uchar cdate[2];
53 uchar adate[2];
54 uchar starthi[2];
55 uchar mtime[2];
56 uchar mdate[2];
57 uchar startlo[2];
58 uchar len[4];
59 };
60
61 struct Pbs
62 {
63 uchar magic[3];
64 uchar version[8];
65 uchar sectsize[2];
66 uchar clustsize;
67 uchar nreserv[2];
68 uchar nfats;
69 uchar rootsize[2];
70 uchar volsize[2];
71 uchar mediadesc;
72 uchar fatsize[2];
73 uchar trksize[2];
74 uchar nheads[2];
75 uchar nhidden[4];
76 uchar bigvolsize[4];
77 uchar driveno;
78 uchar reserved0;
79 uchar bootsig;
80 uchar volid[4];
81 uchar label[11];
82 uchar type[8];
83 };
84
85 struct Pbs32
86 {
87 uchar common[36];
88 uchar fatsize[4];
89 uchar flags[2];
90 uchar ver[2];
91 uchar rootclust[4];
92 uchar fsinfo[2];
93 uchar bootbak[2];
94 uchar reserved0[12];
95 uchar driveno;
96 uchar reserved1;
97 uchar bootsig;
98 uchar volid[4];
99 uchar label[11];
100 uchar type[8];
101 };
102
103 enum {
104 Initfreq = 400000, /* initialisation frequency for MMC */
105 SDfreq = 25000000, /* standard SD frequency */
106 DTO = 14, /* data timeout exponent (guesswork) */
107 };
108
109 enum {
110 /* Controller registers */
111 Sysaddr = 0x00>>2,
112 Blksizecnt = 0x04>>2,
113 Arg1 = 0x08>>2,
114 Cmdtm = 0x0c>>2,
115 Resp0 = 0x10>>2,
116 Resp1 = 0x14>>2,
117 Resp2 = 0x18>>2,
118 Resp3 = 0x1c>>2,
119 Data = 0x20>>2,
120 Status = 0x24>>2,
121 Control0 = 0x28>>2,
122 Control1 = 0x2c>>2,
123 Interrupt = 0x30>>2,
124 Irptmask = 0x34>>2,
125 Irpten = 0x38>>2,
126 Capabilites = 0x40>>2,
127 Forceirpt = 0x50>>2,
128 Boottimeout = 0x60>>2,
129 Dbgsel = 0x64>>2,
130 Spiintspt = 0xf0>>2,
131 Slotisrver = 0xfc>>2,
132
133 /* Control0 */
134 Dwidth4 = 1<<1,
135 Dwidth1 = 0<<1,
136
137 /* Control1 */
138 Srstdata = 1<<26, /* reset data circuit */
139 Srstcmd = 1<<25, /* reset command circuit */
140 Srsthc = 1<<24, /* reset complete host controller */
141 Datatoshift = 16, /* data timeout unit exponent */
142 Datatomask = 0xF0000,
143 Clkfreq8shift = 8, /* SD clock base divider LSBs */
144 Clkfreq8mask = 0xFF00,
145 Clkfreqms2shift = 6, /* SD clock base divider MSBs */
146 Clkfreqms2mask = 0xC0,
147 Clkgendiv = 0<<5, /* SD clock divided */
148 Clkgenprog = 1<<5, /* SD clock programmable */
149 Clken = 1<<2, /* SD clock enable */
150 Clkstable = 1<<1,
151 Clkintlen = 1<<0, /* enable internal EMMC clocks */
152
153 /* Cmdtm */
154 Indexshift = 24,
155 Suspend = 1<<22,
156 Resume = 2<<22,
157 Abort = 3<<22,
158 Isdata = 1<<21,
159 Ixchken = 1<<20,
160 Crcchken = 1<<19,
161 Respmask = 3<<16,
162 Respnone = 0<<16,
163 Resp136 = 1<<16,
164 Resp48 = 2<<16,
165 Resp48busy = 3<<16,
166 Multiblock = 1<<5,
167 Host2card = 0<<4,
168 Card2host = 1<<4,
169 Autocmd12 = 1<<2,
170 Autocmd23 = 2<<2,
171 Blkcnten = 1<<1,
172 Dmaen = 1<<0,
173
174 /* Interrupt */
175 Acmderr = 1<<24,
176 Denderr = 1<<22,
177 Dcrcerr = 1<<21,
178 Dtoerr = 1<<20,
179 Cbaderr = 1<<19,
180 Cenderr = 1<<18,
181 Ccrcerr = 1<<17,
182 Ctoerr = 1<<16,
183 Err = 1<<15,
184 Cardintr = 1<<8,
185 Cardinsert = 1<<6,
186 Readrdy = 1<<5,
187 Writerdy = 1<<4,
188 Dmaintr = 1<<3,
189 Datadone = 1<<1,
190 Cmddone = 1<<0,
191
192 /* Status */
193 Present = 1<<18,
194 Bufread = 1<<11,
195 Bufwrite = 1<<10,
196 Readtrans = 1<<9,
197 Writetrans = 1<<8,
198 Datactive = 1<<2,
199 Datinhibit = 1<<1,
200 Cmdinhibit = 1<<0,
201
202 Inittimeout = 15,
203 // Multiblock = 1,
204
205 /* Commands */
206 GO_IDLE_STATE = 0,
207 ALL_SEND_CID = 2,
208 SEND_RELATIVE_ADDR= 3,
209 SELECT_CARD = 7,
210 SD_SEND_IF_COND = 8,
211 SEND_CSD = 9,
212 STOP_TRANSMISSION= 12,
213 SEND_STATUS = 13,
214 SET_BLOCKLEN = 16,
215 READ_SINGLE_BLOCK= 17,
216 READ_MULTIPLE_BLOCK= 18,
217 WRITE_BLOCK = 24,
218 WRITE_MULTIPLE_BLOCK= 25,
219 APP_CMD = 55, /* prefix for following app-specific commands */
220 SET_BUS_WIDTH = 6,
221 SD_SEND_OP_COND = 41,
222
223 /* Command arguments */
224 /* SD_SEND_IF_COND */
225 Voltage = 1<<8,
226 Checkpattern = 0x42,
227
228 /* SELECT_CARD */
229 Rcashift = 16,
230
231 /* SD_SEND_OP_COND */
232 Hcs = 1<<30, /* host supports SDHC & SDXC */
233 Ccs = 1<<30, /* card is SDHC or SDXC */
234 V3_3 = 3<<20, /* 3.2-3.4 volts */
235
236 /* SET_BUS_WIDTH */
237 Width1 = 0<<0,
238 Width4 = 2<<0,
239
240 /* OCR (operating conditions register) */
241 Powerup = 1<<31,
242 };
243
244 static int cmdinfo[64] = {
245 [0] Ixchken,
246 [2] Resp136,
247 [3] Resp48 | Ixchken | Crcchken,
248 [6] Resp48 | Ixchken | Crcchken,
249 [7] Resp48busy | Ixchken | Crcchken,
250 [8] Resp48 | Ixchken | Crcchken,
251 [9] Resp136,
252 [12] Resp48busy | Ixchken | Crcchken,
253 [13] Resp48 | Ixchken | Crcchken,
254 [16] Resp48,
255 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken | Dmaen,
256 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
257 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken | Dmaen,
258 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
259 [41] Resp48,
260 [55] Resp48 | Ixchken | Crcchken,
261 };
262
263 typedef struct Ctlr Ctlr;
264 struct Ctlr {
265 u32int *regs;
266 ulong extclk;
267
268 /* SD card registers */
269 u16int rca;
270 u32int ocr;
271 u32int cid[4];
272 u32int csd[4];
273 };
274 static Ctlr ctlr = {
275 .regs = (u32int*)0xE0101000,
276 .extclk = 100000000,
277 };
278
279
280 static ushort
GETSHORT(void * v)281 GETSHORT(void *v)
282 {
283 uchar *p = v;
284 return p[0] | p[1]<<8;
285 }
286 static ulong
GETLONG(void * v)287 GETLONG(void *v)
288 {
289 uchar *p = v;
290 return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
291 }
292
293 static int
memcmp(void * src,void * dst,int n)294 memcmp(void *src, void *dst, int n)
295 {
296 uchar *d = dst;
297 uchar *s = src;
298 int r = 0;
299
300 while(n-- > 0){
301 r = *d++ - *s++;
302 if(r != 0)
303 break;
304 }
305
306 return r;
307 }
308
309 static uint
clkdiv(uint d)310 clkdiv(uint d)
311 {
312 uint v;
313
314 v = (d << Clkfreq8shift) & Clkfreq8mask;
315 v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
316 return v;
317 }
318
319 static int
mmcwait(int mask)320 mmcwait(int mask)
321 {
322 int i, t;
323
324 t = 0;
325 while(((i=ctlr.regs[Interrupt])&mask) == 0)
326 if(t++ > 10000000)
327 break;
328
329 return i;
330 }
331
332 static int
mmccmd(u32int cmd,u32int arg,u32int * resp)333 mmccmd(u32int cmd, u32int arg, u32int *resp)
334 {
335 u32int *r;
336 u32int c;
337 int i;
338
339 c = (cmd << Indexshift) | cmdinfo[cmd];
340
341 r = ctlr.regs;
342 if(r[Status] & Cmdinhibit){
343 print("mmc: need to reset Cmdinhibit intr %x stat %x\n",
344 r[Interrupt], r[Status]);
345 r[Control1] |= Srstcmd;
346 while(r[Control1] & Srstcmd)
347 ;
348 while(r[Status] & Cmdinhibit)
349 ;
350 }
351 if((c & Isdata || (c & Respmask) == Resp48busy) && r[Status] & Datinhibit){
352 print("mmc: need to reset Datinhibit intr %x stat %x\n",
353 r[Interrupt], r[Status]);
354 r[Control1] |= Srstdata;
355 while(r[Control1] & Srstdata)
356 ;
357 while(r[Status] & Datinhibit)
358 ;
359 }
360 r[Arg1] = arg;
361 if((i = r[Interrupt]) != 0){
362 if(i != Cardinsert)
363 print("mmc: before command, intr was %x\n", i);
364 r[Interrupt] = i;
365 }
366 r[Cmdtm] = c;
367
368 i = mmcwait(Cmddone|Err);
369 if((i&(Cmddone|Err)) != Cmddone){
370 if((i&~Err) != Ctoerr)
371 print("mmc: CMD%d error intr %x stat %x\n", cmd, i, r[Status]);
372 r[Interrupt] = i;
373 if(r[Status]&Cmdinhibit){
374 r[Control1] |= Srstcmd;
375 while(r[Control1]&Srstcmd)
376 ;
377 }
378 return -1;
379 }
380 r[Interrupt] = i & ~(Datadone|Readrdy|Writerdy);
381 switch(c & Respmask){
382 case Resp136:
383 resp[0] = r[Resp0]<<8;
384 resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
385 resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
386 resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
387 break;
388 case Resp48:
389 case Resp48busy:
390 resp[0] = r[Resp0];
391 break;
392 case Respnone:
393 resp[0] = 0;
394 break;
395 }
396 if((c & Respmask) == Resp48busy){
397 r[Irpten] = Datadone|Err;
398 i = mmcwait(Cmddone|Err);
399 if(i)
400 r[Interrupt] = i;
401 r[Irpten] = 0;
402 if((i & Datadone) == 0)
403 print("mmc: no Datadone after CMD%d\n", cmd);
404 if(i & Err)
405 print("mmc: CMD%d error interrupt %x\n", cmd, i);
406 }
407
408 /*
409 * Once card is selected, use faster clock
410 */
411 if(cmd == SELECT_CARD){
412 sleep(10);
413 r[Control1] = clkdiv(ctlr.extclk / SDfreq - 1) |
414 DTO << Datatoshift | Clkgendiv | Clken | Clkintlen;
415 for(i = 0; i < 1000; i++){
416 sleep(1);
417 if(r[Control1] & Clkstable)
418 break;
419 }
420 sleep(10);
421 }
422
423 /*
424 * If card bus width changes, change host bus width
425 */
426 if(cmd == SET_BUS_WIDTH)
427 switch(arg){
428 case 0:
429 r[Control0] &= ~Dwidth4;
430 break;
431 case 2:
432 r[Control0] |= Dwidth4;
433 break;
434 }
435 return 0;
436 }
437
438 static int
mmconline(void)439 mmconline(void)
440 {
441 u32int r[4];
442 int hcs, i;
443
444 mmccmd(GO_IDLE_STATE, 0, r);
445
446 hcs = 0;
447 if(mmccmd(SD_SEND_IF_COND, Voltage|Checkpattern, r) == 0){
448 if(r[0] == (Voltage|Checkpattern)) /* SD 2.0 or above */
449 hcs = Hcs;
450 }
451 for(i = 0; i < Inittimeout; i++){
452 sleep(100);
453 mmccmd(APP_CMD, 0, r);
454 mmccmd(SD_SEND_OP_COND, hcs|V3_3, r);
455 if(r[0] & Powerup)
456 break;
457 }
458 if(i == Inittimeout){
459 print("mmc: card won't power up\n");
460 return -1;
461 }
462 ctlr.ocr = r[0];
463 mmccmd(ALL_SEND_CID, 0, r);
464 memcpy(ctlr.cid, r, sizeof ctlr.cid);
465 mmccmd(SEND_RELATIVE_ADDR, 0, r);
466 ctlr.rca = r[0]>>16;
467 mmccmd(SEND_CSD, ctlr.rca<<Rcashift, r);
468 memcpy(ctlr.csd, r, sizeof ctlr.csd);
469 mmccmd(SELECT_CARD, ctlr.rca<<Rcashift, r);
470 mmccmd(SET_BLOCKLEN, Sectsz, r);
471 mmccmd(APP_CMD, ctlr.rca<<Rcashift, r);
472 mmccmd(SET_BUS_WIDTH, Width4, r);
473 return 0;
474 }
475
476 static int
mmcinit(void)477 mmcinit(void)
478 {
479 u32int *r;
480 int i;
481
482 r = ctlr.regs;
483 r[Control1] = Srsthc;
484 for(i = 0; i < 100; i++){
485 sleep(10);
486 if((r[Control1] & Srsthc) == 0)
487 break;
488 }
489 if(i == 100){
490 print("mmc: reset timeout!\n");
491 return -1;
492 }
493 r[Control1] = clkdiv(ctlr.extclk / Initfreq - 1) | DTO << Datatoshift |
494 Clkgendiv | Clken | Clkintlen;
495 for(i = 0; i < 1000; i++){
496 sleep(1);
497 if(r[Control1] & Clkstable)
498 break;
499 }
500 if(i == 1000){
501 print("mmc: SD clock won't initialise!\n");
502 return -1;
503 }
504 r[Irptmask] = ~(Dtoerr|Cardintr|Dmaintr);
505 return mmconline();
506 }
507
508 static int
mmcread(ulong bno,uchar buf[Sectsz])509 mmcread(ulong bno, uchar buf[Sectsz])
510 {
511 u32int *r, rr[4];
512 int i, t;
513
514 r = ctlr.regs;
515 for(t=0; t<3; t++){
516 r[Sysaddr] = (u32int)buf;
517 r[Blksizecnt] = 7<<12 | 1<<16 | Sectsz;
518 r[Irpten] = Datadone|Err;
519 mmccmd(READ_SINGLE_BLOCK, ctlr.ocr & Ccs? bno : bno*Sectsz, rr);
520 i = mmcwait(Datadone|Err);
521 if(i)
522 r[Interrupt] = i;
523 r[Irpten] = 0;
524 if((i & Err) != 0)
525 print("mmcread: error intr %x stat %x\n", i, r[Status]);
526 else if((i & Datadone) == 0)
527 print("mmcread: timeout intr %x stat %x\n", i, r[Status]);
528 else
529 return 0;
530 }
531 return -1;
532 }
533
534 static int
dirname(Dir * d,char buf[Maxpath])535 dirname(Dir *d, char buf[Maxpath])
536 {
537 char c, *x;
538
539 if(d->attr == 0x0F || *d->name <= 0)
540 return -1;
541 memcpy(buf, d->name, 8);
542 x = buf+8;
543 while(x > buf && x[-1] == ' ')
544 x--;
545 if(d->name[8] != ' '){
546 *x++ = '.';
547 memcpy(x, d->name+8, 3);
548 x += 3;
549 }
550 while(x > buf && x[-1] == ' ')
551 x--;
552 *x = 0;
553 x = buf;
554 while(c = *x){
555 if(c >= 'A' && c <= 'Z'){
556 c -= 'A';
557 c += 'a';
558 }
559 *x++ = c;
560 }
561 return x - buf;
562 }
563
564 static ulong
dirclust(Dir * d)565 dirclust(Dir *d)
566 {
567 return GETSHORT(d->starthi)<<16 | GETSHORT(d->startlo);
568 }
569
570 static void
fileinit(File * fp,Fat * fat,ulong lba)571 fileinit(File *fp, Fat *fat, ulong lba)
572 {
573 fp->fat = fat;
574 fp->lba = lba;
575 fp->len = 0;
576 fp->lbaoff = 0;
577 fp->clust = ~0U;
578 fp->rp = fp->ep = fp->buf + Sectsz;
579 }
580
581 static ulong
readnext(File * fp,ulong clust)582 readnext(File *fp, ulong clust)
583 {
584 Fat *fat = fp->fat;
585 uchar tmp[2], *p;
586 ulong idx, lba;
587
588 if(fat->ver == Fat12)
589 idx = (3*clust)/2;
590 else
591 idx = clust*fat->ver;
592 lba = fat->fatlba + (idx / Sectsz);
593 if(mmcread(lba, fp->buf))
594 memset(fp->buf, 0xff, Sectsz);
595 p = &fp->buf[idx % Sectsz];
596 if(p == &fp->buf[Sectsz-1]){
597 tmp[0] = *p;
598 if(mmcread(++lba, fp->buf))
599 memset(fp->buf, 0xff, Sectsz);
600 tmp[1] = fp->buf[0];
601 p = tmp;
602 }
603 if(fat->ver == Fat32)
604 return GETLONG(p) & 0xfffffff;
605 idx = GETSHORT(p);
606 if(fat->ver == Fat12){
607 if(clust & 1)
608 idx >>= 4;
609 idx &= 0xfff;
610 }
611 return idx;
612 }
613
614 static int
fileread(File * fp,void * data,int len)615 fileread(File *fp, void *data, int len)
616 {
617 Fat *fat = fp->fat;
618
619 if(fp->len > 0 && fp->rp >= fp->ep){
620 if(fp->clust != ~0U){
621 if(fp->lbaoff % fat->clustsize == 0){
622 if(fp->clust < 2 || fp->clust >= fat->eofmark)
623 return -1;
624 fp->lbaoff = (fp->clust - 2) * fat->clustsize;
625 fp->clust = readnext(fp, fp->clust);
626 fp->lba = fp->lbaoff + fat->datalba;
627 }
628 fp->lbaoff++;
629 }
630 if(mmcread(fp->lba++, fp->rp = fp->buf))
631 return -1;
632 }
633 if(fp->len < len)
634 len = fp->len;
635 if(len > (fp->ep - fp->rp))
636 len = fp->ep - fp->rp;
637 memcpy(data, fp->rp, len);
638 fp->rp += len;
639 fp->len -= len;
640 return len;
641 }
642
643 static int
fatwalk(File * fp,Fat * fat,char * path)644 fatwalk(File *fp, Fat *fat, char *path)
645 {
646 char name[Maxpath], *end;
647 int i, j;
648 Dir d;
649
650 if(fat->ver == Fat32){
651 fileinit(fp, fat, 0);
652 fp->clust = fat->dirstart;
653 fp->len = ~0U;
654 }else{
655 fileinit(fp, fat, fat->dirstart);
656 fp->len = fat->dirents * Dirsz;
657 }
658 for(;;){
659 if(fileread(fp, &d, Dirsz) != Dirsz)
660 break;
661 if((i = dirname(&d, name)) <= 0)
662 continue;
663 while(*path == '/')
664 path++;
665 for(end = path; *end != '\0'; end++)
666 if(*end == '/')
667 break;
668 j = end - path;
669 if(i == j && memcmp(name, path, j) == 0){
670 fileinit(fp, fat, 0);
671 fp->clust = dirclust(&d);
672 fp->len = GETLONG(d.len);
673 if(*end == 0)
674 return 0;
675 else if(d.attr & 0x10){
676 fp->len = fat->clustsize * Sectsz;
677 path = end;
678 continue;
679 }
680 break;
681 }
682 }
683 return -1;
684 }
685
686 static int
conffat(Fat * fat,void * buf)687 conffat(Fat *fat, void *buf)
688 {
689 Pbs *p = buf;
690 uint fatsize, volsize, datasize, reserved;
691 uint ver, dirsize, dirents, clusters;
692
693 if(GETSHORT(p->sectsize) != Sectsz)
694 return -1;
695 if(memcmp(p->type, "FAT", 3) && memcmp(((Pbs32*)buf)->type, "FAT", 3))
696 return -1;
697
698 /* load values from fat */
699 ver = 0;
700 fatsize = GETSHORT(p->fatsize);
701 if(fatsize == 0){
702 fatsize = GETLONG(((Pbs32*)buf)->fatsize);
703 ver = Fat32;
704 }
705 volsize = GETSHORT(p->volsize);
706 if(volsize == 0)
707 volsize = GETLONG(p->bigvolsize);
708 reserved = GETSHORT(p->nreserv);
709 dirents = GETSHORT(p->rootsize);
710 dirsize = (dirents * Dirsz + Sectsz - 1) / Sectsz;
711 datasize = volsize - (reserved + fatsize * p->nfats + dirsize);
712 clusters = datasize / p->clustsize;
713 if(ver != Fat32)
714 if(clusters < 0xff7)
715 ver = Fat12;
716 else
717 ver = Fat16;
718
719 /* fill FAT descriptor */
720 fat->ver = ver;
721 fat->dirents = dirents;
722 fat->clustsize = p->clustsize;
723 fat->fatlba = fat->partlba + reserved;
724 fat->dirstart = fat->fatlba + fatsize * p->nfats;
725 if(ver == Fat32){
726 fat->datalba = fat->dirstart;
727 fat->dirstart = GETLONG(((Pbs32*)buf)->rootclust);
728 fat->eofmark = 0xffffff7;
729 }else{
730 fat->datalba = fat->dirstart + dirsize;
731 if(ver == Fat16)
732 fat->eofmark = 0xfff7;
733 else
734 fat->eofmark = 0xff7;
735 }
736 return 0;
737 }
738
739 static int
findfat(Fat * fat,ulong xbase,ulong lba)740 findfat(Fat *fat, ulong xbase, ulong lba)
741 {
742 struct {
743 uchar status;
744 uchar bchs[3];
745 uchar typ;
746 uchar echs[3];
747 uchar lba[4];
748 uchar len[4];
749 } p[4];
750 uchar buf[Sectsz];
751 int i;
752
753 if(xbase == 0)
754 xbase = lba;
755 if(mmcread(lba, buf))
756 return -1;
757 if(buf[0x1fe] != 0x55 || buf[0x1ff] != 0xAA)
758 return -1;
759 memcpy(p, &buf[0x1be], sizeof(p));
760 for(i=0; i<4; i++){
761 switch(p[i].typ){
762 case 0x05:
763 case 0x0f:
764 case 0x85:
765 /* extended partitions */
766 if(!findfat(fat, xbase, xbase + GETLONG(p[i].lba)))
767 return 0;
768 /* no break */
769 case 0x00:
770 continue;
771 default:
772 fat->partlba = lba + GETLONG(p[i].lba);
773 if(mmcread(fat->partlba, buf))
774 continue;
775 if(!conffat(fat, buf))
776 return 0;
777 }
778 }
779 return -1;
780 }
781
782 static int
load(Fat * fat,char * path,void * data)783 load(Fat *fat, char *path, void *data)
784 {
785 uchar *p;
786 File fi;
787 int n;
788
789 print("%s", path);
790 if(fatwalk(&fi, fat, path)){
791 print(": not found\n", path);
792 return -1;
793 }
794 print("...");
795 p = data;
796 while((n = fileread(&fi, p, Sectsz)) > 0)
797 p += n;
798 print("\n");
799 return p - (uchar*)data;
800 }
801
802 int
mmcboot(void)803 mmcboot(void)
804 {
805 char file[Maxpath], *p;
806 Fat fat;
807
808 if(mmcinit() < 0)
809 return 0;
810 if(findfat(&fat, 0, 0)){
811 print("no fat\n");
812 return 0;
813 }
814 memcpy(file, "9zynq", 6);
815 memset(p = (char*)CONF, 0, CONFSIZE);
816 p += load(&fat, "plan9.ini", p);
817 p -= 9; /* "bootfile=" */
818 while(--p >= (char*)CONF){
819 while(p > (char*)CONF && p[-1] != '\n')
820 p--;
821 if(memcmp("bootfile=", p, 9) == 0){
822 p += 9;
823 memcpy(file, p, sizeof(file)-1);
824 for(p=file; p < &file[sizeof(file)-1]; p++)
825 if(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
826 break;
827 *p = '\0';
828 break;
829 }
830 }
831 return load(&fat, file, (void*)TZERO) > 0;
832 }
833