Files
5150/fat12.c
2025-09-24 00:46:50 +02:00

139 lines
3.3 KiB
C

#include <stdint.h>
#include <stdlib.h>
#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) {
continue;
} else {
return ret;
}
}
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);
}