xref: /openbmc/u-boot/lib/efi_loader/efi_runtime.c (revision 9d466f2f)
1 /*
2  *  EFI application runtime services
3  *
4  *  Copyright (c) 2016 Alexander Graf
5  *
6  *  SPDX-License-Identifier:     GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <command.h>
11 #include <dm.h>
12 #include <efi_loader.h>
13 #include <rtc.h>
14 #include <asm/global_data.h>
15 
16 /* For manual relocation support */
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 struct efi_runtime_mmio_list {
20 	struct list_head link;
21 	void **ptr;
22 	u64 paddr;
23 	u64 len;
24 };
25 
26 /* This list contains all runtime available mmio regions */
27 LIST_HEAD(efi_runtime_mmio);
28 
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);
32 
33 #ifdef CONFIG_SYS_CACHELINE_SIZE
34 #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
35 #else
36 /* Just use the greatest cache flush alignment requirement I'm aware of */
37 #define EFI_CACHELINE_SIZE 128
38 #endif
39 
40 #if defined(CONFIG_ARM64)
41 #define R_RELATIVE	1027
42 #define R_MASK		0xffffffffULL
43 #define IS_RELA		1
44 #elif defined(CONFIG_ARM)
45 #define R_RELATIVE	23
46 #define R_MASK		0xffULL
47 #elif defined(CONFIG_X86)
48 #include <asm/elf.h>
49 #define R_RELATIVE	R_386_RELATIVE
50 #define R_MASK		0xffULL
51 #else
52 #error Need to add relocation awareness
53 #endif
54 
55 struct elf_rel {
56 	ulong *offset;
57 	ulong info;
58 };
59 
60 struct elf_rela {
61 	ulong *offset;
62 	ulong info;
63 	long addend;
64 };
65 
66 /*
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
70  */
71 
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)
76 {
77 	EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
78 		  reset_data);
79 
80 	switch (reset_type) {
81 	case EFI_RESET_COLD:
82 	case EFI_RESET_WARM:
83 		do_reset(NULL, 0, 0, NULL);
84 		break;
85 	case EFI_RESET_SHUTDOWN:
86 		/* We don't have anything to map this to */
87 		break;
88 	}
89 
90 	while (1) { }
91 }
92 
93 static efi_status_t EFIAPI efi_get_time_boottime(
94 			struct efi_time *time,
95 			struct efi_time_cap *capabilities)
96 {
97 #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
98 	struct rtc_time tm;
99 	int r;
100 	struct udevice *dev;
101 
102 	EFI_ENTRY("%p %p", time, capabilities);
103 
104 	r = uclass_get_device(UCLASS_RTC, 0, &dev);
105 	if (r)
106 		return EFI_EXIT(EFI_DEVICE_ERROR);
107 
108 	r = dm_rtc_get(dev, &tm);
109 	if (r)
110 		return EFI_EXIT(EFI_DEVICE_ERROR);
111 
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;
119 
120 	return EFI_EXIT(EFI_SUCCESS);
121 #else
122 	return EFI_DEVICE_ERROR;
123 #endif
124 }
125 
126 /* Boards may override the helpers below to implement RTS functionality */
127 
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)
132 {
133 	/* Nothing we can do */
134 	while (1) { }
135 }
136 
137 void __weak efi_reset_system_init(void)
138 {
139 }
140 
141 efi_status_t __weak __efi_runtime EFIAPI efi_get_time(
142 			struct efi_time *time,
143 			struct efi_time_cap *capabilities)
144 {
145 	/* Nothing we can do */
146 	return EFI_DEVICE_ERROR;
147 }
148 
149 void __weak efi_get_time_init(void)
150 {
151 }
152 
153 struct efi_runtime_detach_list_struct {
154 	void *ptr;
155 	void *patchto;
156 };
157 
158 static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
159 	{
160 		/* do_reset is gone */
161 		.ptr = &efi_runtime_services.reset_system,
162 		.patchto = efi_reset_system,
163 	}, {
164 		/* invalidate_*cache_all are gone */
165 		.ptr = &efi_runtime_services.set_virtual_address_map,
166 		.patchto = &efi_invalid_parameter,
167 	}, {
168 		/* RTC accessors are gone */
169 		.ptr = &efi_runtime_services.get_time,
170 		.patchto = &efi_get_time,
171 	}, {
172 		/* Clean up system table */
173 		.ptr = &systab.con_in,
174 		.patchto = NULL,
175 	}, {
176 		/* Clean up system table */
177 		.ptr = &systab.con_out,
178 		.patchto = NULL,
179 	}, {
180 		/* Clean up system table */
181 		.ptr = &systab.std_err,
182 		.patchto = NULL,
183 	}, {
184 		/* Clean up system table */
185 		.ptr = &systab.boottime,
186 		.patchto = NULL,
187 	}, {
188 		.ptr = &efi_runtime_services.get_variable,
189 		.patchto = &efi_device_error,
190 	}, {
191 		.ptr = &efi_runtime_services.get_next_variable,
192 		.patchto = &efi_device_error,
193 	}, {
194 		.ptr = &efi_runtime_services.set_variable,
195 		.patchto = &efi_device_error,
196 	}
197 };
198 
199 static bool efi_runtime_tobedetached(void *p)
200 {
201 	int i;
202 
203 	for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++)
204 		if (efi_runtime_detach_list[i].ptr == p)
205 			return true;
206 
207 	return false;
208 }
209 
210 static void efi_runtime_detach(ulong offset)
211 {
212 	int i;
213 	ulong patchoff = offset - (ulong)gd->relocaddr;
214 
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;
219 
220 		debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
221 		*p = newaddr;
222 	}
223 }
224 
225 /* Relocate EFI runtime to uboot_reloc_base = offset */
226 void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
227 {
228 #ifdef IS_RELA
229 	struct elf_rela *rel = (void*)&__efi_runtime_rel_start;
230 #else
231 	struct elf_rel *rel = (void*)&__efi_runtime_rel_start;
232 	static ulong lastoff = CONFIG_SYS_TEXT_BASE;
233 #endif
234 
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;
238 		ulong *p;
239 		ulong newaddr;
240 
241 		p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
242 
243 		if ((rel->info & R_MASK) != R_RELATIVE) {
244 			continue;
245 		}
246 
247 #ifdef IS_RELA
248 		newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE;
249 #else
250 		newaddr = *p - lastoff + offset;
251 #endif
252 
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);
260 			continue;
261 		}
262 
263 		debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
264 		*p = newaddr;
265 		flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1),
266 			ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE));
267 	}
268 
269 #ifndef IS_RELA
270 	lastoff = offset;
271 #endif
272 
273         invalidate_icache_all();
274 }
275 
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)
281 {
282 	ulong runtime_start = (ulong)&__efi_runtime_start &
283 			      ~(ulong)EFI_PAGE_MASK;
284 	int n = memory_map_size / descriptor_size;
285 	int i;
286 
287 	EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
288 		  descriptor_version, virtmap);
289 
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;
298 
299 		/* Adjust all mmio pointers in this region */
300 		list_for_each(lhandle, &efi_runtime_mmio) {
301 			struct efi_runtime_mmio_list *lmmio;
302 
303 			lmmio = list_entry(lhandle,
304 					   struct efi_runtime_mmio_list,
305 					   link);
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;
311 			}
312 		}
313 	}
314 
315 	/* Move the actual runtime code over */
316 	for (i = 0; i < n; i++) {
317 		struct efi_mem_desc *map;
318 
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);
323 
324 			efi_runtime_relocate(new_offset, map);
325 			/* Once we're virtual, we can no longer handle
326 			   complex callbacks */
327 			efi_runtime_detach(new_offset);
328 			return EFI_EXIT(EFI_SUCCESS);
329 		}
330 	}
331 
332 	return EFI_EXIT(EFI_INVALID_PARAMETER);
333 }
334 
335 void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
336 {
337 	struct efi_runtime_mmio_list *newmmio;
338 
339 	u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
340 	efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
341 
342 	newmmio = calloc(1, sizeof(*newmmio));
343 	newmmio->ptr = mmio_ptr;
344 	newmmio->paddr = *(uintptr_t *)mmio_ptr;
345 	newmmio->len = len;
346 	list_add_tail(&newmmio->link, &efi_runtime_mmio);
347 }
348 
349 /*
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
352  * section.
353  *
354  *        !!WARNING!!
355  *
356  * This means that we can not rely on any code outside of this file in any
357  * function or variable below this line.
358  *
359  * Please keep everything fully self-contained and annotated with
360  * __efi_runtime and __efi_runtime_data markers.
361  */
362 
363 /*
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
366  * address map calls.
367  */
368 
369 static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
370 {
371 	return EFI_UNSUPPORTED;
372 }
373 
374 static efi_status_t __efi_runtime EFIAPI efi_device_error(void)
375 {
376 	return EFI_DEVICE_ERROR;
377 }
378 
379 static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void)
380 {
381 	return EFI_INVALID_PARAMETER;
382 }
383 
384 efi_status_t __efi_runtime EFIAPI efi_update_capsule(
385 			struct efi_capsule_header **capsule_header_array,
386 			efi_uintn_t capsule_count,
387 			u64 scatter_gather_list)
388 {
389 	return EFI_UNSUPPORTED;
390 }
391 
392 efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
393 			struct efi_capsule_header **capsule_header_array,
394 			efi_uintn_t capsule_count,
395 			u64 maximum_capsule_size,
396 			u32 reset_type)
397 {
398 	return EFI_UNSUPPORTED;
399 }
400 
401 efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
402 			u32 attributes,
403 			u64 maximum_variable_storage_size,
404 			u64 remaining_variable_storage_size,
405 			u64 maximum_variable_size)
406 {
407 	return EFI_UNSUPPORTED;
408 }
409 
410 struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
411 	.hdr = {
412 		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
413 		.revision = EFI_RUNTIME_SERVICES_REVISION,
414 		.headersize = sizeof(struct efi_table_hdr),
415 	},
416 	.get_time = &efi_get_time_boottime,
417 	.set_time = (void *)&efi_device_error,
418 	.get_wakeup_time = (void *)&efi_unimplemented,
419 	.set_wakeup_time = (void *)&efi_unimplemented,
420 	.set_virtual_address_map = &efi_set_virtual_address_map,
421 	.convert_pointer = (void *)&efi_invalid_parameter,
422 	.get_variable = efi_get_variable,
423 	.get_next_variable = efi_get_next_variable,
424 	.set_variable = efi_set_variable,
425 	.get_next_high_mono_count = (void *)&efi_device_error,
426 	.reset_system = &efi_reset_system_boottime,
427 	.update_capsule = efi_update_capsule,
428 	.query_capsule_caps = efi_query_capsule_caps,
429 	.query_variable_info = efi_query_variable_info,
430 };
431