blob: 7a9449f59c38368ad3d8bc5e944bb3dd98d54dab [file] [log] [blame]
Alexander Grafbee91162016-03-04 01:09:59 +01001/*
2 * EFI application boot time services
3 *
4 * Copyright (c) 2016 Alexander Graf
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
Alexander Grafbee91162016-03-04 01:09:59 +01009#include <common.h>
Heinrich Schuchardt7d963322017-10-05 16:14:14 +020010#include <div64.h>
Alexander Grafbee91162016-03-04 01:09:59 +010011#include <efi_loader.h>
Rob Clarkad644e72017-09-13 18:05:37 -040012#include <environment.h>
Alexander Grafbee91162016-03-04 01:09:59 +010013#include <malloc.h>
14#include <asm/global_data.h>
Masahiro Yamadab08c8c42018-03-05 01:20:11 +090015#include <linux/libfdt_env.h>
Alexander Grafbee91162016-03-04 01:09:59 +010016#include <u-boot/crc.h>
17#include <bootm.h>
18#include <inttypes.h>
19#include <watchdog.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +020023/* Task priority level */
Heinrich Schuchardt152cade2017-11-06 21:17:47 +010024static efi_uintn_t efi_tpl = TPL_APPLICATION;
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +020025
Alexander Grafbee91162016-03-04 01:09:59 +010026/* This list contains all the EFI objects our payload has access to */
27LIST_HEAD(efi_obj_list);
28
Heinrich Schuchardt43bce442018-02-18 15:17:50 +010029/* List of all events */
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +010030LIST_HEAD(efi_events);
Heinrich Schuchardt43bce442018-02-18 15:17:50 +010031
Alexander Grafbee91162016-03-04 01:09:59 +010032/*
33 * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
34 * we need to do trickery with caches. Since we don't want to break the EFI
35 * aware boot path, only apply hacks when loading exiting directly (breaking
36 * direct Linux EFI booting along the way - oh well).
37 */
38static bool efi_is_direct_boot = true;
39
40/*
41 * EFI can pass arbitrary additional "tables" containing vendor specific
42 * information to the payload. One such table is the FDT table which contains
43 * a pointer to a flattened device tree blob.
44 *
45 * In most cases we want to pass an FDT to the payload, so reserve one slot of
46 * config table space for it. The pointer gets populated by do_bootefi_exec().
47 */
Alexander Graf3c63db92016-10-14 13:45:30 +020048static struct efi_configuration_table __efi_runtime_data efi_conf_table[2];
Alexander Grafbee91162016-03-04 01:09:59 +010049
Simon Glass65e4c0b2016-09-25 15:27:35 -060050#ifdef CONFIG_ARM
Alexander Grafbee91162016-03-04 01:09:59 +010051/*
52 * The "gd" pointer lives in a register on ARM and AArch64 that we declare
53 * fixed when compiling U-Boot. However, the payload does not know about that
54 * restriction so we need to manually swap its and our view of that register on
55 * EFI callback entry/exit.
56 */
57static volatile void *efi_gd, *app_gd;
Simon Glass65e4c0b2016-09-25 15:27:35 -060058#endif
Alexander Grafbee91162016-03-04 01:09:59 +010059
Rob Clarkc160d2f2017-07-27 08:04:18 -040060static int entry_count;
Rob Clarkaf65db82017-07-27 08:04:19 -040061static int nesting_level;
Heinrich Schuchardtbc4f9132018-03-03 15:29:03 +010062/* GUID of the device tree table */
63const efi_guid_t efi_guid_fdt = EFI_FDT_GUID;
Heinrich Schuchardtf0959db2018-01-11 08:16:02 +010064/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
65const efi_guid_t efi_guid_driver_binding_protocol =
66 EFI_DRIVER_BINDING_PROTOCOL_GUID;
Rob Clarkc160d2f2017-07-27 08:04:18 -040067
Heinrich Schuchardta3a28f52018-02-18 15:17:51 +010068/* event group ExitBootServices() invoked */
69const efi_guid_t efi_guid_event_group_exit_boot_services =
70 EFI_EVENT_GROUP_EXIT_BOOT_SERVICES;
71/* event group SetVirtualAddressMap() invoked */
72const efi_guid_t efi_guid_event_group_virtual_address_change =
73 EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE;
74/* event group memory map changed */
75const efi_guid_t efi_guid_event_group_memory_map_change =
76 EFI_EVENT_GROUP_MEMORY_MAP_CHANGE;
77/* event group boot manager about to boot */
78const efi_guid_t efi_guid_event_group_ready_to_boot =
79 EFI_EVENT_GROUP_READY_TO_BOOT;
80/* event group ResetSystem() invoked (before ExitBootServices) */
81const efi_guid_t efi_guid_event_group_reset_system =
82 EFI_EVENT_GROUP_RESET_SYSTEM;
83
Heinrich Schuchardt2074f702018-01-11 08:16:09 +010084static efi_status_t EFIAPI efi_disconnect_controller(
85 efi_handle_t controller_handle,
86 efi_handle_t driver_image_handle,
87 efi_handle_t child_handle);
Heinrich Schuchardt3f9b0042018-01-11 08:16:04 +010088
Rob Clarkc160d2f2017-07-27 08:04:18 -040089/* Called on every callback entry */
90int __efi_entry_check(void)
91{
92 int ret = entry_count++ == 0;
93#ifdef CONFIG_ARM
94 assert(efi_gd);
95 app_gd = gd;
96 gd = efi_gd;
97#endif
98 return ret;
99}
100
101/* Called on every callback exit */
102int __efi_exit_check(void)
103{
104 int ret = --entry_count == 0;
105#ifdef CONFIG_ARM
106 gd = app_gd;
107#endif
108 return ret;
109}
110
Alexander Grafbee91162016-03-04 01:09:59 +0100111/* Called from do_bootefi_exec() */
112void efi_save_gd(void)
113{
Simon Glass65e4c0b2016-09-25 15:27:35 -0600114#ifdef CONFIG_ARM
Alexander Grafbee91162016-03-04 01:09:59 +0100115 efi_gd = gd;
Simon Glass65e4c0b2016-09-25 15:27:35 -0600116#endif
Alexander Grafbee91162016-03-04 01:09:59 +0100117}
118
Rob Clarkc160d2f2017-07-27 08:04:18 -0400119/*
120 * Special case handler for error/abort that just forces things back
121 * to u-boot world so we can dump out an abort msg, without any care
122 * about returning back to UEFI world.
123 */
Alexander Grafbee91162016-03-04 01:09:59 +0100124void efi_restore_gd(void)
125{
Simon Glass65e4c0b2016-09-25 15:27:35 -0600126#ifdef CONFIG_ARM
Alexander Grafbee91162016-03-04 01:09:59 +0100127 /* Only restore if we're already in EFI context */
128 if (!efi_gd)
129 return;
Alexander Grafbee91162016-03-04 01:09:59 +0100130 gd = efi_gd;
Simon Glass65e4c0b2016-09-25 15:27:35 -0600131#endif
Alexander Grafbee91162016-03-04 01:09:59 +0100132}
133
Rob Clarkaf65db82017-07-27 08:04:19 -0400134/*
Heinrich Schuchardtc8df80c2018-01-24 19:21:36 +0100135 * Return a string for indenting with two spaces per level. A maximum of ten
136 * indent levels is supported. Higher indent levels will be truncated.
137 *
138 * @level indent level
139 * @return indent string
Rob Clarkaf65db82017-07-27 08:04:19 -0400140 */
141static const char *indent_string(int level)
142{
143 const char *indent = " ";
144 const int max = strlen(indent);
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +0100145
Rob Clarkaf65db82017-07-27 08:04:19 -0400146 level = min(max, level * 2);
147 return &indent[max - level];
148}
149
Heinrich Schuchardtae0bd3a2017-08-18 17:45:16 +0200150const char *__efi_nesting(void)
151{
152 return indent_string(nesting_level);
153}
154
Rob Clarkaf65db82017-07-27 08:04:19 -0400155const char *__efi_nesting_inc(void)
156{
157 return indent_string(nesting_level++);
158}
159
160const char *__efi_nesting_dec(void)
161{
162 return indent_string(--nesting_level);
163}
164
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200165/*
166 * Queue an EFI event.
167 *
168 * This function queues the notification function of the event for future
169 * execution.
170 *
171 * The notification function is called if the task priority level of the
172 * event is higher than the current task priority level.
173 *
174 * For the SignalEvent service see efi_signal_event_ext.
175 *
176 * @event event to signal
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100177 * @check_tpl check the TPL level
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200178 */
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100179static void efi_queue_event(struct efi_event *event, bool check_tpl)
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200180{
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200181 if (event->notify_function) {
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200182 event->is_queued = true;
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200183 /* Check TPL */
Heinrich Schuchardt9bc96642018-01-19 20:24:51 +0100184 if (check_tpl && efi_tpl >= event->notify_tpl)
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200185 return;
Heinrich Schuchardtea630ce2017-09-15 10:06:10 +0200186 EFI_CALL_VOID(event->notify_function(event,
187 event->notify_context));
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200188 }
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200189 event->is_queued = false;
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200190}
191
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200192/*
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100193 * Signal an EFI event.
194 *
195 * This function signals an event. If the event belongs to an event group
196 * all events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL
197 * their notification function is queued.
198 *
199 * For the SignalEvent service see efi_signal_event_ext.
200 *
201 * @event event to signal
202 * @check_tpl check the TPL level
203 */
204void efi_signal_event(struct efi_event *event, bool check_tpl)
205{
206 if (event->group) {
207 struct efi_event *evt;
208
209 /*
210 * The signaled state has to set before executing any
211 * notification function
212 */
213 list_for_each_entry(evt, &efi_events, link) {
214 if (!evt->group || guidcmp(evt->group, event->group))
215 continue;
216 if (evt->is_signaled)
217 continue;
218 evt->is_signaled = true;
219 if (evt->type & EVT_NOTIFY_SIGNAL &&
220 evt->notify_function)
221 evt->is_queued = true;
222 }
223 list_for_each_entry(evt, &efi_events, link) {
224 if (!evt->group || guidcmp(evt->group, event->group))
225 continue;
226 if (evt->is_queued)
227 efi_queue_event(evt, check_tpl);
228 }
229 } else if (!event->is_signaled) {
230 event->is_signaled = true;
231 if (event->type & EVT_NOTIFY_SIGNAL)
232 efi_queue_event(event, check_tpl);
233 }
234}
235
236/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200237 * Raise the task priority level.
238 *
239 * This function implements the RaiseTpl service.
240 * See the Unified Extensible Firmware Interface (UEFI) specification
241 * for details.
242 *
243 * @new_tpl new value of the task priority level
244 * @return old value of the task priority level
245 */
Heinrich Schuchardt152cade2017-11-06 21:17:47 +0100246static unsigned long EFIAPI efi_raise_tpl(efi_uintn_t new_tpl)
Alexander Grafbee91162016-03-04 01:09:59 +0100247{
Heinrich Schuchardt152cade2017-11-06 21:17:47 +0100248 efi_uintn_t old_tpl = efi_tpl;
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200249
xypron.glpk@gmx.de503f2692017-07-18 20:17:19 +0200250 EFI_ENTRY("0x%zx", new_tpl);
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200251
252 if (new_tpl < efi_tpl)
253 debug("WARNING: new_tpl < current_tpl in %s\n", __func__);
254 efi_tpl = new_tpl;
255 if (efi_tpl > TPL_HIGH_LEVEL)
256 efi_tpl = TPL_HIGH_LEVEL;
257
258 EFI_EXIT(EFI_SUCCESS);
259 return old_tpl;
Alexander Grafbee91162016-03-04 01:09:59 +0100260}
261
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200262/*
263 * Lower the task priority level.
264 *
265 * This function implements the RestoreTpl service.
266 * See the Unified Extensible Firmware Interface (UEFI) specification
267 * for details.
268 *
269 * @old_tpl value of the task priority level to be restored
270 */
Heinrich Schuchardt152cade2017-11-06 21:17:47 +0100271static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl)
Alexander Grafbee91162016-03-04 01:09:59 +0100272{
xypron.glpk@gmx.de503f2692017-07-18 20:17:19 +0200273 EFI_ENTRY("0x%zx", old_tpl);
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200274
275 if (old_tpl > efi_tpl)
276 debug("WARNING: old_tpl > current_tpl in %s\n", __func__);
277 efi_tpl = old_tpl;
278 if (efi_tpl > TPL_HIGH_LEVEL)
279 efi_tpl = TPL_HIGH_LEVEL;
280
Heinrich Schuchardt0f7fcc72018-03-24 18:40:21 +0100281 /*
282 * Lowering the TPL may have made queued events eligible for execution.
283 */
284 efi_timer_check();
285
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200286 EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +0100287}
288
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200289/*
290 * Allocate memory pages.
291 *
292 * This function implements the AllocatePages service.
293 * See the Unified Extensible Firmware Interface (UEFI) specification
294 * for details.
295 *
296 * @type type of allocation to be performed
297 * @memory_type usage type of the allocated memory
298 * @pages number of pages to be allocated
299 * @memory allocated memory
300 * @return status code
301 */
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900302static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100303 efi_uintn_t pages,
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900304 uint64_t *memory)
Alexander Grafbee91162016-03-04 01:09:59 +0100305{
306 efi_status_t r;
307
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100308 EFI_ENTRY("%d, %d, 0x%zx, %p", type, memory_type, pages, memory);
Alexander Grafbee91162016-03-04 01:09:59 +0100309 r = efi_allocate_pages(type, memory_type, pages, memory);
310 return EFI_EXIT(r);
311}
312
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200313/*
314 * Free memory pages.
315 *
316 * This function implements the FreePages service.
317 * See the Unified Extensible Firmware Interface (UEFI) specification
318 * for details.
319 *
320 * @memory start of the memory area to be freed
321 * @pages number of pages to be freed
322 * @return status code
323 */
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900324static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100325 efi_uintn_t pages)
Alexander Grafbee91162016-03-04 01:09:59 +0100326{
327 efi_status_t r;
328
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +0100329 EFI_ENTRY("%" PRIx64 ", 0x%zx", memory, pages);
Alexander Grafbee91162016-03-04 01:09:59 +0100330 r = efi_free_pages(memory, pages);
331 return EFI_EXIT(r);
332}
333
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200334/*
335 * Get map describing memory usage.
336 *
337 * This function implements the GetMemoryMap service.
338 * See the Unified Extensible Firmware Interface (UEFI) specification
339 * for details.
340 *
341 * @memory_map_size on entry the size, in bytes, of the memory map buffer,
342 * on exit the size of the copied memory map
343 * @memory_map buffer to which the memory map is written
344 * @map_key key for the memory map
345 * @descriptor_size size of an individual memory descriptor
346 * @descriptor_version version number of the memory descriptor structure
347 * @return status code
348 */
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900349static efi_status_t EFIAPI efi_get_memory_map_ext(
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100350 efi_uintn_t *memory_map_size,
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900351 struct efi_mem_desc *memory_map,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100352 efi_uintn_t *map_key,
353 efi_uintn_t *descriptor_size,
Masahiro Yamada6e0bf8d2017-06-22 17:49:03 +0900354 uint32_t *descriptor_version)
Alexander Grafbee91162016-03-04 01:09:59 +0100355{
356 efi_status_t r;
357
358 EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map,
359 map_key, descriptor_size, descriptor_version);
360 r = efi_get_memory_map(memory_map_size, memory_map, map_key,
361 descriptor_size, descriptor_version);
362 return EFI_EXIT(r);
363}
364
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200365/*
366 * Allocate memory from pool.
367 *
368 * This function implements the AllocatePool service.
369 * See the Unified Extensible Firmware Interface (UEFI) specification
370 * for details.
371 *
372 * @pool_type type of the pool from which memory is to be allocated
373 * @size number of bytes to be allocated
374 * @buffer allocated memory
375 * @return status code
376 */
Stefan Brünsead12742016-10-09 22:17:18 +0200377static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100378 efi_uintn_t size,
Stefan Brünsead12742016-10-09 22:17:18 +0200379 void **buffer)
Alexander Grafbee91162016-03-04 01:09:59 +0100380{
Alexander Graf1cd29f02016-03-24 01:37:37 +0100381 efi_status_t r;
382
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100383 EFI_ENTRY("%d, %zd, %p", pool_type, size, buffer);
Stefan Brünsead12742016-10-09 22:17:18 +0200384 r = efi_allocate_pool(pool_type, size, buffer);
Alexander Graf1cd29f02016-03-24 01:37:37 +0100385 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +0100386}
387
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200388/*
389 * Free memory from pool.
390 *
391 * This function implements the FreePool service.
392 * See the Unified Extensible Firmware Interface (UEFI) specification
393 * for details.
394 *
395 * @buffer start of memory to be freed
396 * @return status code
397 */
Stefan Brüns42417bc2016-10-09 22:17:26 +0200398static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
Alexander Grafbee91162016-03-04 01:09:59 +0100399{
Alexander Graf1cd29f02016-03-24 01:37:37 +0100400 efi_status_t r;
401
402 EFI_ENTRY("%p", buffer);
Stefan Brüns42417bc2016-10-09 22:17:26 +0200403 r = efi_free_pool(buffer);
Alexander Graf1cd29f02016-03-24 01:37:37 +0100404 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +0100405}
406
Heinrich Schuchardt2edab5e2017-10-26 19:25:49 +0200407/*
Heinrich Schuchardt44549d62017-11-26 14:05:23 +0100408 * Add a new object to the object list.
409 *
410 * The protocols list is initialized.
411 * The object handle is set.
412 *
413 * @obj object to be added
414 */
415void efi_add_handle(struct efi_object *obj)
416{
417 if (!obj)
418 return;
419 INIT_LIST_HEAD(&obj->protocols);
420 obj->handle = obj;
421 list_add_tail(&obj->link, &efi_obj_list);
422}
423
424/*
Heinrich Schuchardt2edab5e2017-10-26 19:25:49 +0200425 * Create handle.
426 *
427 * @handle new handle
428 * @return status code
429 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100430efi_status_t efi_create_handle(efi_handle_t *handle)
Heinrich Schuchardt3cc6e3f2017-08-27 00:51:09 +0200431{
432 struct efi_object *obj;
433 efi_status_t r;
434
435 r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
436 sizeof(struct efi_object),
437 (void **)&obj);
438 if (r != EFI_SUCCESS)
439 return r;
Heinrich Schuchardt44549d62017-11-26 14:05:23 +0100440 efi_add_handle(obj);
441 *handle = obj->handle;
Heinrich Schuchardt3cc6e3f2017-08-27 00:51:09 +0200442 return r;
443}
444
Alexander Grafbee91162016-03-04 01:09:59 +0100445/*
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100446 * Find a protocol on a handle.
447 *
448 * @handle handle
449 * @protocol_guid GUID of the protocol
450 * @handler reference to the protocol
451 * @return status code
452 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100453efi_status_t efi_search_protocol(const efi_handle_t handle,
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100454 const efi_guid_t *protocol_guid,
455 struct efi_handler **handler)
456{
457 struct efi_object *efiobj;
458 struct list_head *lhandle;
459
460 if (!handle || !protocol_guid)
461 return EFI_INVALID_PARAMETER;
462 efiobj = efi_search_obj(handle);
463 if (!efiobj)
464 return EFI_INVALID_PARAMETER;
465 list_for_each(lhandle, &efiobj->protocols) {
466 struct efi_handler *protocol;
467
468 protocol = list_entry(lhandle, struct efi_handler, link);
469 if (!guidcmp(protocol->guid, protocol_guid)) {
470 if (handler)
471 *handler = protocol;
472 return EFI_SUCCESS;
473 }
474 }
475 return EFI_NOT_FOUND;
476}
477
478/*
479 * Delete protocol from a handle.
480 *
481 * @handle handle from which the protocol shall be deleted
482 * @protocol GUID of the protocol to be deleted
483 * @protocol_interface interface of the protocol implementation
484 * @return status code
485 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100486efi_status_t efi_remove_protocol(const efi_handle_t handle,
487 const efi_guid_t *protocol,
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100488 void *protocol_interface)
489{
490 struct efi_handler *handler;
491 efi_status_t ret;
492
493 ret = efi_search_protocol(handle, protocol, &handler);
494 if (ret != EFI_SUCCESS)
495 return ret;
496 if (guidcmp(handler->guid, protocol))
497 return EFI_INVALID_PARAMETER;
498 list_del(&handler->link);
499 free(handler);
500 return EFI_SUCCESS;
501}
502
503/*
504 * Delete all protocols from a handle.
505 *
506 * @handle handle from which the protocols shall be deleted
507 * @return status code
508 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100509efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100510{
511 struct efi_object *efiobj;
Heinrich Schuchardt32e6fed2018-01-11 08:15:55 +0100512 struct efi_handler *protocol;
513 struct efi_handler *pos;
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100514
515 efiobj = efi_search_obj(handle);
516 if (!efiobj)
517 return EFI_INVALID_PARAMETER;
Heinrich Schuchardt32e6fed2018-01-11 08:15:55 +0100518 list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) {
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100519 efi_status_t ret;
520
Heinrich Schuchardt678e03a2017-12-04 18:03:02 +0100521 ret = efi_remove_protocol(handle, protocol->guid,
522 protocol->protocol_interface);
523 if (ret != EFI_SUCCESS)
524 return ret;
525 }
526 return EFI_SUCCESS;
527}
528
529/*
530 * Delete handle.
531 *
532 * @handle handle to delete
533 */
534void efi_delete_handle(struct efi_object *obj)
535{
536 if (!obj)
537 return;
538 efi_remove_all_protocols(obj->handle);
539 list_del(&obj->link);
540 free(obj);
541}
542
543/*
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100544 * Check if a pointer is a valid event.
545 *
546 * @event pointer to check
547 * @return status code
Alexander Grafbee91162016-03-04 01:09:59 +0100548 */
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100549static efi_status_t efi_is_event(const struct efi_event *event)
550{
551 const struct efi_event *evt;
552
553 if (!event)
554 return EFI_INVALID_PARAMETER;
555 list_for_each_entry(evt, &efi_events, link) {
556 if (evt == event)
557 return EFI_SUCCESS;
558 }
559 return EFI_INVALID_PARAMETER;
560}
Alexander Grafbee91162016-03-04 01:09:59 +0100561
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200562/*
563 * Create an event.
564 *
565 * This function is used inside U-Boot code to create an event.
566 *
567 * For the API function implementing the CreateEvent service see
568 * efi_create_event_ext.
569 *
570 * @type type of the event to create
571 * @notify_tpl task priority level of the event
572 * @notify_function notification function of the event
573 * @notify_context pointer passed to the notification function
574 * @event created event
575 * @return status code
576 */
Heinrich Schuchardt152cade2017-11-06 21:17:47 +0100577efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200578 void (EFIAPI *notify_function) (
xypron.glpk@gmx.de2fd945f2017-07-18 20:17:17 +0200579 struct efi_event *event,
580 void *context),
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100581 void *notify_context, efi_guid_t *group,
582 struct efi_event **event)
Alexander Grafbee91162016-03-04 01:09:59 +0100583{
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100584 struct efi_event *evt;
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200585
Jonathan Graya95343b2017-03-12 19:26:07 +1100586 if (event == NULL)
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200587 return EFI_INVALID_PARAMETER;
Jonathan Graya95343b2017-03-12 19:26:07 +1100588
589 if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT))
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200590 return EFI_INVALID_PARAMETER;
Jonathan Graya95343b2017-03-12 19:26:07 +1100591
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100592 if ((type & (EVT_NOTIFY_SIGNAL | EVT_NOTIFY_WAIT)) &&
Jonathan Graya95343b2017-03-12 19:26:07 +1100593 notify_function == NULL)
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200594 return EFI_INVALID_PARAMETER;
Jonathan Graya95343b2017-03-12 19:26:07 +1100595
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100596 evt = calloc(1, sizeof(struct efi_event));
597 if (!evt)
598 return EFI_OUT_OF_RESOURCES;
599 evt->type = type;
600 evt->notify_tpl = notify_tpl;
601 evt->notify_function = notify_function;
602 evt->notify_context = notify_context;
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100603 evt->group = group;
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100604 /* Disable timers on bootup */
605 evt->trigger_next = -1ULL;
606 evt->is_queued = false;
607 evt->is_signaled = false;
608 list_add_tail(&evt->link, &efi_events);
609 *event = evt;
610 return EFI_SUCCESS;
Alexander Grafbee91162016-03-04 01:09:59 +0100611}
612
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200613/*
Heinrich Schuchardt9f0930e2018-02-04 23:05:13 +0100614 * Create an event in a group.
615 *
616 * This function implements the CreateEventEx service.
617 * See the Unified Extensible Firmware Interface (UEFI) specification
618 * for details.
619 * TODO: Support event groups
620 *
621 * @type type of the event to create
622 * @notify_tpl task priority level of the event
623 * @notify_function notification function of the event
624 * @notify_context pointer passed to the notification function
625 * @event created event
626 * @event_group event group
627 * @return status code
628 */
629efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl,
630 void (EFIAPI *notify_function) (
631 struct efi_event *event,
632 void *context),
633 void *notify_context,
634 efi_guid_t *event_group,
635 struct efi_event **event)
636{
637 EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function,
638 notify_context, event_group);
Heinrich Schuchardt9f0930e2018-02-04 23:05:13 +0100639 return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function,
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100640 notify_context, event_group, event));
Heinrich Schuchardt9f0930e2018-02-04 23:05:13 +0100641}
642
643/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200644 * Create an event.
645 *
646 * This function implements the CreateEvent service.
647 * See the Unified Extensible Firmware Interface (UEFI) specification
648 * for details.
649 *
650 * @type type of the event to create
651 * @notify_tpl task priority level of the event
652 * @notify_function notification function of the event
653 * @notify_context pointer passed to the notification function
654 * @event created event
655 * @return status code
656 */
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200657static efi_status_t EFIAPI efi_create_event_ext(
Heinrich Schuchardt152cade2017-11-06 21:17:47 +0100658 uint32_t type, efi_uintn_t notify_tpl,
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200659 void (EFIAPI *notify_function) (
660 struct efi_event *event,
661 void *context),
662 void *notify_context, struct efi_event **event)
663{
664 EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function,
665 notify_context);
666 return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function,
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100667 notify_context, NULL, event));
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +0200668}
669
Alexander Grafbee91162016-03-04 01:09:59 +0100670/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200671 * Check if a timer event has occurred or a queued notification function should
672 * be called.
673 *
Alexander Grafbee91162016-03-04 01:09:59 +0100674 * Our timers have to work without interrupts, so we check whenever keyboard
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200675 * input or disk accesses happen if enough time elapsed for them to fire.
Alexander Grafbee91162016-03-04 01:09:59 +0100676 */
677void efi_timer_check(void)
678{
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100679 struct efi_event *evt;
Alexander Grafbee91162016-03-04 01:09:59 +0100680 u64 now = timer_get_us();
681
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100682 list_for_each_entry(evt, &efi_events, link) {
683 if (evt->is_queued)
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100684 efi_queue_event(evt, true);
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100685 if (!(evt->type & EVT_TIMER) || now < evt->trigger_next)
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200686 continue;
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100687 switch (evt->trigger_type) {
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200688 case EFI_TIMER_RELATIVE:
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100689 evt->trigger_type = EFI_TIMER_STOP;
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200690 break;
691 case EFI_TIMER_PERIODIC:
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100692 evt->trigger_next += evt->trigger_time;
Heinrich Schuchardtca62a4f2017-09-15 10:06:13 +0200693 break;
694 default:
695 continue;
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200696 }
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100697 evt->is_signaled = false;
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100698 efi_signal_event(evt, true);
Alexander Grafbee91162016-03-04 01:09:59 +0100699 }
Alexander Grafbee91162016-03-04 01:09:59 +0100700 WATCHDOG_RESET();
701}
702
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200703/*
704 * Set the trigger time for a timer event or stop the event.
705 *
706 * This is the function for internal usage in U-Boot. For the API function
707 * implementing the SetTimer service see efi_set_timer_ext.
708 *
709 * @event event for which the timer is set
710 * @type type of the timer
711 * @trigger_time trigger period in multiples of 100ns
712 * @return status code
713 */
xypron.glpk@gmx.deb521d292017-07-19 19:22:34 +0200714efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
xypron.glpk@gmx.debfc72462017-07-18 20:17:21 +0200715 uint64_t trigger_time)
Alexander Grafbee91162016-03-04 01:09:59 +0100716{
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100717 /* Check that the event is valid */
718 if (efi_is_event(event) != EFI_SUCCESS || !(event->type & EVT_TIMER))
719 return EFI_INVALID_PARAMETER;
Alexander Grafbee91162016-03-04 01:09:59 +0100720
xypron.glpk@gmx.de8787b022017-07-18 20:17:23 +0200721 /*
722 * The parameter defines a multiple of 100ns.
723 * We use multiples of 1000ns. So divide by 10.
724 */
Heinrich Schuchardt7d963322017-10-05 16:14:14 +0200725 do_div(trigger_time, 10);
Alexander Grafbee91162016-03-04 01:09:59 +0100726
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100727 switch (type) {
728 case EFI_TIMER_STOP:
729 event->trigger_next = -1ULL;
730 break;
731 case EFI_TIMER_PERIODIC:
732 case EFI_TIMER_RELATIVE:
733 event->trigger_next = timer_get_us() + trigger_time;
734 break;
735 default:
736 return EFI_INVALID_PARAMETER;
Alexander Grafbee91162016-03-04 01:09:59 +0100737 }
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100738 event->trigger_type = type;
739 event->trigger_time = trigger_time;
740 event->is_signaled = false;
741 return EFI_SUCCESS;
xypron.glpk@gmx.debfc72462017-07-18 20:17:21 +0200742}
743
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200744/*
745 * Set the trigger time for a timer event or stop the event.
746 *
747 * This function implements the SetTimer service.
748 * See the Unified Extensible Firmware Interface (UEFI) specification
749 * for details.
750 *
751 * @event event for which the timer is set
752 * @type type of the timer
753 * @trigger_time trigger period in multiples of 100ns
754 * @return status code
755 */
xypron.glpk@gmx.deb521d292017-07-19 19:22:34 +0200756static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event,
757 enum efi_timer_delay type,
758 uint64_t trigger_time)
xypron.glpk@gmx.debfc72462017-07-18 20:17:21 +0200759{
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +0100760 EFI_ENTRY("%p, %d, %" PRIx64, event, type, trigger_time);
xypron.glpk@gmx.debfc72462017-07-18 20:17:21 +0200761 return EFI_EXIT(efi_set_timer(event, type, trigger_time));
Alexander Grafbee91162016-03-04 01:09:59 +0100762}
763
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200764/*
765 * Wait for events to be signaled.
766 *
767 * This function implements the WaitForEvent service.
768 * See the Unified Extensible Firmware Interface (UEFI) specification
769 * for details.
770 *
771 * @num_events number of events to be waited for
772 * @events events to be waited for
773 * @index index of the event that was signaled
774 * @return status code
775 */
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100776static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events,
xypron.glpk@gmx.de2fd945f2017-07-18 20:17:17 +0200777 struct efi_event **event,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100778 efi_uintn_t *index)
Alexander Grafbee91162016-03-04 01:09:59 +0100779{
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100780 int i;
Alexander Grafbee91162016-03-04 01:09:59 +0100781
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +0100782 EFI_ENTRY("%zd, %p, %p", num_events, event, index);
Alexander Grafbee91162016-03-04 01:09:59 +0100783
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200784 /* Check parameters */
785 if (!num_events || !event)
786 return EFI_EXIT(EFI_INVALID_PARAMETER);
Heinrich Schuchardt32f4b2f2017-09-15 10:06:16 +0200787 /* Check TPL */
788 if (efi_tpl != TPL_APPLICATION)
789 return EFI_EXIT(EFI_UNSUPPORTED);
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200790 for (i = 0; i < num_events; ++i) {
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100791 if (efi_is_event(event[i]) != EFI_SUCCESS)
792 return EFI_EXIT(EFI_INVALID_PARAMETER);
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200793 if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
794 return EFI_EXIT(EFI_INVALID_PARAMETER);
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200795 if (!event[i]->is_signaled)
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100796 efi_queue_event(event[i], true);
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200797 }
798
799 /* Wait for signal */
800 for (;;) {
801 for (i = 0; i < num_events; ++i) {
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200802 if (event[i]->is_signaled)
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200803 goto out;
804 }
805 /* Allow events to occur. */
806 efi_timer_check();
807 }
808
809out:
810 /*
811 * Reset the signal which is passed to the caller to allow periodic
812 * events to occur.
813 */
Heinrich Schuchardte190e892017-10-04 15:03:24 +0200814 event[i]->is_signaled = false;
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200815 if (index)
816 *index = i;
Alexander Grafbee91162016-03-04 01:09:59 +0100817
818 return EFI_EXIT(EFI_SUCCESS);
819}
820
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200821/*
822 * Signal an EFI event.
823 *
824 * This function implements the SignalEvent service.
825 * See the Unified Extensible Firmware Interface (UEFI) specification
826 * for details.
827 *
828 * This functions sets the signaled state of the event and queues the
829 * notification function for execution.
830 *
831 * @event event to signal
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +0200832 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200833 */
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200834static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
Alexander Grafbee91162016-03-04 01:09:59 +0100835{
836 EFI_ENTRY("%p", event);
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100837 if (efi_is_event(event) != EFI_SUCCESS)
838 return EFI_EXIT(EFI_INVALID_PARAMETER);
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100839 efi_signal_event(event, true);
Alexander Grafbee91162016-03-04 01:09:59 +0100840 return EFI_EXIT(EFI_SUCCESS);
841}
842
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200843/*
844 * Close an EFI event.
845 *
846 * This function implements the CloseEvent service.
847 * See the Unified Extensible Firmware Interface (UEFI) specification
848 * for details.
849 *
850 * @event event to close
851 * @return status code
852 */
xypron.glpk@gmx.de2fd945f2017-07-18 20:17:17 +0200853static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
Alexander Grafbee91162016-03-04 01:09:59 +0100854{
855 EFI_ENTRY("%p", event);
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100856 if (efi_is_event(event) != EFI_SUCCESS)
857 return EFI_EXIT(EFI_INVALID_PARAMETER);
858 list_del(&event->link);
859 free(event);
860 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +0100861}
862
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200863/*
864 * Check if an event is signaled.
865 *
866 * This function implements the CheckEvent service.
867 * See the Unified Extensible Firmware Interface (UEFI) specification
868 * for details.
869 *
Heinrich Schuchardt70695152018-02-18 11:32:02 +0100870 * If an event is not signaled yet, the notification function is queued.
871 * The signaled state is cleared.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200872 *
873 * @event event to check
874 * @return status code
875 */
xypron.glpk@gmx.de2fd945f2017-07-18 20:17:17 +0200876static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
Alexander Grafbee91162016-03-04 01:09:59 +0100877{
878 EFI_ENTRY("%p", event);
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200879 efi_timer_check();
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100880 if (efi_is_event(event) != EFI_SUCCESS ||
881 event->type & EVT_NOTIFY_SIGNAL)
882 return EFI_EXIT(EFI_INVALID_PARAMETER);
883 if (!event->is_signaled)
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +0100884 efi_queue_event(event, true);
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100885 if (event->is_signaled) {
886 event->is_signaled = false;
887 return EFI_EXIT(EFI_SUCCESS);
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +0200888 }
Heinrich Schuchardt43bce442018-02-18 15:17:50 +0100889 return EFI_EXIT(EFI_NOT_READY);
Alexander Grafbee91162016-03-04 01:09:59 +0100890}
891
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200892/*
Heinrich Schuchardt7b9f8ad2017-10-18 18:13:03 +0200893 * Find the internal EFI object for a handle.
894 *
895 * @handle handle to find
896 * @return EFI object
897 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100898struct efi_object *efi_search_obj(const efi_handle_t handle)
Heinrich Schuchardt7b9f8ad2017-10-18 18:13:03 +0200899{
Heinrich Schuchardt1b681532017-11-06 21:17:50 +0100900 struct efi_object *efiobj;
Heinrich Schuchardt7b9f8ad2017-10-18 18:13:03 +0200901
Heinrich Schuchardt1b681532017-11-06 21:17:50 +0100902 list_for_each_entry(efiobj, &efi_obj_list, link) {
Heinrich Schuchardt7b9f8ad2017-10-18 18:13:03 +0200903 if (efiobj->handle == handle)
904 return efiobj;
905 }
906
907 return NULL;
908}
909
910/*
Heinrich Schuchardtfe1599d2018-01-11 08:15:57 +0100911 * Create open protocol info entry and add it to a protocol.
912 *
913 * @handler handler of a protocol
914 * @return open protocol info entry
915 */
916static struct efi_open_protocol_info_entry *efi_create_open_info(
917 struct efi_handler *handler)
918{
919 struct efi_open_protocol_info_item *item;
920
921 item = calloc(1, sizeof(struct efi_open_protocol_info_item));
922 if (!item)
923 return NULL;
924 /* Append the item to the open protocol info list. */
925 list_add_tail(&item->link, &handler->open_infos);
926
927 return &item->info;
928}
929
930/*
931 * Remove an open protocol info entry from a protocol.
932 *
933 * @handler handler of a protocol
934 * @return status code
935 */
936static efi_status_t efi_delete_open_info(
937 struct efi_open_protocol_info_item *item)
938{
939 list_del(&item->link);
940 free(item);
941 return EFI_SUCCESS;
942}
943
944/*
Heinrich Schuchardt3f79a2b2017-10-26 19:25:53 +0200945 * Install new protocol on a handle.
946 *
947 * @handle handle on which the protocol shall be installed
948 * @protocol GUID of the protocol to be installed
949 * @protocol_interface interface of the protocol implementation
950 * @return status code
951 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +0100952efi_status_t efi_add_protocol(const efi_handle_t handle,
953 const efi_guid_t *protocol,
Heinrich Schuchardt3f79a2b2017-10-26 19:25:53 +0200954 void *protocol_interface)
955{
956 struct efi_object *efiobj;
957 struct efi_handler *handler;
958 efi_status_t ret;
Heinrich Schuchardt3f79a2b2017-10-26 19:25:53 +0200959
960 efiobj = efi_search_obj(handle);
961 if (!efiobj)
962 return EFI_INVALID_PARAMETER;
963 ret = efi_search_protocol(handle, protocol, NULL);
964 if (ret != EFI_NOT_FOUND)
965 return EFI_INVALID_PARAMETER;
966 handler = calloc(1, sizeof(struct efi_handler));
967 if (!handler)
968 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +0100969 handler->guid = protocol;
970 handler->protocol_interface = protocol_interface;
Heinrich Schuchardtfe1599d2018-01-11 08:15:57 +0100971 INIT_LIST_HEAD(&handler->open_infos);
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +0100972 list_add_tail(&handler->link, &efiobj->protocols);
Heinrich Schuchardtd5504142018-01-11 08:16:01 +0100973 if (!guidcmp(&efi_guid_device_path, protocol))
974 EFI_PRINT("installed device path '%pD'\n", protocol_interface);
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +0100975 return EFI_SUCCESS;
Heinrich Schuchardt3f79a2b2017-10-26 19:25:53 +0200976}
977
978/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200979 * Install protocol interface.
980 *
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +0100981 * This function implements the InstallProtocolInterface service.
982 * See the Unified Extensible Firmware Interface (UEFI) specification
983 * for details.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +0200984 *
985 * @handle handle on which the protocol shall be installed
986 * @protocol GUID of the protocol to be installed
987 * @protocol_interface_type type of the interface to be installed,
988 * always EFI_NATIVE_INTERFACE
989 * @protocol_interface interface of the protocol implementation
990 * @return status code
991 */
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +0100992static efi_status_t EFIAPI efi_install_protocol_interface(
993 void **handle, const efi_guid_t *protocol,
994 int protocol_interface_type, void *protocol_interface)
Alexander Grafbee91162016-03-04 01:09:59 +0100995{
xypron.glpk@gmx.dee0549f82017-07-11 22:06:16 +0200996 efi_status_t r;
997
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +0100998 EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type,
999 protocol_interface);
1000
xypron.glpk@gmx.dee0549f82017-07-11 22:06:16 +02001001 if (!handle || !protocol ||
1002 protocol_interface_type != EFI_NATIVE_INTERFACE) {
1003 r = EFI_INVALID_PARAMETER;
1004 goto out;
1005 }
1006
1007 /* Create new handle if requested. */
1008 if (!*handle) {
Heinrich Schuchardt3cc6e3f2017-08-27 00:51:09 +02001009 r = efi_create_handle(handle);
1010 if (r != EFI_SUCCESS)
1011 goto out;
Heinrich Schuchardtaf1408e2017-10-26 19:25:43 +02001012 debug("%sEFI: new handle %p\n", indent_string(nesting_level),
1013 *handle);
1014 } else {
1015 debug("%sEFI: handle %p\n", indent_string(nesting_level),
1016 *handle);
xypron.glpk@gmx.dee0549f82017-07-11 22:06:16 +02001017 }
Heinrich Schuchardt12025302017-10-26 19:25:54 +02001018 /* Add new protocol */
1019 r = efi_add_protocol(*handle, protocol, protocol_interface);
xypron.glpk@gmx.dee0549f82017-07-11 22:06:16 +02001020out:
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +01001021 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01001022}
xypron.glpk@gmx.dee0549f82017-07-11 22:06:16 +02001023
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001024/*
1025 * Reinstall protocol interface.
1026 *
1027 * This function implements the ReinstallProtocolInterface service.
1028 * See the Unified Extensible Firmware Interface (UEFI) specification
1029 * for details.
1030 *
1031 * @handle handle on which the protocol shall be
1032 * reinstalled
1033 * @protocol GUID of the protocol to be installed
1034 * @old_interface interface to be removed
1035 * @new_interface interface to be installed
1036 * @return status code
1037 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001038static efi_status_t EFIAPI efi_reinstall_protocol_interface(
1039 efi_handle_t handle, const efi_guid_t *protocol,
1040 void *old_interface, void *new_interface)
Alexander Grafbee91162016-03-04 01:09:59 +01001041{
Rob Clark778e6af2017-09-13 18:05:41 -04001042 EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface,
Alexander Grafbee91162016-03-04 01:09:59 +01001043 new_interface);
1044 return EFI_EXIT(EFI_ACCESS_DENIED);
1045}
1046
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001047/*
Heinrich Schuchardt3f9b0042018-01-11 08:16:04 +01001048 * Get all drivers associated to a controller.
1049 * The allocated buffer has to be freed with free().
1050 *
1051 * @efiobj handle of the controller
1052 * @protocol protocol guid (optional)
1053 * @number_of_drivers number of child controllers
1054 * @driver_handle_buffer handles of the the drivers
1055 * @return status code
1056 */
1057static efi_status_t efi_get_drivers(struct efi_object *efiobj,
1058 const efi_guid_t *protocol,
1059 efi_uintn_t *number_of_drivers,
1060 efi_handle_t **driver_handle_buffer)
1061{
1062 struct efi_handler *handler;
1063 struct efi_open_protocol_info_item *item;
1064 efi_uintn_t count = 0, i;
1065 bool duplicate;
1066
1067 /* Count all driver associations */
1068 list_for_each_entry(handler, &efiobj->protocols, link) {
1069 if (protocol && guidcmp(handler->guid, protocol))
1070 continue;
1071 list_for_each_entry(item, &handler->open_infos, link) {
1072 if (item->info.attributes &
1073 EFI_OPEN_PROTOCOL_BY_DRIVER)
1074 ++count;
1075 }
1076 }
1077 /*
1078 * Create buffer. In case of duplicate driver assignments the buffer
1079 * will be too large. But that does not harm.
1080 */
1081 *number_of_drivers = 0;
1082 *driver_handle_buffer = calloc(count, sizeof(efi_handle_t));
1083 if (!*driver_handle_buffer)
1084 return EFI_OUT_OF_RESOURCES;
1085 /* Collect unique driver handles */
1086 list_for_each_entry(handler, &efiobj->protocols, link) {
1087 if (protocol && guidcmp(handler->guid, protocol))
1088 continue;
1089 list_for_each_entry(item, &handler->open_infos, link) {
1090 if (item->info.attributes &
1091 EFI_OPEN_PROTOCOL_BY_DRIVER) {
1092 /* Check this is a new driver */
1093 duplicate = false;
1094 for (i = 0; i < *number_of_drivers; ++i) {
1095 if ((*driver_handle_buffer)[i] ==
1096 item->info.agent_handle)
1097 duplicate = true;
1098 }
1099 /* Copy handle to buffer */
1100 if (!duplicate) {
1101 i = (*number_of_drivers)++;
1102 (*driver_handle_buffer)[i] =
1103 item->info.agent_handle;
1104 }
1105 }
1106 }
1107 }
1108 return EFI_SUCCESS;
1109}
1110
1111/*
1112 * Disconnect all drivers from a controller.
1113 *
1114 * This function implements the DisconnectController service.
1115 * See the Unified Extensible Firmware Interface (UEFI) specification
1116 * for details.
1117 *
1118 * @efiobj handle of the controller
1119 * @protocol protocol guid (optional)
1120 * @child_handle handle of the child to destroy
1121 * @return status code
1122 */
1123static efi_status_t efi_disconnect_all_drivers(
1124 struct efi_object *efiobj,
1125 const efi_guid_t *protocol,
1126 efi_handle_t child_handle)
1127{
1128 efi_uintn_t number_of_drivers;
1129 efi_handle_t *driver_handle_buffer;
1130 efi_status_t r, ret;
1131
1132 ret = efi_get_drivers(efiobj, protocol, &number_of_drivers,
1133 &driver_handle_buffer);
1134 if (ret != EFI_SUCCESS)
1135 return ret;
1136
1137 ret = EFI_NOT_FOUND;
1138 while (number_of_drivers) {
1139 r = EFI_CALL(efi_disconnect_controller(
1140 efiobj->handle,
1141 driver_handle_buffer[--number_of_drivers],
1142 child_handle));
1143 if (r == EFI_SUCCESS)
1144 ret = r;
1145 }
1146 free(driver_handle_buffer);
1147 return ret;
1148}
1149
1150/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001151 * Uninstall protocol interface.
1152 *
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01001153 * This function implements the UninstallProtocolInterface service.
1154 * See the Unified Extensible Firmware Interface (UEFI) specification
1155 * for details.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001156 *
1157 * @handle handle from which the protocol shall be removed
1158 * @protocol GUID of the protocol to be removed
1159 * @protocol_interface interface to be removed
1160 * @return status code
1161 */
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01001162static efi_status_t EFIAPI efi_uninstall_protocol_interface(
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001163 efi_handle_t handle, const efi_guid_t *protocol,
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01001164 void *protocol_interface)
Alexander Grafbee91162016-03-04 01:09:59 +01001165{
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001166 struct efi_object *efiobj;
Heinrich Schuchardt58105112017-10-26 19:25:56 +02001167 struct efi_handler *handler;
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001168 struct efi_open_protocol_info_item *item;
1169 struct efi_open_protocol_info_item *pos;
Heinrich Schuchardt58105112017-10-26 19:25:56 +02001170 efi_status_t r;
xypron.glpk@gmx.de4b6ed0d2017-07-11 22:06:17 +02001171
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01001172 EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface);
1173
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001174 /* Check handle */
1175 efiobj = efi_search_obj(handle);
1176 if (!efiobj) {
xypron.glpk@gmx.de4b6ed0d2017-07-11 22:06:17 +02001177 r = EFI_INVALID_PARAMETER;
1178 goto out;
1179 }
Heinrich Schuchardt58105112017-10-26 19:25:56 +02001180 /* Find the protocol on the handle */
1181 r = efi_search_protocol(handle, protocol, &handler);
1182 if (r != EFI_SUCCESS)
1183 goto out;
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001184 /* Disconnect controllers */
1185 efi_disconnect_all_drivers(efiobj, protocol, NULL);
1186 if (!list_empty(&handler->open_infos)) {
Heinrich Schuchardt58105112017-10-26 19:25:56 +02001187 r = EFI_ACCESS_DENIED;
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001188 goto out;
xypron.glpk@gmx.de4b6ed0d2017-07-11 22:06:17 +02001189 }
Heinrich Schuchardtad973732018-01-11 08:16:05 +01001190 /* Close protocol */
1191 list_for_each_entry_safe(item, pos, &handler->open_infos, link) {
1192 if (item->info.attributes ==
1193 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ||
1194 item->info.attributes == EFI_OPEN_PROTOCOL_GET_PROTOCOL ||
1195 item->info.attributes == EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
1196 list_del(&item->link);
1197 }
1198 if (!list_empty(&handler->open_infos)) {
1199 r = EFI_ACCESS_DENIED;
1200 goto out;
1201 }
1202 r = efi_remove_protocol(handle, protocol, protocol_interface);
xypron.glpk@gmx.de4b6ed0d2017-07-11 22:06:17 +02001203out:
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01001204 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01001205}
1206
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001207/*
1208 * Register an event for notification when a protocol is installed.
1209 *
1210 * This function implements the RegisterProtocolNotify service.
1211 * See the Unified Extensible Firmware Interface (UEFI) specification
1212 * for details.
1213 *
1214 * @protocol GUID of the protocol whose installation shall be
1215 * notified
1216 * @event event to be signaled upon installation of the protocol
1217 * @registration key for retrieving the registration information
1218 * @return status code
1219 */
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02001220static efi_status_t EFIAPI efi_register_protocol_notify(
1221 const efi_guid_t *protocol,
1222 struct efi_event *event,
1223 void **registration)
Alexander Grafbee91162016-03-04 01:09:59 +01001224{
Rob Clark778e6af2017-09-13 18:05:41 -04001225 EFI_ENTRY("%pUl, %p, %p", protocol, event, registration);
Alexander Grafbee91162016-03-04 01:09:59 +01001226 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
1227}
1228
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001229/*
1230 * Determine if an EFI handle implements a protocol.
1231 *
1232 * See the documentation of the LocateHandle service in the UEFI specification.
1233 *
1234 * @search_type selection criterion
1235 * @protocol GUID of the protocol
1236 * @search_key registration key
1237 * @efiobj handle
1238 * @return 0 if the handle implements the protocol
1239 */
Alexander Grafbee91162016-03-04 01:09:59 +01001240static int efi_search(enum efi_locate_search_type search_type,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02001241 const efi_guid_t *protocol, void *search_key,
Alexander Grafbee91162016-03-04 01:09:59 +01001242 struct efi_object *efiobj)
1243{
Heinrich Schuchardt42cf1242017-10-26 19:25:55 +02001244 efi_status_t ret;
Alexander Grafbee91162016-03-04 01:09:59 +01001245
1246 switch (search_type) {
Heinrich Schuchardt9f0770f2017-11-06 21:17:42 +01001247 case ALL_HANDLES:
Alexander Grafbee91162016-03-04 01:09:59 +01001248 return 0;
Heinrich Schuchardt9f0770f2017-11-06 21:17:42 +01001249 case BY_REGISTER_NOTIFY:
Heinrich Schuchardt42cf1242017-10-26 19:25:55 +02001250 /* TODO: RegisterProtocolNotify is not implemented yet */
Alexander Grafbee91162016-03-04 01:09:59 +01001251 return -1;
Heinrich Schuchardt9f0770f2017-11-06 21:17:42 +01001252 case BY_PROTOCOL:
Heinrich Schuchardt42cf1242017-10-26 19:25:55 +02001253 ret = efi_search_protocol(efiobj->handle, protocol, NULL);
1254 return (ret != EFI_SUCCESS);
1255 default:
1256 /* Invalid search type */
Alexander Grafbee91162016-03-04 01:09:59 +01001257 return -1;
1258 }
Alexander Grafbee91162016-03-04 01:09:59 +01001259}
1260
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001261/*
1262 * Locate handles implementing a protocol.
1263 *
1264 * This function is meant for U-Boot internal calls. For the API implementation
1265 * of the LocateHandle service see efi_locate_handle_ext.
1266 *
1267 * @search_type selection criterion
1268 * @protocol GUID of the protocol
1269 * @search_key registration key
1270 * @buffer_size size of the buffer to receive the handles in bytes
1271 * @buffer buffer to receive the relevant handles
1272 * @return status code
1273 */
xypron.glpk@gmx.deebf199b2017-08-09 20:55:00 +02001274static efi_status_t efi_locate_handle(
Alexander Grafbee91162016-03-04 01:09:59 +01001275 enum efi_locate_search_type search_type,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02001276 const efi_guid_t *protocol, void *search_key,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01001277 efi_uintn_t *buffer_size, efi_handle_t *buffer)
Alexander Grafbee91162016-03-04 01:09:59 +01001278{
Heinrich Schuchardtcaf864e2017-11-06 21:17:49 +01001279 struct efi_object *efiobj;
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01001280 efi_uintn_t size = 0;
Alexander Grafbee91162016-03-04 01:09:59 +01001281
Heinrich Schuchardtcaf864e2017-11-06 21:17:49 +01001282 /* Check parameters */
1283 switch (search_type) {
1284 case ALL_HANDLES:
1285 break;
1286 case BY_REGISTER_NOTIFY:
1287 if (!search_key)
1288 return EFI_INVALID_PARAMETER;
1289 /* RegisterProtocolNotify is not implemented yet */
1290 return EFI_UNSUPPORTED;
1291 case BY_PROTOCOL:
1292 if (!protocol)
1293 return EFI_INVALID_PARAMETER;
1294 break;
1295 default:
1296 return EFI_INVALID_PARAMETER;
1297 }
1298
1299 /*
1300 * efi_locate_handle_buffer uses this function for
1301 * the calculation of the necessary buffer size.
1302 * So do not require a buffer for buffersize == 0.
1303 */
1304 if (!buffer_size || (*buffer_size && !buffer))
1305 return EFI_INVALID_PARAMETER;
1306
Alexander Grafbee91162016-03-04 01:09:59 +01001307 /* Count how much space we need */
Heinrich Schuchardtcaf864e2017-11-06 21:17:49 +01001308 list_for_each_entry(efiobj, &efi_obj_list, link) {
1309 if (!efi_search(search_type, protocol, search_key, efiobj))
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001310 size += sizeof(void *);
Alexander Grafbee91162016-03-04 01:09:59 +01001311 }
1312
1313 if (*buffer_size < size) {
1314 *buffer_size = size;
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02001315 return EFI_BUFFER_TOO_SMALL;
Alexander Grafbee91162016-03-04 01:09:59 +01001316 }
1317
Rob Clark796a78c2017-08-06 14:10:07 -04001318 *buffer_size = size;
1319 if (size == 0)
1320 return EFI_NOT_FOUND;
1321
Alexander Grafbee91162016-03-04 01:09:59 +01001322 /* Then fill the array */
Heinrich Schuchardtcaf864e2017-11-06 21:17:49 +01001323 list_for_each_entry(efiobj, &efi_obj_list, link) {
1324 if (!efi_search(search_type, protocol, search_key, efiobj))
1325 *buffer++ = efiobj->handle;
Alexander Grafbee91162016-03-04 01:09:59 +01001326 }
1327
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02001328 return EFI_SUCCESS;
1329}
1330
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001331/*
1332 * Locate handles implementing a protocol.
1333 *
1334 * This function implements the LocateHandle service.
1335 * See the Unified Extensible Firmware Interface (UEFI) specification
1336 * for details.
1337 *
1338 * @search_type selection criterion
1339 * @protocol GUID of the protocol
1340 * @search_key registration key
1341 * @buffer_size size of the buffer to receive the handles in bytes
1342 * @buffer buffer to receive the relevant handles
1343 * @return 0 if the handle implements the protocol
1344 */
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02001345static efi_status_t EFIAPI efi_locate_handle_ext(
1346 enum efi_locate_search_type search_type,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02001347 const efi_guid_t *protocol, void *search_key,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01001348 efi_uintn_t *buffer_size, efi_handle_t *buffer)
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02001349{
Rob Clark778e6af2017-09-13 18:05:41 -04001350 EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key,
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02001351 buffer_size, buffer);
1352
1353 return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key,
1354 buffer_size, buffer));
Alexander Grafbee91162016-03-04 01:09:59 +01001355}
1356
Alexander Grafd98cdf62017-07-26 13:41:04 +02001357/* Collapses configuration table entries, removing index i */
1358static void efi_remove_configuration_table(int i)
1359{
1360 struct efi_configuration_table *this = &efi_conf_table[i];
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001361 struct efi_configuration_table *next = &efi_conf_table[i + 1];
Alexander Grafd98cdf62017-07-26 13:41:04 +02001362 struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables];
1363
1364 memmove(this, next, (ulong)end - (ulong)next);
1365 systab.nr_tables--;
1366}
1367
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001368/*
1369 * Adds, updates, or removes a configuration table.
1370 *
1371 * This function is used for internal calls. For the API implementation of the
1372 * InstallConfigurationTable service see efi_install_configuration_table_ext.
1373 *
1374 * @guid GUID of the installed table
1375 * @table table to be installed
1376 * @return status code
1377 */
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001378efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
1379 void *table)
Alexander Grafbee91162016-03-04 01:09:59 +01001380{
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001381 struct efi_event *evt;
Alexander Grafbee91162016-03-04 01:09:59 +01001382 int i;
1383
Heinrich Schuchardteb68b4e2018-02-18 00:08:00 +01001384 if (!guid)
1385 return EFI_INVALID_PARAMETER;
1386
Alexander Grafbee91162016-03-04 01:09:59 +01001387 /* Check for guid override */
1388 for (i = 0; i < systab.nr_tables; i++) {
1389 if (!guidcmp(guid, &efi_conf_table[i].guid)) {
Alexander Grafd98cdf62017-07-26 13:41:04 +02001390 if (table)
1391 efi_conf_table[i].table = table;
1392 else
1393 efi_remove_configuration_table(i);
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001394 goto out;
Alexander Grafbee91162016-03-04 01:09:59 +01001395 }
1396 }
1397
Alexander Grafd98cdf62017-07-26 13:41:04 +02001398 if (!table)
1399 return EFI_NOT_FOUND;
1400
Alexander Grafbee91162016-03-04 01:09:59 +01001401 /* No override, check for overflow */
1402 if (i >= ARRAY_SIZE(efi_conf_table))
Alexander Graf488bf122016-08-19 01:23:24 +02001403 return EFI_OUT_OF_RESOURCES;
Alexander Grafbee91162016-03-04 01:09:59 +01001404
1405 /* Add a new entry */
1406 memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
1407 efi_conf_table[i].table = table;
Alexander Grafaba5e912016-08-19 01:23:30 +02001408 systab.nr_tables = i + 1;
Alexander Grafbee91162016-03-04 01:09:59 +01001409
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001410out:
1411 /* Notify that the configuration table was changed */
1412 list_for_each_entry(evt, &efi_events, link) {
1413 if (evt->group && !guidcmp(evt->group, guid)) {
1414 efi_signal_event(evt, false);
1415 break;
1416 }
1417 }
1418
Alexander Graf488bf122016-08-19 01:23:24 +02001419 return EFI_SUCCESS;
1420}
1421
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001422/*
1423 * Adds, updates, or removes a configuration table.
1424 *
1425 * This function implements the InstallConfigurationTable service.
1426 * See the Unified Extensible Firmware Interface (UEFI) specification
1427 * for details.
1428 *
1429 * @guid GUID of the installed table
1430 * @table table to be installed
1431 * @return status code
1432 */
Alexander Graf488bf122016-08-19 01:23:24 +02001433static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
1434 void *table)
1435{
Rob Clark778e6af2017-09-13 18:05:41 -04001436 EFI_ENTRY("%pUl, %p", guid, table);
Alexander Graf488bf122016-08-19 01:23:24 +02001437 return EFI_EXIT(efi_install_configuration_table(guid, table));
Alexander Grafbee91162016-03-04 01:09:59 +01001438}
1439
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001440/*
1441 * Initialize a loaded_image_info + loaded_image_info object with correct
Rob Clark95c55532017-09-13 18:05:33 -04001442 * protocols, boot-device, etc.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001443 *
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02001444 * @info loaded image info to be passed to the entry point of the
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001445 * image
1446 * @obj internal object associated with the loaded image
1447 * @device_path device path of the loaded image
1448 * @file_path file path of the loaded image
Heinrich Schuchardt56d92882017-12-04 18:03:01 +01001449 * @return status code
Rob Clark95c55532017-09-13 18:05:33 -04001450 */
Heinrich Schuchardt56d92882017-12-04 18:03:01 +01001451efi_status_t efi_setup_loaded_image(
1452 struct efi_loaded_image *info, struct efi_object *obj,
1453 struct efi_device_path *device_path,
1454 struct efi_device_path *file_path)
Rob Clark95c55532017-09-13 18:05:33 -04001455{
Heinrich Schuchardt48b66232017-10-26 19:25:58 +02001456 efi_status_t ret;
1457
Heinrich Schuchardt44549d62017-11-26 14:05:23 +01001458 /* Add internal object to object list */
1459 efi_add_handle(obj);
1460 /* efi_exit() assumes that the handle points to the info */
Rob Clark95c55532017-09-13 18:05:33 -04001461 obj->handle = info;
1462
Rob Clark95c55532017-09-13 18:05:33 -04001463 info->file_path = file_path;
Rob Clark95c55532017-09-13 18:05:33 -04001464
Heinrich Schuchardt7df5af62018-01-26 06:50:54 +01001465 if (device_path) {
1466 info->device_handle = efi_dp_find_obj(device_path, NULL);
1467 /*
1468 * When asking for the device path interface, return
1469 * bootefi_device_path
1470 */
1471 ret = efi_add_protocol(obj->handle, &efi_guid_device_path,
1472 device_path);
1473 if (ret != EFI_SUCCESS)
1474 goto failure;
1475 }
Heinrich Schuchardt48b66232017-10-26 19:25:58 +02001476
1477 /*
1478 * When asking for the loaded_image interface, just
1479 * return handle which points to loaded_image_info
1480 */
1481 ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info);
1482 if (ret != EFI_SUCCESS)
1483 goto failure;
1484
Heinrich Schuchardt48b66232017-10-26 19:25:58 +02001485 ret = efi_add_protocol(obj->handle,
1486 &efi_guid_device_path_to_text_protocol,
1487 (void *)&efi_device_path_to_text);
1488 if (ret != EFI_SUCCESS)
1489 goto failure;
1490
Leif Lindholme70f8df2018-03-09 17:43:21 +01001491 ret = efi_add_protocol(obj->handle,
1492 &efi_guid_device_path_utilities_protocol,
1493 (void *)&efi_device_path_utilities);
1494 if (ret != EFI_SUCCESS)
1495 goto failure;
1496
Heinrich Schuchardt56d92882017-12-04 18:03:01 +01001497 return ret;
Heinrich Schuchardt48b66232017-10-26 19:25:58 +02001498failure:
1499 printf("ERROR: Failure to install protocols for loaded image\n");
Heinrich Schuchardt56d92882017-12-04 18:03:01 +01001500 return ret;
Rob Clark95c55532017-09-13 18:05:33 -04001501}
1502
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001503/*
1504 * Load an image using a file path.
1505 *
1506 * @file_path the path of the image to load
1507 * @buffer buffer containing the loaded image
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02001508 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001509 */
Rob Clark9975fe92017-09-13 18:05:38 -04001510efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
1511 void **buffer)
Rob Clark838ee4b2017-09-13 18:05:35 -04001512{
1513 struct efi_file_info *info = NULL;
1514 struct efi_file_handle *f;
1515 static efi_status_t ret;
Heinrich Schuchardtb6dd5772018-04-03 22:37:11 +02001516 efi_uintn_t bs;
Rob Clark838ee4b2017-09-13 18:05:35 -04001517
1518 f = efi_file_from_path(file_path);
1519 if (!f)
1520 return EFI_DEVICE_ERROR;
1521
1522 bs = 0;
1523 EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid,
1524 &bs, info));
1525 if (ret == EFI_BUFFER_TOO_SMALL) {
1526 info = malloc(bs);
1527 EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid,
1528 &bs, info));
1529 }
1530 if (ret != EFI_SUCCESS)
1531 goto error;
1532
1533 ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer);
1534 if (ret)
1535 goto error;
1536
Heinrich Schuchardtb6dd5772018-04-03 22:37:11 +02001537 bs = info->file_size;
1538 EFI_CALL(ret = f->read(f, &bs, *buffer));
Rob Clark838ee4b2017-09-13 18:05:35 -04001539
1540error:
1541 free(info);
1542 EFI_CALL(f->close(f));
1543
1544 if (ret != EFI_SUCCESS) {
1545 efi_free_pool(*buffer);
1546 *buffer = NULL;
1547 }
1548
1549 return ret;
1550}
1551
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001552/*
1553 * Load an EFI image into memory.
1554 *
1555 * This function implements the LoadImage service.
1556 * See the Unified Extensible Firmware Interface (UEFI) specification
1557 * for details.
1558 *
1559 * @boot_policy true for request originating from the boot manager
Heinrich Schuchardtc8df80c2018-01-24 19:21:36 +01001560 * @parent_image the caller's image handle
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001561 * @file_path the path of the image to load
1562 * @source_buffer memory location from which the image is installed
1563 * @source_size size of the memory area from which the image is
1564 * installed
1565 * @image_handle handle for the newly installed image
1566 * @return status code
1567 */
Alexander Grafbee91162016-03-04 01:09:59 +01001568static efi_status_t EFIAPI efi_load_image(bool boot_policy,
1569 efi_handle_t parent_image,
1570 struct efi_device_path *file_path,
1571 void *source_buffer,
Heinrich Schuchardt7fb96a12018-04-03 22:29:30 +02001572 efi_uintn_t source_size,
Alexander Grafbee91162016-03-04 01:09:59 +01001573 efi_handle_t *image_handle)
1574{
Alexander Grafbee91162016-03-04 01:09:59 +01001575 struct efi_loaded_image *info;
1576 struct efi_object *obj;
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001577 efi_status_t ret;
Alexander Grafbee91162016-03-04 01:09:59 +01001578
Heinrich Schuchardt7fb96a12018-04-03 22:29:30 +02001579 EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image,
Alexander Grafbee91162016-03-04 01:09:59 +01001580 file_path, source_buffer, source_size, image_handle);
Rob Clark838ee4b2017-09-13 18:05:35 -04001581
Heinrich Schuchardt28a4fd42018-03-07 02:40:51 +01001582 if (!image_handle || !parent_image) {
1583 ret = EFI_INVALID_PARAMETER;
1584 goto error;
1585 }
1586
1587 if (!source_buffer && !file_path) {
1588 ret = EFI_NOT_FOUND;
1589 goto error;
1590 }
1591
Rob Clark838ee4b2017-09-13 18:05:35 -04001592 info = calloc(1, sizeof(*info));
Heinrich Schuchardt28a4fd42018-03-07 02:40:51 +01001593 if (!info) {
1594 ret = EFI_OUT_OF_RESOURCES;
1595 goto error;
1596 }
Rob Clark838ee4b2017-09-13 18:05:35 -04001597 obj = calloc(1, sizeof(*obj));
Heinrich Schuchardt28a4fd42018-03-07 02:40:51 +01001598 if (!obj) {
1599 free(info);
1600 ret = EFI_OUT_OF_RESOURCES;
1601 goto error;
1602 }
Rob Clark838ee4b2017-09-13 18:05:35 -04001603
1604 if (!source_buffer) {
1605 struct efi_device_path *dp, *fp;
Rob Clark838ee4b2017-09-13 18:05:35 -04001606
Rob Clark9975fe92017-09-13 18:05:38 -04001607 ret = efi_load_image_from_path(file_path, &source_buffer);
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001608 if (ret != EFI_SUCCESS)
1609 goto failure;
Rob Clark838ee4b2017-09-13 18:05:35 -04001610 /*
1611 * split file_path which contains both the device and
1612 * file parts:
1613 */
1614 efi_dp_split_file_path(file_path, &dp, &fp);
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001615 ret = efi_setup_loaded_image(info, obj, dp, fp);
1616 if (ret != EFI_SUCCESS)
1617 goto failure;
Rob Clark838ee4b2017-09-13 18:05:35 -04001618 } else {
1619 /* In this case, file_path is the "device" path, ie.
1620 * something like a HARDWARE_DEVICE:MEMORY_MAPPED
1621 */
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001622 ret = efi_setup_loaded_image(info, obj, file_path, NULL);
1623 if (ret != EFI_SUCCESS)
1624 goto failure;
Rob Clark838ee4b2017-09-13 18:05:35 -04001625 }
Alexander Grafbee91162016-03-04 01:09:59 +01001626 info->reserved = efi_load_pe(source_buffer, info);
1627 if (!info->reserved) {
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001628 ret = EFI_UNSUPPORTED;
1629 goto failure;
Alexander Grafbee91162016-03-04 01:09:59 +01001630 }
Heinrich Schuchardt32fc2ac2017-10-18 18:13:20 +02001631 info->system_table = &systab;
1632 info->parent_handle = parent_image;
Heinrich Schuchardtea54ad52017-11-26 14:05:22 +01001633 *image_handle = obj->handle;
Alexander Grafbee91162016-03-04 01:09:59 +01001634 return EFI_EXIT(EFI_SUCCESS);
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001635failure:
1636 free(info);
1637 efi_delete_handle(obj);
Heinrich Schuchardt28a4fd42018-03-07 02:40:51 +01001638error:
Heinrich Schuchardtb9b17592017-12-04 18:03:03 +01001639 return EFI_EXIT(ret);
Alexander Grafbee91162016-03-04 01:09:59 +01001640}
1641
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001642/*
1643 * Call the entry point of an image.
1644 *
1645 * This function implements the StartImage service.
1646 * See the Unified Extensible Firmware Interface (UEFI) specification
1647 * for details.
1648 *
1649 * @image_handle handle of the image
1650 * @exit_data_size size of the buffer
1651 * @exit_data buffer to receive the exit data of the called image
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02001652 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001653 */
Alexander Grafbee91162016-03-04 01:09:59 +01001654static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
1655 unsigned long *exit_data_size,
1656 s16 **exit_data)
1657{
Alexander Grafc6fa5df2018-01-24 00:18:08 +01001658 EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
1659 struct efi_system_table *st);
Alexander Grafbee91162016-03-04 01:09:59 +01001660 struct efi_loaded_image *info = image_handle;
Heinrich Schuchardt727a1af2018-01-18 20:28:43 +01001661 efi_status_t ret;
Alexander Grafbee91162016-03-04 01:09:59 +01001662
1663 EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
1664 entry = info->reserved;
1665
1666 efi_is_direct_boot = false;
1667
1668 /* call the image! */
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001669 if (setjmp(&info->exit_jmp)) {
Heinrich Schuchardt727a1af2018-01-18 20:28:43 +01001670 /*
1671 * We called the entry point of the child image with EFI_CALL
1672 * in the lines below. The child image called the Exit() boot
1673 * service efi_exit() which executed the long jump that brought
1674 * us to the current line. This implies that the second half
1675 * of the EFI_CALL macro has not been executed.
1676 */
1677#ifdef CONFIG_ARM
1678 /*
1679 * efi_exit() called efi_restore_gd(). We have to undo this
1680 * otherwise __efi_entry_check() will put the wrong value into
1681 * app_gd.
1682 */
1683 gd = app_gd;
1684#endif
1685 /*
1686 * To get ready to call EFI_EXIT below we have to execute the
1687 * missed out steps of EFI_CALL.
1688 */
1689 assert(__efi_entry_check());
1690 debug("%sEFI: %lu returned by started image\n",
1691 __efi_nesting_dec(),
1692 (unsigned long)((uintptr_t)info->exit_status &
1693 ~EFI_ERROR_MASK));
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001694 return EFI_EXIT(info->exit_status);
1695 }
1696
Heinrich Schuchardt727a1af2018-01-18 20:28:43 +01001697 ret = EFI_CALL(entry(image_handle, &systab));
Alexander Grafbee91162016-03-04 01:09:59 +01001698
Alexander Graf56672bf2018-01-26 00:47:53 +01001699 /*
1700 * Usually UEFI applications call Exit() instead of returning.
1701 * But because the world doesn not consist of ponies and unicorns,
1702 * we're happy to emulate that behavior on behalf of a payload
1703 * that forgot.
1704 */
1705 return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
Alexander Grafbee91162016-03-04 01:09:59 +01001706}
1707
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001708/*
1709 * Leave an EFI application or driver.
1710 *
1711 * This function implements the Exit service.
1712 * See the Unified Extensible Firmware Interface (UEFI) specification
1713 * for details.
1714 *
1715 * @image_handle handle of the application or driver that is exiting
1716 * @exit_status status code
1717 * @exit_data_size size of the buffer in bytes
1718 * @exit_data buffer with data describing an error
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02001719 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001720 */
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001721static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001722 efi_status_t exit_status,
1723 unsigned long exit_data_size,
1724 int16_t *exit_data)
Alexander Grafbee91162016-03-04 01:09:59 +01001725{
Heinrich Schuchardt44549d62017-11-26 14:05:23 +01001726 /*
1727 * We require that the handle points to the original loaded
1728 * image protocol interface.
1729 *
1730 * For getting the longjmp address this is safer than locating
1731 * the protocol because the protocol may have been reinstalled
1732 * pointing to another memory location.
1733 *
1734 * TODO: We should call the unload procedure of the loaded
1735 * image protocol.
1736 */
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001737 struct efi_loaded_image *loaded_image_info = (void *)image_handle;
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001738
Alexander Grafbee91162016-03-04 01:09:59 +01001739 EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
1740 exit_data_size, exit_data);
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001741
Alexander Grafa1489202017-09-03 14:14:17 +02001742 /* Make sure entry/exit counts for EFI world cross-overs match */
Heinrich Schuchardt727a1af2018-01-18 20:28:43 +01001743 EFI_EXIT(exit_status);
Heinrich Schuchardtda940732017-08-25 19:53:14 +02001744
Alexander Grafa1489202017-09-03 14:14:17 +02001745 /*
1746 * But longjmp out with the U-Boot gd, not the application's, as
1747 * the other end is a setjmp call inside EFI context.
1748 */
1749 efi_restore_gd();
1750
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001751 loaded_image_info->exit_status = exit_status;
Alexander Graf692fcdd2016-09-27 09:30:32 +02001752 longjmp(&loaded_image_info->exit_jmp, 1);
Alexander Grafa86aeaf2016-05-20 23:28:23 +02001753
1754 panic("EFI application exited");
Alexander Grafbee91162016-03-04 01:09:59 +01001755}
1756
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001757/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001758 * Unload an EFI image.
1759 *
1760 * This function implements the UnloadImage service.
1761 * See the Unified Extensible Firmware Interface (UEFI) specification
1762 * for details.
1763 *
1764 * @image_handle handle of the image to be unloaded
1765 * @return status code
1766 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001767static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
Alexander Grafbee91162016-03-04 01:09:59 +01001768{
1769 struct efi_object *efiobj;
1770
1771 EFI_ENTRY("%p", image_handle);
1772 efiobj = efi_search_obj(image_handle);
1773 if (efiobj)
1774 list_del(&efiobj->link);
1775
1776 return EFI_EXIT(EFI_SUCCESS);
1777}
1778
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001779/*
1780 * Fix up caches for EFI payloads if necessary.
1781 */
Alexander Grafbee91162016-03-04 01:09:59 +01001782static void efi_exit_caches(void)
1783{
1784#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
1785 /*
1786 * Grub on 32bit ARM needs to have caches disabled before jumping into
1787 * a zImage, but does not know of all cache layers. Give it a hand.
1788 */
1789 if (efi_is_direct_boot)
1790 cleanup_before_linux();
1791#endif
1792}
1793
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001794/*
Heinrich Schuchardtcc20ed02018-01-19 20:24:52 +01001795 * Stop all boot services.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001796 *
1797 * This function implements the ExitBootServices service.
1798 * See the Unified Extensible Firmware Interface (UEFI) specification
1799 * for details.
1800 *
Heinrich Schuchardtcc20ed02018-01-19 20:24:52 +01001801 * All timer events are disabled.
1802 * For exit boot services events the notification function is called.
1803 * The boot services are disabled in the system table.
1804 *
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001805 * @image_handle handle of the loaded image
1806 * @map_key key of the memory map
1807 * @return status code
1808 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001809static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
Alexander Grafbee91162016-03-04 01:09:59 +01001810 unsigned long map_key)
1811{
Heinrich Schuchardt43bce442018-02-18 15:17:50 +01001812 struct efi_event *evt;
Heinrich Schuchardt152a2632017-09-15 10:06:18 +02001813
Alexander Grafbee91162016-03-04 01:09:59 +01001814 EFI_ENTRY("%p, %ld", image_handle, map_key);
1815
Heinrich Schuchardtcc20ed02018-01-19 20:24:52 +01001816 /* Make sure that notification functions are not called anymore */
1817 efi_tpl = TPL_HIGH_LEVEL;
1818
1819 /* Check if ExitBootServices has already been called */
1820 if (!systab.boottime)
1821 return EFI_EXIT(EFI_SUCCESS);
1822
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001823 /* Add related events to the event group */
1824 list_for_each_entry(evt, &efi_events, link) {
1825 if (evt->type == EVT_SIGNAL_EXIT_BOOT_SERVICES)
1826 evt->group = &efi_guid_event_group_exit_boot_services;
1827 }
Heinrich Schuchardt152a2632017-09-15 10:06:18 +02001828 /* Notify that ExitBootServices is invoked. */
Heinrich Schuchardt43bce442018-02-18 15:17:50 +01001829 list_for_each_entry(evt, &efi_events, link) {
Heinrich Schuchardtb095f3c2018-02-18 15:17:52 +01001830 if (evt->group &&
1831 !guidcmp(evt->group,
1832 &efi_guid_event_group_exit_boot_services)) {
1833 efi_signal_event(evt, false);
1834 break;
1835 }
Heinrich Schuchardt152a2632017-09-15 10:06:18 +02001836 }
Heinrich Schuchardt152a2632017-09-15 10:06:18 +02001837
Heinrich Schuchardtcc20ed02018-01-19 20:24:52 +01001838 /* TODO Should persist EFI variables here */
Rob Clarkad644e72017-09-13 18:05:37 -04001839
Alexander Grafb7b84102016-11-17 01:02:57 +01001840 board_quiesce_devices();
1841
Alexander Grafbee91162016-03-04 01:09:59 +01001842 /* Fix up caches for EFI payloads if necessary */
1843 efi_exit_caches();
1844
1845 /* This stops all lingering devices */
1846 bootm_disable_interrupts();
1847
Heinrich Schuchardtcc20ed02018-01-19 20:24:52 +01001848 /* Disable boottime services */
1849 systab.con_in_handle = NULL;
1850 systab.con_in = NULL;
1851 systab.con_out_handle = NULL;
1852 systab.con_out = NULL;
1853 systab.stderr_handle = NULL;
1854 systab.std_err = NULL;
1855 systab.boottime = NULL;
1856
1857 /* Recalculate CRC32 */
1858 systab.hdr.crc32 = 0;
1859 systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab,
1860 sizeof(struct efi_system_table));
1861
Alexander Grafbee91162016-03-04 01:09:59 +01001862 /* Give the payload some time to boot */
Heinrich Schuchardtb3d60902017-10-18 18:13:04 +02001863 efi_set_watchdog(0);
Alexander Grafbee91162016-03-04 01:09:59 +01001864 WATCHDOG_RESET();
1865
1866 return EFI_EXIT(EFI_SUCCESS);
1867}
1868
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001869/*
1870 * Get next value of the counter.
1871 *
1872 * This function implements the NextMonotonicCount service.
1873 * See the Unified Extensible Firmware Interface (UEFI) specification
1874 * for details.
1875 *
1876 * @count returned value of the counter
1877 * @return status code
1878 */
Alexander Grafbee91162016-03-04 01:09:59 +01001879static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count)
1880{
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001881 static uint64_t mono;
1882
Alexander Grafbee91162016-03-04 01:09:59 +01001883 EFI_ENTRY("%p", count);
1884 *count = mono++;
1885 return EFI_EXIT(EFI_SUCCESS);
1886}
1887
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001888/*
1889 * Sleep.
1890 *
1891 * This function implements the Stall sercive.
1892 * See the Unified Extensible Firmware Interface (UEFI) specification
1893 * for details.
1894 *
1895 * @microseconds period to sleep in microseconds
1896 * @return status code
1897 */
Alexander Grafbee91162016-03-04 01:09:59 +01001898static efi_status_t EFIAPI efi_stall(unsigned long microseconds)
1899{
1900 EFI_ENTRY("%ld", microseconds);
1901 udelay(microseconds);
1902 return EFI_EXIT(EFI_SUCCESS);
1903}
1904
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001905/*
1906 * Reset the watchdog timer.
1907 *
Heinrich Schuchardtb3d60902017-10-18 18:13:04 +02001908 * This function implements the SetWatchdogTimer service.
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001909 * See the Unified Extensible Firmware Interface (UEFI) specification
1910 * for details.
1911 *
1912 * @timeout seconds before reset by watchdog
1913 * @watchdog_code code to be logged when resetting
1914 * @data_size size of buffer in bytes
1915 * @watchdog_data buffer with data describing the reset reason
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02001916 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001917 */
Alexander Grafbee91162016-03-04 01:09:59 +01001918static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
1919 uint64_t watchdog_code,
1920 unsigned long data_size,
1921 uint16_t *watchdog_data)
1922{
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001923 EFI_ENTRY("%ld, 0x%" PRIx64 ", %ld, %p", timeout, watchdog_code,
Alexander Grafbee91162016-03-04 01:09:59 +01001924 data_size, watchdog_data);
Heinrich Schuchardtb3d60902017-10-18 18:13:04 +02001925 return EFI_EXIT(efi_set_watchdog(timeout));
Alexander Grafbee91162016-03-04 01:09:59 +01001926}
1927
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001928/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001929 * Close a protocol.
1930 *
1931 * This function implements the CloseProtocol service.
1932 * See the Unified Extensible Firmware Interface (UEFI) specification
1933 * for details.
1934 *
1935 * @handle handle on which the protocol shall be closed
1936 * @protocol GUID of the protocol to close
1937 * @agent_handle handle of the driver
1938 * @controller_handle handle of the controller
1939 * @return status code
1940 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001941static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02001942 const efi_guid_t *protocol,
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01001943 efi_handle_t agent_handle,
1944 efi_handle_t controller_handle)
Alexander Grafbee91162016-03-04 01:09:59 +01001945{
Heinrich Schuchardt3b8a4892018-01-11 08:15:59 +01001946 struct efi_handler *handler;
1947 struct efi_open_protocol_info_item *item;
1948 struct efi_open_protocol_info_item *pos;
1949 efi_status_t r;
1950
Rob Clark778e6af2017-09-13 18:05:41 -04001951 EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle,
Alexander Grafbee91162016-03-04 01:09:59 +01001952 controller_handle);
Heinrich Schuchardt3b8a4892018-01-11 08:15:59 +01001953
1954 if (!agent_handle) {
1955 r = EFI_INVALID_PARAMETER;
1956 goto out;
1957 }
1958 r = efi_search_protocol(handle, protocol, &handler);
1959 if (r != EFI_SUCCESS)
1960 goto out;
1961
1962 r = EFI_NOT_FOUND;
1963 list_for_each_entry_safe(item, pos, &handler->open_infos, link) {
1964 if (item->info.agent_handle == agent_handle &&
1965 item->info.controller_handle == controller_handle) {
1966 efi_delete_open_info(item);
1967 r = EFI_SUCCESS;
1968 break;
1969 }
1970 }
1971out:
1972 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01001973}
1974
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02001975/*
1976 * Provide information about then open status of a protocol on a handle
1977 *
1978 * This function implements the OpenProtocolInformation service.
1979 * See the Unified Extensible Firmware Interface (UEFI) specification
1980 * for details.
1981 *
1982 * @handle handle for which the information shall be retrieved
1983 * @protocol GUID of the protocol
1984 * @entry_buffer buffer to receive the open protocol information
1985 * @entry_count number of entries available in the buffer
1986 * @return status code
1987 */
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01001988static efi_status_t EFIAPI efi_open_protocol_information(
1989 efi_handle_t handle, const efi_guid_t *protocol,
Alexander Grafbee91162016-03-04 01:09:59 +01001990 struct efi_open_protocol_info_entry **entry_buffer,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01001991 efi_uintn_t *entry_count)
Alexander Grafbee91162016-03-04 01:09:59 +01001992{
Heinrich Schuchardte3fbbc32018-01-11 08:16:00 +01001993 unsigned long buffer_size;
1994 unsigned long count;
1995 struct efi_handler *handler;
1996 struct efi_open_protocol_info_item *item;
1997 efi_status_t r;
1998
Rob Clark778e6af2017-09-13 18:05:41 -04001999 EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer,
Alexander Grafbee91162016-03-04 01:09:59 +01002000 entry_count);
Heinrich Schuchardte3fbbc32018-01-11 08:16:00 +01002001
2002 /* Check parameters */
2003 if (!entry_buffer) {
2004 r = EFI_INVALID_PARAMETER;
2005 goto out;
2006 }
2007 r = efi_search_protocol(handle, protocol, &handler);
2008 if (r != EFI_SUCCESS)
2009 goto out;
2010
2011 /* Count entries */
2012 count = 0;
2013 list_for_each_entry(item, &handler->open_infos, link) {
2014 if (item->info.open_count)
2015 ++count;
2016 }
2017 *entry_count = count;
2018 *entry_buffer = NULL;
2019 if (!count) {
2020 r = EFI_SUCCESS;
2021 goto out;
2022 }
2023
2024 /* Copy entries */
2025 buffer_size = count * sizeof(struct efi_open_protocol_info_entry);
2026 r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
2027 (void **)entry_buffer);
2028 if (r != EFI_SUCCESS)
2029 goto out;
2030 list_for_each_entry_reverse(item, &handler->open_infos, link) {
2031 if (item->info.open_count)
2032 (*entry_buffer)[--count] = item->info;
2033 }
2034out:
2035 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01002036}
2037
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002038/*
2039 * Get protocols installed on a handle.
2040 *
2041 * This function implements the ProtocolsPerHandleService.
2042 * See the Unified Extensible Firmware Interface (UEFI) specification
2043 * for details.
2044 *
2045 * @handle handle for which the information is retrieved
2046 * @protocol_buffer buffer with protocol GUIDs
2047 * @protocol_buffer_count number of entries in the buffer
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02002048 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002049 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01002050static efi_status_t EFIAPI efi_protocols_per_handle(
2051 efi_handle_t handle, efi_guid_t ***protocol_buffer,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01002052 efi_uintn_t *protocol_buffer_count)
Alexander Grafbee91162016-03-04 01:09:59 +01002053{
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002054 unsigned long buffer_size;
2055 struct efi_object *efiobj;
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +01002056 struct list_head *protocol_handle;
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002057 efi_status_t r;
2058
Alexander Grafbee91162016-03-04 01:09:59 +01002059 EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
2060 protocol_buffer_count);
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002061
2062 if (!handle || !protocol_buffer || !protocol_buffer_count)
2063 return EFI_EXIT(EFI_INVALID_PARAMETER);
2064
2065 *protocol_buffer = NULL;
Rob Clark661c8322017-07-20 07:59:39 -04002066 *protocol_buffer_count = 0;
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002067
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +01002068 efiobj = efi_search_obj(handle);
2069 if (!efiobj)
2070 return EFI_EXIT(EFI_INVALID_PARAMETER);
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002071
Heinrich Schuchardt69fb6b12017-11-26 14:05:17 +01002072 /* Count protocols */
2073 list_for_each(protocol_handle, &efiobj->protocols) {
2074 ++*protocol_buffer_count;
2075 }
2076
2077 /* Copy guids */
2078 if (*protocol_buffer_count) {
2079 size_t j = 0;
2080
2081 buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count;
2082 r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
2083 (void **)protocol_buffer);
2084 if (r != EFI_SUCCESS)
2085 return EFI_EXIT(r);
2086 list_for_each(protocol_handle, &efiobj->protocols) {
2087 struct efi_handler *protocol;
2088
2089 protocol = list_entry(protocol_handle,
2090 struct efi_handler, link);
2091 (*protocol_buffer)[j] = (void *)protocol->guid;
2092 ++j;
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002093 }
xypron.glpk@gmx.dec0ebfc82017-07-13 23:24:32 +02002094 }
2095
2096 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +01002097}
2098
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002099/*
2100 * Locate handles implementing a protocol.
2101 *
2102 * This function implements the LocateHandleBuffer service.
2103 * See the Unified Extensible Firmware Interface (UEFI) specification
2104 * for details.
2105 *
2106 * @search_type selection criterion
2107 * @protocol GUID of the protocol
2108 * @search_key registration key
2109 * @no_handles number of returned handles
2110 * @buffer buffer with the returned handles
2111 * @return status code
2112 */
Alexander Grafbee91162016-03-04 01:09:59 +01002113static efi_status_t EFIAPI efi_locate_handle_buffer(
2114 enum efi_locate_search_type search_type,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02002115 const efi_guid_t *protocol, void *search_key,
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01002116 efi_uintn_t *no_handles, efi_handle_t **buffer)
Alexander Grafbee91162016-03-04 01:09:59 +01002117{
xypron.glpk@gmx.dec2e703f2017-07-11 22:06:22 +02002118 efi_status_t r;
Heinrich Schuchardtf5a2a932017-11-06 21:17:48 +01002119 efi_uintn_t buffer_size = 0;
xypron.glpk@gmx.dec2e703f2017-07-11 22:06:22 +02002120
Rob Clark778e6af2017-09-13 18:05:41 -04002121 EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key,
Alexander Grafbee91162016-03-04 01:09:59 +01002122 no_handles, buffer);
xypron.glpk@gmx.dec2e703f2017-07-11 22:06:22 +02002123
2124 if (!no_handles || !buffer) {
2125 r = EFI_INVALID_PARAMETER;
2126 goto out;
2127 }
2128 *no_handles = 0;
2129 *buffer = NULL;
2130 r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
2131 *buffer);
2132 if (r != EFI_BUFFER_TOO_SMALL)
2133 goto out;
2134 r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
2135 (void **)buffer);
2136 if (r != EFI_SUCCESS)
2137 goto out;
2138 r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
2139 *buffer);
2140 if (r == EFI_SUCCESS)
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01002141 *no_handles = buffer_size / sizeof(efi_handle_t);
xypron.glpk@gmx.dec2e703f2017-07-11 22:06:22 +02002142out:
2143 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01002144}
2145
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002146/*
2147 * Find an interface implementing a protocol.
2148 *
2149 * This function implements the LocateProtocol service.
2150 * See the Unified Extensible Firmware Interface (UEFI) specification
2151 * for details.
2152 *
2153 * @protocol GUID of the protocol
2154 * @registration registration key passed to the notification function
2155 * @protocol_interface interface implementing the protocol
Heinrich Schuchardt10a08c42017-10-08 06:57:27 +02002156 * @return status code
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002157 */
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02002158static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
Alexander Grafbee91162016-03-04 01:09:59 +01002159 void *registration,
2160 void **protocol_interface)
2161{
xypron.glpk@gmx.de88adae52017-07-11 22:06:24 +02002162 struct list_head *lhandle;
Heinrich Schuchardt9172cd92017-10-26 19:25:57 +02002163 efi_status_t ret;
Alexander Grafbee91162016-03-04 01:09:59 +01002164
Rob Clark778e6af2017-09-13 18:05:41 -04002165 EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface);
xypron.glpk@gmx.de88adae52017-07-11 22:06:24 +02002166
2167 if (!protocol || !protocol_interface)
2168 return EFI_EXIT(EFI_INVALID_PARAMETER);
2169
2170 list_for_each(lhandle, &efi_obj_list) {
2171 struct efi_object *efiobj;
Heinrich Schuchardt9172cd92017-10-26 19:25:57 +02002172 struct efi_handler *handler;
xypron.glpk@gmx.de88adae52017-07-11 22:06:24 +02002173
2174 efiobj = list_entry(lhandle, struct efi_object, link);
xypron.glpk@gmx.de88adae52017-07-11 22:06:24 +02002175
Heinrich Schuchardt9172cd92017-10-26 19:25:57 +02002176 ret = efi_search_protocol(efiobj->handle, protocol, &handler);
2177 if (ret == EFI_SUCCESS) {
2178 *protocol_interface = handler->protocol_interface;
2179 return EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +01002180 }
2181 }
xypron.glpk@gmx.de88adae52017-07-11 22:06:24 +02002182 *protocol_interface = NULL;
Alexander Grafbee91162016-03-04 01:09:59 +01002183
2184 return EFI_EXIT(EFI_NOT_FOUND);
2185}
2186
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002187/*
Heinrich Schuchardtae2c85c2017-11-26 14:05:10 +01002188 * Get the device path and handle of an device implementing a protocol.
2189 *
2190 * This function implements the LocateDevicePath service.
2191 * See the Unified Extensible Firmware Interface (UEFI) specification
2192 * for details.
2193 *
2194 * @protocol GUID of the protocol
2195 * @device_path device path
2196 * @device handle of the device
2197 * @return status code
2198 */
2199static efi_status_t EFIAPI efi_locate_device_path(
2200 const efi_guid_t *protocol,
2201 struct efi_device_path **device_path,
2202 efi_handle_t *device)
2203{
2204 struct efi_device_path *dp;
2205 size_t i;
2206 struct efi_handler *handler;
2207 efi_handle_t *handles;
2208 size_t len, len_dp;
2209 size_t len_best = 0;
2210 efi_uintn_t no_handles;
2211 u8 *remainder;
2212 efi_status_t ret;
2213
2214 EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
2215
2216 if (!protocol || !device_path || !*device_path || !device) {
2217 ret = EFI_INVALID_PARAMETER;
2218 goto out;
2219 }
2220
2221 /* Find end of device path */
2222 len = efi_dp_size(*device_path);
2223
2224 /* Get all handles implementing the protocol */
2225 ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
2226 &no_handles, &handles));
2227 if (ret != EFI_SUCCESS)
2228 goto out;
2229
2230 for (i = 0; i < no_handles; ++i) {
2231 /* Find the device path protocol */
2232 ret = efi_search_protocol(handles[i], &efi_guid_device_path,
2233 &handler);
2234 if (ret != EFI_SUCCESS)
2235 continue;
2236 dp = (struct efi_device_path *)handler->protocol_interface;
2237 len_dp = efi_dp_size(dp);
2238 /*
2239 * This handle can only be a better fit
2240 * if its device path length is longer than the best fit and
2241 * if its device path length is shorter of equal the searched
2242 * device path.
2243 */
2244 if (len_dp <= len_best || len_dp > len)
2245 continue;
2246 /* Check if dp is a subpath of device_path */
2247 if (memcmp(*device_path, dp, len_dp))
2248 continue;
2249 *device = handles[i];
2250 len_best = len_dp;
2251 }
2252 if (len_best) {
2253 remainder = (u8 *)*device_path + len_best;
2254 *device_path = (struct efi_device_path *)remainder;
2255 ret = EFI_SUCCESS;
2256 } else {
2257 ret = EFI_NOT_FOUND;
2258 }
2259out:
2260 return EFI_EXIT(ret);
2261}
2262
2263/*
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002264 * Install multiple protocol interfaces.
2265 *
2266 * This function implements the MultipleProtocolInterfaces service.
2267 * See the Unified Extensible Firmware Interface (UEFI) specification
2268 * for details.
2269 *
2270 * @handle handle on which the protocol interfaces shall be installed
2271 * @... NULL terminated argument list with pairs of protocol GUIDS and
2272 * interfaces
2273 * @return status code
2274 */
Alexander Grafbee91162016-03-04 01:09:59 +01002275static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
2276 void **handle, ...)
2277{
2278 EFI_ENTRY("%p", handle);
xypron.glpk@gmx.de58b83582017-07-11 22:06:20 +02002279
2280 va_list argptr;
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02002281 const efi_guid_t *protocol;
xypron.glpk@gmx.de58b83582017-07-11 22:06:20 +02002282 void *protocol_interface;
2283 efi_status_t r = EFI_SUCCESS;
2284 int i = 0;
2285
2286 if (!handle)
2287 return EFI_EXIT(EFI_INVALID_PARAMETER);
2288
2289 va_start(argptr, handle);
2290 for (;;) {
2291 protocol = va_arg(argptr, efi_guid_t*);
2292 if (!protocol)
2293 break;
2294 protocol_interface = va_arg(argptr, void*);
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +01002295 r = EFI_CALL(efi_install_protocol_interface(
2296 handle, protocol,
2297 EFI_NATIVE_INTERFACE,
2298 protocol_interface));
xypron.glpk@gmx.de58b83582017-07-11 22:06:20 +02002299 if (r != EFI_SUCCESS)
2300 break;
2301 i++;
2302 }
2303 va_end(argptr);
2304 if (r == EFI_SUCCESS)
2305 return EFI_EXIT(r);
2306
Heinrich Schuchardt62471e42017-10-26 19:25:42 +02002307 /* If an error occurred undo all changes. */
xypron.glpk@gmx.de58b83582017-07-11 22:06:20 +02002308 va_start(argptr, handle);
2309 for (; i; --i) {
2310 protocol = va_arg(argptr, efi_guid_t*);
2311 protocol_interface = va_arg(argptr, void*);
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01002312 EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
2313 protocol_interface));
xypron.glpk@gmx.de58b83582017-07-11 22:06:20 +02002314 }
2315 va_end(argptr);
2316
2317 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01002318}
2319
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002320/*
2321 * Uninstall multiple protocol interfaces.
2322 *
2323 * This function implements the UninstallMultipleProtocolInterfaces service.
2324 * See the Unified Extensible Firmware Interface (UEFI) specification
2325 * for details.
2326 *
2327 * @handle handle from which the protocol interfaces shall be removed
2328 * @... NULL terminated argument list with pairs of protocol GUIDS and
2329 * interfaces
2330 * @return status code
2331 */
Alexander Grafbee91162016-03-04 01:09:59 +01002332static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
2333 void *handle, ...)
2334{
2335 EFI_ENTRY("%p", handle);
Heinrich Schuchardt843ce542017-10-26 19:25:44 +02002336
2337 va_list argptr;
2338 const efi_guid_t *protocol;
2339 void *protocol_interface;
2340 efi_status_t r = EFI_SUCCESS;
2341 size_t i = 0;
2342
2343 if (!handle)
2344 return EFI_EXIT(EFI_INVALID_PARAMETER);
2345
2346 va_start(argptr, handle);
2347 for (;;) {
2348 protocol = va_arg(argptr, efi_guid_t*);
2349 if (!protocol)
2350 break;
2351 protocol_interface = va_arg(argptr, void*);
2352 r = EFI_CALL(efi_uninstall_protocol_interface(
2353 handle, protocol,
2354 protocol_interface));
2355 if (r != EFI_SUCCESS)
2356 break;
2357 i++;
2358 }
2359 va_end(argptr);
2360 if (r == EFI_SUCCESS)
2361 return EFI_EXIT(r);
2362
2363 /* If an error occurred undo all changes. */
2364 va_start(argptr, handle);
2365 for (; i; --i) {
2366 protocol = va_arg(argptr, efi_guid_t*);
2367 protocol_interface = va_arg(argptr, void*);
2368 EFI_CALL(efi_install_protocol_interface(&handle, protocol,
2369 EFI_NATIVE_INTERFACE,
2370 protocol_interface));
2371 }
2372 va_end(argptr);
2373
2374 return EFI_EXIT(r);
Alexander Grafbee91162016-03-04 01:09:59 +01002375}
2376
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002377/*
2378 * Calculate cyclic redundancy code.
2379 *
2380 * This function implements the CalculateCrc32 service.
2381 * See the Unified Extensible Firmware Interface (UEFI) specification
2382 * for details.
2383 *
2384 * @data buffer with data
2385 * @data_size size of buffer in bytes
2386 * @crc32_p cyclic redundancy code
2387 * @return status code
2388 */
Alexander Grafbee91162016-03-04 01:09:59 +01002389static efi_status_t EFIAPI efi_calculate_crc32(void *data,
2390 unsigned long data_size,
2391 uint32_t *crc32_p)
2392{
2393 EFI_ENTRY("%p, %ld", data, data_size);
2394 *crc32_p = crc32(0, data, data_size);
2395 return EFI_EXIT(EFI_SUCCESS);
2396}
2397
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002398/*
2399 * Copy memory.
2400 *
2401 * This function implements the CopyMem service.
2402 * See the Unified Extensible Firmware Interface (UEFI) specification
2403 * for details.
2404 *
2405 * @destination destination of the copy operation
2406 * @source source of the copy operation
2407 * @length number of bytes to copy
2408 */
Heinrich Schuchardtfc05a952017-10-05 16:35:52 +02002409static void EFIAPI efi_copy_mem(void *destination, const void *source,
2410 size_t length)
Alexander Grafbee91162016-03-04 01:09:59 +01002411{
Heinrich Schuchardtfc05a952017-10-05 16:35:52 +02002412 EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length);
Alexander Grafbee91162016-03-04 01:09:59 +01002413 memcpy(destination, source, length);
Heinrich Schuchardtf7c78172017-10-05 16:35:51 +02002414 EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +01002415}
2416
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002417/*
2418 * Fill memory with a byte value.
2419 *
2420 * This function implements the SetMem service.
2421 * See the Unified Extensible Firmware Interface (UEFI) specification
2422 * for details.
2423 *
2424 * @buffer buffer to fill
2425 * @size size of buffer in bytes
2426 * @value byte to copy to the buffer
2427 */
Heinrich Schuchardtfc05a952017-10-05 16:35:52 +02002428static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
Alexander Grafbee91162016-03-04 01:09:59 +01002429{
Heinrich Schuchardtfc05a952017-10-05 16:35:52 +02002430 EFI_ENTRY("%p, %ld, 0x%x", buffer, (unsigned long)size, value);
Alexander Grafbee91162016-03-04 01:09:59 +01002431 memset(buffer, value, size);
Heinrich Schuchardtf7c78172017-10-05 16:35:51 +02002432 EFI_EXIT(EFI_SUCCESS);
Alexander Grafbee91162016-03-04 01:09:59 +01002433}
2434
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002435/*
2436 * Open protocol interface on a handle.
2437 *
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002438 * @handler handler of a protocol
2439 * @protocol_interface interface implementing the protocol
2440 * @agent_handle handle of the driver
2441 * @controller_handle handle of the controller
2442 * @attributes attributes indicating how to open the protocol
2443 * @return status code
2444 */
2445static efi_status_t efi_protocol_open(
2446 struct efi_handler *handler,
2447 void **protocol_interface, void *agent_handle,
2448 void *controller_handle, uint32_t attributes)
2449{
2450 struct efi_open_protocol_info_item *item;
2451 struct efi_open_protocol_info_entry *match = NULL;
2452 bool opened_by_driver = false;
2453 bool opened_exclusive = false;
2454
2455 /* If there is no agent, only return the interface */
2456 if (!agent_handle)
2457 goto out;
2458
2459 /* For TEST_PROTOCOL ignore interface attribute */
2460 if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
2461 *protocol_interface = NULL;
2462
2463 /*
2464 * Check if the protocol is already opened by a driver with the same
2465 * attributes or opened exclusively
2466 */
2467 list_for_each_entry(item, &handler->open_infos, link) {
2468 if (item->info.agent_handle == agent_handle) {
2469 if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) &&
2470 (item->info.attributes == attributes))
2471 return EFI_ALREADY_STARTED;
2472 }
2473 if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE)
2474 opened_exclusive = true;
2475 }
2476
2477 /* Only one controller can open the protocol exclusively */
2478 if (opened_exclusive && attributes &
2479 (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER))
2480 return EFI_ACCESS_DENIED;
2481
2482 /* Prepare exclusive opening */
2483 if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) {
2484 /* Try to disconnect controllers */
2485 list_for_each_entry(item, &handler->open_infos, link) {
2486 if (item->info.attributes ==
2487 EFI_OPEN_PROTOCOL_BY_DRIVER)
2488 EFI_CALL(efi_disconnect_controller(
2489 item->info.controller_handle,
2490 item->info.agent_handle,
2491 NULL));
2492 }
2493 opened_by_driver = false;
2494 /* Check if all controllers are disconnected */
2495 list_for_each_entry(item, &handler->open_infos, link) {
2496 if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER)
2497 opened_by_driver = true;
2498 }
2499 /* Only one controller can be conncected */
2500 if (opened_by_driver)
2501 return EFI_ACCESS_DENIED;
2502 }
2503
2504 /* Find existing entry */
2505 list_for_each_entry(item, &handler->open_infos, link) {
2506 if (item->info.agent_handle == agent_handle &&
2507 item->info.controller_handle == controller_handle)
2508 match = &item->info;
2509 }
2510 /* None found, create one */
2511 if (!match) {
2512 match = efi_create_open_info(handler);
2513 if (!match)
2514 return EFI_OUT_OF_RESOURCES;
2515 }
2516
2517 match->agent_handle = agent_handle;
2518 match->controller_handle = controller_handle;
2519 match->attributes = attributes;
2520 match->open_count++;
2521
2522out:
2523 /* For TEST_PROTOCOL ignore interface attribute. */
2524 if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
2525 *protocol_interface = handler->protocol_interface;
2526
2527 return EFI_SUCCESS;
2528}
2529
2530/*
2531 * Open protocol interface on a handle.
2532 *
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002533 * This function implements the OpenProtocol interface.
2534 * See the Unified Extensible Firmware Interface (UEFI) specification
2535 * for details.
2536 *
2537 * @handle handle on which the protocol shall be opened
2538 * @protocol GUID of the protocol
2539 * @protocol_interface interface implementing the protocol
2540 * @agent_handle handle of the driver
2541 * @controller_handle handle of the controller
2542 * @attributes attributes indicating how to open the protocol
2543 * @return status code
2544 */
Alexander Grafbee91162016-03-04 01:09:59 +01002545static efi_status_t EFIAPI efi_open_protocol(
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02002546 void *handle, const efi_guid_t *protocol,
Alexander Grafbee91162016-03-04 01:09:59 +01002547 void **protocol_interface, void *agent_handle,
2548 void *controller_handle, uint32_t attributes)
2549{
Heinrich Schuchardt80286e82017-11-26 14:05:15 +01002550 struct efi_handler *handler;
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002551 efi_status_t r = EFI_INVALID_PARAMETER;
Alexander Grafbee91162016-03-04 01:09:59 +01002552
Rob Clark778e6af2017-09-13 18:05:41 -04002553 EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol,
Alexander Grafbee91162016-03-04 01:09:59 +01002554 protocol_interface, agent_handle, controller_handle,
2555 attributes);
xypron.glpk@gmx.deb5349f72017-07-11 22:06:14 +02002556
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002557 if (!handle || !protocol ||
2558 (!protocol_interface && attributes !=
2559 EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
2560 goto out;
2561 }
2562
2563 switch (attributes) {
2564 case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
2565 case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
2566 case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
2567 break;
2568 case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
2569 if (controller_handle == handle)
2570 goto out;
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002571 /* fall-through */
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002572 case EFI_OPEN_PROTOCOL_BY_DRIVER:
2573 case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002574 /* Check that the controller handle is valid */
2575 if (!efi_search_obj(controller_handle))
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002576 goto out;
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002577 /* fall-through */
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002578 case EFI_OPEN_PROTOCOL_EXCLUSIVE:
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002579 /* Check that the agent handle is valid */
2580 if (!efi_search_obj(agent_handle))
xypron.glpk@gmx.de69baec62017-07-11 22:06:15 +02002581 goto out;
2582 break;
2583 default:
xypron.glpk@gmx.deb5349f72017-07-11 22:06:14 +02002584 goto out;
2585 }
2586
Heinrich Schuchardt80286e82017-11-26 14:05:15 +01002587 r = efi_search_protocol(handle, protocol, &handler);
2588 if (r != EFI_SUCCESS)
2589 goto out;
Alexander Grafbee91162016-03-04 01:09:59 +01002590
Heinrich Schuchardt191a41c2018-01-11 08:15:58 +01002591 r = efi_protocol_open(handler, protocol_interface, agent_handle,
2592 controller_handle, attributes);
Alexander Grafbee91162016-03-04 01:09:59 +01002593out:
2594 return EFI_EXIT(r);
2595}
2596
Heinrich Schuchardt332468f2017-09-21 18:30:11 +02002597/*
2598 * Get interface of a protocol on a handle.
2599 *
2600 * This function implements the HandleProtocol service.
2601 * See the Unified Extensible Firmware Interface (UEFI) specification
2602 * for details.
2603 *
2604 * @handle handle on which the protocol shall be opened
2605 * @protocol GUID of the protocol
2606 * @protocol_interface interface implementing the protocol
2607 * @return status code
2608 */
Heinrich Schuchardt2074f702018-01-11 08:16:09 +01002609static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle,
Heinrich Schuchardt5a9682d2017-10-05 16:35:53 +02002610 const efi_guid_t *protocol,
Alexander Grafbee91162016-03-04 01:09:59 +01002611 void **protocol_interface)
2612{
xypron.glpk@gmx.de8e1d3292017-06-29 21:16:19 +02002613 return efi_open_protocol(handle, protocol, protocol_interface, NULL,
2614 NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
Alexander Grafbee91162016-03-04 01:09:59 +01002615}
2616
Heinrich Schuchardtf0959db2018-01-11 08:16:02 +01002617static efi_status_t efi_bind_controller(
2618 efi_handle_t controller_handle,
2619 efi_handle_t driver_image_handle,
2620 struct efi_device_path *remain_device_path)
2621{
2622 struct efi_driver_binding_protocol *binding_protocol;
2623 efi_status_t r;
2624
2625 r = EFI_CALL(efi_open_protocol(driver_image_handle,
2626 &efi_guid_driver_binding_protocol,
2627 (void **)&binding_protocol,
2628 driver_image_handle, NULL,
2629 EFI_OPEN_PROTOCOL_GET_PROTOCOL));
2630 if (r != EFI_SUCCESS)
2631 return r;
2632 r = EFI_CALL(binding_protocol->supported(binding_protocol,
2633 controller_handle,
2634 remain_device_path));
2635 if (r == EFI_SUCCESS)
2636 r = EFI_CALL(binding_protocol->start(binding_protocol,
2637 controller_handle,
2638 remain_device_path));
2639 EFI_CALL(efi_close_protocol(driver_image_handle,
2640 &efi_guid_driver_binding_protocol,
2641 driver_image_handle, NULL));
2642 return r;
2643}
2644
2645static efi_status_t efi_connect_single_controller(
2646 efi_handle_t controller_handle,
2647 efi_handle_t *driver_image_handle,
2648 struct efi_device_path *remain_device_path)
2649{
2650 efi_handle_t *buffer;
2651 size_t count;
2652 size_t i;
2653 efi_status_t r;
2654 size_t connected = 0;
2655
2656 /* Get buffer with all handles with driver binding protocol */
2657 r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
2658 &efi_guid_driver_binding_protocol,
2659 NULL, &count, &buffer));
2660 if (r != EFI_SUCCESS)
2661 return r;
2662
2663 /* Context Override */
2664 if (driver_image_handle) {
2665 for (; *driver_image_handle; ++driver_image_handle) {
2666 for (i = 0; i < count; ++i) {
2667 if (buffer[i] == *driver_image_handle) {
2668 buffer[i] = NULL;
2669 r = efi_bind_controller(
2670 controller_handle,
2671 *driver_image_handle,
2672 remain_device_path);
2673 /*
2674 * For drivers that do not support the
2675 * controller or are already connected
2676 * we receive an error code here.
2677 */
2678 if (r == EFI_SUCCESS)
2679 ++connected;
2680 }
2681 }
2682 }
2683 }
2684
2685 /*
2686 * TODO: Some overrides are not yet implemented:
2687 * - Platform Driver Override
2688 * - Driver Family Override Search
2689 * - Bus Specific Driver Override
2690 */
2691
2692 /* Driver Binding Search */
2693 for (i = 0; i < count; ++i) {
2694 if (buffer[i]) {
2695 r = efi_bind_controller(controller_handle,
2696 buffer[i],
2697 remain_device_path);
2698 if (r == EFI_SUCCESS)
2699 ++connected;
2700 }
2701 }
2702
2703 efi_free_pool(buffer);
2704 if (!connected)
2705 return EFI_NOT_FOUND;
2706 return EFI_SUCCESS;
2707}
2708
2709/*
2710 * Connect a controller to a driver.
2711 *
2712 * This function implements the ConnectController service.
2713 * See the Unified Extensible Firmware Interface (UEFI) specification
2714 * for details.
2715 *
2716 * First all driver binding protocol handles are tried for binding drivers.
2717 * Afterwards all handles that have openened a protocol of the controller
2718 * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers.
2719 *
2720 * @controller_handle handle of the controller
2721 * @driver_image_handle handle of the driver
2722 * @remain_device_path device path of a child controller
2723 * @recursive true to connect all child controllers
2724 * @return status code
2725 */
2726static efi_status_t EFIAPI efi_connect_controller(
2727 efi_handle_t controller_handle,
2728 efi_handle_t *driver_image_handle,
2729 struct efi_device_path *remain_device_path,
2730 bool recursive)
2731{
2732 efi_status_t r;
2733 efi_status_t ret = EFI_NOT_FOUND;
2734 struct efi_object *efiobj;
2735
2736 EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
2737 remain_device_path, recursive);
2738
2739 efiobj = efi_search_obj(controller_handle);
2740 if (!efiobj) {
2741 ret = EFI_INVALID_PARAMETER;
2742 goto out;
2743 }
2744
2745 r = efi_connect_single_controller(controller_handle,
2746 driver_image_handle,
2747 remain_device_path);
2748 if (r == EFI_SUCCESS)
2749 ret = EFI_SUCCESS;
2750 if (recursive) {
2751 struct efi_handler *handler;
2752 struct efi_open_protocol_info_item *item;
2753
2754 list_for_each_entry(handler, &efiobj->protocols, link) {
2755 list_for_each_entry(item, &handler->open_infos, link) {
2756 if (item->info.attributes &
2757 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
2758 r = EFI_CALL(efi_connect_controller(
2759 item->info.controller_handle,
2760 driver_image_handle,
2761 remain_device_path,
2762 recursive));
2763 if (r == EFI_SUCCESS)
2764 ret = EFI_SUCCESS;
2765 }
2766 }
2767 }
2768 }
2769 /* Check for child controller specified by end node */
2770 if (ret != EFI_SUCCESS && remain_device_path &&
2771 remain_device_path->type == DEVICE_PATH_TYPE_END)
2772 ret = EFI_SUCCESS;
2773out:
2774 return EFI_EXIT(ret);
2775}
2776
Heinrich Schuchardt3f9b0042018-01-11 08:16:04 +01002777/*
2778 * Get all child controllers associated to a driver.
2779 * The allocated buffer has to be freed with free().
2780 *
2781 * @efiobj handle of the controller
2782 * @driver_handle handle of the driver
2783 * @number_of_children number of child controllers
2784 * @child_handle_buffer handles of the the child controllers
2785 */
2786static efi_status_t efi_get_child_controllers(
2787 struct efi_object *efiobj,
2788 efi_handle_t driver_handle,
2789 efi_uintn_t *number_of_children,
2790 efi_handle_t **child_handle_buffer)
2791{
2792 struct efi_handler *handler;
2793 struct efi_open_protocol_info_item *item;
2794 efi_uintn_t count = 0, i;
2795 bool duplicate;
2796
2797 /* Count all child controller associations */
2798 list_for_each_entry(handler, &efiobj->protocols, link) {
2799 list_for_each_entry(item, &handler->open_infos, link) {
2800 if (item->info.agent_handle == driver_handle &&
2801 item->info.attributes &
2802 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
2803 ++count;
2804 }
2805 }
2806 /*
2807 * Create buffer. In case of duplicate child controller assignments
2808 * the buffer will be too large. But that does not harm.
2809 */
2810 *number_of_children = 0;
2811 *child_handle_buffer = calloc(count, sizeof(efi_handle_t));
2812 if (!*child_handle_buffer)
2813 return EFI_OUT_OF_RESOURCES;
2814 /* Copy unique child handles */
2815 list_for_each_entry(handler, &efiobj->protocols, link) {
2816 list_for_each_entry(item, &handler->open_infos, link) {
2817 if (item->info.agent_handle == driver_handle &&
2818 item->info.attributes &
2819 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
2820 /* Check this is a new child controller */
2821 duplicate = false;
2822 for (i = 0; i < *number_of_children; ++i) {
2823 if ((*child_handle_buffer)[i] ==
2824 item->info.controller_handle)
2825 duplicate = true;
2826 }
2827 /* Copy handle to buffer */
2828 if (!duplicate) {
2829 i = (*number_of_children)++;
2830 (*child_handle_buffer)[i] =
2831 item->info.controller_handle;
2832 }
2833 }
2834 }
2835 }
2836 return EFI_SUCCESS;
2837}
2838
2839/*
2840 * Disconnect a controller from a driver.
2841 *
2842 * This function implements the DisconnectController service.
2843 * See the Unified Extensible Firmware Interface (UEFI) specification
2844 * for details.
2845 *
2846 * @controller_handle handle of the controller
2847 * @driver_image_handle handle of the driver
2848 * @child_handle handle of the child to destroy
2849 * @return status code
2850 */
2851static efi_status_t EFIAPI efi_disconnect_controller(
2852 efi_handle_t controller_handle,
2853 efi_handle_t driver_image_handle,
2854 efi_handle_t child_handle)
2855{
2856 struct efi_driver_binding_protocol *binding_protocol;
2857 efi_handle_t *child_handle_buffer = NULL;
2858 size_t number_of_children = 0;
2859 efi_status_t r;
2860 size_t stop_count = 0;
2861 struct efi_object *efiobj;
2862
2863 EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
2864 child_handle);
2865
2866 efiobj = efi_search_obj(controller_handle);
2867 if (!efiobj) {
2868 r = EFI_INVALID_PARAMETER;
2869 goto out;
2870 }
2871
2872 if (child_handle && !efi_search_obj(child_handle)) {
2873 r = EFI_INVALID_PARAMETER;
2874 goto out;
2875 }
2876
2877 /* If no driver handle is supplied, disconnect all drivers */
2878 if (!driver_image_handle) {
2879 r = efi_disconnect_all_drivers(efiobj, NULL, child_handle);
2880 goto out;
2881 }
2882
2883 /* Create list of child handles */
2884 if (child_handle) {
2885 number_of_children = 1;
2886 child_handle_buffer = &child_handle;
2887 } else {
2888 efi_get_child_controllers(efiobj,
2889 driver_image_handle,
2890 &number_of_children,
2891 &child_handle_buffer);
2892 }
2893
2894 /* Get the driver binding protocol */
2895 r = EFI_CALL(efi_open_protocol(driver_image_handle,
2896 &efi_guid_driver_binding_protocol,
2897 (void **)&binding_protocol,
2898 driver_image_handle, NULL,
2899 EFI_OPEN_PROTOCOL_GET_PROTOCOL));
2900 if (r != EFI_SUCCESS)
2901 goto out;
2902 /* Remove the children */
2903 if (number_of_children) {
2904 r = EFI_CALL(binding_protocol->stop(binding_protocol,
2905 controller_handle,
2906 number_of_children,
2907 child_handle_buffer));
2908 if (r == EFI_SUCCESS)
2909 ++stop_count;
2910 }
2911 /* Remove the driver */
2912 if (!child_handle)
2913 r = EFI_CALL(binding_protocol->stop(binding_protocol,
2914 controller_handle,
2915 0, NULL));
2916 if (r == EFI_SUCCESS)
2917 ++stop_count;
2918 EFI_CALL(efi_close_protocol(driver_image_handle,
2919 &efi_guid_driver_binding_protocol,
2920 driver_image_handle, NULL));
2921
2922 if (stop_count)
2923 r = EFI_SUCCESS;
2924 else
2925 r = EFI_NOT_FOUND;
2926out:
2927 if (!child_handle)
2928 free(child_handle_buffer);
2929 return EFI_EXIT(r);
2930}
2931
Alexander Grafbee91162016-03-04 01:09:59 +01002932static const struct efi_boot_services efi_boot_services = {
2933 .hdr = {
2934 .headersize = sizeof(struct efi_table_hdr),
2935 },
2936 .raise_tpl = efi_raise_tpl,
2937 .restore_tpl = efi_restore_tpl,
2938 .allocate_pages = efi_allocate_pages_ext,
2939 .free_pages = efi_free_pages_ext,
2940 .get_memory_map = efi_get_memory_map_ext,
Stefan Brünsead12742016-10-09 22:17:18 +02002941 .allocate_pool = efi_allocate_pool_ext,
Stefan Brüns42417bc2016-10-09 22:17:26 +02002942 .free_pool = efi_free_pool_ext,
xypron.glpk@gmx.de49deb452017-07-18 20:17:20 +02002943 .create_event = efi_create_event_ext,
xypron.glpk@gmx.debfc72462017-07-18 20:17:21 +02002944 .set_timer = efi_set_timer_ext,
Alexander Grafbee91162016-03-04 01:09:59 +01002945 .wait_for_event = efi_wait_for_event,
xypron.glpk@gmx.dec6841592017-07-18 20:17:18 +02002946 .signal_event = efi_signal_event_ext,
Alexander Grafbee91162016-03-04 01:09:59 +01002947 .close_event = efi_close_event,
2948 .check_event = efi_check_event,
Heinrich Schuchardt1760ef52017-11-06 21:17:44 +01002949 .install_protocol_interface = efi_install_protocol_interface,
Alexander Grafbee91162016-03-04 01:09:59 +01002950 .reinstall_protocol_interface = efi_reinstall_protocol_interface,
Heinrich Schuchardtcd534082017-11-06 21:17:45 +01002951 .uninstall_protocol_interface = efi_uninstall_protocol_interface,
Alexander Grafbee91162016-03-04 01:09:59 +01002952 .handle_protocol = efi_handle_protocol,
2953 .reserved = NULL,
2954 .register_protocol_notify = efi_register_protocol_notify,
xypron.glpk@gmx.de26329582017-07-11 22:06:21 +02002955 .locate_handle = efi_locate_handle_ext,
Alexander Grafbee91162016-03-04 01:09:59 +01002956 .locate_device_path = efi_locate_device_path,
Alexander Graf488bf122016-08-19 01:23:24 +02002957 .install_configuration_table = efi_install_configuration_table_ext,
Alexander Grafbee91162016-03-04 01:09:59 +01002958 .load_image = efi_load_image,
2959 .start_image = efi_start_image,
Alexander Grafa86aeaf2016-05-20 23:28:23 +02002960 .exit = efi_exit,
Alexander Grafbee91162016-03-04 01:09:59 +01002961 .unload_image = efi_unload_image,
2962 .exit_boot_services = efi_exit_boot_services,
2963 .get_next_monotonic_count = efi_get_next_monotonic_count,
2964 .stall = efi_stall,
2965 .set_watchdog_timer = efi_set_watchdog_timer,
2966 .connect_controller = efi_connect_controller,
2967 .disconnect_controller = efi_disconnect_controller,
2968 .open_protocol = efi_open_protocol,
2969 .close_protocol = efi_close_protocol,
2970 .open_protocol_information = efi_open_protocol_information,
2971 .protocols_per_handle = efi_protocols_per_handle,
2972 .locate_handle_buffer = efi_locate_handle_buffer,
2973 .locate_protocol = efi_locate_protocol,
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01002974 .install_multiple_protocol_interfaces =
2975 efi_install_multiple_protocol_interfaces,
2976 .uninstall_multiple_protocol_interfaces =
2977 efi_uninstall_multiple_protocol_interfaces,
Alexander Grafbee91162016-03-04 01:09:59 +01002978 .calculate_crc32 = efi_calculate_crc32,
2979 .copy_mem = efi_copy_mem,
2980 .set_mem = efi_set_mem,
Heinrich Schuchardt9f0930e2018-02-04 23:05:13 +01002981 .create_event_ex = efi_create_event_ex,
Alexander Grafbee91162016-03-04 01:09:59 +01002982};
2983
Heinrich Schuchardt05b6f562017-12-11 20:10:20 +01002984static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
Alexander Grafbee91162016-03-04 01:09:59 +01002985
Alexander Graf3c63db92016-10-14 13:45:30 +02002986struct efi_system_table __efi_runtime_data systab = {
Alexander Grafbee91162016-03-04 01:09:59 +01002987 .hdr = {
2988 .signature = EFI_SYSTEM_TABLE_SIGNATURE,
Heinrich Schuchardtf19a95a2018-02-05 18:04:21 +01002989 .revision = 2 << 16 | 70, /* 2.7 */
Alexander Grafbee91162016-03-04 01:09:59 +01002990 .headersize = sizeof(struct efi_table_hdr),
2991 },
2992 .fw_vendor = (long)firmware_vendor,
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01002993 .con_in = (void *)&efi_con_in,
2994 .con_out = (void *)&efi_con_out,
2995 .std_err = (void *)&efi_con_out,
2996 .runtime = (void *)&efi_runtime_services,
2997 .boottime = (void *)&efi_boot_services,
Alexander Grafbee91162016-03-04 01:09:59 +01002998 .nr_tables = 0,
Heinrich Schuchardtab9efa92018-02-18 15:17:49 +01002999 .tables = (void *)efi_conf_table,
Alexander Grafbee91162016-03-04 01:09:59 +01003000};