Skip to content

Core API Documentation

Kacper Słomiński edited this page Sep 22, 2023 · 13 revisions

LAI data types and concepts

In the following, we give an overview over LAI's core data types. All of those types are opaque structs.

A Note on Opaque Structs. Users are expected to employ API methods to manipulate opaque structs. That includes calling the correct functions to "destruct" the objects - failure to do so will lead to memory leaks. Note that explicitly modifying members of opaque structs or manipulating them in any other way (e.g., through memcpy) is explicitly not supported.

lai_nsnode_t

Represents a node in the ACPI namespace. Users only ever deal with pointers to this type. Most API functions expect ACPI namespace paths to be resolved to lai_nsnode_t * handles.

lai_variable_t

Represents a variable in AML; specifically, it stores an AML object. Users need to use lai_variable_t to pass arguments to control methods and to inspect their results.

/* Destructs an object of type lai_variable_t. */
void lai_var_finalize(lai_variable_t *var);

/* Assigns the value of an AML variable to another variable.
 * LAI passes AML objects by pointer, hence the result of
 * lai_var_assign() points to the same AML object as the source. */
void lai_var_assign(lai_variable_t *dest, lai_variable_t *src);

/* Moves the value of an AML variable to another variable.
 * This operation is slightly cheaper than lai_var_assign(),
 * but it resets the source to an empty variable. */
void lai_var_move(lai_variable_t *dest, lai_variable_t *src);

lai_state_t

Encapsulates the AML interpreter state. Users do not need to directly interact with it, but most core functions take a pointer to this struct.

/* Initializes an object of type lai_state_t. */
void lai_init_state(lai_state_t *state);

/* Destructs an object of type lai_state_t. */
void lai_finalize_state(lai_state_t *state);

/* __attribute__((cleanup)) magic to automatically call
 * lai_finalize_state() at the end of the current scope. */
#define LAI_CLEANUP_STATE /* [...] */

LAI_CLEANUP_STATE is the preferred way to ensure that a given lai_state_t object is destructed properly. This idiom renders it unnecessary to explicitly call lai_finalize_state. Usage example:

LAI_CLEANUP_STATE lai_state_t state;
lai_init_state(&state);
/* [...] */

lai_api_error_t

Contains an error in the LAI API

typedef enum lai_api_error {
    LAI_ERROR_NONE,
    LAI_ERROR_TYPE_MISMATCH,
    LAI_ERROR_NO_SUCH_NODE,
    LAI_ERROR_OUT_OF_BOUNDS,
    LAI_ERROR_EXECUTION_FAILURE,
    LAI_ERROR_ILLEGAL_ARGUMENTS,

    /* Evaluating external inputs (e.g., nodes of the ACPI namespace) returned an unexpected result.
     * Unlike LAI_ERROR_EXECUTION_FAILURE, this error does not indicate that
     * execution of AML failed; instead, the resulting object fails to satisfy some
     * expectation (e.g., it is of the wrong type, has an unexpected size, or consists of
     * unexpected contents) */
    LAI_ERROR_UNEXPECTED_RESULT,
    // Error given when end of iterator is reached, nothing to worry about
    LAI_ERROR_END_REACHED,
} lai_api_error_t;

A function is provided to convert a lai_api_error_t into a human readable string

const char *lai_api_error_to_string(lai_api_error_t);

Path resolution and the ACPI namespace

LAI provides various functions to resolve ACPI paths to lai_nsnode_t * handles:

/* Resolve a path in the ACPI namespace.
 * The path may be absolute or relative. Absolute paths start with a
 * backslash (\). Relative paths may start with zero or more carets (^) to
 * indicate that resolution should start at a parent of the context node.
 * 
 * Note that unlike in ASL, single segument paths are not special cases
 * for lai_resolve_path(); in particular, parent scopes are not searched
 * recursively for those paths. Use lai_resolve_search() if you want this
 * behavior.
 * 
 * If ctx_handle is NULL, the path is resolved relative to the root node. */
lai_nsnode_t *lai_resolve_path(lai_nsnode_t *ctx_handle, const char *path);

/* Recursively search for a single segment name in all parent scopes. */
lai_nsnode_t *lai_resolve_search(lai_nsnode_t *ctx_handle, const char *name);

To iterate over the entire ACPI namespace, LAI provides the following API:

/* Returns the root node of the ACPI namespace. */
lai_nsnode_t *lai_ns_get_root();

/* Returns the parent node of a given ACPI namespace node. */
lai_nsnode_t *lai_ns_get_parent(lai_nsnode_t *node);

/* Returns a child node of a given ACPI namespace node. */
lai_nsnode_t *lai_ns_get_child(lai_nsnode_t *node,
                                const char *name);

/* Helper struct that allows a single iteration over the entire
 * ACPI namespace. */
struct lai_ns_iterator; // Opaque struct.

/* Expands to a designated initializer for struct lai_ns_iterator. */
#define LAI_NS_ITERATOR_INITIALIZER /* [...] */

/* Returns a handle to the next ACPI namespace node or NULL if all
 * nodes have been returned already. */
lai_nsnode_t *lai_ns_iterate(struct lai_ns_iterator *iterator);


/* Helper struct that allows a single iteration over the all
 * children of a namespace node. */
struct lai_ns_child_iterator; // Opaque struct.

/* Expands to a designated initializer for struct lai_ns_child_iterator. */
#define LAI_NS_CHILD_ITERATOR_INITIALIZER(parent) /* [...] */

/* Returns a handle to the next child node or NULL if all
 * nodes have been returned already. */
lai_nsnode_t *lai_ns_child_iterate(struct lai_ns_child_iterator *iterator);

Manipulation of AML objects

enum lai_object_type {
    LAI_TYPE_NONE,
    LAI_TYPE_INTEGER,
    LAI_TYPE_STRING,
    LAI_TYPE_BUFFER,
    LAI_TYPE_PACKAGE,
    LAI_TYPE_DEVICE,
};

/* Return the type of an AML object.
 * Unlike the AML ObjectType() operator, this function does not transparently dereference
 * object references (e.g. those returned by Index() or RefOf()). */
enum lai_object_type lai_obj_get_type(lai_variable_t *object);

/* Get an integer out of an AML variable. */
lai_api_error_t lai_obj_get_integer(lai_variable_t *object, uint64_t *out);

/* Get an element of an AML package. */
lai_api_error_t lai_obj_get_pkg(lai_variable_t *object, size_t i, lai_variable_t *out);

/* Get a handle out of an AML variable. */
lai_api_error_t lai_obj_get_handle(lai_variable_t *object, lai_nsnode_t **out);

/* Make a clone (i.e., a deep copy) of an object.
 * This function clones strings, buffers and packages.
 * Packages are cloned recursively. */
void lai_clone_object(lai_variable_t *clone, lai_variable_t *object);

AML Evaluation

/* Evaluate an ACPI namespace node with a given handle. */
void lai_eval_args(lai_variable_t *result, lai_nsnode_t *handle, lai_state_t *state,
                   int argc, lai_variable_t *argv);

/* Like lai_eval_args() but takes the arguments using varargs.
 * Each argument must be given as a lai_variable_t *. The list is terminated by NULL. */
void lai_eval_largs(lai_variable_t *result, lai_nsnode_t *handle, lai_state_t *state,
                    ...);

/* Like lai_eval_largs() but takes a va_list. */
void lai_eval_vargs(lai_variable_t *result, lai_nsnode_t *handle, lai_state_t *state,
                    va_list vl);

/* Equivalent to lai_eval_args(result, handle, state, 0, NULL). */
void lai_eval(lai_variable_t *result, lai_nsnode_t *handle, lai_state_t *state);