blob: 0d261e22d97ed43350955f7865aad32b89054a98 [file] [log] [blame]
Jakub Czapiga168b38b2021-02-11 12:59:51 +01001/* 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. */
12static 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);
Jakub Czapigac08b6a72022-01-10 13:36:47 +000016 u32 byte_zero_mask = 0x3F; /* Bits [0:5] */
Jakub Czapiga168b38b2021-02-11 12:59:51 +010017 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
31static 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
38static 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
51static int teardown_acpigen(void **state)
52{
53 free(*state);
54 return 0;
55}
56
57static 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
Nico Huber043f3392023-11-11 00:06:55 +010079static void create_nested_ifs_recursive(size_t stack_len[], u32 i, u32 n)
Jakub Czapiga168b38b2021-02-11 12:59:51 +010080{
81 if (i >= n)
82 return;
83
Nico Huber043f3392023-11-11 00:06:55 +010084 char *const start = acpigen_get_current();
Jakub Czapiga168b38b2021-02-11 12:59:51 +010085 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
Nico Huber043f3392023-11-11 00:06:55 +010090 create_nested_ifs_recursive(stack_len, i + 1, n);
Jakub Czapiga168b38b2021-02-11 12:59:51 +010091
92 acpigen_pop_len();
Nico Huber043f3392023-11-11 00:06:55 +010093 stack_len[i] = acpigen_get_current() - start;
Jakub Czapiga168b38b2021-02-11 12:59:51 +010094}
95
96static void test_acpigen_nested_ifs(void **state)
97{
98 char *acpigen_buf = *state;
99 const size_t nesting_level = 8;
Nico Huber043f3392023-11-11 00:06:55 +0100100 size_t block_len[8] = {0};
Jakub Czapiga168b38b2021-02-11 12:59:51 +0100101
102 acpigen_set_current(acpigen_buf);
103
Nico Huber043f3392023-11-11 00:06:55 +0100104 create_nested_ifs_recursive(block_len, 0, nesting_level);
Jakub Czapiga168b38b2021-02-11 12:59:51 +0100105
Nico Huber043f3392023-11-11 00:06:55 +0100106 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 }
Jakub Czapiga168b38b2021-02-11 12:59:51 +0100114}
115
116static 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
136static 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
207int main(void)
208{
209 const struct CMUnitTest tests[] = {
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000210 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),
Jakub Czapiga168b38b2021-02-11 12:59:51 +0100218 };
219
Jakub Czapiga7c6081e2021-08-25 16:27:35 +0200220 return cb_run_group_tests(tests, NULL, NULL);
Jakub Czapiga168b38b2021-02-11 12:59:51 +0100221}