Nucleus
Barry CPU specific segment c738dbb (3 years, 2 months ago)
diff --git a/kernel/acpi/apic.c b/kernel/acpi/apic.c
index 73da356..c7f8259 100644
--- a/kernel/acpi/apic.c
+++ b/kernel/acpi/apic.c
@@ -103,7 +103,7 @@ apic_start_timer(void)
{
/* Wait for this processor's "turn" */
static cpu_t c = 0;
- while (c != CPUID);
+ while (c != cpu->id);
/* Start LAPIC countdown from -1 */
LAPIC(0x3E0) = 3;
diff --git a/kernel/gdt.c b/kernel/gdt.c
index bd083a6..b9cebb6 100644
--- a/kernel/gdt.c
+++ b/kernel/gdt.c
@@ -15,12 +15,26 @@
#include <nucleus/cpu.h>
#include "desc.h"
+/* GDT Entry Indicies */
+enum GDTIndex {
+ GDT_NULL,
+ GDT_KERN_CODE,
+ GDT_KERN_DATA,
+ GDT_USER_CODE,
+ GDT_USER_DATA,
+ GDT_FS,
+ GDT_GS,
+ GDT_TSS,
+};
+
/* 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 */
+#define GDT_OFFSET(i) (i * sizeof(struct GDTEntry))
+
/* Structure for a TSS Entry */
static struct TSSEntry {
uint32_t prevTSS;
@@ -58,7 +72,8 @@ cpu_load_gdt(void)
* 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);
+ size_t size = (sizeof(struct GDTEntry) * (GDT_TSS + 1))
+ + sizeof(struct TSSEntry);
off_t idx = CPUID % (PAGE_SIZE / size);
off_t block = (CPUID / (PAGE_SIZE / size)) * (PAGE_SIZE / size);
if (idx == 0)
@@ -68,29 +83,52 @@ cpu_load_gdt(void)
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 */
+ gdt_set_gate(GDT_NULL, 0x00000000, 0x00000000, 0x00, 0x00);
+ gdt_set_gate(GDT_KERN_CODE, 0x00000000, 0xFFFFFFFF, 0x9A, 0xCF);
+ gdt_set_gate(GDT_KERN_DATA, 0x00000000, 0xFFFFFFFF, 0x92, 0xCF);
+ gdt_set_gate(GDT_USER_CODE, 0x00000000, 0xFFFFFFFF, 0xFA, 0xCF);
+ gdt_set_gate(GDT_USER_DATA, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF);
+ gdt_set_gate(GDT_FS, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF);
+ gdt_set_gate(GDT_GS, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF);
- uint32_t addr = (uint32_t) gdt[CPUID] + (sizeof(struct GDTEntry) * 6);
- gdt_set_gate(5, addr, sizeof(struct TSSEntry) - 1, 0xE9, 0);
+ uint32_t addr = (uint32_t) (gdt[CPUID] + (GDT_TSS + 1));
+ gdt_set_gate(GDT_TSS, 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]->cs = GDT_OFFSET(GDT_KERN_CODE) | 0;
+ tss[CPUID]->ds = GDT_OFFSET(GDT_KERN_DATA) | 0;
+ tss[CPUID]->es = tss[CPUID]->ss = tss[CPUID]->ds;
+ tss[CPUID]->fs = tss[CPUID]->gs = GDT_OFFSET(GDT_FS) | 3;
tss[CPUID]->iomapBase = sizeof(struct TSSEntry);
struct DescRecord ptr = {
- .limit = sizeof(struct GDTEntry) * 6,
+ .limit = sizeof(struct GDTEntry) * (GDT_TSS + 1),
.base = (uintptr_t) gdt[CPUID],
};
asm volatile("lgdt %0" :: "m" (ptr));
- asm volatile("ltr %w0" :: "q" (0x28 | 3));
+ asm volatile("ltr %w0" :: "q" (GDT_OFFSET(GDT_TSS) | 3));
+}
+
+/* Set FS base */
+void
+set_fs_base(uintptr_t base)
+{
+ struct GDTEntry *fs = gdt[CPUID] + GDT_FS;
+ fs->baseLower = (base & 0xFFFF);
+ fs->baseMiddle = (base >> 16) & 0xFF;
+ fs->baseHigher = (base >> 24) & 0xFF;
+ asm volatile("mov %0, %%fs" :: "r" (GDT_OFFSET(GDT_FS) | 3));
+}
+
+/* Set FS base */
+void
+set_gs_base(uintptr_t base)
+{
+ struct GDTEntry *gs = gdt[CPUID] + GDT_GS;
+ gs->baseLower = (base & 0xFFFF);
+ gs->baseMiddle = (base >> 16) & 0xFF;
+ gs->baseHigher = (base >> 24) & 0xFF;
+ asm volatile("mov %0, %%gs" :: "r" (GDT_OFFSET(GDT_GS) | 3));
}
diff --git a/kernel/idt.c b/kernel/idt.c
index a9f7c79..6aceb88 100644
--- a/kernel/idt.c
+++ b/kernel/idt.c
@@ -28,10 +28,14 @@ void (**interrupts)(struct InterruptFrame *);
static void
install_idt_entry(uint8_t num, void *addr)
{
+ uint8_t type = 0x8E; /* Interrupt gate */
+ if (num < 32)
+ type = 0x8F; /* Trap gate for exceptions */
+
IDT[num].offsetLower = (uintptr_t) addr & 0xFFFF;
IDT[num].selector = 0x08;
IDT[num].zero = 0;
- IDT[num].typeAttr = 0x8E | 0x60; /* Allowed from ring 3 */
+ IDT[num].typeAttr = type | 0x60; /* Allowed from ring 3 */
IDT[num].offsetHigher = (uintptr_t) addr >> 16;
}
@@ -41,11 +45,12 @@ isr_handler(struct InterruptFrame frame)
{
if (!exceptions[frame.intnum] && frame.intnum < 32)
panic("[CPU#%d] Failed to handle exception %d (%#.8x) @ %#.8x",
- CPUID, frame.intnum, frame.err, frame.eip);
+ cpu->id, frame.intnum, frame.err, frame.eip);
/* Run registered handler */
- if (exceptions[frame.intnum])
- exceptions[frame.intnum](&frame);
+ exc_handler_t handler = exceptions[frame.intnum];
+ if (handler)
+ handler(&frame);
/* Send EOI */
if (frame.intnum >= 40 && frame.intnum < 48)
@@ -62,7 +67,7 @@ isr_handler(struct InterruptFrame frame)
void
register_exception(int num, exc_handler_t addr)
{
- if ((num >= 0 && num < 32) || num >= 48)
+ if (num >= 0 && num < 256)
exceptions[num] = addr;
}
diff --git a/kernel/isr.S b/kernel/isr.S
index c807e7b..914d855 100644
--- a/kernel/isr.S
+++ b/kernel/isr.S
@@ -1,6 +1,8 @@
/*
* This file contains the interrupt service routine stubs. For the most part
- * they just call into the generic handlers after setting up the stack for them.
+ * they just call into the generic handler after setting up the stack for it.
+ * It pushes the interrupt number and saved registers onto the stack for the
+ * handler to access.
*/
.extern isr_handler
@@ -9,7 +11,6 @@
.macro exc_err num
.globl exc\num
exc\num:
- cli
push $\num
jmp isr_stub
.endm
@@ -17,7 +18,6 @@ exc\num:
.macro exc_noerr num
.globl exc\num
exc\num:
- cli
push $0
push $\num
jmp isr_stub
@@ -76,7 +76,9 @@ isr_stub:
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
+ mov $0x28, %ax
mov %ax, %fs
+ mov $0x30, %ax
mov %ax, %gs
call isr_handler
@@ -85,10 +87,11 @@ isr_stub:
popl %ebx
mov %bx, %ds
mov %bx, %es
+ mov $0x28, %bx
mov %bx, %fs
+ mov $0x30, %bx
mov %bx, %gs
popa
addl $8, %esp
- sti
iret
diff --git a/kernel/main.c b/kernel/main.c
index bf1fd8c..76d5ef1 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -17,6 +17,8 @@
#include "desc.h"
#include "acpi/acpi.h"
+struct CPUData __seg_gs *cpu = 0;
+
extern char _bss[], _end[];
void page_fault_handler(struct InterruptFrame *frame);
@@ -45,6 +47,8 @@ cpu_load(void)
/* Tables */
cpu_load_idt();
cpu_load_gdt();
+ set_gs_base((uintptr_t) kmalloc(sizeof(struct CPUData)));
+ cpu->id = CPUID;
asm volatile("sti");
}
diff --git a/kernel/uname.c b/kernel/uname.c
index c930faf..cf0a931 100644
--- a/kernel/uname.c
+++ b/kernel/uname.c
@@ -9,7 +9,7 @@
#include <nucleus/memory.h>
static const char *SYSNAME = "Nucleus";
-static const char *RELEASE = "0.9.0";
+static const char *RELEASE = "0.9.1";
static const char *VERSION = "SMP PREEMPT "__DATE__" "__TIME__;
static const char *MACHINE = "x86";