diff --git a/src/Makefile b/src/Makefile index 83e2e81..cd3f89d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ LDFLAGS = -mregparmcall -Wl,--gc-sections -Os -nostdlib -flto fat12boot.bin: $(OBJCOPY) -O binary $< $@ -fat12boot.elf: fat12boot.o fat12.o bootsect.S +fat12boot.elf: fat12boot.o fat12.o bootsect.S stdlib.o fat12boot.elf: LDFLAGS += -T bootsect.ld fat12boot.bin: fat12boot.elf diff --git a/src/fat12.c b/src/fat12.c index 4484184..bd12c17 100644 --- a/src/fat12.c +++ b/src/fat12.c @@ -1,12 +1,18 @@ #include #include +#include + +#include "polos.h" #define kSectorsPerCluster 2 #define kSectorsPerTrack 9 #define kHeads 2 +#define kTracks 40 #define kFatSizeSectors 2 #define kRootDirSizeSectors 7 +#define kBytesPerCluster 1024 #define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors) +#define kNumClusters ((kSectorsPerTrack * kHeads * kTracks - kDataRegionStartSector) / kSectorsPerCluster + 2) typedef struct { char name[8]; @@ -22,23 +28,12 @@ typedef struct { 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"); - +static uint8_t rwsector(uint8_t w, int c, int h, int s, void* addr) { + uint16_t ret; + uint16_t cmd = w ? 0x0301 : 0x0201; + // retry for a total of up to 3 attempts if drive not ready 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)); + ret = __readwritesector__(cmd, addr, c, h, s) >> 8; if (ret != 0x80) { break; } @@ -47,6 +42,14 @@ static int readsector(int c, int h, int s, uint8_t* addr) { return ret; } +static uint8_t readsector(int c, int h, int s, void* addr) { + return rwsector(0, c, h, s, addr); +} + +static uint8_t writesector(int c, int h, int s, void* addr) { + return rwsector(1, c, h, s, addr); +} + static int readcluster(int cluster) { int offs = cluster * 3 / 2; if (cluster % 2) { @@ -57,6 +60,28 @@ static int readcluster(int cluster) { } } +static int writecluster(int cluster, int value) { + int offs = cluster * 3 / 2; + if (cluster % 2) { + gFat[offs] = (gFat[offs] & 0x0f) + ((value & 0x0f) << 4); + gFat[offs+1] = value >> 4; + // high nibble is lsb + whole byte + } else { + gFat[offs] = value & 0xff; + gFat[offs+1] = (gFat[offs+1] & 0xf0) + (value >> 8); + } + return value; +} + +static int firstfreecluster() { + for (int i = 2; i < kNumClusters; i++) { + if (readcluster(i) == 0) { + return i; + } + } + return -1; +} + static void cluster2chs(int cluster, int* c, int* h, int* s) { int logicalsector = kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster; @@ -65,19 +90,9 @@ static void cluster2chs(int cluster, int* c, int* h, int* s) { *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) { + for (int i = 0; i < entry->size; i += kBytesPerCluster) { int c, h, s; cluster2chs(cluster, &c, &h, &s); if (readsector(c, h, s, addr + i)) { @@ -88,10 +103,10 @@ static int loadfile(direntry* entry, void* addr) { s = 1; h++; } - if (h > 1) { - h = 0; - c++; - } + // if (h > 1) { // this will never happen + // h = 0; + // c++; + // } if (readsector(c, h, s, addr + i + 512)) { return -5; }; @@ -100,6 +115,94 @@ static int loadfile(direntry* entry, void* addr) { return 0; } +static direntry* findfile(const char* name) { + direntry* file = 0; + + for (int i = 0; i < 16; i++) { + direntry* entry = &gRootdir[i]; + if (!strncmp(entry->name, name, 11)) { + file = entry; + break; + } + } + return file; +} + +static direntry* newfile(const char* name) { + direntry* file = 0; + + for (int i = 0; i < 16; i++) { + direntry* entry = &gRootdir[i]; + if (entry->name[0] == 0) { + file = entry; + break; + } + } + if (!file) { + return file; + } + + memcpy(file->name, name, 11); + file->size = 0; + file->cluster = 0; + + return file; +} + +static int allocatecluster(int previous) { + int cluster = firstfreecluster(); + writecluster(cluster, 0xfff); + if (previous != 0) { + writecluster(previous, cluster); + } + return cluster; +} + +static void freeclusterchain(int cluster) { + if (cluster < 2 || cluster >= 0xf00) { + return; + } + freeclusterchain(readcluster(cluster)); + writecluster(cluster, 0); +} + +static int savefile(direntry* file, void* addr, int size) { + freeclusterchain(file->cluster); + file->cluster = 0; + int cluster = 0; + for (int i = 0; i < size; i += kBytesPerCluster) { + cluster = allocatecluster(cluster); + if (file->cluster == 0) { + file->cluster = cluster; + } + int c, h, s; + cluster2chs(cluster, &c, &h, &s); + if (writesector(c, h, s, addr + i)) { + return -7; + } + s++; + if (s > 9) { + s = 1; + h++; + } + // if (h > 1) { // no cluster will cross a cylinder boundary + // h = 0; + // c++; + // } + if (writesector(c, h, s, addr + i + 512)) { + return -7; + }; + } + file->size = size; + if (writesector(0, 0, 2, gFat)) { + return -8; + } + if (writesector(0, 0, 6, gRootdir)) { + return -9; + } + return 0; +} + int fat12_init(void* fat_addr, void* rootdir_addr) { if (readsector(0, 0, 2, fat_addr)) { return -2; @@ -115,21 +218,22 @@ int fat12_init(void* fat_addr, void* rootdir_addr) { } 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; - } - } + direntry* file = findfile(name); if (!file) { return -4; } return loadfile(file, addr); } + +int fat12_writefile(const char* name, void* addr, int size) { + direntry* file = findfile(name); + if (!file) { + file = newfile(name); + } + if (!file) { + // no moar space + return -6; + } + return savefile(file, addr, size); +} diff --git a/src/polos.h b/src/polos.h index 83d9da0..5613ec4 100644 --- a/src/polos.h +++ b/src/polos.h @@ -8,6 +8,9 @@ int runcomms(char until_idle); +int putchar(int); +int puts(const char*); + inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) { register uint16_t ad asm("di") = addr; register uint8_t ret asm("al"); @@ -18,3 +21,39 @@ inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) { : "es"); return ret; } + +inline static void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) { + register uint16_t ad asm("di") = addr; + register uint8_t v asm("al") = val; + asm("mov %0, %%es \t\n" + "stosb \n\t" ::"r"(seg), "r"(ad), "r"(v) : "es", "memory"); +} + +inline static uint16_t __readwritesector__(uint16_t cmd, uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) { + register uint8_t* dest asm("bx") = addr; + 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 ret asm("ax"); + + asm volatile("xor %%ax, %%ax \n\t" + "mov %%ax, %%es \n\t" + "mov %1, %%ax \n\t" + "int $0x13" + : "=r"(ret) + : "ir"(cmd), "r"(dest), "r"(sect), "r"(cyl), + "r"(head), "r"(drive) + ); + + return ret; +} + +inline static uint16_t __readsector__(uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) { + return __readwritesector__(0x0201, addr, c, h, s); +} + +inline static uint16_t __writesector__(uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) { + return __readwritesector__(0x0301, addr, c, h, s); +} + diff --git a/src/stdlib.c b/src/stdlib.c index 71e80a9..43f1b4b 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -46,7 +46,17 @@ void* memset(void* ptr, int val, size_t len) { return ptr; } -int _int80h_2(uint8_t fun, uint16_t arg1, uint16_t arg2) { +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 int80h_2(uint8_t fun, uint16_t arg1, uint16_t arg2) { register uint16_t a1 asm("dx") = arg1; register uint16_t a2 asm("cx") = arg2; register uint8_t ah asm("ah") = fun; @@ -79,12 +89,12 @@ int read(int fd, void* buf, size_t size) { if (fd != kLpt1) { return -1; } - return _int80h_2(0x05, (uint16_t)buf, size); + return int80h_2(0x05, (uint16_t)buf, size); } int write(int fd, void* buf, size_t size) { if (fd != kLpt1) { return -1; } - return _int80h_2(0x06, (uint16_t)buf, size); + return int80h_2(0x06, (uint16_t)buf, size); }