#include #include #define kSectorsPerCluster 2 #define kSectorsPerTrack 9 #define kHeads 2 #define kFatSizeSectors 2 #define kRootDirSizeSectors 7 #define kDataRegionStartSector (1 + kFatSizeSectors*2 + kRootDirSizeSectors) typedef struct { char name[8]; char ext[3]; uint8_t attr; uint8_t dontcare[14]; uint16_t cluster; uint32_t size; } direntry; static uint8_t* gFat; static direntry* gRootdir; static int readsector(int c, int h, int s, uint8_t* addr) { register uint8_t* dest asm ("bx") = addr; register uint8_t nsects asm ("al") = 1; register uint8_t func asm ("ah") = 0x02; register uint8_t sect asm ("cl") = s; register uint8_t cyl asm ("ch") = c; register uint8_t head asm ("dh") = h; register uint8_t drive asm ("dl") = 0; register uint16_t seg asm ("es") = 0; register uint8_t ret asm("ah"); for (int i = 0; i < 3; i++) { asm volatile ("int $0x13" : "=r" (ret) : "r" (dest), "r" (nsects), "r" (func), "r" (sect), "r" (cyl), "r" (head), "r" (drive), "r" (seg)); if (ret != 0x80) { break; } } return ret; } static int readcluster(int cluster) { int offs = cluster * 3 / 2; if (cluster % 2) { // high nibble is lsb + whole byte return ((gFat[offs] & 0xf0) >> 4) + (gFat[offs+1] << 4); } else { return gFat[offs] + ((gFat[offs+1] & 0x0f) << 8); } } static void cluster2chs(int cluster, int* c, int* h, int* s) { int logicalsector = kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster; *s = (logicalsector % kSectorsPerTrack) + 1; *h = (logicalsector / kSectorsPerTrack) % kHeads; *c = logicalsector / (kHeads * kSectorsPerTrack); } static int strncmp(const char* s1, const char *s2, size_t len) { for (int i = 0; i < len && s1[i]; i++) { if (s1[i] != s2[i]) { return 1; } } // XXX: really we should return 0 only if *s1 == *s2 here too return 0; } static int loadfile(direntry* entry, void* addr) { int cluster = entry->cluster; for (int i = 0; i < entry->size; i+=1024) { int c, h, s; cluster2chs(cluster, &c, &h, &s); if (readsector(c, h, s, addr + i)) { return -5; } s++; if (s > 9) { s = 1; h++; } if (h > 1) { h = 0; c++; } if (readsector(c, h, s, addr + i + 512)) { return -5; }; cluster = readcluster(cluster); } return 0; } int fat12_init(void* fat_addr, void* rootdir_addr) { if (readsector(0, 0, 2, fat_addr)) { return -2; } if (readsector(0, 0, 6, rootdir_addr)) { return -3; } gFat = fat_addr; gRootdir = rootdir_addr; return 0; } int fat12_readfile(const char* name, void* addr) { direntry* file = 0; for (int i = 0; i < 16; i++) { direntry* entry = &gRootdir[i]; if (entry->name[0] == 0) { break; } if (!strncmp(entry->name, name, 11)) { file = entry; break; } } if (!file) { return -4; } return loadfile(file, addr); }