WIP gdt changes
This commit is contained in:
@@ -8,10 +8,20 @@
|
|||||||
#define STR_(x) #x
|
#define STR_(x) #x
|
||||||
#define STR(x) STR_(x)
|
#define STR(x) STR_(x)
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GDT Setup
|
* GDT Setup
|
||||||
* =========
|
* =========
|
||||||
*/
|
*/
|
||||||
|
#define GDT_LIMIT_MAX 0xFFFFF
|
||||||
|
|
||||||
|
struct gdt_table_entry {
|
||||||
|
uint8_t data[8];
|
||||||
|
};
|
||||||
|
|
||||||
enum gdt_segment_descriptor_index : size_t {
|
enum gdt_segment_descriptor_index : size_t {
|
||||||
GDT_SDESC_BASE_0 = 2,
|
GDT_SDESC_BASE_0 = 2,
|
||||||
GDT_SDESC_BASE_1 = 3,
|
GDT_SDESC_BASE_1 = 3,
|
||||||
@@ -33,8 +43,13 @@ enum gdt_access_flag : uint8_t {
|
|||||||
GDT_ACCESS_DC = (1<<2),
|
GDT_ACCESS_DC = (1<<2),
|
||||||
GDT_ACCESS_EXEC = (1<<3),
|
GDT_ACCESS_EXEC = (1<<3),
|
||||||
GDT_ACCESS_DESCRIPTOR = (1<<4),
|
GDT_ACCESS_DESCRIPTOR = (1<<4),
|
||||||
GDT_ACCESS_DPL = (1<<5),
|
|
||||||
GDT_ACCESS_PRESENT = (1<<6),
|
GDT_ACCESS_DPL_0 = (0<<5),
|
||||||
|
GDT_ACCESS_DPL_1 = (1<<5),
|
||||||
|
GDT_ACCESS_DPL_2 = (2<<5),
|
||||||
|
GDT_ACCESS_DPL_3 = (3<<5),
|
||||||
|
|
||||||
|
GDT_ACCESS_PRESENT = (1<<7),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum gdt_flags : uint8_t {
|
enum gdt_flags : uint8_t {
|
||||||
@@ -42,59 +57,170 @@ enum gdt_flags : uint8_t {
|
|||||||
GDT_LONG = (1<<1),
|
GDT_LONG = (1<<1),
|
||||||
GDT_SIZE = (1<<2),
|
GDT_SIZE = (1<<2),
|
||||||
GDT_GRANULARITY = (1<<3),
|
GDT_GRANULARITY = (1<<3),
|
||||||
}
|
|
||||||
|
|
||||||
struct gdt {
|
|
||||||
uint32_t base;
|
|
||||||
uint32_t limit;
|
|
||||||
uint8_t access_byte;
|
|
||||||
uint8_t flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gdt_encode_entry(uint8_t *target, struct GDT source)
|
static inline uint16_t gdt_segment_selector(uint16_t index, uint16_t table_indicator, uint16_t priv_level)
|
||||||
{
|
{
|
||||||
#define GDT_LIMIT_MAX 0xFFFFF
|
return (index << 3)
|
||||||
if (source.limit > GDT_LIMIT_MAX)
|
| ((table_indicator << 2) & 0b100)
|
||||||
|
| ((priv_level << 0) & 0b011);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gdt_entry_content {
|
||||||
|
uint32_t base;
|
||||||
|
uint32_t limit;
|
||||||
|
uint8_t access_byte;
|
||||||
|
uint8_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gdt_encode_entry(struct gdt_table_entry* target, struct gdt_entry_content content)
|
||||||
|
{
|
||||||
|
if (content.limit > GDT_LIMIT_MAX)
|
||||||
panic(str_attach("GDT cannot encode limits larger than " STR(GDT_LIMIT_MAX)));
|
panic(str_attach("GDT cannot encode limits larger than " STR(GDT_LIMIT_MAX)));
|
||||||
|
|
||||||
// encode the limit
|
// encode the limit
|
||||||
target[GDT_SDESC_LIMIT_0] = (source.limit >> 0) & 0xFF;
|
target->data[GDT_SDESC_LIMIT_0] = (content.limit >> 0) & 0xFF;
|
||||||
target[GDT_SDESC_LIMIT_1] = (source.limit >> 8) & 0xFF;
|
target->data[GDT_SDESC_LIMIT_1] = (content.limit >> 8) & 0xFF;
|
||||||
target[GDT_SDESC_LIMIT_2] = (source.limit >> 16) & 0xFF;
|
target->data[GDT_SDESC_LIMIT_2] = (content.limit >> 16) & 0xFF;
|
||||||
|
|
||||||
// encode the base
|
// encode the base
|
||||||
target[GDT_SDESC_BASE_0] = (source.base >> 0) & 0xFF;
|
target->data[GDT_SDESC_BASE_0] = (content.base >> 0) & 0xFF;
|
||||||
target[GDT_SDESC_BASE_1] = (source.base >> 8) & 0xFF;
|
target->data[GDT_SDESC_BASE_1] = (content.base >> 8) & 0xFF;
|
||||||
target[GDT_SDESC_BASE_2] = (source.base >> 16) & 0xFF;
|
target->data[GDT_SDESC_BASE_2] = (content.base >> 16) & 0xFF;
|
||||||
target[GDT_SDESC_BASE_3] = (source.base >> 24) & 0xFF;
|
target->data[GDT_SDESC_BASE_3] = (content.base >> 24) & 0xFF;
|
||||||
|
|
||||||
// encode the access byte
|
// encode the access byte
|
||||||
target[GDT_SDESC_ACCESSBYTE] = source.access_byte;
|
target->data[GDT_SDESC_ACCESSBYTE] = content.access_byte;
|
||||||
|
|
||||||
// encode the flags
|
// encode the flags
|
||||||
target[GDT_SDESC_FLAGS] |= (source.flags << 4);
|
target->data[GDT_SDESC_FLAGS] |= (content.flags << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_set(uint16_t limit, uint32_t base)
|
static void gdt_set(uint16_t limit, uint32_t base, uint32_t offset)
|
||||||
{
|
{
|
||||||
|
base += offset;
|
||||||
|
|
||||||
/* the lgdt instruction requires a packed alignment */
|
/* the lgdt instruction requires a packed alignment */
|
||||||
struct __attribute__((packed)) gdtr {
|
struct __attribute__((packed)) gdtr {
|
||||||
uint16_t limit;
|
uint16_t limit;
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gdtr gdtr = {
|
static struct gdtr gdtr;
|
||||||
.limit = limit,
|
gdtr.limit = limit;
|
||||||
.base = base,
|
gdtr.base = base;
|
||||||
};
|
|
||||||
|
|
||||||
__asm__ volatile (
|
__asm__ volatile (
|
||||||
"lgdt %0"
|
"lgdt %[gdtr]"
|
||||||
:
|
:
|
||||||
: "m" (gdtr));
|
: [gdtr] "m"(gdtr)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_segment_reload()
|
// only compiles with O1 or higher ¯\_(ツ)_/¯, might have to make this a macro
|
||||||
|
static inline void gdt_reload(uint32_t code,
|
||||||
|
uint32_t data,
|
||||||
|
uint32_t extra_segment,
|
||||||
|
uint32_t general_segment_1,
|
||||||
|
uint32_t general_segment_2,
|
||||||
|
uint32_t stack_segment)
|
||||||
|
{
|
||||||
|
__asm__ volatile (
|
||||||
|
// Far jump to reload the CS register
|
||||||
|
"jmp %[cs], $reload_CS\n"
|
||||||
|
"reload_CS:\n"
|
||||||
|
// Load data segment into AX and then move it to all segment registers
|
||||||
|
//"movw %[ds], %%ax\n"
|
||||||
|
"movw %[ds], %%ds\n"
|
||||||
|
"movw %[es], %%es\n"
|
||||||
|
"movw %[fs], %%fs\n"
|
||||||
|
"movw %[gs], %%gs\n"
|
||||||
|
"movw %[ss], %%ss\n"
|
||||||
|
: // No output operands
|
||||||
|
: [cs] "i"(code),
|
||||||
|
[ds] "i"(data),
|
||||||
|
[es] "i"(extra_segment),
|
||||||
|
[fs] "i"(general_segment_1),
|
||||||
|
[gs] "i"(general_segment_2),
|
||||||
|
[ss] "i"(stack_segment)
|
||||||
|
: "ax" // Clobbered register
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets a flat model
|
||||||
|
void test_gdt()
|
||||||
|
{
|
||||||
|
// disable interupts
|
||||||
|
__asm__ volatile ("cli");
|
||||||
|
|
||||||
|
static struct gdt_table_entry gdt_table[6];
|
||||||
|
size_t i=0;
|
||||||
|
_Static_assert(sizeof(gdt_table) == 0x30);
|
||||||
|
|
||||||
|
// Null Descriptor
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){0});
|
||||||
|
|
||||||
|
// Kernel mode code segment
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){
|
||||||
|
.base = 0,
|
||||||
|
.limit = GDT_LIMIT_MAX,
|
||||||
|
.access_byte = GDT_ACCESS_RW
|
||||||
|
| GDT_ACCESS_EXEC
|
||||||
|
| GDT_ACCESS_DESCRIPTOR
|
||||||
|
| GDT_ACCESS_DPL_0
|
||||||
|
| GDT_ACCESS_PRESENT,
|
||||||
|
.flags = GDT_SIZE
|
||||||
|
| GDT_GRANULARITY});
|
||||||
|
|
||||||
|
// Kernel mode data segment
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){
|
||||||
|
.base = 0,
|
||||||
|
.limit = GDT_LIMIT_MAX,
|
||||||
|
.access_byte = GDT_ACCESS_RW
|
||||||
|
| GDT_ACCESS_DESCRIPTOR
|
||||||
|
| GDT_ACCESS_DPL_0
|
||||||
|
| GDT_ACCESS_PRESENT,
|
||||||
|
.flags = GDT_SIZE
|
||||||
|
| GDT_GRANULARITY});
|
||||||
|
|
||||||
|
// User mode code segment
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){
|
||||||
|
.base = 0,
|
||||||
|
.limit = GDT_LIMIT_MAX,
|
||||||
|
.access_byte = GDT_ACCESS_RW
|
||||||
|
| GDT_ACCESS_EXEC
|
||||||
|
| GDT_ACCESS_DESCRIPTOR
|
||||||
|
| GDT_ACCESS_DPL_3
|
||||||
|
| GDT_ACCESS_PRESENT,
|
||||||
|
.flags = GDT_SIZE
|
||||||
|
| GDT_GRANULARITY});
|
||||||
|
|
||||||
|
// User mode data segment
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){
|
||||||
|
.base = 0,
|
||||||
|
.limit = GDT_LIMIT_MAX,
|
||||||
|
.access_byte = GDT_ACCESS_RW
|
||||||
|
| GDT_ACCESS_DESCRIPTOR
|
||||||
|
| GDT_ACCESS_DPL_3
|
||||||
|
| GDT_ACCESS_PRESENT,
|
||||||
|
.flags = GDT_SIZE
|
||||||
|
| GDT_GRANULARITY});
|
||||||
|
|
||||||
|
// Task state segment
|
||||||
|
gdt_encode_entry(&gdt_table[i++], (struct gdt_entry_content){
|
||||||
|
.base = &tss,
|
||||||
|
.limit = sizeof(tss)-1,
|
||||||
|
.access_byte = GDT_ACCESS_ACCESSED
|
||||||
|
| GDT_ACCESS_EXEC
|
||||||
|
| GDT_ACCESS_DPL_0
|
||||||
|
| GDT_ACCESS_PRESENT,
|
||||||
|
.flags = 0});
|
||||||
|
|
||||||
|
gdt_set(0, 0, 0);
|
||||||
|
const uint16_t code_segment = 0x8; // placeholder
|
||||||
|
const uint16_t data_segment = 0x10; // placeholder
|
||||||
|
gdt_reload(code_segment, data_segment);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel entrypoint
|
* Kernel entrypoint
|
||||||
@@ -109,3 +235,6 @@ void kernel_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|||||||
Reference in New Issue
Block a user