fat12: can now write files
This commit is contained in:
@@ -18,7 +18,7 @@ LDFLAGS = -mregparmcall -Wl,--gc-sections -Os -nostdlib -flto
|
|||||||
fat12boot.bin:
|
fat12boot.bin:
|
||||||
$(OBJCOPY) -O binary $< $@
|
$(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.elf: LDFLAGS += -T bootsect.ld
|
||||||
|
|
||||||
fat12boot.bin: fat12boot.elf
|
fat12boot.bin: fat12boot.elf
|
||||||
|
190
src/fat12.c
190
src/fat12.c
@@ -1,12 +1,18 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "polos.h"
|
||||||
|
|
||||||
#define kSectorsPerCluster 2
|
#define kSectorsPerCluster 2
|
||||||
#define kSectorsPerTrack 9
|
#define kSectorsPerTrack 9
|
||||||
#define kHeads 2
|
#define kHeads 2
|
||||||
|
#define kTracks 40
|
||||||
#define kFatSizeSectors 2
|
#define kFatSizeSectors 2
|
||||||
#define kRootDirSizeSectors 7
|
#define kRootDirSizeSectors 7
|
||||||
|
#define kBytesPerCluster 1024
|
||||||
#define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors)
|
#define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors)
|
||||||
|
#define kNumClusters ((kSectorsPerTrack * kHeads * kTracks - kDataRegionStartSector) / kSectorsPerCluster + 2)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[8];
|
char name[8];
|
||||||
@@ -22,23 +28,12 @@ typedef struct {
|
|||||||
static uint8_t* gFat;
|
static uint8_t* gFat;
|
||||||
static direntry* gRootdir;
|
static direntry* gRootdir;
|
||||||
|
|
||||||
static int readsector(int c, int h, int s, uint8_t* addr) {
|
static uint8_t rwsector(uint8_t w, int c, int h, int s, void* addr) {
|
||||||
register uint8_t* dest asm("bx") = addr;
|
uint16_t ret;
|
||||||
register uint8_t nsects asm("al") = 1;
|
uint16_t cmd = w ? 0x0301 : 0x0201;
|
||||||
register uint8_t func asm("ah") = 0x02;
|
// retry for a total of up to 3 attempts if drive not ready
|
||||||
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++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
asm volatile("int $0x13"
|
ret = __readwritesector__(cmd, addr, c, h, s) >> 8;
|
||||||
: "=r"(ret)
|
|
||||||
: "r"(dest), "r"(nsects), "r"(func), "r"(sect), "r"(cyl),
|
|
||||||
"r"(head), "r"(drive), "r"(seg));
|
|
||||||
if (ret != 0x80) {
|
if (ret != 0x80) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -47,6 +42,14 @@ static int readsector(int c, int h, int s, uint8_t* addr) {
|
|||||||
return ret;
|
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) {
|
static int readcluster(int cluster) {
|
||||||
int offs = cluster * 3 / 2;
|
int offs = cluster * 3 / 2;
|
||||||
if (cluster % 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) {
|
static void cluster2chs(int cluster, int* c, int* h, int* s) {
|
||||||
int logicalsector =
|
int logicalsector =
|
||||||
kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
|
kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
|
||||||
@@ -65,19 +90,9 @@ static void cluster2chs(int cluster, int* c, int* h, int* s) {
|
|||||||
*c = logicalsector / (kHeads * kSectorsPerTrack);
|
*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) {
|
static int loadfile(direntry* entry, void* addr) {
|
||||||
int cluster = entry->cluster;
|
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;
|
int c, h, s;
|
||||||
cluster2chs(cluster, &c, &h, &s);
|
cluster2chs(cluster, &c, &h, &s);
|
||||||
if (readsector(c, h, s, addr + i)) {
|
if (readsector(c, h, s, addr + i)) {
|
||||||
@@ -88,10 +103,10 @@ static int loadfile(direntry* entry, void* addr) {
|
|||||||
s = 1;
|
s = 1;
|
||||||
h++;
|
h++;
|
||||||
}
|
}
|
||||||
if (h > 1) {
|
// if (h > 1) { // this will never happen
|
||||||
h = 0;
|
// h = 0;
|
||||||
c++;
|
// c++;
|
||||||
}
|
// }
|
||||||
if (readsector(c, h, s, addr + i + 512)) {
|
if (readsector(c, h, s, addr + i + 512)) {
|
||||||
return -5;
|
return -5;
|
||||||
};
|
};
|
||||||
@@ -100,6 +115,94 @@ static int loadfile(direntry* entry, void* addr) {
|
|||||||
return 0;
|
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) {
|
int fat12_init(void* fat_addr, void* rootdir_addr) {
|
||||||
if (readsector(0, 0, 2, fat_addr)) {
|
if (readsector(0, 0, 2, fat_addr)) {
|
||||||
return -2;
|
return -2;
|
||||||
@@ -115,21 +218,22 @@ int fat12_init(void* fat_addr, void* rootdir_addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fat12_readfile(const char* name, void* addr) {
|
int fat12_readfile(const char* name, void* addr) {
|
||||||
direntry* file = 0;
|
direntry* file = findfile(name);
|
||||||
|
|
||||||
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) {
|
if (!file) {
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadfile(file, addr);
|
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);
|
||||||
|
}
|
||||||
|
39
src/polos.h
39
src/polos.h
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
int runcomms(char until_idle);
|
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) {
|
inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
|
||||||
register uint16_t ad asm("di") = addr;
|
register uint16_t ad asm("di") = addr;
|
||||||
register uint8_t ret asm("al");
|
register uint8_t ret asm("al");
|
||||||
@@ -18,3 +21,39 @@ inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
|
|||||||
: "es");
|
: "es");
|
||||||
return ret;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
16
src/stdlib.c
16
src/stdlib.c
@@ -46,7 +46,17 @@ void* memset(void* ptr, int val, size_t len) {
|
|||||||
return ptr;
|
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 a1 asm("dx") = arg1;
|
||||||
register uint16_t a2 asm("cx") = arg2;
|
register uint16_t a2 asm("cx") = arg2;
|
||||||
register uint8_t ah asm("ah") = fun;
|
register uint8_t ah asm("ah") = fun;
|
||||||
@@ -79,12 +89,12 @@ int read(int fd, void* buf, size_t size) {
|
|||||||
if (fd != kLpt1) {
|
if (fd != kLpt1) {
|
||||||
return -1;
|
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) {
|
int write(int fd, void* buf, size_t size) {
|
||||||
if (fd != kLpt1) {
|
if (fd != kLpt1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return _int80h_2(0x06, (uint16_t)buf, size);
|
return int80h_2(0x06, (uint16_t)buf, size);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user