From 996e41f4d86d9369d62700383ab090bdba2be9a7 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 15:50:57 -0400 Subject: kernel: Add initial ACPI code Signed-off-by: Ian Moffett --- sys/dev/acpi/acpi_init.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_subr.c | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 sys/dev/acpi/acpi_init.c create mode 100644 sys/dev/acpi/acpi_subr.c (limited to 'sys/dev/acpi') diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c new file mode 100644 index 0000000..a8423e4 --- /dev/null +++ b/sys/dev/acpi/acpi_init.c @@ -0,0 +1,110 @@ +/* + * 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 +#if defined(__x86_64__) +#include +#endif /* __x86_64__ */ + +#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) + +static struct acpi_root_sdt *root_sdt = NULL; +static size_t root_sdt_entries = 0; +static volatile struct limine_rsdp_request rsdp_req = { + .id = LIMINE_RSDP_REQUEST, + .revision = 0 +}; + +/* + * Writes out OEMID of ACPI header. + * + * @type: Type of structure (e.g RSDP) + * @oemid: OEMID of structure. + */ +static void +acpi_print_oemid(const char *type, char oemid[OEMID_SIZE]) +{ + if (type != NULL) { + pr_trace("%s OEMID: ", type); + } + + for (size_t i = 0; i < OEMID_SIZE; ++i) { + kprintf(OMIT_TIMESTAMP "%c", oemid[i]); + } + + kprintf(OMIT_TIMESTAMP "\n"); +} + +struct acpi_root_sdt * +acpi_get_root_sdt(void) +{ + return root_sdt; +} + +size_t +acpi_get_root_sdt_len(void) +{ + return root_sdt_entries; +} + +void +acpi_init(void) +{ + struct acpi_rsdp *rsdp; + + if (rsdp_req.response == NULL) { + panic("RSDP request has no response\n"); + } + + /* Fetch the RSDP */ + rsdp = rsdp_req.response->address; + acpi_print_oemid("RSDP", rsdp->oemid); + + /* Fetch the root SDT */ + if (rsdp->revision >= 2) { + root_sdt = PHYS_TO_VIRT(rsdp->xsdt_addr); + pr_trace("Using XSDT as root SDT\n"); + } else { + root_sdt = PHYS_TO_VIRT(rsdp->rsdt_addr); + pr_trace("Using RSDT as root SDT\n"); + } + + if (acpi_checksum(&root_sdt->hdr) != 0) { + panic("Root SDT checksum is invalid!\n"); + } + + root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; +} diff --git a/sys/dev/acpi/acpi_subr.c b/sys/dev/acpi/acpi_subr.c new file mode 100644 index 0000000..7cf3287 --- /dev/null +++ b/sys/dev/acpi/acpi_subr.c @@ -0,0 +1,82 @@ +/* + * 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 + +/* + * Compute the ACPI checksum of a header. + * + * @hdr: HDR to check. + * + * Must return zero to be a valid checksum! + */ +uint8_t +acpi_checksum(struct acpi_header *hdr) +{ + uint8_t sum = 0; + + for (int i = 0; i < hdr->length; ++i) { + sum += ((char *)hdr)[i]; + } + + return sum; +} + +/* + * Looks up an ACPI table with a specific + * signature e.g "APIC" for MADT (if present). + * + * @query: The specific query to make e.g "APIC" + */ +void * +acpi_query(const char *query) +{ + struct acpi_header *hdr; + struct acpi_root_sdt *root_sdt; + size_t root_sdt_len, signature_len; + + root_sdt = acpi_get_root_sdt(); + root_sdt_len = acpi_get_root_sdt_len(); + signature_len = sizeof(hdr->signature); + + for (size_t i = 0; i < root_sdt_len; ++i) { + hdr = (struct acpi_header *)PHYS_TO_VIRT(root_sdt->tables[i]); + + if (memcmp(hdr->signature, query, signature_len) == 0) { + return (void *)hdr; + } + } + + return NULL; +} -- cgit v1.2.3 From 7c29fb70b00315bba95fa2a8b044e88a8d0b32d1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 15:52:13 -0400 Subject: kernel/amd64: Add HPET driver Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/hpet.c | 186 ++++++++++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_init.c | 11 +++ sys/include/arch/amd64/hpet.h | 37 +++++++++ 3 files changed, 234 insertions(+) create mode 100644 sys/arch/amd64/amd64/hpet.c create mode 100644 sys/include/arch/amd64/hpet.h (limited to 'sys/dev/acpi') diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c new file mode 100644 index 0000000..860e610 --- /dev/null +++ b/sys/arch/amd64/amd64/hpet.c @@ -0,0 +1,186 @@ +/* + * 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 + +#define pr_trace(fmt, ...) kprintf("hpet: " fmt, ##__VA_ARGS__) +#define pr_error(fmt, ...) pr_trace(__VA_ARGS__) + +#define HPET_REG_CAPS 0x00 +#define HPET_GENERAL_CONFIG 0x10 +#define HPET_REG_MAIN_COUNTER 0xF0 + +#define CAP_REV_ID(caps) (caps & 0xFF) +#define CAP_NUM_TIM(caps) (caps >> 8) & 0x1F +#define CAP_CLK_PERIOD(caps) (caps >> 32) + +#define FSEC_PER_SECOND 1000000000000000ULL +#define USEC_PER_SECOND 1000000ULL + +static void *hpet_base = NULL; +static struct timer timer = {0}; + +/* + * 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; + + 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) { + __ASMV("rep; nop"); + } + + return 0; +} + +static int +hpet_msleep(size_t ms) +{ + return hpet_sleep(ms, 1000000000000); +} + +static int +hpet_usleep(size_t us) +{ + return hpet_sleep(us, 1000000000); +} + +static int +hpet_nsleep(size_t ns) +{ + return hpet_sleep(ns, 1000000); +} + +static size_t +hpet_time_usec(void) +{ + uint64_t period, freq, caps; + uint64_t counter; + + caps = hpet_read(HPET_REG_CAPS); + period = CAP_CLK_PERIOD(caps); + freq = FSEC_PER_SECOND / period; + + counter = hpet_read(HPET_REG_MAIN_COUNTER); + return (counter * USEC_PER_SECOND) / freq; +} + +static size_t +hpet_time_sec(void) +{ + return hpet_time_usec() / USEC_PER_SECOND; +} + +int +hpet_init(void) +{ + struct acpi_gas *gas; + struct acpi_hpet *hpet; + uint64_t caps; + + hpet = acpi_query("HPET"); + if (hpet == NULL) + return -1; + + gas = &hpet->gas; + hpet_base = (void *)gas->address; + + /* Ensure caps aren't bogus */ + caps = hpet_read(HPET_REG_CAPS); + if (CAP_REV_ID(caps) == 0) { + pr_error("Found bogus revision, assuming faulty\n"); + 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 + */ + pr_error("Found bogus COUNTER_CLK_PERIOD, assuming faulty\n"); + return 1; + } + + pr_trace("HPET integrity verified\n"); + hpet_write(HPET_REG_MAIN_COUNTER, 0); + hpet_write(HPET_GENERAL_CONFIG, 1); + + /* Setup timer descriptor */ + timer.name = "HIGH_PRECISION_EVENT_TIMER"; + timer.msleep = hpet_msleep; + timer.usleep = hpet_usleep; + timer.nsleep = hpet_nsleep; + timer.get_time_usec = hpet_time_usec; + timer.get_time_sec = hpet_time_sec; + register_timer(TIMER_GP, &timer); + return 0; +} diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c index a8423e4..f445d95 100644 --- a/sys/dev/acpi/acpi_init.c +++ b/sys/dev/acpi/acpi_init.c @@ -48,6 +48,16 @@ static volatile struct limine_rsdp_request rsdp_req = { .revision = 0 }; +static void +acpi_init_hpet(void) +{ +#if defined(__x86_64__) + if (hpet_init() != 0) { + panic("Could not init HPET\n"); + } +#endif +} + /* * Writes out OEMID of ACPI header. * @@ -107,4 +117,5 @@ acpi_init(void) } root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; + acpi_init_hpet(); } diff --git a/sys/include/arch/amd64/hpet.h b/sys/include/arch/amd64/hpet.h new file mode 100644 index 0000000..0ebc96b --- /dev/null +++ b/sys/include/arch/amd64/hpet.h @@ -0,0 +1,37 @@ +/* + * 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 _MACHINE_HPET_H_ +#define _MACHINE_HPET_H_ + +#include + +int hpet_init(void); + +#endif /* !_MACHINE_HPET_H_ */ -- cgit v1.2.3 From efb3cd0e2ad09f409d66534d44ff07a55e9f1171 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 22:17:28 -0400 Subject: kernel/amd64: acpi: Support parsing MADT Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/acpi_machdep.c | 74 +++++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_init.c | 1 + sys/include/dev/acpi/acpivar.h | 2 + sys/include/dev/acpi/tables.h | 5 +++ 4 files changed, 82 insertions(+) create mode 100644 sys/arch/amd64/amd64/acpi_machdep.c (limited to 'sys/dev/acpi') diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c new file mode 100644 index 0000000..5f3b3bf --- /dev/null +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -0,0 +1,74 @@ +/* + * 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 + +#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) + +int +acpi_init_madt(void) +{ + struct acpi_madt *madt = acpi_query("APIC"); + struct apic_header *apichdr; + struct ioapic *ioapic = NULL; + uint8_t *cur, *end; + + if (madt == NULL) { + panic("Could not find MADT!\n"); + } + + cur = (uint8_t *)(madt + 1); + end = (uint8_t *)madt + madt->hdr.length; + + while (cur < end) { + apichdr = (void *)cur; + if (apichdr->type == APIC_TYPE_IO_APIC) { + /* + * TODO: Figure out how to use multiple I/O APICs + */ + if (ioapic != NULL) { + pr_trace("Skipping I/O APIC with ID %d\n", ioapic->ioapic_id); + break; + } + + ioapic = (struct ioapic *)cur; + pr_trace("Detected I/O APIC (id=%d, gsi_base=%d)\n", + ioapic->ioapic_id, ioapic->gsi_base); + } + + cur += apichdr->length; + } + + return 0; + +} diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c index f445d95..4c0ae1b 100644 --- a/sys/dev/acpi/acpi_init.c +++ b/sys/dev/acpi/acpi_init.c @@ -118,4 +118,5 @@ acpi_init(void) root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; acpi_init_hpet(); + acpi_init_madt(); } diff --git a/sys/include/dev/acpi/acpivar.h b/sys/include/dev/acpi/acpivar.h index 9a37dfb..9cfe945 100644 --- a/sys/include/dev/acpi/acpivar.h +++ b/sys/include/dev/acpi/acpivar.h @@ -35,6 +35,8 @@ uint8_t acpi_checksum(struct acpi_header *hdr); struct acpi_root_sdt *acpi_get_root_sdt(void); + size_t acpi_get_root_sdt_len(void); +int acpi_init_madt(void); #endif /* !_ACPI_ACPIVAR_H_ */ diff --git a/sys/include/dev/acpi/tables.h b/sys/include/dev/acpi/tables.h index d5bfd52..1dca890 100644 --- a/sys/include/dev/acpi/tables.h +++ b/sys/include/dev/acpi/tables.h @@ -33,6 +33,11 @@ #include #include +/* MADT APIC header types */ +#define APIC_TYPE_LOCAL_APIC 0 +#define APIC_TYPE_IO_APIC 1 +#define APIC_TYPE_INTERRUPT_OVERRIDE 2 + #define OEMID_SIZE 6 struct __packed acpi_header { -- cgit v1.2.3