BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 7ae31b03c38925f5d527e6303765925586731209 / proc / gdt.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 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();
}