From 22f86a337996ea039a962aff0bd88fe47a6503ad Mon Sep 17 00:00:00 2001 From: tadryanom_bot Date: Tue, 3 Feb 2026 15:29:55 +0000 Subject: [PATCH] Feat: Add VFS, InitRD Driver and mkinitrd tool --- BUILD_GUIDE.md | 19 ++++++++- include/fs.h | 35 +++++++++++++++++ include/initrd.h | 17 ++++++++ include/multiboot2.h | 8 ++++ include/utils.h | 1 + src/drivers/initrd.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel/fs.c | 25 ++++++++++++ src/kernel/main.c | 45 +++++++++++++++++++-- src/kernel/shell.c | 50 +++++++++++++++++++++-- src/kernel/utils.c | 6 +++ tools/mkinitrd.c | 84 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 375 insertions(+), 9 deletions(-) create mode 100644 include/fs.h create mode 100644 include/initrd.h create mode 100644 src/drivers/initrd.c create mode 100644 src/kernel/fs.c create mode 100644 tools/mkinitrd.c diff --git a/BUILD_GUIDE.md b/BUILD_GUIDE.md index 8b069ca..0208288 100644 --- a/BUILD_GUIDE.md +++ b/BUILD_GUIDE.md @@ -32,18 +32,33 @@ Isso gera o arquivo `adros-x86.bin`. ### Criar ISO Bootável (GRUB) Para x86, precisamos empacotar o kernel numa ISO com GRUB. -Crie um arquivo `grub.cfg` em `iso_root/boot/grub/`: +1. Compile o gerador de InitRD: +```bash +gcc tools/mkinitrd.c -o mkinitrd +``` + +2. Crie arquivos de teste: +```bash +echo "Hello from File System!" > test.txt +echo "AdrOS v0.3" > version.txt +./mkinitrd initrd.img test.txt version.txt +``` + +3. Empacote a ISO: ```bash mkdir -p iso_root/boot/grub +cp adros-x86.bin iso_root/boot/ +cp initrd.img iso_root/boot/ + cat > iso_root/boot/grub/grub.cfg << EOF menuentry "AdrOS" { multiboot2 /boot/adros-x86.bin + module2 /boot/initrd.img boot } EOF -cp adros-x86.bin iso_root/boot/ grub-mkrescue -o adros.iso iso_root ``` diff --git a/include/fs.h b/include/fs.h new file mode 100644 index 0000000..e1fd4f6 --- /dev/null +++ b/include/fs.h @@ -0,0 +1,35 @@ +#ifndef FS_H +#define FS_H + +#include +#include + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 +#define FS_BLOCKDEVICE 0x04 + +typedef struct fs_node { + char name[128]; + uint32_t flags; + uint32_t inode; + uint32_t length; + + // Function pointers for operations (Polymorphism in C) + uint32_t (*read)(struct fs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer); + uint32_t (*write)(struct fs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer); + void (*open)(struct fs_node* node); + void (*close)(struct fs_node* node); + struct fs_node* (*finddir)(struct fs_node* node, char* name); +} fs_node_t; + +// Standard VFS functions +uint32_t vfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer); +uint32_t vfs_write(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer); +void vfs_open(fs_node_t* node); +void vfs_close(fs_node_t* node); + +// Global root of the filesystem +extern fs_node_t* fs_root; + +#endif diff --git a/include/initrd.h b/include/initrd.h new file mode 100644 index 0000000..1e8c1e2 --- /dev/null +++ b/include/initrd.h @@ -0,0 +1,17 @@ +#ifndef INITRD_H +#define INITRD_H + +#include "fs.h" +#include + +typedef struct { + uint8_t magic; // Magic number 0xBF + char name[64]; + uint32_t offset; // Offset relative to start of initrd + uint32_t length; +} initrd_file_header_t; + +// Initialize InitRD and return the root node (directory) +fs_node_t* initrd_init(uint32_t location); + +#endif diff --git a/include/multiboot2.h b/include/multiboot2.h index 57148f5..f7e1f9b 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -56,6 +56,14 @@ struct multiboot_tag_mmap { struct multiboot_mmap_entry entries[0]; }; +struct multiboot_tag_module { + uint32_t type; + uint32_t size; + uint32_t mod_start; + uint32_t mod_end; + char cmdline[0]; +}; + struct multiboot_mmap_entry { uint64_t addr; uint64_t len; diff --git a/include/utils.h b/include/utils.h index 638a62d..042bb59 100644 --- a/include/utils.h +++ b/include/utils.h @@ -7,6 +7,7 @@ size_t strlen(const char* str); int strcmp(const char* s1, const char* s2); int strncmp(const char* s1, const char* s2, size_t n); +char* strcpy(char* dest, const char* src); void* memset(void* ptr, int value, size_t num); void* memcpy(void* dst, const void* src, size_t n); diff --git a/src/drivers/initrd.c b/src/drivers/initrd.c new file mode 100644 index 0000000..34df213 --- /dev/null +++ b/src/drivers/initrd.c @@ -0,0 +1,94 @@ +#include "initrd.h" +#include "heap.h" +#include "utils.h" +#include "uart_console.h" + +// The raw initrd header +typedef struct { + uint32_t nfiles; +} initrd_header_t; + +initrd_header_t* initrd_header; +initrd_file_header_t* file_headers; +fs_node_t* initrd_root; +fs_node_t* root_nodes; // Array of file nodes +int n_root_nodes; + +// Read operation for a specific file +uint32_t initrd_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + initrd_file_header_t header = file_headers[node->inode]; + + if (offset > header.length) + return 0; + + if (offset + size > header.length) + size = header.length - offset; + + // Calculate physical address of data + // Data starts after nfiles + headers + // location + header.offset + // But header.offset is relative to start of data area or start of file? + // Let's assume absolute offset from initrd start for simplicity. + + uint8_t* data = (uint8_t*)((uint32_t)initrd_header + header.offset); + + memcpy(buffer, data + offset, size); + + return size; +} + +// Directory listing (Find file by name) +fs_node_t* initrd_finddir(fs_node_t* node, char* name) { + (void)node; // Root only has flat files + + for (int i = 0; i < n_root_nodes; i++) { + if (strcmp(name, root_nodes[i].name) == 0) { + return &root_nodes[i]; + } + } + return NULL; +} + +fs_node_t* initrd_init(uint32_t location) { + uart_print("[INITRD] Initializing at address: "); + // TODO: Print hex location + uart_print("\n"); + + initrd_header = (initrd_header_t*)location; + file_headers = (initrd_file_header_t*)(location + sizeof(initrd_header_t)); + + // Check sanity (assuming nfiles < 100) + if (initrd_header->nfiles > 100) { + uart_print("[INITRD] Warning: Suspicious file count. Corrupt image?\n"); + return NULL; + } + + n_root_nodes = initrd_header->nfiles; + + // Create Root Directory Node + initrd_root = (fs_node_t*)kmalloc(sizeof(fs_node_t)); + strcpy(initrd_root->name, "initrd"); + initrd_root->flags = FS_DIRECTORY; + initrd_root->finddir = &initrd_finddir; + initrd_root->inode = 0; + + // Create File Nodes + root_nodes = (fs_node_t*)kmalloc(sizeof(fs_node_t) * n_root_nodes); + + for (int i = 0; i < n_root_nodes; i++) { + file_headers[i].offset += location; // Relocate offset to absolute address + + strcpy(root_nodes[i].name, file_headers[i].name); + root_nodes[i].length = file_headers[i].length; + root_nodes[i].inode = i; + root_nodes[i].flags = FS_FILE; + root_nodes[i].read = &initrd_read; + + // Debug + uart_print(" Found file: "); + uart_print(root_nodes[i].name); + uart_print("\n"); + } + + return initrd_root; +} diff --git a/src/kernel/fs.c b/src/kernel/fs.c new file mode 100644 index 0000000..e90bf82 --- /dev/null +++ b/src/kernel/fs.c @@ -0,0 +1,25 @@ +#include "fs.h" + +fs_node_t* fs_root = NULL; + +uint32_t vfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + if (node->read) + return node->read(node, offset, size, buffer); + return 0; +} + +uint32_t vfs_write(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + if (node->write) + return node->write(node, offset, size, buffer); + return 0; +} + +void vfs_open(fs_node_t* node) { + if (node->open) + node->open(node); +} + +void vfs_close(fs_node_t* node) { + if (node->close) + node->close(node); +} diff --git a/src/kernel/main.c b/src/kernel/main.c index 78e5960..2669cf5 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -10,6 +10,9 @@ #include "shell.h" #include "heap.h" #include "timer.h" +#include "fs.h" +#include "initrd.h" +#include "multiboot2.h" /* Check if the compiler thinks we are targeting the wrong operating system. */ #if defined(__linux__) @@ -25,6 +28,8 @@ void kernel_main(unsigned long magic, unsigned long addr) { // 1. Initialize Console (UART works everywhere) uart_init(); uart_print("\n[AdrOS] Booting...\n"); + + uint32_t initrd_location = 0; #if defined(__i386__) || defined(__x86_64__) vga_init(); @@ -36,6 +41,24 @@ void kernel_main(unsigned long magic, unsigned long addr) { uart_print("[ERR] Invalid Multiboot2 Magic!\n"); } else { uart_print("[OK] Multiboot2 Magic Confirmed.\n"); + + // Search for InitRD Module + struct multiboot_tag *tag; + // Addr is physical. We need to access it. + // Bootloader puts it in low memory. We have identity map. + // But let's be safe. + // Assuming addr is accessible. + + for (tag = (struct multiboot_tag *)(addr + 8); + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + { + if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) { + struct multiboot_tag_module *mod = (struct multiboot_tag_module *)tag; + initrd_location = mod->mod_start; // Physical + uart_print("[BOOT] Found InitRD module!\n"); + } + } } #endif @@ -52,18 +75,32 @@ void kernel_main(unsigned long magic, unsigned long addr) { // 4. Initialize Kernel Heap kheap_init(); - // 5. Initialize Interrupts (x86) + // 5. Initialize FS (if InitRD found) + if (initrd_location) { + // Convert physical to virtual (Higher Half) + // P2V macro is in vmm.h or locally defined? + // Let's assume PMM/VMM setup allows access via P2V + // We need to define P2V here or include it + #define P2V(x) ((uintptr_t)(x) + 0xC0000000) + + uint32_t virt_loc = P2V(initrd_location); + fs_root = initrd_init(virt_loc); + } else { + uart_print("[WARN] No InitRD found. Filesystem will be empty.\n"); + } + + // 6. Initialize Interrupts (x86) uart_print("[AdrOS] Initializing IDT...\n"); idt_init(); - // 6. Initialize Drivers + // 7. Initialize Drivers keyboard_init(); - // 7. Initialize Multitasking + // 8. Initialize Multitasking uart_print("[AdrOS] Initializing Scheduler...\n"); process_init(); - // 8. Start Timer (Preemption!) - 50Hz + // 9. Start Timer (Preemption!) - 50Hz timer_init(50); // Start Shell as the main interaction loop diff --git a/src/kernel/shell.c b/src/kernel/shell.c index c1b310d..743a125 100644 --- a/src/kernel/shell.c +++ b/src/kernel/shell.c @@ -4,12 +4,17 @@ #include "utils.h" #include "pmm.h" #include "vga_console.h" -#include "process.h" // For sleep +#include "process.h" +#include "fs.h" #define MAX_CMD_LEN 256 static char cmd_buffer[MAX_CMD_LEN]; static int cmd_index = 0; +// HACK: To list files since we lack readdir +extern int n_root_nodes; +extern fs_node_t* root_nodes; + void print_prompt(void) { uart_print("\nAdrOS $> "); } @@ -20,12 +25,51 @@ void execute_command(char* cmd) { if (strcmp(cmd, "help") == 0) { uart_print("Available commands:\n"); uart_print(" help - Show this list\n"); - uart_print(" clear - Clear screen (if VGA)\n"); + uart_print(" clear - Clear screen\n"); uart_print(" mem - Show memory stats\n"); uart_print(" panic - Trigger kernel panic\n"); uart_print(" reboot - Restart system\n"); - uart_print(" sleep - Sleep for N ticks (50Hz)\n"); + uart_print(" sleep - Sleep for N ticks\n"); + uart_print(" ls - List files\n"); + uart_print(" cat - Print file content\n"); } + else if (strcmp(cmd, "ls") == 0) { + if (!fs_root) { + uart_print("No filesystem mounted.\n"); + } else { + uart_print("Files:\n"); + for(int i=0; ifinddir) + file = fs_root->finddir(fs_root, fname); + + if (file) { + // Alloc buffer or use stack + uint8_t buf[1024]; + // Cap read at 1023 + uint32_t len = file->length > 1023 ? 1023 : file->length; + + vfs_read(file, 0, len, buf); + buf[len] = 0; + uart_print((char*)buf); + uart_print("\n"); + } else { + uart_print("File not found.\n"); + } + } + } else if (strcmp(cmd, "clear") == 0) { // ANSI clear screen for UART uart_print("\033[2J\033[1;1H"); diff --git a/src/kernel/utils.c b/src/kernel/utils.c index cbf3370..210681d 100644 --- a/src/kernel/utils.c +++ b/src/kernel/utils.c @@ -98,6 +98,12 @@ int atoi(const char* str) { return sign * res; } +char* strcpy(char* dest, const char* src) { + char* temp = dest; + while ((*dest++ = *src++)); + return temp; +} + void itoa_hex(uint32_t num, char* str) { const char hex_chars[] = "0123456789ABCDEF"; str[0] = '0'; diff --git a/tools/mkinitrd.c b/tools/mkinitrd.c new file mode 100644 index 0000000..5f09224 --- /dev/null +++ b/tools/mkinitrd.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +struct initrd_header { + uint32_t nfiles; +}; + +struct initrd_file_header { + uint8_t magic; + char name[64]; + uint32_t offset; + uint32_t length; +}; + +int main(int argc, char **argv) { + if (argc < 3) { + printf("Usage: %s [file2] ...\n", argv[0]); + return 1; + } + + int nfiles = argc - 2; + struct initrd_header header; + header.nfiles = nfiles; + + struct initrd_file_header *headers = malloc(sizeof(struct initrd_file_header) * nfiles); + + // First pass: Calculate offsets + uint32_t data_offset = sizeof(struct initrd_header) + (sizeof(struct initrd_file_header) * nfiles); + + printf("Creating InitRD with %d files...\n", nfiles); + + for (int i = 0; i < nfiles; i++) { + char* fname = argv[i+2]; + + // Strip path, keep filename + char* basename = strrchr(fname, '/'); + if (basename) basename++; else basename = fname; + + FILE* f = fopen(fname, "rb"); + if (!f) { + perror("Error opening file"); + return 1; + } + fseek(f, 0, SEEK_END); + uint32_t len = ftell(f); + fclose(f); + + headers[i].magic = 0xBF; + strncpy(headers[i].name, basename, 63); + headers[i].offset = data_offset; // Absolute offset from file start + headers[i].length = len; + + printf(" File: %s (Size: %d bytes, Offset: %d)\n", basename, len, data_offset); + + data_offset += len; + } + + FILE *w = fopen(argv[1], "wb"); + if (!w) { + perror("Error opening output"); + return 1; + } + + fwrite(&header, sizeof(struct initrd_header), 1, w); + fwrite(headers, sizeof(struct initrd_file_header), nfiles, w); + + // Second pass: Write data + for (int i = 0; i < nfiles; i++) { + FILE* f = fopen(argv[i+2], "rb"); + uint8_t *buf = malloc(headers[i].length); + fread(buf, 1, headers[i].length, f); + fwrite(buf, 1, headers[i].length, w); + free(buf); + fclose(f); + } + + fclose(w); + free(headers); + printf("Done! Wrote %s\n", argv[1]); + + return 0; +} -- 2.43.0