From 2fb3f208bd2e739a8968afb23d22e13b6660ca22 Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Fri, 31 Jan 2025 00:48:54 +0000 Subject: spread around defs, x86 asm and bits libs --- api/asm/x86_64/msr.h | 5 +++ api/bits/x86_64/descriptor.h | 18 ++++++++ api/bits/x86_64/msr.h | 29 +++++++++++++ boot/Makefile | 4 +- boot/fake_syscall_entry.S | 17 ++++++-- boot/main.c | 97 +++++++++----------------------------------- lib/asm/x86_64/msr.c | 30 ++++++++++++++ 7 files changed, 117 insertions(+), 83 deletions(-) create mode 100644 api/asm/x86_64/msr.h create mode 100644 api/bits/x86_64/descriptor.h create mode 100644 api/bits/x86_64/msr.h create mode 100644 lib/asm/x86_64/msr.c diff --git a/api/asm/x86_64/msr.h b/api/asm/x86_64/msr.h new file mode 100644 index 0000000..e78e5b5 --- /dev/null +++ b/api/asm/x86_64/msr.h @@ -0,0 +1,5 @@ +#include + +void msr_write(uint32_t index, uint64_t value); +uint64_t msr_read(uint32_t index); + diff --git a/api/bits/x86_64/descriptor.h b/api/bits/x86_64/descriptor.h new file mode 100644 index 0000000..649ac74 --- /dev/null +++ b/api/bits/x86_64/descriptor.h @@ -0,0 +1,18 @@ +#include + +struct descriptor_table_register_long +{ + 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))); + diff --git a/api/bits/x86_64/msr.h b/api/bits/x86_64/msr.h new file mode 100644 index 0000000..a25af7d --- /dev/null +++ b/api/bits/x86_64/msr.h @@ -0,0 +1,29 @@ +#include + +#define MSR_INDEX_EFER 0xc0000080 +#define MSR_INDEX_STAR 0xc0000081 +#define MSR_INDEX_LSTAR 0xc0000082 + +union msr_efer +{ + uint64_t value; +}; + +union msr_star +{ + struct + { + uint32_t target_eip; + uint16_t syscall_segment_base; + uint16_t sysret_segment_base; + } + fields; + uint64_t value; +}; + +union msr_lstar +{ + uint64_t target_rip; + uint64_t value; +}; + diff --git a/boot/Makefile b/boot/Makefile index 3c47336..49b6639 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -4,7 +4,7 @@ include ../defaults.mk $(CC.info) @$(CC) $(LDFLAGS) -o $@ $^ -VPATH := ../lib efi/ +VPATH := ../lib ../lib/asm/$(ARCH) efi/ IMAGE := kjarna.efi @@ -22,7 +22,7 @@ LDFLAGS := --target=$(ARCH)-unknown-windows -nostdlib -ggdb \ all: $(IMAGE) CRT_OBJS := start.o bind.o -LIB_OBJS := memcmp.o memset.o memcpy.o memmove.o string.o elf64.o printf.o stdio.o +LIB_OBJS := memcmp.o memset.o memcpy.o memmove.o string.o elf64.o printf.o stdio.o msr.o EFI_OBJS := file.o memory.o protocol.o image.o APP_OBJS := main.o fake_syscall_entry.o diff --git a/boot/fake_syscall_entry.S b/boot/fake_syscall_entry.S index ff2428d..bc175c1 100644 --- a/boot/fake_syscall_entry.S +++ b/boot/fake_syscall_entry.S @@ -1,18 +1,27 @@ .section .text +.global fake_syscall_entry +.global fake_syscall_return + .extern fake_syscall_handler -.global fake_syscall_entry fake_syscall_entry: - hlt + hlt; -.global fake_syscall_return fake_syscall_return: cli +fake_syscall_swap: + mov %cs, %rax + pushq %rax + pushq %rdx + mov %ds, %rax + pushq %rax + sub $16, %rsp + sgdt (%rsp) + mov %rsp, (%rsi) mov %rdi, %rsp lgdt (%rsp) add $16, %rsp - movw (%rsp), %ds movw (%rsp), %es movw (%rsp), %fs 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 +#include +#include +#include /* * 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); } - diff --git a/lib/asm/x86_64/msr.c b/lib/asm/x86_64/msr.c new file mode 100644 index 0000000..2dfdc44 --- /dev/null +++ b/lib/asm/x86_64/msr.c @@ -0,0 +1,30 @@ +#include + +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; +} + -- cgit v1.3.1-1-g115d