xref: /aosp_15_r20/external/coreboot/tests/acpi/acpigen-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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. */
decode_package_length(const char * ptr)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 
get_current_block_length(const char * base)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 
setup_acpigen(void ** state)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 
teardown_acpigen(void ** state)51 static int teardown_acpigen(void **state)
52 {
53 	free(*state);
54 	return 0;
55 }
56 
test_acpigen_single_if(void ** state)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 
create_nested_ifs_recursive(size_t stack_len[],u32 i,u32 n)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 
test_acpigen_nested_ifs(void ** state)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 
test_acpigen_write_package(void ** state)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 
test_acpigen_scope_with_contents(void ** state)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 
main(void)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 }
222