BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / b9a1b73816b93781911016a677d4b1bed5b8dcc9

// Related

Nucleus

Barry Global Descriptor Tables b9a1b73 (3 years, 3 months ago)
diff --git a/kernel/idt.h b/include/nucleus/cpu.h
similarity index 55%
rename from kernel/idt.h
rename to include/nucleus/cpu.h
index 204f285..9192ea8 100644
--- a/kernel/idt.h
+++ b/include/nucleus/cpu.h
@@ -1,13 +1,12 @@
-#ifndef KERNEL_IDT_H
-#define KERNEL_IDT_H
-
-#include <stdint.h>
+#ifndef _NUCLEUS_CPU_H
+#define _NUCLEUS_CPU_H
 
 /* Structure for an Interrupt Frame */
 struct InterruptFrame {
 	uint32_t eip, cs, eflags;
 };
 
-void init_idt(void);
+#define CPUID 0
+#define MAX_CPUS 1
 
 #endif
diff --git a/kernel/desc.h b/kernel/desc.h
new file mode 100644
index 0000000..616deab
--- /dev/null
+++ b/kernel/desc.h
@@ -0,0 +1,17 @@
+#ifndef KERNEL_DESC_H
+#define KERNEL_DESC_H
+
+#include <stdint.h>
+
+/* Structure for a Descriptor Record */
+struct DescRecord {
+	uint16_t limit;
+	uintptr_t base;
+} __attribute__((packed));
+
+void init_idt(void);
+void init_gdt(void);
+void cpu_load_idt(void);
+void cpu_load_gdt(void);
+
+#endif
diff --git a/kernel/gdt.c b/kernel/gdt.c
new file mode 100644
index 0000000..943ffa4
--- /dev/null
+++ b/kernel/gdt.c
@@ -0,0 +1,102 @@
+/*
+ * 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 to access
+ * all IO ports.  Every logical processor requires a unique TSS, and each one is
+ * also given a unique GDT, to save space, since the number of logical
+ * processors is not known until load time.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <nucleus/memory.h>
+#include <nucleus/panic.h>
+#include <nucleus/cpu.h>
+#include "desc.h"
+
+/* Structure for a GDT Entry */
+static struct GDTEntry {
+	uint16_t limitLower, baseLower;
+	uint8_t baseMiddle, access, gran, baseHigher;
+} __attribute__((packed)) *GDT[MAX_CPUS]; /* Per CPU */
+
+/* Structure for a 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;
+} __attribute__((packed)) *TSS[MAX_CPUS]; /* Per CPU */
+
+/* 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[CPUID][num].baseLower = (base & 0xFFFF);
+	GDT[CPUID][num].baseMiddle = (base >> 16) & 0xFF;
+	GDT[CPUID][num].baseHigher = (base >> 24) & 0xFF;
+	GDT[CPUID][num].limitLower = (limit & 0xFFFF);
+	GDT[CPUID][num].gran = (limit >> 16) & 0x0F;
+	GDT[CPUID][num].gran |= gran & 0xF0;
+	GDT[CPUID][num].access = access;
+}
+
+/* Initialise the GDT */
+void
+init_gdt(void)
+{
+}
+
+/* Load the GDT */
+void
+cpu_load_gdt(void)
+{
+	/*
+	 * Each page can fit multiple GDT/TSS structures.  If there is space in
+	 * an existing page, the new structures should be allocated in there.
+	 * Otherwise, a new page frame should be allocated.
+	 */
+	size_t size = (sizeof(struct GDTEntry) * 6) + sizeof(struct TSSEntry);
+	off_t idx = CPUID % (PAGE_SIZE / size);
+	off_t block = (CPUID / (PAGE_SIZE / size)) * (PAGE_SIZE / size);
+	if (idx == 0)
+		GDT[CPUID] = (void *) alloc_frame();
+	else
+		GDT[CPUID] = (void *) GDT[block] + (size * idx);
+
+	memset(GDT[CPUID], 0, size);
+
+	gdt_set_gate(0, 0x00000000, 0x00000000, 0x00, 0x00); /* Null */
+	/* Ring 0 */
+	gdt_set_gate(1, 0x00000000, 0xFFFFFFFF, 0x9A, 0xCF); /* Code */
+	gdt_set_gate(2, 0x00000000, 0xFFFFFFFF, 0x92, 0xCF); /* Data */
+	/* Ring 3 */
+	gdt_set_gate(3, 0x00000000, 0xFFFFFFFF, 0xFA, 0xCF); /* Code */
+	gdt_set_gate(4, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF); /* Data */
+
+	uint32_t addr = (uint32_t) GDT[CPUID] + (sizeof(struct GDTEntry) * 6);
+	gdt_set_gate(5, addr, sizeof(struct TSSEntry) - 1, 0xE9, 0);
+
+	TSS[CPUID] = (void *) addr;
+	TSS[CPUID]->ss0 = 0x10;
+	TSS[CPUID]->esp0 = 0xF0800000 - sizeof(uintptr_t);
+	TSS[CPUID]->cs = 0x08 | 0;
+	TSS[CPUID]->ds = TSS[CPUID]->es = TSS[CPUID]->ss = 0x10 | 0;
+	TSS[CPUID]->fs = TSS[CPUID]->gs = 0x10 | 3;
+	TSS[CPUID]->iomapBase = sizeof(struct TSSEntry);
+
+	struct DescRecord ptr = {
+		.limit = sizeof(struct GDTEntry) * 6,
+		.base = (uintptr_t) GDT[CPUID],
+	};
+	asm volatile("lgdt %0" :: "m" (ptr));
+	asm volatile("ltr %w0" :: "q" (0x28 | 3));
+}
diff --git a/kernel/idt.c b/kernel/idt.c
index 4c594bb..85f64c6 100644
--- a/kernel/idt.c
+++ b/kernel/idt.c
@@ -9,8 +9,9 @@
 #include <string.h>
 #include <nucleus/panic.h>
 #include <nucleus/memory.h>
+#include <nucleus/cpu.h>
 #include <io.h>
-#include "idt.h"
+#include "desc.h"
 
 /* Structure for an IDT Entry */
 static struct IDTEntry {
@@ -37,6 +38,11 @@ install_idt_entry(uint8_t num, void *addr)
 static void
 exc_handler(int num, struct InterruptFrame *frame, uint32_t err)
 {
+	if (!exceptions[num]) {
+		panic("Failed to handle exception %d (%#.8x)",
+		      num, err);
+	}
+
 	ASSERT(exceptions[num]);
 	exceptions[num](frame, err);
 
@@ -350,3 +356,14 @@ init_idt(void)
 	interrupts = (void *) (exceptions + 32);
 	memset(exceptions, 0, 1024);
 }
+
+/* Load the IDT */
+void
+cpu_load_idt(void)
+{
+	struct DescRecord ptr = {
+		.limit = sizeof(struct IDTEntry) * 256,
+		.base = (uintptr_t) IDT,
+	};
+	asm volatile("lidt %0" :: "m" (ptr));
+}
diff --git a/kernel/main.c b/kernel/main.c
index e797bbc..6f2011e 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -9,10 +9,37 @@
 #include <nucleus/memory.h>
 #include <nucleus/panic.h>
 #include "multiboot.h"
-#include "idt.h"
+#include "desc.h"
 
 extern char _bss[], _end[];
 
+/* Per-CPU Setup */
+void
+cpu_load(void)
+{
+	/* Initialise SSE */
+	asm volatile(
+		"mov %cr0, %eax;"
+		"andl $0xfffffffb, %eax;"
+		"orl $0x2, %eax;"
+		"mov %eax, %cr0;"
+		"mov %cr4, %eax;"
+		"orl $0x600, %eax;"
+		"mov %eax, %cr4;"
+	);
+
+	/* Initialise CR4.PGE */
+	asm volatile(
+		"mov %cr4, %eax;"
+		"orl $0x10, %eax;"
+		"mov %eax, %cr4;"
+	);
+
+	/* Tables */
+	cpu_load_idt();
+	cpu_load_gdt();
+}
+
 /* Kernel main function */
 _Noreturn void
 kmain(uint32_t esp, struct MultibootInfo *mbinfo)
@@ -25,6 +52,9 @@ kmain(uint32_t esp, struct MultibootInfo *mbinfo)
 
 	/* Processor startup */
 	init_idt();
+	init_gdt();
+	//init_pic();
+	cpu_load();
 
 	panic("End of kernel!");
 }