summaryrefslogtreecommitdiff
path: root/kc
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2023-02-19 23:31:10 +0000
committerAda Christine <adachristine18@gmail.com>2023-02-19 23:31:10 +0000
commit838f39324a1f305562addce6d807400522d9c469 (patch)
tree71304643765fd39bc4e4ba3cb74968735b806f23 /kc
parent2f5e6b2d18b2c0fa09ea8ece0bc13e2f040b4d80 (diff)
preparations for user mode
Diffstat (limited to 'kc')
-rw-r--r--kc/core/cpu/cpu.c107
-rw-r--r--kc/core/cpu/descriptor.h4
-rw-r--r--kc/core/memory.h12
-rw-r--r--kc/core/memory/memory.c44
4 files changed, 106 insertions, 61 deletions
diff --git a/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c
index a3205f7..f61ed00 100644
--- a/kc/core/cpu/cpu.c
+++ b/kc/core/cpu/cpu.c
@@ -15,10 +15,17 @@
#define GDT_ENTRIES 16
#define IDT_ENTRIES 256
-#define CODE_SUPER_SEG_INDEX 1
-#define CODE_USER_SEG_INDEX 2
-#define DATA_SEG_INDEX 3
-#define TASK_SEG_INDEX 4
+enum kernel_segment_indices
+{
+ NULL_SEG,
+ CODE64_SUPER_SEG_INDEX,
+ DATA_SUPER_SEG_INDEX,
+ CODE32_USER_SEG_INDEX,
+ DATA32_USER_SEG_INDEX,
+ CODE64_USER_SEG_INDEX,
+ DATA64_USER_SEG_INDEX,
+ TASK64_SEG_INDEX
+};
#define EFER_SCE 1
@@ -28,6 +35,13 @@
#define MSR_CSTAR 0xc0000083
#define MSR_SFMASK 0xc0000084
+struct cpu_state
+{
+ struct segment_descriptor gdt[GDT_ENTRIES];
+ struct gate_descriptor idt[IDT_ENTRIES];
+ struct task64_segment tss;
+};
+
static struct segment_descriptor gdt[GDT_ENTRIES];
static struct gate_descriptor idt[IDT_ENTRIES];
static struct task64_segment tss;
@@ -64,10 +78,16 @@ static void set_gdt(int index,
gdt[index].access = 0xfa;
gdt[index].flags_limit16 |= 0xa0;
break;
- case DATA_SEG:
+ case CODE32_USER_SEG:
+ gdt[index].access = 0xfa;
+ gdt[index].flags_limit16 |= 0xc0;
+ case DATA_SUPER_SEG:
gdt[index].access = 0x92;
gdt[index].flags_limit16 |= 0xc0;
break;
+ case DATA_USER_SEG:
+ gdt[index].access = 0xf2;
+ gdt[index].flags_limit16 |= 0xc0;
case TASK64_SEG:
gdt[index].access = 0x89;
//TODO: make this cleaner i don't like it
@@ -130,8 +150,7 @@ static void gdt_flush(uint16_t code_seg, uint16_t data_seg)
"push %q0\n"
"lea .Lflush(%%rip), %%rax\n"
"push %%rax\n"
- // far return, now we're in the code segment
- // defined here.
+ // far return, now we're in the provided code segment
"lretq\n"
".Lflush:\n"
:
@@ -162,41 +181,46 @@ static void gdt_load(struct dtr64 gdtr)
(
"lgdt %0\n"
:
- : "m"(gdtr)
+ :
+ "m"(gdtr)
);
irq_unlock(rflags);
}
-static void gdt_init(void)
+static struct dtr64 gdt_init(void)
{
- 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);
+ set_gdt(CODE64_SUPER_SEG_INDEX, 0, (uint64_t)-1, CODE64_SUPER_SEG);
+ set_gdt(DATA_SUPER_SEG_INDEX, 0, (uint64_t)-1, DATA_SUPER_SEG);
+ set_gdt(CODE32_USER_SEG_INDEX, 0, (uint64_t)-1, CODE32_USER_SEG);
+ set_gdt(DATA32_USER_SEG_INDEX, 0, (uint64_t)-1, DATA_USER_SEG);
+ set_gdt(CODE64_USER_SEG_INDEX, 0, (uint64_t)-1, CODE64_USER_SEG);
+ set_gdt(DATA64_USER_SEG_INDEX, 0, (uint64_t)-1, DATA_USER_SEG);
+ set_gdt(TASK64_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG);
struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt};
+
gdt_load(gdtr);
- gdt_flush(CODE_SUPER_SEG_INDEX, DATA_SEG_INDEX);
- gdt_load_task(TASK_SEG_INDEX);
-}
+ gdt_flush(CODE64_SUPER_SEG_INDEX, DATA_SUPER_SEG_INDEX);
+ gdt_load_task(TASK64_SEG_INDEX);
+ return gdtr;
+}
-static void idt_init(void)
+static struct dtr64 idt_init(void)
{
struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt};
+ uint64_t rflags = irq_lock();
__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)
+ :
+ :
+ "m"(idtr)
);
+ irq_unlock(rflags);
+
+ return idtr;
}
void cpu_init(void)
@@ -207,7 +231,7 @@ void cpu_init(void)
//TODO: fix rudimentary syscall stuff.
- uint64_t lstar_bits = (uintptr_t)syscall_entry;
+ uintptr_t lstar_bits = (uintptr_t)syscall_entry;
msr_write(MSR_LSTAR, lstar_bits);
union
@@ -215,10 +239,8 @@ void cpu_init(void)
struct
{
uint32_t eip32;
- uint8_t syscall_ss;
- uint8_t syscall_cs;
- uint8_t sysret_ss;
- uint8_t sysret_cs;
+ uint16_t syscall_cs;
+ uint16_t sysret_cs;
}
fields;
uint64_t raw;
@@ -227,10 +249,8 @@ void cpu_init(void)
{
{
0,
- DATA_SEG_INDEX,
- CODE_SUPER_SEG_INDEX,
- DATA_SEG_INDEX,
- CODE_USER_SEG_INDEX
+ CODE64_SUPER_SEG_INDEX << 3,
+ CODE32_USER_SEG_INDEX << 3 | 3
}
};
@@ -253,15 +273,10 @@ void exceptions_init(void)
void isr_install(int vec, void (*isr)(void), int trap, unsigned ist)
{
- enum gate_descriptor_type type = INT64_GATE;
+ enum gate_descriptor_type type = trap ? TRAP64_GATE : INT64_GATE;
- if (trap)
- {
- type = TRAP64_GATE;
- }
+ set_idt(vec, CODE64_SUPER_SEG_INDEX << 3, (uintptr_t)isr, type);
- set_idt(vec, CODE_SUPER_SEG_INDEX << 3, (uintptr_t)isr, type);
- // an IST greater than 7 is invalid
if (ist && ist <= 7)
{
set_ist(vec, ist);
@@ -277,13 +292,3 @@ void ist_install(int ist, void *stack)
tss.ist[ist] = (uintptr_t)stack;
}
-void int_enable(void)
-{
- __asm__ ("sti");
-}
-
-void int_disable(void)
-{
- __asm__ ("cli");
-}
-
diff --git a/kc/core/cpu/descriptor.h b/kc/core/cpu/descriptor.h
index 802c09c..c2a95ac 100644
--- a/kc/core/cpu/descriptor.h
+++ b/kc/core/cpu/descriptor.h
@@ -20,8 +20,10 @@ enum segment_descriptor_type
{
CODE64_SUPER_SEG,
CODE64_USER_SEG,
- DATA_SEG,
+ DATA_SUPER_SEG,
TASK64_SEG,
+ CODE32_USER_SEG,
+ DATA_USER_SEG
};
struct gate_descriptor
diff --git a/kc/core/memory.h b/kc/core/memory.h
index 1303a99..6f70e57 100644
--- a/kc/core/memory.h
+++ b/kc/core/memory.h
@@ -19,10 +19,13 @@ enum page_map_flags
CONTENT_RWDATA = 0x3,
CONTENT_MASK = 0x3,
- SIZE_4K = 0x4,
- SIZE_2M = 0x8,
- SIZE_1G = 0xc,
- SIZE_MASK = 0xc,
+ PRIV_USER = 0x4,
+ PRIV_MASK = 0x4,
+
+ SIZE_4K = 0x8,
+ SIZE_2M = 0x10,
+ SIZE_1G = 0x18,
+ SIZE_MASK = 0x18,
};
enum page_alloc_flags
@@ -60,6 +63,7 @@ int page_inc_ref(kc_phys_addr page);
int page_dec_ref(kc_phys_addr page);
void *page_map(phys_addr_t paddr, enum page_map_flags flags);
+void *page_set_flags(void *vaddr, enum page_map_flags flags);
void page_unmap(void *vaddr);
phys_addr_t page_alloc(enum page_alloc_flags flags);
diff --git a/kc/core/memory/memory.c b/kc/core/memory/memory.c
index 06c2942..f50752f 100644
--- a/kc/core/memory/memory.c
+++ b/kc/core/memory/memory.c
@@ -136,7 +136,9 @@ void page_free(kc_phys_addr page)
page_stack_free(page);
}
-static void *map_tableset(void *vaddr, uint64_t *tables[4])
+#define TABLESET_COUNT 3
+
+static void *map_tableset(void *vaddr, uint64_t *tables[TABLESET_COUNT])
{
uint64_t current_phys;
uint64_t *current_pte;
@@ -144,8 +146,8 @@ static void *map_tableset(void *vaddr, uint64_t *tables[4])
//
current_phys = page_address(mmu_get_map(), 1);
- tables[3] = temp_page_map(current_phys, CONTENT_RWDATA);
- int n = 3;
+ tables[TABLESET_COUNT] = temp_page_map(current_phys, CONTENT_RWDATA);
+ int n = TABLESET_COUNT;
while (n)
{
@@ -185,6 +187,32 @@ static void *map_tableset(void *vaddr, uint64_t *tables[4])
return vaddr;
}
+void *page_set_flags(void *vaddr, enum page_map_flags flags)
+{
+ uint64_t *mapset[PAGE_MAP_LEVELS] = {NULL};
+
+ if (vaddr != map_tableset(vaddr, mapset))
+ {
+ PANIC(GENERAL_PANIC);
+ }
+
+ if (flags & PRIV_MASK)
+ {
+ mapset[3][pte_index(vaddr, 4)] |= PAGE_US;
+ mapset[2][pte_index(vaddr, 3)] |= PAGE_US;
+ mapset[1][pte_index(vaddr, 2)] |= PAGE_US;
+ mapset[0][pte_index(vaddr, 1)] |= PAGE_US;
+ }
+
+ for(int i = 0; i < PAGE_MAP_LEVELS; i++)
+ {
+ if (mapset[i])
+ temp_page_unmap(mapset[i]);
+ }
+
+ return vaddr;
+}
+
static void *page_map_at(
void *vaddr,
phys_addr_t paddr,
@@ -192,7 +220,7 @@ static void *page_map_at(
{
// TODO: add checks to prevent attempts to map reserved addreses
//
- uint64_t *mapset[4] = {NULL};
+ uint64_t *mapset[PAGE_MAP_LEVELS] = {NULL};
if (vaddr != map_tableset(vaddr, mapset))
{
@@ -230,12 +258,18 @@ static void *page_map_at(
default:
vaddr = NULL;
}
+
+ if (flags & PRIV_MASK)
+ {
+ entry |= PAGE_US;
+ }
+
if (vaddr)
{
mapset[0][pte_index(vaddr, 1)] = page_address(paddr, 1) | entry;
}
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < PAGE_MAP_LEVELS; i++)
{
if (mapset[i])
{