:: commit 5f859ea7d13a60eeb18f8b4a955e4d11eef4e0d5

mintsuki <mintsuki@protonmail.com> — 2020-04-18 16:01

parents: 7ae6781282

Add 32 bit stivale support

diff --git a/src/lib/elf.c b/src/lib/elf.c
index dd67078c..f0ff11db 100644
--- a/src/lib/elf.c
+++ b/src/lib/elf.c
@@ -9,9 +9,10 @@
 #define PT_INTERP   0x00000003
 #define PT_PHDR     0x00000006
 
-#define ABI_SYSV 0x00
+#define ABI_SYSV    0x00
 #define ARCH_X86_64 0x3e
-#define BITS_LE 0x01
+#define ARCH_X86_32 0x03
+#define BITS_LE     0x01
 
 /* Indices into identification array */
 #define EI_CLASS    4
@@ -19,8 +20,8 @@
 #define EI_VERSION  6
 #define EI_OSABI    7
 
-struct elf_hdr {
-    uint8_t ident[16];
+struct elf64_hdr {
+    uint8_t  ident[16];
     uint16_t type;
     uint16_t machine;
     uint32_t version;
@@ -36,7 +37,24 @@ struct elf_hdr {
     uint16_t shstrndx;
 };
 
-struct elf_phdr {
+struct elf32_hdr {
+    uint8_t  ident[16];
+    uint16_t type;
+    uint16_t machine;
+    uint32_t version;
+    uint32_t entry;
+    uint32_t phoff;
+    uint32_t shoff;
+    uint32_t flags;
+    uint16_t hdr_size;
+    uint16_t phdr_size;
+    uint16_t ph_num;
+    uint16_t shdr_size;
+    uint16_t sh_num;
+    uint16_t shstrndx;
+};
+
+struct elf64_phdr {
     uint32_t p_type;
     uint32_t p_flags;
     uint64_t p_offset;
@@ -47,22 +65,65 @@ struct elf_phdr {
     uint64_t p_align;
 };
 
-struct elf_shdr {
-    uint32_t   sh_name;
-    uint32_t   sh_type;
-    uint64_t   sh_flags;
-    uint64_t   sh_addr;
-    uint64_t   sh_offset;
-    uint64_t   sh_size;
-    uint32_t   sh_link;
-    uint32_t   sh_info;
-    uint64_t   sh_addralign;
-    uint64_t   sh_entsize;
+struct elf32_phdr {
+    uint32_t p_type;
+    uint32_t p_offset;
+    uint32_t p_vaddr;
+    uint32_t p_paddr;
+    uint32_t p_filesz;
+    uint32_t p_memsz;
+    uint32_t p_flags;
+    uint32_t p_align;
+};
+
+struct elf64_shdr {
+    uint32_t sh_name;
+    uint32_t sh_type;
+    uint64_t sh_flags;
+    uint64_t sh_addr;
+    uint64_t sh_offset;
+    uint64_t sh_size;
+    uint32_t sh_link;
+    uint32_t sh_info;
+    uint64_t sh_addralign;
+    uint64_t sh_entsize;
+};
+
+struct elf32_shdr {
+    uint32_t sh_name;
+    uint32_t sh_type;
+    uint32_t sh_flags;
+    uint32_t sh_addr;
+    uint32_t sh_offset;
+    uint32_t sh_size;
+    uint32_t sh_link;
+    uint32_t sh_info;
+    uint32_t sh_addralign;
+    uint32_t sh_entsize;
 };
 
-int elf_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
-    struct elf_hdr hdr;
-    fread(fd, &hdr, 0, sizeof(struct elf_hdr));
+int elf_bits(struct file_handle *fd) {
+    struct elf64_hdr hdr;
+    fread(fd, &hdr, 0, 20);
+
+    if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
+        print("elf: Not a valid ELF file.\n");
+        return -1;
+    }
+
+    switch (hdr.machine) {
+        case ARCH_X86_64:
+            return 64;
+        case ARCH_X86_32:
+            return 32;
+        default:
+            return -1;
+    }
+}
+
+int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
+    struct elf64_hdr hdr;
+    fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
 
     if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
         print("elf: Not a valid ELF file.\n");
@@ -79,17 +140,17 @@ int elf_load_section(struct file_handle *fd, void *buffer, const char *name, siz
         return 1;
     }
 
-    struct elf_shdr shstrtab;
-    fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf_shdr),
-            sizeof(struct elf_shdr));
+    struct elf64_shdr shstrtab;
+    fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf64_shdr),
+            sizeof(struct elf64_shdr));
 
     char names[shstrtab.sh_size];
     fread(fd, names, shstrtab.sh_offset, shstrtab.sh_size);
 
     for (uint16_t i = 0; i < hdr.sh_num; i++) {
-        struct elf_shdr section;
-        fread(fd, &section, hdr.shoff + i * sizeof(struct elf_shdr),
-                   sizeof(struct elf_shdr));
+        struct elf64_shdr section;
+        fread(fd, &section, hdr.shoff + i * sizeof(struct elf64_shdr),
+                   sizeof(struct elf64_shdr));
 
         if (!strcmp(&names[section.sh_name], name)) {
             if (section.sh_size > limit)
@@ -102,11 +163,53 @@ int elf_load_section(struct file_handle *fd, void *buffer, const char *name, siz
     return 2;
 }
 
-#define FIXED_HIGHER_HALF_OFFSET ((uint64_t)0xffffffff80000000)
+int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
+    struct elf32_hdr hdr;
+    fread(fd, &hdr, 0, sizeof(struct elf32_hdr));
+
+    if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
+        print("elf: Not a valid ELF file.\n");
+        return 1;
+    }
+
+    if (hdr.ident[EI_DATA] != BITS_LE) {
+        print("elf: Not a Little-endian ELF file.\n");
+        return 1;
+    }
+
+    if (hdr.machine != ARCH_X86_32) {
+        print("elf: Not an x86_32 ELF file.\n");
+        return 1;
+    }
+
+    struct elf32_shdr shstrtab;
+    fread(fd, &shstrtab, hdr.shoff + hdr.shstrndx * sizeof(struct elf32_shdr),
+            sizeof(struct elf32_shdr));
+
+    char names[shstrtab.sh_size];
+    fread(fd, names, shstrtab.sh_offset, shstrtab.sh_size);
 
-int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
-    struct elf_hdr hdr;
-    fread(fd, &hdr, 0, sizeof(struct elf_hdr));
+    for (uint16_t i = 0; i < hdr.sh_num; i++) {
+        struct elf32_shdr section;
+        fread(fd, &section, hdr.shoff + i * sizeof(struct elf32_shdr),
+                   sizeof(struct elf32_shdr));
+
+        if (!strcmp(&names[section.sh_name], name)) {
+            if (section.sh_size > limit)
+                return 3;
+            fread(fd, buffer, section.sh_offset, section.sh_size);
+            return 0;
+        }
+    }
+
+    return 2;
+}
+
+#define FIXED_HIGHER_HALF_OFFSET_64 ((uint64_t)0xffffffff80000000)
+
+int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
+    struct elf64_hdr hdr;
+    fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
 
     if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
         print("Not a valid ELF file.\n");
@@ -126,15 +229,15 @@ int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
     *top = 0;
 
     for (uint16_t i = 0; i < hdr.ph_num; i++) {
-        struct elf_phdr phdr;
-        fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf_phdr),
-                   sizeof(struct elf_phdr));
+        struct elf64_phdr phdr;
+        fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf64_phdr),
+                   sizeof(struct elf64_phdr));
 
         if (phdr.p_type != PT_LOAD)
             continue;
 
-        if (phdr.p_vaddr & (1ull << 63))
-            phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET;
+        if (phdr.p_vaddr & ((uint64_t)1 << 63))
+            phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET_64;
 
         uint64_t this_top = phdr.p_vaddr + phdr.p_memsz;
         if (this_top > *top)
@@ -155,3 +258,51 @@ int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top) {
 
     return 0;
 }
+
+int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top) {
+    struct elf32_hdr hdr;
+    fread(fd, &hdr, 0, sizeof(struct elf32_hdr));
+
+    if (strncmp((char *)hdr.ident, "\177ELF", 4)) {
+        print("Not a valid ELF file.\n");
+        return -1;
+    }
+
+    if (hdr.ident[EI_DATA] != BITS_LE) {
+        print("Not a Little-endian ELF file.\n");
+        return -1;
+    }
+
+    if (hdr.machine != ARCH_X86_32) {
+        print("Not an x86_32 ELF file.\n");
+        return -1;
+    }
+
+    *top = 0;
+
+    for (uint16_t i = 0; i < hdr.ph_num; i++) {
+        struct elf32_phdr phdr;
+        fread(fd, &phdr, hdr.phoff + i * sizeof(struct elf32_phdr),
+                   sizeof(struct elf32_phdr));
+
+        if (phdr.p_type != PT_LOAD)
+            continue;
+
+        uint32_t this_top = phdr.p_vaddr + phdr.p_memsz;
+        if (this_top > *top)
+            *top = this_top;
+
+        fread(fd, (void *)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
+
+        size_t to_zero = (size_t)(phdr.p_memsz - phdr.p_filesz);
+
+        if (to_zero) {
+            void *ptr = (void *)(phdr.p_vaddr + phdr.p_filesz);
+            memset(ptr, 0, to_zero);
+        }
+    }
+
+    *entry_point = hdr.entry;
+
+    return 0;
+}
diff --git a/src/lib/elf.h b/src/lib/elf.h
index 85b57845..0d8d4bc6 100644
--- a/src/lib/elf.h
+++ b/src/lib/elf.h
@@ -4,7 +4,12 @@
 #include <stdint.h>
 #include <fs/file.h>
 
-int elf_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top);
-int elf_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
+int elf_bits(struct file_handle *fd);
+
+int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top);
+int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
+
+int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top);
+int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit);
 
 #endif
diff --git a/src/protos/stivale.c b/src/protos/stivale.c
index 30366562..188e66f2 100644
--- a/src/protos/stivale.c
+++ b/src/protos/stivale.c
@@ -11,7 +11,9 @@
 
 struct stivale_header {
     uint64_t stack;
-    uint16_t video_mode;  // 0 = default at boot (CGA text mode). 1 = graphical VESA
+    // Flags
+    // bit 0   0 = text mode,   1 = graphics mode
+    uint16_t flags;
     uint16_t framebuffer_width;
     uint16_t framebuffer_height;
     uint16_t framebuffer_bpp;
@@ -41,29 +43,44 @@ struct stivale_struct {
 struct stivale_struct stivale_struct = {0};
 
 void stivale_load(struct file_handle *fd, char *cmdline) {
-    uint64_t entry_point;
-
     struct stivale_header stivale_hdr;
-    int ret = elf_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+
+    int bits = elf_bits(fd);
+
+    int ret;
+
+    print("stivale: %u-bit ELF file detected\n", bits);
+
+    switch (bits) {
+        case 64:
+            ret = elf64_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+            break;
+        case 32:
+            ret = elf32_load_section(fd, &stivale_hdr, ".stivalehdr", sizeof(struct stivale_header));
+            break;
+    }
+
     switch (ret) {
         case 1:
-            print("stivale: File is not a valid ELF.\n");
-            for (;;);
+            panic("stivale: File is not a valid ELF.\n");
         case 2:
-            print("stivale: Section .stivalehdr not found.\n");
-            for (;;);
+            panic("stivale: Section .stivalehdr not found.\n");
         case 3:
-            print("stivale: Section .stivalehdr exceeds the size of the struct.\n");
-            for (;;);
-        default:
-            break;
+            panic("stivale: Section .stivalehdr exceeds the size of the struct.\n");
     }
 
     print("stivale: Requested stack at %X\n", stivale_hdr.stack);
-    print("stivale: Video mode: %u\n", stivale_hdr.video_mode);
 
-    uint64_t top_used_addr;
-    elf_load(fd, &entry_point, &top_used_addr);
+    uint64_t entry_point   = 0;
+    uint64_t top_used_addr = 0;
+    switch (bits) {
+        case 64:
+            elf64_load(fd, &entry_point, &top_used_addr);
+            break;
+        case 32:
+            elf32_load(fd, (uint32_t *)&entry_point, (uint32_t *)&top_used_addr);
+            break;
+    }
 
     print("stivale: Top used address in ELF: %X\n", top_used_addr);
 
@@ -115,7 +132,6 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
     }
 
     stivale_struct.rsdp = (uint64_t)(size_t)get_rsdp();
-    print("stivale: RSDP at %X\n", stivale_struct.rsdp);
 
     stivale_struct.cmdline = (uint64_t)(size_t)cmdline;
 
@@ -123,7 +139,7 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
     stivale_struct.framebuffer_height = stivale_hdr.framebuffer_height;
     stivale_struct.framebuffer_bpp    = stivale_hdr.framebuffer_bpp;
 
-    if (stivale_hdr.video_mode == 1) {
+    if ((stivale_hdr.flags & 1) == 1) {
         init_vbe(&stivale_struct.framebuffer_addr,
                  &stivale_struct.framebuffer_pitch,
                  &stivale_struct.framebuffer_width,
@@ -131,61 +147,74 @@ void stivale_load(struct file_handle *fd, char *cmdline) {
                  &stivale_struct.framebuffer_bpp);
     }
 
-    struct pagemap {
-        uint64_t pml4[512];
-        uint64_t pml3_lo[512];
-        uint64_t pml3_hi[512];
-        uint64_t pml2_0gb[512];
-        uint64_t pml2_1gb[512];
-        uint64_t pml2_2gb[512];
-        uint64_t pml2_3gb[512];
-    };
-    struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
-
-    // first, zero out the pagemap
-    for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
-        *p = 0;
-
-    pagemap->pml4[511]    = (uint64_t)(size_t)pagemap->pml3_hi  | 0x03;
-    pagemap->pml4[256]    = (uint64_t)(size_t)pagemap->pml3_lo  | 0x03;
-    pagemap->pml4[0]      = (uint64_t)(size_t)pagemap->pml3_lo  | 0x03;
-    pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
-    pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
-    pagemap->pml3_lo[0]   = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
-    pagemap->pml3_lo[1]   = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
-    pagemap->pml3_lo[2]   = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
-    pagemap->pml3_lo[3]   = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
-
-    // populate the page directories
-    for (size_t i = 0; i < 512 * 4; i++)
-        (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
-
-    asm volatile (
-        "cli\n\t"
-        "mov cr3, eax\n\t"
-        "mov eax, cr4\n\t"
-        "or eax, 1 << 5\n\t"
-        "mov cr4, eax\n\t"
-        "mov ecx, 0xc0000080\n\t"
-        "rdmsr\n\t"
-        "or eax, 1 << 8\n\t"
-        "wrmsr\n\t"
-        "mov eax, cr0\n\t"
-        "or eax, 1 << 31\n\t"
-        "mov cr0, eax\n\t"
-        "jmp 0x28:1f\n\t"
-        "1: .code64\n\t"
-        "mov ax, 0x30\n\t"
-        "mov ds, ax\n\t"
-        "mov es, ax\n\t"
-        "mov fs, ax\n\t"
-        "mov gs, ax\n\t"
-        "mov ss, ax\n\t"
-        "mov rsp, [rsi]\n\t"
-        "jmp [rbx]\n\t"
-        ".code32\n\t"
-        :
-        : "a" (pagemap), "b" (&entry_point),
-          "D" (&stivale_struct), "S" (&stivale_hdr.stack)
-    );
+    if (bits == 64) {
+        struct pagemap {
+            uint64_t pml4[512];
+            uint64_t pml3_lo[512];
+            uint64_t pml3_hi[512];
+            uint64_t pml2_0gb[512];
+            uint64_t pml2_1gb[512];
+            uint64_t pml2_2gb[512];
+            uint64_t pml2_3gb[512];
+        };
+        struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
+
+        // first, zero out the pagemap
+        for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
+            *p = 0;
+
+        pagemap->pml4[511]    = (uint64_t)(size_t)pagemap->pml3_hi  | 0x03;
+        pagemap->pml4[256]    = (uint64_t)(size_t)pagemap->pml3_lo  | 0x03;
+        pagemap->pml4[0]      = (uint64_t)(size_t)pagemap->pml3_lo  | 0x03;
+        pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
+        pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
+        pagemap->pml3_lo[0]   = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
+        pagemap->pml3_lo[1]   = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
+        pagemap->pml3_lo[2]   = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
+        pagemap->pml3_lo[3]   = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
+
+        // populate the page directories
+        for (size_t i = 0; i < 512 * 4; i++)
+            (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
+
+        asm volatile (
+            "cli\n\t"
+            "cld\n\t"
+            "mov cr3, eax\n\t"
+            "mov eax, cr4\n\t"
+            "or eax, 1 << 5\n\t"
+            "mov cr4, eax\n\t"
+            "mov ecx, 0xc0000080\n\t"
+            "rdmsr\n\t"
+            "or eax, 1 << 8\n\t"
+            "wrmsr\n\t"
+            "mov eax, cr0\n\t"
+            "or eax, 1 << 31\n\t"
+            "mov cr0, eax\n\t"
+            "jmp 0x28:1f\n\t"
+            "1: .code64\n\t"
+            "mov ax, 0x30\n\t"
+            "mov ds, ax\n\t"
+            "mov es, ax\n\t"
+            "mov fs, ax\n\t"
+            "mov gs, ax\n\t"
+            "mov ss, ax\n\t"
+            "mov rsp, [rsi]\n\t"
+            "call [rbx]\n\t"
+            ".code32\n\t"
+            :
+            : "a" (pagemap), "b" (&entry_point),
+              "D" (&stivale_struct), "S" (&stivale_hdr.stack)
+        );
+    } else if (bits == 32) {
+        asm volatile (
+            "cli\n\t"
+            "cld\n\t"
+            "mov esp, [esi]\n\t"
+            "push edi\n\t"
+            "call [ebx]\n\t"
+            :
+            : "b" (&entry_point), "D" (&stivale_struct), "S" (&stivale_hdr.stack)
+        );
+    }
 }
diff --git a/test/qloader2.cfg b/test/qloader2.cfg
index 9afddf1b..d5799bcd 100644
--- a/test/qloader2.cfg
+++ b/test/qloader2.cfg
@@ -1,14 +1,14 @@
 TIMEOUT=3
 
-KERNEL_PARTITION=0
+KERNEL_PARTITION=1
 KERNEL_PATH=test.elf
 KERNEL_PROTO=stivale
 KERNEL_CMDLINE=none
 
-MODULE_PARTITION=0
+MODULE_PARTITION=1
 MODULE_PATH=qloader2.cfg
 MODULE_STRING=something here
 
-MODULE_PARTITION=0
+MODULE_PARTITION=1
 MODULE_PATH=qloader2.cfg
 MODULE_STRING=second module
tab: 248 wrap: offon