CeDOS - Commit 379049a2

FAT12 bootloader works now
Celina Sophie Kalus
Fri, 24 Mar 2023 16:35:33 +0100
10 files changed, 299 insertions(+), 31 deletions(-)
M src/boot/drives.ssrc/boot/drives.s

@@ -125,8 +125,8 @@ # arguments:

# - ax: first sector (LBA) # - cx: last sector (LBA) # - bx: address offset -.global load_kernel -load_kernel: +.global load_sectors +load_sectors: movw $load_msg, %si call print
M src/boot/entry.ssrc/boot/entry.s

@@ -140,7 +140,7 @@ call reset_drive

call find_bootable_part - call load_kernel + call load_sectors movw $gdt_msg, %si call print

@@ -171,7 +171,7 @@ mov %eax, %fs

mov %eax, %gs mov %eax, %ss - call ss_copy + call load_kernel # create a page directory for the kernel that maps it to 0xC0000000 # and identity maps the first 1M of memory
M src/boot/fat.csrc/boot/fat.c

@@ -0,0 +1,186 @@

+#include "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/boot/fat.hsrc/boot/fat.h

@@ -3,15 +3,10 @@ #define FAT_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; -} BOOT_SECT; +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/boot/link.txtsrc/boot/link.txt

@@ -21,5 +21,6 @@ BYTE(0x55)

BYTE(0xAA) */*.o(.text) */*.o(.data) + */*.o(.rodata*) } >BOOT_VMA }
A src/boot/main.c

@@ -0,0 +1,52 @@

+#include <stdint.h> + +#include "string.h" +#include "fat.h" + +void printc(char c) { + static uint8_t *display = (uint8_t*)(0xB8000); + *(display++) = c; + *(display++) = 0x0F; +} + +void print_string(char *str) { + while (*str != 0) { + printc(*(str++)); + } +} + +int load_kernel() { + FAT_init(); + + int i = 0; + + // first cluster of kernel.bin file + uint16_t first_cluster; + + while (1) { + char buffer[832]; + uint32_t file_size; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + + print_string(buffer); + print_string(" "); + if (i <= 0) { return -1; } + + if (!(strcmp(buffer, "kernel.bin"))) { break; } + } + + // copy all clusters + uint16_t cluster = first_cluster; + void *buffer = (void *)(0x100000); + while (1) { + uint8_t *str = (uint8_t*)(0xB8000); + + buffer = FAT_read_cluster(cluster, buffer); + cluster = FAT_next_cluster(cluster); + + if (cluster == 0xFFF || cluster == 0x000) { break; } + } + + return 0; +}
M src/boot/makefilesrc/boot/makefile

@@ -21,6 +21,7 @@ .PHONY: build

build: $(GLOBAL_BUILD)/boot.bin $(GLOBAL_BUILD)/boot.bin: $(OBJECTS) > $(LD) $^ -T link.txt -Map=$(LOG_DIR)/boot_mapfile.txt -o $@ +> $(LD) $^ -T link.txt -Map=$(LOG_DIR)/boot_mapfile.txt --oformat elf32-i386 -o boot.o $(LOCAL_BUILD)/%.s.o: %.s > $(AS) -o $@ $<
M src/boot/paging.csrc/boot/paging.c

@@ -1,22 +1,8 @@

#include "paging.h" #include "linker.h" - -void *ss_memset(void *ptr, uint8_t value, uint32_t num) { - for (uint32_t i = 0; i < num; i++) { - ((uint8_t*)ptr)[i] = value; - } - return ptr; -} - -void ss_copy() { - char *src = (char*)(0x14E00); - char *dest = (char*)(0x100000); - int num = 0x80 * 0x200; +#include "string.h" +#include "fat.h" - for (uint32_t i = 0; i < num; i++) { - dest[i] = src[i]; - } -} void *create_kernel_environment() { PAGE_DIR_ENTRY (*pdir)[PAGE_ENTRY_COUNT] = (void*)(0 * PAGE_SIZE);

@@ -24,7 +10,7 @@ PAGE_TABLE_ENTRY (*kernel)[PAGE_ENTRY_COUNT] = (void*)(1 * PAGE_SIZE);

PAGE_TABLE_ENTRY (*lowmem)[PAGE_ENTRY_COUNT] = (void*)(2 * PAGE_SIZE); // set everything to zero - ss_memset(pdir, 0, 3 * PAGE_SIZE); + memset(pdir, 0, 3 * PAGE_SIZE); // map page directory to itself (*pdir)[PAGE_ENTRY_COUNT - 1].entry = MAKE_PAGE_ENTRY(pdir, 0b000000000011);
A src/boot/string.c

@@ -0,0 +1,35 @@

+#include "string.h" + +#include <stdint.h> + +void *memset(void *ptr, uint8_t value, uint32_t num) { + for (uint32_t i = 0; i < num; i++) { + ((uint8_t*)ptr)[i] = value; + } + return ptr; +} + +int strcmp(const char *str1, const char *str2) { + int i = 0; + + while (1) { + if (str1[i] != str2[i]) { + return str1[i] - str2[i]; + } + + if (str1[i] == 0) { + return 0; + } + + i++; + } +} + +void *memcpy(void *_dest, const void *_src, uint32_t n) { + uint8_t *src = (uint8_t*)(_src); + uint8_t *dest = (uint8_t*)(_dest); + + for (int i = 0; i < n; i++) { + dest[i] = src[i]; + } +}
A src/boot/string.h

@@ -0,0 +1,12 @@

+#ifndef STRING_H +#define STRING_H + +#include <stdint.h> + +#define NULL (void*)(0) + +void *memset(void *ptr, uint8_t value, uint32_t num); +int strcmp(const char *str1, const char *str2); +void *memcpy(void *dest, const void * src, uint32_t n); + +#endif