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 }