summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch/amd64')
-rw-r--r--src/kernel/arch/amd64/32/32130
-rw-r--r--src/kernel/arch/amd64/32/boot.s1
-rw-r--r--src/kernel/arch/amd64/interrupts/irq.c9
-rw-r--r--src/kernel/arch/amd64/interrupts/irq.h1
-rw-r--r--src/kernel/arch/amd64/interrupts/isr.c6
-rw-r--r--src/kernel/arch/amd64/time.c50
-rw-r--r--src/kernel/arch/amd64/time.h4
7 files changed, 71 insertions, 130 deletions
diff --git a/src/kernel/arch/amd64/32/32 b/src/kernel/arch/amd64/32/32
deleted file mode 100644
index 9bd97e6..0000000
--- a/src/kernel/arch/amd64/32/32
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <kernel/arch/generic.h>
-#include <kernel/arch/amd64/gdt.h>
-#include <shared/mem.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-extern char _isr_mini_stack;
-
-struct gdt_entry {
- uint64_t limit_low : 16;
- uint64_t base_low : 24;
- uint64_t accessed : 1; // set by the processor
- // CODE | DATA
- uint64_t rw : 1; // readable? | writeable?
- uint64_t conforming : 1; // conforming? | expands down?
- uint64_t code : 1; // 1 | 0
-
- uint64_t codeordata : 1; // 1 for everything other than TSS and LDT
- uint64_t ring : 2;
- uint64_t present : 1; // always 1
- uint64_t limit_high : 4;
- uint64_t available : 1; // ???
- uint64_t long_mode : 1;
- uint64_t x32 : 1;
- uint64_t gran : 1; // 1 - 4kb, 0 - 1b
- uint64_t base_high : 8;
-} __attribute__((packed));
-
-struct tss_entry {
- uint32_t _unused0;
- uint32_t esp0; // kernel mode stack pointer
- uint32_t ss0; // kernel mode stack segment
- uint8_t _unused1[0x5c];
-} __attribute__((packed));
-
-struct lgdt_arg {
- uint16_t limit;
- uint32_t base;
-} __attribute__((packed));
-
-__attribute__((section(".shared")))
-static struct gdt_entry GDT[SEG_end];
-__attribute__((section(".shared")))
-static struct tss_entry TSS;
-static struct lgdt_arg lgdt_arg; // probably doesn't need to be global
-
-static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code);
-static void gdt_prepare(void);
-static void gdt_load(void);
-
-
-static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code) {
- *entry = (struct gdt_entry) {
- // set up the identity mapping
- .limit_low = 0xFFFF,
- .limit_high = 0xF,
- .gran = 1, // 4KB * 0xFFFFF = (almost) 4GB
- .base_low = 0,
- .base_high = 0,
-
- .ring = ring,
- .code = code,
-
- .accessed = 0,
- .rw = 1,
- .conforming = 0,
- .codeordata = 1,
- .present = 1,
- .long_mode = 0, // ???
- .available = 1, // ???
- .x32 = 1,
- };
-}
-
-static void gdt_prepare(void) {
- GDT[SEG_null].present = 0;
-
- gdt_fillout(&GDT[SEG_r0code], 0, true);
- gdt_fillout(&GDT[SEG_r0data], 0, false);
- gdt_fillout(&GDT[SEG_r3code], 3, true);
- gdt_fillout(&GDT[SEG_r3data], 3, false);
-
- // tss
- memset(&TSS, 0, sizeof(TSS));
- TSS.ss0 = SEG_r0data << 3; // kernel data segment
- TSS.esp0 = (uintptr_t) &_isr_mini_stack;
-
- GDT[SEG_TSS] = (struct gdt_entry) {
- .limit_low = sizeof(TSS),
- .limit_high = sizeof(TSS) >> 16,
- .gran = 0,
- .base_low = (uintptr_t) &TSS,
- .base_high = ((uintptr_t) &TSS) >> 24,
-
- .accessed = 1, // 1 for TSS
- .rw = 0, // 1 busy / 0 not busy
- .conforming = 0, // 0 for TSS
- .code = 1, // 32bit
- .codeordata = 0, // is a system entry
- .ring = 3,
- .present = 1,
- .available = 0, // 0 for TSS
- .long_mode = 0,
- .x32 = 0, // idk
- };
-}
-
-static void gdt_load(void) {
- lgdt_arg.limit = sizeof(GDT) - 1;
- lgdt_arg.base = (uintptr_t) &GDT;
- asm("lgdt (%0)"
- : : "r" (&lgdt_arg) : "memory");
-
- asm("ltr %%ax"
- : : "a" (SEG_TSS << 3 | 3) : "memory");
-
- // update all segment registers
- gdt_farjump(SEG_r0code << 3);
- asm("mov %0, %%ds;"
- "mov %0, %%ss;"
- "mov %0, %%es;"
- "mov %0, %%fs;"
- "mov %0, %%gs;"
- : : "r" (SEG_r0data << 3) : "memory");
-}
-
-void gdt_init(void) {
- gdt_prepare();
- gdt_load();
-}
diff --git a/src/kernel/arch/amd64/32/boot.s b/src/kernel/arch/amd64/32/boot.s
index 0e21036..0621038 100644
--- a/src/kernel/arch/amd64/32/boot.s
+++ b/src/kernel/arch/amd64/32/boot.s
@@ -2,6 +2,7 @@
.global _start
.type _start, @function
_start:
+ cli
mov $_stack_top, %esp
push %ebx // save the address of the multiboot struct
diff --git a/src/kernel/arch/amd64/interrupts/irq.c b/src/kernel/arch/amd64/interrupts/irq.c
index b5e9255..9872ec7 100644
--- a/src/kernel/arch/amd64/interrupts/irq.c
+++ b/src/kernel/arch/amd64/interrupts/irq.c
@@ -5,6 +5,12 @@
static const int PIC1 = 0x20;
static const int PIC2 = 0xA0;
+static void pit_init(void) {
+ uint16_t divisor = 1193;
+ port_out8(0x40, divisor & 0xFF);
+ port_out8(0x40, divisor >> 8);
+}
+
void irq_init(void) {
port_out8(PIC1, 0x11); /* start init sequence */
port_out8(PIC2, 0x11);
@@ -18,11 +24,14 @@ void irq_init(void) {
port_out8(PIC2+1, 0x1);
uint8_t mask = 0xff;
+ mask &= ~(1 << IRQ_PIT);
mask &= ~(1 << IRQ_PS2);
mask &= ~(1 << IRQ_COM1);
port_out8(PIC1+1, mask);
port_out8(PIC2+1, 0xff);
+
+ pit_init();
}
void irq_eoi(uint8_t line) {
diff --git a/src/kernel/arch/amd64/interrupts/irq.h b/src/kernel/arch/amd64/interrupts/irq.h
index 3340101..2a4b12d 100644
--- a/src/kernel/arch/amd64/interrupts/irq.h
+++ b/src/kernel/arch/amd64/interrupts/irq.h
@@ -3,6 +3,7 @@
#include <stdint.h>
#define IRQ_IBASE 0x20
+#define IRQ_PIT 0
#define IRQ_PS2 1
#define IRQ_COM1 4
diff --git a/src/kernel/arch/amd64/interrupts/isr.c b/src/kernel/arch/amd64/interrupts/isr.c
index 71da27b..0bfd865 100644
--- a/src/kernel/arch/amd64/interrupts/isr.c
+++ b/src/kernel/arch/amd64/interrupts/isr.c
@@ -3,6 +3,7 @@
#include <kernel/arch/amd64/interrupts/irq.h>
#include <kernel/arch/amd64/interrupts/isr.h>
#include <kernel/arch/amd64/port_io.h>
+#include <kernel/arch/amd64/time.h>
#include <kernel/arch/generic.h>
#include <kernel/panic.h>
#include <kernel/proc.h>
@@ -28,6 +29,11 @@ void isr_stage3(int interrupt, uint64_t *stackframe) {
isr_test_interrupt_called = true;
return;
+ case IRQ_IBASE + IRQ_PIT:
+ pit_irq();
+ irq_eoi(IRQ_PIT);
+ return;
+
case IRQ_IBASE + IRQ_PS2:
ps2_irq();
irq_eoi(IRQ_PS2);
diff --git a/src/kernel/arch/amd64/time.c b/src/kernel/arch/amd64/time.c
new file mode 100644
index 0000000..d6e53dd
--- /dev/null
+++ b/src/kernel/arch/amd64/time.c
@@ -0,0 +1,50 @@
+#include <kernel/arch/amd64/time.h>
+#include <kernel/panic.h>
+#include <kernel/proc.h>
+
+static uint64_t uptime = 0, goal = ~0;
+static struct process *scheduled = NULL;
+
+uint64_t uptime_ms(void) { return uptime; }
+
+static void update_goal(void) {
+ goal = scheduled ? scheduled->waits4timer.goal : ~(uint64_t)0;
+}
+
+void pit_irq(void) {
+ // TODO inefficient - getting here executes a lot of code which could just be a few lines of asm
+ uptime++;
+ if (uptime < goal) return;
+
+ struct process *p = scheduled;
+ assert(p);
+ scheduled = p->waits4timer.next;
+ process_transition(p, PS_RUNNING);
+ update_goal();
+}
+
+void timer_schedule(struct process *p, uint64_t time) {
+ process_transition(p, PS_WAITS4TIMER);
+ p->waits4timer.goal = time;
+
+ struct process **slot = &scheduled;
+ while (*slot && (*slot)->waits4timer.goal <= time) {
+ assert((*slot)->state == PS_WAITS4TIMER);
+ slot = &(*slot)->waits4timer.next;
+ }
+ p->waits4timer.next = *slot;
+ *slot = p;
+ update_goal();
+}
+
+void timer_deschedule(struct process *p) {
+ assert(p->state == PS_WAITS4TIMER);
+
+ struct process **slot = &scheduled;
+ while (*slot && *slot != p)
+ slot = &(*slot)->waits4timer.next;
+ assert(*slot);
+ *slot = p->waits4timer.next;
+
+ update_goal();
+}
diff --git a/src/kernel/arch/amd64/time.h b/src/kernel/arch/amd64/time.h
new file mode 100644
index 0000000..04ba9b0
--- /dev/null
+++ b/src/kernel/arch/amd64/time.h
@@ -0,0 +1,4 @@
+#pragma once
+#include <kernel/arch/generic.h>
+
+void pit_irq(void);