From 642385797c6d108ce6ed294839d6dedf6b115541 Mon Sep 17 00:00:00 2001 From: Johnh Stefanelli Date: Thu, 6 Oct 2022 21:20:29 +0200 Subject: [PATCH] [Host/KernelCopy] First implementation of KernelCopy [LibFat] Add libfat [Stage1] Add stage1 project --- CMakeLists.txt | 1 + CMakeToolchain.txt | 2 +- host/CMakeLists.txt | 4 +- host/kernelcopy/CMakeLists.txt | 2 + host/kernelcopy/kernelcopy.c | 144 +++++++++++++++++++++++++++++++++ host/libhost/CMakeLists.txt | 3 + host/libhost/include/libhost.h | 10 +++ host/libhost/libhost.c | 86 ++++++++++++++++++++ host/mbrcopy/CMakeLists.txt | 2 +- host/mbrcopy/mbrcopy.c | 87 +------------------- libfat/include/libfat.h | 1 + libfat/libfat.c | 80 ++++++++++++++++++ mbr/mbr.asm | 10 ++- stage1/CMakeLists.txt | 2 + stage1/stage1.c | 8 ++ 15 files changed, 352 insertions(+), 90 deletions(-) create mode 100644 host/kernelcopy/CMakeLists.txt create mode 100644 host/kernelcopy/kernelcopy.c create mode 100644 host/libhost/CMakeLists.txt create mode 100644 host/libhost/include/libhost.h create mode 100644 host/libhost/libhost.c create mode 100644 stage1/CMakeLists.txt create mode 100644 stage1/stage1.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 783d0b8..4282e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,4 +5,5 @@ set(CMAKE_C_STANDARD 17) add_subdirectory(mbr) add_subdirectory(libfat) +add_subdirectory(stage1) add_subdirectory(rawimg) diff --git a/CMakeToolchain.txt b/CMakeToolchain.txt index b0400fb..469cb5b 100644 --- a/CMakeToolchain.txt +++ b/CMakeToolchain.txt @@ -11,7 +11,7 @@ set(CMAKE_CXX_LINK_EXECUTABLE "i686-elf-ld < set(CMAKE_ASM_NASM_LINK_EXECUTABLE "i686-elf-ld -o ") # Set language flags -set(CMAKE_C_FLAGS "-Wall -mtune=i386 -gdwarf -m32 -oS") +set(CMAKE_C_FLAGS "-Wall -mtune=i386 -gdwarf -m32 -Os") set(CMAKE_ASM_FLAGS "-felf32 -F dwarf -g") set(CMAKE_ASM_NASM_OBJECT_FORMAT elf32) set(CMAKE_STATIC_LINKER_FLAGS "") diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index c7d08e8..4bac132 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -3,4 +3,6 @@ cmake_minimum_required(VERSION 3.21) project(os3_host C) add_subdirectory(../libfat ${CMAKE_CURRENT_BINARY_DIR}/libfat) -add_subdirectory(mbrcopy) \ No newline at end of file +add_subdirectory(libhost) +add_subdirectory(mbrcopy) +add_subdirectory(kernelcopy) \ No newline at end of file diff --git a/host/kernelcopy/CMakeLists.txt b/host/kernelcopy/CMakeLists.txt new file mode 100644 index 0000000..adaf749 --- /dev/null +++ b/host/kernelcopy/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(kernelcopy kernelcopy.c) +target_link_libraries(kernelcopy host libfat) \ No newline at end of file diff --git a/host/kernelcopy/kernelcopy.c b/host/kernelcopy/kernelcopy.c new file mode 100644 index 0000000..da46d6f --- /dev/null +++ b/host/kernelcopy/kernelcopy.c @@ -0,0 +1,144 @@ +#include "libfat.h" +#include "libhost.h" +#include "stdio.h" +#include "string.h" +#include "stdlib.h" + +os_u32 fat_buffer[512]; + +#define STAGE1_NAME "OS3ST1 " +#define STAGE1_EXT "BIN" +#define STAGE1_FULL_NAME "OS3ST1 BIN" + +OS_PACK_START +typedef struct _MBR_BuildSettings { + os_u16 sig_0; + os_u16 sector; + os_u16 size; + os_u16 sig_1; +} OS_PACK_MID MBR_BuildSettings; +OS_PACK_END + +#define MBR_SETTINGS_SIG_0 ((os_u16)0x4952) +#define MBR_SETTINGS_SIG_1 ((os_u16)0x4953) + +int main(int argc, char** argv) { + if (argc < 3) { + fprintf(stderr, "Not enough arguments.\n"); + return 1; + } + + FILE* image = fopen(argv[1], "rb+"); + FILE* kernel = fopen(argv[2], "rb"); + + if (image == NULL) { + fprintf(stderr, "Failed to open image file\n"); + return 1; + } + + LFFileHandle image_handle = libhost_create_handle(image); + + LFControlBlock fat; + if(libfat_init(image_handle, fat_buffer, sizeof(fat_buffer), &fat) != OS_TRUE) { + fprintf(stderr, "Failed to read FAT header\n"); + return 1; + } + + printf("FAT OK.\n"); + + LFDirectory root_dir; + if(libfat_open_directory(&fat, 0, &root_dir) != OS_TRUE) { + fprintf(stderr, "Failed to open root directory\n"); + return 1; + } + + LFFile handle; + os_bool handle_found = OS_FALSE; + LFDirectoryEntry entry; + while(libfat_read_directory(&root_dir, &entry) == OS_TRUE) { + if(strcmp(entry.entry.file_name, STAGE1_NAME) == 0 && strcmp(entry.entry.extension, STAGE1_EXT) == 0) { + printf("Found existing 'OS3ST1.BIN'.\n"); + if(libfat_truncate(&fat, &entry) != OS_TRUE) { + fprintf(stderr, "Failed to truncate existing kernel.\n"); + return 1; + } + + handle_found = OS_TRUE; + break; + } + } + + if(handle_found == OS_FALSE) { + if(libfat_create(&fat, 0, STAGE1_FULL_NAME, OS_FALSE, &entry) != OS_TRUE) { + fprintf(stderr, "Failed to create kernel file\n"); + return 1; + } + printf("Created 'OS3ST1.BIN'.\n"); + } + + + if(libfat_open(&fat, &entry, &handle) != OS_TRUE) { + fprintf(stderr, "Failed to open kernel.\n"); + return 1; + } + + + char* buffer = malloc(8192); + os_u32 kernel_size = 0; + os_u32 read; + do { + read = fread(buffer, 1, 8192, kernel); + if(read > 0) { + if(libfat_write(&handle, buffer, read) != read) { + free(buffer); + fprintf(stderr, "Error during kernel copy\n"); + return 1; + } + } + kernel_size += read; + } while(read > 0); + printf("Kernel copy OK."); + + free(buffer); + fclose(kernel); + + os_u32 kernel_offset = libfat_get_true_entry_offset(&fat, &handle.file_entry); + + if (kernel_offset == 0) { + fprintf(stderr, "Failed to get true file sector.\n"); + return 1; + } + + if (kernel_offset % fat.header.base.bytes_per_sector != 0) { + fprintf(stderr, "Error: STAGE1 not aligned to sector\n"); + return 1; + } + + fseek(image, 0, SEEK_SET); + char mbr[512]; + fread(mbr, 1, 512, image); + + os_bool found = OS_FALSE; + os_s8* ptr = mbr; + for(int i = 0; i < 512 - sizeof(MBR_BuildSettings); i++) { + MBR_BuildSettings* settings = (MBR_BuildSettings*)ptr; + if (settings->sig_0 == MBR_SETTINGS_SIG_0 && settings->sig_1 == MBR_SETTINGS_SIG_1) { + settings->sector = kernel_offset / fat.header.base.bytes_per_sector; + settings->size = kernel_size; + found = OS_TRUE; + break; + } + ptr++; + } + + if (found == OS_FALSE) { + fprintf(stderr, "Error: could not find BUILD_SETTINGS markers\n"); + return 1; + } + + fseek(image, 0, SEEK_SET); + fwrite(mbr, 1, 512, image); + + fclose(image); + return 0; +} \ No newline at end of file diff --git a/host/libhost/CMakeLists.txt b/host/libhost/CMakeLists.txt new file mode 100644 index 0000000..2646770 --- /dev/null +++ b/host/libhost/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(host libhost.c include/libhost.h) +target_link_libraries(host libfat) +target_include_directories(host PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) \ No newline at end of file diff --git a/host/libhost/include/libhost.h b/host/libhost/include/libhost.h new file mode 100644 index 0000000..b14277b --- /dev/null +++ b/host/libhost/include/libhost.h @@ -0,0 +1,10 @@ +#include "libfat.h" +#include "stdio.h" + +extern os_u32 libhost_readRoutine(os_u32 amount, void* buffer, void* user_data); +extern os_u32 libhost_writeRoutine(os_u32 amount, void* buffer, void* user_data); +extern os_bool libhost_seekRoutine(os_u32 offset, os_u32 direction, void* user_data); +extern os_u32 libhost_tellRoutine(void* user_data); +extern void libhost_printRoutine(os_s8* data, os_u16 size); +extern void libhost_printNumber(os_u32 number); +extern LFFileHandle libhost_create_handle(FILE* f); \ No newline at end of file diff --git a/host/libhost/libhost.c b/host/libhost/libhost.c new file mode 100644 index 0000000..ca59657 --- /dev/null +++ b/host/libhost/libhost.c @@ -0,0 +1,86 @@ +#include "libhost.h" +#include "stdio.h" + + +os_u32 libhost_readRoutine(os_u32 amount, void* buffer, void* user_data) { + if (user_data == 0) { + return 0; + } + FILE* f = (FILE*)user_data; + + os_u32 read_bytes = fread(buffer, 1, amount, f); + return read_bytes; +} + +os_u32 libhost_writeRoutine(os_u32 amount, void* buffer, void* user_data) { + if (user_data == 0) { + return 0; + } + + FILE* f = (FILE*)user_data; + + os_u32 written_bytes = fwrite(buffer, 1, amount, f); + return written_bytes; +} + +os_bool libhost_seekRoutine(os_u32 offset, os_u32 direction, void* user_data) { + if (user_data == 0) { + return OS_FALSE; + } + + FILE* f = (FILE*)user_data; + int seek_dir = SEEK_SET; + switch(direction) { + case LIBFAT_SEEK_ORIGIN: + seek_dir = SEEK_SET; + break; + case LIBFAT_SEEK_CURRENT: + seek_dir = SEEK_CUR; + break; + case LIBFAT_SEEK_END: + seek_dir = SEEK_END; + break; + } + + int result = fseek(f, offset, seek_dir); + return result == 0 ? OS_TRUE : OS_FALSE; +} + +os_u32 libhost_tellRoutine(void* user_data) { + if (user_data == 0) { + return 0; + } + + FILE* f = (FILE*)user_data; + + os_u32 result = ftell(f); + return result; +} + +void libhost_printRoutine(os_s8* data, os_u16 size) { + if (size == 0) { + printf("%s\n", data); + return; + } + + for(os_u16 s = 0; s < size; s++) { + printf("%c", *data); + data++; + } + printf("\n"); +} + +void libhost_printNumber(os_u32 number) { + printf("%#x\n", number); +} + +extern LFFileHandle libhost_create_handle(FILE* f) { + LFFileHandle h; + h.read = libhost_readRoutine; + h.write = libhost_writeRoutine; + h.seek = libhost_seekRoutine; + h.tell = libhost_tellRoutine; + h.user_data = (void*)f; + + return h; +} \ No newline at end of file diff --git a/host/mbrcopy/CMakeLists.txt b/host/mbrcopy/CMakeLists.txt index b92409a..7d29c8b 100644 --- a/host/mbrcopy/CMakeLists.txt +++ b/host/mbrcopy/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(mbrcopy mbrcopy.c) -target_link_libraries(mbrcopy libfat) \ No newline at end of file +target_link_libraries(mbrcopy host libfat) \ No newline at end of file diff --git a/host/mbrcopy/mbrcopy.c b/host/mbrcopy/mbrcopy.c index ca767f5..e0ce9f2 100644 --- a/host/mbrcopy/mbrcopy.c +++ b/host/mbrcopy/mbrcopy.c @@ -2,82 +2,11 @@ #include "stdio.h" #include "stdlib.h" #include "string.h" +#include "libhost.h" os_u32 loaded_fat_segment[512]; os_u8 mbr_buffer[512]; -os_u32 readRoutine(os_u32 amount, void* buffer, void* user_data) { - if (user_data == 0) { - return 0; - } - FILE** f = (FILE**)user_data; - - os_u32 read_bytes = fread(buffer, 1, amount, *f); - return read_bytes; -} - -os_u32 writeRoutine(os_u32 amount, void* buffer, void* user_data) { - if (user_data == 0) { - return 0; - } - - FILE** f = (FILE**)user_data; - - os_u32 written_bytes = fwrite(buffer, 1, amount, *f); - return written_bytes; -} - -os_bool seekRoutine(os_u32 offset, os_u32 direction, void* user_data) { - if (user_data == 0) { - return OS_FALSE; - } - - FILE** f = (FILE**)user_data; - int seek_dir = SEEK_SET; - switch(direction) { - case LIBFAT_SEEK_ORIGIN: - seek_dir = SEEK_SET; - break; - case LIBFAT_SEEK_CURRENT: - seek_dir = SEEK_CUR; - break; - case LIBFAT_SEEK_END: - seek_dir = SEEK_END; - break; - } - - int result = fseek(*f, offset, seek_dir); - return result == 0 ? OS_TRUE : OS_FALSE; -} - -os_u32 tellRoutine(void* user_data) { - if (user_data == 0) { - return 0; - } - - FILE** f = (FILE**)user_data; - - os_u32 result = ftell(*f); - return result; -} - -void printRoutine(os_s8* data, os_u16 size) { - if (size == 0) { - printf("%s\n", data); - return; - } - - for(os_u16 s = 0; s < size; s++) { - printf("%c", *data); - data++; - } - printf("\n"); -} - -void printNumber(os_u32 number) { - printf("%#x\n", number); -} - int main(int argc, char** argv) { if (argc < 3) { printf("No files provided\n"); @@ -86,12 +15,7 @@ int main(int argc, char** argv) { FILE* f = fopen(argv[1], "rb+"); - LFFileHandle h; - h.read = readRoutine; - h.write = writeRoutine; - h.seek = seekRoutine; - h.tell = tellRoutine; - h.user_data = (void*)&f; + LFFileHandle h = libhost_create_handle(f); LFControlBlock fat; if(libfat_init(h, loaded_fat_segment, 512 * sizeof(os_u32), &fat) != OS_TRUE) { @@ -101,12 +25,7 @@ int main(int argc, char** argv) { FILE* f2 = fopen(argv[2], "rb"); - LFFileHandle mbrHandle; - mbrHandle.read = readRoutine; - mbrHandle.write = writeRoutine; - mbrHandle.seek = seekRoutine; - mbrHandle.tell = tellRoutine; - mbrHandle.user_data = (void*)&f2; + LFFileHandle mbrHandle = libhost_create_handle(f2); if(libfat_test_mbr(&mbrHandle) != OS_TRUE) { printf("Failed to test MBR...\n"); diff --git a/libfat/include/libfat.h b/libfat/include/libfat.h index 154de59..192cc6a 100644 --- a/libfat/include/libfat.h +++ b/libfat/include/libfat.h @@ -146,6 +146,7 @@ typedef struct _LFDirectory { extern os_bool libfat_init(LFFileHandle handle, void* buffer, os_u32 buffer_size, LFControlBlock* result); +extern os_bool libfat_truncate(LFControlBlock* fat, LFDirectoryEntry* entry); extern os_bool libfat_open(LFControlBlock* fat, LFDirectoryEntry* entry, LFFile* result); extern os_u32 libfat_read(LFFile* file, void* buffer, os_u32 buffer_size); extern os_u32 libfat_write(LFFile* file, void* biffer, os_u32 buffer_size); diff --git a/libfat/libfat.c b/libfat/libfat.c index c0a3d9e..2e9d0ab 100644 --- a/libfat/libfat.c +++ b/libfat/libfat.c @@ -377,6 +377,86 @@ os_bool libfat_fsinfo_update(LFControlBlock* fat) { return OS_TRUE; } +os_bool libfat_fsinfo_free(LFControlBlock* fat, os_u32 freed_cluster) { + os_u32 fsinfo_offset = fat->header.fsinfo_sector * fat->header.base.bytes_per_sector; + if(fat->handle.seek(fsinfo_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { + return OS_FALSE; + } + os_u32 sig = 0; + os_u32 read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); + if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_0) { + return OS_FALSE; + } + + if(fat->handle.seek(fsinfo_offset + 484, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) != OS_TRUE) { + return OS_FALSE; + } + read = fat->handle.read(sizeof(os_u32), (void*)&sig, fat->handle.user_data); + if (read != sizeof(os_u32) || sig != FAT_FSINFO_SIG_1) { + return OS_FALSE; + } + + os_u32 free_clusters = 0; + read = fat->handle.read(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); + if (read != sizeof(os_u32)) { + return OS_FALSE; + } + + os_u32 next_free_cluster = 0; + read = fat->handle.read(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); + if (read != sizeof(os_u32)) { + return OS_FALSE; + } + + if (free_clusters != 0xffffffff) { + free_clusters++; + if(fat->handle.seek(fsinfo_offset + 488, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { + fat->handle.write(sizeof(os_u32), (void*)&free_clusters, fat->handle.user_data); + } + } + + if (next_free_cluster != 0xffffffff && freed_cluster < next_free_cluster) { + next_free_cluster = libfat_find_free_cluster(fat); + if (next_free_cluster < 2) { + next_free_cluster = 0xffffffff; + } + if (fat->handle.seek(fsinfo_offset + 492, LIBFAT_SEEK_ORIGIN, fat->handle.user_data) == OS_TRUE) { + fat->handle.write(sizeof(os_u32), (void*)&next_free_cluster, fat->handle.user_data); + } + } + + return OS_TRUE; +} + + +os_bool libfat_truncate(LFControlBlock* fat, LFDirectoryEntry* entry) { + if (fat == 0 || entry == 0) { + return OS_FALSE; + } + + if ((entry->entry.attribute & FAT_SUBDIRECTORY_BIT) != 0) { + return OS_FALSE; //Disable truncating subdirectories + } + + entry->entry.file_size = 0; + os_u32 written = libfat_write_cluster(fat, entry->entry_cluster, &entry->entry, sizeof(FatDirectoryEntry), entry->entry_offset); + if (written != sizeof(FatDirectoryEntry)) { + return OS_FALSE; + } + + os_u32 cluster = libfat_read_cluster(fat, FAT_ENTRY_CLUSTER(entry->entry)); + libfat_write_fat_cluster(fat, FAT_ENTRY_CLUSTER(entry->entry), FAT_LAST_CLUSTER_32_2); + while(cluster < FAT_LAST_CLUSTER_32) { + os_u32 next_cluster = libfat_read_cluster(fat, cluster); + libfat_write_fat_cluster(fat, cluster, 0); + + libfat_fsinfo_free(fat, cluster); + cluster = next_cluster; + } + + return OS_TRUE; +} + os_u32 libfat_add_cluster_to_chain(LFControlBlock* fat, os_u32 last_cluster_id) { os_u32 cluster_value; do { diff --git a/mbr/mbr.asm b/mbr/mbr.asm index 9f8855e..068665e 100644 --- a/mbr/mbr.asm +++ b/mbr/mbr.asm @@ -218,6 +218,7 @@ entry: SUB SP, 4 ; clear previous call parameters + ; Enable A20 CALL check_a20 ; call check_a20. Result in Ax CMP AX, 0 ; compare AX to 0 (0 = A20 disabled) JNE after_a20 ; if AX != 0, a20 is enabled, skip enabling it @@ -243,6 +244,7 @@ endless_loop: JMP endless_loop ; loop endlessly section .data +info_marker dw 0x4950 disk_info_packet: info_size dw 0x1A info_flags dw 0x0 @@ -251,6 +253,7 @@ info_heads dd 0x0 info_sectors dd 0x0 info_total_sec dq 0x0 info_bps dw 0x0 +info_end dw 0x4951 read_sectors_packet: packet_size db 10h @@ -260,9 +263,10 @@ packet_buffer dd 0h packet_lba dq 0h build_settings: -build_settings_magic_0 dd 0x49494949 -build_settings_bytes dw 0x0 -build_settings_magic_1 dd 0x49494949 +build_settings_magic_0 dw 0x4952 +build_settings_offset dw 0x0 +build_settings_size dw 0x0 +build_settings_magic_1 dw 0x4953 msg db "OS3_BOOT_OK!" a20_msg db "NO_A20" \ No newline at end of file diff --git a/stage1/CMakeLists.txt b/stage1/CMakeLists.txt new file mode 100644 index 0000000..2d1a682 --- /dev/null +++ b/stage1/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(stage1 stage1.c) +target_link_libraries(stage1 libfat) \ No newline at end of file diff --git a/stage1/stage1.c b/stage1/stage1.c new file mode 100644 index 0000000..1d69fc1 --- /dev/null +++ b/stage1/stage1.c @@ -0,0 +1,8 @@ +// +// Created by barba on 06/10/2022. +// + + +int main() { + return 0; +} \ No newline at end of file