summaryrefslogtreecommitdiff
path: root/kc
diff options
context:
space:
mode:
Diffstat (limited to 'kc')
-rw-r--r--kc/core/cpu.c201
-rw-r--r--kc/core/cpu.h6
2 files changed, 149 insertions, 58 deletions
diff --git a/kc/core/cpu.c b/kc/core/cpu.c
index ed1a04e..7b3b95b 100644
--- a/kc/core/cpu.c
+++ b/kc/core/cpu.c
@@ -1,14 +1,24 @@
#include "cpu.h"
#include "exceptions.h"
+#include "kprint.h"
+#include "panic.h"
#include <stdint.h>
#define GDT_ENTRIES 16
#define IDT_ENTRIES 256
-#define CODE_SEG_INDEX 1
-#define DATA_SEG_INDEX 2
-#define TASK_SEG_INDEX 3
+#define CODE_SUPER_SEG_INDEX 1
+#define CODE_USER_SEG_INDEX 2
+#define DATA_SEG_INDEX 3
+#define TASK_SEG_INDEX 4
+
+#define MSR_EFER 0xc0000080
+#define MSR_STAR 0xc0000081
+#define MSR_LSTAR 0xc0000082
+#define MSR_CSTAR 0xc0000083
+#define MSR_SFMASK 0xc0000084
+
struct dtr64
{
@@ -28,7 +38,8 @@ struct segment_descriptor
enum segment_descriptor_type
{
- CODE64_SEG,
+ CODE64_SUPER_SEG,
+ CODE64_USER_SEG,
DATA_SEG,
TASK64_SEG,
};
@@ -65,23 +76,33 @@ static struct segment_descriptor gdt[GDT_ENTRIES];
static struct gate_descriptor idt[IDT_ENTRIES];
static struct task64_segment tss;
+static void syscall_entry(void)
+{
+ kputs("system call\n");
+ halt();
+}
+
static void set_gdt(int index,
- uint64_t base,
- uint64_t limit,
- enum segment_descriptor_type type)
+ uint64_t base,
+ uint64_t limit,
+ enum segment_descriptor_type type)
{
gdt[index].limit0 = limit & 0xffff;
gdt[index].base0 = base & 0xffff;
gdt[index].base16 = (base >> 16) & 0xff;
gdt[index].flags_limit16 = (limit >> 16) & 0xf;
gdt[index].base24 = (base >> 24) & 0xff;
-
+
switch (type)
{
- case CODE64_SEG:
+ case CODE64_SUPER_SEG:
gdt[index].access = 0x9a;
gdt[index].flags_limit16 |= 0xa0;
break;
+ case CODE64_USER_SEG:
+ gdt[index].access = 0xfa;
+ gdt[index].flags_limit16 |= 0xa0;
+ break;
case DATA_SEG:
gdt[index].access = 0x92;
gdt[index].flags_limit16 |= 0xc0;
@@ -96,9 +117,9 @@ static void set_gdt(int index,
}
static void set_idt(int vec,
- uint16_t selector,
- uint64_t offset,
- enum gate_descriptor_type type)
+ uint16_t selector,
+ uint64_t offset,
+ enum gate_descriptor_type type)
{
idt[vec].offset0 = offset & 0xffff;
idt[vec].selector = selector;
@@ -124,61 +145,62 @@ void set_ist(int vec, int ist_index)
static void gdt_init(void)
{
- set_gdt(CODE_SEG_INDEX, 0, (uint64_t)-1, CODE64_SEG);
+ set_gdt(CODE_SUPER_SEG_INDEX, 0, (uint64_t)-1, CODE64_SUPER_SEG);
+ set_gdt(CODE_USER_SEG_INDEX, 0, (uint64_t)-1, CODE64_USER_SEG);
set_gdt(DATA_SEG_INDEX, 0, (uint64_t)-1, DATA_SEG);
set_gdt(TASK_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG);
struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt};
__asm__ volatile
- (
- // can't have interrupts during GDT reload
- // but don't re-enable interrupts if they were already disabled
- "pushf\n"
- "cli\n"
- "lgdt %0\n"
- "mov %w2, %%ds\n"
- "mov %w2, %%es\n"
- "mov %w2, %%fs\n"
- "mov %w2, %%gs\n"
- "mov %w2, %%ss\n"
- // make a far return frame on the stack
- // [ss] @rsp+8
- // [rip] @rsp
- "pushq %1\n"
- "lea .Lflush(%%rip), %%rax\n"
- "push %%rax\n"
- // far return, now we're in the code segment
- // defined here.
- "lretq\n"
- ".Lflush:\n"
- "ltr %w3\n"
- "popf\n"
- // dependency on pre-boot GDT is now gone
- :
- : "m"(gdtr),
- "i"(CODE_SEG_INDEX << 3),
- "r"(DATA_SEG_INDEX << 3),
- "r"(TASK_SEG_INDEX << 3)
- );
+ (
+ // can't have interrupts during GDT reload
+ // but don't re-enable interrupts if they were already disabled
+ "pushf\n"
+ "cli\n"
+ "lgdt %0\n"
+ "mov %w2, %%ds\n"
+ "mov %w2, %%es\n"
+ "mov %w2, %%fs\n"
+ "mov %w2, %%gs\n"
+ "mov %w2, %%ss\n"
+ // make a far return frame on the stack
+ // [ss] @rsp+8
+ // [rip] @rsp
+ "pushq %1\n"
+ "lea .Lflush(%%rip), %%rax\n"
+ "push %%rax\n"
+ // far return, now we're in the code segment
+ // defined here.
+ "lretq\n"
+ ".Lflush:\n"
+ "ltr %w3\n"
+ "popf\n"
+ // dependency on pre-boot GDT is now gone
+ :
+ : "m"(gdtr),
+ "i"(CODE_SUPER_SEG_INDEX << 3),
+ "r"(DATA_SEG_INDEX << 3),
+ "r"(TASK_SEG_INDEX << 3)
+ );
}
static void idt_init(void)
{
struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt};
-
+
__asm__ volatile
- (
- // can't have interrupts enabled during IDT reload--obviously.
- // as with GDT don't re-enable interrupts if they were already
- // disabled.
- "pushf\n"
- "cli\n"
- "lidt %0\n"
- "popf\n"
- // much more straightforward than the gdt code.
- :: "m"(idtr)
- );
+ (
+ // can't have interrupts enabled during IDT reload--obviously.
+ // as with GDT don't re-enable interrupts if they were already
+ // disabled.
+ "pushf\n"
+ "cli\n"
+ "lidt %0\n"
+ "popf\n"
+ // much more straightforward than the gdt code.
+ :: "m"(idtr)
+ );
}
void cpu_init(void)
@@ -186,6 +208,41 @@ void cpu_init(void)
gdt_init();
idt_init();
exceptions_init();
+
+ //TODO: fix rudimentary syscall stuff.
+
+ uint64_t lstar_bits = (uintptr_t)syscall_entry;
+ msr_write(MSR_LSTAR, lstar_bits);
+
+ union
+ {
+ struct
+ {
+ uint32_t eip32;
+ uint8_t syscall_ss;
+ uint8_t syscall_cs;
+ uint8_t sysret_ss;
+ uint8_t sysret_cs;
+ }
+ fields;
+ uint64_t raw;
+ }
+ star_bits =
+ {
+ {
+ 0,
+ DATA_SEG_INDEX,
+ CODE_SUPER_SEG_INDEX,
+ DATA_SEG_INDEX,
+ CODE_USER_SEG_INDEX
+ }
+ };
+
+ msr_write(MSR_STAR, star_bits.raw);
+
+ uint64_t efer_bits = msr_read(MSR_EFER);
+ efer_bits |= 1; // enable syscall extensions
+ msr_write(MSR_EFER, efer_bits);
}
void exceptions_init(void)
@@ -196,13 +253,13 @@ void exceptions_init(void)
void isr_install(int vec, void (*isr)(void), int trap, int ist)
{
enum gate_descriptor_type type = INT64_GATE;
-
+
if (trap)
{
type = TRAP64_GATE;
}
-
- set_idt(vec, CODE_SEG_INDEX << 3, (uint64_t)isr, type);
+
+ set_idt(vec, CODE_SUPER_SEG_INDEX << 3, (uint64_t)isr, type);
if (ist)
{
set_ist(vec, ist);
@@ -223,3 +280,31 @@ void int_disable(void)
{
__asm__ ("cli");
}
+
+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;
+}
+
+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)
+ );
+}
+
diff --git a/kc/core/cpu.h b/kc/core/cpu.h
index 56a4073..2d5e134 100644
--- a/kc/core/cpu.h
+++ b/kc/core/cpu.h
@@ -1,5 +1,7 @@
#pragma once
+#include <stdint.h>
+
void cpu_init(void);
void isr_install(int vec, void (*isr)(void), int ist, int trap);
@@ -7,3 +9,7 @@ void ist_install(int ist, void *stack);
void int_enable(void);
void int_disable(void);
+
+uint64_t msr_read(uint32_t index);
+void msr_write(uint32_t index, uint64_t value);
+