#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); }