135 lines
2.9 KiB
C
135 lines
2.9 KiB
C
#include <stdint.h>
|
|
|
|
#include "cpu.h"
|
|
|
|
#define GDT_PRESENT 0x80
|
|
#define GDT_RING0 0x00
|
|
#define GDT_CODE 0x1a
|
|
#define GDT_DATA 0x12
|
|
#define GDT_TSS_AVAILABLE 0x09
|
|
#define GDT_LONG_MODE 0x20
|
|
#define GDT_GRANULARITY_4K 0x80
|
|
|
|
struct gdt_entry {
|
|
uint16_t limit_low;
|
|
uint16_t base_low;
|
|
uint8_t base_mid;
|
|
uint8_t access;
|
|
uint8_t limit_flags;
|
|
uint8_t base_high;
|
|
} __attribute__((packed));
|
|
|
|
struct tss_entry {
|
|
uint32_t reserved0;
|
|
uint64_t rsp0;
|
|
uint64_t rsp1;
|
|
uint64_t rsp2;
|
|
uint64_t reserved1;
|
|
uint64_t ist[7];
|
|
uint64_t reserved2;
|
|
uint16_t reserved3;
|
|
uint16_t io_map_base;
|
|
} __attribute__((packed));
|
|
|
|
struct tss_descriptor {
|
|
uint16_t limit_low;
|
|
uint16_t base_low;
|
|
uint8_t base_mid;
|
|
uint8_t access;
|
|
uint8_t limit_flags;
|
|
uint8_t base_high;
|
|
uint32_t base_upper;
|
|
uint32_t reserved;
|
|
} __attribute__((packed));
|
|
|
|
struct gdtr {
|
|
uint16_t limit;
|
|
uint64_t base;
|
|
} __attribute__((packed));
|
|
|
|
struct gdt_table {
|
|
struct gdt_entry null;
|
|
struct gdt_entry kernel_code;
|
|
struct gdt_entry kernel_data;
|
|
struct tss_descriptor tss;
|
|
} __attribute__((packed));
|
|
|
|
extern char kernel_stack_top[];
|
|
|
|
static struct tss_entry tss;
|
|
static struct gdt_table gdt;
|
|
|
|
static struct gdt_entry make_gdt_entry(uint8_t access, uint8_t flags)
|
|
{
|
|
struct gdt_entry entry = {
|
|
.limit_low = 0xffff,
|
|
.base_low = 0,
|
|
.base_mid = 0,
|
|
.access = (uint8_t)(GDT_PRESENT | GDT_RING0 | access),
|
|
.limit_flags = (uint8_t)(0x0f | flags),
|
|
.base_high = 0,
|
|
};
|
|
|
|
return entry;
|
|
}
|
|
|
|
static struct tss_descriptor make_tss_descriptor(uint64_t base, uint32_t limit)
|
|
{
|
|
struct tss_descriptor descriptor = {
|
|
.limit_low = (uint16_t)(limit & 0xffff),
|
|
.base_low = (uint16_t)(base & 0xffff),
|
|
.base_mid = (uint8_t)((base >> 16) & 0xff),
|
|
.access = GDT_PRESENT | GDT_TSS_AVAILABLE,
|
|
.limit_flags = (uint8_t)((limit >> 16) & 0x0f),
|
|
.base_high = (uint8_t)((base >> 24) & 0xff),
|
|
.base_upper = (uint32_t)(base >> 32),
|
|
.reserved = 0,
|
|
};
|
|
|
|
return descriptor;
|
|
}
|
|
|
|
static void load_gdt(const struct gdtr *gdtr)
|
|
{
|
|
__asm__ volatile("lgdt (%0)" : : "r"(gdtr) : "memory");
|
|
__asm__ volatile("pushq %[code]\n"
|
|
"leaq 1f(%%rip), %%rax\n"
|
|
"pushq %%rax\n"
|
|
"lretq\n"
|
|
"1:\n"
|
|
"movw %[data], %%ax\n"
|
|
"movw %%ax, %%ds\n"
|
|
"movw %%ax, %%es\n"
|
|
"movw %%ax, %%ss\n"
|
|
:
|
|
: [code] "i"(KERNEL_CODE_SELECTOR),
|
|
[data] "i"(KERNEL_DATA_SELECTOR)
|
|
: "rax", "memory");
|
|
}
|
|
|
|
static void load_tss(void)
|
|
{
|
|
__asm__ volatile("ltr %0" : : "r"((uint16_t)TSS_SELECTOR) : "memory");
|
|
}
|
|
|
|
void gdt_init(void)
|
|
{
|
|
struct gdtr gdtr = {
|
|
.limit = sizeof(gdt) - 1,
|
|
.base = (uint64_t)(uintptr_t)&gdt,
|
|
};
|
|
|
|
tss.rsp0 = (uint64_t)(uintptr_t)kernel_stack_top;
|
|
tss.io_map_base = sizeof(tss);
|
|
|
|
gdt.null = (struct gdt_entry){0};
|
|
gdt.kernel_code =
|
|
make_gdt_entry(GDT_CODE, GDT_LONG_MODE | GDT_GRANULARITY_4K);
|
|
gdt.kernel_data = make_gdt_entry(GDT_DATA, GDT_GRANULARITY_4K);
|
|
gdt.tss =
|
|
make_tss_descriptor((uint64_t)(uintptr_t)&tss, sizeof(tss) - 1);
|
|
|
|
load_gdt(&gdtr);
|
|
load_tss();
|
|
}
|