:: commit 5d3f8b4eb00f9e742c93588b8f5921838749f16f

mintsuki <mintsuki@protonmail.com> — 2021-03-06 23:52

parents: 6c22743c7e

Implement do_32() and make stivale kernels work with UEFI

diff --git a/stage23/Makefile b/stage23/Makefile
index d76b9590..3584646f 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -8,6 +8,8 @@ else
 	$(error Invalid target)
 endif
 
+CC32 = i386-elf-gcc
+
 CC = $(TOOLCHAIN)-gcc
 LD = $(TOOLCHAIN)-ld
 OBJCOPY = $(TOOLCHAIN)-objcopy
@@ -76,6 +78,9 @@ C_FILES := $(shell find -L ./ -type f -name '*.c' | sort)
 ifeq ($(TARGET), bios)
 ASM_FILES := $(shell find -L ./ -type f -name '*.asm' | sort)
 endif
+ifeq ($(TARGET), uefi)
+ASM_FILES := lib/do_32.asm
+endif
 OBJ := $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o)
 HEADER_DEPS := $(C_FILES:.c=.d)
 
@@ -139,8 +144,21 @@ ifeq ($(TARGET), bios)
 	$(CC) $(S2CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
 endif
 
+ifeq ($(TARGET), uefi)
+%.32.o: %.32.c
+	$(CC32) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@.32
+	$(OBJCOPY) -I elf32-i386 -O elf64-x86-64 $@.32 $@
+	rm $@.32
+endif
+
+ifeq ($(TARGET), bios)
 %.o: %.asm
 	nasm $< -F dwarf -g -f elf32 -o $@
+endif
+ifeq ($(TARGET), uefi)
+%.o: %.asm
+	nasm $< -F dwarf -g -f elf64 -o $@
+endif
 
 clean:
 	rm -f limine.elf limine_efi.elf limine_dbg.elf limine_nomap.elf limine_stage2only.elf font.o limine.map.o limine.sys stage2.bin stage2.bin.gz BOOTX64.EFI sys/smp_trampoline.bin sys/smp_trampoline.o $(OBJ) $(HEADER_DEPS)
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index bb5f05c3..8930575f 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -71,6 +71,8 @@ uint64_t sqrt(uint64_t a_nInput) {
 bool efi_boot_services_exited = false;
 
 bool efi_exit_boot_services(void) {
+    EFI_STATUS status;
+
     EFI_MEMORY_DESCRIPTOR tmp_mmap[1];
     UINTN mmap_size = sizeof(tmp_mmap);
     UINTN mmap_key = 0, desc_size = 0, desc_ver = 0;
@@ -78,7 +80,12 @@ bool efi_exit_boot_services(void) {
     uefi_call_wrapper(gBS->GetMemoryMap, 5,
         &mmap_size, tmp_mmap, &mmap_key, &desc_size, &desc_ver);
 
-    uefi_call_wrapper(gBS->ExitBootServices, 2, efi_image_handle, mmap_key);
+    status = uefi_call_wrapper(gBS->ExitBootServices, 2, efi_image_handle, mmap_key);
+
+    if (status)
+        panic("efi: Failed to exit boot services\n");
+
+    asm volatile ("cli" ::: "memory");
 
     efi_boot_services_exited = true;
 
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index 2fdd4e48..bebffe66 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -66,4 +66,8 @@ enum {
 	BOOT_FROM_CD
 };
 
+#if defined (uefi)
+__attribute__((noreturn)) void do_32(void *fnptr, int args, ...);
+#endif
+
 #endif
diff --git a/stage23/lib/do_32.asm b/stage23/lib/do_32.asm
new file mode 100644
index 00000000..312cbabf
--- /dev/null
+++ b/stage23/lib/do_32.asm
@@ -0,0 +1,64 @@
+section .rodata
+
+invalid_idt:
+    dq 0, 0
+
+section .text
+
+%macro push32 1
+    sub rsp, 4
+    mov dword [rsp], %1
+%endmacro
+
+global do_32
+bits 64
+do_32:
+    mov rbp, rsp
+
+    lidt [rel invalid_idt]
+
+    cmp esi, 4
+    jle .no_stack_args
+
+.push_stack_args:
+    dec esi
+    mov eax, [rbp + 8 + rsi*8]
+    push32 eax
+    test esi, esi
+    jnz .push_stack_args
+
+.no_stack_args:
+    push32 r9d
+    push32 r8d
+    push32 ecx
+    push32 edx
+
+    mov eax, 0x20
+    mov ds, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+    mov ss, ax
+
+    lea rbx, [rel .go_32]
+
+    push 0x18
+    push rbx
+    retfq
+
+bits 32
+.go_32:
+    mov eax, cr0
+    btr eax, 31
+    mov cr0, eax
+
+    mov ecx, 0xc0000080
+    rdmsr
+    btr eax, 8
+    wrmsr
+
+    mov eax, cr4
+    btr eax, 5
+    mov cr4, eax
+
+    call edi
diff --git a/stage23/protos/stivale.32.c b/stage23/protos/stivale.32.c
new file mode 100644
index 00000000..2f24f19b
--- /dev/null
+++ b/stage23/protos/stivale.32.c
@@ -0,0 +1,127 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <mm/vmm.h>
+
+__attribute__((noreturn)) void stivale_spinup_32(
+                 int bits, bool level5pg, uint32_t pagemap_top_lv,
+                 uint32_t entry_point_lo, uint32_t entry_point_hi,
+                 void *stivale_struct, uint32_t stack_lo, uint32_t stack_hi) {
+    uint64_t entry_point =
+        (uint64_t)entry_point_lo | ((uint64_t)entry_point_hi << 32);
+    uint64_t stack =
+        (uint64_t)stack_lo | ((uint64_t)stack_hi << 32);
+
+    if (bits == 64) {
+        if (level5pg) {
+            // Enable CR4.LA57
+            asm volatile (
+                "mov eax, cr4\n\t"
+                "bts eax, 12\n\t"
+                "mov cr4, eax\n\t" ::: "eax", "memory"
+            );
+        }
+
+        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"
+            "call 1f\n\t"
+            "1: pop eax\n\t"
+            "add eax, 8\n\t"
+            "push 0x28\n\t"
+            "push eax\n\t"
+            "retf\n\t"
+            ".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"
+
+            // Since we don't really know what is now present in the upper
+            // 32 bits of the 64 bit registers, clear up the upper bits
+            // of the registers we use to store stack pointer and instruction
+            // pointer
+            "mov esi, esi\n\t"
+            "mov ebx, ebx\n\t"
+            "mov edi, edi\n\t"
+
+            // Let's pretend we push a return address
+            "mov rsi, qword ptr [rsi]\n\t"
+            "test rsi, rsi\n\t"
+            "jz 1f\n\t"
+
+            "sub rsi, 8\n\t"
+            "mov qword ptr [rsi], 0\n\t"
+
+            "1:\n\t"
+            "push 0x30\n\t"
+            "push rsi\n\t"
+            "pushfq\n\t"
+            "push 0x28\n\t"
+            "push [rbx]\n\t"
+
+            "xor rax, rax\n\t"
+            "xor rbx, rbx\n\t"
+            "xor rcx, rcx\n\t"
+            "xor rdx, rdx\n\t"
+            "xor rsi, rsi\n\t"
+            "xor rbp, rbp\n\t"
+            "xor r8,  r8\n\t"
+            "xor r9,  r9\n\t"
+            "xor r10, r10\n\t"
+            "xor r11, r11\n\t"
+            "xor r12, r12\n\t"
+            "xor r13, r13\n\t"
+            "xor r14, r14\n\t"
+            "xor r15, r15\n\t"
+
+            "iretq\n\t"
+            ".code32\n\t"
+            :
+            : "a" (pagemap_top_lv), "b" (&entry_point),
+              "D" (stivale_struct), "S" (&stack)
+            : "memory"
+        );
+    } else if (bits == 32) {
+        asm volatile (
+            "cli\n\t"
+            "cld\n\t"
+
+            "mov esp, dword ptr [esi]\n\t"
+            "push edi\n\t"
+            "push 0\n\t"
+
+            "pushfd\n\t"
+            "push 0x18\n\t"
+            "push [ebx]\n\t"
+
+            "xor eax, eax\n\t"
+            "xor ebx, ebx\n\t"
+            "xor ecx, ecx\n\t"
+            "xor edx, edx\n\t"
+            "xor esi, esi\n\t"
+            "xor edi, edi\n\t"
+            "xor ebp, ebp\n\t"
+
+            "iret\n\t"
+            :
+            : "b"(&entry_point), "D"(stivale_struct), "S"(&stack)
+            : "memory"
+        );
+    }
+
+    __builtin_unreachable();
+}
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index 42a8db34..e3134326 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -16,6 +16,7 @@
 #include <lib/term.h>
 #include <sys/pic.h>
 #include <sys/cpu.h>
+#include <sys/gdt.h>
 #include <fs/file.h>
 #include <mm/vmm.h>
 #include <mm/pmm.h>
@@ -199,7 +200,7 @@ void stivale_load(char *config, char *cmdline) {
     stivale_struct.memory_map_entries = (uint64_t)memmap_entries;
     stivale_struct.memory_map_addr    = (uint64_t)(size_t)memmap;
 
-    stivale_spinup(bits, want_5lv, pagemap,
+    stivale_spinup(bits, want_5lv, &pagemap,
                    entry_point, &stivale_struct, stivale_hdr.stack);
 }
 
@@ -244,8 +245,17 @@ pagemap_t stivale_build_pagemap(bool level5pg) {
     return pagemap;
 }
 
+#if defined (uefi)
+extern symbol ImageBase;
+#endif
+
+__attribute__((noreturn)) void stivale_spinup_32(
+                 int bits, bool level5pg, uint32_t pagemap_top_lv,
+                 uint32_t entry_point_lo, uint32_t entry_point_hi,
+                 void *stivale_struct, uint32_t stack_lo, uint32_t stack_hi);
+
 __attribute__((noreturn)) void stivale_spinup(
-                 int bits, bool level5pg, pagemap_t pagemap,
+                 int bits, bool level5pg, pagemap_t *pagemap,
                  uint64_t entry_point, void *stivale_struct, uint64_t stack) {
     mtrr_restore();
 
@@ -261,120 +271,36 @@ __attribute__((noreturn)) void stivale_spinup(
     }
 #endif
 
+#if defined (uefi)
+    efi_exit_boot_services();
+#endif
+
     pic_mask_all();
     pic_flush();
 
-#if defined (bios)
-    if (bits == 64) {
-        if (level5pg) {
-            // Enable CR4.LA57
-            asm volatile (
-                "mov eax, cr4\n\t"
-                "bts eax, 12\n\t"
-                "mov cr4, eax\n\t" ::: "eax", "memory"
-            );
-        }
-
-        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"
-
-            // Since we don't really know what is now present in the upper
-            // 32 bits of the 64 bit registers, clear up the upper bits
-            // of the registers we use to store stack pointer and instruction
-            // pointer
-            "mov esi, esi\n\t"
-            "mov ebx, ebx\n\t"
-            "mov edi, edi\n\t"
-
-            // Let's pretend we push a return address
-            "mov rsi, qword ptr [rsi]\n\t"
-            "test rsi, rsi\n\t"
-            "jz 1f\n\t"
-
-            "sub rsi, 8\n\t"
-            "mov qword ptr [rsi], 0\n\t"
-
-            "1:\n\t"
-            "push 0x30\n\t"
-            "push rsi\n\t"
-            "pushfq\n\t"
-            "push 0x28\n\t"
-            "push [rbx]\n\t"
-
-            "xor rax, rax\n\t"
-            "xor rbx, rbx\n\t"
-            "xor rcx, rcx\n\t"
-            "xor rdx, rdx\n\t"
-            "xor rsi, rsi\n\t"
-            "xor rbp, rbp\n\t"
-            "xor r8,  r8\n\t"
-            "xor r9,  r9\n\t"
-            "xor r10, r10\n\t"
-            "xor r11, r11\n\t"
-            "xor r12, r12\n\t"
-            "xor r13, r13\n\t"
-            "xor r14, r14\n\t"
-            "xor r15, r15\n\t"
-
-            "iretq\n\t"
-            ".code32\n\t"
-            :
-            : "a" (pagemap.top_level), "b" (&entry_point),
-              "D" (stivale_struct), "S" (&stack)
-            : "memory"
-        );
-    } else if (bits == 32) {
-        asm volatile (
-            "cli\n\t"
-            "cld\n\t"
-
-            "mov esp, dword ptr [esi]\n\t"
-            "push edi\n\t"
-            "push 0\n\t"
-
-            "pushfd\n\t"
-            "push 0x18\n\t"
-            "push [ebx]\n\t"
-
-            "xor eax, eax\n\t"
-            "xor ebx, ebx\n\t"
-            "xor ecx, ecx\n\t"
-            "xor edx, edx\n\t"
-            "xor esi, esi\n\t"
-            "xor edi, edi\n\t"
-            "xor ebp, ebp\n\t"
-
-            "iret\n\t"
-            :
-            : "b"(&entry_point), "D"(stivale_struct), "S"(&stack)
-            : "memory"
-        );
-    }
-#elif defined (uefi)
-    (void)bits; (void)level5pg; (void)pagemap; (void)entry_point;
-    (void)stivale_struct; (void)stack;
+#if defined (uefi)
+    gdt.ptr += (uintptr_t)ImageBase;
+
+    asm volatile (
+        "lgdt %0\n\t"
+        :
+        : "m"(gdt)
+        : "memory"
+    );
+
+    do_32(stivale_spinup_32, 8,
+        bits, level5pg, (uint32_t)(uintptr_t)pagemap->top_level,
+        (uint32_t)entry_point, (uint32_t)(entry_point >> 32),
+        stivale_struct,
+        (uint32_t)stack, (uint32_t)(stack >> 32));
+#endif
 
+#if defined (bios)
+    stivale_spinup_32(bits, level5pg, (uint32_t)(uintptr_t)pagemap->top_level,
+        (uint32_t)entry_point, (uint32_t)(entry_point >> 32),
+        stivale_struct,
+        (uint32_t)stack, (uint32_t)(stack >> 32));
 #endif
 
-    for (;;);
+    __builtin_unreachable();
 }
diff --git a/stage23/protos/stivale.h b/stage23/protos/stivale.h
index 0f73be36..367413a3 100644
--- a/stage23/protos/stivale.h
+++ b/stage23/protos/stivale.h
@@ -10,7 +10,7 @@ void stivale_load(char *config, char *cmdline);
 
 pagemap_t stivale_build_pagemap(bool level5pg);
 __attribute__((noreturn)) void stivale_spinup(
-                 int bits, bool level5pg, pagemap_t pagemap,
+                 int bits, bool level5pg, pagemap_t *pagemap,
                  uint64_t entry_point, void *stivale_struct, uint64_t stack);
 
 #endif
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index ed0e0be7..054995c6 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -376,6 +376,6 @@ void stivale2_load(char *config, char *cmdline, bool pxe) {
             break;
     }
 
-    stivale_spinup(bits, level5pg && level5pg_requested, pagemap,
+    stivale_spinup(bits, level5pg && level5pg_requested, &pagemap,
                    entry_point, &stivale2_struct, stivale2_hdr.stack);
 }
diff --git a/stage23/sys/gdt.h b/stage23/sys/gdt.h
new file mode 100644
index 00000000..e8eaf4a2
--- /dev/null
+++ b/stage23/sys/gdt.h
@@ -0,0 +1,22 @@
+#ifndef __SYS__GDT_H__
+#define __SYS__GDT_H__
+
+#include <stdint.h>
+
+struct gdtr {
+    uint16_t  limit;
+    uintptr_t ptr;
+} __attribute__((packed));
+
+struct gdt_desc {
+    uint16_t limit;
+    uint16_t base_low;
+    uint8_t  base_mid;
+    uint8_t  access;
+    uint8_t  granularity;
+    uint8_t  base_hi;
+} __attribute__((packed));
+
+extern struct gdtr gdt;
+
+#endif
diff --git a/stage23/sys/gdt.s2.asm b/stage23/sys/gdt.s2.asm
deleted file mode 100644
index b9f450c5..00000000
--- a/stage23/sys/gdt.s2.asm
+++ /dev/null
@@ -1,63 +0,0 @@
-section .data
-
-global gdt
-
-gdt:
-    dw .size - 1    ; GDT size
-    dd .start       ; GDT start address
-
-  .start:
-    ; Null desc
-    dq 0
-
-    ; 16-bit code
-    dw 0xffff       ; Limit
-    dw 0x0000       ; Base (low 16 bits)
-    db 0x00         ; Base (mid 8 bits)
-    db 10011010b    ; Access
-    db 00000000b    ; Granularity
-    db 0x00         ; Base (high 8 bits)
-
-    ; 16-bit data
-    dw 0xffff       ; 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)
-
-    ; 32-bit code
-    dw 0xffff       ; Limit
-    dw 0x0000       ; Base (low 16 bits)
-    db 0x00         ; Base (mid 8 bits)
-    db 10011010b    ; Access
-    db 11001111b    ; Granularity
-    db 0x00         ; Base (high 8 bits)
-
-    ; 32-bit data
-    dw 0xffff       ; Limit
-    dw 0x0000       ; Base (low 16 bits)
-    db 0x00         ; Base (mid 8 bits)
-    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)
-
-  .end:
-
-  .size: equ .end - .start
diff --git a/stage23/sys/gdt.s2.c b/stage23/sys/gdt.s2.c
new file mode 100644
index 00000000..0db99914
--- /dev/null
+++ b/stage23/sys/gdt.s2.c
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include <sys/gdt.h>
+
+static struct gdt_desc gdt_descs[] = {
+    {0},
+
+    {
+        .limit       = 0xffff,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10011010,
+        .granularity = 0b00000000,
+        .base_hi     = 0x00
+    },
+
+    {
+        .limit       = 0xffff,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10010010,
+        .granularity = 0b00000000,
+        .base_hi     = 0x00
+    },
+
+    {
+        .limit       = 0xffff,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10011010,
+        .granularity = 0b11001111,
+        .base_hi     = 0x00
+    },
+
+    {
+        .limit       = 0xffff,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10010010,
+        .granularity = 0b11001111,
+        .base_hi     = 0x00
+    },
+
+    {
+        .limit       = 0x0000,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10011010,
+        .granularity = 0b00100000,
+        .base_hi     = 0x00
+    },
+
+    {
+        .limit       = 0x0000,
+        .base_low    = 0x0000,
+        .base_mid    = 0x00,
+        .access      = 0b10010010,
+        .granularity = 0b00000000,
+        .base_hi     = 0x00
+    }
+};
+
+struct gdtr gdt = {
+    sizeof(gdt_descs) - 1,
+    (uintptr_t)gdt_descs
+};
diff --git a/stage23/sys/smp.c b/stage23/sys/smp.c
index d7dd100a..138d602c 100644
--- a/stage23/sys/smp.c
+++ b/stage23/sys/smp.c
@@ -8,6 +8,7 @@
 #include <lib/print.h>
 #include <sys/smp.h>
 #include <sys/lapic.h>
+#include <sys/gdt.h>
 #include <mm/vmm.h>
 #include <mm/pmm.h>
 #include <mm/mtrr.h>
@@ -39,11 +40,6 @@ struct madt_x2apic {
     uint32_t acpi_processor_uid;
 } __attribute__((packed));
 
-struct gdtr {
-    uint16_t limit;
-    uint32_t ptr;
-} __attribute__((packed));
-
 static void delay(uint32_t cycles) {
     for (uint32_t i = 0; i < cycles; i++)
         inb(0x80);
tab: 248 wrap: offon