Implement do_32() and make stivale kernels work with UEFI

This commit is contained in:
mintsuki 2021-03-07 00:52:25 +01:00
parent 6c22743c7e
commit 5d3f8b4eb0
12 changed files with 348 additions and 182 deletions

View File

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

View File

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

View File

@ -66,4 +66,8 @@ enum {
BOOT_FROM_CD
};
#if defined (uefi)
__attribute__((noreturn)) void do_32(void *fnptr, int args, ...);
#endif
#endif

64
stage23/lib/do_32.asm Normal file
View File

@ -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

127
stage23/protos/stivale.32.c Normal file
View File

@ -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();
}

View File

@ -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"
);
}
#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"
"lgdt %0\n\t"
:
: "a" (pagemap.top_level), "b" (&entry_point),
"D" (stivale_struct), "S" (&stack)
: "m"(gdt)
: "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;
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();
}

View File

@ -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

View File

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

22
stage23/sys/gdt.h Normal file
View File

@ -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

View File

@ -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

65
stage23/sys/gdt.s2.c Normal file
View File

@ -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
};

View File

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