#include <uacpi/types.h>
#include <uacpi/platform/arch_helpers.h>
#include "mm/memory.h"
#include "arch/x86_64/io.h"
#include "arch/x86_64/irq.h"
#include "arch/x86_64/pit.h"
#include "time/time.h"
#include <stdatomic.h>
#include <stdarg.h>
#include "mm/vmm.h"


extern uint64_t g_rsdp_phys;
extern volatile uint64_t tsc_cycles_per_us;

// Returns the PHYSICAL address of the RSDP structure via *out_rsdp_address.
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address)
{
    if (g_rsdp_phys == INVALID_PHYS)
        return UACPI_STATUS_NOT_FOUND;
    *out_rsdp_address = g_rsdp_phys;
    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)
{
    (void)len;
    return (void *)((uintptr_t)addr + MEM_PHYS_OFFSET);
}

/**
 * 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)
{
    (void)addr;
    (void)len;
    /* HHDM mappings are permanent — nothing to unmap */
}

static const char *uacpi_log_prefix(uacpi_log_level level)
{
    switch (level) {
    case UACPI_LOG_DEBUG: return "[uACPI DBG ] ";
    case UACPI_LOG_TRACE: return "[uACPI TRC ] ";
    case UACPI_LOG_INFO:  return "[uACPI INFO] ";
    case UACPI_LOG_WARN:  return "[uACPI WARN] ";
    case UACPI_LOG_ERROR: return "[uACPI ERR ] ";
    default:              return "[uACPI     ] ";
    }
}

#ifndef UACPI_FORMATTED_LOGGING
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *msg)
{
    printf("%s%s", uacpi_log_prefix(level), msg);
}
#else
UACPI_PRINTF_DECL(2, 3)
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *fmt, ...)
{
    va_list va;
    va_start(va, fmt);
    uacpi_kernel_vlog(level, fmt, va);
    va_end(va);
}
 
void uacpi_kernel_vlog(uacpi_log_level level, const uacpi_char *fmt,
                       uacpi_va_list va)
{
    printf("%s", uacpi_log_prefix(level));
    vfprintf(fmt, va);
}
#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.
 *
 * The device at 'address' might not actually exist on the system, in this case
 * the api is allowed to return UACPI_STATUS_NOT_FOUND to indicate that, this
 * error is handled gracefully by creating a dummy device internally that always
 * returns 0xFF on reads and is no-op for writes. This is to support a common
 * pattern in AML that probes for 0xFF reads to detect whether a device exists.
 *
 * The handle returned via 'out_handle' is used to perform IO on the
 * configuration space of the device.
 */

#define PCI_CFG_ADDR_PORT 0x0CF8u
#define PCI_CFG_DATA_PORT 0x0CFCu
 
typedef struct { uint8_t bus, dev, func; } pci_dev_impl_t;
 
static uint32_t pci_make_addr(pci_dev_impl_t *d, uacpi_size offset)
{
    return (1u << 31)
         | ((uint32_t)d->bus  << 16)
         | ((uint32_t)d->dev  << 11)
         | ((uint32_t)d->func <<  8)
         | (uint32_t)(offset & 0xFCu);
}
 
static uint32_t pci_read32(pci_dev_impl_t *d, uacpi_size offset)
{
    x86_64_outl(PCI_CFG_ADDR_PORT, pci_make_addr(d, offset));
    return x86_64_inl(PCI_CFG_DATA_PORT);
}
 
static void pci_write32_masked(pci_dev_impl_t *d, uacpi_size offset,
                               uint32_t val, uint32_t mask)
{
    x86_64_outl(PCI_CFG_ADDR_PORT, pci_make_addr(d, offset));
    uint32_t old = x86_64_inl(PCI_CFG_DATA_PORT);
    x86_64_outl(PCI_CFG_DATA_PORT, (old & ~mask) | (val & mask));
}
 
uacpi_status uacpi_kernel_pci_device_open(uacpi_pci_address addr,
                                          uacpi_handle *out_handle)
{
    pci_dev_impl_t *d = kmalloc(sizeof(*d));
    if (!d) return UACPI_STATUS_OUT_OF_MEMORY;
    d->bus  = addr.bus;
    d->dev  = addr.device;
    d->func = addr.function;
    *out_handle = (uacpi_handle)d;
    return UACPI_STATUS_OK;
}
 
void uacpi_kernel_pci_device_close(uacpi_handle handle) { kfree(handle); }
 
uacpi_status uacpi_kernel_pci_read8(uacpi_handle h, uacpi_size off,
                                    uacpi_u8 *v)
{
    uint8_t shift = (off & 3u) * 8u;
    *v = (pci_read32(h, off) >> shift) & 0xFFu;
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_pci_read16(uacpi_handle h, uacpi_size off,
                                     uacpi_u16 *v)
{
    uint8_t shift = (off & 3u) * 8u;
    *v = (pci_read32(h, off) >> shift) & 0xFFFFu;
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_pci_read32(uacpi_handle h, uacpi_size off,
                                     uacpi_u32 *v)
{
    *v = pci_read32(h, off);
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_pci_write8(uacpi_handle h, uacpi_size off,
                                     uacpi_u8 v)
{
    uint8_t shift = (off & 3u) * 8u;
    pci_write32_masked(h, off, (uint32_t)v << shift, 0xFFu << shift);
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_pci_write16(uacpi_handle h, uacpi_size off,
                                      uacpi_u16 v)
{
    uint8_t shift = (off & 3u) * 8u;
    pci_write32_masked(h, off, (uint32_t)v << shift, 0xFFFFu << shift);
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_pci_write32(uacpi_handle h, uacpi_size off,
                                      uacpi_u32 v)
{
    x86_64_outl(PCI_CFG_ADDR_PORT, pci_make_addr(h, off));
    x86_64_outl(PCI_CFG_DATA_PORT, v);
    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.
 */
uacpi_status uacpi_kernel_io_map(uacpi_io_addr base, uacpi_size len,
                                 uacpi_handle *out_handle)
{
    (void)len;
    *out_handle = (uacpi_handle)(uintptr_t)base;
    return UACPI_STATUS_OK;
}

void uacpi_kernel_io_unmap(uacpi_handle handle) { (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.
 */

static inline uint16_t io_port_of(uacpi_handle h, uacpi_size offset)
{
    return (uint16_t)((uintptr_t)h + offset);
}
 

uacpi_status uacpi_kernel_io_read8(uacpi_handle h, uacpi_size off,
                                   uacpi_u8 *v)
{
    *v = x86_64_inb(io_port_of(h, off));
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_io_read16(uacpi_handle h, uacpi_size off,
                                    uacpi_u16 *v)
{
    *v = x86_64_inw(io_port_of(h, off));
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_io_read32(uacpi_handle h, uacpi_size off,
                                    uacpi_u32 *v)
{
    *v = x86_64_inl(io_port_of(h, off));
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_io_write8(uacpi_handle h, uacpi_size off,
                                    uacpi_u8 v)
{
    x86_64_outb(io_port_of(h, off), v);
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_io_write16(uacpi_handle h, uacpi_size off,
                                     uacpi_u16 v)
{
    x86_64_outw(io_port_of(h, off), v);
    return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_io_write32(uacpi_handle h, uacpi_size off,
                                     uacpi_u32 v)
{
    x86_64_outl(io_port_of(h, off), v);
    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 kmalloc(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)
{
    void *p = kmalloc(size);
    if (p) memset(p, 0, size);
    return p;
}
#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)
{
    kfree(mem);
}
#else
void uacpi_kernel_free(void *mem, uacpi_size size_hint)
{
    (void)size_hint;
    kfree(mem);
}
#endif

/**
 * Returns the number of nanosecond ticks elapsed since boot,
 * strictly monotonic.
 */
uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void)
{
    return rdtsc() / (tsc_cycles_per_us / 1000);  // rough ns
}

/**
 * Spin for N microseconds.
 */
void uacpi_kernel_stall(uacpi_u8 usec)
{
    uint64_t start = rdtsc();
    uint64_t target = start + ((uint64_t)usec * tsc_cycles_per_us);

    while (rdtsc() < target)
        __asm__ volatile("pause");
}

/**
 * Sleep for N milliseconds.
 */
void uacpi_kernel_sleep(uacpi_u64 msec)
{
    uint64_t start = g_Ticks;
    uint64_t target = start + msec;

    while (g_Ticks < target)
    {
        __asm__ volatile("hlt");
    }
}

typedef struct { atomic_flag flag; } uacpi_mutex_impl_t;
/**
 * Create/free an opaque non-recursive kernel mutex object.
 */
uacpi_handle uacpi_kernel_create_mutex(void)
{
    uacpi_mutex_impl_t *m = kmalloc(sizeof(*m));
    if (!m) return UACPI_NULL;
    atomic_flag_clear(&m->flag);
    return (uacpi_handle)m;
}

void uacpi_kernel_free_mutex(uacpi_handle handle)
{
    kfree(handle);
}

/**
 * Create/free an opaque kernel (semaphore-like) event object.
 */
typedef struct { atomic_uint counter; } uacpi_event_impl_t;
 
uacpi_handle uacpi_kernel_create_event(void)
{
    uacpi_event_impl_t *e = kmalloc(sizeof(*e));
    if (!e) return UACPI_NULL;
    atomic_store_explicit(&e->counter, 0u, memory_order_relaxed);
    return (uacpi_handle)e;
}
 
void uacpi_kernel_free_event(uacpi_handle handle)
{
    kfree(handle);
}



/**
 * Disable interrupts and return an kernel-defined value representing the
 * "before" state. This value is used in the subsequent call to restore the
 * prior state.
 *
 * Note that this is talking about ALL interrupts on the current CPU, not just
 * those installed by uACPI. This is typically achieved by executing the 'cli'
 * instruction on x86, 'msr daifset, #3' on aarch64 etc.
 */
uacpi_interrupt_state uacpi_kernel_disable_interrupts(void)
{
    uint64_t flags;
    asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
    return (uacpi_interrupt_state)flags;
}

void uacpi_kernel_restore_interrupts(uacpi_interrupt_state state)
{
    asm volatile("push %0; popfq" :: "r"((uint64_t)state) : "memory", "cc");
}
 

/**
 * Restore the state of the interrupt flags to the kernel-defined value provided
 * in 'state'.
 */
uacpi_thread_id uacpi_kernel_get_thread_id(void)
{
    /* Always "thread 1" — update when you add SMP */
    return (uacpi_thread_id)1;
}

/**
 * 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 handle, uacpi_u16 timeout)
{
    uacpi_mutex_impl_t *m = handle;
 
    if (timeout == 0) {
        if (atomic_flag_test_and_set_explicit(&m->flag, memory_order_acquire))
            return UACPI_STATUS_TIMEOUT;
        return UACPI_STATUS_OK;
    }
 
    while (atomic_flag_test_and_set_explicit(&m->flag, memory_order_acquire))
        asm volatile("pause" ::: "memory");
    return UACPI_STATUS_OK;
}

void uacpi_kernel_release_mutex(uacpi_handle handle)
{
    uacpi_mutex_impl_t *m = handle;
    atomic_flag_clear_explicit(&m->flag, memory_order_release);
}



/**
 * 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 handle, uacpi_u16 timeout)
{
    uacpi_event_impl_t *e = handle;
 
    if (timeout == 0xFFFF) {
        while (atomic_load_explicit(&e->counter, memory_order_acquire) == 0)
            asm volatile("pause" ::: "memory");
    } else {
        if (atomic_load_explicit(&e->counter, memory_order_acquire) == 0)
            return UACPI_FALSE;
    }
 
    atomic_fetch_sub_explicit(&e->counter, 1u, memory_order_acq_rel);
    return UACPI_TRUE;
}
 

/**
 * 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 handle)
{
    uacpi_event_impl_t *e = handle;
    atomic_fetch_add_explicit(&e->counter, 1u, memory_order_release);
}

/**
 * Reset the event counter to 0.
 */
void uacpi_kernel_reset_event(uacpi_handle handle)
{
    uacpi_event_impl_t *e = handle;
    atomic_store_explicit(&e->counter, 0u, memory_order_release);
}

/**
 * Handle a firmware request.
 *
 * Currently either a Breakpoint or Fatal operators.
 */
uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request *req)
{
    switch (req->type) {
    case UACPI_FIRMWARE_REQUEST_TYPE_BREAKPOINT:
        printf("[uACPI] AML Breakpoint\n");
        return UACPI_STATUS_OK;
    case UACPI_FIRMWARE_REQUEST_TYPE_FATAL:
        printf("[uACPI] AML Fatal! type=0x%x code=0x%x arg=0x%lx\n",
               req->fatal.type, req->fatal.code,
               (unsigned long)req->fatal.arg);
        for (;;) asm volatile("hlt");
    default:
        return UACPI_STATUS_UNIMPLEMENTED;
    }
}

/**
 * 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.
 */

#define UACPI_MAX_IRQS 16
 
typedef struct {
    uacpi_interrupt_handler fn;
    uacpi_handle            ctx;
} uacpi_irq_entry_t;



static uacpi_irq_entry_t uacpi_irq_table[UACPI_MAX_IRQS];

static void uacpi_irq_shim(Registers *regs)
{
    int irq = (int)regs->interrupt - 0x20; /* PIC_REMAP_OFFSET */
    if ((unsigned)irq < UACPI_MAX_IRQS && uacpi_irq_table[irq].fn)
        uacpi_irq_table[irq].fn(uacpi_irq_table[irq].ctx);
}

uacpi_status uacpi_kernel_install_interrupt_handler(
    uacpi_u32 irq, uacpi_interrupt_handler handler,
    uacpi_handle ctx, uacpi_handle *out_irq_handle)
{
    if (irq >= UACPI_MAX_IRQS)
        return UACPI_STATUS_INVALID_ARGUMENT;
 
    uacpi_irq_table[irq].fn  = handler;
    uacpi_irq_table[irq].ctx = ctx;
    x86_64_IRQ_RegisterHandler((int)irq, uacpi_irq_shim);
 
    /* Return a non-NULL token the caller can pass to uninstall */
    *out_irq_handle = (uacpi_handle)(uintptr_t)(irq + 1);
    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 handler, uacpi_handle irq_handle)
{
    (void)handler;
    uacpi_u32 irq = (uacpi_u32)(uintptr_t)irq_handle - 1;
    if (irq >= UACPI_MAX_IRQS)
        return UACPI_STATUS_INVALID_ARGUMENT;
 
    uacpi_irq_table[irq].fn  = NULL;
    uacpi_irq_table[irq].ctx = NULL;
    x86_64_IRQ_RegisterHandler((int)irq, NULL);
    return UACPI_STATUS_OK;
}

typedef struct { atomic_flag flag; } uacpi_spinlock_impl_t;

/**
 * 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)
{
    uacpi_spinlock_impl_t *sl = kmalloc(sizeof(*sl));
    if (!sl) return UACPI_NULL;
    atomic_flag_clear(&sl->flag);
    return (uacpi_handle)sl;
}

void uacpi_kernel_free_spinlock(uacpi_handle handle)
{
    kfree(handle);
}

/**
 * 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 handle)
{
    uint64_t flags;
    asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
    uacpi_spinlock_impl_t *sl = handle;
    while (atomic_flag_test_and_set_explicit(&sl->flag, memory_order_acquire))
        asm volatile("pause" ::: "memory");
    return (uacpi_cpu_flags)flags;
}

void uacpi_kernel_unlock_spinlock(uacpi_handle handle, uacpi_cpu_flags saved)
{
    uacpi_spinlock_impl_t *sl = handle;
    atomic_flag_clear_explicit(&sl->flag, memory_order_release);
    asm volatile("push %0; popfq" :: "r"((uint64_t)saved) : "memory", "cc");
}

typedef enum uacpi_work_type {
    /**
     * Schedule a GPE handler method for execution.
     * This should be scheduled to run on CPU0 to avoid potential SMI-related
     * firmware bugs.
     */
    UACPI_WORK_GPE_EXECUTION,

    /**
     * Schedule a Notify(device) firmware request for execution.
     * This can run on any CPU.
     */
    UACPI_WORK_NOTIFICATION,
} uacpi_work_type;

typedef void (*uacpi_work_handler)(uacpi_handle);

/**
 * Schedules deferred work for execution.
 * Might be invoked from an interrupt context.
 */
uacpi_status uacpi_kernel_schedule_work(uacpi_work_type type,
                                        uacpi_work_handler handler,
                                        uacpi_handle ctx)
{
    (void)type;
    handler(ctx);
    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)
{
    return UACPI_STATUS_OK; /* all work ran synchronously above */
}

#endif // !UACPI_BAREBONES_MODE