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:
2021-03-21 17:34:38 +01:00
parent 513693189e
commit 20ab9e1d6e
28 changed files with 351 additions and 121 deletions

18
kernel/cpu/gdt.S Normal file
View 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
View 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();
}