summaryrefslogtreecommitdiff
path: root/kernel/src/drivers/acpi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/drivers/acpi.cpp')
-rw-r--r--kernel/src/drivers/acpi.cpp569
1 files changed, 14 insertions, 555 deletions
diff --git a/kernel/src/drivers/acpi.cpp b/kernel/src/drivers/acpi.cpp
index 61a4366..e0ab5ee 100644
--- a/kernel/src/drivers/acpi.cpp
+++ b/kernel/src/drivers/acpi.cpp
@@ -1,570 +1,29 @@
-
#include <cstdint>
#include <drivers/acpi.hpp>
-
-#include <etc/bootloaderinfo.hpp>
+#include <uacpi/uacpi.h>
+#include <uacpi/acpi.h>
#include <uacpi/types.h>
#include <uacpi/platform/arch_helpers.h>
-#include <generic/mm/paging.hpp>
-#include <generic/mm/heap.hpp>
-#include <generic/mm/pmm.hpp>
#include <uacpi/kernel_api.h>
#include <uacpi/uacpi.h>
-
-#include <arch/x86_64/cpu/data.hpp>
-
-#include <drivers/io.hpp>
-
-#include <generic/locks/spinlock.hpp>
-
-#include <arch/x86_64/interrupts/irq.hpp>
-
-#include <drivers/ioapic.hpp>
-
-#include <drivers/pci.hpp>
-#include <drivers/io.hpp>
-
-#include <drivers/tsc.hpp>
-#include <drivers/hpet.hpp>
-
-#include <arch/x86_64/cpu/lapic.hpp>
-
-#include <etc/logging.hpp>
-
-#include <etc/etc.hpp>
-
#include <uacpi/utilities.h>
#include <uacpi/event.h>
+#include <uacpi/uacpi.h>
+#include <uacpi/event.h>
-#include <generic/time.hpp>
-
-extern std::uint64_t __hpet_counter();
-
-extern int how_much_cpus;
-
-void drivers::acpi::init() {
+void acpi::init_tables() {
+#if defined(__x86_64__)
uacpi_status ret = uacpi_initialize(0);
-
- drivers::hpet::init();
- Log::Display(LEVEL_MESSAGE_OK,"HPET initializied\n");
-
- drivers::tsc::init();
- Log::Display(LEVEL_MESSAGE_OK,"TSC initializied\n");
-
- drivers::ioapic::init();
- Log::Display(LEVEL_MESSAGE_OK,"IOAPIC initializied\n");
-
- arch::x86_64::cpu::data()->lapic_block = arch::x86_64::cpu::lapic::init(15000);
-
- ret = uacpi_namespace_load();
-
- ret = uacpi_set_interrupt_model(UACPI_INTERRUPT_MODEL_IOAPIC);
-
- ret = uacpi_namespace_initialize();
- ret = uacpi_finalize_gpe_initialization();
-
-}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns the PHYSICAL address of the RSDP structure via *out_rsdp_address.
-uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address) {
- *out_rsdp_address = BootloaderInfo::AccessRSDP();
- return UACPI_STATUS_OK;
-}
-
-/*
- * Map a physical memory range starting at 'addr' with length 'len', and return
- * a virtual address that can be used to access it.
- *
- * NOTE: 'addr' may be misaligned, in this case the host is expected to round it
- * down to the nearest page-aligned boundary and map that, while making
- * sure that at least 'len' bytes are still mapped starting at 'addr'. The
- * return value preserves the misaligned offset.
- *
- * Example for uacpi_kernel_map(0x1ABC, 0xF00):
- * 1. Round down the 'addr' we got to the nearest page boundary.
- * Considering a PAGE_SIZE of 4096 (or 0x1000), 0x1ABC rounded down
- * is 0x1000, offset within the page is 0x1ABC - 0x1000 => 0xABC
- * 2. Requested 'len' is 0xF00 bytes, but we just rounded the address
- * down by 0xABC bytes, so add those on top. 0xF00 + 0xABC => 0x19BC
- * 3. Round up the final 'len' to the nearest PAGE_SIZE boundary, in
- * this case 0x19BC is 0x2000 bytes (2 pages if PAGE_SIZE is 4096)
- * 4. Call the VMM to map the aligned address 0x1000 (from step 1)
- * with length 0x2000 (from step 3). Let's assume the returned
- * virtual address for the mapping is 0xF000.
- * 5. Add the original offset within page 0xABC (from step 1) to the
- * resulting virtual address 0xF000 + 0xABC => 0xFABC. Return it
- * to uACPI.
- */
-void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len) {
- extern std::uint64_t kernel_cr3;
- memory::paging::maprange(kernel_cr3,addr,(std::uint64_t)Other::toVirt(addr),len,PTE_PRESENT | PTE_RW);
- return Other::toVirt(addr);
-}
-
-/*
- * Unmap a virtual memory range at 'addr' with a length of 'len' bytes.
- *
- * NOTE: 'addr' may be misaligned, see the comment above 'uacpi_kernel_map'.
- * Similar steps to uacpi_kernel_map can be taken to retrieve the
- * virtual address originally returned by the VMM for this mapping
- * as well as its true length.
- */
-void uacpi_kernel_unmap(void *addr, uacpi_size len) {
- asm volatile("nop");
-}
-
-#ifndef UACPI_FORMATTED_LOGGING
-void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char* msg) {
- Log::Display(LEVEL_MESSAGE_INFO,"UACPI: %s",msg);
-}
-#else
-UACPI_PRINTF_DECL(2, 3)
-void uacpi_kernel_log(uacpi_log_level, const uacpi_char*, ...);
-void uacpi_kernel_vlog(uacpi_log_level, const uacpi_char*, uacpi_va_list);
+ (void)ret;
#endif
-
-/*
- * Only the above ^^^ API may be used by early table access and
- * UACPI_BAREBONES_MODE.
- */
-#ifndef UACPI_BAREBONES_MODE
-
-/*
- * Convenience initialization/deinitialization hooks that will be called by
- * uACPI automatically when appropriate if compiled-in.
- */
-#ifdef UACPI_KERNEL_INITIALIZATION
-/*
- * This API is invoked for each initialization level so that appropriate parts
- * of the host kernel and/or glue code can be initialized at different stages.
- *
- * uACPI API that triggers calls to uacpi_kernel_initialize and the respective
- * 'current_init_lvl' passed to the hook at that stage:
- * 1. uacpi_initialize() -> UACPI_INIT_LEVEL_EARLY
- * 2. uacpi_namespace_load() -> UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED
- * 3. (start of) uacpi_namespace_initialize() -> UACPI_INIT_LEVEL_NAMESPACE_LOADED
- * 4. (end of) uacpi_namespace_initialize() -> UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED
- */
-uacpi_status uacpi_kernel_initialize(uacpi_init_level current_init_lvl);
-void uacpi_kernel_deinitialize(void);
-#endif
-
-/*
- * Open a PCI device at 'address' for reading & writing.
- *
- * Note that this must be able to open any arbitrary PCI device, not just those
- * detected during kernel PCI enumeration, since the following pattern is
- * relatively common in AML firmware:
- * Device (THC0)
- * {
- * // Device at 00:10.06
- * Name (_ADR, 0x00100006) // _ADR: Address
- *
- * OperationRegion (THCR, PCI_Config, Zero, 0x0100)
- * Field (THCR, ByteAcc, NoLock, Preserve)
- * {
- * // Vendor ID field in the PCI configuration space
- * VDID, 32
- * }
- *
- * // Check if the device at 00:10.06 actually exists, that is reading
- * // from its configuration space returns something other than 0xFFs.
- * If ((VDID != 0xFFFFFFFF))
- * {
- * // Actually create the rest of the device's body if it's present
- * // in the system, otherwise skip it.
- * }
- * }
- *
- * The handle returned via 'out_handle' is used to perform IO on the
- * configuration space of the device.
- */
-uacpi_status uacpi_kernel_pci_device_open(
- uacpi_pci_address address, uacpi_handle *out_handle
-) {
- uacpi_pci_address* pci = new uacpi_pci_address;
- *pci = address;
- *out_handle = (uacpi_handle)pci;
- return UACPI_STATUS_OK;
-}
-
-void uacpi_kernel_pci_device_close(uacpi_handle hnd) {
- delete (void*)hnd;
-}
-
-/*
- * Read & write the configuration space of a previously open PCI device.
- */
-uacpi_status uacpi_kernel_pci_read8(
- uacpi_handle device, uacpi_size offset, uacpi_u8 *value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- *value = drivers::pci::in(pci->bus,pci->device,pci->function,offset,1);
- return UACPI_STATUS_OK;
}
-uacpi_status uacpi_kernel_pci_read16(
- uacpi_handle device, uacpi_size offset, uacpi_u16 *value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- *value = drivers::pci::in(pci->bus,pci->device,pci->function,offset,2);
- return UACPI_STATUS_OK;
-}
-
-uacpi_status uacpi_kernel_pci_read32(
- uacpi_handle device, uacpi_size offset, uacpi_u32 *value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- *value = drivers::pci::in(pci->bus,pci->device,pci->function,offset,4);
- return UACPI_STATUS_OK;
-}
-
-uacpi_status uacpi_kernel_pci_write8(
- uacpi_handle device, uacpi_size offset, uacpi_u8 value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- drivers::pci::out(pci->bus,pci->device,pci->function,offset,value,1);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_pci_write16(
- uacpi_handle device, uacpi_size offset, uacpi_u16 value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- drivers::pci::out(pci->bus,pci->device,pci->function,offset,value,2);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_pci_write32(
- uacpi_handle device, uacpi_size offset, uacpi_u32 value
-) {
- uacpi_pci_address* pci = (uacpi_pci_address*)device;
- drivers::pci::out(pci->bus,pci->device,pci->function,offset,value,4);
- return UACPI_STATUS_OK;
-}
-
-/*
- * Map a SystemIO address at [base, base + len) and return a kernel-implemented
- * handle that can be used for reading and writing the IO range.
- *
- * NOTE: The x86 architecture uses the in/out family of instructions
- * to access the SystemIO address space.
- */
-typedef struct {
- uint64_t base;
- uint64_t len;
-} __attribute__((packed)) uacpi_io_struct_t;
-
-uacpi_status uacpi_kernel_io_map(
- uacpi_io_addr base, uacpi_size len, uacpi_handle *out_handle
-) {
- uacpi_io_struct_t* iomap = new uacpi_io_struct_t;
- iomap->base = base;
- iomap->len = len;
- *out_handle = (uacpi_handle*)iomap;
- return UACPI_STATUS_OK;
-}
-void uacpi_kernel_io_unmap(uacpi_handle handle) {
- delete (void*)handle;
-}
-
-/*
- * Read/Write the IO range mapped via uacpi_kernel_io_map
- * at a 0-based 'offset' within the range.
- *
- * NOTE:
- * The x86 architecture uses the in/out family of instructions
- * to access the SystemIO address space.
- *
- * You are NOT allowed to break e.g. a 4-byte access into four 1-byte accesses.
- * Hardware ALWAYS expects accesses to be of the exact width.
- */
-uacpi_status uacpi_kernel_io_read8(
- uacpi_handle hnd, uacpi_size offset, uacpi_u8 *out_value
-) {
- drivers::io io;
- *out_value = io.inb(*(std::uint16_t*)hnd + offset);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_io_read16(
- uacpi_handle hnd, uacpi_size offset, uacpi_u16 *out_value
-) {
- drivers::io io;
- *out_value = io.inw(*(std::uint16_t*)hnd + offset);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_io_read32(
- uacpi_handle hnd, uacpi_size offset, uacpi_u32 *out_value
-) {
- drivers::io io;
- *out_value = io.ind(*(std::uint16_t*)hnd + offset);
- return UACPI_STATUS_OK;
-}
-
-uacpi_status uacpi_kernel_io_write8(
- uacpi_handle hnd, uacpi_size offset, uacpi_u8 in_value
-) {
- drivers::io io;
- io.outb(*(std::uint16_t*)hnd + offset,in_value);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_io_write16(
- uacpi_handle hnd, uacpi_size offset, uacpi_u16 in_value
-) {
- drivers::io io;
- io.outw(*(std::uint16_t*)hnd + offset,in_value);
- return UACPI_STATUS_OK;
-}
-uacpi_status uacpi_kernel_io_write32(
- uacpi_handle hnd, uacpi_size offset, uacpi_u32 in_value
-) {
- drivers::io io;
- io.outd(*(std::uint16_t*)hnd + offset,in_value);
- return UACPI_STATUS_OK;
-}
-
-/*
- * Allocate a block of memory of 'size' bytes.
- * The contents of the allocated memory are unspecified.
- */
-void *uacpi_kernel_alloc(uacpi_size size) {
- return memory::heap::malloc(size);
-}
-
-#ifdef UACPI_NATIVE_ALLOC_ZEROED
-/*
- * Allocate a block of memory of 'size' bytes.
- * The returned memory block is expected to be zero-filled.
- */
-void *uacpi_kernel_alloc_zeroed(uacpi_size size);
-#endif
-
-/*
- * Free a previously allocated memory block.
- *
- * 'mem' might be a NULL pointer. In this case, the call is assumed to be a
- * no-op.
- *
- * An optionally enabled 'size_hint' parameter contains the size of the original
- * allocation. Note that in some scenarios this incurs additional cost to
- * calculate the object size.
- */
-#ifndef UACPI_SIZED_FREES
-void uacpi_kernel_free(void *mem) {
- memory::heap::free(mem);
-}
-#else
-void uacpi_kernel_free(void *mem, uacpi_size size_hint);
-#endif
-
-/*
- * Returns the number of nanosecond ticks elapsed since boot,
- * strictly monotonic.
- */
-uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void) {
- return drivers::tsc::currentnano();
-}
-
-/*
- * Spin for N microseconds.
- */
-void uacpi_kernel_stall(uacpi_u8 usec) {
- drivers::tsc::sleep(usec);
-}
-
-/*
- * Sleep for N milliseconds.
- */
-void uacpi_kernel_sleep(uacpi_u64 msec) {
- drivers::tsc::sleep(msec * 1000);
-}
-
-/*
- * Create/free an opaque non-recursive kernel mutex object.
- */
-uacpi_handle uacpi_kernel_create_mutex(void) {
- locks::spinlock* lock = new locks::spinlock;
- return (uacpi_handle)lock;
-}
-
-void uacpi_kernel_free_mutex(uacpi_handle hnd) {
- delete (void*)hnd;
-}
-
-/*
- * Create/free an opaque kernel (semaphore-like) event object.
- */
-uacpi_handle uacpi_kernel_create_event(void) {
- return (uacpi_handle)1;
-}
-
-void uacpi_kernel_free_event(uacpi_handle) {
- asm volatile("nop");
-}
-
-/*
- * Returns a unique identifier of the currently executing thread.
- *
- * The returned thread id cannot be UACPI_THREAD_ID_NONE.
- */
-uacpi_thread_id uacpi_kernel_get_thread_id(void) {
- return 0;
-}
-
-/*
- * Try to acquire the mutex with a millisecond timeout.
- *
- * The timeout value has the following meanings:
- * 0x0000 - Attempt to acquire the mutex once, in a non-blocking manner
- * 0x0001...0xFFFE - Attempt to acquire the mutex for at least 'timeout'
- * milliseconds
- * 0xFFFF - Infinite wait, block until the mutex is acquired
- *
- * The following are possible return values:
- * 1. UACPI_STATUS_OK - successful acquire operation
- * 2. UACPI_STATUS_TIMEOUT - timeout reached while attempting to acquire (or the
- * single attempt to acquire was not successful for
- * calls with timeout=0)
- * 3. Any other value - signifies a host internal error and is treated as such
- */
-uacpi_status uacpi_kernel_acquire_mutex(uacpi_handle lock, uacpi_u16) {
- locks::spinlock* slock = (locks::spinlock*)lock;
- slock->lock();
- return UACPI_STATUS_OK;
-}
-
-void uacpi_kernel_release_mutex(uacpi_handle lock) {
- locks::spinlock* slock = (locks::spinlock*)lock;
- slock->unlock();
-}
-
-/*
- * Try to wait for an event (counter > 0) with a millisecond timeout.
- * A timeout value of 0xFFFF implies infinite wait.
- *
- * The internal counter is decremented by 1 if wait was successful.
- *
- * A successful wait is indicated by returning UACPI_TRUE.
- */
-uacpi_bool uacpi_kernel_wait_for_event(uacpi_handle, uacpi_u16) {
- return 1;
-}
-
-/*
- * Signal the event object by incrementing its internal counter by 1.
- *
- * This function may be used in interrupt contexts.
- */
-void uacpi_kernel_signal_event(uacpi_handle) {
- asm volatile("nop");
-}
-
-/*
- * Reset the event counter to 0.
- */
-void uacpi_kernel_reset_event(uacpi_handle) {
- asm volatile("nop");
-}
-
-/*
- * Handle a firmware request.
- *
- * Currently either a Breakpoint or Fatal operators.
- */
-uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request*) {
- return UACPI_STATUS_OK;
-}
-
-/*
- * Install an interrupt handler at 'irq', 'ctx' is passed to the provided
- * handler for every invocation.
- *
- * 'out_irq_handle' is set to a kernel-implemented value that can be used to
- * refer to this handler from other API.
- */
-
-uacpi_status uacpi_kernel_install_interrupt_handler(
- uacpi_u32 irq, uacpi_interrupt_handler base, uacpi_handle ctx,
- uacpi_handle *out_irq_handle
-) {
- std::uint8_t vec = arch::x86_64::interrupts::irq::create(irq,IRQ_TYPE_LEGACY,(void (*)(void*))base,0,0);
- *out_irq_handle = (uacpi_handle)vec;
- return UACPI_STATUS_OK;
-}
-
-/*
- * Uninstall an interrupt handler. 'irq_handle' is the value returned via
- * 'out_irq_handle' during installation.
- */
-uacpi_status uacpi_kernel_uninstall_interrupt_handler(
- uacpi_interrupt_handler, uacpi_handle irq_handle
-) {
- asm volatile("nop");
- return UACPI_STATUS_OK;
-}
-
-/*
- * Create/free a kernel spinlock object.
- *
- * Unlike other types of locks, spinlocks may be used in interrupt contexts.
- */
-uacpi_handle uacpi_kernel_create_spinlock(void) {
- locks::spinlock* lock = new locks::spinlock;
- return (uacpi_handle)lock;
-}
-
-void uacpi_kernel_free_spinlock(uacpi_handle hnd) {
- delete (void*)hnd;
-}
-
-/*
- * Lock/unlock helpers for spinlocks.
- *
- * These are expected to disable interrupts, returning the previous state of cpu
- * flags, that can be used to possibly re-enable interrupts if they were enabled
- * before.
- *
- * Note that lock is infalliable.
- */
-uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle hnd) {
- locks::spinlock* lock = (locks::spinlock*)hnd;
- lock->lock();
- return UACPI_STATUS_OK;
-}
-
-void uacpi_kernel_unlock_spinlock(uacpi_handle hnd, uacpi_cpu_flags) {
- locks::spinlock* lock = (locks::spinlock*)hnd;
- lock->unlock();
-}
-
-/*
- * Schedules deferred work for execution.
- * Might be invoked from an interrupt context.
- */
-uacpi_status uacpi_kernel_schedule_work(
- uacpi_work_type, uacpi_work_handler, uacpi_handle ctx
-) {
- asm volatile("nop");
- return UACPI_STATUS_OK;
-}
-
-/*
- * Waits for two types of work to finish:
- * 1. All in-flight interrupts installed via uacpi_kernel_install_interrupt_handler
- * 2. All work scheduled via uacpi_kernel_schedule_work
- *
- * Note that the waits must be done in this order specifically.
- */
-uacpi_status uacpi_kernel_wait_for_work_completion(void) {
- asm volatile("nop");
- return UACPI_STATUS_OK;
-}
-
-#endif // !UACPI_BAREBONES_MODE
-
-#ifdef __cplusplus
-}
+void acpi::full_init() {
+#if defined(__x86_64__)
+ uacpi_namespace_load();
+ uacpi_namespace_initialize();
+ uacpi_finalize_gpe_initialization();
+ uacpi_set_interrupt_model(UACPI_INTERRUPT_MODEL_IOAPIC);
#endif
+} \ No newline at end of file