diff options
Diffstat (limited to 'boot/main.c')
| -rw-r--r-- | boot/main.c | 97 |
1 files changed, 20 insertions, 77 deletions
diff --git a/boot/main.c b/boot/main.c index 570b703..d217235 100644 --- a/boot/main.c +++ b/boot/main.c @@ -1,5 +1,8 @@ #include "kjarna.h" #include <stdnoreturn.h> +#include <asm/x86_64/msr.h> +#include <bits/x86_64/msr.h> +#include <bits/x86_64/descriptor.h> /* * Fake syscall mechanism - @@ -10,12 +13,12 @@ * in a way to make use of the SYSCALL instruction possible. * * This causes us to have to work inside of constraints during loading time - * - All "user" mode execution entirely blocks interrupts processing. That - * means that user mode code must not execute "hlt", or the system will + * - All "user" mode execution entirely blocks interrupt processing. That + * means that "user" mode code must not execute "hlt", or the system will * be locked. * - When (if?) user input is required, it is always buffered. It is possible * to simulate unbuffered input, at the cost of one syscall per transfer - * from "kernel" side to "user" side. This will cause high input lag. + * from "kernel" side to "user" side. This will cause high input latency. * We will not be running Quake in this environment. * * These constraints are probably fine, as the loading process only needs to @@ -23,40 +26,6 @@ */ -struct dtr64 -{ - uint16_t limit; - uint64_t base; -} __attribute__((packed, aligned(16))); - -struct segment_descriptor -{ - uint16_t limit0; - uint16_t base0; - uint8_t base16; - uint8_t access; - uint8_t flags_limit16; - uint8_t base24; -} __attribute__((packed, aligned(8))); - -union msr_star -{ - struct - { - uint32_t target_eip; - uint16_t syscall_selector_base; - uint16_t sysret_selector_base; - } - fields; - uint64_t value; -}; - -union msr_lstar -{ - void (*syscall_handler)(void); - uint64_t value; -}; - void *stack_alloc(void **stack_pointer, size_t alloc_size) { void *block = *(char **)stack_pointer -= alloc_size; @@ -67,33 +36,6 @@ void *stack_alloc(void **stack_pointer, size_t alloc_size) return block; } -static void msr_write(uint32_t index, uint64_t value) -{ - uint32_t low = value & 0xffffffff; - uint32_t high = value >> 32; - - __asm__ volatile - ( - "wrmsr\n\t" - :: "a"(low), "d"(high), "c"(index) - ); -} - -uint64_t msr_read(uint32_t index) -{ - uint32_t low; - uint32_t high; - - __asm__ volatile - ( - "rdmsr\n\t" - : "=a"(low), "=d"(high) - : "c"(index) - ); - - return ((uint64_t)high << 32)|low; -} - static struct segment_descriptor const fake_syscall_gdt[] = { { 0 }, @@ -101,35 +43,38 @@ static struct segment_descriptor const fake_syscall_gdt[] = { 0xffff, 0, 0, 0x92, 0xcf, 0} }; -static noreturn void fake_syscall_entry(void) +SYSV_ABI static void fake_syscall_handler(void) { while (true); } -SYSV_ABI void fake_syscall_return(void *target_rsp); +static void *return_rsp; + +SYSV_ABI void fake_syscall_entry(void); +SYSV_ABI void fake_syscall_return(void *target_rsp, void **return_rsp, SYSV_ABI void (*callback)()); static void install_syscall_handler(void) { - union msr_lstar lstar = { fake_syscall_entry }; + union msr_lstar lstar = { (uintptr_t)fake_syscall_entry }; union msr_star star = { { 0, 1 << 3, 1 << 3 | 3 } }; - msr_write(0xc0000082, lstar.value); - msr_write(0xc0000081, star.value); + msr_write(MSR_INDEX_LSTAR, lstar.value); + msr_write(MSR_INDEX_STAR, star.value); - uint64_t efer = msr_read(0xc0000080); + uint64_t efer = msr_read(MSR_INDEX_EFER); efer |= 1; - msr_write(0xc0000080, efer); + msr_write(MSR_INDEX_EFER, efer); } struct context_stack_frame { - struct dtr64 lret_gdtr; + struct descriptor_table_register_long lret_gdtr; uint64_t lret_ds; uint64_t lret_rip; uint64_t lret_cs; }; -static noreturn void enter_boot_image(struct kjarna_boot_image *image) +static void enter_boot_image(struct kjarna_boot_image *image) { size_t boot_stack_size = 0x10000; char *boot_image_stack = calloc(1, boot_stack_size); @@ -144,7 +89,8 @@ static noreturn void enter_boot_image(struct kjarna_boot_image *image) stack_frame->lret_gdtr.limit = sizeof(fake_syscall_gdt) - 1; stack_frame->lret_gdtr.base = (uintptr_t)fake_syscall_gdt; - fake_syscall_return(boot_image_stack_head); + + fake_syscall_return(boot_image_stack_head, &return_rsp, fake_syscall_handler); while (true); } @@ -156,11 +102,8 @@ int main(int argc, char **argv) (void)argc; (void)argv; - printf("DEBUG: alignof(struct dtr64) = %zu", alignof(struct dtr64)); - printf("DEBUG: sizeof(struct dtr64) = %zu", sizeof(struct dtr64)); struct kjarna_boot_image boot_image = get_boot_image(); install_syscall_handler(); enter_boot_image(&boot_image); } - |
