fat.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (C) 2018 bzt (bztsrc@github)
  3. *
  4. * Permission is hereby granted, free of charge, to any person
  5. * obtaining a copy of this software and associated documentation
  6. * files (the "Software"), to deal in the Software without
  7. * restriction, including without limitation the rights to use, copy,
  8. * modify, merge, publish, distribute, sublicense, and/or sell copies
  9. * of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22. * DEALINGS IN THE SOFTWARE.
  23. *
  24. */
  25. #include "sd.h"
  26. #include "uart.h"
  27. // get the end of bss segment from linker
  28. extern unsigned char _end;
  29. static unsigned int partitionlba = 0;
  30. // the BIOS Parameter Block (in Volume Boot Record)
  31. typedef struct {
  32. char jmp[3];
  33. char oem[8];
  34. unsigned char bps0;
  35. unsigned char bps1;
  36. unsigned char spc;
  37. unsigned short rsc;
  38. unsigned char nf;
  39. unsigned char nr0;
  40. unsigned char nr1;
  41. unsigned short ts16;
  42. unsigned char media;
  43. unsigned short spf16;
  44. unsigned short spt;
  45. unsigned short nh;
  46. unsigned int hs;
  47. unsigned int ts32;
  48. unsigned int spf32;
  49. unsigned int flg;
  50. unsigned int rc;
  51. char vol[6];
  52. char fst[8];
  53. char dmy[20];
  54. char fst2[8];
  55. } __attribute__((packed)) bpb_t;
  56. // directory entry structure
  57. typedef struct {
  58. char name[8];
  59. char ext[3];
  60. char attr[9];
  61. unsigned short ch;
  62. unsigned int attr2;
  63. unsigned short cl;
  64. unsigned int size;
  65. } __attribute__((packed)) fatdir_t;
  66. /**
  67. * Get the starting LBA address of the first partition
  68. * so that we know where our FAT file system starts, and
  69. * read that volume's BIOS Parameter Block
  70. */
  71. int fat_getpartition(void)
  72. {
  73. unsigned char *mbr=&_end;
  74. bpb_t *bpb=(bpb_t*)&_end;
  75. // read the partitioning table
  76. if(sd_readblock(0,&_end,1)) {
  77. // check magic
  78. if(mbr[510]!=0x55 || mbr[511]!=0xAA) {
  79. uart_puts("ERROR: Bad magic in MBR\n");
  80. return 0;
  81. }
  82. // check partition type
  83. if(mbr[0x1C2]!=0xE/*FAT16 LBA*/ && mbr[0x1C2]!=0xC/*FAT32 LBA*/) {
  84. uart_puts("ERROR: Wrong partition type\n");
  85. return 0;
  86. }
  87. uart_puts("MBR disk identifier: ");
  88. uart_hex(*((unsigned int*)((unsigned long)&_end+0x1B8)));
  89. uart_puts("\nFAT partition starts at: ");
  90. // should be this, but compiler generates bad code...
  91. //partitionlba=*((unsigned int*)((unsigned long)&_end+0x1C6));
  92. partitionlba=mbr[0x1C6] + (mbr[0x1C7]<<8) + (mbr[0x1C8]<<16) + (mbr[0x1C9]<<24);
  93. uart_hex(partitionlba);
  94. uart_puts("\n");
  95. // read the boot record
  96. if(!sd_readblock(partitionlba,&_end,1)) {
  97. uart_puts("ERROR: Unable to read boot record\n");
  98. return 0;
  99. }
  100. // check file system type. We don't use cluster numbers for that, but magic bytes
  101. if( !(bpb->fst[0]=='F' && bpb->fst[1]=='A' && bpb->fst[2]=='T') &&
  102. !(bpb->fst2[0]=='F' && bpb->fst2[1]=='A' && bpb->fst2[2]=='T')) {
  103. uart_puts("ERROR: Unknown file system type\n");
  104. return 0;
  105. }
  106. uart_puts("FAT type: ");
  107. // if 16 bit sector per fat is zero, then it's a FAT32
  108. uart_puts(bpb->spf16>0?"FAT16":"FAT32");
  109. uart_puts("\n");
  110. return 1;
  111. }
  112. return 0;
  113. }
  114. /**
  115. * List root directory entries in a FAT file system
  116. */
  117. void fat_listdirectory(void)
  118. {
  119. bpb_t *bpb=(bpb_t*)&_end;
  120. fatdir_t *dir=(fatdir_t*)&_end;
  121. unsigned int root_sec, s;
  122. // find the root directory's LBA
  123. root_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc;
  124. s = (bpb->nr0 + (bpb->nr1 << 8));
  125. uart_puts("FAT number of root diretory entries: ");
  126. uart_hex(s);
  127. s *= sizeof(fatdir_t);
  128. if(bpb->spf16==0) {
  129. // adjust for FAT32
  130. root_sec+=(bpb->rc-2)*bpb->spc;
  131. }
  132. // add partition LBA
  133. root_sec+=partitionlba;
  134. uart_puts("\nFAT root directory LBA: ");
  135. uart_hex(root_sec);
  136. uart_puts("\n");
  137. // load the root directory
  138. if(sd_readblock(root_sec,(unsigned char*)&_end,s/512+1)) {
  139. uart_puts("\nAttrib Cluster Size Name\n");
  140. // iterate on each entry and print out
  141. for(;dir->name[0]!=0;dir++) {
  142. // is it a valid entry?
  143. if(dir->name[0]==0xE5 || dir->attr[0]==0xF) continue;
  144. // decode attributes
  145. uart_send(dir->attr[0]& 1?'R':'.'); // read-only
  146. uart_send(dir->attr[0]& 2?'H':'.'); // hidden
  147. uart_send(dir->attr[0]& 4?'S':'.'); // system
  148. uart_send(dir->attr[0]& 8?'L':'.'); // volume label
  149. uart_send(dir->attr[0]&16?'D':'.'); // directory
  150. uart_send(dir->attr[0]&32?'A':'.'); // archive
  151. uart_send(' ');
  152. // staring cluster
  153. uart_hex(((unsigned int)dir->ch)<<16|dir->cl);
  154. uart_send(' ');
  155. // size
  156. uart_hex(dir->size);
  157. uart_send(' ');
  158. // filename
  159. dir->attr[0]=0;
  160. uart_puts(dir->name);
  161. uart_puts("\n");
  162. }
  163. } else {
  164. uart_puts("ERROR: Unable to load root directory\n");
  165. }
  166. }