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 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_unimplemented(void);
20 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_device_error(void);
21 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_invalid_parameter(void);
23 #ifdef CONFIG_SYS_CACHELINE_SIZE
24 #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
26 /* Just use the greatest cache flush alignment requirement I'm aware of */
27 #define EFI_CACHELINE_SIZE 128
30 #if defined(CONFIG_ARM64)
31 #define R_RELATIVE 1027
32 #define R_MASK 0xffffffffULL
34 #elif defined(CONFIG_ARM)
36 #define R_MASK 0xffULL
38 #error Need to add relocation awareness
53 * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI
54 * payload are running concurrently at the same time. In this mode, we can
55 * handle a good number of runtime callbacks
58 static void EFIAPI
efi_reset_system(enum efi_reset_type reset_type
,
59 efi_status_t reset_status
,
60 unsigned long data_size
, void *reset_data
)
62 EFI_ENTRY("%d %lx %lx %p", reset_type
, reset_status
, data_size
,
68 do_reset(NULL
, 0, 0, NULL
);
70 case EFI_RESET_SHUTDOWN
:
71 /* We don't have anything to map this to */
75 EFI_EXIT(EFI_SUCCESS
);
78 static efi_status_t EFIAPI
efi_get_time(struct efi_time
*time
,
79 struct efi_time_cap
*capabilities
)
81 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
86 EFI_ENTRY("%p %p", time
, capabilities
);
88 r
= uclass_get_device(UCLASS_RTC
, 0, &dev
);
90 return EFI_EXIT(EFI_DEVICE_ERROR
);
92 r
= dm_rtc_get(dev
, &tm
);
94 return EFI_EXIT(EFI_DEVICE_ERROR
);
96 memset(time
, 0, sizeof(*time
));
97 time
->year
= tm
.tm_year
;
98 time
->month
= tm
.tm_mon
;
99 time
->day
= tm
.tm_mday
;
100 time
->hour
= tm
.tm_hour
;
101 time
->minute
= tm
.tm_min
;
102 time
->daylight
= tm
.tm_isdst
;
104 return EFI_EXIT(EFI_SUCCESS
);
106 return EFI_DEVICE_ERROR
;
110 struct efi_runtime_detach_list_struct
{
115 static const struct efi_runtime_detach_list_struct efi_runtime_detach_list
[] = {
117 /* do_reset is gone */
118 .ptr
= &efi_runtime_services
.reset_system
,
121 /* invalidate_*cache_all are gone */
122 .ptr
= &efi_runtime_services
.set_virtual_address_map
,
123 .patchto
= &efi_invalid_parameter
,
125 /* RTC accessors are gone */
126 .ptr
= &efi_runtime_services
.get_time
,
127 .patchto
= &efi_device_error
,
129 /* Clean up system table */
130 .ptr
= &systab
.con_in
,
133 /* Clean up system table */
134 .ptr
= &systab
.con_out
,
137 /* Clean up system table */
138 .ptr
= &systab
.std_err
,
141 /* Clean up system table */
142 .ptr
= &systab
.boottime
,
147 static bool efi_runtime_tobedetached(void *p
)
151 for (i
= 0; i
< ARRAY_SIZE(efi_runtime_detach_list
); i
++)
152 if (efi_runtime_detach_list
[i
].ptr
== p
)
158 static void efi_runtime_detach(ulong offset
)
161 ulong patchoff
= offset
- (ulong
)gd
->relocaddr
;
163 for (i
= 0; i
< ARRAY_SIZE(efi_runtime_detach_list
); i
++) {
164 ulong patchto
= (ulong
)efi_runtime_detach_list
[i
].patchto
;
165 ulong
*p
= efi_runtime_detach_list
[i
].ptr
;
166 ulong newaddr
= patchto
? (patchto
+ patchoff
) : 0;
169 printf("%s: Setting %p to %lx\n", __func__
, p
, newaddr
);
175 /* Relocate EFI runtime to uboot_reloc_base = offset */
176 void efi_runtime_relocate(ulong offset
, struct efi_mem_desc
*map
)
179 struct elf_rela
*rel
= (void*)&__efi_runtime_rel_start
;
181 struct elf_rel
*rel
= (void*)&__efi_runtime_rel_start
;
182 static ulong lastoff
= CONFIG_SYS_TEXT_BASE
;
186 printf("%s: Relocating to offset=%lx\n", __func__
, offset
);
189 for (; (ulong
)rel
< (ulong
)&__efi_runtime_rel_stop
; rel
++) {
190 ulong base
= CONFIG_SYS_TEXT_BASE
;
194 p
= (void*)((ulong
)rel
->offset
- base
) + gd
->relocaddr
;
196 if ((rel
->info
& R_MASK
) != R_RELATIVE
) {
201 newaddr
= rel
->addend
+ offset
- CONFIG_SYS_TEXT_BASE
;
203 newaddr
= *p
- lastoff
+ offset
;
206 /* Check if the relocation is inside bounds */
207 if (map
&& ((newaddr
< map
->virtual_start
) ||
208 newaddr
> (map
->virtual_start
+ (map
->num_pages
<< 12)))) {
209 if (!efi_runtime_tobedetached(p
))
210 printf("U-Boot EFI: Relocation at %p is out of "
211 "range (%lx)\n", p
, newaddr
);
216 printf("%s: Setting %p to %lx\n", __func__
, p
, newaddr
);
220 flush_dcache_range((ulong
)p
& ~(EFI_CACHELINE_SIZE
- 1),
221 ALIGN((ulong
)&p
[1], EFI_CACHELINE_SIZE
));
228 invalidate_icache_all();
231 static efi_status_t EFIAPI
efi_set_virtual_address_map(
232 unsigned long memory_map_size
,
233 unsigned long descriptor_size
,
234 uint32_t descriptor_version
,
235 struct efi_mem_desc
*virtmap
)
237 ulong runtime_start
= (ulong
)&__efi_runtime_start
& ~0xfffULL
;
238 int n
= memory_map_size
/ descriptor_size
;
241 EFI_ENTRY("%lx %lx %x %p", memory_map_size
, descriptor_size
,
242 descriptor_version
, virtmap
);
244 for (i
= 0; i
< n
; i
++) {
245 struct efi_mem_desc
*map
;
247 map
= (void*)virtmap
+ (descriptor_size
* i
);
248 if (map
->type
== EFI_RUNTIME_SERVICES_CODE
) {
249 ulong new_offset
= map
->virtual_start
- (runtime_start
- gd
->relocaddr
);
251 efi_runtime_relocate(new_offset
, map
);
252 /* Once we're virtual, we can no longer handle
254 efi_runtime_detach(new_offset
);
255 return EFI_EXIT(EFI_SUCCESS
);
259 return EFI_EXIT(EFI_INVALID_PARAMETER
);
263 * In the second stage, U-Boot has disappeared. To isolate our runtime code
264 * that at this point still exists from the rest, we put it into a special
269 * This means that we can not rely on any code outside of this file in any
270 * function or variable below this line.
272 * Please keep everything fully self-contained and annotated with
273 * EFI_RUNTIME_TEXT and EFI_RUNTIME_DATA markers.
277 * Relocate the EFI runtime stub to a different place. We need to call this
278 * the first time we expose the runtime interface to a user and on set virtual
282 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_unimplemented(void)
284 return EFI_UNSUPPORTED
;
287 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_device_error(void)
289 return EFI_DEVICE_ERROR
;
292 static efi_status_t EFI_RUNTIME_TEXT EFIAPI
efi_invalid_parameter(void)
294 return EFI_INVALID_PARAMETER
;
297 struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services
= {
299 .signature
= EFI_RUNTIME_SERVICES_SIGNATURE
,
300 .revision
= EFI_RUNTIME_SERVICES_REVISION
,
301 .headersize
= sizeof(struct efi_table_hdr
),
303 .get_time
= &efi_get_time
,
304 .set_time
= (void *)&efi_device_error
,
305 .get_wakeup_time
= (void *)&efi_unimplemented
,
306 .set_wakeup_time
= (void *)&efi_unimplemented
,
307 .set_virtual_address_map
= &efi_set_virtual_address_map
,
308 .convert_pointer
= (void *)&efi_invalid_parameter
,
309 .get_variable
= (void *)&efi_device_error
,
310 .get_next_variable
= (void *)&efi_device_error
,
311 .set_variable
= (void *)&efi_device_error
,
312 .get_next_high_mono_count
= (void *)&efi_device_error
,
313 .reset_system
= &efi_reset_system
,