xref: /openbmc/u-boot/lib/efi_loader/efi_runtime.c (revision 9d922450)
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 };
189 
190 static bool efi_runtime_tobedetached(void *p)
191 {
192 	int i;
193 
194 	for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++)
195 		if (efi_runtime_detach_list[i].ptr == p)
196 			return true;
197 
198 	return false;
199 }
200 
201 static void efi_runtime_detach(ulong offset)
202 {
203 	int i;
204 	ulong patchoff = offset - (ulong)gd->relocaddr;
205 
206 	for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) {
207 		ulong patchto = (ulong)efi_runtime_detach_list[i].patchto;
208 		ulong *p = efi_runtime_detach_list[i].ptr;
209 		ulong newaddr = patchto ? (patchto + patchoff) : 0;
210 
211 		debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
212 		*p = newaddr;
213 	}
214 }
215 
216 /* Relocate EFI runtime to uboot_reloc_base = offset */
217 void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
218 {
219 #ifdef IS_RELA
220 	struct elf_rela *rel = (void*)&__efi_runtime_rel_start;
221 #else
222 	struct elf_rel *rel = (void*)&__efi_runtime_rel_start;
223 	static ulong lastoff = CONFIG_SYS_TEXT_BASE;
224 #endif
225 
226 	debug("%s: Relocating to offset=%lx\n", __func__, offset);
227 	for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) {
228 		ulong base = CONFIG_SYS_TEXT_BASE;
229 		ulong *p;
230 		ulong newaddr;
231 
232 		p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
233 
234 		if ((rel->info & R_MASK) != R_RELATIVE) {
235 			continue;
236 		}
237 
238 #ifdef IS_RELA
239 		newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE;
240 #else
241 		newaddr = *p - lastoff + offset;
242 #endif
243 
244 		/* Check if the relocation is inside bounds */
245 		if (map && ((newaddr < map->virtual_start) ||
246 		    newaddr > (map->virtual_start + (map->num_pages << 12)))) {
247 			if (!efi_runtime_tobedetached(p))
248 				printf("U-Boot EFI: Relocation at %p is out of "
249 				       "range (%lx)\n", p, newaddr);
250 			continue;
251 		}
252 
253 		debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
254 		*p = newaddr;
255 		flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1),
256 			ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE));
257 	}
258 
259 #ifndef IS_RELA
260 	lastoff = offset;
261 #endif
262 
263         invalidate_icache_all();
264 }
265 
266 static efi_status_t EFIAPI efi_set_virtual_address_map(
267 			unsigned long memory_map_size,
268 			unsigned long descriptor_size,
269 			uint32_t descriptor_version,
270 			struct efi_mem_desc *virtmap)
271 {
272 	ulong runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
273 	int n = memory_map_size / descriptor_size;
274 	int i;
275 
276 	EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
277 		  descriptor_version, virtmap);
278 
279 	/* Rebind mmio pointers */
280 	for (i = 0; i < n; i++) {
281 		struct efi_mem_desc *map = (void*)virtmap +
282 					   (descriptor_size * i);
283 		struct list_head *lhandle;
284 		efi_physical_addr_t map_start = map->physical_start;
285 		efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
286 		efi_physical_addr_t map_end = map_start + map_len;
287 
288 		/* Adjust all mmio pointers in this region */
289 		list_for_each(lhandle, &efi_runtime_mmio) {
290 			struct efi_runtime_mmio_list *lmmio;
291 
292 			lmmio = list_entry(lhandle,
293 					   struct efi_runtime_mmio_list,
294 					   link);
295 			if ((map_start <= lmmio->paddr) &&
296 			    (map_end >= lmmio->paddr)) {
297 				u64 off = map->virtual_start - map_start;
298 				uintptr_t new_addr = lmmio->paddr + off;
299 				*lmmio->ptr = (void *)new_addr;
300 			}
301 		}
302 	}
303 
304 	/* Move the actual runtime code over */
305 	for (i = 0; i < n; i++) {
306 		struct efi_mem_desc *map;
307 
308 		map = (void*)virtmap + (descriptor_size * i);
309 		if (map->type == EFI_RUNTIME_SERVICES_CODE) {
310 			ulong new_offset = map->virtual_start -
311 					   (runtime_start - gd->relocaddr);
312 
313 			efi_runtime_relocate(new_offset, map);
314 			/* Once we're virtual, we can no longer handle
315 			   complex callbacks */
316 			efi_runtime_detach(new_offset);
317 			return EFI_EXIT(EFI_SUCCESS);
318 		}
319 	}
320 
321 	return EFI_EXIT(EFI_INVALID_PARAMETER);
322 }
323 
324 void efi_add_runtime_mmio(void *mmio_ptr, u64 len)
325 {
326 	struct efi_runtime_mmio_list *newmmio;
327 
328 	u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT;
329 	efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false);
330 
331 	newmmio = calloc(1, sizeof(*newmmio));
332 	newmmio->ptr = mmio_ptr;
333 	newmmio->paddr = *(uintptr_t *)mmio_ptr;
334 	newmmio->len = len;
335 	list_add_tail(&newmmio->link, &efi_runtime_mmio);
336 }
337 
338 /*
339  * In the second stage, U-Boot has disappeared. To isolate our runtime code
340  * that at this point still exists from the rest, we put it into a special
341  * section.
342  *
343  *        !!WARNING!!
344  *
345  * This means that we can not rely on any code outside of this file in any
346  * function or variable below this line.
347  *
348  * Please keep everything fully self-contained and annotated with
349  * __efi_runtime and __efi_runtime_data markers.
350  */
351 
352 /*
353  * Relocate the EFI runtime stub to a different place. We need to call this
354  * the first time we expose the runtime interface to a user and on set virtual
355  * address map calls.
356  */
357 
358 static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
359 {
360 	return EFI_UNSUPPORTED;
361 }
362 
363 static efi_status_t __efi_runtime EFIAPI efi_device_error(void)
364 {
365 	return EFI_DEVICE_ERROR;
366 }
367 
368 static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void)
369 {
370 	return EFI_INVALID_PARAMETER;
371 }
372 
373 struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
374 	.hdr = {
375 		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
376 		.revision = EFI_RUNTIME_SERVICES_REVISION,
377 		.headersize = sizeof(struct efi_table_hdr),
378 	},
379 	.get_time = &efi_get_time_boottime,
380 	.set_time = (void *)&efi_device_error,
381 	.get_wakeup_time = (void *)&efi_unimplemented,
382 	.set_wakeup_time = (void *)&efi_unimplemented,
383 	.set_virtual_address_map = &efi_set_virtual_address_map,
384 	.convert_pointer = (void *)&efi_invalid_parameter,
385 	.get_variable = (void *)&efi_device_error,
386 	.get_next_variable = (void *)&efi_device_error,
387 	.set_variable = (void *)&efi_device_error,
388 	.get_next_high_mono_count = (void *)&efi_device_error,
389 	.reset_system = &efi_reset_system_boottime,
390 };
391