:: commit 85709a0fbea57a0ab79c78d4ff5af39a1bbd6d7f

mintsuki <mintsuki@protonmail.com> — 2020-03-25 03:38

parents: d95a8403cc

elf: Add support for higher half kernels

diff --git a/src/bootsect/gdt.inc b/src/bootsect/gdt.inc
index 15045d27..d4d6b6a4 100644
--- a/src/bootsect/gdt.inc
+++ b/src/bootsect/gdt.inc
@@ -56,4 +56,20 @@ db 10010010b		; Access
 db 11001111b		; Granularity
 db 0x00				; Base (high 8 bits)
 
+; 64 bit code
+dw 0x0000           ; Limit
+dw 0x0000           ; Base (low 16 bits)
+db 0x00             ; Base (mid 8 bits)
+db 10011010b        ; Access
+db 00100000b        ; Granularity
+db 0x00             ; Base (high 8 bits)
+
+; 64 bit data
+dw 0x0000           ; Limit
+dw 0x0000           ; Base (low 16 bits)
+db 0x00             ; Base (mid 8 bits)
+db 10010010b        ; Access
+db 00000000b        ; Granularity
+db 0x00             ; Base (high 8 bits)
+
 .GDTEnd:
diff --git a/src/lib/elf.c b/src/lib/elf.c
index dcfb7974..1cbcbb5c 100644
--- a/src/lib/elf.c
+++ b/src/lib/elf.c
@@ -1,5 +1,6 @@
 #include <stdint.h>
 #include <stddef.h>
+#include <stdbool.h>
 #include <lib/blib.h>
 #include <lib/libc.h>
 #include <lib/elf.h>
@@ -46,9 +47,11 @@ struct elf_phdr {
     uint64_t p_align;
 };
 
-int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count);
+#define FIXED_HIGHER_HALF_OFFSET ((uint64_t)0xffffffff80000000)
 
 int elf_load(struct echfs_file_handle *fd) {
+    bool elf_higher_half = false;
+
     struct elf_hdr hdr;
     echfs_read(fd, &hdr, 0, sizeof(struct elf_hdr));
 
@@ -75,6 +78,12 @@ int elf_load(struct echfs_file_handle *fd) {
         if (phdr.p_type != PT_LOAD)
             continue;
 
+        if (phdr.p_vaddr & (1ull << 63)) {
+            print("elf: This is a higher half kernel!\n");
+            elf_higher_half = true;
+            phdr.p_vaddr -= FIXED_HIGHER_HALF_OFFSET;
+        }
+
         echfs_read(fd, (void *)(uint32_t)phdr.p_vaddr,
                    phdr.p_offset, phdr.p_filesz);
 
@@ -86,10 +95,63 @@ int elf_load(struct echfs_file_handle *fd) {
         }
     }
 
+    volatile struct {
+        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];
+    } *pagemap = (void *)0x10000;
+
+    // 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[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 * 0x1000) | 0x03 | (1 << 7);
+
+    uint32_t entry_point = elf_higher_half
+                             ? (uint32_t)(hdr.entry - FIXED_HIGHER_HALF_OFFSET)
+                             : (uint32_t)hdr.entry;
+
     asm volatile (
-        "jmp %0\n\t"
+        "cli\n\t"
+        "mov cr3, eax\n\t"
+        "mov eax, cr4\n\t"
+        "or eax, 1 << 5 | 1 << 7\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"
+        "jmp rbx\n\t"
+        ".code32\n\t"
         :
-        : "r" ((uint32_t)hdr.entry)
-        : "memory"
+        : "a" (pagemap), "b" (entry_point)
     );
+
+    for (;;);
 }
diff --git a/test/linker.ld b/test/linker.ld
index 92cdcf66..a1f8fbd3 100644
--- a/test/linker.ld
+++ b/test/linker.ld
@@ -1,7 +1,7 @@
 ENTRY(_start)
 
 SECTIONS {
-    . = 0x100000;
+    . = 0xffffffff80100000;
 
     .text : {
         *(.text*)
diff --git a/test/test.asm b/test/test.asm
index f378f478..68ce5412 100644
--- a/test/test.asm
+++ b/test/test.asm
@@ -6,9 +6,8 @@
 section .text
 
 ; Entry point
-bits 32
 
 global _start
 _start:
-    mov eax, 0xdeadbeef
+    mov rax, 0xcafebabedeadbeef
     jmp $
tab: 248 wrap: offon