// SPDX-License-Identifier: GPL-2.0+ /* * efi_selftest_variables * * Copyright (c) 2018 Heinrich Schuchardt * * This unit test checks the runtime services for variables: * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. */ #include #define EFI_ST_MAX_DATA_SIZE 16 #define EFI_ST_MAX_VARNAME_SIZE 80 static struct efi_boot_services *boottime; static struct efi_runtime_services *runtime; 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); /* * Setup unit test. * * @handle handle of the loaded image * @systable system table */ static int setup(const efi_handle_t img_handle, const struct efi_system_table *systable) { boottime = systable->boottime; runtime = systable->runtime; return EFI_ST_SUCCESS; } /* * 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; u64 max_storage, rem_storage, max_size; ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, &max_storage, &rem_storage, &max_size); if (ret != EFI_SUCCESS) { efi_st_todo("QueryVariableInfo failed\n"); } else if (!max_storage || !rem_storage || !max_size) { efi_st_error("QueryVariableInfo: wrong info\n"); return EFI_ST_FAILURE; } /* Set variable 0 */ ret = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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; } boottime->set_mem(&guid, 16, 0); *varname = 0; flag = 0; for (;;) { len = EFI_ST_MAX_VARNAME_SIZE; ret = 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 = 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 = 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 = 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 = 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, .setup = setup, .execute = execute, };