]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
Feat: Add VFS, InitRD Driver and mkinitrd tool
authortadryanom_bot <[email protected]>
Tue, 3 Feb 2026 15:29:55 +0000 (15:29 +0000)
committertadryanom_bot <[email protected]>
Tue, 3 Feb 2026 15:29:55 +0000 (15:29 +0000)
BUILD_GUIDE.md
include/fs.h [new file with mode: 0644]
include/initrd.h [new file with mode: 0644]
include/multiboot2.h
include/utils.h
src/drivers/initrd.c [new file with mode: 0644]
src/kernel/fs.c [new file with mode: 0644]
src/kernel/main.c
src/kernel/shell.c
src/kernel/utils.c
tools/mkinitrd.c [new file with mode: 0644]

index 8b069ca3508975e4920517f369c444d05d0265c5..0208288cbaa64672b377790be96b50e3ea473555 100644 (file)
@@ -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 (file)
index 0000000..e1fd4f6
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef FS_H
+#define FS_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#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 (file)
index 0000000..1e8c1e2
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef INITRD_H
+#define INITRD_H
+
+#include "fs.h"
+#include <stdint.h>
+
+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
index 57148f5fddc626e081ce9f260ce91f475a76c783..f7e1f9b81e6f1176baa6603903144bcdc314c853 100644 (file)
@@ -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;
index 638a62de501966244bdc20e3ef57f5a751bb1f47..042bb59e41b50c4789b9ea423031e2e633649de0 100644 (file)
@@ -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 (file)
index 0000000..34df213
--- /dev/null
@@ -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 (file)
index 0000000..e90bf82
--- /dev/null
@@ -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);
+}
index 78e5960ed65f3d53ab39a537cc832ec6c06a4124..2669cf5522f6d60afca93990a3f754fb9e12e331 100644 (file)
@@ -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
index c1b310d3265e3b703df89692302b9e21a61ef6aa..743a125ce335d573b1b414e0deba97a6c6338de3 100644 (file)
@@ -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 <num> - Sleep for N ticks (50Hz)\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");
+            }
+        }
+    }
+    else if (strncmp(cmd, "cat ", 4) == 0) {
+        if (!fs_root) {
+            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);
+            
+            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");
index cbf3370115ae93c688f5fe6e7e7675c92e67727f..210681d59d163fe8fbb4c7bc8b021de8264abe24 100644 (file)
@@ -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 (file)
index 0000000..5f09224
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+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 <output.img> <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);
+    
+    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;
+}