summaryrefslogtreecommitdiff
path: root/boot/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot/main.c')
-rw-r--r--boot/main.c198
1 files changed, 2 insertions, 196 deletions
diff --git a/boot/main.c b/boot/main.c
index ed18578..55eab00 100644
--- a/boot/main.c
+++ b/boot/main.c
@@ -1,196 +1,5 @@
#include "kjarna.h"
-#include <stdnoreturn.h>
-#include <asm/x86_64/msr.h>
-#include <bits/x86_64/msr.h>
-#include <bits/x86_64/descriptor.h>
-#include <libc/stdio.h>
-#include <posix/sys/mman.h>
-#include <posix/unistd.h>
-
-/*
- * Fake syscall mechanism -
- *
- * We have a GDT with entries for supervisory mode. These serve as the
- * entries to satisfy the requirements of the SYSCALL instruction, as
- * for some reason (possibly intentionally) the OVMF GDT is not laid out
- * 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 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 latency.
- * We will not be running Quake in this environment.
- *
- * These constraints are probably fine, as the loading process only needs to
- * open files, map memory, etc.
- */
-
-
-void *stack_alloc(void **stack_pointer, size_t alloc_size)
-{
- void *block = *(char **)stack_pointer -= alloc_size;
-
- // maintain alignment
- *(char **)stack_pointer -= alloc_size % sizeof(size_t);
-
- return block;
-}
-
-static struct segment_descriptor const fake_syscall_gdt[] =
-{
- { 0 },
- { 0xffff, 0, 0, 0x9a, 0xaf, 0},
- { 0xffff, 0, 0, 0x92, 0xcf, 0}
-};
-
-typedef uint64_t syscall_delegate_parameters[6];
-
-static struct
-{
- uint16_t cs;
- uint16_t ds;
- uint64_t rflags;
- struct descriptor_table_register_long gdtr;
-}
-uefi_context;
-
-static void save_uefi_context()
-{
- __asm__ volatile (
- "movw %%cs, %0\n"
- "movw %%ds, %1\n"
- "pushfq\n"
- "popq %3\n"
- "sgdt %2\n"
- :
- "=m"(uefi_context.cs),
- "=m"(uefi_context.ds),
- "=m"(uefi_context.gdtr),
- "=g"(uefi_context.rflags)
- :
- );
-}
-
-static void restore_uefi_context()
-{
- __asm__ volatile (
- "lgdt %0\n"
- "mov %w1, %%ds\n"
- "mov %w1, %%es\n"
- "mov %w1, %%fs\n"
- "mov %w1, %%gs\n"
- "mov %w1, %%gs\n"
- "mov %w1, %%ss\n"
- "push %q2\n"
- "lea .Lflush(%%rip), %%rax\n"
- "push %%rax\n"
- "lretq\n"
- ".Lflush:\n"
- "push %q3\n"
- "popfq\n"
- :
- :
- "m"(uefi_context.gdtr),
- "m"(uefi_context.ds),
- "m"(uefi_context.cs),
- "g"(uefi_context.rflags)
- :
- "rax"
- );
-
-}
-
-struct syscall_context_return_state
-{
- uint64_t rflags;
- struct descriptor_table_register_long gdtr;
- uint64_t return_ds;
- uintptr_t return_rip;
- uint64_t return_cs;
-};
-
-struct syscall_context
-{
- uint64_t pad;
- uint64_t syscall_index;
- syscall_delegate_parameters parameters;
- struct syscall_context_return_state state;
-};
-
-
-typedef int64_t (syscall_delegate)(syscall_delegate_parameters params);
-
-int64_t syscall_delegate_write(syscall_delegate_parameters params)
-{
- return write((int)params[0], (void *)params[1], (size_t)params[2]);
-}
-
-constexpr int NR_SYSCALLS = 10;
-static syscall_delegate *syscall_handler_delegates[NR_SYSCALLS] =
-{
- nullptr,
- syscall_delegate_write
-};
-
-SYSV_ABI int64_t fake_syscall_handler(struct syscall_context *context)
-{
- if (context->syscall_index > NR_SYSCALLS)
- {
- // TODO: ENOSYS
- return -1;
- }
-
- syscall_delegate *delegate = syscall_handler_delegates[context->syscall_index];
-
- if (delegate == nullptr)
- {
- // TODO: ENOSYS
- return -1;
- }
-
- restore_uefi_context();
- int64_t result = delegate(context->parameters);
- save_uefi_context();
-
- return result;
-}
-
-SYSV_ABI void fake_syscall_entry(void);
-SYSV_ABI void fake_syscall_start(void *stack);
-
-static void install_syscall_handler(void)
-{
- union msr_lstar lstar = { (uintptr_t)fake_syscall_entry };
- union msr_star star = { { 0, 1 << 3, 1 << 3 | 3 } };
-
- msr_write(MSR_INDEX_LSTAR, lstar.value);
- msr_write(MSR_INDEX_STAR, star.value);
-
- uint64_t efer = msr_read(MSR_INDEX_EFER);
- efer |= 1;
- msr_write(MSR_INDEX_EFER, efer);
-}
-
-static void *create_fake_syscall_stack(void *entry_addr)
-{
- constexpr size_t fake_syscall_stack_size = 0x20000; // 128KiB stack
- char *stack_pointer_base = mmap(nullptr, fake_syscall_stack_size, 0, 0, -1, 0);
- void *stack_pointer_head = stack_pointer_base + fake_syscall_stack_size;
-
- struct syscall_context *context = stack_alloc(&stack_pointer_head, sizeof(*context));
-
- context->state.rflags = 0;
- context->state.gdtr.base = (uintptr_t)&fake_syscall_gdt;
- context->state.gdtr.limit = sizeof(fake_syscall_gdt) - 1;
- context->state.return_ds = 16;
- context->state.return_cs = 8;
- context->state.return_rip = (uintptr_t)entry_addr;
-
- return stack_pointer_head;
-}
+#include "fake_syscall.h"
int main(int argc, char **argv)
{
@@ -198,9 +7,6 @@ int main(int argc, char **argv)
(void)argv;
struct kjarna_boot_image boot_image = get_boot_image();
- install_syscall_handler();
- void *fake_syscall_stack = create_fake_syscall_stack((void *)boot_image.entry);
- save_uefi_context();
- fake_syscall_start(fake_syscall_stack);
+ fake_syscall_start(&boot_image);
}