Signed-off-by: Jakub Czapiga <jacz@semihalf.com> Change-Id: Icc128212c1f72beb50caca671b4bada3507d3a1f Reviewed-on: https://review.coreboot.org/c/coreboot/+/50520 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
		
			
				
	
	
		
			218 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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);
 | |
| }
 |