summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2021-06-25 16:22:43 +0200
committerdzwdz2021-06-25 16:22:43 +0200
commitf60d40f3bf4dfe8ed6f63a27367d323319a4ef97 (patch)
tree1cde54eb600106d0d1fc11927f55d5a03eb2b4aa
parent376325d08388d9103ca2f57aceb60c4a507a42aa (diff)
ring3
-rw-r--r--Makefile6
-rw-r--r--kernel/gdt.c20
-rw-r--r--kernel/gdt.h12
-rw-r--r--kernel/main.c16
-rw-r--r--kernel/util.c9
-rw-r--r--kernel/util.h4
-rw-r--r--platform/sysenter.h4
-rw-r--r--platform/sysenter.s31
8 files changed, 86 insertions, 16 deletions
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 <kernel/gdt.h>
#include <kernel/tty.h>
+#include <kernel/util.h>
#include <stdint.h>
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 <kernel/gdt.h>
#include <kernel/tty.h>
+#include <platform/sysenter.h>
+
+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 <kernel/util.h>
+#include <stdint.h>
+
+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 <stddef.h>
+
+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