diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/tests/kernel/miscsyscall.c | 6 | ||||
-rw-r--r-- | src/kernel/arch/amd64/acpi.c | 68 | ||||
-rw-r--r-- | src/kernel/arch/amd64/acpi.h | 4 | ||||
-rw-r--r-- | src/kernel/arch/amd64/boot.c | 7 | ||||
-rw-r--r-- | src/kernel/arch/amd64/time.c | 46 | ||||
-rw-r--r-- | src/kernel/arch/amd64/time.h | 4 | ||||
-rw-r--r-- | src/kernel/arch/generic.h | 4 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 3 |
8 files changed, 118 insertions, 24 deletions
diff --git a/src/cmd/tests/kernel/miscsyscall.c b/src/cmd/tests/kernel/miscsyscall.c index 0518654..7c61392 100644 --- a/src/cmd/tests/kernel/miscsyscall.c +++ b/src/cmd/tests/kernel/miscsyscall.c @@ -271,7 +271,11 @@ static void test_sleep(void) { long ret = _sys_read(reader, buf, sizeof buf, 0); if (ret == 0) break; test(pos + ret <= target); - test(memcmp(buf, expected + pos, ret) == 0); + if (memcmp(buf, expected + pos, ret) != 0) { + buf[ret] = '\0'; + printf("got %s\n", buf); + test(0); + } pos += ret; } test(pos == target); 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); diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h index 647badc..a6a14c9 100644 --- a/src/kernel/arch/generic.h +++ b/src/kernel/arch/generic.h @@ -23,8 +23,8 @@ void shutdown(void); /** on x86: waits for an IRQ */ void cpu_pause(void); -uint64_t uptime_ms(void); -void timer_schedule(Proc *p, uint64_t time); +uint64_t uptime_ns(void); +void timer_schedule(Proc *p, uint64_t ns); void timer_deschedule(Proc *p); // src/arch/i386/sysenter.s diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index b040285..a2e0e27 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -347,8 +347,7 @@ long _sys_pipe(hid_t __user user_ends[2], int flags) { } void _sys_sleep(long ms) { - // TODO no overflow check - can leak current uptime - timer_schedule(proc_cur, uptime_ms() + ms); + timer_schedule(proc_cur, ms * 1000000); } void _sys_filicide(void) { |