From 63167f223e1f54910f6b80e698390ee60aec79ee Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Tue, 11 Aug 2020 11:33:21 -0400 Subject: lots of progress currently, BAR fields of IDE drives are all returning zero, and the ATA read function isn't working. i'm not sure why. i'm going to work on VESA next, and come back to the IDE driver later --- src/kernel/fat.c | 271 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 183 insertions(+), 88 deletions(-) (limited to 'src/kernel/fat.c') 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 -- cgit v1.2.3