Bläddra i källkod

feat: set new gdt and tss

greatbridf 3 år sedan
förälder
incheckning
682a1ebb2d
8 ändrade filer med 159 tillägg och 7 borttagningar
  1. 1 1
      include/asm/boot.h
  2. 5 0
      include/asm/sys.h
  3. 20 0
      include/kernel/mem.h
  4. 16 0
      include/kernel/task.h
  5. 3 0
      include/kernel_main.h
  6. 48 0
      src/asm/sys.s
  7. 62 6
      src/kernel/mem.c
  8. 4 0
      src/kernel_main.c

+ 1 - 1
include/asm/boot.h

@@ -2,7 +2,7 @@
 
 #include <types/stdint.h>
 
-struct gdt_descriptor {
+struct __attribute__((__packed__)) gdt_descriptor {
     uint16_t size;
     uint32_t address;
 };

+ 5 - 0
include/asm/sys.h

@@ -8,6 +8,11 @@ extern "C" {
 
 void asm_enable_paging(page_directory_entry* pd_addr);
 
+// the limit should be set on the higher 16bit
+void asm_load_gdt(uint32_t limit, uint32_t addr);
+
+void asm_load_tr(uint16_t index);
+
 #ifdef __cplusplus
 }
 #endif

+ 20 - 0
include/kernel/mem.h

@@ -108,6 +108,26 @@ typedef union page_table_entry {
 
 void init_paging(void);
 
+#define SD_TYPE_CODE_SYSTEM (0x9a)
+#define SD_TYPE_DATA_SYSTEM (0x92)
+
+#define SD_TYPE_CODE_USER (0xfa)
+#define SD_TYPE_DATA_USER (0xf2)
+
+#define SD_TYPE_TSS (0x89)
+
+typedef struct segment_descriptor_struct {
+    uint64_t limit_low : 16;
+    uint64_t base_low : 16;
+    uint64_t base_mid : 8;
+    uint64_t access : 8;
+    uint64_t limit_high : 4;
+    uint64_t flags : 4;
+    uint64_t base_high : 8;
+} segment_descriptor;
+
+void init_gdt_with_tss(void* kernel_esp, uint16_t kernel_ss);
+
 #ifdef __cplusplus
 }
 #endif

+ 16 - 0
include/kernel/task.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tss32_t {
+    uint32_t backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
+    uint32_t eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
+    uint32_t es, cs, ss, ds, fs, gs;
+    uint32_t ldtr, iomap;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 3 - 0
include/kernel_main.h

@@ -2,4 +2,7 @@
 
 #define MAKE_BREAK_POINT() asm volatile("xchgw %bx, %bx")
 
+#define KERNEL_STACK_SIZE (16 * 1024)
+#define KERNEL_STACK_SEGMENT (0x10)
+
 void kernel_main(void);

+ 48 - 0
src/asm/sys.s

@@ -15,3 +15,51 @@ asm_enable_paging:
     movl %eax, %cr0
 
     ret
+
+.global asm_load_gdt
+.type   asm_load_gdt @function
+asm_load_gdt:
+    cli
+    leal 6(%esp), %eax
+    lgdt (%eax)
+    ljmp $0x08, $_asm_load_gdt_fin
+_asm_load_gdt_fin:
+    sti
+    ret
+
+.global asm_load_tr
+.type   asm_load_tr @function
+asm_load_tr:
+    cli
+    movl 4(%esp), %eax
+    orl $0, %eax
+    ltr %ax
+    sti
+    ret
+
+
+# examples for going ring 3
+_test_user_space_program:
+    movl $0x1919810, %eax
+    movl $0xc48c, %ecx
+_reap:
+    cmpl $1000, (%ecx)
+    jl _reap
+_fault:
+    cli
+
+go_user_space_example:
+    movl $((4 * 8) | 3), %eax
+    movw %ax, %ds
+    movw %ax, %es
+    movw %ax, %fs
+    movw %ax, %gs
+
+    movl %esp, %eax
+    pushl $((4 * 8) | 3)
+    pushl %eax
+    pushf
+    pushl $((3 * 8) | 3)
+    pushl $_test_user_space_program
+
+    iret

+ 62 - 6
src/kernel/mem.c

@@ -1,12 +1,18 @@
+#include <asm/boot.h>
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <kernel/errno.h>
 #include <kernel/mem.h>
+#include <kernel/task.h>
 #include <kernel/vga.h>
 #include <kernel_main.h>
 
 static void* p_start;
 static void* p_break;
+static segment_descriptor* gdt;
+
+// temporary
+static struct tss32_t _tss;
 
 static int32_t set_heap_start(void* start_addr)
 {
@@ -163,12 +169,20 @@ static page_directory_entry* _kernel_pd = KERNEL_PAGE_DIRECTORY_ADDR;
 static inline void _create_kernel_pt(int32_t index)
 {
     page_table_entry* pt = KERNEL_PAGE_TABLE_START_ADDR + index * 0x1000;
+
+    // 0xc0000000 ~ 0xffffffff is mapped as kernel space
+    // from physical address 0 to
+    int32_t is_kernel = (index >= 768);
+    if (is_kernel) {
+        index -= 768;
+    }
+
     for (int32_t i = 0; i < 1024; ++i) {
-        pt[i].v = 0b00000011;
-        // 0xc0000000 ~ 0xffffffff is mapped as kernel space
-        // from physical address 0 to
-        if (index >= 768)
-            index -= 768;
+        if (is_kernel) {
+            pt[i].v = 0b00000011;
+        } else {
+            pt[i].v = 0b00000111;
+        }
         pt[i].in.addr = ((index * 0x400000) + i * 0x1000) >> 12;
     }
 }
@@ -176,7 +190,11 @@ static inline void _create_kernel_pt(int32_t index)
 static inline void _create_kernel_pd(void)
 {
     for (int32_t i = 0; i < 1024; ++i) {
-        _kernel_pd[i].v = 0b00000011;
+        if (i >= 768) {
+            _kernel_pd[i].v = 0b00000011;
+        } else {
+            _kernel_pd[i].v = 0b00000111;
+        }
         _kernel_pd[i].in.addr = ((uint32_t)(KERNEL_PAGE_TABLE_START_ADDR + i * 0x1000) >> 12);
         _create_kernel_pt(i);
     }
@@ -187,3 +205,41 @@ void init_paging(void)
     _create_kernel_pd();
     asm_enable_paging(_kernel_pd);
 }
+
+static inline void
+set_segment_descriptor(
+    segment_descriptor* sd,
+    uint32_t base,
+    uint32_t limit,
+    uint8_t access,
+    uint8_t flags)
+{
+    sd->access = access;
+    sd->flags = flags;
+    sd->base_low = base;
+    sd->base_mid = base >> 16;
+    sd->base_high = base >> 24;
+    sd->limit_low = limit;
+    sd->limit_high = limit >> 16;
+}
+
+void init_gdt_with_tss(void* kernel_esp, uint16_t kernel_ss)
+{
+    gdt = k_malloc(sizeof(segment_descriptor) * 6);
+    // since the size in the struct is an OFFSET
+    // it needs to be added one to get its real size
+    uint16_t asm_gdt_size = (asm_gdt_descriptor.size + 1) / 8;
+    segment_descriptor* asm_gdt = (segment_descriptor*)asm_gdt_descriptor.address;
+
+    for (int i = 0; i < asm_gdt_size; ++i) {
+        gdt[i] = asm_gdt[i];
+    }
+
+    set_segment_descriptor(gdt + 5, (uint32_t)&_tss, sizeof(struct tss32_t), SD_TYPE_TSS, 0b0000);
+
+    _tss.esp0 = (uint32_t)kernel_esp;
+    _tss.ss0 = kernel_ss;
+
+    asm_load_gdt((6 * sizeof(segment_descriptor) - 1) << 16, (uint32_t)gdt);
+    asm_load_tr((6 - 1) * 8);
+}

+ 4 - 0
src/kernel_main.c

@@ -105,6 +105,10 @@ void kernel_main(void)
     vga_printk(k_malloc_buf, 0x0fu);
     k_free(k_malloc_buf);
 
+    void* kernel_stack = k_malloc(KERNEL_STACK_SIZE);
+    init_gdt_with_tss(kernel_stack + KERNEL_STACK_SIZE - 1, KERNEL_STACK_SEGMENT);
+    printkf("new GDT and TSS loaded\n");
+
     printkf("No work to do, halting...\n");
 
     while (1) {