| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * efi_selftest_variables | |
| * | |
| * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> | |
| * | |
| * This unit test checks the runtime services for variables: | |
| * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. | |
| */ | |
| #include <efi_selftest.h> | |
| #define EFI_ST_MAX_DATA_SIZE 16 | |
| #define EFI_ST_MAX_VARNAME_SIZE 80 | |
| static const efi_guid_t guid_vendor0 = | |
| EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1, | |
| 0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6); | |
| static const efi_guid_t guid_vendor1 = | |
| EFI_GUID(0xff629290, 0x1fc1, 0xd73f, | |
| 0x8f, 0xb1, 0x32, 0xf9, 0x0c, 0xa0, 0x42, 0xea); | |
| /* | |
| * Execute unit test. | |
| */ | |
| static int execute(void) | |
| { | |
| efi_status_t ret; | |
| efi_uintn_t len; | |
| u32 attr; | |
| u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, | |
| 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; | |
| u8 data[EFI_ST_MAX_DATA_SIZE]; | |
| u16 varname[EFI_ST_MAX_VARNAME_SIZE]; | |
| int flag; | |
| efi_guid_t guid; | |
| int test_ret; | |
| test_ret = efi_st_query_variable_common(EFI_VARIABLE_BOOTSERVICE_ACCESS); | |
| if (test_ret != EFI_ST_SUCCESS) { | |
| efi_st_error("QueryVariableInfo failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Set variable 0 */ | |
| ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS, 3, | |
| v + 4); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| data[3] = 0xff; | |
| len = 3; | |
| ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0, &attr, | |
| &len, data); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("GetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (memcmp(data, v + 4, 3)) { | |
| efi_st_error("GetVariable returned wrong value\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (data[3] != 0xff) { | |
| efi_st_error("GetVariable wrote past the end of the buffer\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Set variable 1 */ | |
| ret = st_runtime->set_variable(u"efi_st_var1", &guid_vendor1, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS, 8, v); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_st_var1", &guid_vendor1, &attr, | |
| &len, data); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("GetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (len != 8) { | |
| efi_st_error("GetVariable returned wrong length %u\n", | |
| (unsigned int)len); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (memcmp(data, v, 8)) { | |
| efi_st_error("GetVariable returned wrong value\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Append variable 1 */ | |
| ret = st_runtime->set_variable(u"efi_st_var1", &guid_vendor1, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
| EFI_VARIABLE_APPEND_WRITE, | |
| 7, v + 8); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable(APPEND_WRITE) failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_st_var1", &guid_vendor1, &attr, | |
| &len, data); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("GetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (len != 15) | |
| efi_st_todo("GetVariable returned wrong length %u\n", | |
| (unsigned int)len); | |
| if (memcmp(data, v, len)) | |
| efi_st_todo("GetVariable returned wrong value\n"); | |
| /* Append variable 2, write to non-existent variable with datasize=0 */ | |
| ret = st_runtime->set_variable(u"efi_none", &guid_vendor1, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
| EFI_VARIABLE_APPEND_WRITE, | |
| 0, v); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error( | |
| "SetVariable(APPEND_WRITE) with size 0 to non-existent variable returns wrong code\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_none", &guid_vendor1, &attr, &len, | |
| data); | |
| if (ret != EFI_NOT_FOUND) { | |
| efi_st_error("Variable must not be created\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Append variable 2, write to non-existent variable with valid data size*/ | |
| ret = st_runtime->set_variable(u"efi_none", &guid_vendor1, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
| EFI_VARIABLE_APPEND_WRITE, | |
| 15, v); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error( | |
| "SetVariable(APPEND_WRITE) with valid size and data to non-existent variable must be succcessful\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_none", &guid_vendor1, &attr, &len, | |
| data); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("GetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (len != 15) | |
| efi_st_todo("GetVariable returned wrong length %u\n", | |
| (unsigned int)len); | |
| if (memcmp(data, v, len)) | |
| efi_st_todo("GetVariable returned wrong value\n"); | |
| /* Delete variable efi_none */ | |
| ret = st_runtime->set_variable(u"efi_none", &guid_vendor1, 0, 0, NULL); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_none", &guid_vendor1, &attr, &len, | |
| data); | |
| if (ret != EFI_NOT_FOUND) { | |
| efi_st_error("Variable was not deleted\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Enumerate variables */ | |
| ret = st_runtime->get_next_variable_name(NULL, u"efi_st_var1", &guid); | |
| if (ret != EFI_INVALID_PARAMETER) { | |
| efi_st_error("GetNextVariableName missing parameter check\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = 24; | |
| ret = st_runtime->get_next_variable_name(&len, NULL, &guid); | |
| if (ret != EFI_INVALID_PARAMETER) { | |
| efi_st_error("GetNextVariableName missing parameter check\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = 24; | |
| ret = st_runtime->get_next_variable_name(&len, u"efi_st_var1", NULL); | |
| if (ret != EFI_INVALID_PARAMETER) { | |
| efi_st_error("GetNextVariableName missing parameter check\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = 1; | |
| ret = st_runtime->get_next_variable_name(&len, u"", &guid); | |
| if (ret != EFI_INVALID_PARAMETER) { | |
| efi_st_error("GetNextVariableName missing parameter check\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = 16; | |
| ret = st_runtime->get_next_variable_name(&len, u"efi_st_var1", &guid); | |
| if (ret != EFI_INVALID_PARAMETER) { | |
| efi_st_error("GetNextVariableName missing parameter check\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| st_boottime->set_mem(&guid, 16, 0); | |
| *varname = 0; | |
| flag = 0; | |
| for (;;) { | |
| len = EFI_ST_MAX_VARNAME_SIZE; | |
| ret = st_runtime->get_next_variable_name(&len, varname, &guid); | |
| if (ret == EFI_NOT_FOUND) | |
| break; | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("GetNextVariableName failed (%u)\n", | |
| (unsigned int)ret); | |
| return EFI_ST_FAILURE; | |
| } | |
| if (!memcmp(&guid, &guid_vendor0, sizeof(efi_guid_t)) && | |
| !efi_st_strcmp_16_8(varname, "efi_st_var0")) { | |
| flag |= 1; | |
| if (len != 24) { | |
| efi_st_error( | |
| "GetNextVariableName report wrong length %u, expected 24\n", | |
| (unsigned int)len); | |
| return EFI_ST_FAILURE; | |
| } | |
| } | |
| if (!memcmp(&guid, &guid_vendor1, sizeof(efi_guid_t)) && | |
| !efi_st_strcmp_16_8(varname, "efi_st_var1")) | |
| flag |= 2; | |
| } | |
| if (flag != 3) { | |
| efi_st_error( | |
| "GetNextVariableName did not return all variables\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Delete variable 1 */ | |
| ret = st_runtime->set_variable(u"efi_st_var1", &guid_vendor1, 0, 0, | |
| NULL); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_st_var1", &guid_vendor1, &attr, | |
| &len, data); | |
| if (ret != EFI_NOT_FOUND) { | |
| efi_st_error("Variable was not deleted\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| /* Delete variable 0 */ | |
| ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0, 0, 0, | |
| NULL); | |
| if (ret != EFI_SUCCESS) { | |
| efi_st_error("SetVariable failed\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| len = EFI_ST_MAX_DATA_SIZE; | |
| ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0, &attr, | |
| &len, data); | |
| if (ret != EFI_NOT_FOUND) { | |
| efi_st_error("Variable was not deleted\n"); | |
| return EFI_ST_FAILURE; | |
| } | |
| return EFI_ST_SUCCESS; | |
| } | |
| EFI_UNIT_TEST(variables) = { | |
| .name = "variables", | |
| .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, | |
| .execute = execute, | |
| }; |