vulcanos/kernel/drivers/gdt.c

103 lines
3.0 KiB
C

#include "gdt.h"
// Internal method
extern void gdt_flush(uint32_t); // Defined on cpu/gdt.asm
static gdt_entry_t construct_null_entry();
static gdt_entry_t construct_entry(gdt_access_t access);
static void init_gdt();
gdt_entry_t gdt_entries[5];
gdt_ptr_t gdt_ptr;
// This method will be called by the kernel
void gdt_setup() {
init_gdt();
}
static void init_gdt() {
gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
gdt_entry_t null_segment = construct_null_entry();
gdt_entry_t kernel_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t kernel_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING0,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_code_segment = construct_entry(
(struct gdt_access){
.type = GDT_CODE_TYPE_EXEC_READ,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entry_t user_mode_data_segment = construct_entry(
(struct gdt_access){
.type = GDT_DATA_TYPE_READ_WRITE,
.dt = GDT_CODE_AND_DATA_DESCRIPTOR,
.dpl = GDT_RING3,
.p = GDT_SEGMENT_PRESENT
}
);
gdt_entries[0] = null_segment;
gdt_entries[1] = kernel_mode_code_segment;
gdt_entries[2] = kernel_mode_data_segment;
gdt_entries[3] = user_mode_code_segment;
gdt_entries[4] = user_mode_data_segment;
gdt_flush((uint32_t)&gdt_ptr);
}
static gdt_entry_t construct_entry(gdt_access_t access) {
gdt_entry_t entry = (struct gdt_entry_struct) {
.base_low = GDT_BASE & 0xFFFF,
.base_middle = (GDT_BASE >> 16) & 0xFF,
.base_high = (GDT_BASE >> 24) & 0xFF,
.limit_low = (GDT_LIMIT & 0xFFFF),
.access = access,
.granularity = (struct gdt_granularity) {
.g = GDT_GRANULARITY_4K,
.d = GDT_OPERAND_SIZE_32,
.zero = 0,
.seglen = GDT_SEGMENT_LENGTH
}
};
return entry;
}
// The only difference is in the access
static gdt_entry_t construct_null_entry() {
gdt_entry_t null_entry = (struct gdt_entry_struct) {
.base_low = 0,
.base_middle = 0,
.base_high = 0,
.limit_low = 0,
.access = (struct gdt_access) {
.p = 0,
.dpl = 0,
.dt = 0,
.type = 0
},
.granularity = (struct gdt_granularity) {
.g = 0,
.d = 0,
.zero = 0,
.seglen = 0
}
};
return null_entry;
}