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);
