1 // SPDX-License-Identifier: GPL-2.0+
3 * File interface for UEFI variables
5 * Copyright (c) 2020, Heinrich Schuchardt
9 #include <efi_loader.h>
10 #include <efi_variable.h>
11 #include <u-boot/crc.h>
13 struct efi_var_file __efi_runtime_data *efi_var_buf;
14 static struct efi_var_entry __efi_runtime_data *efi_current_var;
17 * efi_var_mem_compare() - compare GUID and name with a variable
19 * @var: variable to compare
20 * @guid: GUID to compare
21 * @name: variable name to compare
22 * @next: pointer to next variable
23 * Return: true if match
25 static bool __efi_runtime
26 efi_var_mem_compare(struct efi_var_entry *var, const efi_guid_t *guid,
27 const u16 *name, struct efi_var_entry **next)
31 const u16 *data, *var_name;
34 for (guid1 = (u8 *)&var->guid, guid2 = (u8 *)guid, i = 0;
35 i < sizeof(efi_guid_t) && match; ++i)
36 match = (guid1[i] == guid2[i]);
38 for (data = var->name, var_name = name;; ++data, ++var_name) {
40 match = (*data == *var_name);
48 *next = (struct efi_var_entry *)
49 ALIGN((uintptr_t)data + var->length, 8);
52 efi_current_var = var;
57 struct efi_var_entry __efi_runtime
58 *efi_var_mem_find(const efi_guid_t *guid, const u16 *name,
59 struct efi_var_entry **next)
61 struct efi_var_entry *var, *last;
63 last = (struct efi_var_entry *)
64 ((uintptr_t)efi_var_buf + efi_var_buf->length);
68 *next = efi_var_buf->var;
74 if (efi_current_var &&
75 efi_var_mem_compare(efi_current_var, guid, name, next)) {
76 if (next && *next >= last)
78 return efi_current_var;
81 var = efi_var_buf->var;
84 struct efi_var_entry *pos;
87 match = efi_var_mem_compare(var, guid, name, &pos);
103 void __efi_runtime efi_var_mem_del(struct efi_var_entry *var)
106 struct efi_var_entry *next, *last;
111 last = (struct efi_var_entry *)
112 ((uintptr_t)efi_var_buf + efi_var_buf->length);
113 if (var <= efi_current_var)
114 efi_current_var = NULL;
116 for (data = var->name; *data; ++data)
119 next = (struct efi_var_entry *)
120 ALIGN((uintptr_t)data + var->length, 8);
121 efi_var_buf->length -= (uintptr_t)next - (uintptr_t)var;
123 /* efi_memcpy_runtime() can be used because next >= var. */
124 efi_memcpy_runtime(var, next, (uintptr_t)last - (uintptr_t)next);
125 efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var,
126 efi_var_buf->length -
127 sizeof(struct efi_var_file));
130 efi_status_t __efi_runtime efi_var_mem_ins(
132 const efi_guid_t *vendor, u32 attributes,
133 const efi_uintn_t size1, const void *data1,
134 const efi_uintn_t size2, const void *data2,
138 struct efi_var_entry *var;
141 var = (struct efi_var_entry *)
142 ((uintptr_t)efi_var_buf + efi_var_buf->length);
143 for (var_name_len = 0; variable_name[var_name_len]; ++var_name_len)
146 data = var->name + var_name_len;
148 if ((uintptr_t)data - (uintptr_t)efi_var_buf + size1 + size2 >
150 return EFI_OUT_OF_RESOURCES;
152 var->attr = attributes;
153 var->length = size1 + size2;
156 efi_memcpy_runtime(&var->guid, vendor, sizeof(efi_guid_t));
157 efi_memcpy_runtime(var->name, variable_name,
158 sizeof(u16) * var_name_len);
159 efi_memcpy_runtime(data, data1, size1);
160 efi_memcpy_runtime((u8 *)data + size1, data2, size2);
162 var = (struct efi_var_entry *)
163 ALIGN((uintptr_t)data + var->length, 8);
164 efi_var_buf->length = (uintptr_t)var - (uintptr_t)efi_var_buf;
165 efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var,
166 efi_var_buf->length -
167 sizeof(struct efi_var_file));
172 u64 __efi_runtime efi_var_mem_free(void)
174 return EFI_VAR_BUF_SIZE - efi_var_buf->length -
175 sizeof(struct efi_var_entry);
179 * efi_var_mem_bs_del() - delete boot service only variables
181 static void efi_var_mem_bs_del(void)
183 struct efi_var_entry *var = efi_var_buf->var;
186 struct efi_var_entry *last;
188 last = (struct efi_var_entry *)
189 ((uintptr_t)efi_var_buf + efi_var_buf->length);
192 if (var->attr & EFI_VARIABLE_RUNTIME_ACCESS) {
196 for (data = var->name; *data; ++data)
199 var = (struct efi_var_entry *)
200 ALIGN((uintptr_t)data + var->length, 8);
202 /* delete variable */
203 efi_var_mem_del(var);
209 * efi_var_mem_notify_exit_boot_services() - ExitBootService callback
211 * @event: callback event
212 * @context: callback context
215 efi_var_mem_notify_exit_boot_services(struct efi_event *event, void *context)
217 EFI_ENTRY("%p, %p", event, context);
219 /* Delete boot service only variables */
220 efi_var_mem_bs_del();
222 EFI_EXIT(EFI_SUCCESS);
226 * efi_var_mem_notify_exit_boot_services() - SetVirtualMemoryMap callback
228 * @event: callback event
229 * @context: callback context
231 static void EFIAPI __efi_runtime
232 efi_var_mem_notify_virtual_address_map(struct efi_event *event, void *context)
234 efi_convert_pointer(0, (void **)&efi_var_buf);
235 efi_current_var = NULL;
238 efi_status_t efi_var_mem_init(void)
242 struct efi_event *event;
244 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
245 EFI_RUNTIME_SERVICES_DATA,
246 efi_size_in_pages(EFI_VAR_BUF_SIZE),
248 if (ret != EFI_SUCCESS)
250 efi_var_buf = (struct efi_var_file *)(uintptr_t)memory;
251 memset(efi_var_buf, 0, EFI_VAR_BUF_SIZE);
252 efi_var_buf->magic = EFI_VAR_FILE_MAGIC;
253 efi_var_buf->length = (uintptr_t)efi_var_buf->var -
254 (uintptr_t)efi_var_buf;
255 /* crc32 for 0 bytes = 0 */
257 ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
258 efi_var_mem_notify_exit_boot_services, NULL,
260 if (ret != EFI_SUCCESS)
262 ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_CALLBACK,
263 efi_var_mem_notify_virtual_address_map, NULL,
265 if (ret != EFI_SUCCESS)
270 efi_status_t __efi_runtime
271 efi_get_variable_mem(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes,
272 efi_uintn_t *data_size, void *data, u64 *timep)
274 efi_uintn_t old_size;
275 struct efi_var_entry *var;
278 if (!variable_name || !vendor || !data_size)
279 return EFI_INVALID_PARAMETER;
280 var = efi_var_mem_find(vendor, variable_name, NULL);
282 return EFI_NOT_FOUND;
285 *attributes = var->attr;
289 old_size = *data_size;
290 *data_size = var->length;
291 if (old_size < var->length)
292 return EFI_BUFFER_TOO_SMALL;
295 return EFI_INVALID_PARAMETER;
297 for (pdata = var->name; *pdata; ++pdata)
301 efi_memcpy_runtime(data, pdata, var->length);
306 efi_status_t __efi_runtime
307 efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name,
310 struct efi_var_entry *var;
311 efi_uintn_t old_size;
314 if (!variable_name_size || !variable_name || !vendor)
315 return EFI_INVALID_PARAMETER;
317 efi_var_mem_find(vendor, variable_name, &var);
320 return EFI_NOT_FOUND;
322 for (pdata = var->name; *pdata; ++pdata)
326 old_size = *variable_name_size;
327 *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
329 if (old_size < *variable_name_size)
330 return EFI_BUFFER_TOO_SMALL;
332 efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
333 efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));