diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index bcb288eab4..caf792b5d2 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -25,6 +25,7 @@ #include #include #include "hw/acpi/aml-build.h" +#include "qemu/bswap.h" GArray *build_alloc_array(void) { @@ -257,3 +258,80 @@ void build_append_int(GArray *table, uint32_t value) build_append_value(table, value, 4); } } + +static GPtrArray *alloc_list; + +static Aml *aml_alloc(void) +{ + Aml *var = g_new0(typeof(*var), 1); + + g_ptr_array_add(alloc_list, var); + var->block_flags = AML_NO_OPCODE; + var->buf = build_alloc_array(); + return var; +} + +static void aml_free(gpointer data) +{ + Aml *var = data; + build_free_array(var->buf); +} + +Aml *init_aml_allocator(void) +{ + Aml *var; + + assert(!alloc_list); + alloc_list = g_ptr_array_new_with_free_func(aml_free); + var = aml_alloc(); + return var; +} + +void free_aml_allocator(void) +{ + g_ptr_array_free(alloc_list, true); + alloc_list = 0; +} + +/* pack data with DefBuffer encoding */ +static void build_buffer(GArray *array, uint8_t op) +{ + GArray *data = build_alloc_array(); + + build_append_int(data, array->len); + g_array_prepend_vals(array, data->data, data->len); + build_free_array(data); + build_package(array, op); +} + +void aml_append(Aml *parent_ctx, Aml *child) +{ + switch (child->block_flags) { + case AML_OPCODE: + build_append_byte(parent_ctx->buf, child->op); + break; + case AML_EXT_PACKAGE: + build_extop_package(child->buf, child->op); + break; + case AML_PACKAGE: + build_package(child->buf, child->op); + break; + case AML_RES_TEMPLATE: + build_append_byte(child->buf, 0x79); /* EndTag */ + /* + * checksum operations are treated as succeeded if checksum + * field is zero. [ACPI Spec 1.0b, 6.4.2.8 End Tag] + */ + build_append_byte(child->buf, 0); + /* fall through, to pack resources in buffer */ + case AML_BUFFER: + build_buffer(child->buf, child->op); + break; + case AML_NO_OPCODE: + break; + default: + assert(0); + break; + } + build_append_array(parent_ctx->buf, child->buf); +} diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 199f003265..1e1b03bc4e 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -5,6 +5,61 @@ #include #include "qemu/compiler.h" +typedef enum { + AML_NO_OPCODE = 0,/* has only data */ + AML_OPCODE, /* has opcode optionally followed by data */ + AML_PACKAGE, /* has opcode and uses PkgLength for its length */ + AML_EXT_PACKAGE, /* ame as AML_PACKAGE but also has 'ExOpPrefix' */ + AML_BUFFER, /* data encoded as 'DefBuffer' */ + AML_RES_TEMPLATE, /* encoded as ResourceTemplate macro */ +} AmlBlockFlags; + +struct Aml { + GArray *buf; + + /*< private >*/ + uint8_t op; + AmlBlockFlags block_flags; +}; +typedef struct Aml Aml; + +/** + * init_aml_allocator: + * + * Called for initializing API allocator which allow to use + * AML API. + * Returns: toplevel container which accumulates all other + * AML elements for a table. + */ +Aml *init_aml_allocator(void); + +/** + * free_aml_allocator: + * + * Releases all elements used by AML API, frees associated memory + * and invalidates AML allocator. After this call @init_aml_allocator + * should be called again if AML API is to be used again. + */ +void free_aml_allocator(void); + +/** + * aml_append: + * @parent_ctx: context to which @child element is added + * @child: element that is copied into @parent_ctx context + * + * Joins Aml elements together and helps to construct AML tables + * Examle of usage: + * Aml *table = aml_def_block("SSDT", ...); + * Aml *sb = aml_scope("\_SB"); + * Aml *dev = aml_device("PCI0"); + * + * aml_append(dev, aml_name_decl("HID", aml_eisaid("PNP0A03"))); + * aml_append(sb, dev); + * aml_append(table, sb); + */ +void aml_append(Aml *parent_ctx, Aml *child); + +/* other helpers */ GArray *build_alloc_array(void); void build_free_array(GArray *array); void build_prepend_byte(GArray *array, uint8_t val);