Fri, 24 Mar 2023 19:08:40 +0100
4 files changed,
237 insertions(+),
0 deletions(-)
A
include/cedos/fat.h
@@ -0,0 +1,12 @@
+#ifndef FAT_H +#define FAT_H + +#include <stdint.h> + +void *FAT_init(); +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset); +void *FAT_read_cluster(uint16_t cluster, void *buffer); +uint16_t FAT_next_cluster(uint16_t cluster); +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size); + +#endif
M
src/kernel/core.c
→
src/kernel/core.c
@@ -125,6 +125,9 @@ while (*fmt) {
if (state == STATE_ARGUMENT && *fmt == 'X') { printk_uint32(va_arg(args, uint32_t)); state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == 'x') { + printk_uint32(va_arg(args, uint32_t)); + state = STATE_DEFAULT; } else if (state == STATE_ARGUMENT && *fmt == 'i') { printk_int(va_arg(args, int)); state = STATE_DEFAULT;
A
src/kernel/fat.c
@@ -0,0 +1,186 @@
+#include "cedos/fat.h" +#include "string.h" +#include <stdint.h> + +typedef struct { + char jmp[3]; + char oemname[8]; + + uint16_t bytes_per_sect; + uint8_t sect_per_cluster; + uint16_t num_reserved_sectors; + uint8_t num_FAT; + uint16_t max_root_dir_entries; + uint16_t total_log_sectors; + uint8_t media_desc; + uint16_t log_sect_per_fat; +} __attribute__((packed)) BOOT_SECT; + +typedef struct { + char name[8]; + char ext[3]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t create_time; + uint16_t create_date; + uint16_t last_access_date; + uint16_t access_rights; + uint16_t last_modified_time; + uint16_t last_modified_date; + uint16_t start_of_clusters; + uint32_t file_size; +} __attribute__((packed)) DIR_ENTRY; + +typedef struct { + uint8_t seq_num; + uint16_t part_1[5]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t part_2[6]; + uint16_t start_of_clusters; + uint16_t part_3[2]; +} __attribute__((packed)) VFAT_LFN_ENTRY; + + +void *FAT_addr; +BOOT_SECT *boot_sect; + +uint32_t FAT1_lba; +uint32_t FAT2_lba; +uint32_t root_lba; +uint32_t data_lba; + +void *FAT_init() { + const int sector_size = 512; + const int sector_num = 128; + const int part_size = sector_size * sector_num; + + // open image file + FAT_addr = (void*)(0x10000); + + boot_sect = (BOOT_SECT*)(FAT_addr); + + FAT1_lba = boot_sect->num_reserved_sectors; + FAT2_lba = FAT1_lba + boot_sect->log_sect_per_fat; + root_lba = FAT1_lba + (boot_sect->log_sect_per_fat * boot_sect->num_FAT); + + long root_dir_size = boot_sect->max_root_dir_entries * sizeof(DIR_ENTRY); + data_lba = root_lba + (root_dir_size / boot_sect->bytes_per_sect); +} + +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset) { + if (offset != NULL) { + lba += (*offset) / boot_sect->bytes_per_sect; + *offset = (*offset) % boot_sect->bytes_per_sect; + } + + return (void*)((long)(FAT_addr) + (long)(lba * boot_sect->bytes_per_sect)); +} + +void *FAT_read_cluster(uint16_t cluster, void *buffer) { + // TODO: perform memcpy + void *addr = FAT_read_sector_offset(data_lba + ((cluster - 2) * boot_sect->sect_per_cluster), NULL); + + uint32_t cluster_size = boot_sect->bytes_per_sect * boot_sect->sect_per_cluster; + + memcpy(buffer, addr, cluster_size); + + return (void*)((uint8_t*)(buffer) + cluster_size); +} + +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size) { + memset(fname_buffer, 0, sizeof(fname_buffer)); + + while (1) { + // index overflow + if (index >= boot_sect->max_root_dir_entries) { + return -1; + } + + uint32_t offset = index * sizeof(DIR_ENTRY); + void *sect = FAT_read_sector_offset(root_lba, &offset); + DIR_ENTRY *dir_entry = (DIR_ENTRY *)((uint32_t)(sect) + offset); + + // if first character of name is 0, then no subsequent entry is in use + if (dir_entry->name[0] == 0x00) { + return -1; + } + + // deleted file + if (dir_entry->name[0] == 0xE5) { + index++; + continue; + } + + // VFAT LFN entry + if (dir_entry->file_attr == 0x0F && dir_entry->start_of_clusters == 0 && dir_entry->file_size != 0) { + VFAT_LFN_ENTRY *lfn_entry = (VFAT_LFN_ENTRY*)(dir_entry); + + int offset = 13 * ((lfn_entry->seq_num & 0x3F) - 1); + + // read long file name + for (int i = 0; i < 5; i++) { + fname_buffer[offset++] = lfn_entry->part_1[i]; + } + + for (int i = 0; i < 6; i++) { + fname_buffer[offset++] = lfn_entry->part_2[i]; + } + + for (int i = 0; i < 2; i++) { + fname_buffer[offset++] = lfn_entry->part_3[i]; + } + + index++; + continue; + } + + if (index == 0 && (dir_entry->file_attr & 0x08) && dir_entry->file_size == 0) { + // volume label + + } else if ((dir_entry->file_attr & 0x10) && dir_entry->file_size == 0) { + // subdirectory + + } else { + // regular file + + } + + *file_size = dir_entry->file_size; + *first_cluster = dir_entry->start_of_clusters; + + // if no VFAT LFN exists, use DOS name + if (fname_buffer[0] == 0) { + for (int i = 0; i < 8; i++) { + fname_buffer[i] = dir_entry->name[i]; + } + fname_buffer[8] = '.'; + for (int i = 0; i < 3; i++) { + fname_buffer[i + 9] = dir_entry->ext[i]; + } + fname_buffer[12] = 0; + } + + return index + 1; + } +} + +uint16_t FAT_next_cluster(uint16_t cluster) { + // assuming FAT12 + int offset = (cluster >> 1) * 3; + uint8_t *sect = FAT_read_sector_offset(FAT1_lba, &offset); + sect += offset; + + if (cluster & 0x01) { + uint16_t high = (uint16_t)(sect[2]); + uint16_t low = (uint16_t)(sect[1] & 0xF0) >> 4; + return (high << 4) | low; + } else { + uint16_t low = (uint16_t)(sect[0]); + uint16_t high = (uint16_t)(sect[1] & 0x0F) << 8; + return low | high; + } +} +
M
src/kernel/main.c
→
src/kernel/main.c
@@ -14,6 +14,8 @@ #include "cedos/core.h"
#include "cedos/elf.h" +#include "cedos/fat.h" + #include "linker.h" #include "assert.h"@@ -133,6 +135,40 @@ }
int os_main(void) { infodump(); + + FAT_init(); + + int i = 0; + + while (1) { + char buffer[832]; + uint16_t first_cluster; + uint32_t file_size; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + if (i <= 0) { break; } + + printk("%s (start: %i, size: %i)\n", buffer, first_cluster, file_size); + + uint16_t cluster = first_cluster; + + if (cluster == 0xFFF || cluster == 0x000) { continue; } + + printk(" clusters: "); + while (1) { + printk("%x", cluster); + + //char *sect = FAT_read_cluster(cluster); + //hexdump(sect, 512 * 8); + + cluster = FAT_next_cluster(cluster); + if (cluster == 0xFFF || cluster == 0x000) { break; } + printk(", "); + } + printk("\n"); + } + + while (1) {} // create test tasks printk("Creating tasks.\n");