summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/cpu/cpu.c3
-rw-r--r--kernel/cpu/tss.S6
-rw-r--r--kernel/cpu/tss.c80
-rw-r--r--kernel/cpu/tss.h31
-rw-r--r--kernel/entry.S5
5 files changed, 124 insertions, 1 deletions
diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c
index 136a1d8..6ef5ef5 100644
--- a/kernel/cpu/cpu.c
+++ b/kernel/cpu/cpu.c
@@ -3,6 +3,7 @@
#include "pic.h"
#include "idt.h"
+#include "tss.h"
static inline void fpu_init(void)
{
@@ -73,6 +74,8 @@ void cpu_init(void)
if (feats.avx)
avx_init();
}
+
+ tss_init();
}
void cpu_report(void)
diff --git a/kernel/cpu/tss.S b/kernel/cpu/tss.S
new file mode 100644
index 0000000..27f2955
--- /dev/null
+++ b/kernel/cpu/tss.S
@@ -0,0 +1,6 @@
+ .globl tss_flush
+
+tss_flush:
+ movw $0x28, %ax
+ ltr %ax
+ ret
diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c
new file mode 100644
index 0000000..bda713b
--- /dev/null
+++ b/kernel/cpu/tss.c
@@ -0,0 +1,80 @@
+#include "lib/kstring.h"
+#include <stdint.h>
+
+#include "tss.h"
+
+struct sys_seg_descriptor {
+ uint64_t limit0_15 : 16;
+ uint64_t base0_15 : 16;
+ uint64_t base16_23 : 8;
+ uint64_t type : 4;
+ uint64_t : 1;
+ uint64_t DPL : 2;
+ uint64_t present : 1;
+ uint64_t limit16_19: 4;
+ uint64_t available : 1;
+ uint64_t : 1;
+ uint64_t : 1;
+ uint64_t gran : 1;
+ uint64_t base24_31 : 8;
+ uint64_t base32_63 : 32;
+ uint64_t : 32;
+} __attribute__((packed));
+
+struct tss {
+ uint64_t : 32;
+ uint64_t rsp0 : 64;
+ uint64_t rsp1 : 64;
+ uint64_t rsp2 : 64;
+ uint64_t : 64;
+ uint64_t ist1 : 64;
+ uint64_t ist2 : 64;
+ uint64_t ist3 : 64;
+ uint64_t ist4 : 64;
+ uint64_t ist5 : 64;
+ uint64_t ist6 : 64;
+ uint64_t ist7 : 64;
+ uint64_t : 64;
+ uint64_t : 16;
+ uint64_t iopb : 16;
+} __attribute__((packed));
+
+// tss entry
+static volatile struct tss tss;
+
+// gdt entries
+extern volatile uint8_t GDT[];
+static volatile struct sys_seg_descriptor *GDT_TSS;
+
+// kernel stack pointer
+extern char kern_stack_end[];
+
+void tss_init(void) {
+ uint64_t base = (uint64_t) &tss;
+ uint64_t limit = sizeof tss - 1;
+
+ // setup tss entry
+ memsetv(&tss, 0, sizeof(struct tss));
+ tss.rsp0 = (uint64_t) kern_stack_end;
+
+ // map tss into gdt
+ GDT_TSS = (volatile struct sys_seg_descriptor *) (GDT + 0x28);
+ memsetv(GDT_TSS, 0, sizeof(struct sys_seg_descriptor));
+ GDT_TSS->limit0_15 = limit & 0xFFFF;
+ GDT_TSS->base0_15 = base & 0xFFFF;
+ GDT_TSS->base16_23 = (base >> 16) & 0xFF;
+ GDT_TSS->type = 0x9;
+ GDT_TSS->DPL = 0;
+ GDT_TSS->present = 1;
+ GDT_TSS->limit16_19 = (limit >> 16) & 0xF;
+ GDT_TSS->available = 0;
+ GDT_TSS->gran = 0;
+ GDT_TSS->base24_31 = (base >> 24) & 0xFF;
+ GDT_TSS->base32_63 = (base >> 32) & 0xFFFFFFFF;
+
+ tss_flush();
+}
+
+void tss_set_stack(uint64_t stack) {
+ tss.rsp0 = stack;
+}
diff --git a/kernel/cpu/tss.h b/kernel/cpu/tss.h
new file mode 100644
index 0000000..f17b619
--- /dev/null
+++ b/kernel/cpu/tss.h
@@ -0,0 +1,31 @@
+/**
+ * @file tss.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * TSS functions
+ */
+
+#ifndef TSS_H_
+#define TSS_H_
+
+#define TSS_REMAP_OFFSET 0x20
+
+#include <stdint.h>
+
+/**
+ * Load the TSS selector
+ */
+void tss_init(void);
+
+/**
+ * Flush the tss
+ */
+void tss_flush(void);
+
+/**
+ * Set the kernel stack pointer in the tss
+ */
+void tss_set_stack(uint64_t stack);
+
+#endif /* tss.h */
diff --git a/kernel/entry.S b/kernel/entry.S
index aa4c38d..4b5415b 100644
--- a/kernel/entry.S
+++ b/kernel/entry.S
@@ -7,8 +7,10 @@
.globl kernel_pd_0_ents
.globl kernel_pd_1
.globl paging_pt
+ .globl GDT
+ .globl kern_stack_end
+ .globl kern_stack_start
.extern main
- .extern GDT
.section .multiboot
@@ -155,6 +157,7 @@ GDT:
# TSS segment (0x28)
.equ GDT.TSS, . - GDT
+ .quad 0
.quad 0 # to be modified in kernel
# GDT Pointer