/src/u-boot/lib/efi_loader/efi_runtime.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * EFI application runtime services |
4 | | * |
5 | | * Copyright (c) 2016 Alexander Graf |
6 | | */ |
7 | | |
8 | | #define LOG_CATEGORY LOGC_EFI |
9 | | |
10 | | #include <command.h> |
11 | | #include <cpu_func.h> |
12 | | #include <dm.h> |
13 | | #include <elf.h> |
14 | | #include <efi_loader.h> |
15 | | #include <efi_variable.h> |
16 | | #include <log.h> |
17 | | #include <malloc.h> |
18 | | #include <rtc.h> |
19 | | #include <asm/global_data.h> |
20 | | #include <u-boot/crc.h> |
21 | | #include <asm/sections.h> |
22 | | |
23 | | /* For manual relocation support */ |
24 | | DECLARE_GLOBAL_DATA_PTR; |
25 | | |
26 | | /* GUID of the runtime properties table */ |
27 | | static const efi_guid_t efi_rt_properties_table_guid = |
28 | | EFI_RT_PROPERTIES_TABLE_GUID; |
29 | | |
30 | | struct efi_runtime_mmio_list { |
31 | | struct list_head link; |
32 | | void **ptr; |
33 | | u64 paddr; |
34 | | u64 len; |
35 | | }; |
36 | | |
37 | | /* This list contains all runtime available mmio regions */ |
38 | | static LIST_HEAD(efi_runtime_mmio); |
39 | | |
40 | | static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); |
41 | | |
42 | | /* |
43 | | * TODO(sjg@chromium.org): These defines and structures should come from the ELF |
44 | | * header for each architecture (or a generic header) rather than being repeated |
45 | | * here. |
46 | | */ |
47 | | #if defined(__aarch64__) |
48 | | #define R_RELATIVE R_AARCH64_RELATIVE |
49 | | #define R_MASK 0xffffffffULL |
50 | | #define IS_RELA 1 |
51 | | #elif defined(__arm__) |
52 | | #define R_RELATIVE R_ARM_RELATIVE |
53 | | #define R_MASK 0xffULL |
54 | | #elif defined(__i386__) |
55 | | #define R_RELATIVE R_386_RELATIVE |
56 | | #define R_MASK 0xffULL |
57 | | #elif defined(__x86_64__) |
58 | 0 | #define R_RELATIVE R_X86_64_RELATIVE |
59 | 0 | #define R_MASK 0xffffffffULL |
60 | | #define IS_RELA 1 |
61 | | #elif defined(__riscv) |
62 | | #define R_RELATIVE R_RISCV_RELATIVE |
63 | | #define R_MASK 0xffULL |
64 | | #define IS_RELA 1 |
65 | | |
66 | | struct dyn_sym { |
67 | | ulong foo1; |
68 | | ulong addr; |
69 | | u32 foo2; |
70 | | u32 foo3; |
71 | | }; |
72 | | #if (__riscv_xlen == 32) |
73 | | #define R_ABSOLUTE R_RISCV_32 |
74 | | #define SYM_INDEX 8 |
75 | | #elif (__riscv_xlen == 64) |
76 | | #define R_ABSOLUTE R_RISCV_64 |
77 | | #define SYM_INDEX 32 |
78 | | #else |
79 | | #error unknown riscv target |
80 | | #endif |
81 | | #else |
82 | | #error Need to add relocation awareness |
83 | | #endif |
84 | | |
85 | | struct elf_rel { |
86 | | ulong *offset; |
87 | | ulong info; |
88 | | }; |
89 | | |
90 | | struct elf_rela { |
91 | | ulong *offset; |
92 | | ulong info; |
93 | | long addend; |
94 | | }; |
95 | | |
96 | | static __efi_runtime_data struct efi_mem_desc *efi_virtmap; |
97 | | static __efi_runtime_data efi_uintn_t efi_descriptor_count; |
98 | | static __efi_runtime_data efi_uintn_t efi_descriptor_size; |
99 | | |
100 | | /* |
101 | | * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI |
102 | | * payload are running concurrently at the same time. In this mode, we can |
103 | | * handle a good number of runtime callbacks |
104 | | */ |
105 | | |
106 | | /** |
107 | | * efi_init_runtime_supported() - create runtime properties table |
108 | | * |
109 | | * Create a configuration table specifying which services are available at |
110 | | * runtime. |
111 | | * |
112 | | * Return: status code |
113 | | */ |
114 | | efi_status_t efi_init_runtime_supported(void) |
115 | 0 | { |
116 | 0 | const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID; |
117 | 0 | efi_status_t ret; |
118 | 0 | struct efi_rt_properties_table *rt_table; |
119 | |
|
120 | 0 | ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA, |
121 | 0 | sizeof(struct efi_rt_properties_table), |
122 | 0 | (void **)&rt_table); |
123 | 0 | if (ret != EFI_SUCCESS) |
124 | 0 | return ret; |
125 | | |
126 | 0 | rt_table->version = EFI_RT_PROPERTIES_TABLE_VERSION; |
127 | 0 | rt_table->length = sizeof(struct efi_rt_properties_table); |
128 | 0 | rt_table->runtime_services_supported = |
129 | 0 | EFI_RT_SUPPORTED_GET_VARIABLE | |
130 | 0 | EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME | |
131 | 0 | EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | |
132 | 0 | EFI_RT_SUPPORTED_CONVERT_POINTER; |
133 | |
|
134 | 0 | if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) |
135 | 0 | rt_table->runtime_services_supported |= |
136 | 0 | EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO; |
137 | |
|
138 | 0 | if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { |
139 | 0 | u8 s = 0; |
140 | |
|
141 | 0 | ret = efi_set_variable_int(u"RTStorageVolatile", |
142 | 0 | &efi_guid_efi_rt_var_file, |
143 | 0 | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
144 | 0 | EFI_VARIABLE_RUNTIME_ACCESS | |
145 | 0 | EFI_VARIABLE_READ_ONLY, |
146 | 0 | sizeof(EFI_VAR_FILE_NAME), |
147 | 0 | EFI_VAR_FILE_NAME, false); |
148 | 0 | if (ret != EFI_SUCCESS) { |
149 | 0 | log_err("Failed to set RTStorageVolatile\n"); |
150 | 0 | return ret; |
151 | 0 | } |
152 | | /* |
153 | | * This variable needs to be visible so users can read it, |
154 | | * but the real contents are going to be filled during |
155 | | * GetVariable |
156 | | */ |
157 | 0 | ret = efi_set_variable_int(u"VarToFile", |
158 | 0 | &efi_guid_efi_rt_var_file, |
159 | 0 | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
160 | 0 | EFI_VARIABLE_RUNTIME_ACCESS | |
161 | 0 | EFI_VARIABLE_READ_ONLY, |
162 | 0 | sizeof(s), |
163 | 0 | &s, false); |
164 | 0 | if (ret != EFI_SUCCESS) { |
165 | 0 | log_err("Failed to set VarToFile\n"); |
166 | 0 | efi_set_variable_int(u"RTStorageVolatile", |
167 | 0 | &efi_guid_efi_rt_var_file, |
168 | 0 | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
169 | 0 | EFI_VARIABLE_RUNTIME_ACCESS | |
170 | 0 | EFI_VARIABLE_READ_ONLY, |
171 | 0 | 0, NULL, false); |
172 | |
|
173 | 0 | return ret; |
174 | 0 | } |
175 | 0 | rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE; |
176 | 0 | } |
177 | | |
178 | | /* |
179 | | * This value must be synced with efi_runtime_detach_list |
180 | | * as well as efi_runtime_services. |
181 | | */ |
182 | 0 | #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET |
183 | 0 | rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; |
184 | 0 | #endif |
185 | |
|
186 | 0 | ret = efi_install_configuration_table(&efi_rt_properties_table_guid, |
187 | 0 | rt_table); |
188 | 0 | return ret; |
189 | 0 | } |
190 | | |
191 | | /** |
192 | | * efi_memcpy_runtime() - copy memory area |
193 | | * |
194 | | * At runtime memcpy() is not available. |
195 | | * |
196 | | * Overlapping memory areas can be copied safely if src >= dest. |
197 | | * |
198 | | * @dest: destination buffer |
199 | | * @src: source buffer |
200 | | * @n: number of bytes to copy |
201 | | * Return: pointer to destination buffer |
202 | | */ |
203 | | void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n) |
204 | 0 | { |
205 | 0 | u8 *d = dest; |
206 | 0 | const u8 *s = src; |
207 | |
|
208 | 0 | for (; n; --n) |
209 | 0 | *d++ = *s++; |
210 | 0 | } |
211 | | |
212 | | /** |
213 | | * efi_update_table_header_crc32() - Update crc32 in table header |
214 | | * |
215 | | * @table: EFI table |
216 | | */ |
217 | | void __efi_runtime efi_update_table_header_crc32(struct efi_table_hdr *table) |
218 | 0 | { |
219 | 0 | table->crc32 = 0; |
220 | 0 | table->crc32 = crc32(0, (const unsigned char *)table, |
221 | 0 | table->headersize); |
222 | 0 | } |
223 | | |
224 | | /** |
225 | | * efi_reset_system_boottime() - reset system at boot time |
226 | | * |
227 | | * This function implements the ResetSystem() runtime service before |
228 | | * SetVirtualAddressMap() is called. |
229 | | * |
230 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
231 | | * details. |
232 | | * |
233 | | * @reset_type: type of reset to perform |
234 | | * @reset_status: status code for the reset |
235 | | * @data_size: size of reset_data |
236 | | * @reset_data: information about the reset |
237 | | */ |
238 | | static void EFIAPI efi_reset_system_boottime( |
239 | | enum efi_reset_type reset_type, |
240 | | efi_status_t reset_status, |
241 | | unsigned long data_size, void *reset_data) |
242 | 0 | { |
243 | 0 | struct efi_event *evt; |
244 | |
|
245 | 0 | EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size, |
246 | 0 | reset_data); |
247 | | |
248 | | /* Notify reset */ |
249 | 0 | list_for_each_entry(evt, &efi_events, link) { |
250 | 0 | if (evt->group && |
251 | 0 | !guidcmp(evt->group, |
252 | 0 | &efi_guid_event_group_reset_system)) { |
253 | 0 | efi_signal_event(evt); |
254 | 0 | break; |
255 | 0 | } |
256 | 0 | } |
257 | 0 | switch (reset_type) { |
258 | 0 | case EFI_RESET_COLD: |
259 | 0 | case EFI_RESET_WARM: |
260 | 0 | case EFI_RESET_PLATFORM_SPECIFIC: |
261 | 0 | do_reset(NULL, 0, 0, NULL); |
262 | 0 | break; |
263 | 0 | case EFI_RESET_SHUTDOWN: |
264 | 0 | #ifdef CONFIG_CMD_POWEROFF |
265 | 0 | do_poweroff(NULL, 0, 0, NULL); |
266 | 0 | #endif |
267 | 0 | break; |
268 | 0 | } |
269 | | |
270 | 0 | while (1) { } |
271 | 0 | } |
272 | | |
273 | | /** |
274 | | * efi_get_time_boottime() - get current time at boot time |
275 | | * |
276 | | * This function implements the GetTime runtime service before |
277 | | * SetVirtualAddressMap() is called. |
278 | | * |
279 | | * See the Unified Extensible Firmware Interface (UEFI) specification |
280 | | * for details. |
281 | | * |
282 | | * @time: pointer to structure to receive current time |
283 | | * @capabilities: pointer to structure to receive RTC properties |
284 | | * Returns: status code |
285 | | */ |
286 | | static efi_status_t EFIAPI efi_get_time_boottime( |
287 | | struct efi_time *time, |
288 | | struct efi_time_cap *capabilities) |
289 | | { |
290 | | #ifdef CONFIG_EFI_GET_TIME |
291 | | efi_status_t ret = EFI_SUCCESS; |
292 | | struct rtc_time tm; |
293 | | struct udevice *dev; |
294 | | |
295 | | EFI_ENTRY("%p %p", time, capabilities); |
296 | | |
297 | | if (!time) { |
298 | | ret = EFI_INVALID_PARAMETER; |
299 | | goto out; |
300 | | } |
301 | | if (uclass_get_device(UCLASS_RTC, 0, &dev) || |
302 | | dm_rtc_get(dev, &tm)) { |
303 | | ret = EFI_UNSUPPORTED; |
304 | | goto out; |
305 | | } |
306 | | if (dm_rtc_get(dev, &tm)) { |
307 | | ret = EFI_DEVICE_ERROR; |
308 | | goto out; |
309 | | } |
310 | | |
311 | | memset(time, 0, sizeof(*time)); |
312 | | time->year = tm.tm_year; |
313 | | time->month = tm.tm_mon; |
314 | | time->day = tm.tm_mday; |
315 | | time->hour = tm.tm_hour; |
316 | | time->minute = tm.tm_min; |
317 | | time->second = tm.tm_sec; |
318 | | if (tm.tm_isdst > 0) |
319 | | time->daylight = |
320 | | EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT; |
321 | | else if (!tm.tm_isdst) |
322 | | time->daylight = EFI_TIME_ADJUST_DAYLIGHT; |
323 | | else |
324 | | time->daylight = 0; |
325 | | time->timezone = EFI_UNSPECIFIED_TIMEZONE; |
326 | | |
327 | | if (capabilities) { |
328 | | /* Set reasonable dummy values */ |
329 | | capabilities->resolution = 1; /* 1 Hz */ |
330 | | capabilities->accuracy = 100000000; /* 100 ppm */ |
331 | | capabilities->sets_to_zero = false; |
332 | | } |
333 | | out: |
334 | | return EFI_EXIT(ret); |
335 | | #else |
336 | | EFI_ENTRY("%p %p", time, capabilities); |
337 | | return EFI_EXIT(EFI_UNSUPPORTED); |
338 | | #endif |
339 | | } |
340 | | |
341 | | #ifdef CONFIG_EFI_SET_TIME |
342 | | |
343 | | /** |
344 | | * efi_validate_time() - checks if timestamp is valid |
345 | | * |
346 | | * @time: timestamp to validate |
347 | | * Returns: 0 if timestamp is valid, 1 otherwise |
348 | | */ |
349 | | static int efi_validate_time(struct efi_time *time) |
350 | 0 | { |
351 | 0 | return (!time || |
352 | 0 | time->year < 1900 || time->year > 9999 || |
353 | 0 | !time->month || time->month > 12 || !time->day || |
354 | 0 | time->day > rtc_month_days(time->month - 1, time->year) || |
355 | 0 | time->hour > 23 || time->minute > 59 || time->second > 59 || |
356 | 0 | time->nanosecond > 999999999 || |
357 | 0 | time->daylight & |
358 | 0 | ~(EFI_TIME_IN_DAYLIGHT | EFI_TIME_ADJUST_DAYLIGHT) || |
359 | 0 | ((time->timezone < -1440 || time->timezone > 1440) && |
360 | 0 | time->timezone != EFI_UNSPECIFIED_TIMEZONE)); |
361 | 0 | } |
362 | | |
363 | | #endif |
364 | | |
365 | | /** |
366 | | * efi_set_time_boottime() - set current time |
367 | | * |
368 | | * This function implements the SetTime() runtime service before |
369 | | * SetVirtualAddressMap() is called. |
370 | | * |
371 | | * See the Unified Extensible Firmware Interface (UEFI) specification |
372 | | * for details. |
373 | | * |
374 | | * @time: pointer to structure to with current time |
375 | | * Returns: status code |
376 | | */ |
377 | | static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) |
378 | | { |
379 | | #ifdef CONFIG_EFI_SET_TIME |
380 | | efi_status_t ret = EFI_SUCCESS; |
381 | | struct rtc_time tm; |
382 | | struct udevice *dev; |
383 | | |
384 | | EFI_ENTRY("%p", time); |
385 | | |
386 | | if (efi_validate_time(time)) { |
387 | | ret = EFI_INVALID_PARAMETER; |
388 | | goto out; |
389 | | } |
390 | | |
391 | | if (uclass_get_device(UCLASS_RTC, 0, &dev)) { |
392 | | ret = EFI_UNSUPPORTED; |
393 | | goto out; |
394 | | } |
395 | | |
396 | | memset(&tm, 0, sizeof(tm)); |
397 | | tm.tm_year = time->year; |
398 | | tm.tm_mon = time->month; |
399 | | tm.tm_mday = time->day; |
400 | | tm.tm_hour = time->hour; |
401 | | tm.tm_min = time->minute; |
402 | | tm.tm_sec = time->second; |
403 | | switch (time->daylight) { |
404 | | case EFI_TIME_ADJUST_DAYLIGHT: |
405 | | tm.tm_isdst = 0; |
406 | | break; |
407 | | case EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT: |
408 | | tm.tm_isdst = 1; |
409 | | break; |
410 | | default: |
411 | | tm.tm_isdst = -1; |
412 | | break; |
413 | | } |
414 | | /* Calculate day of week */ |
415 | | rtc_calc_weekday(&tm); |
416 | | |
417 | | if (dm_rtc_set(dev, &tm)) |
418 | | ret = EFI_DEVICE_ERROR; |
419 | | out: |
420 | | return EFI_EXIT(ret); |
421 | | #else |
422 | | EFI_ENTRY("%p", time); |
423 | | return EFI_EXIT(EFI_UNSUPPORTED); |
424 | | #endif |
425 | | } |
426 | | /** |
427 | | * efi_reset_system() - reset system |
428 | | * |
429 | | * This function implements the ResetSystem() runtime service after |
430 | | * SetVirtualAddressMap() is called. As this placeholder cannot reset the |
431 | | * system it simply return to the caller. |
432 | | * |
433 | | * Boards may override the helpers below to implement reset functionality. |
434 | | * |
435 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
436 | | * details. |
437 | | * |
438 | | * @reset_type: type of reset to perform |
439 | | * @reset_status: status code for the reset |
440 | | * @data_size: size of reset_data |
441 | | * @reset_data: information about the reset |
442 | | */ |
443 | | void __weak __efi_runtime EFIAPI efi_reset_system( |
444 | | enum efi_reset_type reset_type, |
445 | | efi_status_t reset_status, |
446 | | unsigned long data_size, void *reset_data) |
447 | | { |
448 | | return; |
449 | | } |
450 | | |
451 | | /** |
452 | | * efi_reset_system_init() - initialize the reset driver |
453 | | * |
454 | | * Boards may override this function to initialize the reset driver. |
455 | | */ |
456 | | efi_status_t __weak efi_reset_system_init(void) |
457 | 0 | { |
458 | 0 | return EFI_SUCCESS; |
459 | 0 | } |
460 | | |
461 | | /** |
462 | | * efi_get_time() - get current time |
463 | | * |
464 | | * This function implements the GetTime runtime service after |
465 | | * SetVirtualAddressMap() is called. As the U-Boot driver are not available |
466 | | * anymore only an error code is returned. |
467 | | * |
468 | | * See the Unified Extensible Firmware Interface (UEFI) specification |
469 | | * for details. |
470 | | * |
471 | | * @time: pointer to structure to receive current time |
472 | | * @capabilities: pointer to structure to receive RTC properties |
473 | | * Returns: status code |
474 | | */ |
475 | | efi_status_t __weak __efi_runtime EFIAPI efi_get_time( |
476 | | struct efi_time *time, |
477 | | struct efi_time_cap *capabilities) |
478 | 0 | { |
479 | 0 | return EFI_UNSUPPORTED; |
480 | 0 | } |
481 | | |
482 | | /** |
483 | | * efi_set_time() - set current time |
484 | | * |
485 | | * This function implements the SetTime runtime service after |
486 | | * SetVirtualAddressMap() is called. As the U-Boot driver are not available |
487 | | * anymore only an error code is returned. |
488 | | * |
489 | | * See the Unified Extensible Firmware Interface (UEFI) specification |
490 | | * for details. |
491 | | * |
492 | | * @time: pointer to structure to with current time |
493 | | * Returns: status code |
494 | | */ |
495 | | efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time) |
496 | 0 | { |
497 | 0 | return EFI_UNSUPPORTED; |
498 | 0 | } |
499 | | |
500 | | /** |
501 | | * efi_update_capsule_unsupported() - process information from operating system |
502 | | * |
503 | | * This function implements the UpdateCapsule() runtime service. |
504 | | * |
505 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
506 | | * details. |
507 | | * |
508 | | * @capsule_header_array: pointer to array of virtual pointers |
509 | | * @capsule_count: number of pointers in capsule_header_array |
510 | | * @scatter_gather_list: pointer to array of physical pointers |
511 | | * Returns: status code |
512 | | */ |
513 | | static efi_status_t __efi_runtime EFIAPI efi_update_capsule_unsupported( |
514 | | struct efi_capsule_header **capsule_header_array, |
515 | | efi_uintn_t capsule_count, |
516 | | u64 scatter_gather_list) |
517 | 0 | { |
518 | 0 | return EFI_UNSUPPORTED; |
519 | 0 | } |
520 | | |
521 | | /** |
522 | | * efi_query_capsule_caps_unsupported() - check if capsule is supported |
523 | | * |
524 | | * This function implements the QueryCapsuleCapabilities() runtime service. |
525 | | * |
526 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
527 | | * details. |
528 | | * |
529 | | * @capsule_header_array: pointer to array of virtual pointers |
530 | | * @capsule_count: number of pointers in capsule_header_array |
531 | | * @maximum_capsule_size: maximum capsule size |
532 | | * @reset_type: type of reset needed for capsule update |
533 | | * Returns: status code |
534 | | */ |
535 | | static efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps_unsupported( |
536 | | struct efi_capsule_header **capsule_header_array, |
537 | | efi_uintn_t capsule_count, |
538 | | u64 *maximum_capsule_size, |
539 | | u32 *reset_type) |
540 | 0 | { |
541 | 0 | return EFI_UNSUPPORTED; |
542 | 0 | } |
543 | | |
544 | | /** |
545 | | * efi_is_runtime_service_pointer() - check if pointer points to runtime table |
546 | | * |
547 | | * @p: pointer to check |
548 | | * Return: true if the pointer points to a service function pointer in the |
549 | | * runtime table |
550 | | */ |
551 | | static bool efi_is_runtime_service_pointer(void *p) |
552 | 0 | { |
553 | 0 | return (p >= (void *)&efi_runtime_services.get_time && |
554 | 0 | p <= (void *)&efi_runtime_services.query_variable_info) || |
555 | 0 | p == (void *)&efi_events.prev || |
556 | 0 | p == (void *)&efi_events.next; |
557 | 0 | } |
558 | | |
559 | | /** |
560 | | * efi_runtime_detach() - detach unimplemented runtime functions |
561 | | */ |
562 | | void efi_runtime_detach(void) |
563 | 0 | { |
564 | 0 | efi_runtime_services.reset_system = efi_reset_system; |
565 | 0 | efi_runtime_services.get_time = efi_get_time; |
566 | 0 | efi_runtime_services.set_time = efi_set_time; |
567 | 0 | if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE)) { |
568 | | /* won't support at runtime */ |
569 | 0 | efi_runtime_services.update_capsule = |
570 | 0 | efi_update_capsule_unsupported; |
571 | 0 | efi_runtime_services.query_capsule_caps = |
572 | 0 | efi_query_capsule_caps_unsupported; |
573 | 0 | } |
574 | | |
575 | | /* Update CRC32 */ |
576 | 0 | efi_update_table_header_crc32(&efi_runtime_services.hdr); |
577 | 0 | } |
578 | | |
579 | | /** |
580 | | * efi_set_virtual_address_map_runtime() - change from physical to virtual |
581 | | * mapping |
582 | | * |
583 | | * This function implements the SetVirtualAddressMap() runtime service after |
584 | | * it is first called. |
585 | | * |
586 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
587 | | * details. |
588 | | * |
589 | | * @memory_map_size: size of the virtual map |
590 | | * @descriptor_size: size of an entry in the map |
591 | | * @descriptor_version: version of the map entries |
592 | | * @virtmap: virtual address mapping information |
593 | | * Return: status code EFI_UNSUPPORTED |
594 | | */ |
595 | | static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime( |
596 | | efi_uintn_t memory_map_size, |
597 | | efi_uintn_t descriptor_size, |
598 | | uint32_t descriptor_version, |
599 | | struct efi_mem_desc *virtmap) |
600 | 0 | { |
601 | 0 | return EFI_UNSUPPORTED; |
602 | 0 | } |
603 | | |
604 | | /** |
605 | | * efi_convert_pointer_runtime() - convert from physical to virtual pointer |
606 | | * |
607 | | * This function implements the ConvertPointer() runtime service after |
608 | | * the first call to SetVirtualAddressMap(). |
609 | | * |
610 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
611 | | * details. |
612 | | * |
613 | | * @debug_disposition: indicates if pointer may be converted to NULL |
614 | | * @address: pointer to be converted |
615 | | * Return: status code EFI_UNSUPPORTED |
616 | | */ |
617 | | static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime( |
618 | | efi_uintn_t debug_disposition, void **address) |
619 | 0 | { |
620 | 0 | return EFI_UNSUPPORTED; |
621 | 0 | } |
622 | | |
623 | | /** |
624 | | * efi_convert_pointer() - convert from physical to virtual pointer |
625 | | * |
626 | | * This function implements the ConvertPointer() runtime service until |
627 | | * the first call to SetVirtualAddressMap(). |
628 | | * |
629 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
630 | | * details. |
631 | | * |
632 | | * @debug_disposition: indicates if pointer may be converted to NULL |
633 | | * @address: pointer to be converted |
634 | | * Return: status code |
635 | | */ |
636 | | __efi_runtime efi_status_t EFIAPI |
637 | | efi_convert_pointer(efi_uintn_t debug_disposition, void **address) |
638 | 0 | { |
639 | 0 | efi_physical_addr_t addr; |
640 | 0 | efi_uintn_t i; |
641 | 0 | efi_status_t ret = EFI_NOT_FOUND; |
642 | |
|
643 | 0 | if (!efi_virtmap) { |
644 | 0 | ret = EFI_UNSUPPORTED; |
645 | 0 | goto out; |
646 | 0 | } |
647 | | |
648 | 0 | if (!address) { |
649 | 0 | ret = EFI_INVALID_PARAMETER; |
650 | 0 | goto out; |
651 | 0 | } |
652 | 0 | if (!*address) { |
653 | 0 | if (debug_disposition & EFI_OPTIONAL_PTR) |
654 | 0 | return EFI_SUCCESS; |
655 | 0 | else |
656 | 0 | return EFI_INVALID_PARAMETER; |
657 | 0 | } |
658 | | |
659 | 0 | addr = (uintptr_t)*address; |
660 | 0 | for (i = 0; i < efi_descriptor_count; i++) { |
661 | 0 | struct efi_mem_desc *map = (void *)efi_virtmap + |
662 | 0 | (efi_descriptor_size * i); |
663 | |
|
664 | 0 | if (addr >= map->physical_start && |
665 | 0 | (addr < map->physical_start |
666 | 0 | + (map->num_pages << EFI_PAGE_SHIFT))) { |
667 | 0 | *address = (void *)(uintptr_t) |
668 | 0 | (addr + map->virtual_start - |
669 | 0 | map->physical_start); |
670 | |
|
671 | 0 | ret = EFI_SUCCESS; |
672 | 0 | break; |
673 | 0 | } |
674 | 0 | } |
675 | |
|
676 | 0 | out: |
677 | 0 | return ret; |
678 | 0 | } |
679 | | |
680 | | static __efi_runtime void efi_relocate_runtime_table(ulong offset) |
681 | 0 | { |
682 | 0 | ulong patchoff; |
683 | 0 | void **pos; |
684 | | |
685 | | /* Relocate the runtime services pointers */ |
686 | 0 | patchoff = offset - gd->relocaddr; |
687 | 0 | for (pos = (void **)&efi_runtime_services.get_time; |
688 | 0 | pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) { |
689 | 0 | if (*pos) |
690 | 0 | *pos += patchoff; |
691 | 0 | } |
692 | | |
693 | | /* |
694 | | * The entry for SetVirtualAddress() must point to a physical address. |
695 | | * After the first execution the service must return EFI_UNSUPPORTED. |
696 | | */ |
697 | 0 | efi_runtime_services.set_virtual_address_map = |
698 | 0 | &efi_set_virtual_address_map_runtime; |
699 | | |
700 | | /* |
701 | | * The entry for ConvertPointer() must point to a physical address. |
702 | | * The service is not usable after SetVirtualAddress(). |
703 | | */ |
704 | 0 | efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime; |
705 | | |
706 | | /* |
707 | | * TODO: Update UEFI variable RuntimeServicesSupported removing flags |
708 | | * EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP and |
709 | | * EFI_RT_SUPPORTED_CONVERT_POINTER as required by the UEFI spec 2.8. |
710 | | */ |
711 | | |
712 | | /* Update CRC32 */ |
713 | 0 | efi_update_table_header_crc32(&efi_runtime_services.hdr); |
714 | 0 | } |
715 | | |
716 | | /* Relocate EFI runtime to uboot_reloc_base = offset */ |
717 | | void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) |
718 | 0 | { |
719 | 0 | #ifdef IS_RELA |
720 | 0 | struct elf_rela *rel = (void *)__efi_runtime_rel_start; |
721 | | #else |
722 | | struct elf_rel *rel = (void *)__efi_runtime_rel_start; |
723 | | static ulong lastoff = CONFIG_TEXT_BASE; |
724 | | #endif |
725 | |
|
726 | 0 | debug("%s: Relocating to offset=%lx\n", __func__, offset); |
727 | 0 | for (; (uintptr_t)rel < (uintptr_t)__efi_runtime_rel_stop; rel++) { |
728 | 0 | ulong base = CONFIG_TEXT_BASE; |
729 | 0 | ulong *p; |
730 | 0 | ulong newaddr; |
731 | |
|
732 | 0 | p = (void*)((ulong)rel->offset - base) + gd->relocaddr; |
733 | | |
734 | | /* |
735 | | * The runtime services table is updated in |
736 | | * efi_relocate_runtime_table() |
737 | | */ |
738 | 0 | if (map && efi_is_runtime_service_pointer(p)) |
739 | 0 | continue; |
740 | | |
741 | 0 | debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__, |
742 | 0 | rel->info, *p, rel->offset); |
743 | |
|
744 | 0 | switch (rel->info & R_MASK) { |
745 | 0 | case R_RELATIVE: |
746 | 0 | #ifdef IS_RELA |
747 | 0 | newaddr = rel->addend + offset - CONFIG_TEXT_BASE; |
748 | | #else |
749 | | newaddr = *p - lastoff + offset; |
750 | | #endif |
751 | 0 | break; |
752 | | #ifdef R_ABSOLUTE |
753 | | case R_ABSOLUTE: { |
754 | | ulong symidx = rel->info >> SYM_INDEX; |
755 | | extern struct dyn_sym __dyn_sym_start[]; |
756 | | newaddr = __dyn_sym_start[symidx].addr + offset; |
757 | | #ifdef IS_RELA |
758 | | newaddr -= CONFIG_TEXT_BASE; |
759 | | #endif |
760 | | break; |
761 | | } |
762 | | #endif |
763 | 0 | default: |
764 | 0 | printf("%s: Unknown relocation type %llx\n", |
765 | 0 | __func__, rel->info & R_MASK); |
766 | 0 | continue; |
767 | 0 | } |
768 | | |
769 | | /* Check if the relocation is inside bounds */ |
770 | 0 | if (map && ((newaddr < map->virtual_start) || |
771 | 0 | newaddr > (map->virtual_start + |
772 | 0 | (map->num_pages << EFI_PAGE_SHIFT)))) { |
773 | 0 | printf("%s: Relocation at %p is out of range (%lx)\n", |
774 | 0 | __func__, p, newaddr); |
775 | 0 | continue; |
776 | 0 | } |
777 | | |
778 | 0 | debug("%s: Setting %p to %lx\n", __func__, p, newaddr); |
779 | 0 | *p = newaddr; |
780 | 0 | flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1), |
781 | 0 | ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE)); |
782 | 0 | } |
783 | | |
784 | | #ifndef IS_RELA |
785 | | lastoff = offset; |
786 | | #endif |
787 | | |
788 | | /* |
789 | | * If on x86 a write affects a prefetched instruction, |
790 | | * the prefetch queue is invalidated. |
791 | | */ |
792 | 0 | if (!CONFIG_IS_ENABLED(X86)) |
793 | 0 | invalidate_icache_all(); |
794 | 0 | } |
795 | | |
796 | | /** |
797 | | * efi_set_virtual_address_map() - change from physical to virtual mapping |
798 | | * |
799 | | * This function implements the SetVirtualAddressMap() runtime service. |
800 | | * |
801 | | * See the Unified Extensible Firmware Interface (UEFI) specification for |
802 | | * details. |
803 | | * |
804 | | * @memory_map_size: size of the virtual map |
805 | | * @descriptor_size: size of an entry in the map |
806 | | * @descriptor_version: version of the map entries |
807 | | * @virtmap: virtual address mapping information |
808 | | * Return: status code |
809 | | */ |
810 | | static efi_status_t EFIAPI efi_set_virtual_address_map( |
811 | | efi_uintn_t memory_map_size, |
812 | | efi_uintn_t descriptor_size, |
813 | | uint32_t descriptor_version, |
814 | | struct efi_mem_desc *virtmap) |
815 | | { |
816 | | efi_uintn_t n = memory_map_size / descriptor_size; |
817 | | efi_uintn_t i; |
818 | | efi_status_t ret = EFI_INVALID_PARAMETER; |
819 | | int rt_code_sections = 0; |
820 | | struct efi_event *event; |
821 | | |
822 | | EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size, |
823 | | descriptor_version, virtmap); |
824 | | |
825 | | if (descriptor_version != EFI_MEMORY_DESCRIPTOR_VERSION || |
826 | | descriptor_size < sizeof(struct efi_mem_desc)) |
827 | | goto out; |
828 | | |
829 | | efi_virtmap = virtmap; |
830 | | efi_descriptor_size = descriptor_size; |
831 | | efi_descriptor_count = n; |
832 | | |
833 | | /* |
834 | | * TODO: |
835 | | * Further down we are cheating. While really we should implement |
836 | | * SetVirtualAddressMap() events and ConvertPointer() to allow |
837 | | * dynamically loaded drivers to expose runtime services, we don't |
838 | | * today. |
839 | | * |
840 | | * So let's ensure we see exactly one single runtime section, as |
841 | | * that is the built-in one. If we see more (or less), someone must |
842 | | * have tried adding or removing to that which we don't support yet. |
843 | | * In that case, let's better fail rather than expose broken runtime |
844 | | * services. |
845 | | */ |
846 | | for (i = 0; i < n; i++) { |
847 | | struct efi_mem_desc *map = (void*)virtmap + |
848 | | (descriptor_size * i); |
849 | | |
850 | | if (map->type == EFI_RUNTIME_SERVICES_CODE) |
851 | | rt_code_sections++; |
852 | | } |
853 | | |
854 | | if (rt_code_sections != 1) { |
855 | | /* |
856 | | * We expose exactly one single runtime code section, so |
857 | | * something is definitely going wrong. |
858 | | */ |
859 | | goto out; |
860 | | } |
861 | | |
862 | | /* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */ |
863 | | list_for_each_entry(event, &efi_events, link) { |
864 | | if (event->notify_function) |
865 | | EFI_CALL_VOID(event->notify_function( |
866 | | event, event->notify_context)); |
867 | | } |
868 | | |
869 | | /* Rebind mmio pointers */ |
870 | | for (i = 0; i < n; i++) { |
871 | | struct efi_mem_desc *map = (void*)virtmap + |
872 | | (descriptor_size * i); |
873 | | struct list_head *lhandle; |
874 | | efi_physical_addr_t map_start = map->physical_start; |
875 | | efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT; |
876 | | efi_physical_addr_t map_end = map_start + map_len; |
877 | | u64 off = map->virtual_start - map_start; |
878 | | |
879 | | /* Adjust all mmio pointers in this region */ |
880 | | list_for_each(lhandle, &efi_runtime_mmio) { |
881 | | struct efi_runtime_mmio_list *lmmio; |
882 | | |
883 | | lmmio = list_entry(lhandle, |
884 | | struct efi_runtime_mmio_list, |
885 | | link); |
886 | | if ((map_start <= lmmio->paddr) && |
887 | | (map_end >= lmmio->paddr)) { |
888 | | uintptr_t new_addr = lmmio->paddr + off; |
889 | | *lmmio->ptr = (void *)new_addr; |
890 | | } |
891 | | } |
892 | | if ((map_start <= (uintptr_t)systab.tables) && |
893 | | (map_end >= (uintptr_t)systab.tables)) { |
894 | | char *ptr = (char *)systab.tables; |
895 | | |
896 | | ptr += off; |
897 | | systab.tables = (struct efi_configuration_table *)ptr; |
898 | | } |
899 | | } |
900 | | |
901 | | /* Relocate the runtime. See TODO above */ |
902 | | for (i = 0; i < n; i++) { |
903 | | struct efi_mem_desc *map; |
904 | | |
905 | | map = (void*)virtmap + (descriptor_size * i); |
906 | | if (map->type == EFI_RUNTIME_SERVICES_CODE) { |
907 | | ulong new_offset = map->virtual_start - |
908 | | map->physical_start + gd->relocaddr; |
909 | | |
910 | | efi_relocate_runtime_table(new_offset); |
911 | | efi_runtime_relocate(new_offset, map); |
912 | | ret = EFI_SUCCESS; |
913 | | goto out; |
914 | | } |
915 | | } |
916 | | |
917 | | out: |
918 | | return EFI_EXIT(ret); |
919 | | } |
920 | | |
921 | | /** |
922 | | * efi_add_runtime_mmio() - add memory-mapped IO region |
923 | | * |
924 | | * This function adds a memory-mapped IO region to the memory map to make it |
925 | | * available at runtime. |
926 | | * |
927 | | * @mmio_ptr: pointer to a pointer to the start of the memory-mapped |
928 | | * IO region |
929 | | * @len: size of the memory-mapped IO region |
930 | | * Returns: status code |
931 | | */ |
932 | | efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) |
933 | 0 | { |
934 | 0 | struct efi_runtime_mmio_list *newmmio; |
935 | 0 | uint64_t addr = *(uintptr_t *)mmio_ptr; |
936 | 0 | efi_status_t ret; |
937 | |
|
938 | 0 | ret = efi_add_memory_map(addr, len, EFI_MMAP_IO); |
939 | 0 | if (ret != EFI_SUCCESS) |
940 | 0 | return EFI_OUT_OF_RESOURCES; |
941 | | |
942 | 0 | newmmio = calloc(1, sizeof(*newmmio)); |
943 | 0 | if (!newmmio) |
944 | 0 | return EFI_OUT_OF_RESOURCES; |
945 | 0 | newmmio->ptr = mmio_ptr; |
946 | 0 | newmmio->paddr = *(uintptr_t *)mmio_ptr; |
947 | 0 | newmmio->len = len; |
948 | 0 | list_add_tail(&newmmio->link, &efi_runtime_mmio); |
949 | |
|
950 | 0 | return EFI_SUCCESS; |
951 | 0 | } |
952 | | |
953 | | /* |
954 | | * In the second stage, U-Boot has disappeared. To isolate our runtime code |
955 | | * that at this point still exists from the rest, we put it into a special |
956 | | * section. |
957 | | * |
958 | | * !!WARNING!! |
959 | | * |
960 | | * This means that we can not rely on any code outside of this file in any |
961 | | * function or variable below this line. |
962 | | * |
963 | | * Please keep everything fully self-contained and annotated with |
964 | | * __efi_runtime and __efi_runtime_data markers. |
965 | | */ |
966 | | |
967 | | /* |
968 | | * Relocate the EFI runtime stub to a different place. We need to call this |
969 | | * the first time we expose the runtime interface to a user and on set virtual |
970 | | * address map calls. |
971 | | */ |
972 | | |
973 | | /** |
974 | | * efi_unimplemented() - replacement function, returns EFI_UNSUPPORTED |
975 | | * |
976 | | * This function is used after SetVirtualAddressMap() is called as replacement |
977 | | * for services that are not available anymore due to constraints of the U-Boot |
978 | | * implementation. |
979 | | * |
980 | | * Return: EFI_UNSUPPORTED |
981 | | */ |
982 | | static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void) |
983 | 0 | { |
984 | 0 | return EFI_UNSUPPORTED; |
985 | 0 | } |
986 | | |
987 | | struct efi_runtime_services __efi_runtime_data efi_runtime_services = { |
988 | | .hdr = { |
989 | | .signature = EFI_RUNTIME_SERVICES_SIGNATURE, |
990 | | .revision = EFI_SPECIFICATION_VERSION, |
991 | | .headersize = sizeof(struct efi_runtime_services), |
992 | | }, |
993 | | .get_time = &efi_get_time_boottime, |
994 | | .set_time = &efi_set_time_boottime, |
995 | | .get_wakeup_time = (void *)&efi_unimplemented, |
996 | | .set_wakeup_time = (void *)&efi_unimplemented, |
997 | | .set_virtual_address_map = &efi_set_virtual_address_map, |
998 | | .convert_pointer = efi_convert_pointer, |
999 | | .get_variable = efi_get_variable, |
1000 | | .get_next_variable_name = efi_get_next_variable_name, |
1001 | | .set_variable = efi_set_variable, |
1002 | | .get_next_high_mono_count = (void *)&efi_unimplemented, |
1003 | | .reset_system = &efi_reset_system_boottime, |
1004 | | #ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE |
1005 | | .update_capsule = efi_update_capsule, |
1006 | | .query_capsule_caps = efi_query_capsule_caps, |
1007 | | #else |
1008 | | .update_capsule = efi_update_capsule_unsupported, |
1009 | | .query_capsule_caps = efi_query_capsule_caps_unsupported, |
1010 | | #endif |
1011 | | .query_variable_info = efi_query_variable_info, |
1012 | | }; |