Integrate uACPI

This commit is contained in:
2025-08-17 18:37:57 +02:00
parent 069870cd0d
commit 92ccd189e7
166 changed files with 42104 additions and 33 deletions

View File

@ -0,0 +1,605 @@
#include "helpers.h"
#include "os.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uacpi/kernel_api.h>
#include <uacpi/status.h>
#include <uacpi/types.h>
uacpi_phys_addr g_rsdp;
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address)
{
*out_rsdp_address = g_rsdp;
return UACPI_STATUS_OK;
}
static uint8_t *io_space;
#ifdef UACPI_KERNEL_INITIALIZATION
uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl)
{
if (lvl == UACPI_INIT_LEVEL_EARLY)
io_space = do_malloc(UINT16_MAX + 1);
return UACPI_STATUS_OK;
}
void uacpi_kernel_deinitialize(void)
{
free(io_space);
io_space = NULL;
}
#endif
uacpi_status uacpi_kernel_io_map(
uacpi_io_addr base, uacpi_size len, uacpi_handle *out_handle
)
{
UACPI_UNUSED(len);
*out_handle = (uacpi_handle)((uintptr_t)base);
return UACPI_STATUS_OK;
}
void uacpi_kernel_io_unmap(uacpi_handle handle)
{
UACPI_UNUSED(handle);
}
#define UACPI_IO_READ(bits) \
uacpi_status uacpi_kernel_io_read##bits( \
uacpi_handle handle, uacpi_size offset, uacpi_u##bits *out_value \
) \
{ \
uacpi_io_addr addr = (uacpi_io_addr)((uintptr_t)handle) + offset; \
\
if (io_space && addr <= UINT16_MAX) \
memcpy(out_value, &io_space[addr], bits / 8); \
else \
*out_value = (uacpi_u##bits)0xFFFFFFFFFFFFFFFF; \
\
return UACPI_STATUS_OK; \
}
#define UACPI_IO_WRITE(bits) \
uacpi_status uacpi_kernel_io_write##bits( \
uacpi_handle handle, uacpi_size offset, uacpi_u##bits in_value \
) \
{ \
uacpi_io_addr addr = (uacpi_io_addr)((uintptr_t)handle) + offset; \
\
if (io_space && addr <= UINT16_MAX) \
memcpy(&io_space[addr], &in_value, bits / 8); \
\
return UACPI_STATUS_OK; \
}
#define UACPI_PCI_READ(bits) \
uacpi_status uacpi_kernel_pci_read##bits( \
uacpi_handle handle, uacpi_size offset, uacpi_u##bits *value \
) \
{ \
UACPI_UNUSED(handle); \
UACPI_UNUSED(offset); \
\
*value = (uacpi_u##bits)0xFFFFFFFFFFFFFFFF; \
return UACPI_STATUS_OK; \
}
#define UACPI_PCI_WRITE(bits) \
uacpi_status uacpi_kernel_pci_write##bits( \
uacpi_handle handle, uacpi_size offset, uacpi_u##bits value \
) \
{ \
UACPI_UNUSED(handle); \
UACPI_UNUSED(offset); \
UACPI_UNUSED(value); \
\
return UACPI_STATUS_OK; \
}
UACPI_IO_READ(8)
UACPI_IO_READ(16)
UACPI_IO_READ(32)
UACPI_IO_WRITE(8)
UACPI_IO_WRITE(16)
UACPI_IO_WRITE(32)
UACPI_PCI_READ(8)
UACPI_PCI_READ(16)
UACPI_PCI_READ(32)
UACPI_PCI_WRITE(8)
UACPI_PCI_WRITE(16)
UACPI_PCI_WRITE(32)
uacpi_status uacpi_kernel_pci_device_open(
uacpi_pci_address address, uacpi_handle *out_handle
)
{
UACPI_UNUSED(address);
*out_handle = NULL;
return UACPI_STATUS_OK;
}
void uacpi_kernel_pci_device_close(uacpi_handle handle)
{
UACPI_UNUSED(handle);
}
bool g_expect_virtual_addresses = true;
typedef struct {
hash_node_t node;
uint64_t phys;
size_t references;
} virt_location_t;
typedef struct {
hash_node_t node;
void *virt;
} mapping_t;
typedef struct {
hash_node_t node;
hash_table_t mappings;
} phys_location_t;
static hash_table_t virt_locations;
static hash_table_t phys_locations;
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len)
{
if (!g_expect_virtual_addresses) {
phys_location_t *phys_location = HASH_TABLE_FIND(
&phys_locations, addr, phys_location_t, node
);
void *virt;
virt_location_t *location;
mapping_t *mapping;
if (phys_location != NULL) {
mapping = HASH_TABLE_FIND(
&phys_location->mappings, len, mapping_t, node
);
if (mapping != NULL) {
location = HASH_TABLE_FIND(
&virt_locations, (uintptr_t)mapping->virt, virt_location_t,
node
);
location->references += 1;
return mapping->virt;
}
printf(
"WARN: remapping physical 0x%016" PRIX64 " with size %zu\n",
addr, len
);
}
virt = do_calloc(len, 1);
location = HASH_TABLE_GET_OR_ADD(
&virt_locations, (uintptr_t)virt, virt_location_t, node
);
location->phys = addr;
location->references = 1;
phys_location = HASH_TABLE_GET_OR_ADD(
&phys_locations, addr, phys_location_t, node
);
mapping = HASH_TABLE_GET_OR_ADD(
&phys_location->mappings, len, mapping_t, node
);
mapping->virt = virt;
return virt;
}
return (void*)((uintptr_t)addr);
}
void uacpi_kernel_unmap(void *addr, uacpi_size len)
{
virt_location_t *virt_location = HASH_TABLE_FIND(
&virt_locations, (uintptr_t)addr, virt_location_t, node
);
phys_location_t *phys_location;
mapping_t *mapping;
if (!virt_location)
return;
if (--virt_location->references > 0)
return;
phys_location = HASH_TABLE_FIND(
&phys_locations, virt_location->phys, phys_location_t, node
);
mapping = HASH_TABLE_FIND(&phys_location->mappings, len, mapping_t, node);
if (!mapping) {
printf(
"WARN: cannot identify mapping virt=%p phys=0x%016" PRIX64 " with "
"size %zu\n", addr, phys_location->node.key, len
);
return;
}
HASH_TABLE_REMOVE(&phys_location->mappings, mapping, mapping_t, node);
if (hash_table_empty(&phys_location->mappings)) {
hash_table_cleanup(&phys_location->mappings);
HASH_TABLE_REMOVE(
&phys_locations, phys_location, phys_location_t, node
);
}
free((void*)((uintptr_t)virt_location->node.key));
HASH_TABLE_REMOVE(&virt_locations, virt_location, virt_location_t, node);
}
void interface_cleanup(void)
{
size_t i;
for (i = 0; i < phys_locations.capacity; i++) {
phys_location_t *location = CONTAINER(
phys_location_t, node, phys_locations.entries[i]
);
while (location) {
hash_table_cleanup(&location->mappings);
location = CONTAINER(phys_location_t, node, location->node.next);
}
}
hash_table_cleanup(&phys_locations);
hash_table_cleanup(&virt_locations);
}
#ifdef UACPI_SIZED_FREES
typedef struct {
hash_node_t node;
size_t size;
} allocation_t;
static hash_table_t allocations;
void *uacpi_kernel_alloc(uacpi_size size)
{
void *ret;
allocation_t *allocation;
if (size == 0)
abort();
ret = malloc(size);
if (ret == NULL)
return ret;
allocation = HASH_TABLE_GET_OR_ADD(
&allocations, (uintptr_t)ret, allocation_t, node
);
allocation->size = size;
return ret;
}
void uacpi_kernel_free(void *mem, uacpi_size size_hint)
{
allocation_t *allocation;
if (mem == NULL)
return;
allocation = HASH_TABLE_FIND(
&allocations, (uintptr_t)mem, allocation_t, node
);
if (!allocation)
error("unable to find heap allocation %p\n", mem);
if (allocation->size != size_hint)
error(
"invalid free size: originally allocated %zu bytes, freeing as %zu",
allocation->size, size_hint
);
HASH_TABLE_REMOVE(&allocations, allocation, allocation_t, node);
free(mem);
}
#else
void *uacpi_kernel_alloc(uacpi_size size)
{
if (size == 0)
error("attempted to allocate zero bytes");
return malloc(size);
}
void uacpi_kernel_free(void *mem)
{
free(mem);
}
#endif
#ifdef UACPI_NATIVE_ALLOC_ZEROED
void *uacpi_kernel_alloc_zeroed(uacpi_size size)
{
void *ret = uacpi_kernel_alloc(size);
if (ret == NULL)
return ret;
memset(ret, 0, size);
return ret;
}
#endif
#ifdef UACPI_FORMATTED_LOGGING
void uacpi_kernel_vlog(
uacpi_log_level level, const uacpi_char *format, va_list args
)
{
printf("[uACPI][%s] ", uacpi_log_level_to_string(level));
vprintf(format, args);
}
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *format, ...)
{
va_list args;
va_start(args, format);
uacpi_kernel_vlog(level, format, args);
va_end(args);
}
#else
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *str)
{
printf("[uACPI][%s] %s", uacpi_log_level_to_string(level), str);
}
#endif
uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void)
{
return get_nanosecond_timer();
}
void uacpi_kernel_stall(uacpi_u8 usec)
{
uint64_t end = get_nanosecond_timer() + (uint64_t)usec * 1000;
for (;;)
if (get_nanosecond_timer() >= end)
break;
}
void uacpi_kernel_sleep(uacpi_u64 msec)
{
millisecond_sleep(msec);
}
uacpi_handle uacpi_kernel_create_mutex(void)
{
mutex_t *mutex = do_malloc(sizeof(*mutex));
mutex_init(mutex);
return mutex;
}
void uacpi_kernel_free_mutex(uacpi_handle handle)
{
mutex_free(handle);
free(handle);
}
uacpi_thread_id uacpi_kernel_get_thread_id(void)
{
return get_thread_id();
}
uacpi_status uacpi_kernel_acquire_mutex(uacpi_handle handle, uacpi_u16 timeout)
{
if (timeout == 0)
return mutex_try_lock(handle) ? UACPI_STATUS_OK : UACPI_STATUS_TIMEOUT;
if (timeout == 0xFFFF) {
mutex_lock(handle);
return UACPI_STATUS_OK;
}
if (mutex_lock_timeout(handle, timeout * 1000000ull))
return UACPI_STATUS_OK;
return UACPI_STATUS_TIMEOUT;
}
void uacpi_kernel_release_mutex(uacpi_handle handle)
{
mutex_unlock(handle);
}
typedef struct {
mutex_t mutex;
condvar_t condvar;
size_t counter;
} event_t;
uacpi_handle uacpi_kernel_create_event(void)
{
event_t *event = do_calloc(1, sizeof(*event));
mutex_init(&event->mutex);
condvar_init(&event->condvar);
return event;
}
void uacpi_kernel_free_event(uacpi_handle handle)
{
event_t *event = handle;
condvar_free(&event->condvar);
mutex_free(&event->mutex);
free(handle);
}
static bool event_pred(void *ptr)
{
event_t *event = ptr;
return event->counter != 0;
}
uacpi_bool uacpi_kernel_wait_for_event(uacpi_handle handle, uacpi_u16 timeout)
{
event_t *event = handle;
bool ok;
mutex_lock(&event->mutex);
if (event->counter > 0) {
event->counter -= 1;
mutex_unlock(&event->mutex);
return UACPI_TRUE;
}
if (timeout == 0) {
mutex_unlock(&event->mutex);
return UACPI_FALSE;
}
if (timeout == 0xFFFF) {
condvar_wait(&event->condvar, &event->mutex, event_pred, event);
event->counter -= 1;
mutex_unlock(&event->mutex);
return UACPI_TRUE;
}
ok = condvar_wait_timeout(
&event->condvar, &event->mutex, event_pred, event, timeout * 1000000ull
);
if (ok)
event->counter -= 1;
mutex_unlock(&event->mutex);
return ok ? UACPI_TRUE : UACPI_FALSE;
}
void uacpi_kernel_signal_event(uacpi_handle handle)
{
event_t *event = handle;
mutex_lock(&event->mutex);
event->counter += 1;
condvar_signal(&event->condvar);
mutex_unlock(&event->mutex);
}
void uacpi_kernel_reset_event(uacpi_handle handle)
{
event_t *event = handle;
mutex_lock(&event->mutex);
event->counter = 0;
mutex_unlock(&event->mutex);
}
uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request *req)
{
switch (req->type) {
case UACPI_FIRMWARE_REQUEST_TYPE_BREAKPOINT:
printf("Ignoring breakpoint\n");
break;
case UACPI_FIRMWARE_REQUEST_TYPE_FATAL:
printf(
"Fatal firmware error: type: %" PRIx8 " code: %" PRIx32 " arg: "
"%" PRIx64 "\n", req->fatal.type, req->fatal.code, req->fatal.arg
);
break;
default:
error("unknown firmware request type %d", req->type);
}
return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_install_interrupt_handler(
uacpi_u32 irq, uacpi_interrupt_handler handler, uacpi_handle ctx,
uacpi_handle *out_irq_handle
)
{
UACPI_UNUSED(irq);
UACPI_UNUSED(handler);
UACPI_UNUSED(ctx);
UACPI_UNUSED(out_irq_handle);
return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_uninstall_interrupt_handler(
uacpi_interrupt_handler handler, uacpi_handle irq_handle
)
{
UACPI_UNUSED(handler);
UACPI_UNUSED(irq_handle);
return UACPI_STATUS_OK;
}
uacpi_handle uacpi_kernel_create_spinlock(void)
{
return uacpi_kernel_create_mutex();
}
void uacpi_kernel_free_spinlock(uacpi_handle handle)
{
uacpi_kernel_free_mutex(handle);
}
uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle handle)
{
uacpi_kernel_acquire_mutex(handle, 0xFFFF);
return 0;
}
void uacpi_kernel_unlock_spinlock(uacpi_handle handle, uacpi_cpu_flags flags)
{
UACPI_UNUSED(flags);
uacpi_kernel_release_mutex(handle);
}
uacpi_status uacpi_kernel_schedule_work(
uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx
)
{
UACPI_UNUSED(type);
handler(ctx);
return UACPI_STATUS_OK;
}
uacpi_status uacpi_kernel_wait_for_work_completion(void)
{
return UACPI_STATUS_OK;
}