1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * KUnit test for the ACPI-WMI marshalling code. 4 * 5 * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de> 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/align.h> 10 #include <linux/module.h> 11 #include <linux/slab.h> 12 #include <linux/string.h> 13 #include <linux/types.h> 14 #include <linux/wmi.h> 15 16 #include <kunit/resource.h> 17 #include <kunit/test.h> 18 19 #include "../internal.h" 20 21 struct wmi_acpi_param { 22 const char *name; 23 const union acpi_object obj; 24 const struct wmi_buffer buffer; 25 }; 26 27 struct wmi_string_param { 28 const char *name; 29 const char *string; 30 const struct wmi_buffer buffer; 31 }; 32 33 struct wmi_invalid_acpi_param { 34 const char *name; 35 const union acpi_object obj; 36 }; 37 38 struct wmi_invalid_string_param { 39 const char *name; 40 const struct wmi_buffer buffer; 41 }; 42 43 /* 0xdeadbeef */ 44 static u8 expected_single_integer[] = { 45 0xef, 0xbe, 0xad, 0xde, 46 }; 47 48 /* "TEST" */ 49 static u8 expected_single_string[] = { 50 0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00, 51 }; 52 53 static u8 test_buffer[] = { 54 0xab, 0xcd, 55 }; 56 57 static u8 expected_single_buffer[] = { 58 0xab, 0xcd, 59 }; 60 61 static union acpi_object simple_package_elements[] = { 62 { 63 .buffer = { 64 .type = ACPI_TYPE_BUFFER, 65 .length = sizeof(test_buffer), 66 .pointer = test_buffer, 67 }, 68 }, 69 { 70 .integer = { 71 .type = ACPI_TYPE_INTEGER, 72 .value = 0x01020304, 73 }, 74 }, 75 }; 76 77 static u8 expected_simple_package[] = { 78 0xab, 0xcd, 79 0x00, 0x00, 80 0x04, 0x03, 0x02, 0x01, 81 }; 82 83 static u8 test_small_buffer[] = { 84 0xde, 85 }; 86 87 static union acpi_object complex_package_elements[] = { 88 { 89 .integer = { 90 .type = ACPI_TYPE_INTEGER, 91 .value = 0xdeadbeef, 92 }, 93 }, 94 { 95 .buffer = { 96 .type = ACPI_TYPE_BUFFER, 97 .length = sizeof(test_small_buffer), 98 .pointer = test_small_buffer, 99 }, 100 }, 101 { 102 .string = { 103 .type = ACPI_TYPE_STRING, 104 .length = sizeof("TEST") - 1, 105 .pointer = "TEST", 106 }, 107 }, 108 { 109 .buffer = { 110 .type = ACPI_TYPE_BUFFER, 111 .length = sizeof(test_small_buffer), 112 .pointer = test_small_buffer, 113 }, 114 }, 115 { 116 .integer = { 117 .type = ACPI_TYPE_INTEGER, 118 .value = 0x01020304, 119 }, 120 } 121 }; 122 123 static u8 expected_complex_package[] = { 124 0xef, 0xbe, 0xad, 0xde, 125 0xde, 126 0x00, 127 0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00, 128 0xde, 129 0x00, 130 0x04, 0x03, 0x02, 0x01, 131 }; 132 133 static const struct wmi_acpi_param wmi_acpi_params_array[] = { 134 { 135 .name = "single_integer", 136 .obj = { 137 .integer = { 138 .type = ACPI_TYPE_INTEGER, 139 .value = 0xdeadbeef, 140 }, 141 }, 142 .buffer = { 143 .data = expected_single_integer, 144 .length = sizeof(expected_single_integer), 145 }, 146 }, 147 { 148 .name = "single_string", 149 .obj = { 150 .string = { 151 .type = ACPI_TYPE_STRING, 152 .length = sizeof("TEST") - 1, 153 .pointer = "TEST", 154 }, 155 }, 156 .buffer = { 157 .data = expected_single_string, 158 .length = sizeof(expected_single_string), 159 }, 160 }, 161 { 162 .name = "single_buffer", 163 .obj = { 164 .buffer = { 165 .type = ACPI_TYPE_BUFFER, 166 .length = sizeof(test_buffer), 167 .pointer = test_buffer, 168 }, 169 }, 170 .buffer = { 171 .data = expected_single_buffer, 172 .length = sizeof(expected_single_buffer), 173 }, 174 }, 175 { 176 .name = "simple_package", 177 .obj = { 178 .package = { 179 .type = ACPI_TYPE_PACKAGE, 180 .count = ARRAY_SIZE(simple_package_elements), 181 .elements = simple_package_elements, 182 }, 183 }, 184 .buffer = { 185 .data = expected_simple_package, 186 .length = sizeof(expected_simple_package), 187 }, 188 }, 189 { 190 .name = "complex_package", 191 .obj = { 192 .package = { 193 .type = ACPI_TYPE_PACKAGE, 194 .count = ARRAY_SIZE(complex_package_elements), 195 .elements = complex_package_elements, 196 }, 197 }, 198 .buffer = { 199 .data = expected_complex_package, 200 .length = sizeof(expected_complex_package), 201 }, 202 }, 203 }; 204 205 static void wmi_acpi_param_get_desc(const struct wmi_acpi_param *param, char *desc) 206 { 207 strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); 208 } 209 210 KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object, wmi_acpi_params_array, wmi_acpi_param_get_desc); 211 212 /* "WMI\0" */ 213 static u8 padded_wmi_string[] = { 214 0x0a, 0x00, 215 0x57, 0x00, 216 0x4D, 0x00, 217 0x49, 0x00, 218 0x00, 0x00, 219 0x00, 0x00, 220 }; 221 222 static const struct wmi_string_param wmi_string_params_array[] = { 223 { 224 .name = "test", 225 .string = "TEST", 226 .buffer = { 227 .length = sizeof(expected_single_string), 228 .data = expected_single_string, 229 }, 230 }, 231 { 232 .name = "padded", 233 .string = "WMI", 234 .buffer = { 235 .length = sizeof(padded_wmi_string), 236 .data = padded_wmi_string, 237 }, 238 }, 239 }; 240 241 static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc) 242 { 243 strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); 244 } 245 246 KUNIT_ARRAY_PARAM(wmi_marshal_string, wmi_string_params_array, wmi_string_param_get_desc); 247 248 static union acpi_object nested_package_elements[] = { 249 { 250 .package = { 251 .type = ACPI_TYPE_PACKAGE, 252 .count = ARRAY_SIZE(simple_package_elements), 253 .elements = simple_package_elements, 254 }, 255 } 256 }; 257 258 static const struct wmi_invalid_acpi_param wmi_invalid_acpi_params_array[] = { 259 { 260 .name = "nested_package", 261 .obj = { 262 .package = { 263 .type = ACPI_TYPE_PACKAGE, 264 .count = ARRAY_SIZE(nested_package_elements), 265 .elements = nested_package_elements, 266 }, 267 }, 268 }, 269 { 270 .name = "reference", 271 .obj = { 272 .reference = { 273 .type = ACPI_TYPE_LOCAL_REFERENCE, 274 .actual_type = ACPI_TYPE_ANY, 275 .handle = NULL, 276 }, 277 }, 278 }, 279 { 280 .name = "processor", 281 .obj = { 282 .processor = { 283 .type = ACPI_TYPE_PROCESSOR, 284 .proc_id = 0, 285 .pblk_address = 0, 286 .pblk_length = 0, 287 }, 288 }, 289 }, 290 { 291 .name = "power_resource", 292 .obj = { 293 .power_resource = { 294 .type = ACPI_TYPE_POWER, 295 .system_level = 0, 296 .resource_order = 0, 297 }, 298 }, 299 }, 300 }; 301 302 static void wmi_invalid_acpi_param_get_desc(const struct wmi_invalid_acpi_param *param, char *desc) 303 { 304 strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); 305 } 306 307 KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object_failure, wmi_invalid_acpi_params_array, 308 wmi_invalid_acpi_param_get_desc); 309 310 static u8 oversized_wmi_string[] = { 311 0x04, 0x00, 0x00, 0x00, 312 }; 313 314 /* 315 * The error is that 3 bytes can not hold UTF-16 characters 316 * without cutting of the last one. 317 */ 318 static u8 undersized_wmi_string[] = { 319 0x03, 0x00, 0x00, 0x00, 0x00, 320 }; 321 322 static u8 non_ascii_wmi_string[] = { 323 0x04, 0x00, 0xC4, 0x00, 0x00, 0x00, 324 }; 325 326 static const struct wmi_invalid_string_param wmi_invalid_string_params_array[] = { 327 { 328 .name = "empty_buffer", 329 .buffer = { 330 .length = 0, 331 .data = ZERO_SIZE_PTR, 332 }, 333 334 }, 335 { 336 .name = "oversized", 337 .buffer = { 338 .length = sizeof(oversized_wmi_string), 339 .data = oversized_wmi_string, 340 }, 341 }, 342 { 343 .name = "undersized", 344 .buffer = { 345 .length = sizeof(undersized_wmi_string), 346 .data = undersized_wmi_string, 347 }, 348 }, 349 { 350 .name = "non_ascii", 351 .buffer = { 352 .length = sizeof(non_ascii_wmi_string), 353 .data = non_ascii_wmi_string, 354 }, 355 }, 356 }; 357 358 static void wmi_invalid_string_param_get_desc(const struct wmi_invalid_string_param *param, 359 char *desc) 360 { 361 strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); 362 } 363 364 KUNIT_ARRAY_PARAM(wmi_marshal_string_failure, wmi_invalid_string_params_array, 365 wmi_invalid_string_param_get_desc); 366 367 KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *); 368 369 static void wmi_unmarshal_acpi_object_test(struct kunit *test) 370 { 371 const struct wmi_acpi_param *param = test->param_value; 372 struct wmi_buffer result; 373 int ret; 374 375 ret = wmi_unmarshal_acpi_object(¶m->obj, &result); 376 if (ret < 0) 377 KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n"); 378 379 kunit_add_action(test, kfree_wrapper, result.data); 380 381 KUNIT_EXPECT_TRUE(test, IS_ALIGNED((uintptr_t)result.data, 8)); 382 KUNIT_EXPECT_EQ(test, result.length, param->buffer.length); 383 KUNIT_EXPECT_MEMEQ(test, result.data, param->buffer.data, result.length); 384 } 385 386 static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test) 387 { 388 const struct wmi_invalid_acpi_param *param = test->param_value; 389 struct wmi_buffer result; 390 int ret; 391 392 ret = wmi_unmarshal_acpi_object(¶m->obj, &result); 393 if (ret < 0) 394 return; 395 396 kfree(result.data); 397 KUNIT_FAIL(test, "Invalid ACPI object was not rejected\n"); 398 } 399 400 static void wmi_marshal_string_test(struct kunit *test) 401 { 402 const struct wmi_string_param *param = test->param_value; 403 struct acpi_buffer result; 404 int ret; 405 406 ret = wmi_marshal_string(¶m->buffer, &result); 407 if (ret < 0) 408 KUNIT_FAIL_AND_ABORT(test, "Marshalling of WMI string failed\n"); 409 410 kunit_add_action(test, kfree_wrapper, result.pointer); 411 412 KUNIT_EXPECT_EQ(test, result.length, strlen(param->string)); 413 KUNIT_EXPECT_STREQ(test, result.pointer, param->string); 414 } 415 416 static void wmi_marshal_string_failure_test(struct kunit *test) 417 { 418 const struct wmi_invalid_string_param *param = test->param_value; 419 struct acpi_buffer result; 420 int ret; 421 422 ret = wmi_marshal_string(¶m->buffer, &result); 423 if (ret < 0) 424 return; 425 426 kfree(result.pointer); 427 KUNIT_FAIL(test, "Invalid string was not rejected\n"); 428 } 429 430 static struct kunit_case wmi_marshalling_test_cases[] = { 431 KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test, 432 wmi_unmarshal_acpi_object_gen_params), 433 KUNIT_CASE_PARAM(wmi_marshal_string_test, 434 wmi_marshal_string_gen_params), 435 KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_failure_test, 436 wmi_unmarshal_acpi_object_failure_gen_params), 437 KUNIT_CASE_PARAM(wmi_marshal_string_failure_test, 438 wmi_marshal_string_failure_gen_params), 439 {} 440 }; 441 442 static struct kunit_suite wmi_marshalling_test_suite = { 443 .name = "wmi_marshalling", 444 .test_cases = wmi_marshalling_test_cases, 445 }; 446 447 kunit_test_suite(wmi_marshalling_test_suite); 448 449 MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>"); 450 MODULE_DESCRIPTION("KUnit test for the ACPI-WMI marshalling code"); 451 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 452 MODULE_LICENSE("GPL"); 453