summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2023-09-19 15:38:34 +0200
committerdzwdz2023-09-19 15:38:34 +0200
commit8b0953d8cdbf676cf100bcb0f77a0c82755b53ae (patch)
tree9ebfdfa1bf8bd7d663b35482b622338a14c8133c /src/kernel
parent14fd2aecd074fb93bb509df0c1cedd1f1055a4a6 (diff)
kernel: use HPET timer for sleeps
not strictly necessary, but this should improve: 1. sleep performance 2. power efficiency when idle
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/arch/amd64/boot.c1
-rw-r--r--src/kernel/arch/amd64/boot.h1
-rw-r--r--src/kernel/arch/amd64/interrupts.h2
-rw-r--r--src/kernel/arch/amd64/interrupts/irq.c10
-rw-r--r--src/kernel/arch/amd64/time.c71
5 files changed, 58 insertions, 27 deletions
diff --git a/src/kernel/arch/amd64/boot.c b/src/kernel/arch/amd64/boot.c
index 330a11e..76bc864 100644
--- a/src/kernel/arch/amd64/boot.c
+++ b/src/kernel/arch/amd64/boot.c
@@ -35,7 +35,6 @@ void kmain_early(void *mbi) {
idt_init();
kprintf("irq...");
irq_init();
- timer_init();
{
kprintf("mem...\n");
diff --git a/src/kernel/arch/amd64/boot.h b/src/kernel/arch/amd64/boot.h
index fac4ab6..0a867a8 100644
--- a/src/kernel/arch/amd64/boot.h
+++ b/src/kernel/arch/amd64/boot.h
@@ -17,7 +17,6 @@ enum gdt_segs {
void kmain_early(void *mbi);
void gdt_init(void);
void idt_init(void);
-void timer_init(void);
/* used from asm */
extern struct lgdt_arg lgdt_arg;
diff --git a/src/kernel/arch/amd64/interrupts.h b/src/kernel/arch/amd64/interrupts.h
index 262ea16..dfc523a 100644
--- a/src/kernel/arch/amd64/interrupts.h
+++ b/src/kernel/arch/amd64/interrupts.h
@@ -4,10 +4,10 @@
#define IRQ_COM1 4
#define IRQ_IBASE 0x20
-#define IRQ_PIT 0
#define IRQ_PS2KB 1
#define IRQ_PS2MOUSE 12
#define IRQ_RTL8139 11
+#define IRQ_HPET 8
extern void (*irq_fn[16])(void);
extern const char _isr_stubs;
diff --git a/src/kernel/arch/amd64/interrupts/irq.c b/src/kernel/arch/amd64/interrupts/irq.c
index e900450..f2f11fb 100644
--- a/src/kernel/arch/amd64/interrupts/irq.c
+++ b/src/kernel/arch/amd64/interrupts/irq.c
@@ -5,12 +5,6 @@
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);
@@ -26,15 +20,13 @@ void irq_init(void) {
uint16_t mask = 0xffff;
mask &= ~(1 << 2); // cascade
mask &= ~(1 << IRQ_COM1);
- mask &= ~(1 << IRQ_PIT);
mask &= ~(1 << IRQ_PS2KB);
mask &= ~(1 << IRQ_PS2MOUSE);
mask &= ~(1 << IRQ_RTL8139);
+ mask &= ~(1 << IRQ_HPET);
port_out8(PIC1+1, mask & 0xff);
port_out8(PIC2+1, (mask >> 8) & 0xff);
-
- pit_init();
}
void irq_eoi(uint8_t line) {
diff --git a/src/kernel/arch/amd64/time.c b/src/kernel/arch/amd64/time.c
index ef76249..44bd84e 100644
--- a/src/kernel/arch/amd64/time.c
+++ b/src/kernel/arch/amd64/time.c
@@ -6,40 +6,83 @@
static Proc *scheduled = NULL;
-static void *hpet = NULL;
+static volatile void *hpet = NULL;
static uint64_t hpet_period;
+static void hpet_irq(void);
+
+enum {
+ /* bitfields */
+ HpetIs64Bit = 1<<13,
+ HpetHasLegacyMap = 1<<15,
+
+ HpetEnabled = 1<<0,
+ HpetUseLegacyMap = 1<<1,
+
+ HpetTimerTrigger = 1<<1, /* true if level triggered */
+ HpetTimerEnable = 1<<2,
+ HpetTimerPeriodic = 1<<3,
+ HpetTimer64 = 1<<5,
+};
+
void hpet_init(void *base) {
if (hpet) panic_invalid_state();
hpet = base;
- uint64_t *info = hpet;
- uint64_t *cfg = hpet + 0x10;
+ volatile uint64_t *info = hpet;
+ volatile uint64_t *cfg = hpet + 0x10;
hpet_period = *info >> 32;
- *cfg |= 1<<0; /* enable */
+ if (!(*info & HpetIs64Bit)) panic_unimplemented();
+ if (!(*info & HpetHasLegacyMap)) panic_unimplemented();
+
+ volatile uint64_t *timcfg = hpet + 0x120;
+ if (!(*timcfg & HpetTimer64)) panic_unimplemented();
+ *timcfg |= HpetTimerTrigger;
+ *timcfg &= ~HpetTimerPeriodic;
+ *cfg |= HpetEnabled | HpetUseLegacyMap;
+
+ irq_fn[IRQ_HPET] = hpet_irq;
}
-uint64_t uptime_ns(void) {
+static void hpet_sched(void) {
+ volatile uint64_t *status = hpet + 0x20;
+ volatile uint64_t *timcfg = hpet + 0x120;
+ volatile uint64_t *timval = hpet + 0x128;
+ if (scheduled) {
+ *timval = scheduled->waits4timer.goal;
+ *timcfg |= HpetTimerEnable;
+ } else {
+ *timcfg &= ~HpetTimerEnable;
+ }
+ *status = ~0;
+}
+
+static uint64_t get_counter(void) {
if (hpet == NULL) panic_invalid_state();
- uint64_t *counter = hpet + 0xF0;
- unsigned __int128 femto = *counter * hpet_period;
+ volatile uint64_t *counter = hpet + 0xF0;
+ return *counter;
+}
+
+uint64_t uptime_ns(void) {
+ unsigned __int128 femto = get_counter() * hpet_period;
uint64_t nano = femto / 1000000;
return nano;
}
-static void pit_irq(void) {
+static void hpet_irq(void) {
Proc *p = scheduled;
- if (p && p->waits4timer.goal < uptime_ns()) {
+ if (p && p->waits4timer.goal < get_counter()) {
scheduled = p->waits4timer.next;
proc_setstate(p, PS_RUNNING);
}
+ hpet_sched();
}
void timer_schedule(Proc *p, uint64_t time) {
- uint64_t now = uptime_ns();
+ uint64_t now = get_counter();
/* to prevent leaking the current uptime, saturate instead of overflowing */
- time = now + time;
+ time = now + (time * 1000000 / hpet_period);
if (time < now) {
time = ~0;
}
@@ -54,6 +97,7 @@ void timer_schedule(Proc *p, uint64_t time) {
}
p->waits4timer.next = *slot;
*slot = p;
+ hpet_sched(); // TODO can sometimes be skipped
}
void timer_deschedule(Proc *p) {
@@ -66,8 +110,5 @@ void timer_deschedule(Proc *p) {
*slot = p->waits4timer.next;
proc_setstate(p, PS_RUNNING);
-}
-
-void timer_init(void) {
- irq_fn[IRQ_PIT] = pit_irq;
+ hpet_sched(); // TODO can sometimes be skipped
}