// SPDX-License-Identifier: GPL-2.0-or-later /* * KUnit test for the ACPI-WMI marshalling code. * * Copyright (C) 2025 Armin Wolf */ #include #include #include #include #include #include #include #include #include #include "../internal.h" struct wmi_acpi_param { const char *name; const union acpi_object obj; const struct wmi_buffer buffer; }; struct wmi_string_param { const char *name; const char *string; const struct wmi_buffer buffer; }; struct wmi_invalid_acpi_param { const char *name; const union acpi_object obj; }; struct wmi_invalid_string_param { const char *name; const struct wmi_buffer buffer; }; /* 0xdeadbeef */ static u8 expected_single_integer[] = { 0xef, 0xbe, 0xad, 0xde, }; /* "TEST" */ static u8 expected_single_string[] = { 0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00, }; static u8 test_buffer[] = { 0xab, 0xcd, }; static u8 expected_single_buffer[] = { 0xab, 0xcd, }; static union acpi_object simple_package_elements[] = { { .buffer = { .type = ACPI_TYPE_BUFFER, .length = sizeof(test_buffer), .pointer = test_buffer, }, }, { .integer = { .type = ACPI_TYPE_INTEGER, .value = 0x01020304, }, }, }; static u8 expected_simple_package[] = { 0xab, 0xcd, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, }; static u8 test_small_buffer[] = { 0xde, }; static union acpi_object complex_package_elements[] = { { .integer = { .type = ACPI_TYPE_INTEGER, .value = 0xdeadbeef, }, }, { .buffer = { .type = ACPI_TYPE_BUFFER, .length = sizeof(test_small_buffer), .pointer = test_small_buffer, }, }, { .string = { .type = ACPI_TYPE_STRING, .length = sizeof("TEST") - 1, .pointer = "TEST", }, }, { .buffer = { .type = ACPI_TYPE_BUFFER, .length = sizeof(test_small_buffer), .pointer = test_small_buffer, }, }, { .integer = { .type = ACPI_TYPE_INTEGER, .value = 0x01020304, }, } }; static u8 expected_complex_package[] = { 0xef, 0xbe, 0xad, 0xde, 0xde, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00, 0xde, 0x00, 0x04, 0x03, 0x02, 0x01, }; static const struct wmi_acpi_param wmi_acpi_params_array[] = { { .name = "single_integer", .obj = { .integer = { .type = ACPI_TYPE_INTEGER, .value = 0xdeadbeef, }, }, .buffer = { .data = expected_single_integer, .length = sizeof(expected_single_integer), }, }, { .name = "single_string", .obj = { .string = { .type = ACPI_TYPE_STRING, .length = sizeof("TEST") - 1, .pointer = "TEST", }, }, .buffer = { .data = expected_single_string, .length = sizeof(expected_single_string), }, }, { .name = "single_buffer", .obj = { .buffer = { .type = ACPI_TYPE_BUFFER, .length = sizeof(test_buffer), .pointer = test_buffer, }, }, .buffer = { .data = expected_single_buffer, .length = sizeof(expected_single_buffer), }, }, { .name = "simple_package", .obj = { .package = { .type = ACPI_TYPE_PACKAGE, .count = ARRAY_SIZE(simple_package_elements), .elements = simple_package_elements, }, }, .buffer = { .data = expected_simple_package, .length = sizeof(expected_simple_package), }, }, { .name = "complex_package", .obj = { .package = { .type = ACPI_TYPE_PACKAGE, .count = ARRAY_SIZE(complex_package_elements), .elements = complex_package_elements, }, }, .buffer = { .data = expected_complex_package, .length = sizeof(expected_complex_package), }, }, }; static void wmi_acpi_param_get_desc(const struct wmi_acpi_param *param, char *desc) { strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object, wmi_acpi_params_array, wmi_acpi_param_get_desc); /* "WMI\0" */ static u8 padded_wmi_string[] = { 0x0a, 0x00, 0x57, 0x00, 0x4D, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const struct wmi_string_param wmi_string_params_array[] = { { .name = "test", .string = "TEST", .buffer = { .length = sizeof(expected_single_string), .data = expected_single_string, }, }, { .name = "padded", .string = "WMI", .buffer = { .length = sizeof(padded_wmi_string), .data = padded_wmi_string, }, }, }; static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc) { strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(wmi_marshal_string, wmi_string_params_array, wmi_string_param_get_desc); static union acpi_object nested_package_elements[] = { { .package = { .type = ACPI_TYPE_PACKAGE, .count = ARRAY_SIZE(simple_package_elements), .elements = simple_package_elements, }, } }; static const struct wmi_invalid_acpi_param wmi_invalid_acpi_params_array[] = { { .name = "nested_package", .obj = { .package = { .type = ACPI_TYPE_PACKAGE, .count = ARRAY_SIZE(nested_package_elements), .elements = nested_package_elements, }, }, }, { .name = "reference", .obj = { .reference = { .type = ACPI_TYPE_LOCAL_REFERENCE, .actual_type = ACPI_TYPE_ANY, .handle = NULL, }, }, }, { .name = "processor", .obj = { .processor = { .type = ACPI_TYPE_PROCESSOR, .proc_id = 0, .pblk_address = 0, .pblk_length = 0, }, }, }, { .name = "power_resource", .obj = { .power_resource = { .type = ACPI_TYPE_POWER, .system_level = 0, .resource_order = 0, }, }, }, }; static void wmi_invalid_acpi_param_get_desc(const struct wmi_invalid_acpi_param *param, char *desc) { strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object_failure, wmi_invalid_acpi_params_array, wmi_invalid_acpi_param_get_desc); static u8 oversized_wmi_string[] = { 0x04, 0x00, 0x00, 0x00, }; /* * The error is that 3 bytes can not hold UTF-16 characters * without cutting of the last one. */ static u8 undersized_wmi_string[] = { 0x03, 0x00, 0x00, 0x00, 0x00, }; static u8 non_ascii_wmi_string[] = { 0x04, 0x00, 0xC4, 0x00, 0x00, 0x00, }; static const struct wmi_invalid_string_param wmi_invalid_string_params_array[] = { { .name = "empty_buffer", .buffer = { .length = 0, .data = ZERO_SIZE_PTR, }, }, { .name = "oversized", .buffer = { .length = sizeof(oversized_wmi_string), .data = oversized_wmi_string, }, }, { .name = "undersized", .buffer = { .length = sizeof(undersized_wmi_string), .data = undersized_wmi_string, }, }, { .name = "non_ascii", .buffer = { .length = sizeof(non_ascii_wmi_string), .data = non_ascii_wmi_string, }, }, }; static void wmi_invalid_string_param_get_desc(const struct wmi_invalid_string_param *param, char *desc) { strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(wmi_marshal_string_failure, wmi_invalid_string_params_array, wmi_invalid_string_param_get_desc); KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *); static void wmi_unmarshal_acpi_object_test(struct kunit *test) { const struct wmi_acpi_param *param = test->param_value; struct wmi_buffer result; int ret; ret = wmi_unmarshal_acpi_object(¶m->obj, &result); if (ret < 0) KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n"); kunit_add_action(test, kfree_wrapper, result.data); KUNIT_EXPECT_TRUE(test, IS_ALIGNED((uintptr_t)result.data, 8)); KUNIT_EXPECT_EQ(test, result.length, param->buffer.length); KUNIT_EXPECT_MEMEQ(test, result.data, param->buffer.data, result.length); } static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test) { const struct wmi_invalid_acpi_param *param = test->param_value; struct wmi_buffer result; int ret; ret = wmi_unmarshal_acpi_object(¶m->obj, &result); if (ret < 0) return; kfree(result.data); KUNIT_FAIL(test, "Invalid ACPI object was not rejected\n"); } static void wmi_marshal_string_test(struct kunit *test) { const struct wmi_string_param *param = test->param_value; struct acpi_buffer result; int ret; ret = wmi_marshal_string(¶m->buffer, &result); if (ret < 0) KUNIT_FAIL_AND_ABORT(test, "Marshalling of WMI string failed\n"); kunit_add_action(test, kfree_wrapper, result.pointer); KUNIT_EXPECT_EQ(test, result.length, strlen(param->string)); KUNIT_EXPECT_STREQ(test, result.pointer, param->string); } static void wmi_marshal_string_failure_test(struct kunit *test) { const struct wmi_invalid_string_param *param = test->param_value; struct acpi_buffer result; int ret; ret = wmi_marshal_string(¶m->buffer, &result); if (ret < 0) return; kfree(result.pointer); KUNIT_FAIL(test, "Invalid string was not rejected\n"); } static struct kunit_case wmi_marshalling_test_cases[] = { KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test, wmi_unmarshal_acpi_object_gen_params), KUNIT_CASE_PARAM(wmi_marshal_string_test, wmi_marshal_string_gen_params), KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_failure_test, wmi_unmarshal_acpi_object_failure_gen_params), KUNIT_CASE_PARAM(wmi_marshal_string_failure_test, wmi_marshal_string_failure_gen_params), {} }; static struct kunit_suite wmi_marshalling_test_suite = { .name = "wmi_marshalling", .test_cases = wmi_marshalling_test_cases, }; kunit_test_suite(wmi_marshalling_test_suite); MODULE_AUTHOR("Armin Wolf "); MODULE_DESCRIPTION("KUnit test for the ACPI-WMI marshalling code"); MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); MODULE_LICENSE("GPL");