From 686aa1cf45189cc05d1200e1634eec537ab91ff7 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 14 Feb 2024 11:11:54 -0500 Subject: kernel/amd64: hpet: HPET is architecture specific Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/hpet.c | 193 +++++++++++++++++++++++++++++++++++++++++ sys/arch/amd64/amd64/lapic.c | 2 +- sys/arch/amd64/amd64/machdep.c | 12 +++ sys/dev/timer/hpet.c | 193 ----------------------------------------- sys/firmware/acpi/acpi_init.c | 9 -- sys/include/arch/amd64/hpet.h | 40 +++++++++ sys/include/dev/timer/hpet.h | 40 --------- sys/include/sys/machdep.h | 1 + sys/kern/init_main.c | 4 + 9 files changed, 251 insertions(+), 243 deletions(-) create mode 100644 sys/arch/amd64/amd64/hpet.c delete mode 100644 sys/dev/timer/hpet.c create mode 100644 sys/include/arch/amd64/hpet.h delete mode 100644 sys/include/dev/timer/hpet.h diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c new file mode 100644 index 0000000..9835d6c --- /dev/null +++ b/sys/arch/amd64/amd64/hpet.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +__MODULE_NAME("hpet"); +__KERNEL_META("$Hyra$: hpet.c, Ian Marco Moffett, " + "HPET driver"); + +#define HPET_REG_CAPS 0x00 +#define HPET_GENERAL_CONFIG 0x10 +#define HPET_REG_MAIN_COUNTER 0xF0 + +#define CAP_REV_ID(caps) __SHIFTOUT(caps, 0xFF) +#define CAP_NUM_TIM(caps) __SHIFTOUT(caps, 0x1F << 8) +#define CAP_COUNT_SIZE(caps) __SHIFTOUT(caps, __BIT(13)) +#define CAP_VENDOR_ID(caps) __SHIFTOUT(caps, 0xFFFF << 16) +#define CAP_CLK_PERIOD(caps) (caps >> 32) + +/* + * TODO: Use some sort of helper function that + * uses PAUSE or some similar instruction + * for the current architecture. It is + * *not* a good idea to spin for a prolonged + * amount of time without it. For now we'll + * just use PAUSE on x86_64 like this. + */ +#if defined(__x86_64__) +#define spinwait_hint() __ASMV("pause") +#else +#define spinwait_hint() __nothing +#endif /* defined(__x86_64__) */ + +static struct timer timer = { 0 }; +static struct hpet *acpi_hpet = NULL; +static void *hpet_base = NULL; +static bool is_faulty = false; + +/* + * Read from HPET register space. + * + * @reg: Register to read from. + */ +static inline uint64_t +hpet_read(uint32_t reg) +{ + void *addr; + + addr = (void *)((uintptr_t)hpet_base + reg); + return mmio_read64(addr); +} + +/* + * Write to HPET register space. + * + * @reg: Register to write to. + * @val: Value to write. + */ +static inline void +hpet_write(uint32_t reg, uint64_t val) +{ + void *addr; + + addr = (void *)((uintptr_t)hpet_base + reg); + mmio_write64(addr, val); +} + +static int +hpet_sleep(uint64_t n, uint64_t units) +{ + uint64_t caps; + uint32_t period; + uint64_t counter_val; + volatile size_t ticks; + + /* Don't even try if faulty, would probably cause deadlock */ + if (is_faulty) { + return EXIT_FAILURE; + } + + caps = hpet_read(HPET_REG_CAPS); + period = CAP_CLK_PERIOD(caps); + counter_val = hpet_read(HPET_REG_MAIN_COUNTER); + + ticks = counter_val + (n * (units / period)); + + while (hpet_read(HPET_REG_MAIN_COUNTER) < ticks) { + spinwait_hint(); + } + + return EXIT_SUCCESS; +} + +int +hpet_msleep(size_t ms) +{ + return hpet_sleep(ms, 1000000000000); +} + +int +hpet_usleep(size_t us) +{ + return hpet_sleep(us, 1000000000); +} + +int +hpet_nsleep(size_t ns) +{ + return hpet_sleep(ns, 1000000); +} + +int +hpet_init(void) +{ + struct acpi_gas *gas; + uint64_t caps; + + acpi_hpet = acpi_query("HPET"); + if (acpi_hpet == NULL) + return 1; /* Not found */ + + gas = &acpi_hpet->gas; + hpet_base = (void *)gas->address; + caps = hpet_read(HPET_REG_CAPS); + + /* Ensure caps aren't bogus */ + if (CAP_REV_ID(caps) == 0) { + KERR("Found bogus revision, assuming faulty\n"); + is_faulty = true; + return 1; + } + if (CAP_CLK_PERIOD(caps) > 0x05F5E100) { + /* + * The spec states this counter clk period + * must be <= 0x05F5E100. So we'll consider it + * as bogus if it exceeds this value + */ + KERR("Found bogus COUNTER_CLK_PERIOD, assuming faulty\n"); + KINFO("HPET REV - 0x%x\n", CAP_REV_ID(caps)); + KINFO("COUNTER_CLK_PERIOD - 0x%x\n", CAP_CLK_PERIOD(caps)); + is_faulty = true; + return 1; + } + + KINFO("HPET integrity verified\n"); + + hpet_write(HPET_REG_MAIN_COUNTER, 0); + hpet_write(HPET_GENERAL_CONFIG, 1); + + /* Setup the timer descriptor */ + timer.name = "HIGH_PRECISION_EVENT_TIMER"; + timer.msleep = hpet_msleep; + timer.usleep = hpet_usleep; + timer.nsleep = hpet_nsleep; + register_timer(TIMER_GP, &timer); + + /* Not faulty */ + is_faulty = false; + return 0; +} diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index c4e81a6..a1cbbf1 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -37,13 +37,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include __MODULE_NAME("lapic"); __KERNEL_META("$Hyra$: lapic.c, Ian Marco Moffett, " diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 07f16fc..af3918d 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -29,10 +29,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -94,6 +96,16 @@ serial_dbgch(char c) uart8250_write(c); } +void +chips_init(void) +{ + /* Hyra requires HPET on x86_64 */ + if (hpet_init() != 0) + panic("Machine does not support HPET!\n"); + + hpet_init(); +} + /* * Things set up before processor_init() call... */ diff --git a/sys/dev/timer/hpet.c b/sys/dev/timer/hpet.c deleted file mode 100644 index b836205..0000000 --- a/sys/dev/timer/hpet.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Hyra nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -__MODULE_NAME("hpet"); -__KERNEL_META("$Hyra$: hpet.c, Ian Marco Moffett, " - "HPET driver"); - -#define HPET_REG_CAPS 0x00 -#define HPET_GENERAL_CONFIG 0x10 -#define HPET_REG_MAIN_COUNTER 0xF0 - -#define CAP_REV_ID(caps) __SHIFTOUT(caps, 0xFF) -#define CAP_NUM_TIM(caps) __SHIFTOUT(caps, 0x1F << 8) -#define CAP_COUNT_SIZE(caps) __SHIFTOUT(caps, __BIT(13)) -#define CAP_VENDOR_ID(caps) __SHIFTOUT(caps, 0xFFFF << 16) -#define CAP_CLK_PERIOD(caps) (caps >> 32) - -/* - * TODO: Use some sort of helper function that - * uses PAUSE or some similar instruction - * for the current architecture. It is - * *not* a good idea to spin for a prolonged - * amount of time without it. For now we'll - * just use PAUSE on x86_64 like this. - */ -#if defined(__x86_64__) -#define spinwait_hint() __ASMV("pause") -#else -#define spinwait_hint() __nothing -#endif /* defined(__x86_64__) */ - -static struct timer timer = { 0 }; -static struct hpet *acpi_hpet = NULL; -static void *hpet_base = NULL; -static bool is_faulty = false; - -/* - * Read from HPET register space. - * - * @reg: Register to read from. - */ -static inline uint64_t -hpet_read(uint32_t reg) -{ - void *addr; - - addr = (void *)((uintptr_t)hpet_base + reg); - return mmio_read64(addr); -} - -/* - * Write to HPET register space. - * - * @reg: Register to write to. - * @val: Value to write. - */ -static inline void -hpet_write(uint32_t reg, uint64_t val) -{ - void *addr; - - addr = (void *)((uintptr_t)hpet_base + reg); - mmio_write64(addr, val); -} - -static int -hpet_sleep(uint64_t n, uint64_t units) -{ - uint64_t caps; - uint32_t period; - uint64_t counter_val; - volatile size_t ticks; - - /* Don't even try if faulty, would probably cause deadlock */ - if (is_faulty) { - return EXIT_FAILURE; - } - - caps = hpet_read(HPET_REG_CAPS); - period = CAP_CLK_PERIOD(caps); - counter_val = hpet_read(HPET_REG_MAIN_COUNTER); - - ticks = counter_val + (n * (units / period)); - - while (hpet_read(HPET_REG_MAIN_COUNTER) < ticks) { - spinwait_hint(); - } - - return EXIT_SUCCESS; -} - -int -hpet_msleep(size_t ms) -{ - return hpet_sleep(ms, 1000000000000); -} - -int -hpet_usleep(size_t us) -{ - return hpet_sleep(us, 1000000000); -} - -int -hpet_nsleep(size_t ns) -{ - return hpet_sleep(ns, 1000000); -} - -int -hpet_init(void) -{ - struct acpi_gas *gas; - uint64_t caps; - - acpi_hpet = acpi_query("HPET"); - if (acpi_hpet == NULL) - return 1; /* Not found */ - - gas = &acpi_hpet->gas; - hpet_base = (void *)gas->address; - caps = hpet_read(HPET_REG_CAPS); - - /* Ensure caps aren't bogus */ - if (CAP_REV_ID(caps) == 0) { - KERR("Found bogus revision, assuming faulty\n"); - is_faulty = true; - return 1; - } - if (CAP_CLK_PERIOD(caps) > 0x05F5E100) { - /* - * The spec states this counter clk period - * must be <= 0x05F5E100. So we'll consider it - * as bogus if it exceeds this value - */ - KERR("Found bogus COUNTER_CLK_PERIOD, assuming faulty\n"); - KINFO("HPET REV - 0x%x\n", CAP_REV_ID(caps)); - KINFO("COUNTER_CLK_PERIOD - 0x%x\n", CAP_CLK_PERIOD(caps)); - is_faulty = true; - return 1; - } - - KINFO("HPET integrity verified\n"); - - hpet_write(HPET_REG_MAIN_COUNTER, 0); - hpet_write(HPET_GENERAL_CONFIG, 1); - - /* Setup the timer descriptor */ - timer.name = "HIGH_PRECISION_EVENT_TIMER"; - timer.msleep = hpet_msleep; - timer.usleep = hpet_usleep; - timer.nsleep = hpet_nsleep; - register_timer(TIMER_GP, &timer); - - /* Not faulty */ - is_faulty = false; - return 0; -} diff --git a/sys/firmware/acpi/acpi_init.c b/sys/firmware/acpi/acpi_init.c index f267d91..c23506b 100644 --- a/sys/firmware/acpi/acpi_init.c +++ b/sys/firmware/acpi/acpi_init.c @@ -33,7 +33,6 @@ #include #include #include -#include #include __MODULE_NAME("acpi"); @@ -107,12 +106,4 @@ acpi_init(void) panic("Root SDT has an invalid checksum!\n"); } root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; - -#if defined(__x86_64__) - /* Hyra requires HPET on x86_64 */ - if (hpet_init() != 0) - panic("Machine does not support HPET!\n"); -#else - hpet_init(); -#endif /* defined(__x86_64__) */ } diff --git a/sys/include/arch/amd64/hpet.h b/sys/include/arch/amd64/hpet.h new file mode 100644 index 0000000..dc4366c --- /dev/null +++ b/sys/include/arch/amd64/hpet.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TIMER_HPET_H_ +#define _TIMER_HPET_H_ + +#include + +int hpet_init(void); +int hpet_msleep(size_t ms); +int hpet_usleep(size_t us); +int hpet_nsleep(size_t ns); + +#endif /* !_TIMER_HPET_H_ */ diff --git a/sys/include/dev/timer/hpet.h b/sys/include/dev/timer/hpet.h deleted file mode 100644 index dc4366c..0000000 --- a/sys/include/dev/timer/hpet.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Hyra nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _TIMER_HPET_H_ -#define _TIMER_HPET_H_ - -#include - -int hpet_init(void); -int hpet_msleep(size_t ms); -int hpet_usleep(size_t us); -int hpet_nsleep(size_t ns); - -#endif /* !_TIMER_HPET_H_ */ diff --git a/sys/include/sys/machdep.h b/sys/include/sys/machdep.h index b97748c..3180e1d 100644 --- a/sys/include/sys/machdep.h +++ b/sys/include/sys/machdep.h @@ -37,6 +37,7 @@ #define MAXCPUS 32 +__weak void chips_init(void); __weak void processor_init(void); __weak void pre_init(void); __weak void processor_halt(void); diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 2fe84ed..a5d7577 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -87,6 +87,10 @@ main(void) acpi_init(); + if (chips_init == NULL) { + chips_init(); + } + processor_init(); list_timers(); -- cgit v1.2.3