From f60d40f3bf4dfe8ed6f63a27367d323319a4ef97 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 25 Jun 2021 16:22:43 +0200 Subject: ring3 --- Makefile | 6 +++--- kernel/gdt.c | 20 +++++++------------- kernel/gdt.h | 12 ++++++++++++ kernel/main.c | 16 ++++++++++++++++ kernel/util.c | 9 +++++++++ kernel/util.h | 4 ++++ platform/sysenter.h | 4 ++++ platform/sysenter.s | 31 +++++++++++++++++++++++++++++++ 8 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 kernel/util.c create mode 100644 kernel/util.h create mode 100644 platform/sysenter.h create mode 100644 platform/sysenter.s diff --git a/Makefile b/Makefile index a1f9899..605b112 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ CC = i686-elf-gcc CFLAGS = -std=gnu99 -ffreestanding -O2 -Wall -Wextra CFLAGS += -I. LFLAGS = -ffreestanding -O2 -nostdlib -lgcc -QFLAGS = -no-reboot -d guest_errors +QFLAGS = -no-reboot -d guest_errors,int,pcall,cpu_reset -OBJ = platform/boot.o +OBJ = $(patsubst %.s,%.o,$(wildcard platform/*.s)) OBJ += $(patsubst %.c,%.o,$(wildcard kernel/*.c)) @@ -27,7 +27,7 @@ kernel.bin: $(OBJ) $(CC) $(LFLAGS) -T linker.ld $^ -o $@ grub-file --is-x86-multiboot $@ -platform/boot.o: platform/boot.s +platform/%.o: platform/%.s $(AS) $^ -o $@ %.o: %.c diff --git a/kernel/gdt.c b/kernel/gdt.c index 8d1ac65..8a29032 100644 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -1,4 +1,6 @@ +#include #include +#include #include extern void stack_top; // platform/boot.s @@ -36,16 +38,6 @@ struct lgdt_arg { uint32_t base; } __attribute__((packed)); -enum { - SEG_null, - SEG_r0data, - SEG_r0code, - SEG_r3data, - SEG_r3code, - SEG_TSS, - - SEG_end -}; static struct gdt_entry GDT[SEG_end]; static struct tss_entry TSS; static struct lgdt_arg lgdt_arg; // probably doesn't need to be global @@ -84,7 +76,7 @@ static void gdt_prepare() { GDT[SEG_r3data].ring = 3; // tss - // TODO memset(&TSS, 0, sizeof(TSS)); + memset(&TSS, 0, sizeof(TSS)); TSS.ss0 = SEG_r0data << SEG_r3data; // kernel data segment TSS.esp0 = (uint32_t) &stack_top; @@ -108,13 +100,15 @@ static void gdt_prepare() { static void gdt_load() { lgdt_arg.limit = sizeof(GDT) - 1; lgdt_arg.base = (uint32_t) &GDT; - asm("lgdt (%0)" : : "b" (&lgdt_arg)); + asm("lgdt (%0)" : : "r" (&lgdt_arg) : "memory"); + + asm("ltr %%ax" : : "a" (SEG_TSS << 3 | 3) : "memory"); } static void gdt_check() { tty_write("checking gdt...", 15); asm("mov %0, %%ds;" - : : "r" (SEG_r0data << 3)); + : : "r" (SEG_r0data << 3) : "memory"); tty_write("ok", 2); } diff --git a/kernel/gdt.h b/kernel/gdt.h index 9ae366c..9e5a6a5 100644 --- a/kernel/gdt.h +++ b/kernel/gdt.h @@ -1,3 +1,15 @@ #pragma once +enum { + SEG_null, + // order dictated by SYSENTER + SEG_r0code, + SEG_r0data, + SEG_r3code, + SEG_r3data, + SEG_TSS, + + SEG_end +}; + void gdt_init(); diff --git a/kernel/main.c b/kernel/main.c index d2f0693..e63ca14 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,8 +1,24 @@ #include #include +#include + +extern void stack_top; + +void r3_test(); void kmain() { tty_clear(); gdt_init(); + sysenter_setup(); + + tty_write("user...", 7); + sysexit(r3_test, &stack_top); +} + +void r3_test() { + tty_write("in ring3", 8); + asm("cli"); // privileged instruction, should cause a GP + tty_write(" oh no", 6); // shouldn't happen + for (;;) {} } diff --git a/kernel/util.c b/kernel/util.c new file mode 100644 index 0000000..da3ac9d --- /dev/null +++ b/kernel/util.c @@ -0,0 +1,9 @@ +#include +#include + +void *memset(void *s, int c, size_t n) { + uint8_t *s2 = s; + for (size_t i = 0; i < n; n++) + s2[i] = c; + return s; +} diff --git a/kernel/util.h b/kernel/util.h new file mode 100644 index 0000000..688ac63 --- /dev/null +++ b/kernel/util.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void *memset(void *s, int c, size_t n); diff --git a/platform/sysenter.h b/platform/sysenter.h new file mode 100644 index 0000000..b0495cc --- /dev/null +++ b/platform/sysenter.h @@ -0,0 +1,4 @@ +#pragma once + +void sysexit(void (*fun)(), void *stack_top); +void sysenter_setup(); diff --git a/platform/sysenter.s b/platform/sysenter.s new file mode 100644 index 0000000..270dc08 --- /dev/null +++ b/platform/sysenter.s @@ -0,0 +1,31 @@ +/* kernel/gdt.c */ +.set SEG_r0code, 1 +.set SEG_r3code, 3 +.set SEG_r3data, 4 + +.set IA32_SYSENTER_CS, 0x174 + +.section .text +.global sysexit +.type sysexit, @function +sysexit: + pop %ecx + pop %edx + + mov $(SEG_r3data << 3 | 3), %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + sysexit + + +.global sysenter_setup +.type sysenter_setup, @function +sysenter_setup: + xor %edx, %edx + mov $(SEG_r0code << 3), %eax + mov $IA32_SYSENTER_CS, %ecx + wrmsr + ret -- cgit v1.2.3