summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2025-01-27 02:05:07 +0000
committerAda Christine <adachristine18@gmail.com>2025-01-27 02:05:07 +0000
commit0d2ddecc9aeb232746b76b4eebdb1381053a8951 (patch)
tree31fe2fc38ead88a0d982b06b3783aae4f094b8ad
parent6faeb8d3aed797ddfac66ecc21fc8a717d5e848a (diff)
checkpoint. we can fake syscall with the dummy gdt
-rw-r--r--boot/Makefile4
-rw-r--r--boot/efi/image.c48
-rw-r--r--boot/efi/start.c10
-rw-r--r--boot/fake_syscall_entry.S25
-rw-r--r--boot/kjarna.h21
-rw-r--r--boot/main.c159
-rw-r--r--kc/core/cpu/cpu.c2
-rw-r--r--lldbscript6
-rw-r--r--service/Makefile4
-rw-r--r--service/kjarna.c14
-rw-r--r--service/lib/posix.c19
11 files changed, 280 insertions, 32 deletions
diff --git a/boot/Makefile b/boot/Makefile
index 7f4be6b..3c47336 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -14,6 +14,8 @@ CFLAGS += --target=$(ARCH)-unknown-windows -fshort-wchar -mno-avx \
-mno-sse -mno-mmx -funsigned-char -Wno-pointer-sign -ggdb \
-fno-ms-extensions
+ASFLAGS += --target=$(ARCH)-unknown-windows -ggdb
+
LDFLAGS := --target=$(ARCH)-unknown-windows -nostdlib -ggdb \
-Wl,-entry:_start,-subsystem:efi_application -fuse-ld=lld-link
@@ -22,7 +24,7 @@ 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
EFI_OBJS := file.o memory.o protocol.o image.o
-APP_OBJS := main.o
+APP_OBJS := main.o fake_syscall_entry.o
OBJS := $(CRT_OBJS) $(LIB_OBJS) $(EFI_OBJS) $(APP_OBJS)
DEPS := $(OBJS:.o=.d)
diff --git a/boot/efi/image.c b/boot/efi/image.c
index 25e1911..b9b4891 100644
--- a/boot/efi/image.c
+++ b/boot/efi/image.c
@@ -14,12 +14,6 @@
#include <efi/error.h>
-struct image_buffer
-{
- char *base;
- size_t length;
-};
-
static int create_image_buffer(int fd, struct image_buffer *buffer)
{
if ((buffer->length = elf64_size_fd(fd)) == 0)
@@ -89,9 +83,9 @@ kjarna_image_entry_func *image_entry_addr(struct image_buffer *buffer)
return (kjarna_image_entry_func *)(buffer->base + ehdr->e_entry);
}
-int image_start(void)
+struct kjarna_interface get_boot_interface(void)
{
- struct kjarna_interface interface =
+ struct kjarna_interface result =
{
efi_open,
efi_close,
@@ -102,6 +96,30 @@ int image_start(void)
efi_munmap
};
+ return result;
+}
+
+struct kjarna_boot_image get_boot_image(void)
+{
+ struct kjarna_boot_image image =
+ {
+ { nullptr, 0 },
+ nullptr
+ };
+
+ image.buffer = load_image();
+
+ if (image.buffer.base != nullptr)
+ {
+ image.entry = image_entry_addr(&image.buffer);
+ }
+
+ return image;
+}
+
+int image_start(void)
+{
+ struct kjarna_interface interface = get_boot_interface();
struct kjarna_entry_params params =
{
&interface,
@@ -110,21 +128,19 @@ int image_start(void)
nullptr
};
- struct image_buffer buffer = load_image();
-
- kjarna_image_entry_func *image_entry = nullptr;
+ struct kjarna_boot_image image = get_boot_image();
- if (buffer.base != nullptr)
+ if (image.buffer.base != nullptr)
{
- image_entry = image_entry_addr(&buffer);
+ image.entry = image_entry_addr(&image.buffer);
}
- if (image_entry != nullptr)
+ if (image.entry != nullptr)
{
- image_entry(&params);
+ image.entry(&params);
}
- if (munmap(buffer.base, buffer.length) == -1)
+ if (munmap(image.buffer.base, image.buffer.length) == -1)
{
write(STDOUT_FILENO, "failed unmap\r\n", -1);
diff --git a/boot/efi/start.c b/boot/efi/start.c
index f1f4ec7..fc44377 100644
--- a/boot/efi/start.c
+++ b/boot/efi/start.c
@@ -28,8 +28,18 @@ EFI_STATUS _start(EFI_HANDLE handle, EFI_SYSTEM_TABLE *system_table)
EFI_GUID lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_LOADED_IMAGE_PROTOCOL *lip = efi_get_protocol(efi_context->handle, &lip_guid);
+ uint64_t text_base;
+ uint64_t data_base;
+
printf("DEBUG: EFI_LOADED_IMAGE_PROTOCOL { .ImageBase = %p }\n", lip->ImageBase);
__asm__ volatile ("movq %0, %%rax" :: "r"(lip->ImageBase) : "rax");
+ __asm__ volatile (
+ "lea .text, %0\n"
+ "lea .data, %1\n"
+ : "=r"(text_base), "=r"(data_base)
+ :
+ );
+ printf("DEBUG: .text %p .data %p\n", text_base, data_base);
bool wait = true;
while(wait)
diff --git a/boot/fake_syscall_entry.S b/boot/fake_syscall_entry.S
new file mode 100644
index 0000000..ff2428d
--- /dev/null
+++ b/boot/fake_syscall_entry.S
@@ -0,0 +1,25 @@
+.section .text
+
+.extern fake_syscall_handler
+
+.global fake_syscall_entry
+fake_syscall_entry:
+ hlt
+
+.global fake_syscall_return
+fake_syscall_return:
+ cli
+ mov %rdi, %rsp
+ lgdt (%rsp)
+ add $16, %rsp
+
+ movw (%rsp), %ds
+ movw (%rsp), %es
+ movw (%rsp), %fs
+ movw (%rsp), %gs
+ movw (%rsp), %ss
+
+ add $8, %rsp
+
+ lretq
+
diff --git a/boot/kjarna.h b/boot/kjarna.h
index 81bb79b..38a550f 100644
--- a/boot/kjarna.h
+++ b/boot/kjarna.h
@@ -1,7 +1,28 @@
#pragma once
+#pragma once
+
#include <kjarna/interface.h>
int main(int argc, char **argv);
int image_start(void);
+void *malloc(size_t size);
+void *calloc(size_t count, size_t size);
+void free(void *block);
+
+struct image_buffer
+{
+ char *base;
+ size_t length;
+};
+
+struct kjarna_boot_image
+{
+ struct image_buffer buffer;
+ kjarna_image_entry_func *entry;
+};
+
+struct kjarna_interface get_boot_interface(void);
+struct kjarna_boot_image get_boot_image(void);
+
diff --git a/boot/main.c b/boot/main.c
index 38c913f..570b703 100644
--- a/boot/main.c
+++ b/boot/main.c
@@ -1,9 +1,166 @@
#include "kjarna.h"
+#include <stdnoreturn.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 interrupts 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.
+ * 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.
+ */
+
+
+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;
+
+ // maintain alignment
+ *(char **)stack_pointer -= alloc_size % sizeof(size_t);
+
+ 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 },
+ { 0xffff, 0, 0, 0x9a, 0xaf, 0},
+ { 0xffff, 0, 0, 0x92, 0xcf, 0}
+};
+
+static noreturn void fake_syscall_entry(void)
+{
+ while (true);
+}
+
+SYSV_ABI void fake_syscall_return(void *target_rsp);
+
+static void install_syscall_handler(void)
+{
+ union msr_lstar lstar = { fake_syscall_entry };
+ union msr_star star = { { 0, 1 << 3, 1 << 3 | 3 } };
+
+ msr_write(0xc0000082, lstar.value);
+ msr_write(0xc0000081, star.value);
+
+ uint64_t efer = msr_read(0xc0000080);
+ efer |= 1;
+ msr_write(0xc0000080, efer);
+}
+
+struct context_stack_frame
+{
+ struct dtr64 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)
+{
+ size_t boot_stack_size = 0x10000;
+ char *boot_image_stack = calloc(1, boot_stack_size);
+ void *boot_image_stack_head = boot_image_stack + boot_stack_size;
+
+ struct context_stack_frame *stack_frame = stack_alloc(&boot_image_stack_head, sizeof(*stack_frame));
+
+ stack_frame->lret_cs = 8;
+ stack_frame->lret_ds = 16;
+ stack_frame->lret_rip = (uintptr_t)image->entry;
+
+ 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);
+
+ while (true);
+}
+
+#include <libc/stdio.h>
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
- return image_start();
+
+ 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/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c
index f61ed00..da55d38 100644
--- a/kc/core/cpu/cpu.c
+++ b/kc/core/cpu/cpu.c
@@ -81,6 +81,7 @@ static void set_gdt(int index,
case CODE32_USER_SEG:
gdt[index].access = 0xfa;
gdt[index].flags_limit16 |= 0xc0;
+ break;
case DATA_SUPER_SEG:
gdt[index].access = 0x92;
gdt[index].flags_limit16 |= 0xc0;
@@ -88,6 +89,7 @@ static void set_gdt(int index,
case DATA_USER_SEG:
gdt[index].access = 0xf2;
gdt[index].flags_limit16 |= 0xc0;
+ break;
case TASK64_SEG:
gdt[index].access = 0x89;
//TODO: make this cleaner i don't like it
diff --git a/lldbscript b/lldbscript
index 13842b8..3f94ba2 100644
--- a/lldbscript
+++ b/lldbscript
@@ -1,7 +1,7 @@
target create --no-dependents --arch x86_64 boot/kjarna.efi --symfile boot/kjarna.pdb
target modules add service/kjarna.os
gdb-remote localhost:1234
-target modules load --file kjarna.efi .text 0x63ec000 .data 0x63f1000
-target modules load --file kjarna.os --slide 0x63dc000
-b efi_open
+target modules load --file kjarna.efi .text 0x6184000 .data 0x6189000
+target modules load --file kjarna.os --slide 0x6178000
+b enter_boot_image
diff --git a/service/Makefile b/service/Makefile
index 09ff0be..b78cac3 100644
--- a/service/Makefile
+++ b/service/Makefile
@@ -4,7 +4,7 @@ LDFLAGS += -z max-page-size=4096 --export-dynamic -pic \
-z separate-code -pie -Bsymbolic -shared \
-z noexecstack -g
-VPATH := ../lib arch/x86_64/
+VPATH := ../lib arch/x86_64/ lib
TARGET := kjarna.os
.DEFAULT: $(TARGET)
@@ -15,7 +15,7 @@ CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only
LDSCRIPT := kjarna.ld
-CRT_OBJS := start.o rtld_link.o dynamic.o elf64.o kjarna.o
+CRT_OBJS := start.o rtld_link.o dynamic.o elf64.o kjarna.o posix.o
LIB_OBJS := memcmp.o memcpy.o memmove.o memset.o string.o stdio.o \
printf.o heap.o
APP_OBJS := main.o
diff --git a/service/kjarna.c b/service/kjarna.c
index 1240c97..ce9ec54 100644
--- a/service/kjarna.c
+++ b/service/kjarna.c
@@ -4,19 +4,15 @@ struct kjarna_entry_params *entry_params;
extern int main(int argc, char **argv);
-int kjarna_entry(struct kjarna_entry_params *params)
+int kjarna_entry()
{
- entry_params = params;
-
- __asm__ ("leaq kc_image_base(%%rip), %%rax" ::: "rax");
+ uint64_t image_base;
+ __asm__ ("leaq kc_image_base(%%rip), %0" : "=r"(image_base) :: );
bool wait = true;
- while(wait)
- {
- __asm__ volatile("hlt");
- }
+ while(wait);
- return main(params->argc, params->argv);
+ return main(0, nullptr);
}
diff --git a/service/lib/posix.c b/service/lib/posix.c
new file mode 100644
index 0000000..a912977
--- /dev/null
+++ b/service/lib/posix.c
@@ -0,0 +1,19 @@
+#include <unistd.h>
+
+ssize_t write(int fd, const void *buffer, size_t length)
+{
+ ssize_t result;
+
+ __asm__ (
+ "movq %0, %%rdi\n"
+ "movq %1, %%rsi\n"
+ "movq %2, %%rdx\n"
+ "movq $1, %%rax\n"
+ "syscall"
+ : "=a"(result)
+ : "g"(fd), "g"(buffer), "g"(length)
+ : "rdi", "rsi","rdx");
+
+ return result;
+}
+