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/acpi.c68
-rw-r--r--src/kernel/arch/amd64/acpi.h4
-rw-r--r--src/kernel/arch/amd64/boot.c7
-rw-r--r--src/kernel/arch/amd64/time.c46
-rw-r--r--src/kernel/arch/amd64/time.h4
5 files changed, 110 insertions, 19 deletions
diff --git a/src/kernel/arch/amd64/acpi.c b/src/kernel/arch/amd64/acpi.c
new file mode 100644
index 0000000..cc7791f
--- /dev/null
+++ b/src/kernel/arch/amd64/acpi.c
@@ -0,0 +1,68 @@
+#include <kernel/arch/amd64/acpi.h>
+#include <kernel/panic.h>
+#include <shared/mem.h>
+#include <stdint.h>
+
+typedef struct {
+ char sig[8];
+ uint8_t checksum;
+ char oemid[6];
+ uint8_t rev;
+ uint32_t rsdt;
+} __attribute__((packed)) RDSP;
+
+typedef struct {
+ char sig[4];
+ uint32_t len;
+ uint8_t rev;
+ uint8_t checksum;
+ char oemID[6];
+ char oemTID[8];
+ uint32_t oemRev;
+ uint32_t creatorId;
+ uint32_t creatorRev;
+ char data[0];
+} __attribute__((packed)) SDT;
+
+/* https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf */
+typedef struct {
+ uint8_t where;
+ uint8_t bitwidth;
+ uint8_t bitoffset;
+ uint8_t _reserved;
+ uint64_t addr;
+} __attribute__((packed)) GAS; /* Generic Address Structure */
+
+typedef struct {
+ SDT hdr;
+ uint32_t _someid;
+ GAS addr;
+ /* ... */
+} __attribute__((packed)) HPET;
+
+void
+acpi_parse(const void *rdsp_v)
+{
+ const RDSP *rdsp = rdsp_v;
+ if (memcmp(rdsp->sig, "RSD PTR ", 8) != 0) {
+ panic_invalid_state();
+ }
+
+ SDT *rsdt = (void*)(uintptr_t)rdsp->rsdt;
+ if (memcmp(rsdt->sig, "RSDT ", 4) != 0) {
+ panic_invalid_state();
+ }
+
+ uint32_t *sub = (void*)rsdt->data;
+ int len = (rsdt->len - sizeof(SDT)) / 4;
+ for (int i = 0; i < len; i++) {
+ SDT *it = (void*)(uintptr_t)sub[i];
+ if (memcmp(it->sig, "HPET", 4) == 0) {
+ HPET *hpet = (void*)it;
+ GAS *gas = &hpet->addr;
+ if (gas->where == 0) { /* in memory */
+ hpet_init((void*)gas->addr);
+ }
+ }
+ }
+}
diff --git a/src/kernel/arch/amd64/acpi.h b/src/kernel/arch/amd64/acpi.h
new file mode 100644
index 0000000..138bf41
--- /dev/null
+++ b/src/kernel/arch/amd64/acpi.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void acpi_parse(const void *rsdp);
+void hpet_init(void *base);
diff --git a/src/kernel/arch/amd64/boot.c b/src/kernel/arch/amd64/boot.c
index 337d23b..330a11e 100644
--- a/src/kernel/arch/amd64/boot.c
+++ b/src/kernel/arch/amd64/boot.c
@@ -1,4 +1,5 @@
#include <kernel/arch/amd64/3rdparty/multiboot2.h>
+#include <kernel/arch/amd64/acpi.h>
#include <kernel/arch/amd64/boot.h>
#include <kernel/arch/amd64/driver/driver.h>
#include <kernel/arch/amd64/driver/serial.h>
@@ -71,6 +72,12 @@ void kmain_early(void *mbi) {
video_init(vid);
pata_init();
+ {
+ struct multiboot_tag_old_acpi *mod;
+ mod = mbi_tag(mbi, MULTIBOOT_TAG_TYPE_ACPI_OLD);
+ acpi_parse(mod->rsdp);
+ }
+
kprintf("pci...\n");
pci_init();
diff --git a/src/kernel/arch/amd64/time.c b/src/kernel/arch/amd64/time.c
index f4fa744..ef76249 100644
--- a/src/kernel/arch/amd64/time.c
+++ b/src/kernel/arch/amd64/time.c
@@ -1,31 +1,49 @@
+#include <kernel/arch/amd64/acpi.h>
#include <kernel/arch/amd64/boot.h>
#include <kernel/arch/amd64/interrupts.h>
-#include <kernel/arch/amd64/time.h>
#include <kernel/panic.h>
#include <kernel/proc.h>
-static uint64_t uptime = 0, goal = ~0;
static Proc *scheduled = NULL;
-uint64_t uptime_ms(void) { return uptime; }
+static void *hpet = NULL;
+static uint64_t hpet_period;
-static void update_goal(void) {
- goal = scheduled ? scheduled->waits4timer.goal : ~(uint64_t)0;
+void hpet_init(void *base) {
+ if (hpet) panic_invalid_state();
+ hpet = base;
+
+ uint64_t *info = hpet;
+ uint64_t *cfg = hpet + 0x10;
+ hpet_period = *info >> 32;
+ *cfg |= 1<<0; /* enable */
}
-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;
+uint64_t uptime_ns(void) {
+ if (hpet == NULL) panic_invalid_state();
+ uint64_t *counter = hpet + 0xF0;
+ unsigned __int128 femto = *counter * hpet_period;
+ uint64_t nano = femto / 1000000;
+ return nano;
+}
+static void pit_irq(void) {
Proc *p = scheduled;
- assert(p);
- scheduled = p->waits4timer.next;
- proc_setstate(p, PS_RUNNING);
- update_goal();
+ if (p && p->waits4timer.goal < uptime_ns()) {
+ scheduled = p->waits4timer.next;
+ proc_setstate(p, PS_RUNNING);
+ }
}
+
void timer_schedule(Proc *p, uint64_t time) {
+ uint64_t now = uptime_ns();
+ /* to prevent leaking the current uptime, saturate instead of overflowing */
+ time = now + time;
+ if (time < now) {
+ time = ~0;
+ }
+
proc_setstate(p, PS_WAITS4TIMER);
p->waits4timer.goal = time;
@@ -36,7 +54,6 @@ void timer_schedule(Proc *p, uint64_t time) {
}
p->waits4timer.next = *slot;
*slot = p;
- update_goal();
}
void timer_deschedule(Proc *p) {
@@ -49,7 +66,6 @@ void timer_deschedule(Proc *p) {
*slot = p->waits4timer.next;
proc_setstate(p, PS_RUNNING);
- update_goal();
}
void timer_init(void) {
diff --git a/src/kernel/arch/amd64/time.h b/src/kernel/arch/amd64/time.h
deleted file mode 100644
index 04ba9b0..0000000
--- a/src/kernel/arch/amd64/time.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-#include <kernel/arch/generic.h>
-
-void pit_irq(void);