feat: gdt, attributes move, reorder
Added late gdt setup with initial tss Moved attributes to include root Reordered some imports
This commit is contained in:
18
kernel/cpu/gdt.S
Normal file
18
kernel/cpu/gdt.S
Normal file
@@ -0,0 +1,18 @@
|
||||
.code32
|
||||
.extern gdt_ptr
|
||||
|
||||
.global _gdt_switch
|
||||
_gdt_switch:
|
||||
lgdt gdt_ptr
|
||||
movw $0x10,%ax
|
||||
movw %ax,%ds
|
||||
movw %ax,%es
|
||||
movw %ax,%fs
|
||||
movw %ax,%gs
|
||||
ljmp $0x8, $_gdt_switch_continue
|
||||
_gdt_switch_continue:
|
||||
movw $0x2a, %ax // 0x28 + 0x03 = 0x2a
|
||||
ltr %ax
|
||||
ret
|
||||
|
||||
|
||||
192
kernel/cpu/gdt.c
Normal file
192
kernel/cpu/gdt.c
Normal file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// Created by rick on 19-03-21.
|
||||
//
|
||||
#include <attributes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/cpu/gdt.h>
|
||||
|
||||
typedef struct gdt {
|
||||
uint32_t base;
|
||||
uint32_t limit;
|
||||
union {
|
||||
uint8_t access_byte;
|
||||
struct {
|
||||
bool accessed: 1;
|
||||
bool read_write: 1; // for executable, if reading is allowed. For Non-exec if writing is allowed
|
||||
// data sector: direction
|
||||
// grows up(false) or down(true).
|
||||
// executable sector: conforming
|
||||
// if true higher privilege levels can execute this code (e.g. ring 3 can exec ring 0 code) the privilege level it self is not changed.
|
||||
// if false, only the specified ring can execute the code
|
||||
bool direction_conforming: 1;
|
||||
bool executable: 1;
|
||||
bool is_sector: 1;
|
||||
uint8_t privilege: 2;
|
||||
bool present: 1;
|
||||
} att_packed;
|
||||
};
|
||||
union {
|
||||
uint8_t flags_byte: 4;
|
||||
struct {
|
||||
uint8_t unused: 2;
|
||||
bool size: 1; // false 16bit, true 32bit
|
||||
bool granularity: 1; // false 1 byte, true 4KiB
|
||||
} att_packed;
|
||||
};
|
||||
} gdt_t;
|
||||
|
||||
struct tss_ring {
|
||||
uint32_t esp;
|
||||
uint16_t ss;
|
||||
uint16_t: 16; // skipped
|
||||
} att_packed;
|
||||
|
||||
typedef struct tss {
|
||||
uint16_t link;
|
||||
uint16_t: 16; // skipped
|
||||
struct tss_ring r0;
|
||||
struct tss_ring r1;
|
||||
struct tss_ring r2;
|
||||
struct {
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint16_t es;
|
||||
uint16_t: 16;
|
||||
uint16_t cs;
|
||||
uint16_t: 16;
|
||||
uint16_t ss;
|
||||
uint16_t: 16;
|
||||
uint16_t ds;
|
||||
uint16_t: 16;
|
||||
uint16_t fs;
|
||||
uint16_t: 16;
|
||||
uint16_t gs;
|
||||
uint16_t: 16;
|
||||
uint16_t ldtr;
|
||||
uint16_t: 16;
|
||||
} att_packed regs;
|
||||
uint16_t: 16;
|
||||
uint16_t iopb_offset;
|
||||
} att_packed tss_t;
|
||||
_Static_assert(sizeof(tss_t) == 104, "TSS incorrect size");
|
||||
|
||||
typedef struct gdtr {
|
||||
uint16_t size;
|
||||
uint32_t offset;
|
||||
} att_packed gdtr_t;
|
||||
|
||||
#define num_gdts 5
|
||||
|
||||
extern void _gdt_switch();
|
||||
|
||||
tss_t tss = {
|
||||
.iopb_offset = sizeof(tss_t),
|
||||
.r0.ss = 0x10,
|
||||
};
|
||||
|
||||
gdt_t gdts[num_gdts] = {
|
||||
{ // 0x08 kernel code
|
||||
.present = true,
|
||||
.base = 0,
|
||||
.limit = 0xFFFFFFFF,
|
||||
.is_sector = true,
|
||||
.size = true,
|
||||
.granularity = true,
|
||||
.executable = true,
|
||||
.read_write = true,
|
||||
.privilege = 0,
|
||||
}, { // 0x10 kernel data
|
||||
.present = true,
|
||||
.base = 0,
|
||||
.limit = 0xFFFFFFFF,
|
||||
.is_sector = true,
|
||||
.size = true,
|
||||
.granularity = true,
|
||||
.executable = false,
|
||||
.read_write = true,
|
||||
}, { // 0x18 user code
|
||||
.present = true,
|
||||
.base = 0,
|
||||
.limit = 0xFFFFFFFF,
|
||||
.privilege = 3,
|
||||
.is_sector = true,
|
||||
.size = true,
|
||||
.granularity = true,
|
||||
.executable = true,
|
||||
.read_write = true,
|
||||
}, { // 0x20 user data
|
||||
.present = true,
|
||||
.base = 0,
|
||||
.limit = 0xFFFFFFFF,
|
||||
.privilege = 3,
|
||||
.is_sector = true,
|
||||
.size = true,
|
||||
.granularity = true,
|
||||
.executable = true,
|
||||
.read_write = true,
|
||||
}, { // 0x28 tss
|
||||
.base = (uint32_t) &tss,
|
||||
.limit = sizeof(tss_t),
|
||||
.present = true,
|
||||
.executable = true,
|
||||
.accessed = true,
|
||||
.size = true,
|
||||
}
|
||||
};
|
||||
uint64_t gdt_values[num_gdts + 1] = {0};
|
||||
gdtr_t gdt_ptr = {
|
||||
.size = sizeof(uint64_t) * (num_gdts + 1) - 1,
|
||||
.offset = (uint32_t) &gdt_values,
|
||||
};
|
||||
_Static_assert(sizeof(gdt_ptr) == 6, "GDT PTR incorrect size");
|
||||
|
||||
uint64_t gdt_encode(gdt_t *gdt) {
|
||||
// high limit must be full 4k
|
||||
uint64_t limit = gdt->limit;
|
||||
if (limit > 65536 && (limit & 0xFFF) != 0xFFF && !gdt->granularity) {
|
||||
return 0;
|
||||
} else {
|
||||
limit >>= 12;
|
||||
}
|
||||
uint64_t value = 0
|
||||
| (limit & 0xFFFF)
|
||||
| ((gdt->base & 0xFFFF) << 16)
|
||||
| ((uint64_t) ((gdt->base >> 16) & 0xFF) << 32)
|
||||
| ((uint64_t) (gdt->access_byte) << 40)
|
||||
| ((limit >> 16) << 48)
|
||||
| ((uint64_t) (gdt->flags_byte) << 52)
|
||||
| ((uint64_t) (gdt->base >> 24) << 56);
|
||||
return value;
|
||||
}
|
||||
|
||||
void gdt_activate() {
|
||||
gdt_values[0] = 0; // first is zero
|
||||
for (int i = 0; i < num_gdts; ++i) {
|
||||
gdt_values[i + 1] = gdt_encode(&gdts[i]);
|
||||
if (gdt_values[i + 1] == 0) {
|
||||
// todo failed to encode
|
||||
k_panics("Failed to encode GDT\n");
|
||||
}
|
||||
}
|
||||
_gdt_switch();
|
||||
}
|
||||
|
||||
void gdt_init() {
|
||||
// Replace the early gdt with a new one
|
||||
// this one will be extensible and support stuff like TSS
|
||||
|
||||
tss.r0.esp = 0; // todo
|
||||
|
||||
gdt_activate();
|
||||
}
|
||||
Reference in New Issue
Block a user