Orion
Barry Importing existing Orion kernel d41a53c (3 years, 2 months ago)
/*
* This file deals with the Global Descriptor Table. It creates a simple GDT,
* suitable for use in the Kernel, and attaches a TSS to the end. The TSS,
* which can be used to switch from ring 3 to ring 0, allows processes access to
* all IO ports.
*/
#include <stdint.h>
#include "../mem/heap.h"
#include "../mem/mem.h"
#include "../mem/frame.h"
#include "../proc/proc.h"
#include "../screen.h"
#define GDT_ENTRIES 6
/* Structure for GDT entry */
static struct GDTEntry {
uint16_t limitLower, baseLower;
uint8_t baseMiddle, access, gran, baseHigher;
} __attribute__((packed)) *GDT;
/* Structure for TSS entry */
static struct TSSEntry {
uint32_t prevTSS;
uint32_t esp0, ss0;
uint32_t esp1, ss1;
uint32_t esp2, ss2;
uint32_t cr3, eip, eflags;
uint32_t eax, ecx, edx, ebx;
uint32_t esp, ebp, esi, edi;
uint32_t es, cs, ss, ds, fs, gs;
uint32_t ldt;
uint16_t trap, iomapBase;
// uint32_t iomap[2048];
} __attribute__((packed)) *TSS; /* Per CPU */
void load_gdt(uint32_t gdtPtr);
void load_tss(void);
/* Set a gate of the GDT */
static void
gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit,
uint8_t access, uint8_t gran)
{
GDT[num].baseLower = (base & 0xFFFF);
GDT[num].baseMiddle = (base >> 16) & 0xFF;
GDT[num].baseHigher = (base >> 24) & 0xFF;
GDT[num].limitLower = (limit & 0xFFFF);
GDT[num].gran = (limit >> 16) & 0x0F;
GDT[num].gran |= gran & 0xF0;
GDT[num].access = access;
}
/* Create a TSS */
static void
write_tss(uint8_t num, uint32_t esp)
{
uint32_t base = (uint32_t) TSS;
uint32_t limit = sizeof(struct TSSEntry) - 1;
gdt_set_gate(num, base, limit, 0xE9, 0x00);
num -= 5;
memset(&TSS[num], 0, sizeof(struct TSSEntry));
TSS[num].ss0 = 0x10;
TSS[num].esp0 = esp;
TSS[num].cs = 0x08 | 0;
TSS[num].ds = TSS[num].es = TSS[num].ss = 0x10 | 0;
TSS[num].fs = TSS[num].gs = 0x10 | 3;
TSS[num].iomapBase = 104;
}
/* Initialise the Kernel GDT */
void
init_gdt(void)
{
GDT = (void *) alloc_frames(1);
TSS = (void *) (GDT + GDT_ENTRIES);
kprintf("Loaded GDT @ %#.8x, TSS @ %#.8x", GDT, TSS);
}
/* Load the Kernel GDT */
void
cpu_load_gdt(void)
{
memset(GDT, 0, sizeof(GDT[0]) * GDT_ENTRIES);
gdt_set_gate(0, 0x00000000, 0x00000000, 0x00, 0x00); /* Null segment */
/* Ring 0 */
gdt_set_gate(1, 0x00000000, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
gdt_set_gate(2, 0x00000000, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
/* Ring 3 */
gdt_set_gate(3, 0x00000000, 0xFFFFFFFF, 0xFA, 0xCF); /* Code segment */
gdt_set_gate(4, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF); /* Data segment */
/* TSS */
write_tss(5, 0xF0800000 - sizeof(uintptr_t));
uint16_t gdtPtr[3];
gdtPtr[0] = (sizeof(GDT[0]) * GDT_ENTRIES) - 1;
gdtPtr[1] = ((uint32_t) GDT) & 0xFFFF;
gdtPtr[2] = ((uint32_t) GDT) >> 16;
load_gdt((uint32_t) &gdtPtr);
load_tss();
}