diff options
-rw-r--r-- | tests/Makefile.inc | 4 | ||||
-rw-r--r-- | tests/acpi/Makefile.inc | 7 | ||||
-rw-r--r-- | tests/acpi/acpigen-test.c | 217 |
3 files changed, 226 insertions, 2 deletions
diff --git a/tests/Makefile.inc b/tests/Makefile.inc index a10e9bf73b..1e260fabba 100644 --- a/tests/Makefile.inc +++ b/tests/Makefile.inc @@ -59,8 +59,8 @@ stages:= decompressor bootblock romstage smm verstage stages+= ramstage rmodule postcar libagesa alltests:= -subdirs:= tests/arch tests/commonlib tests/console tests/cpu tests/device -subdirs+= tests/drivers tests/ec tests/lib tests/mainboard +subdirs:= tests/arch tests/acpi tests/commonlib tests/console tests/cpu +subdirs+= tests/device tests/drivers tests/ec tests/lib tests/mainboard subdirs+= tests/northbridge tests/security tests/soc tests/southbridge subdirs+= tests/superio tests/vendorcode diff --git a/tests/acpi/Makefile.inc b/tests/acpi/Makefile.inc new file mode 100644 index 0000000000..b0ef5fa7b6 --- /dev/null +++ b/tests/acpi/Makefile.inc @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +tests-y += acpigen-test + +acpigen-test-srcs += tests/acpi/acpigen-test.c +acpigen-test-srcs += src/acpi/acpigen.c +acpigen-test-srcs += tests/stubs/console.c diff --git a/tests/acpi/acpigen-test.c b/tests/acpi/acpigen-test.c new file mode 100644 index 0000000000..369ff29001 --- /dev/null +++ b/tests/acpi/acpigen-test.c @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <stdlib.h> +#include <types.h> +#include <tests/test.h> +#include <acpi/acpigen.h> + +#define ACPIGEN_TEST_BUFFER_SZ (16 * KiB) + +/* Returns AML package length. Works with normal and extended packages. + This implementation is independent from acpigen.c implementation of package length. */ +static u32 decode_package_length(const char *ptr) +{ + const u8 *aml = (u8 *)ptr; + const u32 offset = (aml[0] == EXT_OP_PREFIX ? 2 : 1); + u32 byte_zero_mask = 0x3F; /* Bits [0:5] */ + u32 byte_count = aml[offset] >> 6; + u32 package_length = 0; + + while (byte_count) { + package_length |= aml[offset + byte_count] << ((byte_count << 3) - 4); + byte_zero_mask = 0x0F; /* Use bits [0:3] of byte 0 */ + byte_count--; + } + + package_length |= (aml[offset] & byte_zero_mask); + + return package_length; +} + +static u32 get_current_block_length(const char *base) +{ + const u32 offset = (base[0] == EXT_OP_PREFIX ? 2 : 1); + + return ((uintptr_t)acpigen_get_current() - ((uintptr_t)base + offset)); +} + +static int setup_acpigen(void **state) +{ + void *buffer = malloc(ACPIGEN_TEST_BUFFER_SZ); + + if (buffer == NULL) + return -1; + + memset(buffer, 0, ACPIGEN_TEST_BUFFER_SZ); + + *state = buffer; + return 0; +} + +static int teardown_acpigen(void **state) +{ + free(*state); + return 0; +} + +static void test_acpigen_single_if(void **state) +{ + char *acpigen_buf = *state; + u32 if_package_length = 0; + u32 block_length = 0; + + acpigen_set_current(acpigen_buf); + + /* Create dummy AML */ + acpigen_write_if_lequal_op_int(LOCAL0_OP, 64); + + for (int i = 0; i < 20; ++i) + acpigen_write_store_ops(ZERO_OP, LOCAL1_OP); + + /* Close if */ + acpigen_pop_len(); + + if_package_length = decode_package_length(acpigen_buf); + block_length = get_current_block_length(acpigen_buf); + assert_int_equal(if_package_length, block_length); +} + +static void create_nested_ifs_recursive(char *stack_start[], char *stack_end[], u32 i, u32 n) +{ + if (i >= n) + return; + + stack_start[i] = acpigen_get_current(); + acpigen_write_if_and(LOCAL0_OP, ZERO_OP); + + for (int k = 0; k < 3; ++k) + acpigen_write_store_ops(ZERO_OP, LOCAL1_OP); + + create_nested_ifs_recursive(stack_start, stack_end, i + 1, n); + + acpigen_pop_len(); + stack_end[i] = acpigen_get_current(); +} + +static void test_acpigen_nested_ifs(void **state) +{ + char *acpigen_buf = *state; + const size_t nesting_level = 8; + char *block_start[8] = {0}; + char *block_end[8] = {0}; + + acpigen_set_current(acpigen_buf); + + create_nested_ifs_recursive(block_start, block_end, 0, nesting_level); + + for (int i = 0; i < nesting_level; ++i) + assert_int_equal(decode_package_length(block_start[i]), + block_end[i] - block_start[i] - 1); +} + +static void test_acpigen_write_package(void **state) +{ + char *acpigen_buf = *state; + u32 package_length; + u32 block_length; + + acpigen_set_current(acpigen_buf); + acpigen_write_package(3); + + acpigen_write_return_singleton_buffer(0xA); + acpigen_write_return_singleton_buffer(0x7); + acpigen_write_return_singleton_buffer(0xF); + + acpigen_pop_len(); + + package_length = decode_package_length(acpigen_buf); + block_length = get_current_block_length(acpigen_buf); + assert_int_equal(package_length, block_length); +} + +static void test_acpigen_scope_with_contents(void **state) +{ + char *acpigen_buf = *state; + char *block_start[8] = {0}; + u32 block_counter = 0; + u32 package_length; + u32 block_length; + + acpigen_set_current(acpigen_buf); + + /* Scope("\_SB") { */ + block_start[block_counter++] = acpigen_get_current(); + acpigen_write_scope("\\_SB"); + + /* Device("PCI0") { */ + block_start[block_counter++] = acpigen_get_current(); + acpigen_write_device("PCI0"); + + /* Name(INT1, 0x1234) */ + acpigen_write_name_integer("INT1", 0x1234); + + /* Name (_HID, EisaId ("PNP0A08")) // PCI Express Bus */ + acpigen_write_name("_HID"); + acpigen_emit_eisaid("PNP0A08"); + + /* Method(^BN00, 0, NotSerialized) { */ + block_start[block_counter++] = acpigen_get_current(); + acpigen_write_method("^BN00", 0); + + /* Return( 0x12 + ^PCI0.INT1 ) */ + acpigen_write_return_op(AND_OP); + acpigen_write_byte(0x12); + acpigen_emit_namestring("^PCI0.INT1"); + + /* } */ + acpigen_pop_len(); + block_counter--; + package_length = decode_package_length(block_start[block_counter]); + block_length = get_current_block_length(block_start[block_counter]); + assert_int_equal(package_length, block_length); + + /* Method (_BBN, 0, NotSerialized) { */ + block_start[block_counter++] = acpigen_get_current(); + acpigen_write_method("_BBN", 0); + + /* Return (BN00 ()) */ + acpigen_write_return_namestr("BN00"); + acpigen_emit_byte(0x0A); + + /* } */ + acpigen_pop_len(); + block_counter--; + package_length = decode_package_length(block_start[block_counter]); + block_length = get_current_block_length(block_start[block_counter]); + assert_int_equal(package_length, block_length); + + /* } */ + acpigen_pop_len(); + block_counter--; + package_length = decode_package_length(block_start[block_counter]); + block_length = get_current_block_length(block_start[block_counter]); + assert_int_equal(package_length, block_length); + + /* } */ + acpigen_pop_len(); + block_counter--; + package_length = decode_package_length(block_start[block_counter]); + block_length = get_current_block_length(block_start[block_counter]); + assert_int_equal(package_length, block_length); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_acpigen_single_if, + setup_acpigen, teardown_acpigen), + cmocka_unit_test_setup_teardown(test_acpigen_nested_ifs, + setup_acpigen, teardown_acpigen), + cmocka_unit_test_setup_teardown(test_acpigen_write_package, + setup_acpigen, teardown_acpigen), + cmocka_unit_test_setup_teardown(test_acpigen_scope_with_contents, + setup_acpigen, teardown_acpigen), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |