blob: 379c4f9c47b73d58022c344330535fcd855e5193 [file] [log] [blame]
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * efi_selftest_variables_runtime
4 *
5 * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks the runtime services for variables after
8 * ExitBootServices():
9 * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
10 */
11
12#include <efi_selftest.h>
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030013#include <efi_variable.h>
14#include <u-boot/crc.h>
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020015
16#define EFI_ST_MAX_DATA_SIZE 16
17#define EFI_ST_MAX_VARNAME_SIZE 40
18
19static struct efi_boot_services *boottime;
20static struct efi_runtime_services *runtime;
Heinrich Schuchardtfd956fc2020-07-06 17:06:07 +020021static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID;
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030022static const efi_guid_t __efi_runtime_data efi_rt_var_guid =
23 U_BOOT_EFI_RT_VAR_FILE_GUID;
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020024
25/*
26 * Setup unit test.
27 *
28 * @handle handle of the loaded image
29 * @systable system table
30 */
31static int setup(const efi_handle_t img_handle,
32 const struct efi_system_table *systable)
33{
34 boottime = systable->boottime;
35 runtime = systable->runtime;
36
37 return EFI_ST_SUCCESS;
38}
39
40/**
41 * execute() - execute unit test
42 *
43 * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
44 */
45static int execute(void)
46{
47 efi_status_t ret;
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030048 efi_uintn_t len, avail, append_len = 17;
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020049 u32 attr;
50 u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
51 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030052 u8 v2[CONFIG_EFI_VAR_BUF_SIZE];
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020053 u8 data[EFI_ST_MAX_DATA_SIZE];
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030054 u8 data2[CONFIG_EFI_VAR_BUF_SIZE];
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020055 u16 varname[EFI_ST_MAX_VARNAME_SIZE];
56 efi_guid_t guid;
57 u64 max_storage, rem_storage, max_size;
Ilias Apalodimas30d537e2024-04-25 08:18:20 +030058 int test_ret;
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020059
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030060 memset(v2, 0x1, sizeof(v2));
Ilias Apalodimasfc071532024-04-25 08:18:19 +030061
62 if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) {
Ilias Apalodimas30d537e2024-04-25 08:18:20 +030063 test_ret = efi_st_query_variable_common(runtime, EFI_VARIABLE_BOOTSERVICE_ACCESS |
64 EFI_VARIABLE_RUNTIME_ACCESS);
65 if (test_ret != EFI_ST_SUCCESS) {
Ilias Apalodimasfc071532024-04-25 08:18:19 +030066 efi_st_error("QueryVariableInfo failed\n");
67 return EFI_ST_FAILURE;
68 }
69 } else {
Ilias Apalodimas30d537e2024-04-25 08:18:20 +030070 ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS,
71 &max_storage, &rem_storage,
72 &max_size);
Ilias Apalodimasfc071532024-04-25 08:18:19 +030073 if (ret != EFI_UNSUPPORTED) {
74 efi_st_error("QueryVariableInfo failed\n");
75 return EFI_ST_FAILURE;
76 }
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020077 }
78
Simon Glass90975372022-01-23 12:55:12 -070079 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +020080 EFI_VARIABLE_BOOTSERVICE_ACCESS |
81 EFI_VARIABLE_RUNTIME_ACCESS,
82 3, v + 4);
Ilias Apalodimas86ba8692024-04-18 15:54:50 +030083 if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030084 efi_uintn_t prev_len, delta;
85 struct efi_var_entry *var;
86 struct efi_var_file *hdr;
87
Ilias Apalodimas86ba8692024-04-18 15:54:50 +030088 /* At runtime only non-volatile variables may be set. */
89 if (ret != EFI_INVALID_PARAMETER) {
90 efi_st_error("SetVariable failed\n");
91 return EFI_ST_FAILURE;
92 }
Ilias Apalodimasb0f75b62024-04-18 15:54:53 +030093
94 /* runtime atttribute must be set */
95 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
96 EFI_VARIABLE_BOOTSERVICE_ACCESS |
97 EFI_VARIABLE_NON_VOLATILE,
98 3, v + 4);
99 if (ret != EFI_INVALID_PARAMETER) {
100 efi_st_error("SetVariable failed\n");
101 return EFI_ST_FAILURE;
102 }
103
104 len = sizeof(data);
105 ret = runtime->get_variable(u"RTStorageVolatile",
106 &efi_rt_var_guid,
107 &attr, &len, data);
108 if (ret != EFI_SUCCESS) {
109 efi_st_error("GetVariable failed\n");
110 return EFI_ST_FAILURE;
111 }
112
113 if (len != sizeof(EFI_VAR_FILE_NAME) ||
114 memcmp(data, EFI_VAR_FILE_NAME, sizeof(EFI_VAR_FILE_NAME))) {
115 data[len - 1] = 0;
116 efi_st_error("RTStorageVolatile = %s\n", data);
117 return EFI_ST_FAILURE;
118 }
119
120 len = sizeof(data2);
121 ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
122 &attr, &len, data2);
123 if (ret != EFI_SUCCESS) {
124 efi_st_error("GetVariable failed\n");
125 return EFI_ST_FAILURE;
126 }
127 /*
128 * VarToFile size must change once a variable is inserted
129 * Store it now, we'll use it later
130 */
131 prev_len = len;
132 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
133 EFI_VARIABLE_BOOTSERVICE_ACCESS |
134 EFI_VARIABLE_RUNTIME_ACCESS |
135 EFI_VARIABLE_NON_VOLATILE,
136 sizeof(v2),
137 v2);
138 /*
139 * This will try to update VarToFile as well and must fail,
140 * without changing or deleting VarToFile
141 */
142 if (ret != EFI_OUT_OF_RESOURCES) {
143 efi_st_error("SetVariable failed\n");
144 return EFI_ST_FAILURE;
145 }
146 len = sizeof(data2);
147 ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
148 &attr, &len, data2);
149 if (ret != EFI_SUCCESS || prev_len != len) {
150 efi_st_error("Get/SetVariable failed\n");
151 return EFI_ST_FAILURE;
152 }
153
154 /* Add an 8byte aligned variable */
155 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
156 EFI_VARIABLE_BOOTSERVICE_ACCESS |
157 EFI_VARIABLE_RUNTIME_ACCESS |
158 EFI_VARIABLE_NON_VOLATILE,
159 sizeof(v), v);
160 if (ret != EFI_SUCCESS) {
161 efi_st_error("SetVariable failed\n");
162 return EFI_ST_FAILURE;
163 }
164
165 /* Delete it by setting the attrs to 0 */
166 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
167 0, sizeof(v), v);
168 if (ret != EFI_SUCCESS) {
169 efi_st_error("SetVariable failed\n");
170 return EFI_ST_FAILURE;
171 }
172
173 /* Add it back */
174 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
175 EFI_VARIABLE_BOOTSERVICE_ACCESS |
176 EFI_VARIABLE_RUNTIME_ACCESS |
177 EFI_VARIABLE_NON_VOLATILE,
178 sizeof(v), v);
179 if (ret != EFI_SUCCESS) {
180 efi_st_error("SetVariable failed\n");
181 return EFI_ST_FAILURE;
182 }
183
184 /* Delete it again by setting the size to 0 */
185 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
186 EFI_VARIABLE_BOOTSERVICE_ACCESS |
187 EFI_VARIABLE_RUNTIME_ACCESS |
188 EFI_VARIABLE_NON_VOLATILE,
189 0, NULL);
190 if (ret != EFI_SUCCESS) {
191 efi_st_error("SetVariable failed\n");
192 return EFI_ST_FAILURE;
193 }
194
195 /* Delete it again and make sure it's not there */
196 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
197 EFI_VARIABLE_BOOTSERVICE_ACCESS |
198 EFI_VARIABLE_RUNTIME_ACCESS |
199 EFI_VARIABLE_NON_VOLATILE,
200 0, NULL);
201 if (ret != EFI_NOT_FOUND) {
202 efi_st_error("SetVariable failed\n");
203 return EFI_ST_FAILURE;
204 }
205
206 /*
207 * Add a non-aligned variable
208 * VarToFile updates must include efi_st_var0
209 */
210 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
211 EFI_VARIABLE_BOOTSERVICE_ACCESS |
212 EFI_VARIABLE_RUNTIME_ACCESS |
213 EFI_VARIABLE_NON_VOLATILE,
214 9, v + 4);
215 if (ret != EFI_SUCCESS) {
216 efi_st_error("SetVariable failed\n");
217 return EFI_ST_FAILURE;
218 }
219 var = efi_var_mem_find(&guid_vendor0, u"efi_st_var0", NULL);
220 if (!var) {
221 efi_st_error("GetVariable failed\n");
222 return EFI_ST_FAILURE;
223 }
224 delta = efi_var_entry_len(var);
225 len = sizeof(data2);
226 ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
227 &attr, &len, data2);
228 if (ret != EFI_SUCCESS || prev_len + delta != len) {
229 efi_st_error("Get/SetVariable failed\n");
230 return EFI_ST_FAILURE;
231 }
232
233 /*
234 * Append on an existing variable must update VarToFile
235 * Our variable entries are 8-byte aligned.
236 * Adding a single byte will fit on the existing space
237 */
238 prev_len = len;
239 avail = efi_var_entry_len(var) -
240 (sizeof(u16) * (u16_strlen(var->name) + 1) + sizeof(*var)) -
241 var->length;
242 if (avail >= append_len)
243 delta = 0;
244 else
245 delta = ALIGN(append_len - avail, 8);
246 ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
247 EFI_VARIABLE_BOOTSERVICE_ACCESS |
248 EFI_VARIABLE_RUNTIME_ACCESS |
249 EFI_VARIABLE_APPEND_WRITE |
250 EFI_VARIABLE_NON_VOLATILE,
251 append_len, v2);
252 if (ret != EFI_SUCCESS) {
253 efi_st_error("SetVariable failed\n");
254 return EFI_ST_FAILURE;
255 }
256 len = sizeof(data2);
257 ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
258 &attr, &len, data2);
259 if (ret != EFI_SUCCESS) {
260 efi_st_error("GetVariable failed\n");
261 return EFI_ST_FAILURE;
262 }
263 if (prev_len + delta != len) {
264 efi_st_error("Unexpected VarToFile size");
265 return EFI_ST_FAILURE;
266 }
267
268 /* Make sure that variable contains a valid file */
269 hdr = (struct efi_var_file *)data2;
270 if (hdr->magic != EFI_VAR_FILE_MAGIC ||
271 len != hdr->length ||
272 hdr->crc32 != crc32(0, (u8 *)((uintptr_t)data2 + sizeof(struct efi_var_file)),
273 len - sizeof(struct efi_var_file))) {
274 efi_st_error("VarToFile invalid header\n");
275 return EFI_ST_FAILURE;
276 }
277
278 /* Variables that are BS, RT and volatile are RO after EBS */
279 ret = runtime->set_variable(u"VarToFile", &efi_rt_var_guid,
280 EFI_VARIABLE_BOOTSERVICE_ACCESS |
281 EFI_VARIABLE_RUNTIME_ACCESS |
282 EFI_VARIABLE_NON_VOLATILE,
283 sizeof(v), v);
284 if (ret != EFI_WRITE_PROTECTED) {
285 efi_st_error("Get/SetVariable failed\n");
286 return EFI_ST_FAILURE;
287 }
Ilias Apalodimas86ba8692024-04-18 15:54:50 +0300288 } else {
289 if (ret != EFI_UNSUPPORTED) {
290 efi_st_error("SetVariable failed\n");
291 return EFI_ST_FAILURE;
292 }
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +0200293 }
Heinrich Schuchardtfd956fc2020-07-06 17:06:07 +0200294 len = EFI_ST_MAX_DATA_SIZE;
Simon Glass90975372022-01-23 12:55:12 -0700295 ret = runtime->get_variable(u"PlatformLangCodes", &guid_vendor0,
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +0200296 &attr, &len, data);
Heinrich Schuchardtfd956fc2020-07-06 17:06:07 +0200297 if (ret != EFI_SUCCESS) {
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +0200298 efi_st_error("GetVariable failed\n");
299 return EFI_ST_FAILURE;
300 }
301 memset(&guid, 0, 16);
302 *varname = 0;
Heinrich Schuchardtfd956fc2020-07-06 17:06:07 +0200303 len = 2 * EFI_ST_MAX_VARNAME_SIZE;
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +0200304 ret = runtime->get_next_variable_name(&len, varname, &guid);
Heinrich Schuchardtfd956fc2020-07-06 17:06:07 +0200305 if (ret != EFI_SUCCESS) {
Heinrich Schuchardtc0267f92019-06-20 16:18:48 +0200306 efi_st_error("GetNextVariableName failed\n");
307 return EFI_ST_FAILURE;
308 }
309
310 return EFI_ST_SUCCESS;
311}
312
313EFI_UNIT_TEST(variables_run) = {
314 .name = "variables at runtime",
315 .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
316 .setup = setup,
317 .execute = execute,
318};