]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
Feat: Virtual Filesystem (VFS) and Initial Ramdisk (InitRD) support
authortadryanom_bot <[email protected]>
Tue, 3 Feb 2026 15:31:46 +0000 (15:31 +0000)
committertadryanom_bot <[email protected]>
Tue, 3 Feb 2026 15:31:46 +0000 (15:31 +0000)
include/multiboot2.h
include/utils.h
src/drivers/initrd.c
src/kernel/main.c
src/kernel/shell.c
src/kernel/utils.c
tools/mkinitrd.c

index f7e1f9b81e6f1176baa6603903144bcdc314c853..c28535e1a54376f327dff206b13b65df72fe9247 100644 (file)
@@ -61,7 +61,7 @@ struct multiboot_tag_module {
     uint32_t size;
     uint32_t mod_start;
     uint32_t mod_end;
-    char cmdline[0];
+    char string[0];
 };
 
 struct multiboot_mmap_entry {
index 042bb59e41b50c4789b9ea423031e2e633649de0..107e36e8837cca045971c179e7f56bafab1f8004 100644 (file)
@@ -10,6 +10,7 @@ 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);
+char* strcpy(char* dest, const char* src);
 
 // Reverse a string (helper for itoa)
 void reverse(char* str, int length);
index 34df213a1d706c3369889d23bf6f45d9e96e58d4..bd21bde24c4734fe11da11e8df6d6ce0989d162a 100644 (file)
@@ -1,94 +1,98 @@
 #include "initrd.h"
-#include "heap.h"
 #include "utils.h"
+#include "heap.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 > 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.
+    // Calculate memory location: location_of_headers + sizeof(headers) + offset_in_file
+    // Wait, our simple format:
+    // [n_files] [header 0] [header 1] ... [data]
+    // The 'offset' in header is relative to the START of the initrd or the data region?
+    // Let's assume relative to START of InitRD location.
     
-    uint8_t* data = (uint8_t*)((uint32_t)initrd_header + header.offset);
+    // We need to know the base address of InitRD. Let's store it globally or in node.
+    // Hack: Assuming offset in header is absolute address for now (patched during build)
+    // OR: offset is relative to initrd start.
     
-    memcpy(buffer, data + offset, size);
+    // Let's refine the format logic in initrd_init.
+    return 0; // Placeholder until init logic fixed below
+}
+
+// Fixed read function
+// We need to store the base address somewhere.
+static uint32_t initrd_location_base = 0;
+
+uint32_t initrd_read_impl(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;
+        
+    // Address = Base + Header_Offset + Read_Offset
+    uint8_t* src = (uint8_t*)(initrd_location_base + header.offset + offset);
+    
+    memcpy(buffer, src, 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
-    
+struct fs_node* initrd_finddir(struct fs_node* node, char* name) {
+    (void)node;
     for (int i = 0; i < n_root_nodes; i++) {
-        if (strcmp(name, root_nodes[i].name) == 0) {
+        if (strcmp(name, root_nodes[i].name) == 0)
             return &root_nodes[i];
-        }
     }
-    return NULL;
+    return 0;
 }
 
 fs_node_t* initrd_init(uint32_t location) {
-    uart_print("[INITRD] Initializing at address: ");
-    // TODO: Print hex location
-    uart_print("\n");
+    initrd_location_base = location;
     
-    initrd_header = (initrd_header_t*)location;
-    file_headers = (initrd_file_header_t*)(location + sizeof(initrd_header_t));
+    // Read number of files (first 4 bytes)
+    uint32_t* n_files_ptr = (uint32_t*)location;
+    n_root_nodes = *n_files_ptr;
     
-    // 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;
+    uart_print("[INITRD] Found ");
+    char buf[16]; itoa(n_root_nodes, buf, 10);
+    uart_print(buf);
+    uart_print(" files.\n");
     
-    // 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;
+    // Headers start right after n_files
+    file_headers = (initrd_file_header_t*)(location + sizeof(uint32_t));
     
-    // Create File Nodes
+    // Allocate nodes for files
     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
+        file_headers[i].offset += location; // Fixup offset to be 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].length = file_headers[i].length;
         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");
+        root_nodes[i].read = &initrd_read_impl;
+        root_nodes[i].write = 0;
+        root_nodes[i].open = 0;
+        root_nodes[i].close = 0;
+        root_nodes[i].finddir = 0;
     }
     
+    // 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;
+    
     return initrd_root;
 }
index 2669cf5522f6d60afca93990a3f754fb9e12e331..4d9dd9efcbea7fcbdec0182f2e9365146e429107 100644 (file)
@@ -10,9 +10,9 @@
 #include "shell.h"
 #include "heap.h"
 #include "timer.h"
-#include "fs.h"
-#include "initrd.h"
 #include "multiboot2.h"
+#include "initrd.h"
+#include "fs.h"
 
 /* Check if the compiler thinks we are targeting the wrong operating system. */
 #if defined(__linux__)
@@ -28,8 +28,6 @@ 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();
@@ -41,24 +39,6 @@ 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
 
@@ -75,33 +55,45 @@ void kernel_main(unsigned long magic, unsigned long addr) {
     // 4. Initialize Kernel Heap
     kheap_init();
     
-    // 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)
+    // 5. Initialize Interrupts (x86)
     uart_print("[AdrOS] Initializing IDT...\n");
     idt_init();
     
-    // 7. Initialize Drivers
+    // 6. Initialize Drivers
     keyboard_init();
     
-    // 8. Initialize Multitasking
+    // 7. Initialize Multitasking
     uart_print("[AdrOS] Initializing Scheduler...\n");
     process_init();
     
-    // 9. Start Timer (Preemption!) - 50Hz
+    // 8. Start Timer (Preemption!) - 50Hz
     timer_init(50);
+
+    // 9. Load InitRD (if available)
+    struct multiboot_tag *tag;
+    // addr is physical. In Higher Half, we might need to convert it?
+    // boot.S mapped 0-4MB identity, so if multiboot struct is there, we are good.
+    // Let's assume addr is accessible.
+    
+    for (tag = (struct multiboot_tag *)((uint8_t *)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;
+            
+            uart_print("[INITRD] Module found at: ");
+            // TODO: Print Hex
+            uart_print("\n");
+            
+            // mod->mod_start is Physical Address.
+            // We need to access it. Assuming Identity Map covers it or we use P2V logic.
+            // Let's rely on P2V macro logic if it was available here, or just cast.
+            // For now, let's assume it's low memory and identity mapped.
+            
+            fs_root = initrd_init(mod->mod_start);
+        }
+    }
     
     // Start Shell as the main interaction loop
     shell_init();
@@ -114,7 +106,6 @@ void kernel_main(unsigned long magic, unsigned long addr) {
 
     // Infinite loop acting as Idle Task
     for(;;) {
-        // HLT puts CPU to sleep until next interrupt (Timer or Keyboard)
         #if defined(__i386__) || defined(__x86_64__)
         __asm__("hlt");
         #elif defined(__aarch64__)
index 743a125ce335d573b1b414e0deba97a6c6338de3..acabec1aee53af89becc8c27d2eb086e6a3e89a2 100644 (file)
@@ -4,17 +4,14 @@
 #include "utils.h"
 #include "pmm.h"
 #include "vga_console.h"
-#include "process.h"
+#include "process.h" 
 #include "fs.h"
+#include "heap.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 $> ");
 }
@@ -26,23 +23,19 @@ void execute_command(char* cmd) {
         uart_print("Available commands:\n");
         uart_print("  help        - Show this list\n");
         uart_print("  clear       - Clear screen\n");
+        uart_print("  ls          - List files (Dummy)\n");
+        uart_print("  cat <file>  - Read file content\n");
         uart_print("  mem         - Show memory stats\n");
         uart_print("  panic       - Trigger kernel panic\n");
         uart_print("  reboot      - Restart system\n");
         uart_print("  sleep <num> - Sleep for N ticks\n");
-        uart_print("  ls          - List files\n");
-        uart_print("  cat <file>  - 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; i<n_root_nodes; i++) {
-                uart_print("  ");
-                uart_print(root_nodes[i].name);
-                uart_print("\n");
-            }
+            uart_print("Filesystem Mounted (InitRD).\n");
+            uart_print("Try: cat test.txt\n");
         }
     }
     else if (strncmp(cmd, "cat ", 4) == 0) {
@@ -50,28 +43,25 @@ void execute_command(char* cmd) {
             uart_print("No filesystem mounted.\n");
         } else {
             char* fname = cmd + 4;
-            // Trim spaces?
-            fs_node_t* file = NULL;
-            if (fs_root->finddir)
-                file = fs_root->finddir(fs_root, fname);
-            
+            fs_node_t* 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");
+                uart_print("Reading "); uart_print(fname); uart_print("...\n");
+                uint8_t* buf = (uint8_t*)kmalloc(file->length + 1);
+                if (buf) {
+                    uint32_t sz = vfs_read(file, 0, file->length, buf);
+                    buf[sz] = 0;
+                    uart_print((char*)buf);
+                    uart_print("\n");
+                    kfree(buf);
+                } else {
+                    uart_print("OOM: File too big for heap.\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");
     }
     else if (strncmp(cmd, "sleep ", 6) == 0) {
@@ -83,29 +73,16 @@ void execute_command(char* cmd) {
         uart_print("Woke up!\n");
     }
     else if (strcmp(cmd, "mem") == 0) {
-        // pmm_print_stats() is not impl yet, so let's fake it or add it
         uart_print("Memory Stats:\n");
         uart_print("  Total RAM: [TODO] MB\n");
-        uart_print("  Used:      [TODO] KB\n");
-        uart_print("  Free:      [TODO] KB\n");
     }
     else if (strcmp(cmd, "panic") == 0) {
-        // Trigger Int 0 (Div by zero)
-        int a = 1;
-        int b = 0;
-        int c = a / b;
-        (void)c;
+        int a = 1; int b = 0; int c = a / b; (void)c;
     }
     else if (strcmp(cmd, "reboot") == 0) {
-        // 8042 keyboard controller reset command
         uint8_t good = 0x02;
-        while (good & 0x02)
-            good = inb(0x64);
+        while (good & 0x02) good = inb(0x64);
         outb(0x64, 0xFE);
-        
-        // Triple Fault fallback
-        // idt_set_gate(0, 0, 0, 0);
-        // __asm__("int $0");
     }
     else if (strlen(cmd) > 0) {
         uart_print("Unknown command: ");
@@ -117,18 +94,17 @@ void execute_command(char* cmd) {
 }
 
 void shell_callback(char c) {
-    // Echo to screen
     char str[2] = { c, 0 };
     
     if (c == '\n') {
-        cmd_buffer[cmd_index] = 0; // Null terminate
+        cmd_buffer[cmd_index] = 0;
         execute_command(cmd_buffer);
         cmd_index = 0;
     }
     else if (c == '\b') {
         if (cmd_index > 0) {
             cmd_index--;
-            uart_print("\b \b"); // Backspace hack
+            uart_print("\b \b");
         }
     }
     else {
index 210681d59d163fe8fbb4c7bc8b021de8264abe24..a5b35ded92c8c966c3993946a11f85535c59ec01 100644 (file)
@@ -40,6 +40,15 @@ void* memcpy(void* dst, const void* src, size_t n) {
     return dst;
 }
 
+char* strcpy(char* dest, const char* src) {
+    char* saved = dest;
+    while (*src) {
+        *dest++ = *src++;
+    }
+    *dest = 0;
+    return saved;
+}
+
 void reverse(char* str, int length) {
     int start = 0;
     int end = length - 1;
index 5f09224b485d7b8e09c4a239e474cdc40b916719..98eb13f2dd5febae99e23073e2cf81b2c2c3bb17 100644 (file)
@@ -4,11 +4,7 @@
 #include <stdint.h>
 
 struct initrd_header {
-    uint32_t nfiles;
-};
-
-struct initrd_file_header {
-    uint8_t magic;
+    uint8_t magic; // Unused for now
     char name[64];
     uint32_t offset;
     uint32_t length;
@@ -16,69 +12,60 @@ struct initrd_file_header {
 
 int main(int argc, char **argv) {
     if (argc < 3) {
-        printf("Usage: %s <output.img> <file1> [file2] ...\n", argv[0]);
+        printf("Usage: %s <output> <file1> [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);
+    int nheader = argc - 2;
+    struct initrd_header headers[nheader];
     
-    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;
+    // Calculate offsets
+    // Data starts after: [4 bytes count] + [headers * n]
+    uint32_t data_offset = sizeof(uint32_t) + (sizeof(struct initrd_header) * nheader);
+    
+    printf("Creating InitRD with %d files...\n", nheader);
+    
+    // Prepare headers
+    for(int i = 0; i < nheader; i++) {
+        printf("Adding: %s\n", argv[i+2]);
+        strcpy(headers[i].name, argv[i+2]); // Warning: Buffer overflow unsafe, good enough for tool
+        headers[i].offset = data_offset;
+        headers[i].magic = 0xBF;
         
-        FILE* f = fopen(fname, "rb");
-        if (!f) {
-            perror("Error opening file");
+        FILE *stream = fopen(argv[i+2], "r");
+        if(!stream) {
+            printf("Error opening file: %s\n", argv[i+2]);
             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;
+        fseek(stream, 0, SEEK_END);
+        headers[i].length = ftell(stream);
+        data_offset += headers[i].length;
+        fclose(stream);
     }
-
-    FILE *w = fopen(argv[1], "wb");
-    if (!w) {
-        perror("Error opening output");
+    
+    FILE *wstream = fopen(argv[1], "w");
+    if(!wstream) {
+        printf("Error opening output: %s\n", argv[1]);
         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);
+    
+    // Write count
+    fwrite(&nheader, sizeof(uint32_t), 1, wstream);
+    // Write headers
+    fwrite(headers, sizeof(struct initrd_header), nheader, wstream);
+    
+    // Write data
+    for(int i = 0; i < nheader; i++) {
+        FILE *stream = fopen(argv[i+2], "r");
+        unsigned char *buf = (unsigned char *)malloc(headers[i].length);
+        fread(buf, 1, headers[i].length, stream);
+        fwrite(buf, 1, headers[i].length, wstream);
+        fclose(stream);
         free(buf);
-        fclose(f);
     }
-
-    fclose(w);
-    free(headers);
-    printf("Done! Wrote %s\n", argv[1]);
+    
+    fclose(wstream);
+    printf("Done. InitRD size: %d bytes.\n", data_offset);
     
     return 0;
 }