:: commit 81a134b59b8f6c3820860a8963d87bfba3bf78ff

mintsuki <mintsuki@protonmail.com> — 2021-01-27 15:16

parents: 5e344a54b5

linux: Misc protocol bug fixes

diff --git a/limine-pxe.bin b/limine-pxe.bin
index c241ce3b..ba65ccc0 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index 7ca62e94..03da12e3 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2.map b/stage2.map
index 7a9d6bb2..8e255800 100644
Binary files a/stage2.map and b/stage2.map differ
diff --git a/stage2/fs/file.c b/stage2/fs/file.c
index db1d9200..67069cd2 100644
--- a/stage2/fs/file.c
+++ b/stage2/fs/file.c
@@ -80,7 +80,7 @@ int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
 
 void *freadall(struct file_handle *fd, uint32_t type) {
     if (fd->is_memfile) {
-        memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false);
+        memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true);
         return fd->fd;
     } else {
         void *ret = ext_mem_alloc_aligned_type(fd->size, 4096, type);
diff --git a/stage2/lib/elf.c b/stage2/lib/elf.c
index 1c614521..f4c52b9c 100644
--- a/stage2/lib/elf.c
+++ b/stage2/lib/elf.c
@@ -309,7 +309,7 @@ int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uin
         if (this_top > *top)
             *top = this_top;
 
-        memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true);
+        memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, true);
 
         fread(fd, (void *)(uint32_t)load_vaddr, phdr.p_offset, phdr.p_filesz);
 
@@ -362,7 +362,7 @@ int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top, uin
         if (this_top > *top)
             *top = this_top;
 
-        memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true);
+        memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true);
 
         fread(fd, (void *)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
 
diff --git a/stage2/mm/pmm.c b/stage2/mm/pmm.c
index 14d86a80..0cbda451 100644
--- a/stage2/mm/pmm.c
+++ b/stage2/mm/pmm.c
@@ -237,7 +237,7 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
 
         // We now reserve the range we need.
         int64_t aligned_length = entry_top - alloc_base;
-        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true);
+        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true);
 
         void *ret = (void *)(size_t)alloc_base;
 
@@ -252,13 +252,17 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
     panic("High memory allocator: Out of memory");
 }
 
-void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only) {
+bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic) {
     uint64_t top = base + length;
 
     if (base < 0x100000) {
-        // We don't do allocations below 1 MiB
-        panic("Attempt to allocate memory below 1 MiB (%X-%X)",
-              base, base + length);
+        if (do_panic) {
+            // We don't do allocations below 1 MiB
+            panic("Attempt to allocate memory below 1 MiB (%X-%X)",
+                  base, base + length);
+        } else {
+            return false;
+        }
     }
 
     for (size_t i = 0; i < memmap_entries; i++) {
@@ -303,11 +307,14 @@ void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
             target->base   = base;
             target->length = length;
 
-            return;
+            return true;
         }
     }
 
-    panic("Out of memory");
+    if (do_panic)
+        panic("Out of memory");
+
+    return false;
 }
 
 extern symbol bss_end;
diff --git a/stage2/mm/pmm.h b/stage2/mm/pmm.h
index a843f599..b5173f63 100644
--- a/stage2/mm/pmm.h
+++ b/stage2/mm/pmm.h
@@ -20,7 +20,7 @@ extern size_t memmap_entries;
 void init_memmap(void);
 struct e820_entry_t *get_memmap(size_t *entries);
 void print_memmap(struct e820_entry_t *mm, size_t size);
-void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only);
+bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool panic);
 
 void *ext_mem_alloc(size_t count);
 void *ext_mem_alloc_type(size_t count, uint32_t type);
diff --git a/stage2/protos/linux.c b/stage2/protos/linux.c
index 32303302..798f0503 100644
--- a/stage2/protos/linux.c
+++ b/stage2/protos/linux.c
@@ -13,10 +13,11 @@
 #include <mm/mtrr.h>
 
 #define KERNEL_LOAD_ADDR ((size_t)0x100000)
-#define INITRD_LOAD_ADDR ((size_t)0x1000000)
+#define KERNEL_HEAP_SIZE ((size_t)0x1000)
 
 __attribute__((section(".realmode"), used))
-static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
+static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg,
+                   uint16_t stack_pointer) {
     asm volatile (
         "cld\n\t"
 
@@ -38,30 +39,22 @@ static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
         "mov fs, bx\n\t"
         "mov gs, bx\n\t"
         "mov ss, bx\n\t"
-        "mov esp, 0xfdf0\n\t"
-
-        "sti\n\t"
+        "mov esp, edx\n\t"
 
         "push cx\n\t"
         "push 0\n\t"
+
         "retf\n\t"
 
         ".code32\n\t"
         :
-        : "b" (real_mode_code_seg), "c" (kernel_entry_seg)
+        : "b" (real_mode_code_seg), "c" (kernel_entry_seg),
+          "d" (stack_pointer)
         : "memory"
     );
 }
 
 void linux_load(char *config, char *cmdline) {
-    // The command line needs to be before address 0xa0000, we can use
-    // a conv_mem_alloc() allocated buffer for that.
-    // Allocate the relocation buffer for the command line early so it's allocated
-    // before the real mode code.
-    size_t cmdline_len = strlen(cmdline);
-    char *cmdline_reloc = conv_mem_alloc(cmdline_len + 1);
-    strcpy(cmdline_reloc, cmdline);
-
     struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
@@ -93,15 +86,12 @@ void linux_load(char *config, char *cmdline) {
 
     print("linux: Real Mode code size: %x\n", real_mode_code_size);
 
-    void *real_mode_code = conv_mem_alloc_aligned(real_mode_code_size, 0x1000);
+    size_t real_mode_and_heap_size =
+        ((real_mode_code_size & 0x0f) + 0x10) + KERNEL_HEAP_SIZE;
 
-    fread(kernel, real_mode_code, 0, real_mode_code_size);
-
-    size_t heap_end_ptr = ((real_mode_code_size & 0x0f) + 0x10) - 0x200;
-    *((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
+    void *real_mode_code = conv_mem_alloc_aligned(real_mode_and_heap_size, 0x1000);
 
-    // vid_mode. 0xffff means "normal"
-    *((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
+    fread(kernel, real_mode_code, 0, real_mode_code_size);
 
     uint16_t boot_protocol_ver;
     boot_protocol_ver = *((uint16_t *)(real_mode_code + 0x206));
@@ -109,6 +99,24 @@ void linux_load(char *config, char *cmdline) {
     print("linux: Boot protocol: %u.%u\n",
           boot_protocol_ver >> 8, boot_protocol_ver & 0xff);
 
+    if (boot_protocol_ver < 0x203) {
+        panic("Linux protocols < 2.03 are not supported");
+    }
+
+    size_t heap_end_ptr = real_mode_and_heap_size - 0x200;
+    *((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
+
+    // The command line needs to be before address 0xa0000, we can use
+    // a conv_mem_alloc() allocated buffer for that.
+    // Allocate the relocation buffer for the command line early so it's allocated
+    // before the real mode code.
+    size_t cmdline_len = strlen(cmdline);
+    char *cmdline_reloc = conv_mem_alloc(cmdline_len + 1);
+    strcpy(cmdline_reloc, cmdline);
+
+    // vid_mode. 0xffff means "normal"
+    *((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
+
     char *kernel_version;
     kernel_version = real_mode_code + *((uint16_t *)(real_mode_code + 0x20e)) + 0x200;
 
@@ -122,7 +130,10 @@ void linux_load(char *config, char *cmdline) {
     uint8_t loadflags;
     loadflags = *((uint8_t *)(real_mode_code + 0x211));
 
-    loadflags |=  (1 << 0);     // kernel is loaded at 0x100000
+    if (!(loadflags & (1 << 0))) {
+        panic("Linux kernels that load at 0x10000 are not supported");
+    }
+
     loadflags &= ~(1 << 5);     // print early messages
     loadflags |=  (1 << 7);     // can use heap
 
@@ -132,10 +143,34 @@ void linux_load(char *config, char *cmdline) {
 
     // load kernel
     print("Loading kernel...\n");
-    memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true);
+    memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true, true);
     fread(kernel, (void *)KERNEL_LOAD_ADDR, real_mode_code_size, kernel->size - real_mode_code_size);
 
-    size_t modules_mem_base = INITRD_LOAD_ADDR;
+    uint32_t modules_mem_base = *((uint32_t *)(real_mode_code + 0x22c)) + 1;
+    size_t size_of_all_modules = 0;
+
+    for (size_t i = 0; ; i++) {
+        char *module_path = config_get_value(config, i, "MODULE_PATH");
+        if (module_path == NULL)
+            break;
+
+        struct file_handle module;
+        if (!uri_open(&module, module_path))
+            panic("Could not open `%s`", module_path);
+
+        size_of_all_modules += module.size;
+    }
+
+    modules_mem_base -= size_of_all_modules;
+    modules_mem_base = ALIGN_DOWN(modules_mem_base, 4096);
+
+    for (;;) {
+        if (memmap_alloc_range(modules_mem_base, size_of_all_modules, 0, true, false))
+            break;
+        modules_mem_base -= 4096;
+    }
+
+    size_t _modules_mem_base = modules_mem_base;
     for (size_t i = 0; ; i++) {
         char *module_path = config_get_value(config, i, "MODULE_PATH");
         if (module_path == NULL)
@@ -147,15 +182,14 @@ void linux_load(char *config, char *cmdline) {
 
         print("Loading module `%s`...\n", module_path);
 
-        memmap_alloc_range(modules_mem_base, module.size, 0, true);
-        fread(&module, (void *)modules_mem_base, 0, module.size);
+        fread(&module, (void *)_modules_mem_base, 0, module.size);
 
-        modules_mem_base += module.size;
+        _modules_mem_base += module.size;
     }
 
-    if (modules_mem_base != INITRD_LOAD_ADDR) {
-        *((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)INITRD_LOAD_ADDR;
-        *((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)(modules_mem_base - INITRD_LOAD_ADDR);
+    if (size_of_all_modules != 0) {
+        *((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)modules_mem_base;
+        *((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)size_of_all_modules;
     }
 
     uint16_t real_mode_code_seg = rm_seg(real_mode_code);
@@ -165,5 +199,5 @@ void linux_load(char *config, char *cmdline) {
 
     mtrr_restore();
 
-    spinup(real_mode_code_seg, kernel_entry_seg);
+    spinup(real_mode_code_seg, kernel_entry_seg, real_mode_and_heap_size);
 }
tab: 248 wrap: offon