diff options
Diffstat (limited to 'boot/main.c')
| -rw-r--r-- | boot/main.c | 108 |
1 files changed, 96 insertions, 12 deletions
diff --git a/boot/main.c b/boot/main.c index 611c833..ed18578 100644 --- a/boot/main.c +++ b/boot/main.c @@ -5,6 +5,7 @@ #include <bits/x86_64/descriptor.h> #include <libc/stdio.h> #include <posix/sys/mman.h> +#include <posix/unistd.h> /* * Fake syscall mechanism - @@ -47,32 +48,114 @@ static struct segment_descriptor const fake_syscall_gdt[] = 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; // 8 - struct descriptor_table_register_long gdtr; // 24 - uint64_t return_ds; // 32 - uintptr_t return_rip; // 40 - uint64_t return_cs; // 48 + 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; // 8 - uint64_t syscall_index; // 16 - syscall_delegate_parameters parameters; // 64 + 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); -//constexpr int NR_SYSCALLS = 10; -//static syscall_delegate *syscall_handler_delegates[NR_SYSCALLS]; +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) { - (void)context; - return -1; + 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); @@ -117,6 +200,7 @@ int main(int argc, char **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); } |
