From 5d3f8b4eb00f9e742c93588b8f5921838749f16f Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sun, 7 Mar 2021 00:52:25 +0100 Subject: [PATCH] Implement do_32() and make stivale kernels work with UEFI --- stage23/Makefile | 18 +++++ stage23/lib/blib.c | 9 ++- stage23/lib/blib.h | 4 + stage23/lib/do_32.asm | 64 ++++++++++++++++ stage23/protos/stivale.32.c | 127 +++++++++++++++++++++++++++++++ stage23/protos/stivale.c | 148 +++++++++--------------------------- stage23/protos/stivale.h | 2 +- stage23/protos/stivale2.c | 2 +- stage23/sys/gdt.h | 22 ++++++ stage23/sys/gdt.s2.asm | 63 --------------- stage23/sys/gdt.s2.c | 65 ++++++++++++++++ stage23/sys/smp.c | 6 +- 12 files changed, 348 insertions(+), 182 deletions(-) create mode 100644 stage23/lib/do_32.asm create mode 100644 stage23/protos/stivale.32.c create mode 100644 stage23/sys/gdt.h delete mode 100644 stage23/sys/gdt.s2.asm create mode 100644 stage23/sys/gdt.s2.c 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 +#include +#include +#include + +__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 #include #include +#include #include #include #include @@ -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" - ); - } +#if defined (uefi) + gdt.ptr += (uintptr_t)ImageBase; - 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; + 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 - for (;;); +#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 + + __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 + +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 +#include + +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 #include #include +#include #include #include #include @@ -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);