/ tests / acpi / acpigen-test.c
acpigen-test.c
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #include <stdlib.h>
  4  #include <types.h>
  5  #include <tests/test.h>
  6  #include <acpi/acpigen.h>
  7  
  8  #define ACPIGEN_TEST_BUFFER_SZ (16 * KiB)
  9  
 10  /* Returns AML package length. Works with normal and extended packages.
 11     This implementation is independent from acpigen.c implementation of package length. */
 12  static u32 decode_package_length(const char *ptr)
 13  {
 14  	const u8 *aml = (u8 *)ptr;
 15  	const u32 offset = (aml[0] == EXT_OP_PREFIX ? 2 : 1);
 16  	u32 byte_zero_mask = 0x3F; /* Bits [0:5] */
 17  	u32 byte_count = aml[offset] >> 6;
 18  	u32 package_length = 0;
 19  
 20  	while (byte_count) {
 21  		package_length |= aml[offset + byte_count] << ((byte_count << 3) - 4);
 22  		byte_zero_mask = 0x0F; /* Use bits [0:3] of byte 0 */
 23  		byte_count--;
 24  	}
 25  
 26  	package_length |= (aml[offset] & byte_zero_mask);
 27  
 28  	return package_length;
 29  }
 30  
 31  static u32 get_current_block_length(const char *base)
 32  {
 33  	const u32 offset = (base[0] == EXT_OP_PREFIX ? 2 : 1);
 34  
 35  	return ((uintptr_t)acpigen_get_current() - ((uintptr_t)base + offset));
 36  }
 37  
 38  static int setup_acpigen(void **state)
 39  {
 40  	void *buffer = malloc(ACPIGEN_TEST_BUFFER_SZ);
 41  
 42  	if (buffer == NULL)
 43  		return -1;
 44  
 45  	memset(buffer, 0, ACPIGEN_TEST_BUFFER_SZ);
 46  
 47  	*state = buffer;
 48  	return 0;
 49  }
 50  
 51  static int teardown_acpigen(void **state)
 52  {
 53  	free(*state);
 54  	return 0;
 55  }
 56  
 57  static void test_acpigen_single_if(void **state)
 58  {
 59  	char *acpigen_buf = *state;
 60  	u32 if_package_length = 0;
 61  	u32 block_length = 0;
 62  
 63  	acpigen_set_current(acpigen_buf);
 64  
 65  	/* Create dummy AML */
 66  	acpigen_write_if_lequal_op_int(LOCAL0_OP, 64);
 67  
 68  	for (int i = 0; i < 20; ++i)
 69  		acpigen_write_store_ops(ZERO_OP, LOCAL1_OP);
 70  
 71  	/* Close if */
 72  	acpigen_pop_len();
 73  
 74  	if_package_length = decode_package_length(acpigen_buf);
 75  	block_length = get_current_block_length(acpigen_buf);
 76  	assert_int_equal(if_package_length, block_length);
 77  }
 78  
 79  static void create_nested_ifs_recursive(size_t stack_len[], u32 i, u32 n)
 80  {
 81  	if (i >= n)
 82  		return;
 83  
 84  	char *const start = acpigen_get_current();
 85  	acpigen_write_if_and(LOCAL0_OP, ZERO_OP);
 86  
 87  	for (int k = 0; k < 3; ++k)
 88  		acpigen_write_store_ops(ZERO_OP, LOCAL1_OP);
 89  
 90  	create_nested_ifs_recursive(stack_len, i + 1, n);
 91  
 92  	acpigen_pop_len();
 93  	stack_len[i] = acpigen_get_current() - start;
 94  }
 95  
 96  static void test_acpigen_nested_ifs(void **state)
 97  {
 98  	char *acpigen_buf = *state;
 99  	const size_t nesting_level = 8;
100  	size_t block_len[8] = {0};
101  
102  	acpigen_set_current(acpigen_buf);
103  
104  	create_nested_ifs_recursive(block_len, 0, nesting_level);
105  
106  	for (int i = 0, j = 0; i < nesting_level; ++i, ++j) {
107  		/* Find next if op */
108  		for (; j < ACPIGEN_TEST_BUFFER_SZ; ++j) {
109  			if ((u8)acpigen_buf[j] == IF_OP)
110  				break;
111  		}
112  		assert_int_equal(decode_package_length(acpigen_buf + j), block_len[i] - 1);
113  	}
114  }
115  
116  static void test_acpigen_write_package(void **state)
117  {
118  	char *acpigen_buf = *state;
119  	u32 package_length;
120  	u32 block_length;
121  
122  	acpigen_set_current(acpigen_buf);
123  	acpigen_write_package(3);
124  
125  	acpigen_write_return_singleton_buffer(0xA);
126  	acpigen_write_return_singleton_buffer(0x7);
127  	acpigen_write_return_singleton_buffer(0xF);
128  
129  	acpigen_pop_len();
130  
131  	package_length = decode_package_length(acpigen_buf);
132  	block_length = get_current_block_length(acpigen_buf);
133  	assert_int_equal(package_length, block_length);
134  }
135  
136  static void test_acpigen_scope_with_contents(void **state)
137  {
138  	char *acpigen_buf = *state;
139  	char *block_start[8] = {0};
140  	u32 block_counter = 0;
141  	u32 package_length;
142  	u32 block_length;
143  
144  	acpigen_set_current(acpigen_buf);
145  
146  	/* Scope("\_SB") { */
147  	block_start[block_counter++] = acpigen_get_current();
148  	acpigen_write_scope("\\_SB");
149  
150  	/* Device("PCI0") { */
151  	block_start[block_counter++] = acpigen_get_current();
152  	acpigen_write_device("PCI0");
153  
154  	/* Name(INT1, 0x1234) */
155  	acpigen_write_name_integer("INT1", 0x1234);
156  
157  	/* Name (_HID, EisaId ("PNP0A08")) // PCI Express Bus */
158  	acpigen_write_name("_HID");
159  	acpigen_emit_eisaid("PNP0A08");
160  
161  	/* Method(^BN00, 0, NotSerialized) { */
162  	block_start[block_counter++] = acpigen_get_current();
163  	acpigen_write_method("^BN00", 0);
164  
165  	/* Return( 0x12 + ^PCI0.INT1 ) */
166  	acpigen_write_return_op(AND_OP);
167  	acpigen_write_byte(0x12);
168  	acpigen_emit_namestring("^PCI0.INT1");
169  
170  	/* } */
171  	acpigen_pop_len();
172  	block_counter--;
173  	package_length = decode_package_length(block_start[block_counter]);
174  	block_length = get_current_block_length(block_start[block_counter]);
175  	assert_int_equal(package_length, block_length);
176  
177  	/* Method (_BBN, 0, NotSerialized) { */
178  	block_start[block_counter++] = acpigen_get_current();
179  	acpigen_write_method("_BBN", 0);
180  
181  	/* Return (BN00 ()) */
182  	acpigen_write_return_namestr("BN00");
183  	acpigen_emit_byte(0x0A);
184  
185  	/* } */
186  	acpigen_pop_len();
187  	block_counter--;
188  	package_length = decode_package_length(block_start[block_counter]);
189  	block_length = get_current_block_length(block_start[block_counter]);
190  	assert_int_equal(package_length, block_length);
191  
192  	/* } */
193  	acpigen_pop_len();
194  	block_counter--;
195  	package_length = decode_package_length(block_start[block_counter]);
196  	block_length = get_current_block_length(block_start[block_counter]);
197  	assert_int_equal(package_length, block_length);
198  
199  	/* } */
200  	acpigen_pop_len();
201  	block_counter--;
202  	package_length = decode_package_length(block_start[block_counter]);
203  	block_length = get_current_block_length(block_start[block_counter]);
204  	assert_int_equal(package_length, block_length);
205  }
206  
207  int main(void)
208  {
209  	const struct CMUnitTest tests[] = {
210  		cmocka_unit_test_setup_teardown(test_acpigen_single_if, setup_acpigen,
211  						teardown_acpigen),
212  		cmocka_unit_test_setup_teardown(test_acpigen_nested_ifs, setup_acpigen,
213  						teardown_acpigen),
214  		cmocka_unit_test_setup_teardown(test_acpigen_write_package, setup_acpigen,
215  						teardown_acpigen),
216  		cmocka_unit_test_setup_teardown(test_acpigen_scope_with_contents, setup_acpigen,
217  						teardown_acpigen),
218  	};
219  
220  	return cb_run_group_tests(tests, NULL, NULL);
221  }