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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/log.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Set the minimum log level to be accepted by the logging facilities. Any logs
* below this level are discarded and not passed to uacpi_kernel_log, etc.
*
* 0 is treated as a special value that resets the setting to the default value.
*
* E.g. for a log level of UACPI_LOG_INFO:
* UACPI_LOG_DEBUG -> discarded
* UACPI_LOG_TRACE -> discarded
* UACPI_LOG_INFO -> allowed
* UACPI_LOG_WARN -> allowed
* UACPI_LOG_ERROR -> allowed
*/
void uacpi_context_set_log_level(uacpi_log_level);
/*
* Enables table checksum validation at installation time instead of first use.
* Note that this makes uACPI map the entire table at once, which not all
* hosts are able to handle at early init.
*/
void uacpi_context_set_proactive_table_checksum(uacpi_bool);
#ifndef UACPI_BAREBONES_MODE
/*
* Set the maximum number of seconds a While loop is allowed to run for before
* getting timed out.
*
* 0 is treated a special value that resets the setting to the default value.
*/
void uacpi_context_set_loop_timeout(uacpi_u32 seconds);
/*
* Set the maximum call stack depth AML can reach before getting aborted.
*
* 0 is treated as a special value that resets the setting to the default value.
*/
void uacpi_context_set_max_call_stack_depth(uacpi_u32 depth);
uacpi_u32 uacpi_context_get_loop_timeout(void);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,286 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/uacpi.h>
#include <uacpi/acpi.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
typedef enum uacpi_fixed_event {
UACPI_FIXED_EVENT_TIMER_STATUS = 1,
UACPI_FIXED_EVENT_POWER_BUTTON,
UACPI_FIXED_EVENT_SLEEP_BUTTON,
UACPI_FIXED_EVENT_RTC,
UACPI_FIXED_EVENT_MAX = UACPI_FIXED_EVENT_RTC,
} uacpi_fixed_event;
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_install_fixed_event_handler(
uacpi_fixed_event event, uacpi_interrupt_handler handler, uacpi_handle user
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_uninstall_fixed_event_handler(
uacpi_fixed_event event
))
/*
* Enable/disable a fixed event. Note that the event is automatically enabled
* upon installing a handler to it.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enable_fixed_event(uacpi_fixed_event event)
)
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_disable_fixed_event(uacpi_fixed_event event)
)
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_clear_fixed_event(uacpi_fixed_event event)
)
typedef enum uacpi_event_info {
// Event is enabled in software
UACPI_EVENT_INFO_ENABLED = (1 << 0),
// Event is enabled in software (only for wake)
UACPI_EVENT_INFO_ENABLED_FOR_WAKE = (1 << 1),
// Event is masked
UACPI_EVENT_INFO_MASKED = (1 << 2),
// Event has a handler attached
UACPI_EVENT_INFO_HAS_HANDLER = (1 << 3),
// Hardware enable bit is set
UACPI_EVENT_INFO_HW_ENABLED = (1 << 4),
// Hardware status bit is set
UACPI_EVENT_INFO_HW_STATUS = (1 << 5),
} uacpi_event_info;
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_fixed_event_info(
uacpi_fixed_event event, uacpi_event_info *out_info
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_gpe_info(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_event_info *out_info
))
// Set if the handler wishes to reenable the GPE it just handled
#define UACPI_GPE_REENABLE (1 << 7)
typedef uacpi_interrupt_ret (*uacpi_gpe_handler)(
uacpi_handle ctx, uacpi_namespace_node *gpe_device, uacpi_u16 idx
);
typedef enum uacpi_gpe_triggering {
UACPI_GPE_TRIGGERING_LEVEL = 0,
UACPI_GPE_TRIGGERING_EDGE = 1,
UACPI_GPE_TRIGGERING_MAX = UACPI_GPE_TRIGGERING_EDGE,
} uacpi_gpe_triggering;
const uacpi_char *uacpi_gpe_triggering_to_string(
uacpi_gpe_triggering triggering
);
/*
* Installs a handler to the provided GPE at 'idx' controlled by device
* 'gpe_device'. The GPE is automatically disabled & cleared according to the
* configured triggering upon invoking the handler. The event is optionally
* re-enabled (by returning UACPI_GPE_REENABLE from the handler)
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_install_gpe_handler(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_gpe_triggering triggering, uacpi_gpe_handler handler, uacpi_handle ctx
))
/*
* Installs a raw handler to the provided GPE at 'idx' controlled by device
* 'gpe_device'. The handler is dispatched immediately after the event is
* received, status & enable bits are untouched.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_install_gpe_handler_raw(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_gpe_triggering triggering, uacpi_gpe_handler handler, uacpi_handle ctx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_uninstall_gpe_handler(
uacpi_namespace_node *gpe_device, uacpi_u16 idx, uacpi_gpe_handler handler
))
/*
* Marks the GPE 'idx' managed by 'gpe_device' as wake-capable. 'wake_device' is
* optional and configures the GPE to generate an implicit notification whenever
* an event occurs.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_setup_gpe_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_namespace_node *wake_device
))
/*
* Mark a GPE managed by 'gpe_device' as enabled/disabled for wake. The GPE must
* have previously been marked by calling uacpi_gpe_setup_for_wake. This
* function only affects the GPE enable register state following the call to
* uacpi_gpe_enable_all_for_wake.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enable_gpe_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_disable_gpe_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Finalize GPE initialization by enabling all GPEs not configured for wake and
* having a matching AML handler detected.
*
* This should be called after the kernel power managment subsystem has
* enumerated all of the devices, executing their _PRW methods etc., and
* marking those it wishes to use for wake by calling uacpi_setup_gpe_for_wake
* or uacpi_mark_gpe_for_wake.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_finalize_gpe_initialization(void)
)
/*
* Enable/disable a general purpose event managed by 'gpe_device'. Internally
* this uses reference counting to make sure a GPE is not disabled until all
* possible users of it do so. GPEs not marked for wake are enabled
* automatically so this API is only needed for wake events or those that don't
* have a corresponding AML handler.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enable_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_disable_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Clear the status bit of the event 'idx' managed by 'gpe_device'.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_clear_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Suspend/resume a general purpose event managed by 'gpe_device'. This bypasses
* the reference counting mechanism and unconditionally clears/sets the
* corresponding bit in the enable registers. This is used for switching the GPE
* to poll mode.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_suspend_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_resume_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Finish handling the GPE managed by 'gpe_device' at 'idx'. This clears the
* status registers if it hasn't been cleared yet and re-enables the event if
* it was enabled before.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_finish_handling_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Hard mask/umask a general purpose event at 'idx' managed by 'gpe_device'.
* This is used to permanently silence an event so that further calls to
* enable/disable as well as suspend/resume get ignored. This might be necessary
* for GPEs that cause an event storm due to the kernel's inability to properly
* handle them. The only way to enable a masked event is by a call to unmask.
*
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_mask_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_unmask_gpe(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
/*
* Disable all GPEs currently set up on the system.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_disable_all_gpes(void)
)
/*
* Enable all GPEs not marked as wake. This is only needed after the system
* wakes from a shallow sleep state and is called automatically by wake code.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enable_all_runtime_gpes(void)
)
/*
* Enable all GPEs marked as wake. This is only needed before the system goes
* to sleep is called automatically by sleep code.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enable_all_wake_gpes(void)
)
/*
* Install/uninstall a new GPE block, usually defined by a device in the
* namespace with a _HID of ACPI0006.
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_install_gpe_block(
uacpi_namespace_node *gpe_device, uacpi_u64 address,
uacpi_address_space address_space, uacpi_u16 num_registers,
uacpi_u32 irq
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_uninstall_gpe_block(
uacpi_namespace_node *gpe_device
))
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,12 @@
#pragma once
#include <uacpi/platform/compiler.h>
#define UACPI_BUILD_BUG_ON_WITH_MSG(expr, msg) UACPI_STATIC_ASSERT(!(expr), msg)
#define UACPI_BUILD_BUG_ON(expr) \
UACPI_BUILD_BUG_ON_WITH_MSG(expr, "BUILD BUG: " #expr " evaluated to true")
#define UACPI_EXPECT_SIZEOF(type, size) \
UACPI_BUILD_BUG_ON_WITH_MSG(sizeof(type) != size, \
"BUILD BUG: invalid type size")

View File

@ -0,0 +1,3 @@
#pragma once
#include <uacpi/platform/compiler.h>

View File

@ -0,0 +1,155 @@
#pragma once
#include <uacpi/acpi.h>
#include <uacpi/types.h>
#include <uacpi/uacpi.h>
#include <uacpi/internal/dynamic_array.h>
#include <uacpi/internal/shareable.h>
#include <uacpi/context.h>
struct uacpi_runtime_context {
/*
* A local copy of FADT that has been verified & converted to most optimal
* format for faster access to the registers.
*/
struct acpi_fadt fadt;
uacpi_u64 flags;
#ifndef UACPI_BAREBONES_MODE
/*
* A cached pointer to FACS so that we don't have to look it up in interrupt
* contexts as we can't take mutexes.
*/
struct acpi_facs *facs;
/*
* pm1{a,b}_evt_blk split into two registers for convenience
*/
struct acpi_gas pm1a_status_blk;
struct acpi_gas pm1b_status_blk;
struct acpi_gas pm1a_enable_blk;
struct acpi_gas pm1b_enable_blk;
#define UACPI_SLEEP_TYP_INVALID 0xFF
uacpi_u8 last_sleep_typ_a;
uacpi_u8 last_sleep_typ_b;
uacpi_u8 s0_sleep_typ_a;
uacpi_u8 s0_sleep_typ_b;
uacpi_bool global_lock_acquired;
#ifndef UACPI_REDUCED_HARDWARE
uacpi_bool was_in_legacy_mode;
uacpi_bool has_global_lock;
uacpi_bool sci_handle_valid;
uacpi_handle sci_handle;
#endif
uacpi_u64 opcodes_executed;
uacpi_u32 loop_timeout_seconds;
uacpi_u32 max_call_stack_depth;
uacpi_u32 global_lock_seq_num;
/*
* These are stored here to protect against stuff like:
* - CopyObject(JUNK, \)
* - CopyObject(JUNK, \_GL)
*/
uacpi_mutex *global_lock_mutex;
uacpi_object *root_object;
#ifndef UACPI_REDUCED_HARDWARE
uacpi_handle *global_lock_event;
uacpi_handle *global_lock_spinlock;
uacpi_bool global_lock_pending;
#endif
uacpi_bool bad_timesource;
uacpi_u8 init_level;
#endif // !UACPI_BAREBONES_MODE
#ifndef UACPI_REDUCED_HARDWARE
uacpi_bool is_hardware_reduced;
#endif
/*
* This is a per-table value but we mimic the NT implementation:
* treat all other definition blocks as if they were the same revision
* as DSDT.
*/
uacpi_bool is_rev1;
uacpi_u8 log_level;
};
extern struct uacpi_runtime_context g_uacpi_rt_ctx;
static inline uacpi_bool uacpi_check_flag(uacpi_u64 flag)
{
return (g_uacpi_rt_ctx.flags & flag) == flag;
}
static inline uacpi_bool uacpi_should_log(enum uacpi_log_level lvl)
{
return lvl <= g_uacpi_rt_ctx.log_level;
}
static inline uacpi_bool uacpi_is_hardware_reduced(void)
{
#ifndef UACPI_REDUCED_HARDWARE
return g_uacpi_rt_ctx.is_hardware_reduced;
#else
return UACPI_TRUE;
#endif
}
#ifndef UACPI_BAREBONES_MODE
static inline const uacpi_char *uacpi_init_level_to_string(uacpi_u8 lvl)
{
switch (lvl) {
case UACPI_INIT_LEVEL_EARLY:
return "early";
case UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED:
return "subsystem initialized";
case UACPI_INIT_LEVEL_NAMESPACE_LOADED:
return "namespace loaded";
case UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED:
return "namespace initialized";
default:
return "<invalid>";
}
}
#define UACPI_ENSURE_INIT_LEVEL_AT_LEAST(lvl) \
do { \
if (uacpi_unlikely(g_uacpi_rt_ctx.init_level < lvl)) { \
uacpi_error( \
"while evaluating %s: init level %d (%s) is too low, " \
"expected at least %d (%s)\n", __FUNCTION__, \
g_uacpi_rt_ctx.init_level, \
uacpi_init_level_to_string(g_uacpi_rt_ctx.init_level), lvl, \
uacpi_init_level_to_string(lvl) \
); \
return UACPI_STATUS_INIT_LEVEL_MISMATCH; \
} \
} while (0)
#define UACPI_ENSURE_INIT_LEVEL_IS(lvl) \
do { \
if (uacpi_unlikely(g_uacpi_rt_ctx.init_level != lvl)) { \
uacpi_error( \
"while evaluating %s: invalid init level %d (%s), " \
"expected %d (%s)\n", __FUNCTION__, \
g_uacpi_rt_ctx.init_level, \
uacpi_init_level_to_string(g_uacpi_rt_ctx.init_level), lvl, \
uacpi_init_level_to_string(lvl) \
); \
return UACPI_STATUS_INIT_LEVEL_MISMATCH; \
} \
} while (0)
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,185 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/internal/stdlib.h>
#include <uacpi/kernel_api.h>
#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE(name, type, inline_capacity) \
struct name { \
type inline_storage[inline_capacity]; \
type *dynamic_storage; \
uacpi_size dynamic_capacity; \
uacpi_size size_including_inline; \
}; \
#define DYNAMIC_ARRAY_SIZE(arr) ((arr)->size_including_inline)
#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE_EXPORTS(name, type, prefix) \
prefix uacpi_size name##_inline_capacity(struct name *arr); \
prefix type *name##_at(struct name *arr, uacpi_size idx); \
prefix type *name##_alloc(struct name *arr); \
prefix type *name##_calloc(struct name *arr); \
prefix void name##_pop(struct name *arr); \
prefix uacpi_size name##_size(struct name *arr); \
prefix type *name##_last(struct name *arr) \
prefix void name##_clear(struct name *arr);
#ifndef UACPI_BAREBONES_MODE
#define DYNAMIC_ARRAY_ALLOC_FN(name, type, prefix) \
UACPI_MAYBE_UNUSED \
prefix type *name##_alloc(struct name *arr) \
{ \
uacpi_size inline_cap; \
type *out_ptr; \
\
inline_cap = name##_inline_capacity(arr); \
\
if (arr->size_including_inline >= inline_cap) { \
uacpi_size dynamic_size; \
\
dynamic_size = arr->size_including_inline - inline_cap; \
if (dynamic_size == arr->dynamic_capacity) { \
uacpi_size bytes, type_size; \
void *new_buf; \
\
type_size = sizeof(*arr->dynamic_storage); \
\
if (arr->dynamic_capacity == 0) { \
bytes = type_size * inline_cap; \
} else { \
bytes = (arr->dynamic_capacity / 2) * type_size; \
if (bytes == 0) \
bytes += type_size; \
\
bytes += arr->dynamic_capacity * type_size; \
} \
\
new_buf = uacpi_kernel_alloc(bytes); \
if (uacpi_unlikely(new_buf == UACPI_NULL)) \
return UACPI_NULL; \
\
arr->dynamic_capacity = bytes / type_size; \
\
if (arr->dynamic_storage) { \
uacpi_memcpy(new_buf, arr->dynamic_storage, \
dynamic_size * type_size); \
} \
uacpi_free(arr->dynamic_storage, dynamic_size * type_size); \
arr->dynamic_storage = new_buf; \
} \
\
out_ptr = &arr->dynamic_storage[dynamic_size]; \
goto ret; \
} \
out_ptr = &arr->inline_storage[arr->size_including_inline]; \
ret: \
arr->size_including_inline++; \
return out_ptr; \
}
#define DYNAMIC_ARRAY_CLEAR_FN(name, type, prefix) \
prefix void name##_clear(struct name *arr) \
{ \
uacpi_free( \
arr->dynamic_storage, \
arr->dynamic_capacity * sizeof(*arr->dynamic_storage) \
); \
arr->size_including_inline = 0; \
arr->dynamic_capacity = 0; \
arr->dynamic_storage = UACPI_NULL; \
}
#else
#define DYNAMIC_ARRAY_ALLOC_FN(name, type, prefix) \
UACPI_MAYBE_UNUSED \
prefix type *name##_alloc(struct name *arr) \
{ \
uacpi_size inline_cap; \
type *out_ptr; \
\
inline_cap = name##_inline_capacity(arr); \
\
if (arr->size_including_inline >= inline_cap) { \
uacpi_size dynamic_size; \
\
dynamic_size = arr->size_including_inline - inline_cap; \
if (uacpi_unlikely(dynamic_size == arr->dynamic_capacity)) \
return UACPI_NULL; \
\
out_ptr = &arr->dynamic_storage[dynamic_size]; \
goto ret; \
} \
out_ptr = &arr->inline_storage[arr->size_including_inline]; \
ret: \
arr->size_including_inline++; \
return out_ptr; \
}
#define DYNAMIC_ARRAY_CLEAR_FN(name, type, prefix) \
prefix void name##_clear(struct name *arr) \
{ \
arr->size_including_inline = 0; \
arr->dynamic_capacity = 0; \
arr->dynamic_storage = UACPI_NULL; \
}
#endif
#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE_IMPL(name, type, prefix) \
UACPI_MAYBE_UNUSED \
prefix uacpi_size name##_inline_capacity(struct name *arr) \
{ \
return sizeof(arr->inline_storage) / sizeof(arr->inline_storage[0]); \
} \
\
UACPI_MAYBE_UNUSED \
prefix uacpi_size name##_capacity(struct name *arr) \
{ \
return name##_inline_capacity(arr) + arr->dynamic_capacity; \
} \
\
prefix type *name##_at(struct name *arr, uacpi_size idx) \
{ \
if (idx >= arr->size_including_inline) \
return UACPI_NULL; \
\
if (idx < name##_inline_capacity(arr)) \
return &arr->inline_storage[idx]; \
\
return &arr->dynamic_storage[idx - name##_inline_capacity(arr)]; \
} \
\
DYNAMIC_ARRAY_ALLOC_FN(name, type, prefix) \
\
UACPI_MAYBE_UNUSED \
prefix type *name##_calloc(struct name *arr) \
{ \
type *ret; \
\
ret = name##_alloc(arr); \
if (ret) \
uacpi_memzero(ret, sizeof(*ret)); \
\
return ret; \
} \
\
UACPI_MAYBE_UNUSED \
prefix void name##_pop(struct name *arr) \
{ \
if (arr->size_including_inline == 0) \
return; \
\
arr->size_including_inline--; \
} \
\
UACPI_MAYBE_UNUSED \
prefix uacpi_size name##_size(struct name *arr) \
{ \
return arr->size_including_inline; \
} \
\
UACPI_MAYBE_UNUSED \
prefix type *name##_last(struct name *arr) \
{ \
return name##_at(arr, arr->size_including_inline - 1); \
} \
\
DYNAMIC_ARRAY_CLEAR_FN(name, type, prefix)

View File

@ -0,0 +1,25 @@
#pragma once
#include <uacpi/event.h>
// This fixed event is internal-only, and we don't expose it in the enum
#define UACPI_FIXED_EVENT_GLOBAL_LOCK 0
UACPI_ALWAYS_OK_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_initialize_events_early(void)
)
UACPI_ALWAYS_OK_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_initialize_events(void)
)
UACPI_STUB_IF_REDUCED_HARDWARE(
void uacpi_deinitialize_events(void)
)
UACPI_STUB_IF_REDUCED_HARDWARE(
void uacpi_events_match_post_dynamic_table_load(void)
)
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_clear_all_events(void)
)

View File

@ -0,0 +1,7 @@
#pragma once
#include <uacpi/helpers.h>
#define UACPI_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define UACPI_UNUSED(x) (void)(x)

View File

@ -0,0 +1,24 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#include <uacpi/internal/namespace.h>
#ifndef UACPI_BAREBONES_MODE
enum uacpi_table_load_cause {
UACPI_TABLE_LOAD_CAUSE_LOAD_OP,
UACPI_TABLE_LOAD_CAUSE_LOAD_TABLE_OP,
UACPI_TABLE_LOAD_CAUSE_INIT,
UACPI_TABLE_LOAD_CAUSE_HOST,
};
uacpi_status uacpi_execute_table(void*, enum uacpi_table_load_cause cause);
uacpi_status uacpi_osi(uacpi_handle handle, uacpi_object *retval);
uacpi_status uacpi_execute_control_method(
uacpi_namespace_node *scope, uacpi_control_method *method,
const uacpi_object_array *args, uacpi_object **ret
);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,77 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/acpi.h>
#include <uacpi/io.h>
#ifndef UACPI_BAREBONES_MODE
typedef struct uacpi_mapped_gas {
uacpi_handle mapping;
uacpi_u8 access_bit_width;
uacpi_u8 total_bit_width;
uacpi_u8 bit_offset;
uacpi_status (*read)(
uacpi_handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 *out
);
uacpi_status (*write)(
uacpi_handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 in
);
void (*unmap)(uacpi_handle, uacpi_size);
} uacpi_mapped_gas;
uacpi_status uacpi_map_gas_noalloc(
const struct acpi_gas *gas, uacpi_mapped_gas *out_mapped
);
void uacpi_unmap_gas_nofree(uacpi_mapped_gas *gas);
uacpi_size uacpi_round_up_bits_to_bytes(uacpi_size bit_length);
void uacpi_read_buffer_field(
const uacpi_buffer_field *field, void *dst
);
void uacpi_write_buffer_field(
uacpi_buffer_field *field, const void *src, uacpi_size size
);
uacpi_status uacpi_field_unit_get_read_type(
struct uacpi_field_unit *field, uacpi_object_type *out_type
);
uacpi_status uacpi_field_unit_get_bit_length(
struct uacpi_field_unit *field, uacpi_size *out_length
);
uacpi_status uacpi_read_field_unit(
uacpi_field_unit *field, void *dst, uacpi_size size,
uacpi_data_view *wtr_response
);
uacpi_status uacpi_write_field_unit(
uacpi_field_unit *field, const void *src, uacpi_size size,
uacpi_data_view *wtr_response
);
uacpi_status uacpi_system_memory_read(
void *ptr, uacpi_size offset, uacpi_u8 width, uacpi_u64 *out
);
uacpi_status uacpi_system_memory_write(
void *ptr, uacpi_size offset, uacpi_u8 width, uacpi_u64 in
);
uacpi_status uacpi_system_io_read(
uacpi_handle handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 *out
);
uacpi_status uacpi_system_io_write(
uacpi_handle handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 in
);
uacpi_status uacpi_pci_read(
uacpi_handle handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 *out
);
uacpi_status uacpi_pci_write(
uacpi_handle handle, uacpi_size offset, uacpi_u8 width, uacpi_u64 in
);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,23 @@
#pragma once
#include <uacpi/kernel_api.h>
#include <uacpi/internal/context.h>
#include <uacpi/log.h>
#ifdef UACPI_FORMATTED_LOGGING
#define uacpi_log uacpi_kernel_log
#else
UACPI_PRINTF_DECL(2, 3)
void uacpi_log(uacpi_log_level, const uacpi_char*, ...);
#endif
#define uacpi_log_lvl(lvl, ...) \
do { if (uacpi_should_log(lvl)) uacpi_log(lvl, __VA_ARGS__); } while (0)
#define uacpi_debug(...) uacpi_log_lvl(UACPI_LOG_DEBUG, __VA_ARGS__)
#define uacpi_trace(...) uacpi_log_lvl(UACPI_LOG_TRACE, __VA_ARGS__)
#define uacpi_info(...) uacpi_log_lvl(UACPI_LOG_INFO, __VA_ARGS__)
#define uacpi_warn(...) uacpi_log_lvl(UACPI_LOG_WARN, __VA_ARGS__)
#define uacpi_error(...) uacpi_log_lvl(UACPI_LOG_ERROR, __VA_ARGS__)
void uacpi_logger_initialize(void);

View File

@ -0,0 +1,82 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/kernel_api.h>
#ifndef UACPI_BAREBONES_MODE
uacpi_bool uacpi_this_thread_owns_aml_mutex(uacpi_mutex*);
uacpi_status uacpi_acquire_aml_mutex(uacpi_mutex*, uacpi_u16 timeout);
uacpi_status uacpi_release_aml_mutex(uacpi_mutex*);
static inline uacpi_status uacpi_acquire_native_mutex(uacpi_handle mtx)
{
if (uacpi_unlikely(mtx == UACPI_NULL))
return UACPI_STATUS_INVALID_ARGUMENT;
return uacpi_kernel_acquire_mutex(mtx, 0xFFFF);
}
uacpi_status uacpi_acquire_native_mutex_with_timeout(
uacpi_handle mtx, uacpi_u16 timeout
);
static inline uacpi_status uacpi_release_native_mutex(uacpi_handle mtx)
{
if (uacpi_unlikely(mtx == UACPI_NULL))
return UACPI_STATUS_INVALID_ARGUMENT;
uacpi_kernel_release_mutex(mtx);
return UACPI_STATUS_OK;
}
static inline uacpi_status uacpi_acquire_native_mutex_may_be_null(
uacpi_handle mtx
)
{
if (mtx == UACPI_NULL)
return UACPI_STATUS_OK;
return uacpi_kernel_acquire_mutex(mtx, 0xFFFF);
}
static inline uacpi_status uacpi_release_native_mutex_may_be_null(
uacpi_handle mtx
)
{
if (mtx == UACPI_NULL)
return UACPI_STATUS_OK;
uacpi_kernel_release_mutex(mtx);
return UACPI_STATUS_OK;
}
struct uacpi_recursive_lock {
uacpi_handle mutex;
uacpi_size depth;
uacpi_thread_id owner;
};
uacpi_status uacpi_recursive_lock_init(struct uacpi_recursive_lock *lock);
uacpi_status uacpi_recursive_lock_deinit(struct uacpi_recursive_lock *lock);
uacpi_status uacpi_recursive_lock_acquire(struct uacpi_recursive_lock *lock);
uacpi_status uacpi_recursive_lock_release(struct uacpi_recursive_lock *lock);
struct uacpi_rw_lock {
uacpi_handle read_mutex;
uacpi_handle write_mutex;
uacpi_size num_readers;
};
uacpi_status uacpi_rw_lock_init(struct uacpi_rw_lock *lock);
uacpi_status uacpi_rw_lock_deinit(struct uacpi_rw_lock *lock);
uacpi_status uacpi_rw_lock_read(struct uacpi_rw_lock *lock);
uacpi_status uacpi_rw_unlock_read(struct uacpi_rw_lock *lock);
uacpi_status uacpi_rw_lock_write(struct uacpi_rw_lock *lock);
uacpi_status uacpi_rw_unlock_write(struct uacpi_rw_lock *lock);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,123 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/internal/shareable.h>
#include <uacpi/status.h>
#include <uacpi/namespace.h>
#ifndef UACPI_BAREBONES_MODE
#define UACPI_NAMESPACE_NODE_FLAG_ALIAS (1 << 0)
/*
* This node has been uninstalled and has no object associated with it.
*
* This is used to handle edge cases where an object needs to reference
* a namespace node, where the node might end up going out of scope before
* the object lifetime ends.
*/
#define UACPI_NAMESPACE_NODE_FLAG_DANGLING (1u << 1)
/*
* This node is method-local and must not be exposed via public API as its
* lifetime is limited.
*/
#define UACPI_NAMESPACE_NODE_FLAG_TEMPORARY (1u << 2)
#define UACPI_NAMESPACE_NODE_PREDEFINED (1u << 31)
typedef struct uacpi_namespace_node {
struct uacpi_shareable shareable;
uacpi_object_name name;
uacpi_u32 flags;
uacpi_object *object;
struct uacpi_namespace_node *parent;
struct uacpi_namespace_node *child;
struct uacpi_namespace_node *next;
} uacpi_namespace_node;
uacpi_status uacpi_initialize_namespace(void);
void uacpi_deinitialize_namespace(void);
uacpi_namespace_node *uacpi_namespace_node_alloc(uacpi_object_name name);
void uacpi_namespace_node_unref(uacpi_namespace_node *node);
uacpi_status uacpi_namespace_node_type_unlocked(
const uacpi_namespace_node *node, uacpi_object_type *out_type
);
uacpi_status uacpi_namespace_node_is_one_of_unlocked(
const uacpi_namespace_node *node, uacpi_object_type_bits type_mask,
uacpi_bool *out
);
uacpi_object *uacpi_namespace_node_get_object(const uacpi_namespace_node *node);
uacpi_object *uacpi_namespace_node_get_object_typed(
const uacpi_namespace_node *node, uacpi_object_type_bits type_mask
);
uacpi_status uacpi_namespace_node_acquire_object(
const uacpi_namespace_node *node, uacpi_object **out_obj
);
uacpi_status uacpi_namespace_node_acquire_object_typed(
const uacpi_namespace_node *node, uacpi_object_type_bits,
uacpi_object **out_obj
);
uacpi_status uacpi_namespace_node_reacquire_object(
uacpi_object *obj
);
uacpi_status uacpi_namespace_node_release_object(
uacpi_object *obj
);
uacpi_status uacpi_namespace_node_install(
uacpi_namespace_node *parent, uacpi_namespace_node *node
);
uacpi_status uacpi_namespace_node_uninstall(uacpi_namespace_node *node);
uacpi_namespace_node *uacpi_namespace_node_find_sub_node(
uacpi_namespace_node *parent,
uacpi_object_name name
);
enum uacpi_may_search_above_parent {
UACPI_MAY_SEARCH_ABOVE_PARENT_NO,
UACPI_MAY_SEARCH_ABOVE_PARENT_YES,
};
enum uacpi_permanent_only {
UACPI_PERMANENT_ONLY_NO,
UACPI_PERMANENT_ONLY_YES,
};
enum uacpi_should_lock {
UACPI_SHOULD_LOCK_NO,
UACPI_SHOULD_LOCK_YES,
};
uacpi_status uacpi_namespace_node_resolve(
uacpi_namespace_node *scope, const uacpi_char *path, enum uacpi_should_lock,
enum uacpi_may_search_above_parent, enum uacpi_permanent_only,
uacpi_namespace_node **out_node
);
uacpi_status uacpi_namespace_do_for_each_child(
uacpi_namespace_node *parent, uacpi_iteration_callback descending_callback,
uacpi_iteration_callback ascending_callback,
uacpi_object_type_bits, uacpi_u32 max_depth, enum uacpi_should_lock,
enum uacpi_permanent_only, void *user
);
uacpi_bool uacpi_namespace_node_is_dangling(uacpi_namespace_node *node);
uacpi_bool uacpi_namespace_node_is_temporary(uacpi_namespace_node *node);
uacpi_bool uacpi_namespace_node_is_predefined(uacpi_namespace_node *node);
uacpi_status uacpi_namespace_read_lock(void);
uacpi_status uacpi_namespace_read_unlock(void);
uacpi_status uacpi_namespace_write_lock(void);
uacpi_status uacpi_namespace_write_unlock(void);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,13 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/notify.h>
#ifndef UACPI_BAREBONES_MODE
uacpi_status uacpi_initialize_notify(void);
void uacpi_deinitialize_notify(void);
uacpi_status uacpi_notify_all(uacpi_namespace_node *node, uacpi_u64 value);
#endif // !UACPI_BAREBONES_MODE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/opregion.h>
#ifndef UACPI_BAREBONES_MODE
uacpi_status uacpi_initialize_opregion(void);
void uacpi_deinitialize_opregion(void);
void uacpi_trace_region_error(
uacpi_namespace_node *node, uacpi_char *message, uacpi_status ret
);
uacpi_status uacpi_install_address_space_handler_with_flags(
uacpi_namespace_node *device_node, enum uacpi_address_space space,
uacpi_region_handler handler, uacpi_handle handler_context,
uacpi_u16 flags
);
void uacpi_opregion_uninstall_handler(uacpi_namespace_node *node);
uacpi_bool uacpi_address_space_handler_is_default(
uacpi_address_space_handler *handler
);
uacpi_address_space_handlers *uacpi_node_get_address_space_handlers(
uacpi_namespace_node *node
);
uacpi_status uacpi_initialize_opregion_node(uacpi_namespace_node *node);
uacpi_status uacpi_opregion_attach(uacpi_namespace_node *node);
void uacpi_install_default_address_space_handlers(void);
uacpi_bool uacpi_is_buffer_access_address_space(uacpi_address_space space);
union uacpi_opregion_io_data {
uacpi_u64 *integer;
uacpi_data_view buffer;
};
uacpi_status uacpi_dispatch_opregion_io(
uacpi_field_unit *field, uacpi_u32 offset,
uacpi_region_op op, union uacpi_opregion_io_data data
);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,8 @@
#pragma once
#include <uacpi/osi.h>
uacpi_status uacpi_initialize_interfaces(void);
void uacpi_deinitialize_interfaces(void);
uacpi_status uacpi_handle_osi(const uacpi_char *string, uacpi_bool *out_value);

View File

@ -0,0 +1,7 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/registers.h>
uacpi_status uacpi_initialize_registers(void);
void uacpi_deinitialize_registers(void);

View File

@ -0,0 +1,327 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/resources.h>
#ifndef UACPI_BAREBONES_MODE
enum uacpi_aml_resource {
UACPI_AML_RESOURCE_TYPE_INVALID = 0,
// Small resources
UACPI_AML_RESOURCE_IRQ,
UACPI_AML_RESOURCE_DMA,
UACPI_AML_RESOURCE_START_DEPENDENT,
UACPI_AML_RESOURCE_END_DEPENDENT,
UACPI_AML_RESOURCE_IO,
UACPI_AML_RESOURCE_FIXED_IO,
UACPI_AML_RESOURCE_FIXED_DMA,
UACPI_AML_RESOURCE_VENDOR_TYPE0,
UACPI_AML_RESOURCE_END_TAG,
// Large resources
UACPI_AML_RESOURCE_MEMORY24,
UACPI_AML_RESOURCE_GENERIC_REGISTER,
UACPI_AML_RESOURCE_VENDOR_TYPE1,
UACPI_AML_RESOURCE_MEMORY32,
UACPI_AML_RESOURCE_FIXED_MEMORY32,
UACPI_AML_RESOURCE_ADDRESS32,
UACPI_AML_RESOURCE_ADDRESS16,
UACPI_AML_RESOURCE_EXTENDED_IRQ,
UACPI_AML_RESOURCE_ADDRESS64,
UACPI_AML_RESOURCE_ADDRESS64_EXTENDED,
UACPI_AML_RESOURCE_GPIO_CONNECTION,
UACPI_AML_RESOURCE_PIN_FUNCTION,
UACPI_AML_RESOURCE_SERIAL_CONNECTION,
UACPI_AML_RESOURCE_PIN_CONFIGURATION,
UACPI_AML_RESOURCE_PIN_GROUP,
UACPI_AML_RESOURCE_PIN_GROUP_FUNCTION,
UACPI_AML_RESOURCE_PIN_GROUP_CONFIGURATION,
UACPI_AML_RESOURCE_CLOCK_INPUT,
UACPI_AML_RESOURCE_MAX = UACPI_AML_RESOURCE_CLOCK_INPUT,
};
enum uacpi_aml_resource_size_kind {
UACPI_AML_RESOURCE_SIZE_KIND_FIXED,
UACPI_AML_RESOURCE_SIZE_KIND_FIXED_OR_ONE_LESS,
UACPI_AML_RESOURCE_SIZE_KIND_VARIABLE,
};
enum uacpi_aml_resource_kind {
UACPI_AML_RESOURCE_KIND_SMALL = 0,
UACPI_AML_RESOURCE_KIND_LARGE,
};
enum uacpi_resource_convert_opcode {
UACPI_RESOURCE_CONVERT_OPCODE_END = 0,
/*
* AML -> native:
* Take the mask at 'aml_offset' and convert to an array of uacpi_u8
* at 'native_offset' with the value corresponding to the bit index.
* The array size is written to the byte at offset 'arg2'.
*
* native -> AML:
* Walk each element of the array at 'native_offset' and set the
* corresponding bit in the mask at 'aml_offset' to 1. The array size is
* read from the byte at offset 'arg2'.
*/
UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_8,
UACPI_RESOURCE_CONVERT_OPCODE_PACKED_ARRAY_16,
/*
* AML -> native:
* Grab the bits at the byte at 'aml_offset' + 'bit_index', and copy its
* value into the byte at 'native_offset'.
*
* native -> AML:
* Grab first N bits at 'native_offset' and copy to 'aml_offset' starting
* at the 'bit_index'.
*
* NOTE:
* These must be contiguous in this order.
*/
UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_1,
UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_2,
UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_3,
UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_6 =
UACPI_RESOURCE_CONVERT_OPCODE_BIT_FIELD_3 + 3,
/*
* AML -> native:
* Copy N bytes at 'aml_offset' to 'native_offset'.
*
* native -> AML:
* Copy N bytes at 'native_offset' to 'aml_offset'.
*
* 'imm' is added to the accumulator.
*
* NOTE: These are affected by the current value in the accumulator. If it's
* set to 0 at the time of evalution, this is executed once, N times
* otherwise. 0xFF is considered a special value, which resets the
* accumulator to 0 unconditionally.
*/
UACPI_RESOURCE_CONVERT_OPCODE_FIELD_8,
UACPI_RESOURCE_CONVERT_OPCODE_FIELD_16,
UACPI_RESOURCE_CONVERT_OPCODE_FIELD_32,
UACPI_RESOURCE_CONVERT_OPCODE_FIELD_64,
/*
* If the length of the current resource is less than 'arg0', then skip
* 'imm' instructions.
*/
UACPI_RESOURCE_CONVERT_OPCODE_SKIP_IF_AML_SIZE_LESS_THAN,
/*
* Skip 'imm' instructions if 'arg0' is not equal to the value in the
* accumulator.
*/
UACPI_RESOURCE_CONVERT_OPCODE_SKIP_IF_NOT_EQUALS,
/*
* AML -> native:
* Set the byte at 'native_offset' to 'imm'.
*
* native -> AML:
* Set the byte at 'aml_offset' to 'imm'.
*/
UACPI_RESOURCE_CONVERT_OPCODE_SET_TO_IMM,
/*
* AML -> native:
* Load the AML resoruce length into the accumulator as well as the field at
* 'native_offset' of width N.
*
* native -> AML:
* Load the resource length into the accumulator.
*/
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_AML_SIZE_32,
/*
* AML -> native:
* Load the 8 bit field at 'aml_offset' into the accumulator and store at
* 'native_offset'.
*
* native -> AML:
* Load the 8 bit field at 'native_offset' into the accumulator and store
* at 'aml_offset'.
*
* The accumulator is multiplied by 'imm' unless it's set to zero.
*/
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_8_STORE,
/*
* Load the N bit field at 'native_offset' into the accumulator
*/
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_8_NATIVE,
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_16_NATIVE,
/*
* Load 'imm' into the accumulator.
*/
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_IMM,
/*
* AML -> native:
* Load the resource source at offset = aml size + accumulator into the
* uacpi_resource_source struct at 'native_offset'. The string bytes are
* written to the offset at resource size + accumulator. The presence is
* detected by comparing the length of the resource to the offset,
* 'arg2' optionally specifies the offset to the upper bound of the string.
*
* native -> AML:
* Load the resource source from the uacpi_resource_source struct at
* 'native_offset' to aml_size + accumulator. aml_size + accumulator is
* optionally written to 'aml_offset' if it's specified.
*/
UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE,
UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_SOURCE_NO_INDEX,
UACPI_RESOURCE_CONVERT_OPCODE_RESOURCE_LABEL,
/*
* AML -> native:
* Load the pin table with upper bound specified at 'aml_offset'.
* The table length is calculated by subtracting the upper bound from
* aml_size and is written into the accumulator.
*
* native -> AML:
* Load the pin table length from 'native_offset' and multiply by 2, store
* the result in the accumulator.
*/
UACPI_RESOURCE_CONVERT_OPCODE_LOAD_PIN_TABLE_LENGTH,
/*
* AML -> native:
* Store the accumulator divided by 2 at 'native_offset'.
* The table is copied to the offset at resource size from offset at
* aml_size with the pointer written to the offset at 'arg2'.
*
* native -> AML:
* Read the pin table from resource size offset, write aml_size to
* 'aml_offset'. Copy accumulator bytes to the offset at aml_size.
*/
UACPI_RESOURCE_CONVERT_OPCODE_PIN_TABLE,
/*
* AML -> native:
* Load vendor data with offset stored at 'aml_offset'. The length is
* calculated as aml_size - aml_offset and is written to 'native_offset'.
* The data is written to offset - aml_size with the pointer written back
* to the offset at 'arg2'.
*
* native -> AML:
* Read vendor data from the pointer at offset 'arg2' and size at
* 'native_offset', the offset to write to is calculated as the difference
* between the data pointer and the native resource end pointer.
* offset + aml_size is written to 'aml_offset' and the data is copied
* there as well.
*/
UACPI_RESOURCE_CONVERT_OPCODE_VENDOR_DATA,
/*
* AML -> native:
* Read the serial type from the byte at 'aml_offset' and write it to the
* type field of the uacpi_resource_serial_bus_common structure. Convert
* the serial type to native and set the resource type to it. Copy the
* vendor data to the offset at native size, the length is calculated
* as type_data_length - extra-type-specific-size, and is written to
* vendor_data_length, as well as the accumulator. The data pointer is
* written to vendor_data.
*
* native -> AML:
* Set the serial type at 'aml_offset' to the value stored at
* 'native_offset'. Load the vendor data to the offset at aml_size,
* the length is read from 'vendor_data_length', and the data is copied from
* 'vendor_data'.
*/
UACPI_RESOURCE_CONVERT_OPCODE_SERIAL_TYPE_SPECIFIC,
/*
* Produces an error if encountered in the instruction stream.
* Used to trap invalid/unexpected code flow.
*/
UACPI_RESOURCE_CONVERT_OPCODE_UNREACHABLE,
};
struct uacpi_resource_convert_instruction {
uacpi_u8 code;
union {
uacpi_u8 aml_offset;
uacpi_u8 arg0;
} f1;
union {
uacpi_u8 native_offset;
uacpi_u8 arg1;
} f2;
union {
uacpi_u8 imm;
uacpi_u8 bit_index;
uacpi_u8 arg2;
} f3;
};
struct uacpi_resource_spec {
uacpi_u8 type : 5;
uacpi_u8 native_type : 5;
uacpi_u8 resource_kind : 1;
uacpi_u8 size_kind : 2;
/*
* Size of the resource as appears in the AML byte stream, for variable
* length resources this is the minimum.
*/
uacpi_u16 aml_size;
/*
* Size of the native human-readable uacpi resource, for variable length
* resources this is the minimum. The final length is this field plus the
* result of extra_size_for_native().
*/
uacpi_u16 native_size;
/*
* Calculate the amount of extra bytes that must be allocated for a specific
* native resource given the AML counterpart. This being NULL means no extra
* bytes are needed, aka native resources is always the same size.
*/
uacpi_size (*extra_size_for_native)(
const struct uacpi_resource_spec*, void*, uacpi_size
);
/*
* Calculate the number of bytes needed to represent a native resource as
* AML. The 'aml_size' field is used if this is NULL.
*/
uacpi_size (*size_for_aml)(
const struct uacpi_resource_spec*, uacpi_resource*
);
const struct uacpi_resource_convert_instruction *to_native;
const struct uacpi_resource_convert_instruction *to_aml;
};
typedef uacpi_iteration_decision (*uacpi_aml_resource_iteration_callback)(
void*, uacpi_u8 *data, uacpi_u16 resource_size,
const struct uacpi_resource_spec*
);
uacpi_status uacpi_for_each_aml_resource(
uacpi_data_view, uacpi_aml_resource_iteration_callback cb, void *user
);
uacpi_status uacpi_find_aml_resource_end_tag(
uacpi_data_view, uacpi_size *out_offset
);
uacpi_status uacpi_native_resources_from_aml(
uacpi_data_view, uacpi_resources **out_resources
);
uacpi_status uacpi_native_resources_to_aml(
uacpi_resources *resources, uacpi_object **out_template
);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,21 @@
#pragma once
#include <uacpi/types.h>
struct uacpi_shareable {
uacpi_u32 reference_count;
};
void uacpi_shareable_init(uacpi_handle);
uacpi_bool uacpi_bugged_shareable(uacpi_handle);
void uacpi_make_shareable_bugged(uacpi_handle);
uacpi_u32 uacpi_shareable_ref(uacpi_handle);
uacpi_u32 uacpi_shareable_unref(uacpi_handle);
void uacpi_shareable_unref_and_delete_if_last(
uacpi_handle, void (*do_free)(uacpi_handle)
);
uacpi_u32 uacpi_shareable_refcount(uacpi_handle);

View File

@ -0,0 +1,128 @@
#pragma once
#include <uacpi/internal/types.h>
#include <uacpi/internal/helpers.h>
#include <uacpi/platform/libc.h>
#include <uacpi/platform/config.h>
#include <uacpi/kernel_api.h>
#ifdef UACPI_USE_BUILTIN_STRING
#ifndef uacpi_memcpy
void *uacpi_memcpy(void *dest, const void *src, uacpi_size count);
#endif
#ifndef uacpi_memmove
void *uacpi_memmove(void *dest, const void *src, uacpi_size count);
#endif
#ifndef uacpi_memset
void *uacpi_memset(void *dest, uacpi_i32 ch, uacpi_size count);
#endif
#ifndef uacpi_memcmp
uacpi_i32 uacpi_memcmp(const void *lhs, const void *rhs, uacpi_size count);
#endif
#else
#ifndef uacpi_memcpy
#ifdef UACPI_COMPILER_HAS_BUILTIN_MEMCPY
#define uacpi_memcpy __builtin_memcpy
#else
extern void *memcpy(void *dest, const void *src, uacpi_size count);
#define uacpi_memcpy memcpy
#endif
#endif
#ifndef uacpi_memmove
#ifdef UACPI_COMPILER_HAS_BUILTIN_MEMMOVE
#define uacpi_memmove __builtin_memmove
#else
extern void *memmove(void *dest, const void *src, uacpi_size count);
#define uacpi_memmove memmove
#endif
#endif
#ifndef uacpi_memset
#ifdef UACPI_COMPILER_HAS_BUILTIN_MEMSET
#define uacpi_memset __builtin_memset
#else
extern void *memset(void *dest, int ch, uacpi_size count);
#define uacpi_memset memset
#endif
#endif
#ifndef uacpi_memcmp
#ifdef UACPI_COMPILER_HAS_BUILTIN_MEMCMP
#define uacpi_memcmp __builtin_memcmp
#else
extern int memcmp(const void *lhs, const void *rhs, uacpi_size count);
#define uacpi_memcmp memcmp
#endif
#endif
#endif
#ifndef uacpi_strlen
uacpi_size uacpi_strlen(const uacpi_char *str);
#endif
#ifndef uacpi_strnlen
uacpi_size uacpi_strnlen(const uacpi_char *str, uacpi_size max);
#endif
#ifndef uacpi_strcmp
uacpi_i32 uacpi_strcmp(const uacpi_char *lhs, const uacpi_char *rhs);
#endif
#ifndef uacpi_snprintf
UACPI_PRINTF_DECL(3, 4)
uacpi_i32 uacpi_snprintf(
uacpi_char *buffer, uacpi_size capacity, const uacpi_char *fmt, ...
);
#endif
#ifndef uacpi_vsnprintf
uacpi_i32 uacpi_vsnprintf(
uacpi_char *buffer, uacpi_size capacity, const uacpi_char *fmt,
uacpi_va_list vlist
);
#endif
#ifdef UACPI_SIZED_FREES
#define uacpi_free(mem, size) uacpi_kernel_free(mem, size)
#else
#define uacpi_free(mem, _) uacpi_kernel_free(mem)
#endif
#define uacpi_memzero(ptr, size) uacpi_memset(ptr, 0, size)
#define UACPI_COMPARE(x, y, op) ((x) op (y) ? (x) : (y))
#define UACPI_MIN(x, y) UACPI_COMPARE(x, y, <)
#define UACPI_MAX(x, y) UACPI_COMPARE(x, y, >)
#define UACPI_ALIGN_UP_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define UACPI_ALIGN_UP(x, val, type) UACPI_ALIGN_UP_MASK(x, (type)(val) - 1)
#define UACPI_ALIGN_DOWN_MASK(x, mask) ((x) & ~(mask))
#define UACPI_ALIGN_DOWN(x, val, type) UACPI_ALIGN_DOWN_MASK(x, (type)(val) - 1)
#define UACPI_IS_ALIGNED_MASK(x, mask) (((x) & (mask)) == 0)
#define UACPI_IS_ALIGNED(x, val, type) UACPI_IS_ALIGNED_MASK(x, (type)(val) - 1)
#define UACPI_IS_POWER_OF_TWO(x, type) UACPI_IS_ALIGNED(x, x, type)
void uacpi_memcpy_zerout(void *dst, const void *src,
uacpi_size dst_size, uacpi_size src_size);
// Returns the one-based bit location of LSb or 0
uacpi_u8 uacpi_bit_scan_forward(uacpi_u64);
// Returns the one-based bit location of MSb or 0
uacpi_u8 uacpi_bit_scan_backward(uacpi_u64);
#ifndef UACPI_NATIVE_ALLOC_ZEROED
void *uacpi_builtin_alloc_zeroed(uacpi_size size);
#define uacpi_kernel_alloc_zeroed uacpi_builtin_alloc_zeroed
#endif

View File

@ -0,0 +1,70 @@
#pragma once
#include <uacpi/internal/context.h>
#include <uacpi/internal/interpreter.h>
#include <uacpi/types.h>
#include <uacpi/status.h>
#include <uacpi/tables.h>
enum uacpi_table_origin {
#ifndef UACPI_BAREBONES_MODE
UACPI_TABLE_ORIGIN_FIRMWARE_VIRTUAL = 0,
#endif
UACPI_TABLE_ORIGIN_FIRMWARE_PHYSICAL = 1,
UACPI_TABLE_ORIGIN_HOST_VIRTUAL,
UACPI_TABLE_ORIGIN_HOST_PHYSICAL,
};
struct uacpi_installed_table {
uacpi_phys_addr phys_addr;
struct acpi_sdt_hdr hdr;
void *ptr;
uacpi_u16 reference_count;
#define UACPI_TABLE_LOADED (1 << 0)
#define UACPI_TABLE_CSUM_VERIFIED (1 << 1)
#define UACPI_TABLE_INVALID (1 << 2)
uacpi_u8 flags;
uacpi_u8 origin;
};
uacpi_status uacpi_initialize_tables(void);
void uacpi_deinitialize_tables(void);
uacpi_bool uacpi_signatures_match(const void *const lhs, const void *const rhs);
uacpi_status uacpi_check_table_signature(void *table, const uacpi_char *expect);
uacpi_status uacpi_verify_table_checksum(void *table, uacpi_size size);
uacpi_status uacpi_table_install_physical_with_origin(
uacpi_phys_addr phys, enum uacpi_table_origin origin, uacpi_table *out_table
);
uacpi_status uacpi_table_install_with_origin(
void *virt, enum uacpi_table_origin origin, uacpi_table *out_table
);
#ifndef UACPI_BAREBONES_MODE
void uacpi_table_mark_as_loaded(uacpi_size idx);
uacpi_status uacpi_table_load_with_cause(
uacpi_size idx, enum uacpi_table_load_cause cause
);
#endif // !UACPI_BAREBONES_MODE
typedef uacpi_iteration_decision (*uacpi_table_iteration_callback)
(void *user, struct uacpi_installed_table *tbl, uacpi_size idx);
uacpi_status uacpi_for_each_table(
uacpi_size base_idx, uacpi_table_iteration_callback, void *user
);
typedef uacpi_bool (*uacpi_table_match_callback)
(struct uacpi_installed_table *tbl);
uacpi_status uacpi_table_match(
uacpi_size base_idx, uacpi_table_match_callback, uacpi_table *out_table
);
#define UACPI_PRI_TBL_HDR "'%.4s' (OEM ID '%.6s' OEM Table ID '%.8s')"
#define UACPI_FMT_TBL_HDR(hdr) (hdr)->signature, (hdr)->oemid, (hdr)->oem_table_id

View File

@ -0,0 +1,310 @@
#pragma once
#include <uacpi/status.h>
#include <uacpi/types.h>
#include <uacpi/internal/shareable.h>
#ifndef UACPI_BAREBONES_MODE
// object->flags field if object->type == UACPI_OBJECT_REFERENCE
enum uacpi_reference_kind {
UACPI_REFERENCE_KIND_REFOF = 0,
UACPI_REFERENCE_KIND_LOCAL = 1,
UACPI_REFERENCE_KIND_ARG = 2,
UACPI_REFERENCE_KIND_NAMED = 3,
UACPI_REFERENCE_KIND_PKG_INDEX = 4,
};
// object->flags field if object->type == UACPI_OBJECT_STRING
enum uacpi_string_kind {
UACPI_STRING_KIND_NORMAL = 0,
UACPI_STRING_KIND_PATH,
};
typedef struct uacpi_buffer {
struct uacpi_shareable shareable;
union {
void *data;
uacpi_u8 *byte_data;
uacpi_char *text;
};
uacpi_size size;
} uacpi_buffer;
typedef struct uacpi_package {
struct uacpi_shareable shareable;
uacpi_object **objects;
uacpi_size count;
} uacpi_package;
typedef struct uacpi_buffer_field {
uacpi_buffer *backing;
uacpi_size bit_index;
uacpi_u32 bit_length;
uacpi_bool force_buffer;
} uacpi_buffer_field;
typedef struct uacpi_buffer_index {
uacpi_size idx;
uacpi_buffer *buffer;
} uacpi_buffer_index;
typedef struct uacpi_mutex {
struct uacpi_shareable shareable;
uacpi_handle handle;
uacpi_thread_id owner;
uacpi_u16 depth;
uacpi_u8 sync_level;
} uacpi_mutex;
typedef struct uacpi_event {
struct uacpi_shareable shareable;
uacpi_handle handle;
} uacpi_event;
typedef struct uacpi_address_space_handler {
struct uacpi_shareable shareable;
uacpi_region_handler callback;
uacpi_handle user_context;
struct uacpi_address_space_handler *next;
struct uacpi_operation_region *regions;
uacpi_u16 space;
#define UACPI_ADDRESS_SPACE_HANDLER_DEFAULT (1 << 0)
uacpi_u16 flags;
} uacpi_address_space_handler;
/*
* NOTE: These are common object headers.
* Any changes to these structs must be propagated to all objects.
* ==============================================================
* Common for the following objects:
* - UACPI_OBJECT_OPERATION_REGION
* - UACPI_OBJECT_PROCESSOR
* - UACPI_OBJECT_DEVICE
* - UACPI_OBJECT_THERMAL_ZONE
*/
typedef struct uacpi_address_space_handlers {
struct uacpi_shareable shareable;
uacpi_address_space_handler *head;
} uacpi_address_space_handlers;
typedef struct uacpi_device_notify_handler {
uacpi_notify_handler callback;
uacpi_handle user_context;
struct uacpi_device_notify_handler *next;
} uacpi_device_notify_handler;
/*
* Common for the following objects:
* - UACPI_OBJECT_PROCESSOR
* - UACPI_OBJECT_DEVICE
* - UACPI_OBJECT_THERMAL_ZONE
*/
typedef struct uacpi_handlers {
struct uacpi_shareable shareable;
uacpi_address_space_handler *address_space_head;
uacpi_device_notify_handler *notify_head;
} uacpi_handlers;
// This region has a corresponding _REG method that was succesfully executed
#define UACPI_OP_REGION_STATE_REG_EXECUTED (1 << 0)
// This region was successfully attached to a handler
#define UACPI_OP_REGION_STATE_ATTACHED (1 << 1)
typedef struct uacpi_operation_region {
struct uacpi_shareable shareable;
uacpi_address_space_handler *handler;
uacpi_handle user_context;
uacpi_u16 space;
uacpi_u8 state_flags;
uacpi_u64 offset;
uacpi_u64 length;
union {
// If space == TABLE_DATA
uacpi_u64 table_idx;
// If space == PCC
uacpi_u8 *internal_buffer;
};
// Used to link regions sharing the same handler
struct uacpi_operation_region *next;
} uacpi_operation_region;
typedef struct uacpi_device {
struct uacpi_shareable shareable;
uacpi_address_space_handler *address_space_handlers;
uacpi_device_notify_handler *notify_handlers;
} uacpi_device;
typedef struct uacpi_processor {
struct uacpi_shareable shareable;
uacpi_address_space_handler *address_space_handlers;
uacpi_device_notify_handler *notify_handlers;
uacpi_u8 id;
uacpi_u32 block_address;
uacpi_u8 block_length;
} uacpi_processor;
typedef struct uacpi_thermal_zone {
struct uacpi_shareable shareable;
uacpi_address_space_handler *address_space_handlers;
uacpi_device_notify_handler *notify_handlers;
} uacpi_thermal_zone;
typedef struct uacpi_power_resource {
uacpi_u8 system_level;
uacpi_u16 resource_order;
} uacpi_power_resource;
typedef uacpi_status (*uacpi_native_call_handler)(
uacpi_handle ctx, uacpi_object *retval
);
typedef struct uacpi_control_method {
struct uacpi_shareable shareable;
union {
uacpi_u8 *code;
uacpi_native_call_handler handler;
};
uacpi_mutex *mutex;
uacpi_u32 size;
uacpi_u8 sync_level : 4;
uacpi_u8 args : 3;
uacpi_u8 is_serialized : 1;
uacpi_u8 named_objects_persist: 1;
uacpi_u8 native_call : 1;
uacpi_u8 owns_code : 1;
} uacpi_control_method;
typedef enum uacpi_access_type {
UACPI_ACCESS_TYPE_ANY = 0,
UACPI_ACCESS_TYPE_BYTE = 1,
UACPI_ACCESS_TYPE_WORD = 2,
UACPI_ACCESS_TYPE_DWORD = 3,
UACPI_ACCESS_TYPE_QWORD = 4,
UACPI_ACCESS_TYPE_BUFFER = 5,
} uacpi_access_type;
typedef enum uacpi_lock_rule {
UACPI_LOCK_RULE_NO_LOCK = 0,
UACPI_LOCK_RULE_LOCK = 1,
} uacpi_lock_rule;
typedef enum uacpi_update_rule {
UACPI_UPDATE_RULE_PRESERVE = 0,
UACPI_UPDATE_RULE_WRITE_AS_ONES = 1,
UACPI_UPDATE_RULE_WRITE_AS_ZEROES = 2,
} uacpi_update_rule;
typedef enum uacpi_field_unit_kind {
UACPI_FIELD_UNIT_KIND_NORMAL = 0,
UACPI_FIELD_UNIT_KIND_INDEX = 1,
UACPI_FIELD_UNIT_KIND_BANK = 2,
} uacpi_field_unit_kind;
typedef struct uacpi_field_unit {
struct uacpi_shareable shareable;
union {
// UACPI_FIELD_UNIT_KIND_NORMAL
struct {
uacpi_namespace_node *region;
};
// UACPI_FIELD_UNIT_KIND_INDEX
struct {
struct uacpi_field_unit *index;
struct uacpi_field_unit *data;
};
// UACPI_FIELD_UNIT_KIND_BANK
struct {
uacpi_namespace_node *bank_region;
struct uacpi_field_unit *bank_selection;
uacpi_u64 bank_value;
};
};
uacpi_object *connection;
uacpi_u32 byte_offset;
uacpi_u32 bit_length;
uacpi_u32 pin_offset;
uacpi_u8 bit_offset_within_first_byte;
uacpi_u8 access_width_bytes;
uacpi_u8 access_length;
uacpi_u8 attributes : 4;
uacpi_u8 update_rule : 2;
uacpi_u8 kind : 2;
uacpi_u8 lock_rule : 1;
} uacpi_field_unit;
typedef struct uacpi_object {
struct uacpi_shareable shareable;
uacpi_u8 type;
uacpi_u8 flags;
union {
uacpi_u64 integer;
uacpi_package *package;
uacpi_buffer_field buffer_field;
uacpi_object *inner_object;
uacpi_control_method *method;
uacpi_buffer *buffer;
uacpi_mutex *mutex;
uacpi_event *event;
uacpi_buffer_index buffer_index;
uacpi_operation_region *op_region;
uacpi_device *device;
uacpi_processor *processor;
uacpi_thermal_zone *thermal_zone;
uacpi_address_space_handlers *address_space_handlers;
uacpi_handlers *handlers;
uacpi_power_resource power_resource;
uacpi_field_unit *field_unit;
};
} uacpi_object;
uacpi_object *uacpi_create_object(uacpi_object_type type);
enum uacpi_assign_behavior {
UACPI_ASSIGN_BEHAVIOR_DEEP_COPY,
UACPI_ASSIGN_BEHAVIOR_SHALLOW_COPY,
};
uacpi_status uacpi_object_assign(uacpi_object *dst, uacpi_object *src,
enum uacpi_assign_behavior);
void uacpi_object_attach_child(uacpi_object *parent, uacpi_object *child);
void uacpi_object_detach_child(uacpi_object *parent);
struct uacpi_object *uacpi_create_internal_reference(
enum uacpi_reference_kind kind, uacpi_object *child
);
uacpi_object *uacpi_unwrap_internal_reference(uacpi_object *object);
enum uacpi_prealloc_objects {
UACPI_PREALLOC_OBJECTS_NO,
UACPI_PREALLOC_OBJECTS_YES,
};
uacpi_bool uacpi_package_fill(
uacpi_package *pkg, uacpi_size num_elements,
enum uacpi_prealloc_objects prealloc_objects
);
uacpi_mutex *uacpi_create_mutex(void);
void uacpi_mutex_unref(uacpi_mutex*);
void uacpi_method_unref(uacpi_control_method*);
void uacpi_address_space_handler_unref(uacpi_address_space_handler *handler);
void uacpi_buffer_to_view(uacpi_buffer*, uacpi_data_view*);
#endif // !UACPI_BAREBONES_MODE

View File

@ -0,0 +1,45 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/utilities.h>
#include <uacpi/internal/log.h>
#include <uacpi/internal/stdlib.h>
static inline uacpi_phys_addr uacpi_truncate_phys_addr_with_warn(uacpi_u64 large_addr)
{
if (sizeof(uacpi_phys_addr) < 8 && large_addr > 0xFFFFFFFF) {
uacpi_warn(
"truncating a physical address 0x%"UACPI_PRIX64
" outside of address space\n", UACPI_FMT64(large_addr)
);
}
return (uacpi_phys_addr)large_addr;
}
#define UACPI_PTR_TO_VIRT_ADDR(ptr) ((uacpi_virt_addr)(ptr))
#define UACPI_VIRT_ADDR_TO_PTR(vaddr) ((void*)(vaddr))
#define UACPI_PTR_ADD(ptr, value) ((void*)(((uacpi_u8*)(ptr)) + value))
/*
* Target buffer must have a length of at least 8 bytes.
*/
void uacpi_eisa_id_to_string(uacpi_u32, uacpi_char *out_string);
enum uacpi_base {
UACPI_BASE_AUTO,
UACPI_BASE_OCT = 8,
UACPI_BASE_DEC = 10,
UACPI_BASE_HEX = 16,
};
uacpi_status uacpi_string_to_integer(
const uacpi_char *str, uacpi_size max_chars, enum uacpi_base base,
uacpi_u64 *out_value
);
uacpi_bool uacpi_is_valid_nameseg(uacpi_u8 *nameseg);
void uacpi_free_dynamic_string(const uacpi_char *str);
#define UACPI_NANOSECONDS_PER_SEC (1000ull * 1000ull * 1000ull)

View File

@ -0,0 +1,36 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/acpi.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
uacpi_status uacpi_gas_read(const struct acpi_gas *gas, uacpi_u64 *value);
uacpi_status uacpi_gas_write(const struct acpi_gas *gas, uacpi_u64 value);
typedef struct uacpi_mapped_gas uacpi_mapped_gas;
/*
* Map a GAS for faster access in the future. The handle returned via
* 'out_mapped' must be freed & unmapped using uacpi_unmap_gas() when
* no longer needed.
*/
uacpi_status uacpi_map_gas(const struct acpi_gas *gas, uacpi_mapped_gas **out_mapped);
void uacpi_unmap_gas(uacpi_mapped_gas*);
/*
* Same as uacpi_gas_{read,write} but operates on a pre-mapped handle for faster
* access and/or ability to use in critical sections/irq contexts.
*/
uacpi_status uacpi_gas_read_mapped(const uacpi_mapped_gas *gas, uacpi_u64 *value);
uacpi_status uacpi_gas_write_mapped(const uacpi_mapped_gas *gas, uacpi_u64 value);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,375 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/platform/arch_helpers.h>
#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);
/*
* 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);
/*
* 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);
#ifndef UACPI_FORMATTED_LOGGING
void uacpi_kernel_log(uacpi_log_level, const uacpi_char*);
#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);
#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
);
void uacpi_kernel_pci_device_close(uacpi_handle);
/*
* 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_status uacpi_kernel_pci_read16(
uacpi_handle device, uacpi_size offset, uacpi_u16 *value
);
uacpi_status uacpi_kernel_pci_read32(
uacpi_handle device, uacpi_size offset, uacpi_u32 *value
);
uacpi_status uacpi_kernel_pci_write8(
uacpi_handle device, uacpi_size offset, uacpi_u8 value
);
uacpi_status uacpi_kernel_pci_write16(
uacpi_handle device, uacpi_size offset, uacpi_u16 value
);
uacpi_status uacpi_kernel_pci_write32(
uacpi_handle device, uacpi_size offset, uacpi_u32 value
);
/*
* 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 uacpi_kernel_io_unmap(uacpi_handle 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, uacpi_size offset, uacpi_u8 *out_value
);
uacpi_status uacpi_kernel_io_read16(
uacpi_handle, uacpi_size offset, uacpi_u16 *out_value
);
uacpi_status uacpi_kernel_io_read32(
uacpi_handle, uacpi_size offset, uacpi_u32 *out_value
);
uacpi_status uacpi_kernel_io_write8(
uacpi_handle, uacpi_size offset, uacpi_u8 in_value
);
uacpi_status uacpi_kernel_io_write16(
uacpi_handle, uacpi_size offset, uacpi_u16 in_value
);
uacpi_status uacpi_kernel_io_write32(
uacpi_handle, uacpi_size offset, uacpi_u32 in_value
);
/*
* Allocate a block of memory of 'size' bytes.
* The contents of the allocated memory are unspecified.
*/
void *uacpi_kernel_alloc(uacpi_size 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);
#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);
/*
* Spin for N microseconds.
*/
void uacpi_kernel_stall(uacpi_u8 usec);
/*
* Sleep for N milliseconds.
*/
void uacpi_kernel_sleep(uacpi_u64 msec);
/*
* Create/free an opaque non-recursive kernel mutex object.
*/
uacpi_handle uacpi_kernel_create_mutex(void);
void uacpi_kernel_free_mutex(uacpi_handle);
/*
* Create/free an opaque kernel (semaphore-like) event object.
*/
uacpi_handle uacpi_kernel_create_event(void);
void uacpi_kernel_free_event(uacpi_handle);
/*
* 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);
/*
* 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, uacpi_u16);
void uacpi_kernel_release_mutex(uacpi_handle);
/*
* 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);
/*
* 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);
/*
* Reset the event counter to 0.
*/
void uacpi_kernel_reset_event(uacpi_handle);
/*
* Handle a firmware request.
*
* Currently either a Breakpoint or Fatal operators.
*/
uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request*);
/*
* 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, uacpi_handle ctx,
uacpi_handle *out_irq_handle
);
/*
* 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
);
/*
* 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);
void uacpi_kernel_free_spinlock(uacpi_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);
void uacpi_kernel_unlock_spinlock(uacpi_handle, uacpi_cpu_flags);
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, uacpi_work_handler, uacpi_handle ctx
);
/*
* 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);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,40 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef enum uacpi_log_level {
/*
* Super verbose logging, every op & uop being processed is logged.
* Mostly useful for tracking down hangs/lockups.
*/
UACPI_LOG_DEBUG = 5,
/*
* A little verbose, every operation region access is traced with a bit of
* extra information on top.
*/
UACPI_LOG_TRACE = 4,
/*
* Only logs the bare minimum information about state changes and/or
* initialization progress.
*/
UACPI_LOG_INFO = 3,
/*
* Logs recoverable errors and/or non-important aborts.
*/
UACPI_LOG_WARN = 2,
/*
* Logs only critical errors that might affect the ability to initialize or
* prevent stable runtime.
*/
UACPI_LOG_ERROR = 1,
} uacpi_log_level;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,186 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
typedef struct uacpi_namespace_node uacpi_namespace_node;
uacpi_namespace_node *uacpi_namespace_root(void);
typedef enum uacpi_predefined_namespace {
UACPI_PREDEFINED_NAMESPACE_ROOT = 0,
UACPI_PREDEFINED_NAMESPACE_GPE,
UACPI_PREDEFINED_NAMESPACE_PR,
UACPI_PREDEFINED_NAMESPACE_SB,
UACPI_PREDEFINED_NAMESPACE_SI,
UACPI_PREDEFINED_NAMESPACE_TZ,
UACPI_PREDEFINED_NAMESPACE_GL,
UACPI_PREDEFINED_NAMESPACE_OS,
UACPI_PREDEFINED_NAMESPACE_OSI,
UACPI_PREDEFINED_NAMESPACE_REV,
UACPI_PREDEFINED_NAMESPACE_MAX = UACPI_PREDEFINED_NAMESPACE_REV,
} uacpi_predefined_namespace;
uacpi_namespace_node *uacpi_namespace_get_predefined(
uacpi_predefined_namespace
);
/*
* Returns UACPI_TRUE if the provided 'node' is an alias.
*/
uacpi_bool uacpi_namespace_node_is_alias(uacpi_namespace_node *node);
uacpi_object_name uacpi_namespace_node_name(const uacpi_namespace_node *node);
/*
* Returns the type of object stored at the namespace node.
*
* NOTE: due to the existance of the CopyObject operator in AML, the
* return value of this function is subject to TOCTOU bugs.
*/
uacpi_status uacpi_namespace_node_type(
const uacpi_namespace_node *node, uacpi_object_type *out_type
);
/*
* Returns UACPI_TRUE via 'out' if the type of the object stored at the
* namespace node matches the provided value, UACPI_FALSE otherwise.
*
* NOTE: due to the existance of the CopyObject operator in AML, the
* return value of this function is subject to TOCTOU bugs.
*/
uacpi_status uacpi_namespace_node_is(
const uacpi_namespace_node *node, uacpi_object_type type, uacpi_bool *out
);
/*
* Returns UACPI_TRUE via 'out' if the type of the object stored at the
* namespace node matches any of the type bits in the provided value,
* UACPI_FALSE otherwise.
*
* NOTE: due to the existance of the CopyObject operator in AML, the
* return value of this function is subject to TOCTOU bugs.
*/
uacpi_status uacpi_namespace_node_is_one_of(
const uacpi_namespace_node *node, uacpi_object_type_bits type_mask,
uacpi_bool *out
);
uacpi_size uacpi_namespace_node_depth(const uacpi_namespace_node *node);
uacpi_namespace_node *uacpi_namespace_node_parent(
uacpi_namespace_node *node
);
uacpi_status uacpi_namespace_node_find(
uacpi_namespace_node *parent,
const uacpi_char *path,
uacpi_namespace_node **out_node
);
/*
* Same as uacpi_namespace_node_find, except the search recurses upwards when
* the namepath consists of only a single nameseg. Usually, this behavior is
* only desired if resolving a namepath specified in an aml-provided object,
* such as a package element.
*/
uacpi_status uacpi_namespace_node_resolve_from_aml_namepath(
uacpi_namespace_node *scope,
const uacpi_char *path,
uacpi_namespace_node **out_node
);
typedef uacpi_iteration_decision (*uacpi_iteration_callback) (
void *user, uacpi_namespace_node *node, uacpi_u32 node_depth
);
#define UACPI_MAX_DEPTH_ANY 0xFFFFFFFF
/*
* Depth-first iterate the namespace starting at the first child of 'parent'.
*/
uacpi_status uacpi_namespace_for_each_child_simple(
uacpi_namespace_node *parent, uacpi_iteration_callback callback, void *user
);
/*
* Depth-first iterate the namespace starting at the first child of 'parent'.
*
* 'descending_callback' is invoked the first time a node is visited when
* walking down. 'ascending_callback' is invoked the second time a node is
* visited after we reach the leaf node without children and start walking up.
* Either of the callbacks may be NULL, but not both at the same time.
*
* Only nodes matching 'type_mask' are passed to the callbacks.
*
* 'max_depth' is used to limit the maximum reachable depth from 'parent',
* where 1 is only direct children of 'parent', 2 is children of first-level
* children etc. Use UACPI_MAX_DEPTH_ANY or -1 to specify infinite depth.
*/
uacpi_status uacpi_namespace_for_each_child(
uacpi_namespace_node *parent, uacpi_iteration_callback descending_callback,
uacpi_iteration_callback ascending_callback,
uacpi_object_type_bits type_mask, uacpi_u32 max_depth, void *user
);
/*
* Retrieve the next peer namespace node of '*iter', or, if '*iter' is
* UACPI_NULL, retrieve the first child of 'parent' instead. The resulting
* namespace node is stored at '*iter'.
*
* This API can be used to implement an "iterator" version of the
* for_each_child helpers.
*
* Example usage:
* void recurse(uacpi_namespace_node *parent) {
* uacpi_namespace_node *iter = UACPI_NULL;
*
* while (uacpi_namespace_node_next(parent, &iter) == UACPI_STATUS_OK) {
* // Do something with iter...
* descending_callback(iter);
*
* // Recurse down to walk over the children of iter
* recurse(iter);
* }
* }
*
* Prefer the for_each_child family of helpers if possible instead of this API
* as they avoid recursion and/or the need to use dynamic data structures
* entirely.
*/
uacpi_status uacpi_namespace_node_next(
uacpi_namespace_node *parent, uacpi_namespace_node **iter
);
/*
* Retrieve the next peer namespace node of '*iter', or, if '*iter' is
* UACPI_NULL, retrieve the first child of 'parent' instead. The resulting
* namespace node is stored at '*iter'. Only nodes which type matches one
* of the types set in 'type_mask' are returned.
*
* See comment above 'uacpi_namespace_node_next' for usage examples.
*
* Prefer the for_each_child family of helpers if possible instead of this API
* as they avoid recursion and/or the need to use dynamic data structures
* entirely.
*/
uacpi_status uacpi_namespace_node_next_typed(
uacpi_namespace_node *parent, uacpi_namespace_node **iter,
uacpi_object_type_bits type_mask
);
const uacpi_char *uacpi_namespace_node_generate_absolute_path(
const uacpi_namespace_node *node
);
void uacpi_free_absolute_path(const uacpi_char *path);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,30 @@
#pragma once
#include <uacpi/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
/*
* Install a Notify() handler to a device node.
* A handler installed to the root node will receive all notifications, even if
* a device already has a dedicated Notify handler.
* 'handler_context' is passed to the handler on every invocation.
*/
uacpi_status uacpi_install_notify_handler(
uacpi_namespace_node *node, uacpi_notify_handler handler,
uacpi_handle handler_context
);
uacpi_status uacpi_uninstall_notify_handler(
uacpi_namespace_node *node, uacpi_notify_handler handler
);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,47 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
/*
* Install an address space handler to a device node.
* The handler is recursively connected to all of the operation regions of
* type 'space' underneath 'device_node'. Note that this recursion stops as
* soon as another device node that already has an address space handler of
* this type installed is encountered.
*/
uacpi_status uacpi_install_address_space_handler(
uacpi_namespace_node *device_node, enum uacpi_address_space space,
uacpi_region_handler handler, uacpi_handle handler_context
);
/*
* Uninstall the handler of type 'space' from a given device node.
*/
uacpi_status uacpi_uninstall_address_space_handler(
uacpi_namespace_node *device_node,
enum uacpi_address_space space
);
/*
* Execute _REG(space, ACPI_REG_CONNECT) for all of the opregions with this
* address space underneath this device. This should only be called manually
* if you want to register an early handler that must be available before the
* call to uacpi_namespace_initialize().
*/
uacpi_status uacpi_reg_all_opregions(
uacpi_namespace_node *device_node,
enum uacpi_address_space space
);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,125 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
typedef enum uacpi_vendor_interface {
UACPI_VENDOR_INTERFACE_NONE = 0,
UACPI_VENDOR_INTERFACE_WINDOWS_2000,
UACPI_VENDOR_INTERFACE_WINDOWS_XP,
UACPI_VENDOR_INTERFACE_WINDOWS_XP_SP1,
UACPI_VENDOR_INTERFACE_WINDOWS_SERVER_2003,
UACPI_VENDOR_INTERFACE_WINDOWS_XP_SP2,
UACPI_VENDOR_INTERFACE_WINDOWS_SERVER_2003_SP1,
UACPI_VENDOR_INTERFACE_WINDOWS_VISTA,
UACPI_VENDOR_INTERFACE_WINDOWS_SERVER_2008,
UACPI_VENDOR_INTERFACE_WINDOWS_VISTA_SP1,
UACPI_VENDOR_INTERFACE_WINDOWS_VISTA_SP2,
UACPI_VENDOR_INTERFACE_WINDOWS_7,
UACPI_VENDOR_INTERFACE_WINDOWS_8,
UACPI_VENDOR_INTERFACE_WINDOWS_8_1,
UACPI_VENDOR_INTERFACE_WINDOWS_10,
UACPI_VENDOR_INTERFACE_WINDOWS_10_RS1,
UACPI_VENDOR_INTERFACE_WINDOWS_10_RS2,
UACPI_VENDOR_INTERFACE_WINDOWS_10_RS3,
UACPI_VENDOR_INTERFACE_WINDOWS_10_RS4,
UACPI_VENDOR_INTERFACE_WINDOWS_10_RS5,
UACPI_VENDOR_INTERFACE_WINDOWS_10_19H1,
UACPI_VENDOR_INTERFACE_WINDOWS_10_20H1,
UACPI_VENDOR_INTERFACE_WINDOWS_11,
UACPI_VENDOR_INTERFACE_WINDOWS_11_22H2,
} uacpi_vendor_interface;
/*
* Returns the "latest" AML-queried _OSI vendor interface.
*
* E.g. for the following AML code:
* _OSI("Windows 2021")
* _OSI("Windows 2000")
*
* This function will return UACPI_VENDOR_INTERFACE_WINDOWS_11, since this is
* the latest version of the interface the code queried, even though the
* "Windows 2000" query came after "Windows 2021".
*/
uacpi_vendor_interface uacpi_latest_queried_vendor_interface(void);
typedef enum uacpi_interface_kind {
UACPI_INTERFACE_KIND_VENDOR = (1 << 0),
UACPI_INTERFACE_KIND_FEATURE = (1 << 1),
UACPI_INTERFACE_KIND_ALL = UACPI_INTERFACE_KIND_VENDOR |
UACPI_INTERFACE_KIND_FEATURE,
} uacpi_interface_kind;
/*
* Install or uninstall an interface.
*
* The interface kind is used for matching during interface enumeration in
* uacpi_bulk_configure_interfaces().
*
* After installing an interface, all _OSI queries report it as supported.
*/
uacpi_status uacpi_install_interface(
const uacpi_char *name, uacpi_interface_kind
);
uacpi_status uacpi_uninstall_interface(const uacpi_char *name);
typedef enum uacpi_host_interface {
UACPI_HOST_INTERFACE_MODULE_DEVICE = 1,
UACPI_HOST_INTERFACE_PROCESSOR_DEVICE,
UACPI_HOST_INTERFACE_3_0_THERMAL_MODEL,
UACPI_HOST_INTERFACE_3_0_SCP_EXTENSIONS,
UACPI_HOST_INTERFACE_PROCESSOR_AGGREGATOR_DEVICE,
} uacpi_host_interface;
/*
* Same as install/uninstall interface, but comes with an enum of known
* interfaces defined by the ACPI specification. These are disabled by default
* as they depend on the host kernel support.
*/
uacpi_status uacpi_enable_host_interface(uacpi_host_interface);
uacpi_status uacpi_disable_host_interface(uacpi_host_interface);
typedef uacpi_bool (*uacpi_interface_handler)
(const uacpi_char *name, uacpi_bool supported);
/*
* Set a custom interface query (_OSI) handler.
*
* This callback will be invoked for each _OSI query with the value
* passed in the _OSI, as well as whether the interface was detected as
* supported. The callback is able to override the return value dynamically
* or leave it untouched if desired (e.g. if it simply wants to log something or
* do internal bookkeeping of some kind).
*/
uacpi_status uacpi_set_interface_query_handler(uacpi_interface_handler);
typedef enum uacpi_interface_action {
UACPI_INTERFACE_ACTION_DISABLE = 0,
UACPI_INTERFACE_ACTION_ENABLE,
} uacpi_interface_action;
/*
* Bulk interface configuration, used to disable or enable all interfaces that
* match 'kind'.
*
* This is generally only needed to work around buggy hardware, for example if
* requested from the kernel command line.
*
* By default, all vendor strings (like "Windows 2000") are enabled, and all
* host features (like "3.0 Thermal Model") are disabled.
*/
uacpi_status uacpi_bulk_configure_interfaces(
uacpi_interface_action action, uacpi_interface_kind kind
);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,38 @@
#pragma once
#ifdef UACPI_OVERRIDE_ARCH_HELPERS
#include "uacpi_arch_helpers.h"
#else
#include <uacpi/platform/atomic.h>
#ifndef UACPI_ARCH_FLUSH_CPU_CACHE
#define UACPI_ARCH_FLUSH_CPU_CACHE() do {} while (0)
#endif
typedef unsigned long uacpi_cpu_flags;
typedef void *uacpi_thread_id;
/*
* Replace as needed depending on your platform's way to represent thread ids.
* uACPI offers a few more helpers like uacpi_atomic_{load,store}{8,16,32,64,ptr}
* (or you could provide your own helpers)
*/
#ifndef UACPI_ATOMIC_LOAD_THREAD_ID
#define UACPI_ATOMIC_LOAD_THREAD_ID(ptr) ((uacpi_thread_id)uacpi_atomic_load_ptr(ptr))
#endif
#ifndef UACPI_ATOMIC_STORE_THREAD_ID
#define UACPI_ATOMIC_STORE_THREAD_ID(ptr, value) uacpi_atomic_store_ptr(ptr, value)
#endif
/*
* A sentinel value that the kernel promises to NEVER return from
* uacpi_kernel_get_current_thread_id or this will break
*/
#ifndef UACPI_THREAD_ID_NONE
#define UACPI_THREAD_ID_NONE ((uacpi_thread_id)-1)
#endif
#endif

View File

@ -0,0 +1,347 @@
#pragma once
/*
* Most of this header is a giant workaround for MSVC to make atomics into a
* somewhat unified interface with how GCC and Clang handle them.
*
* We don't use the absolutely disgusting C11 stdatomic.h header because it is
* unable to operate on non _Atomic types, which enforce implicit sequential
* consistency and alter the behavior of the standard C binary/unary operators.
*
* The strictness of the atomic helpers defined here is assumed to be at least
* acquire for loads and release for stores. Cmpxchg uses the standard acq/rel
* for success, acq for failure, and is assumed to be strong.
*/
#ifdef UACPI_OVERRIDE_ATOMIC
#include "uacpi_atomic.h"
#else
#include <uacpi/platform/compiler.h>
#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>
// mimic __atomic_compare_exchange_n that doesn't exist on MSVC
#define UACPI_MAKE_MSVC_CMPXCHG(width, type, suffix) \
static inline int uacpi_do_atomic_cmpxchg##width( \
type volatile *ptr, type volatile *expected, type desired \
) \
{ \
type current; \
\
current = _InterlockedCompareExchange##suffix(ptr, *expected, desired); \
if (current != *expected) { \
*expected = current; \
return 0; \
} \
return 1; \
}
#define UACPI_MSVC_CMPXCHG_INVOKE(ptr, expected, desired, width, type) \
uacpi_do_atomic_cmpxchg##width( \
(type volatile*)ptr, (type volatile*)expected, desired \
)
#define UACPI_MSVC_ATOMIC_STORE(ptr, value, type, width) \
_InterlockedExchange##width((type volatile*)(ptr), (type)(value))
#define UACPI_MSVC_ATOMIC_LOAD(ptr, type, width) \
_InterlockedOr##width((type volatile*)(ptr), 0)
#define UACPI_MSVC_ATOMIC_INC(ptr, type, width) \
_InterlockedIncrement##width((type volatile*)(ptr))
#define UACPI_MSVC_ATOMIC_DEC(ptr, type, width) \
_InterlockedDecrement##width((type volatile*)(ptr))
UACPI_MAKE_MSVC_CMPXCHG(64, __int64, 64)
UACPI_MAKE_MSVC_CMPXCHG(32, long,)
UACPI_MAKE_MSVC_CMPXCHG(16, short, 16)
#define uacpi_atomic_cmpxchg16(ptr, expected, desired) \
UACPI_MSVC_CMPXCHG_INVOKE(ptr, expected, desired, 16, short)
#define uacpi_atomic_cmpxchg32(ptr, expected, desired) \
UACPI_MSVC_CMPXCHG_INVOKE(ptr, expected, desired, 32, long)
#define uacpi_atomic_cmpxchg64(ptr, expected, desired) \
UACPI_MSVC_CMPXCHG_INVOKE(ptr, expected, desired, 64, __int64)
#define uacpi_atomic_load8(ptr) UACPI_MSVC_ATOMIC_LOAD(ptr, char, 8)
#define uacpi_atomic_load16(ptr) UACPI_MSVC_ATOMIC_LOAD(ptr, short, 16)
#define uacpi_atomic_load32(ptr) UACPI_MSVC_ATOMIC_LOAD(ptr, long,)
#define uacpi_atomic_load64(ptr) UACPI_MSVC_ATOMIC_LOAD(ptr, __int64, 64)
#define uacpi_atomic_store8(ptr, value) UACPI_MSVC_ATOMIC_STORE(ptr, value, char, 8)
#define uacpi_atomic_store16(ptr, value) UACPI_MSVC_ATOMIC_STORE(ptr, value, short, 16)
#define uacpi_atomic_store32(ptr, value) UACPI_MSVC_ATOMIC_STORE(ptr, value, long,)
#define uacpi_atomic_store64(ptr, value) UACPI_MSVC_ATOMIC_STORE(ptr, value, __int64, 64)
#define uacpi_atomic_inc16(ptr) UACPI_MSVC_ATOMIC_INC(ptr, short, 16)
#define uacpi_atomic_inc32(ptr) UACPI_MSVC_ATOMIC_INC(ptr, long,)
#define uacpi_atomic_inc64(ptr) UACPI_MSVC_ATOMIC_INC(ptr, __int64, 64)
#define uacpi_atomic_dec16(ptr) UACPI_MSVC_ATOMIC_DEC(ptr, short, 16)
#define uacpi_atomic_dec32(ptr) UACPI_MSVC_ATOMIC_DEC(ptr, long,)
#define uacpi_atomic_dec64(ptr) UACPI_MSVC_ATOMIC_DEC(ptr, __int64, 64)
#elif defined(__WATCOMC__)
#include <stdint.h>
static int uacpi_do_atomic_cmpxchg16(volatile uint16_t *ptr, volatile uint16_t *expected, uint16_t desired);
#pragma aux uacpi_do_atomic_cmpxchg16 = \
".486" \
"mov ax, [esi]" \
"lock cmpxchg [edi], bx" \
"mov [esi], ax" \
"setz al" \
"movzx eax, al" \
parm [ edi ] [ esi ] [ ebx ] \
value [ eax ]
static int uacpi_do_atomic_cmpxchg32(volatile uint32_t *ptr, volatile uint32_t *expected, uint32_t desired);
#pragma aux uacpi_do_atomic_cmpxchg32 = \
".486" \
"mov eax, [esi]" \
"lock cmpxchg [edi], ebx" \
"mov [esi], eax" \
"setz al" \
"movzx eax, al" \
parm [ edi ] [ esi ] [ ebx ] \
value [ eax ]
static int uacpi_do_atomic_cmpxchg64_asm(volatile uint64_t *ptr, volatile uint64_t *expected, uint32_t low, uint32_t high);
#pragma aux uacpi_do_atomic_cmpxchg64_asm = \
".586" \
"mov eax, [esi]" \
"mov edx, [esi + 4]" \
"lock cmpxchg8b [edi]" \
"mov [esi], eax" \
"mov [esi + 4], edx" \
"setz al" \
"movzx eax, al" \
modify [ edx ] \
parm [ edi ] [ esi ] [ ebx ] [ ecx ] \
value [ eax ]
static inline int uacpi_do_atomic_cmpxchg64(volatile uint64_t *ptr, volatile uint64_t *expected, uint64_t desired) {
return uacpi_do_atomic_cmpxchg64_asm(ptr, expected, desired, desired >> 32);
}
#define uacpi_atomic_cmpxchg16(ptr, expected, desired) \
uacpi_do_atomic_cmpxchg16((volatile uint16_t*)ptr, (volatile uint16_t*)expected, (uint16_t)desired)
#define uacpi_atomic_cmpxchg32(ptr, expected, desired) \
uacpi_do_atomic_cmpxchg32((volatile uint32_t*)ptr, (volatile uint32_t*)expected, (uint32_t)desired)
#define uacpi_atomic_cmpxchg64(ptr, expected, desired) \
uacpi_do_atomic_cmpxchg64((volatile uint64_t*)ptr, (volatile uint64_t*)expected, (uint64_t)desired)
static uint8_t uacpi_do_atomic_load8(volatile uint8_t *ptr);
#pragma aux uacpi_do_atomic_load8 = \
"mov al, [esi]" \
parm [ esi ] \
value [ al ]
static uint16_t uacpi_do_atomic_load16(volatile uint16_t *ptr);
#pragma aux uacpi_do_atomic_load16 = \
"mov ax, [esi]" \
parm [ esi ] \
value [ ax ]
static uint32_t uacpi_do_atomic_load32(volatile uint32_t *ptr);
#pragma aux uacpi_do_atomic_load32 = \
"mov eax, [esi]" \
parm [ esi ] \
value [ eax ]
static void uacpi_do_atomic_load64_asm(volatile uint64_t *ptr, uint64_t *out);
#pragma aux uacpi_do_atomic_load64_asm = \
".586" \
"xor eax, eax" \
"xor ebx, ebx" \
"xor ecx, ecx" \
"xor edx, edx" \
"lock cmpxchg8b [esi]" \
"mov [edi], eax" \
"mov [edi + 4], edx" \
modify [ eax ebx ecx edx ] \
parm [ esi ] [ edi ]
static inline uint64_t uacpi_do_atomic_load64(volatile uint64_t *ptr) {
uint64_t value;
uacpi_do_atomic_load64_asm(ptr, &value);
return value;
}
#define uacpi_atomic_load8(ptr) uacpi_do_atomic_load8((volatile uint8_t*)ptr)
#define uacpi_atomic_load16(ptr) uacpi_do_atomic_load16((volatile uint16_t*)ptr)
#define uacpi_atomic_load32(ptr) uacpi_do_atomic_load32((volatile uint32_t*)ptr)
#define uacpi_atomic_load64(ptr) uacpi_do_atomic_load64((volatile uint64_t*)ptr)
static void uacpi_do_atomic_store8(volatile uint8_t *ptr, uint8_t value);
#pragma aux uacpi_do_atomic_store8 = \
"mov [edi], al" \
parm [ edi ] [ eax ]
static void uacpi_do_atomic_store16(volatile uint16_t *ptr, uint16_t value);
#pragma aux uacpi_do_atomic_store16 = \
"mov [edi], ax" \
parm [ edi ] [ eax ]
static void uacpi_do_atomic_store32(volatile uint32_t *ptr, uint32_t value);
#pragma aux uacpi_do_atomic_store32 = \
"mov [edi], eax" \
parm [ edi ] [ eax ]
static void uacpi_do_atomic_store64_asm(volatile uint64_t *ptr, uint32_t low, uint32_t high);
#pragma aux uacpi_do_atomic_store64_asm = \
".586" \
"xor eax, eax" \
"xor edx, edx" \
"retry: lock cmpxchg8b [edi]" \
"jnz retry" \
modify [ eax edx ] \
parm [ edi ] [ ebx ] [ ecx ]
static inline void uacpi_do_atomic_store64(volatile uint64_t *ptr, uint64_t value) {
uacpi_do_atomic_store64_asm(ptr, value, value >> 32);
}
#define uacpi_atomic_store8(ptr, value) uacpi_do_atomic_store8((volatile uint8_t*)ptr, (uint8_t)value)
#define uacpi_atomic_store16(ptr, value) uacpi_do_atomic_store16((volatile uint16_t*)ptr, (uint16_t)value)
#define uacpi_atomic_store32(ptr, value) uacpi_do_atomic_store32((volatile uint32_t*)ptr, (uint32_t)value)
#define uacpi_atomic_store64(ptr, value) uacpi_do_atomic_store64((volatile uint64_t*)ptr, (uint64_t)value)
static uint16_t uacpi_do_atomic_inc16(volatile uint16_t *ptr);
#pragma aux uacpi_do_atomic_inc16 = \
".486" \
"mov ax, 1" \
"lock xadd [edi], ax" \
"add ax, 1" \
parm [ edi ] \
value [ ax ]
static uint32_t uacpi_do_atomic_inc32(volatile uint32_t *ptr);
#pragma aux uacpi_do_atomic_inc32 = \
".486" \
"mov eax, 1" \
"lock xadd [edi], eax" \
"add eax, 1" \
parm [ edi ] \
value [ eax ]
static void uacpi_do_atomic_inc64_asm(volatile uint64_t *ptr, uint64_t *out);
#pragma aux uacpi_do_atomic_inc64_asm = \
".586" \
"xor eax, eax" \
"xor edx, edx" \
"mov ebx, 1" \
"mov ecx, 1" \
"retry: lock cmpxchg8b [esi]" \
"mov ebx, eax" \
"mov ecx, edx" \
"add ebx, 1" \
"adc ecx, 0" \
"jnz retry" \
"mov [edi], ebx" \
"mov [edi + 4], ecx" \
modify [ eax ebx ecx edx ] \
parm [ esi ] [ edi ]
static inline uint64_t uacpi_do_atomic_inc64(volatile uint64_t *ptr) {
uint64_t value;
uacpi_do_atomic_inc64_asm(ptr, &value);
return value;
}
#define uacpi_atomic_inc16(ptr) uacpi_do_atomic_inc16((volatile uint16_t*)ptr)
#define uacpi_atomic_inc32(ptr) uacpi_do_atomic_inc32((volatile uint32_t*)ptr)
#define uacpi_atomic_inc64(ptr) uacpi_do_atomic_inc64((volatile uint64_t*)ptr)
static uint16_t uacpi_do_atomic_dec16(volatile uint16_t *ptr);
#pragma aux uacpi_do_atomic_dec16 = \
".486" \
"mov ax, -1" \
"lock xadd [edi], ax" \
"add ax, -1" \
parm [ edi ] \
value [ ax ]
static uint32_t uacpi_do_atomic_dec32(volatile uint32_t *ptr);
#pragma aux uacpi_do_atomic_dec32 = \
".486" \
"mov eax, -1" \
"lock xadd [edi], eax" \
"add eax, -1" \
parm [ edi ] \
value [ eax ]
static void uacpi_do_atomic_dec64_asm(volatile uint64_t *ptr, uint64_t *out);
#pragma aux uacpi_do_atomic_dec64_asm = \
".586" \
"xor eax, eax" \
"xor edx, edx" \
"mov ebx, -1" \
"mov ecx, -1" \
"retry: lock cmpxchg8b [esi]" \
"mov ebx, eax" \
"mov ecx, edx" \
"sub ebx, 1" \
"sbb ecx, 0" \
"jnz retry" \
"mov [edi], ebx" \
"mov [edi + 4], ecx" \
modify [ eax ebx ecx edx ] \
parm [ esi ] [ edi ]
static inline uint64_t uacpi_do_atomic_dec64(volatile uint64_t *ptr) {
uint64_t value;
uacpi_do_atomic_dec64_asm(ptr, &value);
return value;
}
#define uacpi_atomic_dec16(ptr) uacpi_do_atomic_dec16((volatile uint16_t*)ptr)
#define uacpi_atomic_dec32(ptr) uacpi_do_atomic_dec32((volatile uint32_t*)ptr)
#define uacpi_atomic_dec64(ptr) uacpi_do_atomic_dec64((volatile uint64_t*)ptr)
#else
#define UACPI_DO_CMPXCHG(ptr, expected, desired) \
__atomic_compare_exchange_n(ptr, expected, desired, 0, \
__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)
#define uacpi_atomic_cmpxchg16(ptr, expected, desired) \
UACPI_DO_CMPXCHG(ptr, expected, desired)
#define uacpi_atomic_cmpxchg32(ptr, expected, desired) \
UACPI_DO_CMPXCHG(ptr, expected, desired)
#define uacpi_atomic_cmpxchg64(ptr, expected, desired) \
UACPI_DO_CMPXCHG(ptr, expected, desired)
#define uacpi_atomic_load8(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define uacpi_atomic_load16(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define uacpi_atomic_load32(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define uacpi_atomic_load64(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define uacpi_atomic_store8(ptr, value) __atomic_store_n(ptr, value, __ATOMIC_RELEASE)
#define uacpi_atomic_store16(ptr, value) __atomic_store_n(ptr, value, __ATOMIC_RELEASE)
#define uacpi_atomic_store32(ptr, value) __atomic_store_n(ptr, value, __ATOMIC_RELEASE)
#define uacpi_atomic_store64(ptr, value) __atomic_store_n(ptr, value, __ATOMIC_RELEASE)
#define uacpi_atomic_inc16(ptr) __atomic_add_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#define uacpi_atomic_inc32(ptr) __atomic_add_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#define uacpi_atomic_inc64(ptr) __atomic_add_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#define uacpi_atomic_dec16(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#define uacpi_atomic_dec32(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#define uacpi_atomic_dec64(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_ACQ_REL)
#endif
#if UACPI_POINTER_SIZE == 4
#define uacpi_atomic_load_ptr(ptr_to_ptr) uacpi_atomic_load32(ptr_to_ptr)
#define uacpi_atomic_store_ptr(ptr_to_ptr, value) uacpi_atomic_store32(ptr_to_ptr, value)
#else
#define uacpi_atomic_load_ptr(ptr_to_ptr) uacpi_atomic_load64(ptr_to_ptr)
#define uacpi_atomic_store_ptr(ptr_to_ptr, value) uacpi_atomic_store64(ptr_to_ptr, value)
#endif
#endif

View File

@ -0,0 +1,125 @@
#pragma once
/*
* Compiler-specific attributes/macros go here. This is the default placeholder
* that should work for MSVC/GCC/clang.
*/
#ifdef UACPI_OVERRIDE_COMPILER
#include "uacpi_compiler.h"
#else
#define UACPI_ALIGN(x) __declspec(align(x))
#if defined(__WATCOMC__)
#define UACPI_STATIC_ASSERT(expr, msg)
#elif defined(__cplusplus)
#define UACPI_STATIC_ASSERT static_assert
#else
#define UACPI_STATIC_ASSERT _Static_assert
#endif
#ifdef _MSC_VER
#include <intrin.h>
#define UACPI_ALWAYS_INLINE __forceinline
#define UACPI_PACKED(decl) \
__pragma(pack(push, 1)) \
decl; \
__pragma(pack(pop))
#elif defined(__WATCOMC__)
#define UACPI_ALWAYS_INLINE inline
#define UACPI_PACKED(decl) _Packed decl;
#else
#define UACPI_ALWAYS_INLINE inline __attribute__((always_inline))
#define UACPI_PACKED(decl) decl __attribute__((packed));
#endif
#if defined(__GNUC__) || defined(__clang__)
#define uacpi_unlikely(expr) __builtin_expect(!!(expr), 0)
#define uacpi_likely(expr) __builtin_expect(!!(expr), 1)
#ifdef __has_attribute
#if __has_attribute(__fallthrough__)
#define UACPI_FALLTHROUGH __attribute__((__fallthrough__))
#endif
#endif
#define UACPI_MAYBE_UNUSED __attribute__ ((unused))
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_BEGIN \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_END \
_Pragma("GCC diagnostic pop")
#ifdef __clang__
#define UACPI_PRINTF_DECL(fmt_idx, args_idx) \
__attribute__((format(printf, fmt_idx, args_idx)))
#else
#define UACPI_PRINTF_DECL(fmt_idx, args_idx) \
__attribute__((format(gnu_printf, fmt_idx, args_idx)))
#endif
#define UACPI_COMPILER_HAS_BUILTIN_MEMCPY
#define UACPI_COMPILER_HAS_BUILTIN_MEMMOVE
#define UACPI_COMPILER_HAS_BUILTIN_MEMSET
#define UACPI_COMPILER_HAS_BUILTIN_MEMCMP
#elif defined(__WATCOMC__)
#define uacpi_unlikely(expr) expr
#define uacpi_likely(expr) expr
/*
* The OpenWatcom documentation suggests this should be done using
* _Pragma("off (unreferenced)") and _Pragma("pop (unreferenced)"),
* but these pragmas appear to be no-ops. Use inline as the next best thing.
* Note that OpenWatcom accepts redundant modifiers without a warning,
* so UACPI_MAYBE_UNUSED inline still works.
*/
#define UACPI_MAYBE_UNUSED inline
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_BEGIN
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_END
#define UACPI_PRINTF_DECL(fmt_idx, args_idx)
#else
#define uacpi_unlikely(expr) expr
#define uacpi_likely(expr) expr
#define UACPI_MAYBE_UNUSED
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_BEGIN
#define UACPI_NO_UNUSED_PARAMETER_WARNINGS_END
#define UACPI_PRINTF_DECL(fmt_idx, args_idx)
#endif
#ifndef UACPI_FALLTHROUGH
#define UACPI_FALLTHROUGH do {} while (0)
#endif
#ifndef UACPI_POINTER_SIZE
#ifdef _WIN32
#ifdef _WIN64
#define UACPI_POINTER_SIZE 8
#else
#define UACPI_POINTER_SIZE 4
#endif
#elif defined(__GNUC__)
#define UACPI_POINTER_SIZE __SIZEOF_POINTER__
#elif defined(__WATCOMC__)
#ifdef __386__
#define UACPI_POINTER_SIZE 4
#elif defined(__I86__)
#error uACPI does not support 16-bit mode compilation
#else
#error Unknown target architecture
#endif
#else
#error Failed to detect pointer size
#endif
#endif
#endif

View File

@ -0,0 +1,162 @@
#pragma once
#ifdef UACPI_OVERRIDE_CONFIG
#include "uacpi_config.h"
#else
#include <uacpi/helpers.h>
#include <uacpi/log.h>
/*
* =======================
* Context-related options
* =======================
*/
#ifndef UACPI_DEFAULT_LOG_LEVEL
#define UACPI_DEFAULT_LOG_LEVEL UACPI_LOG_INFO
#endif
UACPI_BUILD_BUG_ON_WITH_MSG(
UACPI_DEFAULT_LOG_LEVEL < UACPI_LOG_ERROR ||
UACPI_DEFAULT_LOG_LEVEL > UACPI_LOG_DEBUG,
"configured default log level is invalid"
);
#ifndef UACPI_DEFAULT_LOOP_TIMEOUT_SECONDS
#define UACPI_DEFAULT_LOOP_TIMEOUT_SECONDS 30
#endif
UACPI_BUILD_BUG_ON_WITH_MSG(
UACPI_DEFAULT_LOOP_TIMEOUT_SECONDS < 1,
"configured default loop timeout is invalid (expecting at least 1 second)"
);
#ifndef UACPI_DEFAULT_MAX_CALL_STACK_DEPTH
#define UACPI_DEFAULT_MAX_CALL_STACK_DEPTH 256
#endif
UACPI_BUILD_BUG_ON_WITH_MSG(
UACPI_DEFAULT_MAX_CALL_STACK_DEPTH < 4,
"configured default max call stack depth is invalid "
"(expecting at least 4 frames)"
);
/*
* ===================
* Kernel-api options
* ===================
*/
/*
* Convenience initialization/deinitialization hooks that will be called by
* uACPI automatically when appropriate if compiled-in.
*/
// #define UACPI_KERNEL_INITIALIZATION
/*
* Makes kernel api logging callbacks work with unformatted printf-style
* strings and va_args instead of a pre-formatted string. Can be useful if
* your native logging is implemented in terms of this format as well.
*/
// #define UACPI_FORMATTED_LOGGING
/*
* Makes uacpi_kernel_free take in an additional 'size_hint' parameter, which
* contains the size of the original allocation. Note that this comes with a
* performance penalty in some cases.
*/
// #define UACPI_SIZED_FREES
/*
* Makes uacpi_kernel_alloc_zeroed mandatory to implement by the host, uACPI
* will not provide a default implementation if this is enabled.
*/
// #define UACPI_NATIVE_ALLOC_ZEROED
/*
* =========================
* Platform-specific options
* =========================
*/
/*
* Makes uACPI use the internal versions of mem{cpy,move,set,cmp} instead of
* relying on the host to provide them. Note that compilers like clang and GCC
* rely on these being available by default, even in freestanding mode, so
* compiling uACPI may theoretically generate implicit dependencies on them
* even if this option is defined.
*/
// #define UACPI_USE_BUILTIN_STRING
/*
* Turns uacpi_phys_addr and uacpi_io_addr into a 32-bit type, and adds extra
* code for address truncation. Needed for e.g. i686 platforms without PAE
* support.
*/
// #define UACPI_PHYS_ADDR_IS_32BITS
/*
* Switches uACPI into reduced-hardware-only mode. Strips all full-hardware
* ACPI support code at compile-time, including the event subsystem, the global
* lock, and other full-hardware features.
*/
// #define UACPI_REDUCED_HARDWARE
/*
* Switches uACPI into tables-subsystem-only mode and strips all other code.
* This means only the table API will be usable, no other subsystems are
* compiled in. In this mode, uACPI only depends on the following kernel APIs:
* - uacpi_kernel_get_rsdp
* - uacpi_kernel_{map,unmap}
* - uacpi_kernel_log
*
* Use uacpi_setup_early_table_access to initialize, uacpi_state_reset to
* deinitialize.
*
* This mode is primarily designed for these three use-cases:
* - Bootloader/pre-kernel environments that need to parse ACPI tables, but
* don't actually need a fully-featured AML interpreter, and everything else
* that a full APCI implementation entails.
* - A micro-kernel that has the full AML interpreter running in userspace, but
* still needs to parse ACPI tables to bootstrap allocators, timers, SMP etc.
* - A WIP kernel that needs to parse ACPI tables for bootrapping SMP/timers,
* ECAM, etc., but doesn't yet have enough subsystems implemented in order
* to run a fully-featured AML interpreter.
*/
// #define UACPI_BAREBONES_MODE
/*
* =============
* Misc. options
* =============
*/
/*
* If UACPI_FORMATTED_LOGGING is not enabled, this is the maximum length of the
* pre-formatted message that is passed to the logging callback.
*/
#ifndef UACPI_PLAIN_LOG_BUFFER_SIZE
#define UACPI_PLAIN_LOG_BUFFER_SIZE 128
#endif
UACPI_BUILD_BUG_ON_WITH_MSG(
UACPI_PLAIN_LOG_BUFFER_SIZE < 16,
"configured log buffer size is too small (expecting at least 16 bytes)"
);
/*
* The size of the table descriptor inline storage. All table descriptors past
* this length will be stored in a dynamically allocated heap array. The size
* of one table descriptor is approximately 56 bytes.
*/
#ifndef UACPI_STATIC_TABLE_ARRAY_LEN
#define UACPI_STATIC_TABLE_ARRAY_LEN 16
#endif
UACPI_BUILD_BUG_ON_WITH_MSG(
UACPI_STATIC_TABLE_ARRAY_LEN < 1,
"configured static table array length is too small (expecting at least 1)"
);
#endif

View File

@ -0,0 +1,28 @@
#pragma once
#ifdef UACPI_OVERRIDE_LIBC
#include "uacpi_libc.h"
#else
/*
* The following libc functions are used internally by uACPI and have a default
* (sub-optimal) implementation:
* - strcmp
* - strnlen
* - strlen
* - snprintf
* - vsnprintf
*
* The following use a builtin implementation only if UACPI_USE_BUILTIN_STRING
* is defined (more information can be found in the config.h header):
* - memcpy
* - memmove
* - memset
* - memcmp
*
* In case your platform happens to implement optimized verisons of the helpers
* above, you are able to make uACPI use those instead by overriding them like so:
*
* #define uacpi_memcpy my_fast_memcpy
* #define uacpi_snprintf my_fast_snprintf
*/
#endif

View File

@ -0,0 +1,64 @@
#pragma once
/*
* Platform-specific types go here. This is the default placeholder using
* types from the standard headers.
*/
#ifdef UACPI_OVERRIDE_TYPES
#include "uacpi_types.h"
#else
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#include <uacpi/helpers.h>
typedef uint8_t uacpi_u8;
typedef uint16_t uacpi_u16;
typedef uint32_t uacpi_u32;
typedef uint64_t uacpi_u64;
typedef int8_t uacpi_i8;
typedef int16_t uacpi_i16;
typedef int32_t uacpi_i32;
typedef int64_t uacpi_i64;
#define UACPI_TRUE true
#define UACPI_FALSE false
typedef bool uacpi_bool;
#define UACPI_NULL NULL
typedef uintptr_t uacpi_uintptr;
typedef uacpi_uintptr uacpi_virt_addr;
typedef size_t uacpi_size;
typedef va_list uacpi_va_list;
#define uacpi_va_start va_start
#define uacpi_va_end va_end
#define uacpi_va_arg va_arg
typedef char uacpi_char;
#define uacpi_offsetof offsetof
/*
* We use unsignd long long for 64-bit number formatting because 64-bit types
* don't have a standard way to format them. The inttypes.h header is not
* freestanding therefore it's not practical to force the user to define the
* corresponding PRI macros. Moreover, unsignd long long is required to be
* at least 64-bits as per C99.
*/
UACPI_BUILD_BUG_ON_WITH_MSG(
sizeof(unsigned long long) < 8,
"unsigned long long must be at least 64 bits large as per C99"
);
#define UACPI_PRIu64 "llu"
#define UACPI_PRIx64 "llx"
#define UACPI_PRIX64 "llX"
#define UACPI_FMT64(val) ((unsigned long long)(val))
#endif

View File

@ -0,0 +1,105 @@
#include <uacpi/types.h>
/*
* BEFORE YOU USE THIS API:
* uACPI manages FADT registers on its own entirely, you should only use this
* API directly if there's absolutely no other way for your use case, e.g.
* implementing a CPU idle state driver that does C state switching or similar.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
typedef enum uacpi_register {
UACPI_REGISTER_PM1_STS = 0,
UACPI_REGISTER_PM1_EN,
UACPI_REGISTER_PM1_CNT,
UACPI_REGISTER_PM_TMR,
UACPI_REGISTER_PM2_CNT,
UACPI_REGISTER_SLP_CNT,
UACPI_REGISTER_SLP_STS,
UACPI_REGISTER_RESET,
UACPI_REGISTER_SMI_CMD,
UACPI_REGISTER_MAX = UACPI_REGISTER_SMI_CMD,
} uacpi_register;
/*
* Read a register from FADT
*
* NOTE: write-only bits (if any) are cleared automatically
*/
uacpi_status uacpi_read_register(uacpi_register, uacpi_u64*);
/*
* Write a register from FADT
*
* NOTE:
* - Preserved bits (if any) are preserved automatically
* - If a register is made up of two (e.g. PM1a and PM1b) parts, the input
* is written to both at the same time
*/
uacpi_status uacpi_write_register(uacpi_register, uacpi_u64);
/*
* Write a register from FADT
*
* NOTE:
* - Preserved bits (if any) are preserved automatically
* - For registers that are made up of two (e.g. PM1a and PM1b) parts, the
* provided values are written to their respective physical register
*/
uacpi_status uacpi_write_registers(uacpi_register, uacpi_u64, uacpi_u64);
typedef enum uacpi_register_field {
UACPI_REGISTER_FIELD_TMR_STS = 0,
UACPI_REGISTER_FIELD_BM_STS,
UACPI_REGISTER_FIELD_GBL_STS,
UACPI_REGISTER_FIELD_PWRBTN_STS,
UACPI_REGISTER_FIELD_SLPBTN_STS,
UACPI_REGISTER_FIELD_RTC_STS,
UACPI_REGISTER_FIELD_PCIEX_WAKE_STS,
UACPI_REGISTER_FIELD_HWR_WAK_STS,
UACPI_REGISTER_FIELD_WAK_STS,
UACPI_REGISTER_FIELD_TMR_EN,
UACPI_REGISTER_FIELD_GBL_EN,
UACPI_REGISTER_FIELD_PWRBTN_EN,
UACPI_REGISTER_FIELD_SLPBTN_EN,
UACPI_REGISTER_FIELD_RTC_EN,
UACPI_REGISTER_FIELD_PCIEXP_WAKE_DIS,
UACPI_REGISTER_FIELD_SCI_EN,
UACPI_REGISTER_FIELD_BM_RLD,
UACPI_REGISTER_FIELD_GBL_RLS,
UACPI_REGISTER_FIELD_SLP_TYP,
UACPI_REGISTER_FIELD_HWR_SLP_TYP,
UACPI_REGISTER_FIELD_SLP_EN,
UACPI_REGISTER_FIELD_HWR_SLP_EN,
UACPI_REGISTER_FIELD_ARB_DIS,
UACPI_REGISTER_FIELD_MAX = UACPI_REGISTER_FIELD_ARB_DIS,
} uacpi_register_field;
/*
* Read a field from a FADT register
*
* NOTE: The value is automatically masked and shifted down as appropriate,
* the client code doesn't have to do any bit manipulation. E.g. for
* a field at 0b???XX??? the returned value will contain just the 0bXX
*/
uacpi_status uacpi_read_register_field(uacpi_register_field, uacpi_u64*);
/*
* Write to a field of a FADT register
*
* NOTE: The value is automatically masked and shifted up as appropriate,
* the client code doesn't have to do any bit manipulation. E.g. for
* a field at 0b???XX??? the passed value should be just 0bXX
*/
uacpi_status uacpi_write_register_field(uacpi_register_field, uacpi_u64);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,759 @@
#pragma once
#include <uacpi/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
typedef enum uacpi_resource_type {
UACPI_RESOURCE_TYPE_IRQ,
UACPI_RESOURCE_TYPE_EXTENDED_IRQ,
UACPI_RESOURCE_TYPE_DMA,
UACPI_RESOURCE_TYPE_FIXED_DMA,
UACPI_RESOURCE_TYPE_IO,
UACPI_RESOURCE_TYPE_FIXED_IO,
UACPI_RESOURCE_TYPE_ADDRESS16,
UACPI_RESOURCE_TYPE_ADDRESS32,
UACPI_RESOURCE_TYPE_ADDRESS64,
UACPI_RESOURCE_TYPE_ADDRESS64_EXTENDED,
UACPI_RESOURCE_TYPE_MEMORY24,
UACPI_RESOURCE_TYPE_MEMORY32,
UACPI_RESOURCE_TYPE_FIXED_MEMORY32,
UACPI_RESOURCE_TYPE_START_DEPENDENT,
UACPI_RESOURCE_TYPE_END_DEPENDENT,
// Up to 7 bytes
UACPI_RESOURCE_TYPE_VENDOR_SMALL,
// Up to 2^16 - 1 bytes
UACPI_RESOURCE_TYPE_VENDOR_LARGE,
UACPI_RESOURCE_TYPE_GENERIC_REGISTER,
UACPI_RESOURCE_TYPE_GPIO_CONNECTION,
// These must always be contiguous in this order
UACPI_RESOURCE_TYPE_SERIAL_I2C_CONNECTION,
UACPI_RESOURCE_TYPE_SERIAL_SPI_CONNECTION,
UACPI_RESOURCE_TYPE_SERIAL_UART_CONNECTION,
UACPI_RESOURCE_TYPE_SERIAL_CSI2_CONNECTION,
UACPI_RESOURCE_TYPE_PIN_FUNCTION,
UACPI_RESOURCE_TYPE_PIN_CONFIGURATION,
UACPI_RESOURCE_TYPE_PIN_GROUP,
UACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION,
UACPI_RESOURCE_TYPE_PIN_GROUP_CONFIGURATION,
UACPI_RESOURCE_TYPE_CLOCK_INPUT,
UACPI_RESOURCE_TYPE_END_TAG,
UACPI_RESOURCE_TYPE_MAX = UACPI_RESOURCE_TYPE_END_TAG,
} uacpi_resource_type;
typedef struct uacpi_resource_source {
uacpi_u8 index;
uacpi_bool index_present;
uacpi_u16 length;
uacpi_char *string;
} uacpi_resource_source;
/*
* This applies to IRQ & StartDependent resources only. The DONT_CARE value is
* used for deserialization into the AML format to signify that the serializer
* is allowed to optimize the length down if possible. Note that this is
* generally not allowed unless the resource is generated by the caller:
*
* -- ACPI 6.5 ------------------------------------------------------------
* The resource descriptors in the byte stream argument must be specified
* exactly as listed in the _CRS byte stream - meaning that the identical
* resource descriptors must appear in the identical order, resulting in a
* buffer of exactly the same length. Optimizations such as changing an
* IRQ descriptor to an IRQNoFlags descriptor (or vice-versa) must not be
* performed. Similarly, changing StartDependentFn to StartDependentFnNoPri
* is not allowed.
* ------------------------------------------------------------------------
*/
enum uacpi_resource_length_kind {
UACPI_RESOURCE_LENGTH_KIND_DONT_CARE = 0,
UACPI_RESOURCE_LENGTH_KIND_ONE_LESS,
UACPI_RESOURCE_LENGTH_KIND_FULL,
};
// triggering fields
#define UACPI_TRIGGERING_EDGE 1
#define UACPI_TRIGGERING_LEVEL 0
// polarity
#define UACPI_POLARITY_ACTIVE_HIGH 0
#define UACPI_POLARITY_ACTIVE_LOW 1
#define UACPI_POLARITY_ACTIVE_BOTH 2
// sharing
#define UACPI_EXCLUSIVE 0
#define UACPI_SHARED 1
// wake_capability
#define UACPI_WAKE_CAPABLE 1
#define UACPI_NOT_WAKE_CAPABLE 0
typedef struct uacpi_resource_irq {
uacpi_u8 length_kind;
uacpi_u8 triggering;
uacpi_u8 polarity;
uacpi_u8 sharing;
uacpi_u8 wake_capability;
uacpi_u8 num_irqs;
uacpi_u8 irqs[];
} uacpi_resource_irq;
typedef struct uacpi_resource_extended_irq {
uacpi_u8 direction;
uacpi_u8 triggering;
uacpi_u8 polarity;
uacpi_u8 sharing;
uacpi_u8 wake_capability;
uacpi_u8 num_irqs;
uacpi_resource_source source;
uacpi_u32 irqs[];
} uacpi_resource_extended_irq;
// transfer_type
#define UACPI_TRANSFER_TYPE_8_BIT 0b00
#define UACPI_TRANSFER_TYPE_8_AND_16_BIT 0b01
#define UACPI_TRANSFER_TYPE_16_BIT 0b10
// bus_master_status
#define UACPI_BUS_MASTER 0b1
// channel_speed
#define UACPI_DMA_COMPATIBILITY 0b00
#define UACPI_DMA_TYPE_A 0b01
#define UACPI_DMA_TYPE_B 0b10
#define UACPI_DMA_TYPE_F 0b11
// transfer_width
#define UACPI_TRANSFER_WIDTH_8 0x00
#define UACPI_TRANSFER_WIDTH_16 0x01
#define UACPI_TRANSFER_WIDTH_32 0x02
#define UACPI_TRANSFER_WIDTH_64 0x03
#define UACPI_TRANSFER_WIDTH_128 0x04
#define UACPI_TRANSFER_WIDTH_256 0x05
typedef struct uacpi_resource_dma {
uacpi_u8 transfer_type;
uacpi_u8 bus_master_status;
uacpi_u8 channel_speed;
uacpi_u8 num_channels;
uacpi_u8 channels[];
} uacpi_resource_dma;
typedef struct uacpi_resource_fixed_dma {
uacpi_u16 request_line;
uacpi_u16 channel;
uacpi_u8 transfer_width;
} uacpi_resource_fixed_dma;
// decode_type
#define UACPI_DECODE_16 0b1
#define UACPI_DECODE_10 0b0
typedef struct uacpi_resource_io {
uacpi_u8 decode_type;
uacpi_u16 minimum;
uacpi_u16 maximum;
uacpi_u8 alignment;
uacpi_u8 length;
} uacpi_resource_io;
typedef struct uacpi_resource_fixed_io {
uacpi_u16 address;
uacpi_u8 length;
} uacpi_resource_fixed_io;
// write_status
#define UACPI_NON_WRITABLE 0
#define UACPI_WRITABLE 1
// caching
#define UACPI_NON_CACHEABLE 0
#define UACPI_CACHEABLE 1
#define UACPI_CACHEABLE_WRITE_COMBINING 2
#define UACPI_PREFETCHABLE 3
// range_type
#define UACPI_RANGE_TYPE_MEMORY 0
#define UACPI_RANGE_TYPE_RESERVED 1
#define UACPI_RANGE_TYPE_ACPI 2
#define UACPI_RANGE_TYPE_NVS 3
// address_common->type
#define UACPI_RANGE_MEMORY 0
#define UACPI_RANGE_IO 1
#define UACPI_RANGE_BUS 2
// translation
#define UACPI_IO_MEM_TRANSLATION 1
#define UACPI_IO_MEM_STATIC 0
// translation_type
#define UACPI_TRANSLATION_DENSE 0
#define UACPI_TRANSLATION_SPARSE 1
// direction
#define UACPI_PRODUCER 0
#define UACPI_CONSUMER 1
// decode_type
#define UACPI_POSITIVE_DECODE 0
#define UACPI_SUBTRACTIVE_DECODE 1
// fixed_min_address & fixed_max_address
#define UACPI_ADDRESS_NOT_FIXED 0
#define UACPI_ADDRESS_FIXED 1
typedef struct uacpi_memory_attribute {
uacpi_u8 write_status;
uacpi_u8 caching;
uacpi_u8 range_type;
uacpi_u8 translation;
} uacpi_memory_attribute;
typedef struct uacpi_io_attribute {
uacpi_u8 range_type;
uacpi_u8 translation;
uacpi_u8 translation_type;
} uacpi_io_attribute;
typedef union uacpi_address_attribute {
uacpi_memory_attribute memory;
uacpi_io_attribute io;
uacpi_u8 type_specific;
} uacpi_address_attribute;
typedef struct uacpi_resource_address_common {
uacpi_address_attribute attribute;
uacpi_u8 type;
uacpi_u8 direction;
uacpi_u8 decode_type;
uacpi_u8 fixed_min_address;
uacpi_u8 fixed_max_address;
} uacpi_resource_address_common;
typedef struct uacpi_resource_address16 {
uacpi_resource_address_common common;
uacpi_u16 granularity;
uacpi_u16 minimum;
uacpi_u16 maximum;
uacpi_u16 translation_offset;
uacpi_u16 address_length;
uacpi_resource_source source;
} uacpi_resource_address16;
typedef struct uacpi_resource_address32 {
uacpi_resource_address_common common;
uacpi_u32 granularity;
uacpi_u32 minimum;
uacpi_u32 maximum;
uacpi_u32 translation_offset;
uacpi_u32 address_length;
uacpi_resource_source source;
} uacpi_resource_address32;
typedef struct uacpi_resource_address64 {
uacpi_resource_address_common common;
uacpi_u64 granularity;
uacpi_u64 minimum;
uacpi_u64 maximum;
uacpi_u64 translation_offset;
uacpi_u64 address_length;
uacpi_resource_source source;
} uacpi_resource_address64;
typedef struct uacpi_resource_address64_extended {
uacpi_resource_address_common common;
uacpi_u8 revision_id;
uacpi_u64 granularity;
uacpi_u64 minimum;
uacpi_u64 maximum;
uacpi_u64 translation_offset;
uacpi_u64 address_length;
uacpi_u64 attributes;
} uacpi_resource_address64_extended;
typedef struct uacpi_resource_memory24 {
uacpi_u8 write_status;
uacpi_u16 minimum;
uacpi_u16 maximum;
uacpi_u16 alignment;
uacpi_u16 length;
} uacpi_resource_memory24;
typedef struct uacpi_resource_memory32 {
uacpi_u8 write_status;
uacpi_u32 minimum;
uacpi_u32 maximum;
uacpi_u32 alignment;
uacpi_u32 length;
} uacpi_resource_memory32;
typedef struct uacpi_resource_fixed_memory32 {
uacpi_u8 write_status;
uacpi_u32 address;
uacpi_u32 length;
} uacpi_resource_fixed_memory32;
// compatibility & performance
#define UACPI_GOOD 0
#define UACPI_ACCEPTABLE 1
#define UACPI_SUB_OPTIMAL 2
typedef struct uacpi_resource_start_dependent {
uacpi_u8 length_kind;
uacpi_u8 compatibility;
uacpi_u8 performance;
} uacpi_resource_start_dependent;
typedef struct uacpi_resource_vendor_defined {
uacpi_u8 length;
uacpi_u8 data[];
} uacpi_resource_vendor;
typedef struct uacpi_resource_vendor_typed {
uacpi_u16 length;
uacpi_u8 sub_type;
uacpi_u8 uuid[16];
uacpi_u8 data[];
} uacpi_resource_vendor_typed;
typedef struct uacpi_resource_generic_register {
uacpi_u8 address_space_id;
uacpi_u8 bit_width;
uacpi_u8 bit_offset;
uacpi_u8 access_size;
uacpi_u64 address;
} uacpi_resource_generic_register;
// type
#define UACPI_GPIO_CONNECTION_INTERRUPT 0x00
#define UACPI_GPIO_CONNECTION_IO 0x01
typedef struct uacpi_interrupt_connection_flags {
uacpi_u8 triggering;
uacpi_u8 polarity;
uacpi_u8 sharing;
uacpi_u8 wake_capability;
} uacpi_interrupt_connection_flags;
// restriction
#define UACPI_IO_RESTRICTION_NONE 0x0
#define UACPI_IO_RESTRICTION_INPUT 0x1
#define UACPI_IO_RESTRICTION_OUTPUT 0x2
#define UACPI_IO_RESTRICTION_NONE_PRESERVE 0x3
typedef struct uacpi_io_connection_flags {
uacpi_u8 restriction;
uacpi_u8 sharing;
} uacpi_io_connection_flags;
// pull_configuration
#define UACPI_PIN_CONFIG_DEFAULT 0x00
#define UACPI_PIN_CONFIG_PULL_UP 0x01
#define UACPI_PIN_CONFIG_PULL_DOWN 0x02
#define UACPI_PIN_CONFIG_NO_PULL 0x03
typedef struct uacpi_resource_gpio_connection {
uacpi_u8 revision_id;
uacpi_u8 type;
uacpi_u8 direction;
union {
uacpi_interrupt_connection_flags intr;
uacpi_io_connection_flags io;
uacpi_u16 type_specific;
};
uacpi_u8 pull_configuration;
uacpi_u16 drive_strength;
uacpi_u16 debounce_timeout;
uacpi_u16 vendor_data_length;
uacpi_u16 pin_table_length;
uacpi_resource_source source;
uacpi_u16 *pin_table;
uacpi_u8 *vendor_data;
} uacpi_resource_gpio_connection;
// mode
#define UACPI_MODE_CONTROLLER_INITIATED 0x0
#define UACPI_MODE_DEVICE_INITIATED 0x1
typedef struct uacpi_resource_serial_bus_common {
uacpi_u8 revision_id;
uacpi_u8 type;
uacpi_u8 mode;
uacpi_u8 direction;
uacpi_u8 sharing;
uacpi_u8 type_revision_id;
uacpi_u16 type_data_length;
uacpi_u16 vendor_data_length;
uacpi_resource_source source;
uacpi_u8 *vendor_data;
} uacpi_resource_serial_bus_common;
// addressing_mode
#define UACPI_I2C_7BIT 0x0
#define UACPI_I2C_10BIT 0x1
typedef struct uacpi_resource_i2c_connection {
uacpi_resource_serial_bus_common common;
uacpi_u8 addressing_mode;
uacpi_u16 slave_address;
uacpi_u32 connection_speed;
} uacpi_resource_i2c_connection;
// wire_mode
#define UACPI_SPI_4_WIRES 0
#define UACPI_SPI_3_WIRES 1
// device_polarity
#define UACPI_SPI_ACTIVE_LOW 0
#define UACPI_SPI_ACTIVE_HIGH 1
// phase
#define UACPI_SPI_PHASE_FIRST 0
#define UACPI_SPI_PHASE_SECOND 1
// polarity
#define UACPI_SPI_START_LOW 0
#define UACPI_SPI_START_HIGH 1
typedef struct uacpi_resource_spi_connection {
uacpi_resource_serial_bus_common common;
uacpi_u8 wire_mode;
uacpi_u8 device_polarity;
uacpi_u8 data_bit_length;
uacpi_u8 phase;
uacpi_u8 polarity;
uacpi_u16 device_selection;
uacpi_u32 connection_speed;
} uacpi_resource_spi_connection;
// stop_bits
#define UACPI_UART_STOP_BITS_NONE 0b00
#define UACPI_UART_STOP_BITS_1 0b01
#define UACPI_UART_STOP_BITS_1_5 0b10
#define UACPI_UART_STOP_BITS_2 0b11
// data_bits
#define UACPI_UART_DATA_5BITS 0b000
#define UACPI_UART_DATA_6BITS 0b001
#define UACPI_UART_DATA_7BITS 0b010
#define UACPI_UART_DATA_8BITS 0b011
#define UACPI_UART_DATA_9BITS 0b100
// endianness
#define UACPI_UART_LITTLE_ENDIAN 0
#define UACPI_UART_BIG_ENDIAN 1
// parity
#define UACPI_UART_PARITY_NONE 0x00
#define UACPI_UART_PARITY_EVEN 0x01
#define UACPI_UART_PARITY_ODD 0x02
#define UACPI_UART_PARITY_MARK 0x03
#define UACPI_UART_PARITY_SPACE 0x04
// lines_enabled
#define UACPI_UART_DATA_CARRIER_DETECT (1 << 2)
#define UACPI_UART_RING_INDICATOR (1 << 3)
#define UACPI_UART_DATA_SET_READY (1 << 4)
#define UACPI_UART_DATA_TERMINAL_READY (1 << 5)
#define UACPI_UART_CLEAR_TO_SEND (1 << 6)
#define UACPI_UART_REQUEST_TO_SEND (1 << 7)
// flow_control
#define UACPI_UART_FLOW_CONTROL_NONE 0b00
#define UACPI_UART_FLOW_CONTROL_HW 0b01
#define UACPI_UART_FLOW_CONTROL_XON_XOFF 0b10
typedef struct uacpi_resource_uart_connection {
uacpi_resource_serial_bus_common common;
uacpi_u8 stop_bits;
uacpi_u8 data_bits;
uacpi_u8 endianness;
uacpi_u8 parity;
uacpi_u8 lines_enabled;
uacpi_u8 flow_control;
uacpi_u32 baud_rate;
uacpi_u16 rx_fifo;
uacpi_u16 tx_fifo;
} uacpi_resource_uart_connection;
// phy_type
#define UACPI_CSI2_PHY_C 0b00
#define UACPI_CSI2_PHY_D 0b01
typedef struct uacpi_resource_csi2_connection {
uacpi_resource_serial_bus_common common;
uacpi_u8 phy_type;
uacpi_u8 local_port;
} uacpi_resource_csi2_connection;
typedef struct uacpi_resource_pin_function {
uacpi_u8 revision_id;
uacpi_u8 sharing;
uacpi_u8 pull_configuration;
uacpi_u16 function_number;
uacpi_u16 pin_table_length;
uacpi_u16 vendor_data_length;
uacpi_resource_source source;
uacpi_u16 *pin_table;
uacpi_u8 *vendor_data;
} uacpi_resource_pin_function;
// type
#define UACPI_PIN_CONFIG_DEFAULT 0x00
#define UACPI_PIN_CONFIG_BIAS_PULL_UP 0x01
#define UACPI_PIN_CONFIG_BIAS_PULL_DOWN 0x02
#define UACPI_PIN_CONFIG_BIAS_DEFAULT 0x03
#define UACPI_PIN_CONFIG_BIAS_DISABLE 0x04
#define UACPI_PIN_CONFIG_BIAS_HIGH_IMPEDANCE 0x05
#define UACPI_PIN_CONFIG_BIAS_BUS_HOLD 0x06
#define UACPI_PIN_CONFIG_DRIVE_OPEN_DRAIN 0x07
#define UACPI_PIN_CONFIG_DRIVE_OPEN_SOURCE 0x08
#define UACPI_PIN_CONFIG_DRIVE_PUSH_PULL 0x09
#define UACPI_PIN_CONFIG_DRIVE_STRENGTH 0x0A
#define UACPI_PIN_CONFIG_SLEW_RATE 0x0B
#define UACPI_PIN_CONFIG_INPUT_DEBOUNCE 0x0C
#define UACPI_PIN_CONFIG_INPUT_SCHMITT_TRIGGER 0x0D
typedef struct uacpi_resource_pin_configuration {
uacpi_u8 revision_id;
uacpi_u8 sharing;
uacpi_u8 direction;
uacpi_u8 type;
uacpi_u32 value;
uacpi_u16 pin_table_length;
uacpi_u16 vendor_data_length;
uacpi_resource_source source;
uacpi_u16 *pin_table;
uacpi_u8 *vendor_data;
} uacpi_resource_pin_configuration;
typedef struct uacpi_resource_label {
uacpi_u16 length;
const uacpi_char *string;
} uacpi_resource_label;
typedef struct uacpi_resource_pin_group {
uacpi_u8 revision_id;
uacpi_u8 direction;
uacpi_u16 pin_table_length;
uacpi_u16 vendor_data_length;
uacpi_resource_label label;
uacpi_u16 *pin_table;
uacpi_u8 *vendor_data;
} uacpi_resource_pin_group;
typedef struct uacpi_resource_pin_group_function {
uacpi_u8 revision_id;
uacpi_u8 sharing;
uacpi_u8 direction;
uacpi_u16 function;
uacpi_u16 vendor_data_length;
uacpi_resource_source source;
uacpi_resource_label label;
uacpi_u8 *vendor_data;
} uacpi_resource_pin_group_function;
typedef struct uacpi_resource_pin_group_configuration {
uacpi_u8 revision_id;
uacpi_u8 sharing;
uacpi_u8 direction;
uacpi_u8 type;
uacpi_u32 value;
uacpi_u16 vendor_data_length;
uacpi_resource_source source;
uacpi_resource_label label;
uacpi_u8 *vendor_data;
} uacpi_resource_pin_group_configuration;
// scale
#define UACPI_SCALE_HZ 0b00
#define UACPI_SCALE_KHZ 0b01
#define UACPI_SCALE_MHZ 0b10
// frequency
#define UACPI_FREQUENCY_FIXED 0x0
#define UACPI_FREQUENCY_VARIABLE 0x1
typedef struct uacpi_resource_clock_input {
uacpi_u8 revision_id;
uacpi_u8 frequency;
uacpi_u8 scale;
uacpi_u16 divisor;
uacpi_u32 numerator;
uacpi_resource_source source;
} uacpi_resource_clock_input;
typedef struct uacpi_resource {
uacpi_u32 type;
uacpi_u32 length;
union {
uacpi_resource_irq irq;
uacpi_resource_extended_irq extended_irq;
uacpi_resource_dma dma;
uacpi_resource_fixed_dma fixed_dma;
uacpi_resource_io io;
uacpi_resource_fixed_io fixed_io;
uacpi_resource_address16 address16;
uacpi_resource_address32 address32;
uacpi_resource_address64 address64;
uacpi_resource_address64_extended address64_extended;
uacpi_resource_memory24 memory24;
uacpi_resource_memory32 memory32;
uacpi_resource_fixed_memory32 fixed_memory32;
uacpi_resource_start_dependent start_dependent;
uacpi_resource_vendor vendor;
uacpi_resource_vendor_typed vendor_typed;
uacpi_resource_generic_register generic_register;
uacpi_resource_gpio_connection gpio_connection;
uacpi_resource_serial_bus_common serial_bus_common;
uacpi_resource_i2c_connection i2c_connection;
uacpi_resource_spi_connection spi_connection;
uacpi_resource_uart_connection uart_connection;
uacpi_resource_csi2_connection csi2_connection;
uacpi_resource_pin_function pin_function;
uacpi_resource_pin_configuration pin_configuration;
uacpi_resource_pin_group pin_group;
uacpi_resource_pin_group_function pin_group_function;
uacpi_resource_pin_group_configuration pin_group_configuration;
uacpi_resource_clock_input clock_input;
};
} uacpi_resource;
#define UACPI_NEXT_RESOURCE(cur) \
((uacpi_resource*)((uacpi_u8*)(cur) + (cur)->length))
typedef struct uacpi_resources {
/*
* Length of the 'entries' array in BYTES (NOT the count of resources),
* see comment above 'entries' for more information.
*/
uacpi_size length;
/*
* Resources are variable length! See UACPI_NEXT_RESOURCE to see how to
* retrieve the next resource. You can alternatively use
* uacpi_for_each_resource instead of iterating manually.
*
* Resources are guaranteed to be naturally aligned and are always
* terminated by a resource of type UACPI_RESOURCE_TYPE_END_TAG.
*/
uacpi_resource *entries;
} uacpi_resources;
void uacpi_free_resources(uacpi_resources*);
typedef uacpi_iteration_decision (*uacpi_resource_iteration_callback)
(void *user, uacpi_resource *resource);
/*
* Evaluate the _CRS method for a 'device' and get the returned resource list
* via 'out_resources'.
*
* NOTE: the returned buffer must be released via uacpi_free_resources()
*
* If you don't need to keep the resource array for later use you can
* uacpi_for_each_device_resource(device, "_CRS", ...) instead, which takes
* care of iteration & memory management on its own.
*/
uacpi_status uacpi_get_current_resources(
uacpi_namespace_node *device, uacpi_resources **out_resources
);
/*
* Evaluate the _PRS method for a 'device' and get the returned resource list
* via 'out_resources'.
*
* NOTE: the returned buffer must be released via uacpi_free_resources()
*
* If you don't need to keep the resource array for later use you can
* uacpi_for_each_device_resource(device, "_PRS", ...) instead, which takes
* care of iteration & memory management on its own.
*/
uacpi_status uacpi_get_possible_resources(
uacpi_namespace_node *device, uacpi_resources **out_resources
);
/*
* Evaluate an arbitrary method that is expected to return an AML resource
* buffer for a 'device' and get the returned resource list via 'out_resources'.
*
* NOTE: the returned buffer must be released via uacpi_free_resources()
*
* If you don't need to keep the resource array for later use you can
* uacpi_for_each_device_resource(device, method, ...) instead, which takes
* care of iteration & memory management on its own.
*/
uacpi_status uacpi_get_device_resources(
uacpi_namespace_node *device, const uacpi_char *method,
uacpi_resources **out_resources
);
/*
* Set the configuration to be used by the 'device' by calling its _SRS method.
*
* Note that this expects 'resources' in the normal 'uacpi_resources' format,
* and not the raw AML resources bytestream, the conversion to the latter is
* done automatically by this API. If you want to _SRS a raw AML resources
* bytestream, use 'uacpi_execute' or similar API directly.
*/
uacpi_status uacpi_set_resources(
uacpi_namespace_node *device, uacpi_resources *resources
);
/*
* A convenience helper for iterating over the resource list returned by any
* of the uacpi_get_*_resources functions.
*/
uacpi_status uacpi_for_each_resource(
uacpi_resources *resources, uacpi_resource_iteration_callback cb, void *user
);
/*
* A shorthand for uacpi_get_device_resources() + uacpi_for_each_resource().
*
* Use if you don't actually want to save the 'resources' list, but simply want
* to iterate it once to extract the resources you care about and then free it
* right away.
*/
uacpi_status uacpi_for_each_device_resource(
uacpi_namespace_node *device, const uacpi_char *method,
uacpi_resource_iteration_callback cb, void *user
);
/*
* Convert a single AML-encoded resource to native format.
*
* This should be used for converting Connection() fields (passed during IO on
* GeneralPurposeIO or GenericSerialBus operation regions) or other similar
* buffers with only one resource to native format.
*
* NOTE: the returned buffer must be released via uacpi_free_resource()
*/
uacpi_status uacpi_get_resource_from_buffer(
uacpi_data_view aml_buffer, uacpi_resource **out_resource
);
void uacpi_free_resource(uacpi_resource*);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,67 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#include <uacpi/uacpi.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
/*
* Set the firmware waking vector in FACS.
*
* 'addr32' is the real mode entry-point address
* 'addr64' is the protected mode entry-point address
*/
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_set_waking_vector(
uacpi_phys_addr addr32, uacpi_phys_addr addr64
))
typedef enum uacpi_sleep_state {
UACPI_SLEEP_STATE_S0 = 0,
UACPI_SLEEP_STATE_S1,
UACPI_SLEEP_STATE_S2,
UACPI_SLEEP_STATE_S3,
UACPI_SLEEP_STATE_S4,
UACPI_SLEEP_STATE_S5,
UACPI_SLEEP_STATE_MAX = UACPI_SLEEP_STATE_S5,
} uacpi_sleep_state;
/*
* Prepare for a given sleep state.
* Must be caled with interrupts ENABLED.
*/
uacpi_status uacpi_prepare_for_sleep_state(uacpi_sleep_state);
/*
* Enter the given sleep state after preparation.
* Must be called with interrupts DISABLED.
*/
uacpi_status uacpi_enter_sleep_state(uacpi_sleep_state);
/*
* Prepare to leave the given sleep state.
* Must be called with interrupts DISABLED.
*/
uacpi_status uacpi_prepare_for_wake_from_sleep_state(uacpi_sleep_state);
/*
* Wake from the given sleep state.
* Must be called with interrupts ENABLED.
*/
uacpi_status uacpi_wake_from_sleep_state(uacpi_sleep_state);
/*
* Attempt reset via the FADT reset register.
*/
uacpi_status uacpi_reboot(void);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,57 @@
#pragma once
#include <uacpi/internal/compiler.h>
#include <uacpi/platform/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum uacpi_status {
UACPI_STATUS_OK = 0,
UACPI_STATUS_MAPPING_FAILED = 1,
UACPI_STATUS_OUT_OF_MEMORY = 2,
UACPI_STATUS_BAD_CHECKSUM = 3,
UACPI_STATUS_INVALID_SIGNATURE = 4,
UACPI_STATUS_INVALID_TABLE_LENGTH = 5,
UACPI_STATUS_NOT_FOUND = 6,
UACPI_STATUS_INVALID_ARGUMENT = 7,
UACPI_STATUS_UNIMPLEMENTED = 8,
UACPI_STATUS_ALREADY_EXISTS = 9,
UACPI_STATUS_INTERNAL_ERROR = 10,
UACPI_STATUS_TYPE_MISMATCH = 11,
UACPI_STATUS_INIT_LEVEL_MISMATCH = 12,
UACPI_STATUS_NAMESPACE_NODE_DANGLING = 13,
UACPI_STATUS_NO_HANDLER = 14,
UACPI_STATUS_NO_RESOURCE_END_TAG = 15,
UACPI_STATUS_COMPILED_OUT = 16,
UACPI_STATUS_HARDWARE_TIMEOUT = 17,
UACPI_STATUS_TIMEOUT = 18,
UACPI_STATUS_OVERRIDDEN = 19,
UACPI_STATUS_DENIED = 20,
// All errors that have bytecode-related origin should go here
UACPI_STATUS_AML_UNDEFINED_REFERENCE = 0x0EFF0000,
UACPI_STATUS_AML_INVALID_NAMESTRING = 0x0EFF0001,
UACPI_STATUS_AML_OBJECT_ALREADY_EXISTS = 0x0EFF0002,
UACPI_STATUS_AML_INVALID_OPCODE = 0x0EFF0003,
UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE = 0x0EFF0004,
UACPI_STATUS_AML_BAD_ENCODING = 0x0EFF0005,
UACPI_STATUS_AML_OUT_OF_BOUNDS_INDEX = 0x0EFF0006,
UACPI_STATUS_AML_SYNC_LEVEL_TOO_HIGH = 0x0EFF0007,
UACPI_STATUS_AML_INVALID_RESOURCE = 0x0EFF0008,
UACPI_STATUS_AML_LOOP_TIMEOUT = 0x0EFF0009,
UACPI_STATUS_AML_CALL_STACK_DEPTH_LIMIT = 0x0EFF000A,
} uacpi_status;
const uacpi_char *uacpi_status_to_string(uacpi_status);
#define uacpi_unlikely_error(expr) uacpi_unlikely((expr) != UACPI_STATUS_OK)
#define uacpi_likely_error(expr) uacpi_likely((expr) != UACPI_STATUS_OK)
#define uacpi_unlikely_success(expr) uacpi_unlikely((expr) == UACPI_STATUS_OK)
#define uacpi_likely_success(expr) uacpi_likely((expr) == UACPI_STATUS_OK)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,141 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#ifdef __cplusplus
extern "C" {
#endif
// Forward-declared to avoid including the entire acpi.h here
struct acpi_fadt;
typedef struct uacpi_table_identifiers {
uacpi_object_name signature;
// if oemid[0] == 0 this field is ignored
char oemid[6];
// if oem_table_id[0] == 0 this field is ignored
char oem_table_id[8];
} uacpi_table_identifiers;
typedef struct uacpi_table {
union {
uacpi_virt_addr virt_addr;
void *ptr;
struct acpi_sdt_hdr *hdr;
};
// Index number used to identify this table internally
uacpi_size index;
} uacpi_table;
/*
* Install a table from either a virtual or a physical address.
* The table is simply stored in the internal table array, and not loaded by
* the interpreter (see uacpi_table_load).
*
* The table is optionally returned via 'out_table'.
*
* Manual calls to uacpi_table_install are not subject to filtering via the
* table installation callback (if any).
*/
uacpi_status uacpi_table_install(
void*, uacpi_table *out_table
);
uacpi_status uacpi_table_install_physical(
uacpi_phys_addr, uacpi_table *out_table
);
#ifndef UACPI_BAREBONES_MODE
/*
* Load a previously installed table by feeding it to the interpreter.
*/
uacpi_status uacpi_table_load(uacpi_size index);
#endif // !UACPI_BAREBONES_MODE
/*
* Helpers for finding tables.
*
* for find_by_signature:
* 'signature' is an array of 4 characters, a null terminator is not
* necessary and can be omitted (especially useful for non-C language
* bindings)
*
* 'out_table' is a pointer to a caller allocated uacpi_table structure that
* receives the table pointer & its internal index in case the call was
* successful.
*
* NOTE:
* The returned table's reference count is incremented by 1, which keeps its
* mapping alive forever unless uacpi_table_unref() is called for this table
* later on. Calling uacpi_table_find_next_with_same_signature() on a table also
* drops its reference count by 1, so if you want to keep it mapped you must
* manually call uacpi_table_ref() beforehand.
*/
uacpi_status uacpi_table_find_by_signature(
const uacpi_char *signature, uacpi_table *out_table
);
uacpi_status uacpi_table_find_next_with_same_signature(
uacpi_table *in_out_table
);
uacpi_status uacpi_table_find(
const uacpi_table_identifiers *id, uacpi_table *out_table
);
/*
* Increment/decrement a table's reference count.
* The table is unmapped when the reference count drops to 0.
*/
uacpi_status uacpi_table_ref(uacpi_table*);
uacpi_status uacpi_table_unref(uacpi_table*);
/*
* Returns the pointer to a sanitized internal version of FADT.
*
* The revision is guaranteed to be correct. All of the registers are converted
* to GAS format. Fields that might contain garbage are cleared.
*/
uacpi_status uacpi_table_fadt(struct acpi_fadt**);
typedef enum uacpi_table_installation_disposition {
// Allow the table to be installed as-is
UACPI_TABLE_INSTALLATION_DISPOSITON_ALLOW = 0,
/*
* Deny the table from being installed completely. This is useful for
* debugging various problems, e.g. AML loading bad SSDTs that cause the
* system to hang or enter an undesired state.
*/
UACPI_TABLE_INSTALLATION_DISPOSITON_DENY,
/*
* Override the table being installed with the table at the virtual address
* returned in 'out_override_address'.
*/
UACPI_TABLE_INSTALLATION_DISPOSITON_VIRTUAL_OVERRIDE,
/*
* Override the table being installed with the table at the physical address
* returned in 'out_override_address'.
*/
UACPI_TABLE_INSTALLATION_DISPOSITON_PHYSICAL_OVERRIDE,
} uacpi_table_installation_disposition;
typedef uacpi_table_installation_disposition (*uacpi_table_installation_handler)
(struct acpi_sdt_hdr *hdr, uacpi_u64 *out_override_address);
/*
* Set a handler that is invoked for each table before it gets installed.
*
* Depending on the return value, the table is either allowed to be installed
* as-is, denied, or overriden with a new one.
*/
uacpi_status uacpi_set_table_installation_handler(
uacpi_table_installation_handler handler
);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,544 @@
#pragma once
#include <uacpi/status.h>
#include <uacpi/platform/types.h>
#include <uacpi/platform/compiler.h>
#include <uacpi/platform/arch_helpers.h>
#include <uacpi/platform/config.h>
#ifdef __cplusplus
extern "C" {
#endif
#if UACPI_POINTER_SIZE == 4 && defined(UACPI_PHYS_ADDR_IS_32BITS)
typedef uacpi_u32 uacpi_phys_addr;
typedef uacpi_u32 uacpi_io_addr;
#else
typedef uacpi_u64 uacpi_phys_addr;
typedef uacpi_u64 uacpi_io_addr;
#endif
typedef void *uacpi_handle;
typedef union uacpi_object_name {
uacpi_char text[4];
uacpi_u32 id;
} uacpi_object_name;
typedef enum uacpi_iteration_decision {
UACPI_ITERATION_DECISION_CONTINUE = 0,
UACPI_ITERATION_DECISION_BREAK,
// Only applicable for uacpi_namespace_for_each_child
UACPI_ITERATION_DECISION_NEXT_PEER,
} uacpi_iteration_decision;
typedef enum uacpi_address_space {
UACPI_ADDRESS_SPACE_SYSTEM_MEMORY = 0,
UACPI_ADDRESS_SPACE_SYSTEM_IO = 1,
UACPI_ADDRESS_SPACE_PCI_CONFIG = 2,
UACPI_ADDRESS_SPACE_EMBEDDED_CONTROLLER = 3,
UACPI_ADDRESS_SPACE_SMBUS = 4,
UACPI_ADDRESS_SPACE_SYSTEM_CMOS = 5,
UACPI_ADDRESS_SPACE_PCI_BAR_TARGET = 6,
UACPI_ADDRESS_SPACE_IPMI = 7,
UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO = 8,
UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS = 9,
UACPI_ADDRESS_SPACE_PCC = 0x0A,
UACPI_ADDRESS_SPACE_PRM = 0x0B,
UACPI_ADDRESS_SPACE_FFIXEDHW = 0x7F,
// Internal type
UACPI_ADDRESS_SPACE_TABLE_DATA = 0xDA1A,
} uacpi_address_space;
const uacpi_char *uacpi_address_space_to_string(uacpi_address_space space);
#ifndef UACPI_BAREBONES_MODE
typedef enum uacpi_init_level {
// Reboot state, nothing is available
UACPI_INIT_LEVEL_EARLY = 0,
/*
* State after a successfull call to uacpi_initialize. Table API and
* other helpers that don't depend on the ACPI namespace may be used.
*/
UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED = 1,
/*
* State after a successfull call to uacpi_namespace_load. Most API may be
* used, namespace can be iterated, etc.
*/
UACPI_INIT_LEVEL_NAMESPACE_LOADED = 2,
/*
* The final initialization stage, this is entered after the call to
* uacpi_namespace_initialize. All API is available to use.
*/
UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED = 3,
} uacpi_init_level;
typedef struct uacpi_pci_address {
uacpi_u16 segment;
uacpi_u8 bus;
uacpi_u8 device;
uacpi_u8 function;
} uacpi_pci_address;
typedef struct uacpi_data_view {
union {
uacpi_u8 *bytes;
const uacpi_u8 *const_bytes;
uacpi_char *text;
const uacpi_char *const_text;
void *data;
const void *const_data;
};
uacpi_size length;
} uacpi_data_view;
typedef struct uacpi_namespace_node uacpi_namespace_node;
typedef enum uacpi_object_type {
UACPI_OBJECT_UNINITIALIZED = 0,
UACPI_OBJECT_INTEGER = 1,
UACPI_OBJECT_STRING = 2,
UACPI_OBJECT_BUFFER = 3,
UACPI_OBJECT_PACKAGE = 4,
UACPI_OBJECT_FIELD_UNIT = 5,
UACPI_OBJECT_DEVICE = 6,
UACPI_OBJECT_EVENT = 7,
UACPI_OBJECT_METHOD = 8,
UACPI_OBJECT_MUTEX = 9,
UACPI_OBJECT_OPERATION_REGION = 10,
UACPI_OBJECT_POWER_RESOURCE = 11,
UACPI_OBJECT_PROCESSOR = 12,
UACPI_OBJECT_THERMAL_ZONE = 13,
UACPI_OBJECT_BUFFER_FIELD = 14,
UACPI_OBJECT_DEBUG = 16,
UACPI_OBJECT_REFERENCE = 20,
UACPI_OBJECT_BUFFER_INDEX = 21,
UACPI_OBJECT_MAX_TYPE_VALUE = UACPI_OBJECT_BUFFER_INDEX
} uacpi_object_type;
// Type bits for API requiring a bit mask, e.g. uacpi_eval_typed
typedef enum uacpi_object_type_bits {
UACPI_OBJECT_INTEGER_BIT = (1 << UACPI_OBJECT_INTEGER),
UACPI_OBJECT_STRING_BIT = (1 << UACPI_OBJECT_STRING),
UACPI_OBJECT_BUFFER_BIT = (1 << UACPI_OBJECT_BUFFER),
UACPI_OBJECT_PACKAGE_BIT = (1 << UACPI_OBJECT_PACKAGE),
UACPI_OBJECT_FIELD_UNIT_BIT = (1 << UACPI_OBJECT_FIELD_UNIT),
UACPI_OBJECT_DEVICE_BIT = (1 << UACPI_OBJECT_DEVICE),
UACPI_OBJECT_EVENT_BIT = (1 << UACPI_OBJECT_EVENT),
UACPI_OBJECT_METHOD_BIT = (1 << UACPI_OBJECT_METHOD),
UACPI_OBJECT_MUTEX_BIT = (1 << UACPI_OBJECT_MUTEX),
UACPI_OBJECT_OPERATION_REGION_BIT = (1 << UACPI_OBJECT_OPERATION_REGION),
UACPI_OBJECT_POWER_RESOURCE_BIT = (1 << UACPI_OBJECT_POWER_RESOURCE),
UACPI_OBJECT_PROCESSOR_BIT = (1 << UACPI_OBJECT_PROCESSOR),
UACPI_OBJECT_THERMAL_ZONE_BIT = (1 << UACPI_OBJECT_THERMAL_ZONE),
UACPI_OBJECT_BUFFER_FIELD_BIT = (1 << UACPI_OBJECT_BUFFER_FIELD),
UACPI_OBJECT_DEBUG_BIT = (1 << UACPI_OBJECT_DEBUG),
UACPI_OBJECT_REFERENCE_BIT = (1 << UACPI_OBJECT_REFERENCE),
UACPI_OBJECT_BUFFER_INDEX_BIT = (1 << UACPI_OBJECT_BUFFER_INDEX),
UACPI_OBJECT_ANY_BIT = 0xFFFFFFFF,
} uacpi_object_type_bits;
typedef struct uacpi_object uacpi_object;
void uacpi_object_ref(uacpi_object *obj);
void uacpi_object_unref(uacpi_object *obj);
uacpi_object_type uacpi_object_get_type(uacpi_object*);
uacpi_object_type_bits uacpi_object_get_type_bit(uacpi_object*);
/*
* Returns UACPI_TRUE if the provided object's type matches this type.
*/
uacpi_bool uacpi_object_is(uacpi_object*, uacpi_object_type);
/*
* Returns UACPI_TRUE if the provided object's type is one of the values
* specified in the 'type_mask' of UACPI_OBJECT_*_BIT.
*/
uacpi_bool uacpi_object_is_one_of(
uacpi_object*, uacpi_object_type_bits type_mask
);
const uacpi_char *uacpi_object_type_to_string(uacpi_object_type);
/*
* Create an uninitialized object. The object can be further overwritten via
* uacpi_object_assign_* to anything.
*/
uacpi_object *uacpi_object_create_uninitialized(void);
/*
* Create an integer object with the value provided.
*/
uacpi_object *uacpi_object_create_integer(uacpi_u64);
typedef enum uacpi_overflow_behavior {
UACPI_OVERFLOW_ALLOW = 0,
UACPI_OVERFLOW_TRUNCATE,
UACPI_OVERFLOW_DISALLOW,
} uacpi_overflow_behavior;
/*
* Same as uacpi_object_create_integer, but introduces additional ways to
* control what happens if the provided integer is larger than 32-bits, and the
* AML code expects 32-bit integers.
*
* - UACPI_OVERFLOW_ALLOW -> do nothing, same as the vanilla helper
* - UACPI_OVERFLOW_TRUNCATE -> truncate the integer to 32-bits if it happens to
* be larger than allowed by the DSDT
* - UACPI_OVERFLOW_DISALLOW -> fail object creation with
* UACPI_STATUS_INVALID_ARGUMENT if the provided
* value happens to be too large
*/
uacpi_status uacpi_object_create_integer_safe(
uacpi_u64, uacpi_overflow_behavior, uacpi_object **out_obj
);
uacpi_status uacpi_object_assign_integer(uacpi_object*, uacpi_u64 value);
uacpi_status uacpi_object_get_integer(uacpi_object*, uacpi_u64 *out);
/*
* Create a string/buffer object. Takes in a constant view of the data.
*
* NOTE: The data is copied to a separately allocated buffer and is not taken
* ownership of.
*/
uacpi_object *uacpi_object_create_string(uacpi_data_view);
uacpi_object *uacpi_object_create_cstring(const uacpi_char*);
uacpi_object *uacpi_object_create_buffer(uacpi_data_view);
/*
* Returns a writable view of the data stored in the string or buffer type
* object.
*/
uacpi_status uacpi_object_get_string_or_buffer(
uacpi_object*, uacpi_data_view *out
);
uacpi_status uacpi_object_get_string(uacpi_object*, uacpi_data_view *out);
uacpi_status uacpi_object_get_buffer(uacpi_object*, uacpi_data_view *out);
/*
* Returns UACPI_TRUE if the provided string object is actually an AML namepath.
*
* This can only be the case for package elements. If a package element is
* specified as a path to an object in AML, it's not resolved by the interpreter
* right away as it might not have been defined at that point yet, and is
* instead stored as a special string object to be resolved by client code
* when needed.
*
* Example usage:
* uacpi_namespace_node *target_node = UACPI_NULL;
*
* uacpi_object *obj = UACPI_NULL;
* uacpi_eval(scope, path, UACPI_NULL, &obj);
*
* uacpi_object_array arr;
* uacpi_object_get_package(obj, &arr);
*
* if (uacpi_object_is_aml_namepath(arr.objects[0])) {
* uacpi_object_resolve_as_aml_namepath(
* arr.objects[0], scope, &target_node
* );
* }
*/
uacpi_bool uacpi_object_is_aml_namepath(uacpi_object*);
/*
* Resolve an AML namepath contained in a string object.
*
* This is only applicable to objects that are package elements. See an
* explanation of how this works in the comment above the declaration of
* uacpi_object_is_aml_namepath.
*
* This is a shorthand for:
* uacpi_data_view view;
* uacpi_object_get_string(object, &view);
*
* target_node = uacpi_namespace_node_resolve_from_aml_namepath(
* scope, view.text
* );
*/
uacpi_status uacpi_object_resolve_as_aml_namepath(
uacpi_object*, uacpi_namespace_node *scope, uacpi_namespace_node **out_node
);
/*
* Make the provided object a string/buffer.
* Takes in a constant view of the data to be stored in the object.
*
* NOTE: The data is copied to a separately allocated buffer and is not taken
* ownership of.
*/
uacpi_status uacpi_object_assign_string(uacpi_object*, uacpi_data_view in);
uacpi_status uacpi_object_assign_buffer(uacpi_object*, uacpi_data_view in);
typedef struct uacpi_object_array {
uacpi_object **objects;
uacpi_size count;
} uacpi_object_array;
/*
* Create a package object and store all of the objects in the array inside.
* The array is allowed to be empty.
*
* NOTE: the reference count of each object is incremented before being stored
* in the object. Client code must remove all of the locally created
* references at its own discretion.
*/
uacpi_object *uacpi_object_create_package(uacpi_object_array in);
/*
* Returns the list of objects stored in a package object.
*
* NOTE: the reference count of the objects stored inside is not incremented,
* which means destorying/overwriting the object also potentially destroys
* all of the objects stored inside unless the reference count is
* incremented by the client via uacpi_object_ref.
*/
uacpi_status uacpi_object_get_package(uacpi_object*, uacpi_object_array *out);
/*
* Make the provided object a package and store all of the objects in the array
* inside. The array is allowed to be empty.
*
* NOTE: the reference count of each object is incremented before being stored
* in the object. Client code must remove all of the locally created
* references at its own discretion.
*/
uacpi_status uacpi_object_assign_package(uacpi_object*, uacpi_object_array in);
/*
* Create a reference object and make it point to 'child'.
*
* NOTE: child's reference count is incremented by one. Client code must remove
* all of the locally created references at its own discretion.
*/
uacpi_object *uacpi_object_create_reference(uacpi_object *child);
/*
* Make the provided object a reference and make it point to 'child'.
*
* NOTE: child's reference count is incremented by one. Client code must remove
* all of the locally created references at its own discretion.
*/
uacpi_status uacpi_object_assign_reference(uacpi_object*, uacpi_object *child);
/*
* Retrieve the object pointed to by a reference object.
*
* NOTE: the reference count of the returned object is incremented by one and
* must be uacpi_object_unref'ed by the client when no longer needed.
*/
uacpi_status uacpi_object_get_dereferenced(uacpi_object*, uacpi_object **out);
typedef struct uacpi_processor_info {
uacpi_u8 id;
uacpi_u32 block_address;
uacpi_u8 block_length;
} uacpi_processor_info;
/*
* Returns the information about the provided processor object.
*/
uacpi_status uacpi_object_get_processor_info(
uacpi_object*, uacpi_processor_info *out
);
typedef struct uacpi_power_resource_info {
uacpi_u8 system_level;
uacpi_u16 resource_order;
} uacpi_power_resource_info;
/*
* Returns the information about the provided power resource object.
*/
uacpi_status uacpi_object_get_power_resource_info(
uacpi_object*, uacpi_power_resource_info *out
);
typedef enum uacpi_region_op {
// data => uacpi_region_attach_data
UACPI_REGION_OP_ATTACH = 0,
// data => uacpi_region_detach_data
UACPI_REGION_OP_DETACH,
// data => uacpi_region_rw_data
UACPI_REGION_OP_READ,
UACPI_REGION_OP_WRITE,
// data => uacpi_region_pcc_send_data
UACPI_REGION_OP_PCC_SEND,
// data => uacpi_region_gpio_rw_data
UACPI_REGION_OP_GPIO_READ,
UACPI_REGION_OP_GPIO_WRITE,
// data => uacpi_region_ipmi_rw_data
UACPI_REGION_OP_IPMI_COMMAND,
// data => uacpi_region_ffixedhw_rw_data
UACPI_REGION_OP_FFIXEDHW_COMMAND,
// data => uacpi_region_prm_rw_data
UACPI_REGION_OP_PRM_COMMAND,
// data => uacpi_region_serial_rw_data
UACPI_REGION_OP_SERIAL_READ,
UACPI_REGION_OP_SERIAL_WRITE,
} uacpi_region_op;
typedef struct uacpi_generic_region_info {
uacpi_u64 base;
uacpi_u64 length;
} uacpi_generic_region_info;
typedef struct uacpi_pcc_region_info {
uacpi_data_view buffer;
uacpi_u8 subspace_id;
} uacpi_pcc_region_info;
typedef struct uacpi_gpio_region_info
{
uacpi_u64 num_pins;
} uacpi_gpio_region_info;
typedef struct uacpi_region_attach_data {
void *handler_context;
uacpi_namespace_node *region_node;
union {
uacpi_generic_region_info generic_info;
uacpi_pcc_region_info pcc_info;
uacpi_gpio_region_info gpio_info;
};
void *out_region_context;
} uacpi_region_attach_data;
typedef struct uacpi_region_rw_data {
void *handler_context;
void *region_context;
union {
uacpi_phys_addr address;
uacpi_u64 offset;
};
uacpi_u64 value;
uacpi_u8 byte_width;
} uacpi_region_rw_data;
typedef struct uacpi_region_pcc_send_data {
void *handler_context;
void *region_context;
uacpi_data_view buffer;
} uacpi_region_pcc_send_data;
typedef struct uacpi_region_gpio_rw_data
{
void *handler_context;
void *region_context;
uacpi_data_view connection;
uacpi_u32 pin_offset;
uacpi_u32 num_pins;
uacpi_u64 value;
} uacpi_region_gpio_rw_data;
typedef struct uacpi_region_ipmi_rw_data
{
void *handler_context;
void *region_context;
uacpi_data_view in_out_message;
uacpi_u64 command;
} uacpi_region_ipmi_rw_data;
typedef uacpi_region_ipmi_rw_data uacpi_region_ffixedhw_rw_data;
typedef struct uacpi_region_prm_rw_data
{
void *handler_context;
void *region_context;
uacpi_data_view in_out_message;
} uacpi_region_prm_rw_data;
typedef enum uacpi_access_attribute {
UACPI_ACCESS_ATTRIBUTE_QUICK = 0x02,
UACPI_ACCESS_ATTRIBUTE_SEND_RECEIVE = 0x04,
UACPI_ACCESS_ATTRIBUTE_BYTE = 0x06,
UACPI_ACCESS_ATTRIBUTE_WORD = 0x08,
UACPI_ACCESS_ATTRIBUTE_BLOCK = 0x0A,
UACPI_ACCESS_ATTRIBUTE_BYTES = 0x0B,
UACPI_ACCESS_ATTRIBUTE_PROCESS_CALL = 0x0C,
UACPI_ACCESS_ATTRIBUTE_BLOCK_PROCESS_CALL = 0x0D,
UACPI_ACCESS_ATTRIBUTE_RAW_BYTES = 0x0E,
UACPI_ACCESS_ATTRIBUTE_RAW_PROCESS_BYTES = 0x0F,
} uacpi_access_attribute;
typedef struct uacpi_region_serial_rw_data {
void *handler_context;
void *region_context;
uacpi_u64 command;
uacpi_data_view connection;
uacpi_data_view in_out_buffer;
uacpi_access_attribute access_attribute;
/*
* Applicable if access_attribute is one of:
* - UACPI_ACCESS_ATTRIBUTE_BYTES
* - UACPI_ACCESS_ATTRIBUTE_RAW_BYTES
* - UACPI_ACCESS_ATTRIBUTE_RAW_PROCESS_BYTES
*/
uacpi_u8 access_length;
} uacpi_region_serial_rw_data;
typedef struct uacpi_region_detach_data {
void *handler_context;
void *region_context;
uacpi_namespace_node *region_node;
} uacpi_region_detach_data;
typedef uacpi_status (*uacpi_region_handler)
(uacpi_region_op op, uacpi_handle op_data);
typedef uacpi_status (*uacpi_notify_handler)
(uacpi_handle context, uacpi_namespace_node *node, uacpi_u64 value);
typedef enum uacpi_firmware_request_type {
UACPI_FIRMWARE_REQUEST_TYPE_BREAKPOINT,
UACPI_FIRMWARE_REQUEST_TYPE_FATAL,
} uacpi_firmware_request_type;
typedef struct uacpi_firmware_request {
uacpi_u8 type;
union {
// UACPI_FIRMWARE_REQUEST_BREAKPOINT
struct {
// The context of the method currently being executed
uacpi_handle ctx;
} breakpoint;
// UACPI_FIRMWARE_REQUEST_FATAL
struct {
uacpi_u8 type;
uacpi_u32 code;
uacpi_u64 arg;
} fatal;
};
} uacpi_firmware_request;
#define UACPI_INTERRUPT_NOT_HANDLED 0
#define UACPI_INTERRUPT_HANDLED 1
typedef uacpi_u32 uacpi_interrupt_ret;
typedef uacpi_interrupt_ret (*uacpi_interrupt_handler)(uacpi_handle);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,269 @@
#pragma once
#include <uacpi/types.h>
#include <uacpi/status.h>
#include <uacpi/kernel_api.h>
#include <uacpi/namespace.h>
#define UACPI_MAJOR 3
#define UACPI_MINOR 0
#define UACPI_PATCH 0
#ifdef UACPI_REDUCED_HARDWARE
#define UACPI_MAKE_STUB_FOR_REDUCED_HARDWARE(fn, ret) \
UACPI_NO_UNUSED_PARAMETER_WARNINGS_BEGIN \
static inline fn { return ret; } \
UACPI_NO_UNUSED_PARAMETER_WARNINGS_END
#define UACPI_STUB_IF_REDUCED_HARDWARE(fn) \
UACPI_MAKE_STUB_FOR_REDUCED_HARDWARE(fn,)
#define UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(fn) \
UACPI_MAKE_STUB_FOR_REDUCED_HARDWARE(fn, UACPI_STATUS_COMPILED_OUT)
#define UACPI_ALWAYS_OK_FOR_REDUCED_HARDWARE(fn) \
UACPI_MAKE_STUB_FOR_REDUCED_HARDWARE(fn, UACPI_STATUS_OK)
#else
#define UACPI_STUB_IF_REDUCED_HARDWARE(fn) fn;
#define UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(fn) fn;
#define UACPI_ALWAYS_OK_FOR_REDUCED_HARDWARE(fn) fn;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* Set up early access to the table subsystem. What this means is:
* - uacpi_table_find() and similar API becomes usable before the call to
* uacpi_initialize().
* - No kernel API besides logging and map/unmap will be invoked at this stage,
* allowing for heap and scheduling to still be fully offline.
* - The provided 'temporary_buffer' will be used as a temporary storage for the
* internal metadata about the tables (list, reference count, addresses,
* sizes, etc).
* - The 'temporary_buffer' is replaced with a normal heap buffer allocated via
* uacpi_kernel_alloc() after the call to uacpi_initialize() and can therefore
* be reclaimed by the kernel.
*
* The approximate overhead per table is 56 bytes, so a buffer of 4096 bytes
* yields about 73 tables in terms of capacity. uACPI also has an internal
* static buffer for tables, "UACPI_STATIC_TABLE_ARRAY_LEN", which is configured
* as 16 descriptors in length by default.
*
* This function is used to initialize the barebones mode, see
* UACPI_BAREBONES_MODE in config.h for more information.
*/
uacpi_status uacpi_setup_early_table_access(
void *temporary_buffer, uacpi_size buffer_size
);
/*
* Bad table checksum should be considered a fatal error
* (table load is fully aborted in this case)
*/
#define UACPI_FLAG_BAD_CSUM_FATAL (1ull << 0)
/*
* Unexpected table signature should be considered a fatal error
* (table load is fully aborted in this case)
*/
#define UACPI_FLAG_BAD_TBL_SIGNATURE_FATAL (1ull << 1)
/*
* Force uACPI to use RSDT even for later revisions
*/
#define UACPI_FLAG_BAD_XSDT (1ull << 2)
/*
* If this is set, ACPI mode is not entered during the call to
* uacpi_initialize. The caller is expected to enter it later at their own
* discretion by using uacpi_enter_acpi_mode().
*/
#define UACPI_FLAG_NO_ACPI_MODE (1ull << 3)
/*
* Don't create the \_OSI method when building the namespace.
* Only enable this if you're certain that having this method breaks your AML
* blob, a more atomic/granular interface management is available via osi.h
*/
#define UACPI_FLAG_NO_OSI (1ull << 4)
/*
* Validate table checksums at installation time instead of first use.
* Note that this makes uACPI map the entire table at once, which not all
* hosts are able to handle at early init.
*/
#define UACPI_FLAG_PROACTIVE_TBL_CSUM (1ull << 5)
#ifndef UACPI_BAREBONES_MODE
/*
* Initializes the uACPI subsystem, iterates & records all relevant RSDT/XSDT
* tables. Enters ACPI mode.
*
* 'flags' is any combination of UACPI_FLAG_* above
*/
uacpi_status uacpi_initialize(uacpi_u64 flags);
/*
* Parses & executes all of the DSDT/SSDT tables.
* Initializes the event subsystem.
*/
uacpi_status uacpi_namespace_load(void);
/*
* Initializes all the necessary objects in the namespaces by calling
* _STA/_INI etc.
*/
uacpi_status uacpi_namespace_initialize(void);
// Returns the current subsystem initialization level
uacpi_init_level uacpi_get_current_init_level(void);
/*
* Evaluate an object within the namespace and get back its value.
* Either root or path must be valid.
* A value of NULL for 'parent' implies uacpi_namespace_root() relative
* lookups, unless 'path' is already absolute.
*/
uacpi_status uacpi_eval(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object **ret
);
uacpi_status uacpi_eval_simple(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret
);
/*
* Same as uacpi_eval() but without a return value.
*/
uacpi_status uacpi_execute(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args
);
uacpi_status uacpi_execute_simple(
uacpi_namespace_node *parent, const uacpi_char *path
);
/*
* Same as uacpi_eval, but the return value type is validated against
* the 'ret_mask'. UACPI_STATUS_TYPE_MISMATCH is returned on error.
*/
uacpi_status uacpi_eval_typed(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object_type_bits ret_mask,
uacpi_object **ret
);
uacpi_status uacpi_eval_simple_typed(
uacpi_namespace_node *parent, const uacpi_char *path,
uacpi_object_type_bits ret_mask, uacpi_object **ret
);
/*
* A shorthand for uacpi_eval_typed with UACPI_OBJECT_INTEGER_BIT.
*/
uacpi_status uacpi_eval_integer(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_u64 *out_value
);
uacpi_status uacpi_eval_simple_integer(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_u64 *out_value
);
/*
* A shorthand for uacpi_eval_typed with
* UACPI_OBJECT_BUFFER_BIT | UACPI_OBJECT_STRING_BIT
*
* Use uacpi_object_get_string_or_buffer to retrieve the resulting buffer data.
*/
uacpi_status uacpi_eval_buffer_or_string(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object **ret
);
uacpi_status uacpi_eval_simple_buffer_or_string(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret
);
/*
* A shorthand for uacpi_eval_typed with UACPI_OBJECT_STRING_BIT.
*
* Use uacpi_object_get_string to retrieve the resulting buffer data.
*/
uacpi_status uacpi_eval_string(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object **ret
);
uacpi_status uacpi_eval_simple_string(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret
);
/*
* A shorthand for uacpi_eval_typed with UACPI_OBJECT_BUFFER_BIT.
*
* Use uacpi_object_get_buffer to retrieve the resulting buffer data.
*/
uacpi_status uacpi_eval_buffer(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object **ret
);
uacpi_status uacpi_eval_simple_buffer(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret
);
/*
* A shorthand for uacpi_eval_typed with UACPI_OBJECT_PACKAGE_BIT.
*
* Use uacpi_object_get_package to retrieve the resulting object array.
*/
uacpi_status uacpi_eval_package(
uacpi_namespace_node *parent, const uacpi_char *path,
const uacpi_object_array *args, uacpi_object **ret
);
uacpi_status uacpi_eval_simple_package(
uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret
);
/*
* Get the bitness of the currently loaded AML code according to the DSDT.
*
* Returns either 32 or 64.
*/
uacpi_status uacpi_get_aml_bitness(uacpi_u8 *out_bitness);
/*
* Helpers for entering & leaving ACPI mode. Note that ACPI mode is entered
* automatically during the call to uacpi_initialize().
*/
UACPI_ALWAYS_OK_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_enter_acpi_mode(void)
)
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_leave_acpi_mode(void)
)
/*
* Attempt to acquire the global lock for 'timeout' milliseconds.
* 0xFFFF implies infinite wait.
*
* On success, 'out_seq' is set to a unique sequence number for the current
* acquire transaction. This number is used for validation during release.
*/
uacpi_status uacpi_acquire_global_lock(uacpi_u16 timeout, uacpi_u32 *out_seq);
uacpi_status uacpi_release_global_lock(uacpi_u32 seq);
#endif // !UACPI_BAREBONES_MODE
/*
* Reset the global uACPI state by freeing all internally allocated data
* structures & resetting any global variables. After this call, uACPI must be
* re-initialized from scratch to be used again.
*
* This is called by uACPI automatically if a fatal error occurs during a call
* to uacpi_initialize/uacpi_namespace_load etc. in order to prevent accidental
* use of partially uninitialized subsystems.
*/
void uacpi_state_reset(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,192 @@
#pragma once
#include <uacpi/status.h>
#include <uacpi/types.h>
#include <uacpi/namespace.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UACPI_BAREBONES_MODE
/*
* Checks whether the device at 'node' matches any of the PNP ids provided in
* 'list' (terminated by a UACPI_NULL). This is done by first attempting to
* match the value returned from _HID and then the value(s) from _CID.
*
* Note that the presence of the device (_STA) is not verified here.
*/
uacpi_bool uacpi_device_matches_pnp_id(
uacpi_namespace_node *node,
const uacpi_char *const *list
);
/*
* Find all the devices in the namespace starting at 'parent' matching the
* specified 'hids' (terminated by a UACPI_NULL) against any value from _HID or
* _CID. Only devices reported as present via _STA are checked. Any matching
* devices are then passed to the 'cb'.
*/
uacpi_status uacpi_find_devices_at(
uacpi_namespace_node *parent,
const uacpi_char *const *hids,
uacpi_iteration_callback cb,
void *user
);
/*
* Same as uacpi_find_devices_at, except this starts at the root and only
* matches one hid.
*/
uacpi_status uacpi_find_devices(
const uacpi_char *hid,
uacpi_iteration_callback cb,
void *user
);
typedef enum uacpi_interrupt_model {
UACPI_INTERRUPT_MODEL_PIC = 0,
UACPI_INTERRUPT_MODEL_IOAPIC,
UACPI_INTERRUPT_MODEL_IOSAPIC,
UACPI_INTERRUPT_MODEL_PLATFORM_SPECIFIC,
UACPI_INTERRUPT_MODEL_GIC,
UACPI_INTERRUPT_MODEL_LPIC,
UACPI_INTERRUPT_MODEL_RINTC,
} uacpi_interrupt_model;
uacpi_status uacpi_set_interrupt_model(uacpi_interrupt_model);
typedef struct uacpi_pci_routing_table_entry {
uacpi_u32 address;
uacpi_u32 index;
uacpi_namespace_node *source;
uacpi_u8 pin;
} uacpi_pci_routing_table_entry;
typedef struct uacpi_pci_routing_table {
uacpi_size num_entries;
uacpi_pci_routing_table_entry entries[];
} uacpi_pci_routing_table;
void uacpi_free_pci_routing_table(uacpi_pci_routing_table*);
uacpi_status uacpi_get_pci_routing_table(
uacpi_namespace_node *parent, uacpi_pci_routing_table **out_table
);
typedef struct uacpi_id_string {
// size of the string including the null byte
uacpi_u32 size;
uacpi_char *value;
} uacpi_id_string;
void uacpi_free_id_string(uacpi_id_string *id);
/*
* Evaluate a device's _HID method and get its value.
* The returned struture must be freed using uacpi_free_id_string.
*/
uacpi_status uacpi_eval_hid(uacpi_namespace_node*, uacpi_id_string **out_id);
typedef struct uacpi_pnp_id_list {
// number of 'ids' in the list
uacpi_u32 num_ids;
// size of the 'ids' list including the string lengths
uacpi_u32 size;
// list of PNP ids
uacpi_id_string ids[];
} uacpi_pnp_id_list;
void uacpi_free_pnp_id_list(uacpi_pnp_id_list *list);
/*
* Evaluate a device's _CID method and get its value.
* The returned structure must be freed using uacpi_free_pnp_id_list.
*/
uacpi_status uacpi_eval_cid(uacpi_namespace_node*, uacpi_pnp_id_list **out_list);
/*
* Evaluate a device's _STA method and get its value.
* If this method is not found, the value of 'flags' is set to all ones.
*/
uacpi_status uacpi_eval_sta(uacpi_namespace_node*, uacpi_u32 *flags);
/*
* Evaluate a device's _ADR method and get its value.
*/
uacpi_status uacpi_eval_adr(uacpi_namespace_node*, uacpi_u64 *out);
/*
* Evaluate a device's _CLS method and get its value.
* The format of returned string is BBSSPP where:
* BB => Base Class (e.g. 01 => Mass Storage)
* SS => Sub-Class (e.g. 06 => SATA)
* PP => Programming Interface (e.g. 01 => AHCI)
* The returned struture must be freed using uacpi_free_id_string.
*/
uacpi_status uacpi_eval_cls(uacpi_namespace_node*, uacpi_id_string **out_id);
/*
* Evaluate a device's _UID method and get its value.
* The returned struture must be freed using uacpi_free_id_string.
*/
uacpi_status uacpi_eval_uid(uacpi_namespace_node*, uacpi_id_string **out_uid);
// uacpi_namespace_node_info->flags
#define UACPI_NS_NODE_INFO_HAS_ADR (1 << 0)
#define UACPI_NS_NODE_INFO_HAS_HID (1 << 1)
#define UACPI_NS_NODE_INFO_HAS_UID (1 << 2)
#define UACPI_NS_NODE_INFO_HAS_CID (1 << 3)
#define UACPI_NS_NODE_INFO_HAS_CLS (1 << 4)
#define UACPI_NS_NODE_INFO_HAS_SXD (1 << 5)
#define UACPI_NS_NODE_INFO_HAS_SXW (1 << 6)
typedef struct uacpi_namespace_node_info {
// Size of the entire structure
uacpi_u32 size;
// Object information
uacpi_object_name name;
uacpi_object_type type;
uacpi_u8 num_params;
// UACPI_NS_NODE_INFO_HAS_*
uacpi_u8 flags;
/*
* A mapping of [S1..S4] to the shallowest D state supported by the device
* in that S state.
*/
uacpi_u8 sxd[4];
/*
* A mapping of [S0..S4] to the deepest D state supported by the device
* in that S state to be able to wake itself.
*/
uacpi_u8 sxw[5];
uacpi_u64 adr;
uacpi_id_string hid;
uacpi_id_string uid;
uacpi_id_string cls;
uacpi_pnp_id_list cid;
} uacpi_namespace_node_info;
void uacpi_free_namespace_node_info(uacpi_namespace_node_info*);
/*
* Retrieve information about a namespace node. This includes the attached
* object's type, name, number of parameters (if it's a method), the result of
* evaluating _ADR, _UID, _CLS, _HID, _CID, as well as _SxD and _SxW.
*
* The returned structure must be freed with uacpi_free_namespace_node_info.
*/
uacpi_status uacpi_get_namespace_node_info(
uacpi_namespace_node *node, uacpi_namespace_node_info **out_info
);
#endif // !UACPI_BAREBONES_MODE
#ifdef __cplusplus
}
#endif