2 * EFI application runtime services
4 * Copyright (c) 2016 Alexander Graf
6 * SPDX-License-Identifier: GPL-2.0+
12 #include <efi_loader.h>
14 #include <asm/global_data.h>
16 /* For manual relocation support */
17 DECLARE_GLOBAL_DATA_PTR
;
19 struct efi_runtime_mmio_list
{
20 struct list_head link
;
26 /* This list contains all runtime available mmio regions */
27 LIST_HEAD(efi_runtime_mmio
);
29 static efi_status_t __efi_runtime EFIAPI
efi_unimplemented(void);
30 static efi_status_t __efi_runtime EFIAPI
efi_device_error(void);
31 static efi_status_t __efi_runtime EFIAPI
efi_invalid_parameter(void);
33 #ifdef CONFIG_SYS_CACHELINE_SIZE
34 #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
36 /* Just use the greatest cache flush alignment requirement I'm aware of */
37 #define EFI_CACHELINE_SIZE 128
40 #if defined(CONFIG_ARM64)
41 #define R_RELATIVE 1027
42 #define R_MASK 0xffffffffULL
44 #elif defined(CONFIG_ARM)
46 #define R_MASK 0xffULL
47 #elif defined(CONFIG_X86)
49 #define R_RELATIVE R_386_RELATIVE
50 #define R_MASK 0xffULL
52 #error Need to add relocation awareness
67 * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI
68 * payload are running concurrently at the same time. In this mode, we can
69 * handle a good number of runtime callbacks
72 static void EFIAPI
efi_reset_system_boottime(
73 enum efi_reset_type reset_type
,
74 efi_status_t reset_status
,
75 unsigned long data_size
, void *reset_data
)
77 EFI_ENTRY("%d %lx %lx %p", reset_type
, reset_status
, data_size
,
83 do_reset(NULL
, 0, 0, NULL
);
85 case EFI_RESET_SHUTDOWN
:
86 /* We don't have anything to map this to */
93 static efi_status_t EFIAPI
efi_get_time_boottime(
94 struct efi_time
*time
,
95 struct efi_time_cap
*capabilities
)
97 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
102 EFI_ENTRY("%p %p", time
, capabilities
);
104 r
= uclass_get_device(UCLASS_RTC
, 0, &dev
);
106 return EFI_EXIT(EFI_DEVICE_ERROR
);
108 r
= dm_rtc_get(dev
, &tm
);
110 return EFI_EXIT(EFI_DEVICE_ERROR
);
112 memset(time
, 0, sizeof(*time
));
113 time
->year
= tm
.tm_year
;
114 time
->month
= tm
.tm_mon
;
115 time
->day
= tm
.tm_mday
;
116 time
->hour
= tm
.tm_hour
;
117 time
->minute
= tm
.tm_min
;
118 time
->daylight
= tm
.tm_isdst
;
120 return EFI_EXIT(EFI_SUCCESS
);
122 return EFI_DEVICE_ERROR
;
126 /* Boards may override the helpers below to implement RTS functionality */
128 void __weak __efi_runtime EFIAPI
efi_reset_system(
129 enum efi_reset_type reset_type
,
130 efi_status_t reset_status
,
131 unsigned long data_size
, void *reset_data
)
133 /* Nothing we can do */
137 void __weak
efi_reset_system_init(void)
141 efi_status_t __weak __efi_runtime EFIAPI
efi_get_time(
142 struct efi_time
*time
,
143 struct efi_time_cap
*capabilities
)
145 /* Nothing we can do */
146 return EFI_DEVICE_ERROR
;
149 void __weak
efi_get_time_init(void)
153 struct efi_runtime_detach_list_struct
{
158 static const struct efi_runtime_detach_list_struct efi_runtime_detach_list
[] = {
160 /* do_reset is gone */
161 .ptr
= &efi_runtime_services
.reset_system
,
162 .patchto
= efi_reset_system
,
164 /* invalidate_*cache_all are gone */
165 .ptr
= &efi_runtime_services
.set_virtual_address_map
,
166 .patchto
= &efi_invalid_parameter
,
168 /* RTC accessors are gone */
169 .ptr
= &efi_runtime_services
.get_time
,
170 .patchto
= &efi_get_time
,
172 /* Clean up system table */
173 .ptr
= &systab
.con_in
,
176 /* Clean up system table */
177 .ptr
= &systab
.con_out
,
180 /* Clean up system table */
181 .ptr
= &systab
.std_err
,
184 /* Clean up system table */
185 .ptr
= &systab
.boottime
,
188 .ptr
= &efi_runtime_services
.get_variable
,
189 .patchto
= &efi_device_error
,
191 .ptr
= &efi_runtime_services
.get_next_variable
,
192 .patchto
= &efi_device_error
,
194 .ptr
= &efi_runtime_services
.set_variable
,
195 .patchto
= &efi_device_error
,
199 static bool efi_runtime_tobedetached(void *p
)
203 for (i
= 0; i
< ARRAY_SIZE(efi_runtime_detach_list
); i
++)
204 if (efi_runtime_detach_list
[i
].ptr
== p
)
210 static void efi_runtime_detach(ulong offset
)
213 ulong patchoff
= offset
- (ulong
)gd
->relocaddr
;
215 for (i
= 0; i
< ARRAY_SIZE(efi_runtime_detach_list
); i
++) {
216 ulong patchto
= (ulong
)efi_runtime_detach_list
[i
].patchto
;
217 ulong
*p
= efi_runtime_detach_list
[i
].ptr
;
218 ulong newaddr
= patchto
? (patchto
+ patchoff
) : 0;
220 debug("%s: Setting %p to %lx\n", __func__
, p
, newaddr
);
225 /* Relocate EFI runtime to uboot_reloc_base = offset */
226 void efi_runtime_relocate(ulong offset
, struct efi_mem_desc
*map
)
229 struct elf_rela
*rel
= (void*)&__efi_runtime_rel_start
;
231 struct elf_rel
*rel
= (void*)&__efi_runtime_rel_start
;
232 static ulong lastoff
= CONFIG_SYS_TEXT_BASE
;
235 debug("%s: Relocating to offset=%lx\n", __func__
, offset
);
236 for (; (ulong
)rel
< (ulong
)&__efi_runtime_rel_stop
; rel
++) {
237 ulong base
= CONFIG_SYS_TEXT_BASE
;
241 p
= (void*)((ulong
)rel
->offset
- base
) + gd
->relocaddr
;
243 if ((rel
->info
& R_MASK
) != R_RELATIVE
) {
248 newaddr
= rel
->addend
+ offset
- CONFIG_SYS_TEXT_BASE
;
250 newaddr
= *p
- lastoff
+ offset
;
253 /* Check if the relocation is inside bounds */
254 if (map
&& ((newaddr
< map
->virtual_start
) ||
255 newaddr
> (map
->virtual_start
+
256 (map
->num_pages
<< EFI_PAGE_SHIFT
)))) {
257 if (!efi_runtime_tobedetached(p
))
258 printf("U-Boot EFI: Relocation at %p is out of "
259 "range (%lx)\n", p
, newaddr
);
263 debug("%s: Setting %p to %lx\n", __func__
, p
, newaddr
);
265 flush_dcache_range((ulong
)p
& ~(EFI_CACHELINE_SIZE
- 1),
266 ALIGN((ulong
)&p
[1], EFI_CACHELINE_SIZE
));
273 invalidate_icache_all();
276 static efi_status_t EFIAPI
efi_set_virtual_address_map(
277 unsigned long memory_map_size
,
278 unsigned long descriptor_size
,
279 uint32_t descriptor_version
,
280 struct efi_mem_desc
*virtmap
)
282 ulong runtime_start
= (ulong
)&__efi_runtime_start
&
283 ~(ulong
)EFI_PAGE_MASK
;
284 int n
= memory_map_size
/ descriptor_size
;
287 EFI_ENTRY("%lx %lx %x %p", memory_map_size
, descriptor_size
,
288 descriptor_version
, virtmap
);
290 /* Rebind mmio pointers */
291 for (i
= 0; i
< n
; i
++) {
292 struct efi_mem_desc
*map
= (void*)virtmap
+
293 (descriptor_size
* i
);
294 struct list_head
*lhandle
;
295 efi_physical_addr_t map_start
= map
->physical_start
;
296 efi_physical_addr_t map_len
= map
->num_pages
<< EFI_PAGE_SHIFT
;
297 efi_physical_addr_t map_end
= map_start
+ map_len
;
299 /* Adjust all mmio pointers in this region */
300 list_for_each(lhandle
, &efi_runtime_mmio
) {
301 struct efi_runtime_mmio_list
*lmmio
;
303 lmmio
= list_entry(lhandle
,
304 struct efi_runtime_mmio_list
,
306 if ((map_start
<= lmmio
->paddr
) &&
307 (map_end
>= lmmio
->paddr
)) {
308 u64 off
= map
->virtual_start
- map_start
;
309 uintptr_t new_addr
= lmmio
->paddr
+ off
;
310 *lmmio
->ptr
= (void *)new_addr
;
315 /* Move the actual runtime code over */
316 for (i
= 0; i
< n
; i
++) {
317 struct efi_mem_desc
*map
;
319 map
= (void*)virtmap
+ (descriptor_size
* i
);
320 if (map
->type
== EFI_RUNTIME_SERVICES_CODE
) {
321 ulong new_offset
= map
->virtual_start
-
322 (runtime_start
- gd
->relocaddr
);
324 efi_runtime_relocate(new_offset
, map
);
325 /* Once we're virtual, we can no longer handle
327 efi_runtime_detach(new_offset
);
328 return EFI_EXIT(EFI_SUCCESS
);
332 return EFI_EXIT(EFI_INVALID_PARAMETER
);
335 void efi_add_runtime_mmio(void *mmio_ptr
, u64 len
)
337 struct efi_runtime_mmio_list
*newmmio
;
339 u64 pages
= (len
+ EFI_PAGE_MASK
) >> EFI_PAGE_SHIFT
;
340 efi_add_memory_map(*(uintptr_t *)mmio_ptr
, pages
, EFI_MMAP_IO
, false);
342 newmmio
= calloc(1, sizeof(*newmmio
));
343 newmmio
->ptr
= mmio_ptr
;
344 newmmio
->paddr
= *(uintptr_t *)mmio_ptr
;
346 list_add_tail(&newmmio
->link
, &efi_runtime_mmio
);
350 * In the second stage, U-Boot has disappeared. To isolate our runtime code
351 * that at this point still exists from the rest, we put it into a special
356 * This means that we can not rely on any code outside of this file in any
357 * function or variable below this line.
359 * Please keep everything fully self-contained and annotated with
360 * __efi_runtime and __efi_runtime_data markers.
364 * Relocate the EFI runtime stub to a different place. We need to call this
365 * the first time we expose the runtime interface to a user and on set virtual
369 static efi_status_t __efi_runtime EFIAPI
efi_unimplemented(void)
371 return EFI_UNSUPPORTED
;
374 static efi_status_t __efi_runtime EFIAPI
efi_device_error(void)
376 return EFI_DEVICE_ERROR
;
379 static efi_status_t __efi_runtime EFIAPI
efi_invalid_parameter(void)
381 return EFI_INVALID_PARAMETER
;
384 struct efi_runtime_services __efi_runtime_data efi_runtime_services
= {
386 .signature
= EFI_RUNTIME_SERVICES_SIGNATURE
,
387 .revision
= EFI_RUNTIME_SERVICES_REVISION
,
388 .headersize
= sizeof(struct efi_table_hdr
),
390 .get_time
= &efi_get_time_boottime
,
391 .set_time
= (void *)&efi_device_error
,
392 .get_wakeup_time
= (void *)&efi_unimplemented
,
393 .set_wakeup_time
= (void *)&efi_unimplemented
,
394 .set_virtual_address_map
= &efi_set_virtual_address_map
,
395 .convert_pointer
= (void *)&efi_invalid_parameter
,
396 .get_variable
= efi_get_variable
,
397 .get_next_variable
= efi_get_next_variable
,
398 .set_variable
= efi_set_variable
,
399 .get_next_high_mono_count
= (void *)&efi_device_error
,
400 .reset_system
= &efi_reset_system_boottime
,