From 555c1177a60b81c598c457af9d37133e96a3f634 Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Thu, 11 Feb 2021 22:01:57 +0100 Subject: [PATCH] feat: setup initial fat reading logic --- kernel/fs/fat.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++-- kernel/fs/fat.h | 2 + kernel/fs/mbr.c | 40 ++++++------ kernel/kernel.c | 2 + 4 files changed, 179 insertions(+), 23 deletions(-) diff --git a/kernel/fs/fat.c b/kernel/fs/fat.c index 41430ab..58f0db7 100644 --- a/kernel/fs/fat.c +++ b/kernel/fs/fat.c @@ -3,8 +3,17 @@ // #include "fat.h" +#include "blockdev.h" #include +#include +#include +#include + +#define FAT_TYPE_12 1 +#define FAT_TYPE_16 2 +#define FAT_TYPE_32 3 +#define FAT_TYPE_EXFAT 4 typedef struct { struct { @@ -21,8 +30,8 @@ typedef struct { u16 sectors_per_track; u16 heads_sides; u32 hidden_sectors; - u32 large_sector_count; - } bpb; + u32 large_total_sectors; + } __attribute((packed)) bpb; union { struct { u8 drive_number; @@ -31,7 +40,7 @@ typedef struct { u32 serial; u8 label[11]; u8 system_id[8]; - } ebr_12_16; + } __attribute((packed)) ebr_12_16; struct { u32 sectors_per_fat; u16 flags; @@ -46,8 +55,147 @@ typedef struct { u32 serial; u8 label[11]; u8 system_id[8]; - } ebr_32; + } __attribute((packed)) ebr_32; }; -} fat_bpb; +} __attribute((packed)) fat_bpb; + +typedef struct { + u8 hours: 5; + u8 minutes: 6; + u8 seconds: 5; +} __attribute((packed)) time_83; + +typedef struct { + u8 hours: 5; + u8 minutes: 6; + u8 seconds: 5; +} __attribute((packed)) date_83; + +typedef struct { + union { + struct { + u8 name[11]; + u8 attributes; + u8 reserved; + u8 created_seconds; + time_83 created_time; + date_83 created_date; + date_83 access_date; + u16 high_first_cluster; + time_83 last_mod_time; + date_83 last_mod_date; + u16 low_first_cluster; + u32 file_size; + } __attribute((packed)) name_83; + struct { + u8 order; + u16 text_1[5]; + u8 attribute; + u8 long_entry_type; + u8 checksum; + u16 text_2[6]; + u16 reserved; + u16 text_3[2]; + } __attribute((packed)) long_name; + }; +} __attribute((packed)) fat_directory_entry; + +u8 fat_check_device(const block_device *device, u8 *first_sector); + +block_dev_driver fat_driver = { + .name = "fat", + .check_device = fat_check_device, + .free_device = NULL, // todo +}; + +void fat_register_block_driver() { + block_dev_register_driver(&fat_driver); +} + +void print_chars(char *chars, int amount) { + for (int i = 0; i < amount; ++i) { + if (chars[i] == 0) break; + printf("%c", chars[i]); + } +} + +u8 fat_check_device(const block_device *device, u8 *first_sector) { + fat_bpb bpb; + memcpy((u8 *) &bpb, first_sector, sizeof(fat_bpb)); + printf("OEM: "); + print_chars(bpb.bpb.oem_identifier, 11); + printf("\n"); + + u32 total_sectors = bpb.bpb.total_sectors == 0 ? bpb.bpb.large_total_sectors : bpb.bpb.total_sectors; + u32 fat_size = bpb.bpb.sectors_per_fat == 0 ? bpb.ebr_32.sectors_per_fat : bpb.bpb.sectors_per_fat; + u32 root_dir_sectors = ((bpb.bpb.directories * 32) + (bpb.bpb.bytes_per_sector - 1)) / bpb.bpb.bytes_per_sector; + u32 first_data_sector = bpb.bpb.reserved_sectors + (bpb.bpb.fats * fat_size) + root_dir_sectors; + u32 first_fat_sector = bpb.bpb.reserved_sectors; + u32 data_sectors = total_sectors - (bpb.bpb.reserved_sectors + (bpb.bpb.fats * fat_size) + root_dir_sectors); + u32 total_clusters = data_sectors / bpb.bpb.sectors_per_cluster; + + u8 fat_type; + if (total_clusters < 4085) { + fat_type = FAT_TYPE_12; + } else if (total_clusters < 65525) { + fat_type = FAT_TYPE_16; + } else if (total_clusters < 268435445) { + fat_type = FAT_TYPE_32; + } else { + fat_type = FAT_TYPE_EXFAT; + } + + // dump dir + // fat12/16 only + u32 first_root_dir_sector = first_data_sector - root_dir_sectors; + // todo fat32 + fat_directory_entry *entries = malloc(root_dir_sectors * bpb.bpb.bytes_per_sector); + device->access(device, BLOCK_DEV_DIRECTION_READ, first_root_dir_sector, root_dir_sectors, entries); + // todo read table + free(entries); + + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; +} + +typedef struct { + u32 sector; + u32 value; +} table_result; + +table_result +get_fat_table_value(u8 fat_type, const u8 *fat_table, u32 active_cluster, u32 first_fat_cluster, u32 sector_size) { + u32 fat_offset; + table_result result = { + .value = 0, + .sector = 0, + }; + switch (fat_type) { + case FAT_TYPE_12: + fat_offset = active_cluster * (active_cluster / 2); + result.sector = first_fat_cluster + (fat_offset / sector_size); + result.value = *(u16 *) &fat_table[fat_offset % sector_size]; + if (active_cluster & 0x1) { + result.value = result.value >> 4; + } else { + result.value = result.value & 0x0FFF; + } + return result; + case FAT_TYPE_16: + fat_offset = active_cluster * 2; + result.sector = first_fat_cluster + (fat_offset / sector_size); + result.value = *(u16 *) &fat_table[fat_offset % sector_size]; + return result; + case FAT_TYPE_32: + case FAT_TYPE_EXFAT: + fat_offset = active_cluster * 4; + result.sector = first_fat_cluster + (fat_offset / sector_size); + result.value = *(u32 *) &fat_table[fat_offset % sector_size] & 0x0FFFFFFF; + return result; + default: + break; + } + return result; +} + // steal validation code from here https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/fs/fat/inode.c#L1456 \ No newline at end of file diff --git a/kernel/fs/fat.h b/kernel/fs/fat.h index c01a75b..73d5eaf 100644 --- a/kernel/fs/fat.h +++ b/kernel/fs/fat.h @@ -5,4 +5,6 @@ #ifndef NEW_KERNEL_FAT_H #define NEW_KERNEL_FAT_H +void fat_register_block_driver(); + #endif //NEW_KERNEL_FAT_H diff --git a/kernel/fs/mbr.c b/kernel/fs/mbr.c index 38d6ad5..e82af3b 100644 --- a/kernel/fs/mbr.c +++ b/kernel/fs/mbr.c @@ -8,6 +8,7 @@ #include #include #include +#include typedef struct { u8 bootable; @@ -34,6 +35,19 @@ typedef struct { u32 start_lba; } mbr_block_driver_info; +u8 mbr_check_device(const block_device *device, u8 *first_sector); + +block_dev_driver mbr_driver = { + .name = "mbr", + .flags.root_only = 1, + .check_device = mbr_check_device, + .free_device = NULL, // todo +}; + +void mbr_register_block_driver() { + block_dev_register_driver(&mbr_driver); +} + u8 mbr_block_dev_access(const block_device *device, u8 direction, u32 lba, u8 sectors, void *target) { if (!device->flags.present || lba > device->num_lba) { return BLOCK_DEV_ACCESS_ERR; @@ -49,32 +63,33 @@ u8 mbr_block_dev_access(const block_device *device, u8 direction, u32 lba, u8 se } u8 mbr_check_device(const block_device *device, u8 *first_sector) { - mbr_table *table = (mbr_table *) &first_sector[512 - sizeof(mbr_table)]; - if (table->signature[0] != 0x55 && table->signature[1] != 0xAA) { // AA 55 but in little endian + mbr_table table; + memcpy((u8 *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table)); + if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } - if (table->reserved != 0x0000 && table->reserved != 0x5A5A) { + if (table.reserved != 0x0000 && table.reserved != 0x5A5A) { return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } for (int i = 0; i < 4; ++i) { - if (table->entries[i].num_lbas > device->num_lba || table->entries[i].start_lba > device->num_lba) { + if (table.entries[i].num_lbas > device->num_lba || table.entries[i].start_lba > device->num_lba) { return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } } for (int i = 0; i < 4; ++i) { - if (table->entries[i].system_id == 0) continue; + if (table.entries[i].system_id == 0) continue; mbr_block_driver_info *info = malloc(sizeof(mbr_block_driver_info)); info->device = device; - info->start_lba = table->entries[i].start_lba; + info->start_lba = table.entries[i].start_lba; block_device logical_device = { .flags.present = 1, - .num_lba = table->entries[i].num_lbas, + .num_lba = table.entries[i].num_lbas, .block_size = device->block_size, .access = mbr_block_dev_access, .device_info = info, @@ -89,17 +104,6 @@ u8 mbr_check_device(const block_device *device, u8 *first_sector) { return BLOCK_DEV_DRIVER_CHECK_OK; } -block_dev_driver mbr_driver = { - .name = "mbr", - .flags.root_only = 1, - .check_device = mbr_check_device, - .free_device = NULL, // todo -}; - -void mbr_register_block_driver() { - block_dev_register_driver(&mbr_driver); -} - void mbr_read_from_ide(u8 ide_drive) { char *mbr_data = malloc(0x200); ide_access(0, ide_drive, 0, 1, mbr_data); diff --git a/kernel/kernel.c b/kernel/kernel.c index 9d03395..b1bf65f 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -17,6 +17,7 @@ #include #include #include +#include #define BOOTLOADER_NAME_MAX_LENGTH 64 #define CMDLINE_MAX_LENGTH 256 @@ -149,6 +150,7 @@ void init_pci_system() { void init_block_devices() { // register drivers mbr_register_block_driver(); + fat_register_block_driver(); // scan block_dev_scan_repeat();