summaryrefslogtreecommitdiff
path: root/src/kernel/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/fat.c')
-rw-r--r--src/kernel/fat.c271
1 files changed, 183 insertions, 88 deletions
diff --git a/src/kernel/fat.c b/src/kernel/fat.c
index b8d1c3b..087d79e 100644
--- a/src/kernel/fat.c
+++ b/src/kernel/fat.c
@@ -1,115 +1,210 @@
#include "fat.h"
#include "ata.h"
#include "panic.h"
-#include "fs.h"
+#include "drive.h"
+#include "mem.h"
+#include "util.h"
-void load_fat() {
- read_sectors(FAT_INFO->reserved_sectors, FAT_INFO->sectors_per_fat, FAT);
+#define MAX_FAT_DRIVES 16
+#define MAX_OPEN_FILES_PER_DRIVE 32
+
+enum {
+ FA_READ_ONLY = 0x01,
+ FA_HIDDEN = 0x02,
+ FA_SYSTEM = 0x04,
+ FA_LABEL = 0x08,
+ FA_DIRECTORY = 0x10,
+ FA_ARCHIVE = 0x20,
+
+ FA_LFN = 0x0f
+};
+
+struct directory_entry {
+ uint8_t name[11];
+ uint8_t attrib;
+ uint8_t name_case;
+ uint8_t created_decimal;
+ uint16_t created_time;
+ uint16_t created_date;
+ uint16_t accessed_date;
+ uint16_t ignore;
+ uint16_t modified_time;
+ uint16_t modified_date;
+ uint16_t first_cluster;
+ uint32_t length;
+} __attribute__ ((packed));
+
+struct fat_info {
+ //3 bytes jump
+ uint8_t oem[8];
+ uint16_t bytes_per_sector;//Assumed to be 512
+ uint8_t sectors_per_cluster;//Assumed to be 1
+ uint16_t reserved_sectors;
+ uint8_t fats;//Only first is used
+ uint16_t root_entries;
+ uint16_t sectors;//Assumed not to be 0
+ uint8_t media_type;
+ uint16_t sectors_per_fat;
+ uint16_t sectors_per_track;
+ uint16_t heads;
+ uint32_t hidden_sectors;
+ uint32_t sectors_long;
+ uint8_t drive_number;
+ uint8_t reserved;
+ uint8_t ext_boot_marker;
+ uint32_t volume_id;
+ uint8_t label[11];
+ uint8_t fs_type[8];
+} __attribute__ ((packed));
+
+#define CTOS(c, fi) ((fi)->reserved_sectors + (fi)->sectors_per_fat * (fi)->fats + ((fi)->root_entries >> 4) + (c) - 2)
+
+struct fat_drive_info {
+ struct fat_info *fi;
+ uint16_t *fat;
+ struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE];
+};
+
+struct fat_drive_info infos[MAX_FAT_DRIVES];
+uint8_t next_id = 0;
+
+#define FI(n) ((struct fat_info *)(infos[n].fi + 3))
+#define FN(n, f) (infos[n].open_files[f - 1])
+
+uint8_t fat_driver_buffer[512];
+struct fat_info *next_fi;
+
+void alloc_next_fi() {
+ if (!((uint32_t)(next_fi = (struct fat_info *)((uint32_t)next_fi + 64)) & 0xfff))
+ if (!(next_fi = allocate_pages(1)))
+ panic("Out of memory in FAT driver.");
}
-bool to_fat_name(uint8_t *sname, uint8_t *fname) {
- uint8_t *sp = sname, *fp = fname;
- while (*sp != '.') {
- if (!*sp) {
- while (fp != fname + 11)
- *(fp++) = ' ';
- return false;
- }
- if (sp == sname + 8)
- return true;
- *(fp++) = *(sp++);
- }
- while (fp != fname + 8)
- *(fp++) = ' ';
- while (*++sp) {
- if (fp == fname + 11)
- return true;
- *(fp++) = *sp;
+struct drive *cur_drive;
+fs_id_t cur_id;
+struct directory_entry *cur_dir;
+
+//loads cluster `c`
+void load_cluster(uint16_t c, void *to) {
+ if (c == 0) {
+ *(uint8_t *)to = 0;
+ return;
}
- while (fp != fname + 11)
- *(fp++) = ' ';
- return false;
+
+ uint32_t s = CTOS(c, FI(cur_id));
+ cur_drive->read_sectors(cur_drive, s, 1, to);
}
-bool check_fat_names(uint8_t *lname, uint8_t *rname) {
- return (* (uint32_t *)lname == *(uint32_t *)rname) &&
- (*((uint32_t *)lname + 1) == *((uint32_t *)rname + 1)) &&
- (*((uint16_t *)lname + 4) == *((uint16_t *)rname + 4)) &&
- (*( lname + 10) == *( rname + 10));
+uint16_t next_cluster(uint16_t c) {
+ panic("TODO: compute next sector (or 0 for none)");
}
-struct directory_entry buffer[16];
-uint16_t dir_start, buffer_from;
+static inline bool check_fat_names(uint8_t *a, uint8_t *b) {
+ return (((uint32_t *)a)[0] == ((uint32_t *)b)[0]) &&
+ (((uint32_t *)a)[1] == ((uint32_t *)b)[1]) &&
+ (((uint16_t *)a)[8] == ((uint16_t *)b)[8]) &&
+ (((uint8_t *)a)[10] == ((uint8_t *)b)[10]);
+}
+//after: cur_dir -> specified entry in root
+bool try_locate_root_entry(uint8_t *fat_name) {
+ uint32_t cur_dir_sect = FI(cur_id)->reserved_sectors + FI(cur_id)->sectors_per_fat * FI(cur_id)->fats - 1;
+ cur_dir = (struct directory_entry *)(fat_driver_buffer + 512);
+ while (true) {
+ if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) {
+ cur_dir = (struct directory_entry *)fat_driver_buffer;
+ ++cur_dir_sect;
+ cur_drive->read_sectors(cur_drive, cur_dir_sect, 1, cur_dir);
+ }
+ if (!*(uint8_t *)cur_dir)
+ return false;
+ if (check_fat_names(cur_dir->name, fat_name))
+ return true;
+ else
+ ++cur_dir;
+ }
+}
-void load_root() {
- dir_start = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat;
+//before: cur_dir -> entry of dir to search
+//after: cur_dir -> specified entry in dir
+bool try_locate_entry(uint8_t *fat_name) {
+ uint16_t cur_dir_cluster = cur_dir->first_cluster;
+ load_cluster(cur_dir_cluster, fat_driver_buffer);
+ cur_dir = (struct directory_entry *)fat_driver_buffer;
+ while (true) {
+ if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) {
+ cur_dir = (struct directory_entry *)fat_driver_buffer;
+ ++cur_dir_cluster;
+ load_cluster(cur_dir_cluster = next_cluster(cur_dir_cluster), fat_driver_buffer);
+ }
+ if (!*(uint8_t *)cur_dir)
+ return false;
+ if (check_fat_names(cur_dir -> name, fat_name))
+ return true;
+ else
+ ++cur_dir;
+ }
}
-struct directory_entry *load_subentry(uint8_t *name) {
- uint8_t fname[11];
- if (to_fat_name(name, fname))
- return 0;
- struct directory_entry *ptr = buffer;
- uint16_t dir_current = dir_start;
- read_sectors(buffer_from = dir_current, 1, buffer);
- while (*(uint8_t *)ptr) {
- if (check_fat_names(ptr->name, fname))
- return ptr;
- if (++ptr == buffer + 16) {
- read_sectors(buffer_from = ++dir_current, 1, buffer);
- ptr = buffer;
+drive_file_id_t fat_get_file(struct drive *d, char *path) {
+ cur_drive = d;
+ cur_id = d->drive_id;
+ for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n)
+ if (!*(uint8_t *)(&FN(d->drive_id, n))) {
+ panic("TODO: open path at FN(id, n)");
+ return n;
}
- };
- return 0;
+ panic("Maximum number of files open reached for FAT drive.");
}
-bool load_subdir(uint8_t *name) {
- struct directory_entry *e = load_subentry(name);
- if (!e)
- return true;
- dir_start = CTOS(e->first_cluster);
- return false;
+void fat_free_file(struct drive *d, drive_file_id_t fid) {
+ *(uint8_t *)(&FN(d->drive_id, fid)) = 0;
}
-struct directory_entry *load_entry(uint8_t *path) {
- load_root();
- for (uint8_t *ptr = path; *ptr; ++ptr)
- if (*ptr == '/') {
- *ptr = 0;
- if (load_subdir(path))
- return 0;
- path = ptr + 1;
- }
- return load_subentry(path);
+void fat_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
+ cur_drive = d;
+ cur_id = d->drive_id;
+ uint16_t c = FN(d->drive_id, fid).first_cluster;
+ for (uint32_t i = 0; i < sector; ++i)
+ c = next_cluster(c);
+ load_cluster(c, at);
}
-bool get_entry(uint8_t *path, struct directory_entry *at) {
- struct directory_entry *e = load_entry(path);
- if (!e)
- return true;
- *at = *e;
- return false;
+uint32_t fat_get_free_sectors(struct drive *d) {
+ panic("TODO: get free sectors of drive");
}
-bool update_entry(uint8_t *path, struct directory_entry *value) {
- struct directory_entry *e = load_entry(path);
- if (!e)
- return true;
- *e = *value;
- write_sectors(buffer_from, 1, buffer);
- return false;
+void init_fat() {
+ next_fi = allocate_pages(1);
}
-bool create_entry(uint8_t *dir_path, struct directory_entry *value) {
- fs_handle h = fs_open(dir_path);
- struct directory_entry *check;
- while (fs_read(h, 32, check))
- if (check_fat_names(check->name, value->name)) {
- fs_close(h);
- return true;
- }
- fs_write(h, 32, value);
- fs_close(h);
- return false;
+bool try_fat_init_drive(struct drive *d) {
+ if (next_id >= MAX_FAT_DRIVES)
+ panic("Maximum number of FAT drives reached.");
+
+ if (!d->read_sectors(d, 0, 1, fat_driver_buffer))
+ return false;
+ memcpy(next_fi, fat_driver_buffer + 3, sizeof(struct fat_info));
+ uint32_t *fs_type_32 = (uint32_t *)next_fi->fs_type;
+ if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' + 65536 + '1' * 16777216)) ||
+ (fs_type_32[1] != ('6' + ' ' * 256 + ' ' + 65536 + ' ' * 16777216)))
+ return false;
+
+ d->fs_type = "FAT16";
+ d->get_file = &fat_get_file;
+ d->free_file = &fat_free_file;
+ d->load_sector = &fat_load_sector;
+ d->get_free_sectors = &fat_get_free_sectors;
+
+ d->fs_id = next_id;
+ infos[next_id].fi = next_fi;
+ infos[next_id].fat = allocate_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1);
+ for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i)
+ *(uint8_t *)&FN(next_id, i) = 0;
+
+ d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat);
+
+ alloc_next_fi();
+ ++next_id;
+ return true;
} \ No newline at end of file