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, param->buffer.length); 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, 0); 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 void wmi_unmarshal_acpi_object_undersized_test(struct kunit *test) 431 { 432 const union acpi_object obj = { 433 .integer = { 434 .type = ACPI_TYPE_INTEGER, 435 .value = 0xdeadbeef, 436 }, 437 }; 438 struct wmi_buffer result; 439 int ret; 440 441 ret = wmi_unmarshal_acpi_object(&obj, &result, sizeof(expected_single_integer) + 1); 442 if (ret < 0) 443 return; 444 445 kfree(result.data); 446 KUNIT_FAIL(test, "Undersized unmarshalling result was not rejected\n"); 447 } 448 449 static struct kunit_case wmi_marshalling_test_cases[] = { 450 KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test, 451 wmi_unmarshal_acpi_object_gen_params), 452 KUNIT_CASE_PARAM(wmi_marshal_string_test, 453 wmi_marshal_string_gen_params), 454 KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_failure_test, 455 wmi_unmarshal_acpi_object_failure_gen_params), 456 KUNIT_CASE_PARAM(wmi_marshal_string_failure_test, 457 wmi_marshal_string_failure_gen_params), 458 KUNIT_CASE(wmi_unmarshal_acpi_object_undersized_test), 459 {} 460 }; 461 462 static struct kunit_suite wmi_marshalling_test_suite = { 463 .name = "wmi_marshalling", 464 .test_cases = wmi_marshalling_test_cases, 465 }; 466 467 kunit_test_suite(wmi_marshalling_test_suite); 468 469 MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>"); 470 MODULE_DESCRIPTION("KUnit test for the ACPI-WMI marshalling code"); 471 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 472 MODULE_LICENSE("GPL"); 473