1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+ 2bee91169SAlexander Graf /* 3bee91169SAlexander Graf * EFI application boot time services 4bee91169SAlexander Graf * 5bee91169SAlexander Graf * Copyright (c) 2016 Alexander Graf 6bee91169SAlexander Graf */ 7bee91169SAlexander Graf 8bee91169SAlexander Graf #include <common.h> 97d963323SHeinrich Schuchardt #include <div64.h> 10bee91169SAlexander Graf #include <efi_loader.h> 11ad644e7cSRob Clark #include <environment.h> 12bee91169SAlexander Graf #include <malloc.h> 13b08c8c48SMasahiro Yamada #include <linux/libfdt_env.h> 14bee91169SAlexander Graf #include <u-boot/crc.h> 15bee91169SAlexander Graf #include <bootm.h> 16bee91169SAlexander Graf #include <watchdog.h> 17bee91169SAlexander Graf 18bee91169SAlexander Graf DECLARE_GLOBAL_DATA_PTR; 19bee91169SAlexander Graf 2032f4b2f8SHeinrich Schuchardt /* Task priority level */ 21152cade3SHeinrich Schuchardt static efi_uintn_t efi_tpl = TPL_APPLICATION; 2232f4b2f8SHeinrich Schuchardt 23bee91169SAlexander Graf /* This list contains all the EFI objects our payload has access to */ 24bee91169SAlexander Graf LIST_HEAD(efi_obj_list); 25bee91169SAlexander Graf 2643bce442SHeinrich Schuchardt /* List of all events */ 27b095f3c8SHeinrich Schuchardt LIST_HEAD(efi_events); 2843bce442SHeinrich Schuchardt 29f31239acSAlexander Graf /* 30f31239acSAlexander Graf * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) 31f31239acSAlexander Graf * we need to do trickery with caches. Since we don't want to break the EFI 32f31239acSAlexander Graf * aware boot path, only apply hacks when loading exiting directly (breaking 33f31239acSAlexander Graf * direct Linux EFI booting along the way - oh well). 34f31239acSAlexander Graf */ 35f31239acSAlexander Graf static bool efi_is_direct_boot = true; 36f31239acSAlexander Graf 3765e4c0b1SSimon Glass #ifdef CONFIG_ARM 38bee91169SAlexander Graf /* 39bee91169SAlexander Graf * The "gd" pointer lives in a register on ARM and AArch64 that we declare 40bee91169SAlexander Graf * fixed when compiling U-Boot. However, the payload does not know about that 41bee91169SAlexander Graf * restriction so we need to manually swap its and our view of that register on 42bee91169SAlexander Graf * EFI callback entry/exit. 43bee91169SAlexander Graf */ 44bee91169SAlexander Graf static volatile void *efi_gd, *app_gd; 4565e4c0b1SSimon Glass #endif 46bee91169SAlexander Graf 47c160d2f5SRob Clark static int entry_count; 48af65db85SRob Clark static int nesting_level; 49bc4f9133SHeinrich Schuchardt /* GUID of the device tree table */ 50bc4f9133SHeinrich Schuchardt const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; 51f0959dbeSHeinrich Schuchardt /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ 52f0959dbeSHeinrich Schuchardt const efi_guid_t efi_guid_driver_binding_protocol = 53f0959dbeSHeinrich Schuchardt EFI_DRIVER_BINDING_PROTOCOL_GUID; 54c160d2f5SRob Clark 55a3a28f5fSHeinrich Schuchardt /* event group ExitBootServices() invoked */ 56a3a28f5fSHeinrich Schuchardt const efi_guid_t efi_guid_event_group_exit_boot_services = 57a3a28f5fSHeinrich Schuchardt EFI_EVENT_GROUP_EXIT_BOOT_SERVICES; 58a3a28f5fSHeinrich Schuchardt /* event group SetVirtualAddressMap() invoked */ 59a3a28f5fSHeinrich Schuchardt const efi_guid_t efi_guid_event_group_virtual_address_change = 60a3a28f5fSHeinrich Schuchardt EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE; 61a3a28f5fSHeinrich Schuchardt /* event group memory map changed */ 62a3a28f5fSHeinrich Schuchardt const efi_guid_t efi_guid_event_group_memory_map_change = 63a3a28f5fSHeinrich Schuchardt EFI_EVENT_GROUP_MEMORY_MAP_CHANGE; 64a3a28f5fSHeinrich Schuchardt /* event group boot manager about to boot */ 65a3a28f5fSHeinrich Schuchardt const efi_guid_t efi_guid_event_group_ready_to_boot = 66a3a28f5fSHeinrich Schuchardt EFI_EVENT_GROUP_READY_TO_BOOT; 67a3a28f5fSHeinrich Schuchardt /* event group ResetSystem() invoked (before ExitBootServices) */ 68a3a28f5fSHeinrich Schuchardt const efi_guid_t efi_guid_event_group_reset_system = 69a3a28f5fSHeinrich Schuchardt EFI_EVENT_GROUP_RESET_SYSTEM; 70a3a28f5fSHeinrich Schuchardt 712074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_disconnect_controller( 722074f700SHeinrich Schuchardt efi_handle_t controller_handle, 732074f700SHeinrich Schuchardt efi_handle_t driver_image_handle, 742074f700SHeinrich Schuchardt efi_handle_t child_handle); 753f9b0042SHeinrich Schuchardt 76c160d2f5SRob Clark /* Called on every callback entry */ 77c160d2f5SRob Clark int __efi_entry_check(void) 78c160d2f5SRob Clark { 79c160d2f5SRob Clark int ret = entry_count++ == 0; 80c160d2f5SRob Clark #ifdef CONFIG_ARM 81c160d2f5SRob Clark assert(efi_gd); 82c160d2f5SRob Clark app_gd = gd; 83c160d2f5SRob Clark gd = efi_gd; 84c160d2f5SRob Clark #endif 85c160d2f5SRob Clark return ret; 86c160d2f5SRob Clark } 87c160d2f5SRob Clark 88c160d2f5SRob Clark /* Called on every callback exit */ 89c160d2f5SRob Clark int __efi_exit_check(void) 90c160d2f5SRob Clark { 91c160d2f5SRob Clark int ret = --entry_count == 0; 92c160d2f5SRob Clark #ifdef CONFIG_ARM 93c160d2f5SRob Clark gd = app_gd; 94c160d2f5SRob Clark #endif 95c160d2f5SRob Clark return ret; 96c160d2f5SRob Clark } 97c160d2f5SRob Clark 98bee91169SAlexander Graf /* Called from do_bootefi_exec() */ 99bee91169SAlexander Graf void efi_save_gd(void) 100bee91169SAlexander Graf { 10165e4c0b1SSimon Glass #ifdef CONFIG_ARM 102bee91169SAlexander Graf efi_gd = gd; 10365e4c0b1SSimon Glass #endif 104bee91169SAlexander Graf } 105bee91169SAlexander Graf 106c160d2f5SRob Clark /* 10778a88f79SMario Six * Special case handler for error/abort that just forces things back to u-boot 108b72aaa87SHeinrich Schuchardt * world so we can dump out an abort message, without any care about returning 109b72aaa87SHeinrich Schuchardt * back to UEFI world. 110c160d2f5SRob Clark */ 111bee91169SAlexander Graf void efi_restore_gd(void) 112bee91169SAlexander Graf { 11365e4c0b1SSimon Glass #ifdef CONFIG_ARM 114bee91169SAlexander Graf /* Only restore if we're already in EFI context */ 115bee91169SAlexander Graf if (!efi_gd) 116bee91169SAlexander Graf return; 117bee91169SAlexander Graf gd = efi_gd; 11865e4c0b1SSimon Glass #endif 119bee91169SAlexander Graf } 120bee91169SAlexander Graf 1216b03cd10SHeinrich Schuchardt /** 12278a88f79SMario Six * indent_string() - returns a string for indenting with two spaces per level 12378a88f79SMario Six * @level: indent level 124c8df80c5SHeinrich Schuchardt * 1256b03cd10SHeinrich Schuchardt * A maximum of ten indent levels is supported. Higher indent levels will be 1266b03cd10SHeinrich Schuchardt * truncated. 1276b03cd10SHeinrich Schuchardt * 12878a88f79SMario Six * Return: A string for indenting with two spaces per level is 1296b03cd10SHeinrich Schuchardt * returned. 130af65db85SRob Clark */ 131af65db85SRob Clark static const char *indent_string(int level) 132af65db85SRob Clark { 133af65db85SRob Clark const char *indent = " "; 134af65db85SRob Clark const int max = strlen(indent); 135ab9efa97SHeinrich Schuchardt 136af65db85SRob Clark level = min(max, level * 2); 137af65db85SRob Clark return &indent[max - level]; 138af65db85SRob Clark } 139af65db85SRob Clark 140ae0bd3a9SHeinrich Schuchardt const char *__efi_nesting(void) 141ae0bd3a9SHeinrich Schuchardt { 142ae0bd3a9SHeinrich Schuchardt return indent_string(nesting_level); 143ae0bd3a9SHeinrich Schuchardt } 144ae0bd3a9SHeinrich Schuchardt 145af65db85SRob Clark const char *__efi_nesting_inc(void) 146af65db85SRob Clark { 147af65db85SRob Clark return indent_string(nesting_level++); 148af65db85SRob Clark } 149af65db85SRob Clark 150af65db85SRob Clark const char *__efi_nesting_dec(void) 151af65db85SRob Clark { 152af65db85SRob Clark return indent_string(--nesting_level); 153af65db85SRob Clark } 154af65db85SRob Clark 1556b03cd10SHeinrich Schuchardt /** 15678a88f79SMario Six * efi_queue_event() - queue an EFI event 15778a88f79SMario Six * @event: event to signal 15878a88f79SMario Six * @check_tpl: check the TPL level 159332468f7SHeinrich Schuchardt * 160332468f7SHeinrich Schuchardt * This function queues the notification function of the event for future 161332468f7SHeinrich Schuchardt * execution. 162332468f7SHeinrich Schuchardt * 16378a88f79SMario Six * The notification function is called if the task priority level of the event 16478a88f79SMario Six * is higher than the current task priority level. 165332468f7SHeinrich Schuchardt * 166332468f7SHeinrich Schuchardt * For the SignalEvent service see efi_signal_event_ext. 167332468f7SHeinrich Schuchardt * 168332468f7SHeinrich Schuchardt */ 169b095f3c8SHeinrich Schuchardt static void efi_queue_event(struct efi_event *event, bool check_tpl) 170c6841592Sxypron.glpk@gmx.de { 171ca62a4f5SHeinrich Schuchardt if (event->notify_function) { 172e190e897SHeinrich Schuchardt event->is_queued = true; 17332f4b2f8SHeinrich Schuchardt /* Check TPL */ 1749bc9664dSHeinrich Schuchardt if (check_tpl && efi_tpl >= event->notify_tpl) 17532f4b2f8SHeinrich Schuchardt return; 176ea630ce9SHeinrich Schuchardt EFI_CALL_VOID(event->notify_function(event, 177ea630ce9SHeinrich Schuchardt event->notify_context)); 178c6841592Sxypron.glpk@gmx.de } 179e190e897SHeinrich Schuchardt event->is_queued = false; 180c6841592Sxypron.glpk@gmx.de } 181c6841592Sxypron.glpk@gmx.de 1826b03cd10SHeinrich Schuchardt /** 18321b3edfcSHeinrich Schuchardt * is_valid_tpl() - check if the task priority level is valid 18421b3edfcSHeinrich Schuchardt * 18521b3edfcSHeinrich Schuchardt * @tpl: TPL level to check 186b72aaa87SHeinrich Schuchardt * Return: status code 18721b3edfcSHeinrich Schuchardt */ 18821b3edfcSHeinrich Schuchardt efi_status_t is_valid_tpl(efi_uintn_t tpl) 18921b3edfcSHeinrich Schuchardt { 19021b3edfcSHeinrich Schuchardt switch (tpl) { 19121b3edfcSHeinrich Schuchardt case TPL_APPLICATION: 19221b3edfcSHeinrich Schuchardt case TPL_CALLBACK: 19321b3edfcSHeinrich Schuchardt case TPL_NOTIFY: 19421b3edfcSHeinrich Schuchardt case TPL_HIGH_LEVEL: 19521b3edfcSHeinrich Schuchardt return EFI_SUCCESS; 19621b3edfcSHeinrich Schuchardt default: 19721b3edfcSHeinrich Schuchardt return EFI_INVALID_PARAMETER; 19821b3edfcSHeinrich Schuchardt } 19921b3edfcSHeinrich Schuchardt } 20021b3edfcSHeinrich Schuchardt 20121b3edfcSHeinrich Schuchardt /** 20278a88f79SMario Six * efi_signal_event() - signal an EFI event 20378a88f79SMario Six * @event: event to signal 20478a88f79SMario Six * @check_tpl: check the TPL level 205b095f3c8SHeinrich Schuchardt * 20678a88f79SMario Six * This function signals an event. If the event belongs to an event group all 20778a88f79SMario Six * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL 208b095f3c8SHeinrich Schuchardt * their notification function is queued. 209b095f3c8SHeinrich Schuchardt * 210b095f3c8SHeinrich Schuchardt * For the SignalEvent service see efi_signal_event_ext. 211b095f3c8SHeinrich Schuchardt */ 212b095f3c8SHeinrich Schuchardt void efi_signal_event(struct efi_event *event, bool check_tpl) 213b095f3c8SHeinrich Schuchardt { 214b095f3c8SHeinrich Schuchardt if (event->group) { 215b095f3c8SHeinrich Schuchardt struct efi_event *evt; 216b095f3c8SHeinrich Schuchardt 217b095f3c8SHeinrich Schuchardt /* 218b095f3c8SHeinrich Schuchardt * The signaled state has to set before executing any 219b095f3c8SHeinrich Schuchardt * notification function 220b095f3c8SHeinrich Schuchardt */ 221b095f3c8SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 222b095f3c8SHeinrich Schuchardt if (!evt->group || guidcmp(evt->group, event->group)) 223b095f3c8SHeinrich Schuchardt continue; 224b095f3c8SHeinrich Schuchardt if (evt->is_signaled) 225b095f3c8SHeinrich Schuchardt continue; 226b095f3c8SHeinrich Schuchardt evt->is_signaled = true; 227b095f3c8SHeinrich Schuchardt if (evt->type & EVT_NOTIFY_SIGNAL && 228b095f3c8SHeinrich Schuchardt evt->notify_function) 229b095f3c8SHeinrich Schuchardt evt->is_queued = true; 230b095f3c8SHeinrich Schuchardt } 231b095f3c8SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 232b095f3c8SHeinrich Schuchardt if (!evt->group || guidcmp(evt->group, event->group)) 233b095f3c8SHeinrich Schuchardt continue; 234b095f3c8SHeinrich Schuchardt if (evt->is_queued) 235b095f3c8SHeinrich Schuchardt efi_queue_event(evt, check_tpl); 236b095f3c8SHeinrich Schuchardt } 237b095f3c8SHeinrich Schuchardt } else if (!event->is_signaled) { 238b095f3c8SHeinrich Schuchardt event->is_signaled = true; 239b095f3c8SHeinrich Schuchardt if (event->type & EVT_NOTIFY_SIGNAL) 240b095f3c8SHeinrich Schuchardt efi_queue_event(event, check_tpl); 241b095f3c8SHeinrich Schuchardt } 242b095f3c8SHeinrich Schuchardt } 243b095f3c8SHeinrich Schuchardt 2446b03cd10SHeinrich Schuchardt /** 24578a88f79SMario Six * efi_raise_tpl() - raise the task priority level 24678a88f79SMario Six * @new_tpl: new value of the task priority level 247332468f7SHeinrich Schuchardt * 248332468f7SHeinrich Schuchardt * This function implements the RaiseTpl service. 249332468f7SHeinrich Schuchardt * 25078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 25178a88f79SMario Six * details. 25278a88f79SMario Six * 25378a88f79SMario Six * Return: old value of the task priority level 254332468f7SHeinrich Schuchardt */ 255152cade3SHeinrich Schuchardt static unsigned long EFIAPI efi_raise_tpl(efi_uintn_t new_tpl) 256bee91169SAlexander Graf { 257152cade3SHeinrich Schuchardt efi_uintn_t old_tpl = efi_tpl; 25832f4b2f8SHeinrich Schuchardt 259503f2695Sxypron.glpk@gmx.de EFI_ENTRY("0x%zx", new_tpl); 26032f4b2f8SHeinrich Schuchardt 26132f4b2f8SHeinrich Schuchardt if (new_tpl < efi_tpl) 26232f4b2f8SHeinrich Schuchardt debug("WARNING: new_tpl < current_tpl in %s\n", __func__); 26332f4b2f8SHeinrich Schuchardt efi_tpl = new_tpl; 26432f4b2f8SHeinrich Schuchardt if (efi_tpl > TPL_HIGH_LEVEL) 26532f4b2f8SHeinrich Schuchardt efi_tpl = TPL_HIGH_LEVEL; 26632f4b2f8SHeinrich Schuchardt 26732f4b2f8SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 26832f4b2f8SHeinrich Schuchardt return old_tpl; 269bee91169SAlexander Graf } 270bee91169SAlexander Graf 2716b03cd10SHeinrich Schuchardt /** 27278a88f79SMario Six * efi_restore_tpl() - lower the task priority level 27378a88f79SMario Six * @old_tpl: value of the task priority level to be restored 274332468f7SHeinrich Schuchardt * 275332468f7SHeinrich Schuchardt * This function implements the RestoreTpl service. 276332468f7SHeinrich Schuchardt * 27778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 27878a88f79SMario Six * details. 279332468f7SHeinrich Schuchardt */ 280152cade3SHeinrich Schuchardt static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl) 281bee91169SAlexander Graf { 282503f2695Sxypron.glpk@gmx.de EFI_ENTRY("0x%zx", old_tpl); 28332f4b2f8SHeinrich Schuchardt 28432f4b2f8SHeinrich Schuchardt if (old_tpl > efi_tpl) 28532f4b2f8SHeinrich Schuchardt debug("WARNING: old_tpl > current_tpl in %s\n", __func__); 28632f4b2f8SHeinrich Schuchardt efi_tpl = old_tpl; 28732f4b2f8SHeinrich Schuchardt if (efi_tpl > TPL_HIGH_LEVEL) 28832f4b2f8SHeinrich Schuchardt efi_tpl = TPL_HIGH_LEVEL; 28932f4b2f8SHeinrich Schuchardt 2900f7fcc72SHeinrich Schuchardt /* 2910f7fcc72SHeinrich Schuchardt * Lowering the TPL may have made queued events eligible for execution. 2920f7fcc72SHeinrich Schuchardt */ 2930f7fcc72SHeinrich Schuchardt efi_timer_check(); 2940f7fcc72SHeinrich Schuchardt 29532f4b2f8SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 296bee91169SAlexander Graf } 297bee91169SAlexander Graf 2986b03cd10SHeinrich Schuchardt /** 29978a88f79SMario Six * efi_allocate_pages_ext() - allocate memory pages 3006b03cd10SHeinrich Schuchardt * @type: type of allocation to be performed 3016b03cd10SHeinrich Schuchardt * @memory_type: usage type of the allocated memory 3026b03cd10SHeinrich Schuchardt * @pages: number of pages to be allocated 3036b03cd10SHeinrich Schuchardt * @memory: allocated memory 30478a88f79SMario Six * 30578a88f79SMario Six * This function implements the AllocatePages service. 30678a88f79SMario Six * 30778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 30878a88f79SMario Six * details. 30978a88f79SMario Six * 31078a88f79SMario Six * Return: status code 311332468f7SHeinrich Schuchardt */ 3126e0bf8d8SMasahiro Yamada static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, 313f5a2a938SHeinrich Schuchardt efi_uintn_t pages, 314bee91169SAlexander Graf uint64_t *memory) 315bee91169SAlexander Graf { 316bee91169SAlexander Graf efi_status_t r; 317bee91169SAlexander Graf 318f5a2a938SHeinrich Schuchardt EFI_ENTRY("%d, %d, 0x%zx, %p", type, memory_type, pages, memory); 319bee91169SAlexander Graf r = efi_allocate_pages(type, memory_type, pages, memory); 320bee91169SAlexander Graf return EFI_EXIT(r); 321bee91169SAlexander Graf } 322bee91169SAlexander Graf 3236b03cd10SHeinrich Schuchardt /** 32478a88f79SMario Six * efi_free_pages_ext() - Free memory pages. 3256b03cd10SHeinrich Schuchardt * @memory: start of the memory area to be freed 3266b03cd10SHeinrich Schuchardt * @pages: number of pages to be freed 32778a88f79SMario Six * 32878a88f79SMario Six * This function implements the FreePages service. 32978a88f79SMario Six * 33078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 33178a88f79SMario Six * details. 33278a88f79SMario Six * 33378a88f79SMario Six * Return: status code 334332468f7SHeinrich Schuchardt */ 3356e0bf8d8SMasahiro Yamada static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, 336f5a2a938SHeinrich Schuchardt efi_uintn_t pages) 337bee91169SAlexander Graf { 338bee91169SAlexander Graf efi_status_t r; 339bee91169SAlexander Graf 340dee37fc9SMasahiro Yamada EFI_ENTRY("%llx, 0x%zx", memory, pages); 341bee91169SAlexander Graf r = efi_free_pages(memory, pages); 342bee91169SAlexander Graf return EFI_EXIT(r); 343bee91169SAlexander Graf } 344bee91169SAlexander Graf 3456b03cd10SHeinrich Schuchardt /** 34678a88f79SMario Six * efi_get_memory_map_ext() - get map describing memory usage 3476b03cd10SHeinrich Schuchardt * @memory_map_size: on entry the size, in bytes, of the memory map buffer, 348332468f7SHeinrich Schuchardt * on exit the size of the copied memory map 3496b03cd10SHeinrich Schuchardt * @memory_map: buffer to which the memory map is written 3506b03cd10SHeinrich Schuchardt * @map_key: key for the memory map 3516b03cd10SHeinrich Schuchardt * @descriptor_size: size of an individual memory descriptor 3526b03cd10SHeinrich Schuchardt * @descriptor_version: version number of the memory descriptor structure 35378a88f79SMario Six * 35478a88f79SMario Six * This function implements the GetMemoryMap service. 35578a88f79SMario Six * 35678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 35778a88f79SMario Six * details. 35878a88f79SMario Six * 35978a88f79SMario Six * Return: status code 360332468f7SHeinrich Schuchardt */ 3616e0bf8d8SMasahiro Yamada static efi_status_t EFIAPI efi_get_memory_map_ext( 362f5a2a938SHeinrich Schuchardt efi_uintn_t *memory_map_size, 363bee91169SAlexander Graf struct efi_mem_desc *memory_map, 364f5a2a938SHeinrich Schuchardt efi_uintn_t *map_key, 365f5a2a938SHeinrich Schuchardt efi_uintn_t *descriptor_size, 366bee91169SAlexander Graf uint32_t *descriptor_version) 367bee91169SAlexander Graf { 368bee91169SAlexander Graf efi_status_t r; 369bee91169SAlexander Graf 370bee91169SAlexander Graf EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map, 371bee91169SAlexander Graf map_key, descriptor_size, descriptor_version); 372bee91169SAlexander Graf r = efi_get_memory_map(memory_map_size, memory_map, map_key, 373bee91169SAlexander Graf descriptor_size, descriptor_version); 374bee91169SAlexander Graf return EFI_EXIT(r); 375bee91169SAlexander Graf } 376bee91169SAlexander Graf 3776b03cd10SHeinrich Schuchardt /** 37878a88f79SMario Six * efi_allocate_pool_ext() - allocate memory from pool 3796b03cd10SHeinrich Schuchardt * @pool_type: type of the pool from which memory is to be allocated 3806b03cd10SHeinrich Schuchardt * @size: number of bytes to be allocated 3816b03cd10SHeinrich Schuchardt * @buffer: allocated memory 38278a88f79SMario Six * 38378a88f79SMario Six * This function implements the AllocatePool service. 38478a88f79SMario Six * 38578a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 38678a88f79SMario Six * details. 38778a88f79SMario Six * 38878a88f79SMario Six * Return: status code 389332468f7SHeinrich Schuchardt */ 390ead1274bSStefan Brüns static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, 391f5a2a938SHeinrich Schuchardt efi_uintn_t size, 392bee91169SAlexander Graf void **buffer) 393bee91169SAlexander Graf { 3941cd29f0aSAlexander Graf efi_status_t r; 3951cd29f0aSAlexander Graf 396f5a2a938SHeinrich Schuchardt EFI_ENTRY("%d, %zd, %p", pool_type, size, buffer); 397ead1274bSStefan Brüns r = efi_allocate_pool(pool_type, size, buffer); 3981cd29f0aSAlexander Graf return EFI_EXIT(r); 399bee91169SAlexander Graf } 400bee91169SAlexander Graf 4016b03cd10SHeinrich Schuchardt /** 40278a88f79SMario Six * efi_free_pool_ext() - free memory from pool 40378a88f79SMario Six * @buffer: start of memory to be freed 404332468f7SHeinrich Schuchardt * 405332468f7SHeinrich Schuchardt * This function implements the FreePool service. 406332468f7SHeinrich Schuchardt * 40778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 40878a88f79SMario Six * details. 40978a88f79SMario Six * 41078a88f79SMario Six * Return: status code 411332468f7SHeinrich Schuchardt */ 41242417bc8SStefan Brüns static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) 413bee91169SAlexander Graf { 4141cd29f0aSAlexander Graf efi_status_t r; 4151cd29f0aSAlexander Graf 4161cd29f0aSAlexander Graf EFI_ENTRY("%p", buffer); 41742417bc8SStefan Brüns r = efi_free_pool(buffer); 4181cd29f0aSAlexander Graf return EFI_EXIT(r); 419bee91169SAlexander Graf } 420bee91169SAlexander Graf 4216b03cd10SHeinrich Schuchardt /** 42278a88f79SMario Six * efi_add_handle() - add a new object to the object list 4236b03cd10SHeinrich Schuchardt * @obj: object to be added 42478a88f79SMario Six * 42578a88f79SMario Six * The protocols list is initialized. The object handle is set. 42644549d62SHeinrich Schuchardt */ 427fae0118eSHeinrich Schuchardt void efi_add_handle(efi_handle_t handle) 42844549d62SHeinrich Schuchardt { 429fae0118eSHeinrich Schuchardt if (!handle) 43044549d62SHeinrich Schuchardt return; 431fae0118eSHeinrich Schuchardt INIT_LIST_HEAD(&handle->protocols); 432fae0118eSHeinrich Schuchardt list_add_tail(&handle->link, &efi_obj_list); 43344549d62SHeinrich Schuchardt } 43444549d62SHeinrich Schuchardt 4356b03cd10SHeinrich Schuchardt /** 43678a88f79SMario Six * efi_create_handle() - create handle 4376b03cd10SHeinrich Schuchardt * @handle: new handle 43878a88f79SMario Six * 43978a88f79SMario Six * Return: status code 4402edab5e2SHeinrich Schuchardt */ 4412074f700SHeinrich Schuchardt efi_status_t efi_create_handle(efi_handle_t *handle) 4423cc6e3feSHeinrich Schuchardt { 4433cc6e3feSHeinrich Schuchardt struct efi_object *obj; 4443cc6e3feSHeinrich Schuchardt 445d29e7824SHeinrich Schuchardt obj = calloc(1, sizeof(struct efi_object)); 446d29e7824SHeinrich Schuchardt if (!obj) 447d29e7824SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 448d29e7824SHeinrich Schuchardt 44944549d62SHeinrich Schuchardt efi_add_handle(obj); 450fae0118eSHeinrich Schuchardt *handle = obj; 451d29e7824SHeinrich Schuchardt 452d29e7824SHeinrich Schuchardt return EFI_SUCCESS; 4533cc6e3feSHeinrich Schuchardt } 4543cc6e3feSHeinrich Schuchardt 4556b03cd10SHeinrich Schuchardt /** 45678a88f79SMario Six * efi_search_protocol() - find a protocol on a handle. 4576b03cd10SHeinrich Schuchardt * @handle: handle 4586b03cd10SHeinrich Schuchardt * @protocol_guid: GUID of the protocol 4596b03cd10SHeinrich Schuchardt * @handler: reference to the protocol 46078a88f79SMario Six * 46178a88f79SMario Six * Return: status code 462678e03a0SHeinrich Schuchardt */ 4632074f700SHeinrich Schuchardt efi_status_t efi_search_protocol(const efi_handle_t handle, 464678e03a0SHeinrich Schuchardt const efi_guid_t *protocol_guid, 465678e03a0SHeinrich Schuchardt struct efi_handler **handler) 466678e03a0SHeinrich Schuchardt { 467678e03a0SHeinrich Schuchardt struct efi_object *efiobj; 468678e03a0SHeinrich Schuchardt struct list_head *lhandle; 469678e03a0SHeinrich Schuchardt 470678e03a0SHeinrich Schuchardt if (!handle || !protocol_guid) 471678e03a0SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 472678e03a0SHeinrich Schuchardt efiobj = efi_search_obj(handle); 473678e03a0SHeinrich Schuchardt if (!efiobj) 474678e03a0SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 475678e03a0SHeinrich Schuchardt list_for_each(lhandle, &efiobj->protocols) { 476678e03a0SHeinrich Schuchardt struct efi_handler *protocol; 477678e03a0SHeinrich Schuchardt 478678e03a0SHeinrich Schuchardt protocol = list_entry(lhandle, struct efi_handler, link); 479678e03a0SHeinrich Schuchardt if (!guidcmp(protocol->guid, protocol_guid)) { 480678e03a0SHeinrich Schuchardt if (handler) 481678e03a0SHeinrich Schuchardt *handler = protocol; 482678e03a0SHeinrich Schuchardt return EFI_SUCCESS; 483678e03a0SHeinrich Schuchardt } 484678e03a0SHeinrich Schuchardt } 485678e03a0SHeinrich Schuchardt return EFI_NOT_FOUND; 486678e03a0SHeinrich Schuchardt } 487678e03a0SHeinrich Schuchardt 4886b03cd10SHeinrich Schuchardt /** 48978a88f79SMario Six * efi_remove_protocol() - delete protocol from a handle 4906b03cd10SHeinrich Schuchardt * @handle: handle from which the protocol shall be deleted 4916b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to be deleted 4926b03cd10SHeinrich Schuchardt * @protocol_interface: interface of the protocol implementation 49378a88f79SMario Six * 49478a88f79SMario Six * Return: status code 495678e03a0SHeinrich Schuchardt */ 4962074f700SHeinrich Schuchardt efi_status_t efi_remove_protocol(const efi_handle_t handle, 4972074f700SHeinrich Schuchardt const efi_guid_t *protocol, 498678e03a0SHeinrich Schuchardt void *protocol_interface) 499678e03a0SHeinrich Schuchardt { 500678e03a0SHeinrich Schuchardt struct efi_handler *handler; 501678e03a0SHeinrich Schuchardt efi_status_t ret; 502678e03a0SHeinrich Schuchardt 503678e03a0SHeinrich Schuchardt ret = efi_search_protocol(handle, protocol, &handler); 504678e03a0SHeinrich Schuchardt if (ret != EFI_SUCCESS) 505678e03a0SHeinrich Schuchardt return ret; 506678e03a0SHeinrich Schuchardt if (guidcmp(handler->guid, protocol)) 507678e03a0SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 5081f470e17SHeinrich Schuchardt if (handler->protocol_interface != protocol_interface) 5091f470e17SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 510678e03a0SHeinrich Schuchardt list_del(&handler->link); 511678e03a0SHeinrich Schuchardt free(handler); 512678e03a0SHeinrich Schuchardt return EFI_SUCCESS; 513678e03a0SHeinrich Schuchardt } 514678e03a0SHeinrich Schuchardt 5156b03cd10SHeinrich Schuchardt /** 51678a88f79SMario Six * efi_remove_all_protocols() - delete all protocols from a handle 5176b03cd10SHeinrich Schuchardt * @handle: handle from which the protocols shall be deleted 51878a88f79SMario Six * 51978a88f79SMario Six * Return: status code 520678e03a0SHeinrich Schuchardt */ 5212074f700SHeinrich Schuchardt efi_status_t efi_remove_all_protocols(const efi_handle_t handle) 522678e03a0SHeinrich Schuchardt { 523678e03a0SHeinrich Schuchardt struct efi_object *efiobj; 52432e6fed6SHeinrich Schuchardt struct efi_handler *protocol; 52532e6fed6SHeinrich Schuchardt struct efi_handler *pos; 526678e03a0SHeinrich Schuchardt 527678e03a0SHeinrich Schuchardt efiobj = efi_search_obj(handle); 528678e03a0SHeinrich Schuchardt if (!efiobj) 529678e03a0SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 53032e6fed6SHeinrich Schuchardt list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) { 531678e03a0SHeinrich Schuchardt efi_status_t ret; 532678e03a0SHeinrich Schuchardt 533678e03a0SHeinrich Schuchardt ret = efi_remove_protocol(handle, protocol->guid, 534678e03a0SHeinrich Schuchardt protocol->protocol_interface); 535678e03a0SHeinrich Schuchardt if (ret != EFI_SUCCESS) 536678e03a0SHeinrich Schuchardt return ret; 537678e03a0SHeinrich Schuchardt } 538678e03a0SHeinrich Schuchardt return EFI_SUCCESS; 539678e03a0SHeinrich Schuchardt } 540678e03a0SHeinrich Schuchardt 5416b03cd10SHeinrich Schuchardt /** 54278a88f79SMario Six * efi_delete_handle() - delete handle 543678e03a0SHeinrich Schuchardt * 5446b03cd10SHeinrich Schuchardt * @obj: handle to delete 545678e03a0SHeinrich Schuchardt */ 546fae0118eSHeinrich Schuchardt void efi_delete_handle(efi_handle_t handle) 547678e03a0SHeinrich Schuchardt { 548fae0118eSHeinrich Schuchardt if (!handle) 549678e03a0SHeinrich Schuchardt return; 550fae0118eSHeinrich Schuchardt efi_remove_all_protocols(handle); 551fae0118eSHeinrich Schuchardt list_del(&handle->link); 552fae0118eSHeinrich Schuchardt free(handle); 553678e03a0SHeinrich Schuchardt } 554678e03a0SHeinrich Schuchardt 5556b03cd10SHeinrich Schuchardt /** 55678a88f79SMario Six * efi_is_event() - check if a pointer is a valid event 5576b03cd10SHeinrich Schuchardt * @event: pointer to check 55878a88f79SMario Six * 55978a88f79SMario Six * Return: status code 560bee91169SAlexander Graf */ 56143bce442SHeinrich Schuchardt static efi_status_t efi_is_event(const struct efi_event *event) 56243bce442SHeinrich Schuchardt { 56343bce442SHeinrich Schuchardt const struct efi_event *evt; 56443bce442SHeinrich Schuchardt 56543bce442SHeinrich Schuchardt if (!event) 56643bce442SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 56743bce442SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 56843bce442SHeinrich Schuchardt if (evt == event) 56943bce442SHeinrich Schuchardt return EFI_SUCCESS; 57043bce442SHeinrich Schuchardt } 57143bce442SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 57243bce442SHeinrich Schuchardt } 573bee91169SAlexander Graf 5746b03cd10SHeinrich Schuchardt /** 57578a88f79SMario Six * efi_create_event() - create an event 5766b03cd10SHeinrich Schuchardt * @type: type of the event to create 5776b03cd10SHeinrich Schuchardt * @notify_tpl: task priority level of the event 5786b03cd10SHeinrich Schuchardt * @notify_function: notification function of the event 5796b03cd10SHeinrich Schuchardt * @notify_context: pointer passed to the notification function 5806b03cd10SHeinrich Schuchardt * @group: event group 5816b03cd10SHeinrich Schuchardt * @event: created event 58278a88f79SMario Six * 58378a88f79SMario Six * This function is used inside U-Boot code to create an event. 58478a88f79SMario Six * 58578a88f79SMario Six * For the API function implementing the CreateEvent service see 58678a88f79SMario Six * efi_create_event_ext. 58778a88f79SMario Six * 58878a88f79SMario Six * Return: status code 589332468f7SHeinrich Schuchardt */ 590152cade3SHeinrich Schuchardt efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, 5912fd945feSxypron.glpk@gmx.de void (EFIAPI *notify_function) ( 5922fd945feSxypron.glpk@gmx.de struct efi_event *event, 593e275458cSSimon Glass void *context), 594b095f3c8SHeinrich Schuchardt void *notify_context, efi_guid_t *group, 595b095f3c8SHeinrich Schuchardt struct efi_event **event) 596bee91169SAlexander Graf { 59743bce442SHeinrich Schuchardt struct efi_event *evt; 598c6841592Sxypron.glpk@gmx.de 599a95343b8SJonathan Gray if (event == NULL) 60049deb455Sxypron.glpk@gmx.de return EFI_INVALID_PARAMETER; 601a95343b8SJonathan Gray 60221b3edfcSHeinrich Schuchardt switch (type) { 60321b3edfcSHeinrich Schuchardt case 0: 60421b3edfcSHeinrich Schuchardt case EVT_TIMER: 60521b3edfcSHeinrich Schuchardt case EVT_NOTIFY_SIGNAL: 60621b3edfcSHeinrich Schuchardt case EVT_TIMER | EVT_NOTIFY_SIGNAL: 60721b3edfcSHeinrich Schuchardt case EVT_NOTIFY_WAIT: 60821b3edfcSHeinrich Schuchardt case EVT_TIMER | EVT_NOTIFY_WAIT: 60921b3edfcSHeinrich Schuchardt case EVT_SIGNAL_EXIT_BOOT_SERVICES: 61021b3edfcSHeinrich Schuchardt case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE: 61121b3edfcSHeinrich Schuchardt break; 61221b3edfcSHeinrich Schuchardt default: 61349deb455Sxypron.glpk@gmx.de return EFI_INVALID_PARAMETER; 61421b3edfcSHeinrich Schuchardt } 615a95343b8SJonathan Gray 6163748ed90SAKASHI Takahiro if ((type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) && 6173748ed90SAKASHI Takahiro (is_valid_tpl(notify_tpl) != EFI_SUCCESS)) 61849deb455Sxypron.glpk@gmx.de return EFI_INVALID_PARAMETER; 619a95343b8SJonathan Gray 62043bce442SHeinrich Schuchardt evt = calloc(1, sizeof(struct efi_event)); 62143bce442SHeinrich Schuchardt if (!evt) 62249deb455Sxypron.glpk@gmx.de return EFI_OUT_OF_RESOURCES; 62343bce442SHeinrich Schuchardt evt->type = type; 62443bce442SHeinrich Schuchardt evt->notify_tpl = notify_tpl; 62543bce442SHeinrich Schuchardt evt->notify_function = notify_function; 62643bce442SHeinrich Schuchardt evt->notify_context = notify_context; 627b095f3c8SHeinrich Schuchardt evt->group = group; 62843bce442SHeinrich Schuchardt /* Disable timers on boot up */ 62943bce442SHeinrich Schuchardt evt->trigger_next = -1ULL; 63043bce442SHeinrich Schuchardt evt->is_queued = false; 63143bce442SHeinrich Schuchardt evt->is_signaled = false; 63243bce442SHeinrich Schuchardt list_add_tail(&evt->link, &efi_events); 63343bce442SHeinrich Schuchardt *event = evt; 63443bce442SHeinrich Schuchardt return EFI_SUCCESS; 635c6841592Sxypron.glpk@gmx.de } 636bee91169SAlexander Graf 637332468f7SHeinrich Schuchardt /* 63878a88f79SMario Six * efi_create_event_ex() - create an event in a group 6396b03cd10SHeinrich Schuchardt * @type: type of the event to create 6406b03cd10SHeinrich Schuchardt * @notify_tpl: task priority level of the event 6416b03cd10SHeinrich Schuchardt * @notify_function: notification function of the event 6426b03cd10SHeinrich Schuchardt * @notify_context: pointer passed to the notification function 6436b03cd10SHeinrich Schuchardt * @event: created event 6446b03cd10SHeinrich Schuchardt * @event_group: event group 64578a88f79SMario Six * 64678a88f79SMario Six * This function implements the CreateEventEx service. 64778a88f79SMario Six * 64878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 64978a88f79SMario Six * details. 65078a88f79SMario Six * 65178a88f79SMario Six * Return: status code 6529f0930e5SHeinrich Schuchardt */ 6539f0930e5SHeinrich Schuchardt efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, 6549f0930e5SHeinrich Schuchardt void (EFIAPI *notify_function) ( 6559f0930e5SHeinrich Schuchardt struct efi_event *event, 6569f0930e5SHeinrich Schuchardt void *context), 6579f0930e5SHeinrich Schuchardt void *notify_context, 6589f0930e5SHeinrich Schuchardt efi_guid_t *event_group, 6599f0930e5SHeinrich Schuchardt struct efi_event **event) 6609f0930e5SHeinrich Schuchardt { 6619f0930e5SHeinrich Schuchardt EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function, 6629f0930e5SHeinrich Schuchardt notify_context, event_group); 6639f0930e5SHeinrich Schuchardt return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, 664b095f3c8SHeinrich Schuchardt notify_context, event_group, event)); 6659f0930e5SHeinrich Schuchardt } 6669f0930e5SHeinrich Schuchardt 6676b03cd10SHeinrich Schuchardt /** 66878a88f79SMario Six * efi_create_event_ext() - create an event 6696b03cd10SHeinrich Schuchardt * @type: type of the event to create 6706b03cd10SHeinrich Schuchardt * @notify_tpl: task priority level of the event 6716b03cd10SHeinrich Schuchardt * @notify_function: notification function of the event 6726b03cd10SHeinrich Schuchardt * @notify_context: pointer passed to the notification function 6736b03cd10SHeinrich Schuchardt * @event: created event 67478a88f79SMario Six * 67578a88f79SMario Six * This function implements the CreateEvent service. 67678a88f79SMario Six * 67778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 67878a88f79SMario Six * details. 67978a88f79SMario Six * 68078a88f79SMario Six * Return: status code 681332468f7SHeinrich Schuchardt */ 68249deb455Sxypron.glpk@gmx.de static efi_status_t EFIAPI efi_create_event_ext( 683152cade3SHeinrich Schuchardt uint32_t type, efi_uintn_t notify_tpl, 68449deb455Sxypron.glpk@gmx.de void (EFIAPI *notify_function) ( 68549deb455Sxypron.glpk@gmx.de struct efi_event *event, 68649deb455Sxypron.glpk@gmx.de void *context), 68749deb455Sxypron.glpk@gmx.de void *notify_context, struct efi_event **event) 68849deb455Sxypron.glpk@gmx.de { 68949deb455Sxypron.glpk@gmx.de EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function, 69049deb455Sxypron.glpk@gmx.de notify_context); 69149deb455Sxypron.glpk@gmx.de return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, 692b095f3c8SHeinrich Schuchardt notify_context, NULL, event)); 69349deb455Sxypron.glpk@gmx.de } 69449deb455Sxypron.glpk@gmx.de 6956b03cd10SHeinrich Schuchardt /** 69678a88f79SMario Six * efi_timer_check() - check if a timer event has occurred 6976b03cd10SHeinrich Schuchardt * 698332468f7SHeinrich Schuchardt * Check if a timer event has occurred or a queued notification function should 699332468f7SHeinrich Schuchardt * be called. 700332468f7SHeinrich Schuchardt * 701bee91169SAlexander Graf * Our timers have to work without interrupts, so we check whenever keyboard 702332468f7SHeinrich Schuchardt * input or disk accesses happen if enough time elapsed for them to fire. 703bee91169SAlexander Graf */ 704bee91169SAlexander Graf void efi_timer_check(void) 705bee91169SAlexander Graf { 70643bce442SHeinrich Schuchardt struct efi_event *evt; 707bee91169SAlexander Graf u64 now = timer_get_us(); 708bee91169SAlexander Graf 70943bce442SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 71043bce442SHeinrich Schuchardt if (evt->is_queued) 711b095f3c8SHeinrich Schuchardt efi_queue_event(evt, true); 71243bce442SHeinrich Schuchardt if (!(evt->type & EVT_TIMER) || now < evt->trigger_next) 713ca62a4f5SHeinrich Schuchardt continue; 71443bce442SHeinrich Schuchardt switch (evt->trigger_type) { 715ca62a4f5SHeinrich Schuchardt case EFI_TIMER_RELATIVE: 71643bce442SHeinrich Schuchardt evt->trigger_type = EFI_TIMER_STOP; 717ca62a4f5SHeinrich Schuchardt break; 718ca62a4f5SHeinrich Schuchardt case EFI_TIMER_PERIODIC: 71943bce442SHeinrich Schuchardt evt->trigger_next += evt->trigger_time; 720ca62a4f5SHeinrich Schuchardt break; 721ca62a4f5SHeinrich Schuchardt default: 722ca62a4f5SHeinrich Schuchardt continue; 723bee91169SAlexander Graf } 724b095f3c8SHeinrich Schuchardt evt->is_signaled = false; 72543bce442SHeinrich Schuchardt efi_signal_event(evt, true); 726c6841592Sxypron.glpk@gmx.de } 727bee91169SAlexander Graf WATCHDOG_RESET(); 728bee91169SAlexander Graf } 729bee91169SAlexander Graf 7306b03cd10SHeinrich Schuchardt /** 73178a88f79SMario Six * efi_set_timer() - set the trigger time for a timer event or stop the event 73278a88f79SMario Six * @event: event for which the timer is set 73378a88f79SMario Six * @type: type of the timer 73478a88f79SMario Six * @trigger_time: trigger period in multiples of 100 ns 735332468f7SHeinrich Schuchardt * 736332468f7SHeinrich Schuchardt * This is the function for internal usage in U-Boot. For the API function 737332468f7SHeinrich Schuchardt * implementing the SetTimer service see efi_set_timer_ext. 738332468f7SHeinrich Schuchardt * 73978a88f79SMario Six * Return: status code 740332468f7SHeinrich Schuchardt */ 741b521d29eSxypron.glpk@gmx.de efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, 742bee91169SAlexander Graf uint64_t trigger_time) 743bee91169SAlexander Graf { 74443bce442SHeinrich Schuchardt /* Check that the event is valid */ 74543bce442SHeinrich Schuchardt if (efi_is_event(event) != EFI_SUCCESS || !(event->type & EVT_TIMER)) 74643bce442SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 747bee91169SAlexander Graf 7488787b02eSxypron.glpk@gmx.de /* 7498787b02eSxypron.glpk@gmx.de * The parameter defines a multiple of 100 ns. 7508787b02eSxypron.glpk@gmx.de * We use multiples of 1000 ns. So divide by 10. 7518787b02eSxypron.glpk@gmx.de */ 7527d963323SHeinrich Schuchardt do_div(trigger_time, 10); 753bee91169SAlexander Graf 754bee91169SAlexander Graf switch (type) { 755bee91169SAlexander Graf case EFI_TIMER_STOP: 756c6841592Sxypron.glpk@gmx.de event->trigger_next = -1ULL; 757bee91169SAlexander Graf break; 758bee91169SAlexander Graf case EFI_TIMER_PERIODIC: 759bee91169SAlexander Graf case EFI_TIMER_RELATIVE: 76043bce442SHeinrich Schuchardt event->trigger_next = timer_get_us() + trigger_time; 761bee91169SAlexander Graf break; 762bee91169SAlexander Graf default: 763bfc72462Sxypron.glpk@gmx.de return EFI_INVALID_PARAMETER; 764bee91169SAlexander Graf } 765c6841592Sxypron.glpk@gmx.de event->trigger_type = type; 766c6841592Sxypron.glpk@gmx.de event->trigger_time = trigger_time; 767e190e897SHeinrich Schuchardt event->is_signaled = false; 768bfc72462Sxypron.glpk@gmx.de return EFI_SUCCESS; 769bee91169SAlexander Graf } 770bfc72462Sxypron.glpk@gmx.de 7716b03cd10SHeinrich Schuchardt /** 77278a88f79SMario Six * efi_set_timer_ext() - Set the trigger time for a timer event or stop the 77378a88f79SMario Six * event 7746b03cd10SHeinrich Schuchardt * @event: event for which the timer is set 7756b03cd10SHeinrich Schuchardt * @type: type of the timer 7766b03cd10SHeinrich Schuchardt * @trigger_time: trigger period in multiples of 100 ns 77778a88f79SMario Six * 77878a88f79SMario Six * This function implements the SetTimer service. 77978a88f79SMario Six * 78078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 78178a88f79SMario Six * details. 78278a88f79SMario Six * 78378a88f79SMario Six * 78478a88f79SMario Six * Return: status code 785332468f7SHeinrich Schuchardt */ 786b521d29eSxypron.glpk@gmx.de static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, 787b521d29eSxypron.glpk@gmx.de enum efi_timer_delay type, 788bfc72462Sxypron.glpk@gmx.de uint64_t trigger_time) 789bfc72462Sxypron.glpk@gmx.de { 790dee37fc9SMasahiro Yamada EFI_ENTRY("%p, %d, %llx", event, type, trigger_time); 791bfc72462Sxypron.glpk@gmx.de return EFI_EXIT(efi_set_timer(event, type, trigger_time)); 792c6841592Sxypron.glpk@gmx.de } 793bee91169SAlexander Graf 7946b03cd10SHeinrich Schuchardt /** 79578a88f79SMario Six * efi_wait_for_event() - wait for events to be signaled 7966b03cd10SHeinrich Schuchardt * @num_events: number of events to be waited for 7976b03cd10SHeinrich Schuchardt * @event: events to be waited for 7986b03cd10SHeinrich Schuchardt * @index: index of the event that was signaled 79978a88f79SMario Six * 80078a88f79SMario Six * This function implements the WaitForEvent service. 80178a88f79SMario Six * 80278a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 80378a88f79SMario Six * details. 80478a88f79SMario Six * 80578a88f79SMario Six * Return: status code 806332468f7SHeinrich Schuchardt */ 807f5a2a938SHeinrich Schuchardt static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, 8082fd945feSxypron.glpk@gmx.de struct efi_event **event, 809f5a2a938SHeinrich Schuchardt efi_uintn_t *index) 810bee91169SAlexander Graf { 81143bce442SHeinrich Schuchardt int i; 812bee91169SAlexander Graf 813f5a2a938SHeinrich Schuchardt EFI_ENTRY("%zd, %p, %p", num_events, event, index); 814bee91169SAlexander Graf 815c6841592Sxypron.glpk@gmx.de /* Check parameters */ 816c6841592Sxypron.glpk@gmx.de if (!num_events || !event) 817c6841592Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 81832f4b2f8SHeinrich Schuchardt /* Check TPL */ 81932f4b2f8SHeinrich Schuchardt if (efi_tpl != TPL_APPLICATION) 82032f4b2f8SHeinrich Schuchardt return EFI_EXIT(EFI_UNSUPPORTED); 821c6841592Sxypron.glpk@gmx.de for (i = 0; i < num_events; ++i) { 82243bce442SHeinrich Schuchardt if (efi_is_event(event[i]) != EFI_SUCCESS) 823c6841592Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 824c6841592Sxypron.glpk@gmx.de if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) 825c6841592Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 826e190e897SHeinrich Schuchardt if (!event[i]->is_signaled) 827b095f3c8SHeinrich Schuchardt efi_queue_event(event[i], true); 828c6841592Sxypron.glpk@gmx.de } 829c6841592Sxypron.glpk@gmx.de 830c6841592Sxypron.glpk@gmx.de /* Wait for signal */ 831c6841592Sxypron.glpk@gmx.de for (;;) { 832c6841592Sxypron.glpk@gmx.de for (i = 0; i < num_events; ++i) { 833e190e897SHeinrich Schuchardt if (event[i]->is_signaled) 834c6841592Sxypron.glpk@gmx.de goto out; 835c6841592Sxypron.glpk@gmx.de } 836c6841592Sxypron.glpk@gmx.de /* Allow events to occur. */ 837bee91169SAlexander Graf efi_timer_check(); 838c6841592Sxypron.glpk@gmx.de } 839c6841592Sxypron.glpk@gmx.de 840c6841592Sxypron.glpk@gmx.de out: 841c6841592Sxypron.glpk@gmx.de /* 842c6841592Sxypron.glpk@gmx.de * Reset the signal which is passed to the caller to allow periodic 843c6841592Sxypron.glpk@gmx.de * events to occur. 844c6841592Sxypron.glpk@gmx.de */ 845e190e897SHeinrich Schuchardt event[i]->is_signaled = false; 846c6841592Sxypron.glpk@gmx.de if (index) 847c6841592Sxypron.glpk@gmx.de *index = i; 848bee91169SAlexander Graf 849bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 850bee91169SAlexander Graf } 851bee91169SAlexander Graf 8526b03cd10SHeinrich Schuchardt /** 85378a88f79SMario Six * efi_signal_event_ext() - signal an EFI event 85478a88f79SMario Six * @event: event to signal 855332468f7SHeinrich Schuchardt * 856332468f7SHeinrich Schuchardt * This function implements the SignalEvent service. 85778a88f79SMario Six * 85878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 85978a88f79SMario Six * details. 860332468f7SHeinrich Schuchardt * 861332468f7SHeinrich Schuchardt * This functions sets the signaled state of the event and queues the 862332468f7SHeinrich Schuchardt * notification function for execution. 863332468f7SHeinrich Schuchardt * 86478a88f79SMario Six * Return: status code 865332468f7SHeinrich Schuchardt */ 866c6841592Sxypron.glpk@gmx.de static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) 867bee91169SAlexander Graf { 868bee91169SAlexander Graf EFI_ENTRY("%p", event); 86943bce442SHeinrich Schuchardt if (efi_is_event(event) != EFI_SUCCESS) 87043bce442SHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 8719bc9664dSHeinrich Schuchardt efi_signal_event(event, true); 872bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 873bee91169SAlexander Graf } 874bee91169SAlexander Graf 8756b03cd10SHeinrich Schuchardt /** 87678a88f79SMario Six * efi_close_event() - close an EFI event 87778a88f79SMario Six * @event: event to close 878332468f7SHeinrich Schuchardt * 879332468f7SHeinrich Schuchardt * This function implements the CloseEvent service. 880332468f7SHeinrich Schuchardt * 88178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 88278a88f79SMario Six * details. 88378a88f79SMario Six * 88478a88f79SMario Six * Return: status code 885332468f7SHeinrich Schuchardt */ 8862fd945feSxypron.glpk@gmx.de static efi_status_t EFIAPI efi_close_event(struct efi_event *event) 887bee91169SAlexander Graf { 888bee91169SAlexander Graf EFI_ENTRY("%p", event); 88943bce442SHeinrich Schuchardt if (efi_is_event(event) != EFI_SUCCESS) 890c6841592Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 89143bce442SHeinrich Schuchardt list_del(&event->link); 89243bce442SHeinrich Schuchardt free(event); 89343bce442SHeinrich Schuchardt return EFI_EXIT(EFI_SUCCESS); 894c6841592Sxypron.glpk@gmx.de } 895bee91169SAlexander Graf 8966b03cd10SHeinrich Schuchardt /** 89778a88f79SMario Six * efi_check_event() - check if an event is signaled 89878a88f79SMario Six * @event: event to check 899332468f7SHeinrich Schuchardt * 900332468f7SHeinrich Schuchardt * This function implements the CheckEvent service. 901332468f7SHeinrich Schuchardt * 90278a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 90378a88f79SMario Six * details. 904332468f7SHeinrich Schuchardt * 90578a88f79SMario Six * If an event is not signaled yet, the notification function is queued. The 90678a88f79SMario Six * signaled state is cleared. 90778a88f79SMario Six * 90878a88f79SMario Six * Return: status code 909332468f7SHeinrich Schuchardt */ 9102fd945feSxypron.glpk@gmx.de static efi_status_t EFIAPI efi_check_event(struct efi_event *event) 911bee91169SAlexander Graf { 912bee91169SAlexander Graf EFI_ENTRY("%p", event); 913c6841592Sxypron.glpk@gmx.de efi_timer_check(); 91443bce442SHeinrich Schuchardt if (efi_is_event(event) != EFI_SUCCESS || 91543bce442SHeinrich Schuchardt event->type & EVT_NOTIFY_SIGNAL) 91643bce442SHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 917e190e897SHeinrich Schuchardt if (!event->is_signaled) 918b095f3c8SHeinrich Schuchardt efi_queue_event(event, true); 9197069515eSHeinrich Schuchardt if (event->is_signaled) { 9207069515eSHeinrich Schuchardt event->is_signaled = false; 921c6841592Sxypron.glpk@gmx.de return EFI_EXIT(EFI_SUCCESS); 9227069515eSHeinrich Schuchardt } 923bee91169SAlexander Graf return EFI_EXIT(EFI_NOT_READY); 924bee91169SAlexander Graf } 925bee91169SAlexander Graf 9266b03cd10SHeinrich Schuchardt /** 92778a88f79SMario Six * efi_search_obj() - find the internal EFI object for a handle 9286b03cd10SHeinrich Schuchardt * @handle: handle to find 92978a88f79SMario Six * 93078a88f79SMario Six * Return: EFI object 9317b9f8ad7SHeinrich Schuchardt */ 9322074f700SHeinrich Schuchardt struct efi_object *efi_search_obj(const efi_handle_t handle) 9337b9f8ad7SHeinrich Schuchardt { 9347b9f8ad7SHeinrich Schuchardt struct efi_object *efiobj; 9357b9f8ad7SHeinrich Schuchardt 9361b68153aSHeinrich Schuchardt list_for_each_entry(efiobj, &efi_obj_list, link) { 937fae0118eSHeinrich Schuchardt if (efiobj == handle) 9387b9f8ad7SHeinrich Schuchardt return efiobj; 9397b9f8ad7SHeinrich Schuchardt } 9407b9f8ad7SHeinrich Schuchardt 9417b9f8ad7SHeinrich Schuchardt return NULL; 9427b9f8ad7SHeinrich Schuchardt } 9437b9f8ad7SHeinrich Schuchardt 9446b03cd10SHeinrich Schuchardt /** 94578a88f79SMario Six * efi_open_protocol_info_entry() - create open protocol info entry and add it 9466b03cd10SHeinrich Schuchardt * to a protocol 9476b03cd10SHeinrich Schuchardt * @handler: handler of a protocol 94878a88f79SMario Six * 94978a88f79SMario Six * Return: open protocol info entry 950fe1599daSHeinrich Schuchardt */ 951fe1599daSHeinrich Schuchardt static struct efi_open_protocol_info_entry *efi_create_open_info( 952fe1599daSHeinrich Schuchardt struct efi_handler *handler) 953fe1599daSHeinrich Schuchardt { 954fe1599daSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 955fe1599daSHeinrich Schuchardt 956fe1599daSHeinrich Schuchardt item = calloc(1, sizeof(struct efi_open_protocol_info_item)); 957fe1599daSHeinrich Schuchardt if (!item) 958fe1599daSHeinrich Schuchardt return NULL; 959fe1599daSHeinrich Schuchardt /* Append the item to the open protocol info list. */ 960fe1599daSHeinrich Schuchardt list_add_tail(&item->link, &handler->open_infos); 961fe1599daSHeinrich Schuchardt 962fe1599daSHeinrich Schuchardt return &item->info; 963fe1599daSHeinrich Schuchardt } 964fe1599daSHeinrich Schuchardt 9656b03cd10SHeinrich Schuchardt /** 96678a88f79SMario Six * efi_delete_open_info() - remove an open protocol info entry from a protocol 9676b03cd10SHeinrich Schuchardt * @item: open protocol info entry to delete 96878a88f79SMario Six * 96978a88f79SMario Six * Return: status code 970fe1599daSHeinrich Schuchardt */ 971fe1599daSHeinrich Schuchardt static efi_status_t efi_delete_open_info( 972fe1599daSHeinrich Schuchardt struct efi_open_protocol_info_item *item) 973fe1599daSHeinrich Schuchardt { 974fe1599daSHeinrich Schuchardt list_del(&item->link); 975fe1599daSHeinrich Schuchardt free(item); 976fe1599daSHeinrich Schuchardt return EFI_SUCCESS; 977fe1599daSHeinrich Schuchardt } 978fe1599daSHeinrich Schuchardt 9796b03cd10SHeinrich Schuchardt /** 98078a88f79SMario Six * efi_add_protocol() - install new protocol on a handle 9816b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be installed 9826b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to be installed 9836b03cd10SHeinrich Schuchardt * @protocol_interface: interface of the protocol implementation 98478a88f79SMario Six * 98578a88f79SMario Six * Return: status code 9863f79a2b5SHeinrich Schuchardt */ 9872074f700SHeinrich Schuchardt efi_status_t efi_add_protocol(const efi_handle_t handle, 9882074f700SHeinrich Schuchardt const efi_guid_t *protocol, 9893f79a2b5SHeinrich Schuchardt void *protocol_interface) 9903f79a2b5SHeinrich Schuchardt { 9913f79a2b5SHeinrich Schuchardt struct efi_object *efiobj; 9923f79a2b5SHeinrich Schuchardt struct efi_handler *handler; 9933f79a2b5SHeinrich Schuchardt efi_status_t ret; 9943f79a2b5SHeinrich Schuchardt 9953f79a2b5SHeinrich Schuchardt efiobj = efi_search_obj(handle); 9963f79a2b5SHeinrich Schuchardt if (!efiobj) 9973f79a2b5SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 9983f79a2b5SHeinrich Schuchardt ret = efi_search_protocol(handle, protocol, NULL); 9993f79a2b5SHeinrich Schuchardt if (ret != EFI_NOT_FOUND) 10003f79a2b5SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 10013f79a2b5SHeinrich Schuchardt handler = calloc(1, sizeof(struct efi_handler)); 10023f79a2b5SHeinrich Schuchardt if (!handler) 10033f79a2b5SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 10043f79a2b5SHeinrich Schuchardt handler->guid = protocol; 10053f79a2b5SHeinrich Schuchardt handler->protocol_interface = protocol_interface; 1006fe1599daSHeinrich Schuchardt INIT_LIST_HEAD(&handler->open_infos); 100769fb6b1aSHeinrich Schuchardt list_add_tail(&handler->link, &efiobj->protocols); 1008d5504144SHeinrich Schuchardt if (!guidcmp(&efi_guid_device_path, protocol)) 1009d5504144SHeinrich Schuchardt EFI_PRINT("installed device path '%pD'\n", protocol_interface); 10103f79a2b5SHeinrich Schuchardt return EFI_SUCCESS; 10113f79a2b5SHeinrich Schuchardt } 10123f79a2b5SHeinrich Schuchardt 10136b03cd10SHeinrich Schuchardt /** 101478a88f79SMario Six * efi_install_protocol_interface() - install protocol interface 10156b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be installed 10166b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to be installed 10176b03cd10SHeinrich Schuchardt * @protocol_interface_type: type of the interface to be installed, 1018332468f7SHeinrich Schuchardt * always EFI_NATIVE_INTERFACE 10196b03cd10SHeinrich Schuchardt * @protocol_interface: interface of the protocol implementation 102078a88f79SMario Six * 102178a88f79SMario Six * This function implements the InstallProtocolInterface service. 102278a88f79SMario Six * 102378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 102478a88f79SMario Six * details. 102578a88f79SMario Six * 102678a88f79SMario Six * Return: status code 1027332468f7SHeinrich Schuchardt */ 10281760ef57SHeinrich Schuchardt static efi_status_t EFIAPI efi_install_protocol_interface( 1029faea1041SHeinrich Schuchardt efi_handle_t *handle, const efi_guid_t *protocol, 10301760ef57SHeinrich Schuchardt int protocol_interface_type, void *protocol_interface) 1031bee91169SAlexander Graf { 1032e0549f8aSxypron.glpk@gmx.de efi_status_t r; 1033e0549f8aSxypron.glpk@gmx.de 10341760ef57SHeinrich Schuchardt EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, 10351760ef57SHeinrich Schuchardt protocol_interface); 10361760ef57SHeinrich Schuchardt 1037e0549f8aSxypron.glpk@gmx.de if (!handle || !protocol || 1038e0549f8aSxypron.glpk@gmx.de protocol_interface_type != EFI_NATIVE_INTERFACE) { 1039e0549f8aSxypron.glpk@gmx.de r = EFI_INVALID_PARAMETER; 1040e0549f8aSxypron.glpk@gmx.de goto out; 1041bee91169SAlexander Graf } 1042e0549f8aSxypron.glpk@gmx.de 1043e0549f8aSxypron.glpk@gmx.de /* Create new handle if requested. */ 1044e0549f8aSxypron.glpk@gmx.de if (!*handle) { 10453cc6e3feSHeinrich Schuchardt r = efi_create_handle(handle); 10463cc6e3feSHeinrich Schuchardt if (r != EFI_SUCCESS) 1047e0549f8aSxypron.glpk@gmx.de goto out; 1048af1408e0SHeinrich Schuchardt debug("%sEFI: new handle %p\n", indent_string(nesting_level), 1049af1408e0SHeinrich Schuchardt *handle); 1050af1408e0SHeinrich Schuchardt } else { 1051af1408e0SHeinrich Schuchardt debug("%sEFI: handle %p\n", indent_string(nesting_level), 1052af1408e0SHeinrich Schuchardt *handle); 1053e0549f8aSxypron.glpk@gmx.de } 10541202530dSHeinrich Schuchardt /* Add new protocol */ 10551202530dSHeinrich Schuchardt r = efi_add_protocol(*handle, protocol, protocol_interface); 1056e0549f8aSxypron.glpk@gmx.de out: 10571760ef57SHeinrich Schuchardt return EFI_EXIT(r); 1058e0549f8aSxypron.glpk@gmx.de } 1059e0549f8aSxypron.glpk@gmx.de 10606b03cd10SHeinrich Schuchardt /** 106178a88f79SMario Six * efi_get_drivers() - get all drivers associated to a controller 1062fae0118eSHeinrich Schuchardt * @handle: handle of the controller 1063b72aaa87SHeinrich Schuchardt * @protocol: protocol GUID (optional) 10646b03cd10SHeinrich Schuchardt * @number_of_drivers: number of child controllers 10656b03cd10SHeinrich Schuchardt * @driver_handle_buffer: handles of the the drivers 106678a88f79SMario Six * 106778a88f79SMario Six * The allocated buffer has to be freed with free(). 106878a88f79SMario Six * 106978a88f79SMario Six * Return: status code 10703f9b0042SHeinrich Schuchardt */ 1071fae0118eSHeinrich Schuchardt static efi_status_t efi_get_drivers(efi_handle_t handle, 10723f9b0042SHeinrich Schuchardt const efi_guid_t *protocol, 10733f9b0042SHeinrich Schuchardt efi_uintn_t *number_of_drivers, 10743f9b0042SHeinrich Schuchardt efi_handle_t **driver_handle_buffer) 10753f9b0042SHeinrich Schuchardt { 10763f9b0042SHeinrich Schuchardt struct efi_handler *handler; 10773f9b0042SHeinrich Schuchardt struct efi_open_protocol_info_item *item; 10783f9b0042SHeinrich Schuchardt efi_uintn_t count = 0, i; 10793f9b0042SHeinrich Schuchardt bool duplicate; 10803f9b0042SHeinrich Schuchardt 10813f9b0042SHeinrich Schuchardt /* Count all driver associations */ 1082fae0118eSHeinrich Schuchardt list_for_each_entry(handler, &handle->protocols, link) { 10833f9b0042SHeinrich Schuchardt if (protocol && guidcmp(handler->guid, protocol)) 10843f9b0042SHeinrich Schuchardt continue; 10853f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 10863f9b0042SHeinrich Schuchardt if (item->info.attributes & 10873f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_DRIVER) 10883f9b0042SHeinrich Schuchardt ++count; 10893f9b0042SHeinrich Schuchardt } 10903f9b0042SHeinrich Schuchardt } 10913f9b0042SHeinrich Schuchardt /* 10923f9b0042SHeinrich Schuchardt * Create buffer. In case of duplicate driver assignments the buffer 10933f9b0042SHeinrich Schuchardt * will be too large. But that does not harm. 10943f9b0042SHeinrich Schuchardt */ 10953f9b0042SHeinrich Schuchardt *number_of_drivers = 0; 10963f9b0042SHeinrich Schuchardt *driver_handle_buffer = calloc(count, sizeof(efi_handle_t)); 10973f9b0042SHeinrich Schuchardt if (!*driver_handle_buffer) 10983f9b0042SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 10993f9b0042SHeinrich Schuchardt /* Collect unique driver handles */ 1100fae0118eSHeinrich Schuchardt list_for_each_entry(handler, &handle->protocols, link) { 11013f9b0042SHeinrich Schuchardt if (protocol && guidcmp(handler->guid, protocol)) 11023f9b0042SHeinrich Schuchardt continue; 11033f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 11043f9b0042SHeinrich Schuchardt if (item->info.attributes & 11053f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_DRIVER) { 11063f9b0042SHeinrich Schuchardt /* Check this is a new driver */ 11073f9b0042SHeinrich Schuchardt duplicate = false; 11083f9b0042SHeinrich Schuchardt for (i = 0; i < *number_of_drivers; ++i) { 11093f9b0042SHeinrich Schuchardt if ((*driver_handle_buffer)[i] == 11103f9b0042SHeinrich Schuchardt item->info.agent_handle) 11113f9b0042SHeinrich Schuchardt duplicate = true; 11123f9b0042SHeinrich Schuchardt } 11133f9b0042SHeinrich Schuchardt /* Copy handle to buffer */ 11143f9b0042SHeinrich Schuchardt if (!duplicate) { 11153f9b0042SHeinrich Schuchardt i = (*number_of_drivers)++; 11163f9b0042SHeinrich Schuchardt (*driver_handle_buffer)[i] = 11173f9b0042SHeinrich Schuchardt item->info.agent_handle; 11183f9b0042SHeinrich Schuchardt } 11193f9b0042SHeinrich Schuchardt } 11203f9b0042SHeinrich Schuchardt } 11213f9b0042SHeinrich Schuchardt } 11223f9b0042SHeinrich Schuchardt return EFI_SUCCESS; 11233f9b0042SHeinrich Schuchardt } 11243f9b0042SHeinrich Schuchardt 11256b03cd10SHeinrich Schuchardt /** 112678a88f79SMario Six * efi_disconnect_all_drivers() - disconnect all drivers from a controller 1127fae0118eSHeinrich Schuchardt * @handle: handle of the controller 1128b72aaa87SHeinrich Schuchardt * @protocol: protocol GUID (optional) 11296b03cd10SHeinrich Schuchardt * @child_handle: handle of the child to destroy 113078a88f79SMario Six * 113178a88f79SMario Six * This function implements the DisconnectController service. 113278a88f79SMario Six * 113378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 113478a88f79SMario Six * details. 113578a88f79SMario Six * 113678a88f79SMario Six * Return: status code 11373f9b0042SHeinrich Schuchardt */ 1138fae0118eSHeinrich Schuchardt static efi_status_t efi_disconnect_all_drivers 1139fae0118eSHeinrich Schuchardt (efi_handle_t handle, 11403f9b0042SHeinrich Schuchardt const efi_guid_t *protocol, 11413f9b0042SHeinrich Schuchardt efi_handle_t child_handle) 11423f9b0042SHeinrich Schuchardt { 11433f9b0042SHeinrich Schuchardt efi_uintn_t number_of_drivers; 11443f9b0042SHeinrich Schuchardt efi_handle_t *driver_handle_buffer; 11453f9b0042SHeinrich Schuchardt efi_status_t r, ret; 11463f9b0042SHeinrich Schuchardt 1147fae0118eSHeinrich Schuchardt ret = efi_get_drivers(handle, protocol, &number_of_drivers, 11483f9b0042SHeinrich Schuchardt &driver_handle_buffer); 11493f9b0042SHeinrich Schuchardt if (ret != EFI_SUCCESS) 11503f9b0042SHeinrich Schuchardt return ret; 11513f9b0042SHeinrich Schuchardt 11523f9b0042SHeinrich Schuchardt ret = EFI_NOT_FOUND; 11533f9b0042SHeinrich Schuchardt while (number_of_drivers) { 11543f9b0042SHeinrich Schuchardt r = EFI_CALL(efi_disconnect_controller( 1155fae0118eSHeinrich Schuchardt handle, 11563f9b0042SHeinrich Schuchardt driver_handle_buffer[--number_of_drivers], 11573f9b0042SHeinrich Schuchardt child_handle)); 11583f9b0042SHeinrich Schuchardt if (r == EFI_SUCCESS) 11593f9b0042SHeinrich Schuchardt ret = r; 11603f9b0042SHeinrich Schuchardt } 11613f9b0042SHeinrich Schuchardt free(driver_handle_buffer); 11623f9b0042SHeinrich Schuchardt return ret; 11633f9b0042SHeinrich Schuchardt } 11643f9b0042SHeinrich Schuchardt 11656b03cd10SHeinrich Schuchardt /** 11669b47f13bSHeinrich Schuchardt * efi_uninstall_protocol() - uninstall protocol interface 11679b47f13bSHeinrich Schuchardt * 11686b03cd10SHeinrich Schuchardt * @handle: handle from which the protocol shall be removed 11696b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to be removed 11706b03cd10SHeinrich Schuchardt * @protocol_interface: interface to be removed 117178a88f79SMario Six * 11729b47f13bSHeinrich Schuchardt * This function DOES NOT delete a handle without installed protocol. 117378a88f79SMario Six * 117478a88f79SMario Six * Return: status code 1175332468f7SHeinrich Schuchardt */ 11769b47f13bSHeinrich Schuchardt static efi_status_t efi_uninstall_protocol 11779b47f13bSHeinrich Schuchardt (efi_handle_t handle, const efi_guid_t *protocol, 1178cd534083SHeinrich Schuchardt void *protocol_interface) 1179bee91169SAlexander Graf { 1180ad97373bSHeinrich Schuchardt struct efi_object *efiobj; 11815810511dSHeinrich Schuchardt struct efi_handler *handler; 1182ad97373bSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 1183ad97373bSHeinrich Schuchardt struct efi_open_protocol_info_item *pos; 11845810511dSHeinrich Schuchardt efi_status_t r; 11854b6ed0d7Sxypron.glpk@gmx.de 1186ad97373bSHeinrich Schuchardt /* Check handle */ 1187ad97373bSHeinrich Schuchardt efiobj = efi_search_obj(handle); 1188ad97373bSHeinrich Schuchardt if (!efiobj) { 11894b6ed0d7Sxypron.glpk@gmx.de r = EFI_INVALID_PARAMETER; 11904b6ed0d7Sxypron.glpk@gmx.de goto out; 11914b6ed0d7Sxypron.glpk@gmx.de } 11925810511dSHeinrich Schuchardt /* Find the protocol on the handle */ 11935810511dSHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 11945810511dSHeinrich Schuchardt if (r != EFI_SUCCESS) 11955810511dSHeinrich Schuchardt goto out; 1196ad97373bSHeinrich Schuchardt /* Disconnect controllers */ 1197ad97373bSHeinrich Schuchardt efi_disconnect_all_drivers(efiobj, protocol, NULL); 1198ad97373bSHeinrich Schuchardt if (!list_empty(&handler->open_infos)) { 11994b6ed0d7Sxypron.glpk@gmx.de r = EFI_ACCESS_DENIED; 1200ad97373bSHeinrich Schuchardt goto out; 12014b6ed0d7Sxypron.glpk@gmx.de } 1202ad97373bSHeinrich Schuchardt /* Close protocol */ 1203ad97373bSHeinrich Schuchardt list_for_each_entry_safe(item, pos, &handler->open_infos, link) { 1204ad97373bSHeinrich Schuchardt if (item->info.attributes == 1205ad97373bSHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL || 1206ad97373bSHeinrich Schuchardt item->info.attributes == EFI_OPEN_PROTOCOL_GET_PROTOCOL || 1207ad97373bSHeinrich Schuchardt item->info.attributes == EFI_OPEN_PROTOCOL_TEST_PROTOCOL) 1208ad97373bSHeinrich Schuchardt list_del(&item->link); 1209ad97373bSHeinrich Schuchardt } 1210ad97373bSHeinrich Schuchardt if (!list_empty(&handler->open_infos)) { 1211ad97373bSHeinrich Schuchardt r = EFI_ACCESS_DENIED; 1212ad97373bSHeinrich Schuchardt goto out; 1213ad97373bSHeinrich Schuchardt } 1214ad97373bSHeinrich Schuchardt r = efi_remove_protocol(handle, protocol, protocol_interface); 12154b6ed0d7Sxypron.glpk@gmx.de out: 12169b47f13bSHeinrich Schuchardt return r; 12179b47f13bSHeinrich Schuchardt } 12189b47f13bSHeinrich Schuchardt 12199b47f13bSHeinrich Schuchardt /** 12209b47f13bSHeinrich Schuchardt * efi_uninstall_protocol_interface() - uninstall protocol interface 12219b47f13bSHeinrich Schuchardt * @handle: handle from which the protocol shall be removed 12229b47f13bSHeinrich Schuchardt * @protocol: GUID of the protocol to be removed 12239b47f13bSHeinrich Schuchardt * @protocol_interface: interface to be removed 12249b47f13bSHeinrich Schuchardt * 12259b47f13bSHeinrich Schuchardt * This function implements the UninstallProtocolInterface service. 12269b47f13bSHeinrich Schuchardt * 12279b47f13bSHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for 12289b47f13bSHeinrich Schuchardt * details. 12299b47f13bSHeinrich Schuchardt * 12309b47f13bSHeinrich Schuchardt * Return: status code 12319b47f13bSHeinrich Schuchardt */ 12329b47f13bSHeinrich Schuchardt static efi_status_t EFIAPI efi_uninstall_protocol_interface 12339b47f13bSHeinrich Schuchardt (efi_handle_t handle, const efi_guid_t *protocol, 12349b47f13bSHeinrich Schuchardt void *protocol_interface) 12359b47f13bSHeinrich Schuchardt { 12369b47f13bSHeinrich Schuchardt efi_status_t ret; 12379b47f13bSHeinrich Schuchardt 12389b47f13bSHeinrich Schuchardt EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); 12399b47f13bSHeinrich Schuchardt 12409b47f13bSHeinrich Schuchardt ret = efi_uninstall_protocol(handle, protocol, protocol_interface); 12419b47f13bSHeinrich Schuchardt if (ret != EFI_SUCCESS) 12429b47f13bSHeinrich Schuchardt goto out; 12439b47f13bSHeinrich Schuchardt 12449b47f13bSHeinrich Schuchardt /* If the last protocol has been removed, delete the handle. */ 12459b47f13bSHeinrich Schuchardt if (list_empty(&handle->protocols)) { 12469b47f13bSHeinrich Schuchardt list_del(&handle->link); 12479b47f13bSHeinrich Schuchardt free(handle); 12489b47f13bSHeinrich Schuchardt } 12499b47f13bSHeinrich Schuchardt out: 12509b47f13bSHeinrich Schuchardt return EFI_EXIT(ret); 1251bee91169SAlexander Graf } 1252bee91169SAlexander Graf 12536b03cd10SHeinrich Schuchardt /** 125478a88f79SMario Six * efi_register_protocol_notify() - register an event for notification when a 12556b03cd10SHeinrich Schuchardt * protocol is installed. 125678a88f79SMario Six * @protocol: GUID of the protocol whose installation shall be notified 125778a88f79SMario Six * @event: event to be signaled upon installation of the protocol 125878a88f79SMario Six * @registration: key for retrieving the registration information 1259332468f7SHeinrich Schuchardt * 1260332468f7SHeinrich Schuchardt * This function implements the RegisterProtocolNotify service. 1261332468f7SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification 1262332468f7SHeinrich Schuchardt * for details. 1263332468f7SHeinrich Schuchardt * 126478a88f79SMario Six * Return: status code 1265332468f7SHeinrich Schuchardt */ 12665a9682d0SHeinrich Schuchardt static efi_status_t EFIAPI efi_register_protocol_notify( 12675a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, 12682fd945feSxypron.glpk@gmx.de struct efi_event *event, 1269bee91169SAlexander Graf void **registration) 1270bee91169SAlexander Graf { 1271778e6af8SRob Clark EFI_ENTRY("%pUl, %p, %p", protocol, event, registration); 1272bee91169SAlexander Graf return EFI_EXIT(EFI_OUT_OF_RESOURCES); 1273bee91169SAlexander Graf } 1274bee91169SAlexander Graf 12756b03cd10SHeinrich Schuchardt /** 127678a88f79SMario Six * efi_search() - determine if an EFI handle implements a protocol 12776b03cd10SHeinrich Schuchardt * @search_type: selection criterion 12786b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 12796b03cd10SHeinrich Schuchardt * @search_key: registration key 1280fae0118eSHeinrich Schuchardt * @handle: handle 128178a88f79SMario Six * 128278a88f79SMario Six * See the documentation of the LocateHandle service in the UEFI specification. 128378a88f79SMario Six * 128478a88f79SMario Six * Return: 0 if the handle implements the protocol 1285332468f7SHeinrich Schuchardt */ 1286bee91169SAlexander Graf static int efi_search(enum efi_locate_search_type search_type, 12875a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, void *search_key, 1288fae0118eSHeinrich Schuchardt efi_handle_t handle) 1289bee91169SAlexander Graf { 129042cf1242SHeinrich Schuchardt efi_status_t ret; 1291bee91169SAlexander Graf 1292bee91169SAlexander Graf switch (search_type) { 12939f0770ffSHeinrich Schuchardt case ALL_HANDLES: 1294bee91169SAlexander Graf return 0; 12959f0770ffSHeinrich Schuchardt case BY_REGISTER_NOTIFY: 129642cf1242SHeinrich Schuchardt /* TODO: RegisterProtocolNotify is not implemented yet */ 1297bee91169SAlexander Graf return -1; 12989f0770ffSHeinrich Schuchardt case BY_PROTOCOL: 1299fae0118eSHeinrich Schuchardt ret = efi_search_protocol(handle, protocol, NULL); 130042cf1242SHeinrich Schuchardt return (ret != EFI_SUCCESS); 130142cf1242SHeinrich Schuchardt default: 130242cf1242SHeinrich Schuchardt /* Invalid search type */ 1303bee91169SAlexander Graf return -1; 1304bee91169SAlexander Graf } 1305bee91169SAlexander Graf } 1306bee91169SAlexander Graf 13076b03cd10SHeinrich Schuchardt /** 130878a88f79SMario Six * efi_locate_handle() - locate handles implementing a protocol 13096b03cd10SHeinrich Schuchardt * @search_type: selection criterion 13106b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 13116b03cd10SHeinrich Schuchardt * @search_key: registration key 13126b03cd10SHeinrich Schuchardt * @buffer_size: size of the buffer to receive the handles in bytes 13136b03cd10SHeinrich Schuchardt * @buffer: buffer to receive the relevant handles 131478a88f79SMario Six * 131578a88f79SMario Six * This function is meant for U-Boot internal calls. For the API implementation 131678a88f79SMario Six * of the LocateHandle service see efi_locate_handle_ext. 131778a88f79SMario Six * 131878a88f79SMario Six * Return: status code 1319332468f7SHeinrich Schuchardt */ 1320ebf199b9Sxypron.glpk@gmx.de static efi_status_t efi_locate_handle( 1321bee91169SAlexander Graf enum efi_locate_search_type search_type, 13225a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, void *search_key, 1323f5a2a938SHeinrich Schuchardt efi_uintn_t *buffer_size, efi_handle_t *buffer) 1324bee91169SAlexander Graf { 1325caf864e4SHeinrich Schuchardt struct efi_object *efiobj; 1326f5a2a938SHeinrich Schuchardt efi_uintn_t size = 0; 1327bee91169SAlexander Graf 1328caf864e4SHeinrich Schuchardt /* Check parameters */ 1329caf864e4SHeinrich Schuchardt switch (search_type) { 1330caf864e4SHeinrich Schuchardt case ALL_HANDLES: 1331caf864e4SHeinrich Schuchardt break; 1332caf864e4SHeinrich Schuchardt case BY_REGISTER_NOTIFY: 1333caf864e4SHeinrich Schuchardt if (!search_key) 1334caf864e4SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 1335caf864e4SHeinrich Schuchardt /* RegisterProtocolNotify is not implemented yet */ 1336caf864e4SHeinrich Schuchardt return EFI_UNSUPPORTED; 1337caf864e4SHeinrich Schuchardt case BY_PROTOCOL: 1338caf864e4SHeinrich Schuchardt if (!protocol) 1339caf864e4SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 1340caf864e4SHeinrich Schuchardt break; 1341caf864e4SHeinrich Schuchardt default: 1342caf864e4SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 1343bee91169SAlexander Graf } 1344caf864e4SHeinrich Schuchardt 1345caf864e4SHeinrich Schuchardt /* 1346caf864e4SHeinrich Schuchardt * efi_locate_handle_buffer uses this function for 1347caf864e4SHeinrich Schuchardt * the calculation of the necessary buffer size. 1348caf864e4SHeinrich Schuchardt * So do not require a buffer for buffersize == 0. 1349caf864e4SHeinrich Schuchardt */ 1350caf864e4SHeinrich Schuchardt if (!buffer_size || (*buffer_size && !buffer)) 1351caf864e4SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 1352caf864e4SHeinrich Schuchardt 1353caf864e4SHeinrich Schuchardt /* Count how much space we need */ 1354caf864e4SHeinrich Schuchardt list_for_each_entry(efiobj, &efi_obj_list, link) { 1355caf864e4SHeinrich Schuchardt if (!efi_search(search_type, protocol, search_key, efiobj)) 1356caf864e4SHeinrich Schuchardt size += sizeof(void *); 1357bee91169SAlexander Graf } 1358bee91169SAlexander Graf 1359bee91169SAlexander Graf if (*buffer_size < size) { 1360bee91169SAlexander Graf *buffer_size = size; 136126329584Sxypron.glpk@gmx.de return EFI_BUFFER_TOO_SMALL; 1362bee91169SAlexander Graf } 1363bee91169SAlexander Graf 1364796a78cbSRob Clark *buffer_size = size; 1365796a78cbSRob Clark if (size == 0) 1366796a78cbSRob Clark return EFI_NOT_FOUND; 1367796a78cbSRob Clark 1368bee91169SAlexander Graf /* Then fill the array */ 1369caf864e4SHeinrich Schuchardt list_for_each_entry(efiobj, &efi_obj_list, link) { 1370caf864e4SHeinrich Schuchardt if (!efi_search(search_type, protocol, search_key, efiobj)) 1371fae0118eSHeinrich Schuchardt *buffer++ = efiobj; 1372bee91169SAlexander Graf } 1373bee91169SAlexander Graf 137426329584Sxypron.glpk@gmx.de return EFI_SUCCESS; 137526329584Sxypron.glpk@gmx.de } 137626329584Sxypron.glpk@gmx.de 13776b03cd10SHeinrich Schuchardt /** 137878a88f79SMario Six * efi_locate_handle_ext() - locate handles implementing a protocol. 13796b03cd10SHeinrich Schuchardt * @search_type: selection criterion 13806b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 13816b03cd10SHeinrich Schuchardt * @search_key: registration key 13826b03cd10SHeinrich Schuchardt * @buffer_size: size of the buffer to receive the handles in bytes 13836b03cd10SHeinrich Schuchardt * @buffer: buffer to receive the relevant handles 138478a88f79SMario Six * 138578a88f79SMario Six * This function implements the LocateHandle service. 138678a88f79SMario Six * 138778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 138878a88f79SMario Six * details. 138978a88f79SMario Six * 139078a88f79SMario Six * Return: 0 if the handle implements the protocol 1391332468f7SHeinrich Schuchardt */ 139226329584Sxypron.glpk@gmx.de static efi_status_t EFIAPI efi_locate_handle_ext( 139326329584Sxypron.glpk@gmx.de enum efi_locate_search_type search_type, 13945a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, void *search_key, 1395f5a2a938SHeinrich Schuchardt efi_uintn_t *buffer_size, efi_handle_t *buffer) 139626329584Sxypron.glpk@gmx.de { 1397778e6af8SRob Clark EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, 139826329584Sxypron.glpk@gmx.de buffer_size, buffer); 139926329584Sxypron.glpk@gmx.de 140026329584Sxypron.glpk@gmx.de return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key, 140126329584Sxypron.glpk@gmx.de buffer_size, buffer)); 1402bee91169SAlexander Graf } 1403bee91169SAlexander Graf 14046b03cd10SHeinrich Schuchardt /** 140578a88f79SMario Six * efi_remove_configuration_table() - collapses configuration table entries, 14066b03cd10SHeinrich Schuchardt * removing index i 14076b03cd10SHeinrich Schuchardt * 14086b03cd10SHeinrich Schuchardt * @i: index of the table entry to be removed 14096b03cd10SHeinrich Schuchardt */ 1410d98cdf6aSAlexander Graf static void efi_remove_configuration_table(int i) 1411d98cdf6aSAlexander Graf { 14124182a129SHeinrich Schuchardt struct efi_configuration_table *this = &systab.tables[i]; 14134182a129SHeinrich Schuchardt struct efi_configuration_table *next = &systab.tables[i + 1]; 14144182a129SHeinrich Schuchardt struct efi_configuration_table *end = &systab.tables[systab.nr_tables]; 1415d98cdf6aSAlexander Graf 1416d98cdf6aSAlexander Graf memmove(this, next, (ulong)end - (ulong)next); 1417d98cdf6aSAlexander Graf systab.nr_tables--; 1418d98cdf6aSAlexander Graf } 1419d98cdf6aSAlexander Graf 14206b03cd10SHeinrich Schuchardt /** 142178a88f79SMario Six * efi_install_configuration_table() - adds, updates, or removes a 142278a88f79SMario Six * configuration table 142378a88f79SMario Six * @guid: GUID of the installed table 142478a88f79SMario Six * @table: table to be installed 1425332468f7SHeinrich Schuchardt * 1426332468f7SHeinrich Schuchardt * This function is used for internal calls. For the API implementation of the 1427332468f7SHeinrich Schuchardt * InstallConfigurationTable service see efi_install_configuration_table_ext. 1428332468f7SHeinrich Schuchardt * 142978a88f79SMario Six * Return: status code 1430332468f7SHeinrich Schuchardt */ 1431ab9efa97SHeinrich Schuchardt efi_status_t efi_install_configuration_table(const efi_guid_t *guid, 1432ab9efa97SHeinrich Schuchardt void *table) 1433bee91169SAlexander Graf { 1434b095f3c8SHeinrich Schuchardt struct efi_event *evt; 1435bee91169SAlexander Graf int i; 1436bee91169SAlexander Graf 1437eb68b4efSHeinrich Schuchardt if (!guid) 1438eb68b4efSHeinrich Schuchardt return EFI_INVALID_PARAMETER; 1439eb68b4efSHeinrich Schuchardt 1440b72aaa87SHeinrich Schuchardt /* Check for GUID override */ 1441bee91169SAlexander Graf for (i = 0; i < systab.nr_tables; i++) { 14424182a129SHeinrich Schuchardt if (!guidcmp(guid, &systab.tables[i].guid)) { 1443d98cdf6aSAlexander Graf if (table) 14444182a129SHeinrich Schuchardt systab.tables[i].table = table; 1445d98cdf6aSAlexander Graf else 1446d98cdf6aSAlexander Graf efi_remove_configuration_table(i); 1447b095f3c8SHeinrich Schuchardt goto out; 1448bee91169SAlexander Graf } 1449bee91169SAlexander Graf } 1450bee91169SAlexander Graf 1451d98cdf6aSAlexander Graf if (!table) 1452d98cdf6aSAlexander Graf return EFI_NOT_FOUND; 1453d98cdf6aSAlexander Graf 1454bee91169SAlexander Graf /* No override, check for overflow */ 14554182a129SHeinrich Schuchardt if (i >= EFI_MAX_CONFIGURATION_TABLES) 1456488bf12dSAlexander Graf return EFI_OUT_OF_RESOURCES; 1457bee91169SAlexander Graf 1458bee91169SAlexander Graf /* Add a new entry */ 14594182a129SHeinrich Schuchardt memcpy(&systab.tables[i].guid, guid, sizeof(*guid)); 14604182a129SHeinrich Schuchardt systab.tables[i].table = table; 1461aba5e919SAlexander Graf systab.nr_tables = i + 1; 1462bee91169SAlexander Graf 1463b095f3c8SHeinrich Schuchardt out: 1464b72aaa87SHeinrich Schuchardt /* systab.nr_tables may have changed. So we need to update the CRC32 */ 146555d8ee3bSHeinrich Schuchardt efi_update_table_header_crc32(&systab.hdr); 146655d8ee3bSHeinrich Schuchardt 1467b095f3c8SHeinrich Schuchardt /* Notify that the configuration table was changed */ 1468b095f3c8SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 1469b095f3c8SHeinrich Schuchardt if (evt->group && !guidcmp(evt->group, guid)) { 1470b095f3c8SHeinrich Schuchardt efi_signal_event(evt, false); 1471b095f3c8SHeinrich Schuchardt break; 1472b095f3c8SHeinrich Schuchardt } 1473b095f3c8SHeinrich Schuchardt } 1474b095f3c8SHeinrich Schuchardt 1475488bf12dSAlexander Graf return EFI_SUCCESS; 1476488bf12dSAlexander Graf } 1477488bf12dSAlexander Graf 14786b03cd10SHeinrich Schuchardt /** 147978a88f79SMario Six * efi_install_configuration_table_ex() - Adds, updates, or removes a 14806b03cd10SHeinrich Schuchardt * configuration table. 14816b03cd10SHeinrich Schuchardt * @guid: GUID of the installed table 14826b03cd10SHeinrich Schuchardt * @table: table to be installed 148378a88f79SMario Six * 148478a88f79SMario Six * This function implements the InstallConfigurationTable service. 148578a88f79SMario Six * 148678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 148778a88f79SMario Six * details. 148878a88f79SMario Six * 148978a88f79SMario Six * Return: status code 1490332468f7SHeinrich Schuchardt */ 1491488bf12dSAlexander Graf static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, 1492488bf12dSAlexander Graf void *table) 1493488bf12dSAlexander Graf { 1494778e6af8SRob Clark EFI_ENTRY("%pUl, %p", guid, table); 1495488bf12dSAlexander Graf return EFI_EXIT(efi_install_configuration_table(guid, table)); 1496bee91169SAlexander Graf } 1497bee91169SAlexander Graf 14986b03cd10SHeinrich Schuchardt /** 149978a88f79SMario Six * efi_setup_loaded_image() - initialize a loaded image 150078a88f79SMario Six * @info: loaded image info to be passed to the entry point of the image 150178a88f79SMario Six * @obj: internal object associated with the loaded image 150278a88f79SMario Six * @device_path: device path of the loaded image 150378a88f79SMario Six * @file_path: file path of the loaded image 15046b03cd10SHeinrich Schuchardt * 15056b03cd10SHeinrich Schuchardt * Initialize a loaded_image_info and loaded_image_info object with correct 150695c5553eSRob Clark * protocols, boot-device, etc. 1507332468f7SHeinrich Schuchardt * 150878a88f79SMario Six * Return: status code 150995c5553eSRob Clark */ 1510c982874eSHeinrich Schuchardt efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, 1511c982874eSHeinrich Schuchardt struct efi_device_path *file_path, 1512c982874eSHeinrich Schuchardt struct efi_loaded_image_obj **handle_ptr, 1513c982874eSHeinrich Schuchardt struct efi_loaded_image **info_ptr) 151495c5553eSRob Clark { 151548b66230SHeinrich Schuchardt efi_status_t ret; 1516c982874eSHeinrich Schuchardt struct efi_loaded_image *info; 1517c982874eSHeinrich Schuchardt struct efi_loaded_image_obj *obj; 1518c982874eSHeinrich Schuchardt 1519c982874eSHeinrich Schuchardt info = calloc(1, sizeof(*info)); 1520c982874eSHeinrich Schuchardt if (!info) 1521c982874eSHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 1522c982874eSHeinrich Schuchardt obj = calloc(1, sizeof(*obj)); 1523c982874eSHeinrich Schuchardt if (!obj) { 1524c982874eSHeinrich Schuchardt free(info); 1525c982874eSHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 1526c982874eSHeinrich Schuchardt } 152748b66230SHeinrich Schuchardt 152844549d62SHeinrich Schuchardt /* Add internal object to object list */ 1529d39646a3SHeinrich Schuchardt efi_add_handle(&obj->header); 1530c982874eSHeinrich Schuchardt 1531c982874eSHeinrich Schuchardt if (info_ptr) 1532c982874eSHeinrich Schuchardt *info_ptr = info; 1533c982874eSHeinrich Schuchardt if (handle_ptr) 1534c982874eSHeinrich Schuchardt *handle_ptr = obj; 153595c5553eSRob Clark 153695147313SHeinrich Schuchardt info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; 153795c5553eSRob Clark info->file_path = file_path; 15387e1effceSHeinrich Schuchardt info->system_table = &systab; 153995c5553eSRob Clark 15407df5af6fSHeinrich Schuchardt if (device_path) { 15417df5af6fSHeinrich Schuchardt info->device_handle = efi_dp_find_obj(device_path, NULL); 154248b66230SHeinrich Schuchardt /* 154348b66230SHeinrich Schuchardt * When asking for the device path interface, return 154448b66230SHeinrich Schuchardt * bootefi_device_path 154548b66230SHeinrich Schuchardt */ 1546d39646a3SHeinrich Schuchardt ret = efi_add_protocol(&obj->header, 1547c982874eSHeinrich Schuchardt &efi_guid_device_path, device_path); 154848b66230SHeinrich Schuchardt if (ret != EFI_SUCCESS) 154948b66230SHeinrich Schuchardt goto failure; 15507df5af6fSHeinrich Schuchardt } 155148b66230SHeinrich Schuchardt 155248b66230SHeinrich Schuchardt /* 155348b66230SHeinrich Schuchardt * When asking for the loaded_image interface, just 155448b66230SHeinrich Schuchardt * return handle which points to loaded_image_info 155548b66230SHeinrich Schuchardt */ 1556d39646a3SHeinrich Schuchardt ret = efi_add_protocol(&obj->header, 1557c982874eSHeinrich Schuchardt &efi_guid_loaded_image, info); 155848b66230SHeinrich Schuchardt if (ret != EFI_SUCCESS) 155948b66230SHeinrich Schuchardt goto failure; 156048b66230SHeinrich Schuchardt 1561c9bfb222SLeif Lindholm ret = efi_add_protocol(&obj->header, 1562c9bfb222SLeif Lindholm &efi_guid_hii_string_protocol, 1563c9bfb222SLeif Lindholm (void *)&efi_hii_string); 1564c9bfb222SLeif Lindholm if (ret != EFI_SUCCESS) 1565c9bfb222SLeif Lindholm goto failure; 1566c9bfb222SLeif Lindholm 1567c9bfb222SLeif Lindholm ret = efi_add_protocol(&obj->header, 1568c9bfb222SLeif Lindholm &efi_guid_hii_database_protocol, 1569c9bfb222SLeif Lindholm (void *)&efi_hii_database); 1570c9bfb222SLeif Lindholm if (ret != EFI_SUCCESS) 1571c9bfb222SLeif Lindholm goto failure; 1572c9bfb222SLeif Lindholm 1573*cb728e51SAKASHI Takahiro ret = efi_add_protocol(&obj->header, 1574*cb728e51SAKASHI Takahiro &efi_guid_hii_config_routing_protocol, 1575*cb728e51SAKASHI Takahiro (void *)&efi_hii_config_routing); 1576*cb728e51SAKASHI Takahiro if (ret != EFI_SUCCESS) 1577*cb728e51SAKASHI Takahiro goto failure; 1578*cb728e51SAKASHI Takahiro 157956d92888SHeinrich Schuchardt return ret; 158048b66230SHeinrich Schuchardt failure: 158148b66230SHeinrich Schuchardt printf("ERROR: Failure to install protocols for loaded image\n"); 158256d92888SHeinrich Schuchardt return ret; 158395c5553eSRob Clark } 158495c5553eSRob Clark 15856b03cd10SHeinrich Schuchardt /** 158678a88f79SMario Six * efi_load_image_from_path() - load an image using a file path 15876b03cd10SHeinrich Schuchardt * @file_path: the path of the image to load 15886b03cd10SHeinrich Schuchardt * @buffer: buffer containing the loaded image 158978a88f79SMario Six * 159078a88f79SMario Six * Return: status code 1591332468f7SHeinrich Schuchardt */ 15929975fe96SRob Clark efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, 1593838ee4b4SRob Clark void **buffer) 1594838ee4b4SRob Clark { 1595838ee4b4SRob Clark struct efi_file_info *info = NULL; 1596838ee4b4SRob Clark struct efi_file_handle *f; 1597838ee4b4SRob Clark static efi_status_t ret; 1598b6dd5777SHeinrich Schuchardt efi_uintn_t bs; 1599838ee4b4SRob Clark 1600838ee4b4SRob Clark f = efi_file_from_path(file_path); 1601838ee4b4SRob Clark if (!f) 1602838ee4b4SRob Clark return EFI_DEVICE_ERROR; 1603838ee4b4SRob Clark 1604838ee4b4SRob Clark bs = 0; 1605838ee4b4SRob Clark EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, 1606838ee4b4SRob Clark &bs, info)); 1607838ee4b4SRob Clark if (ret == EFI_BUFFER_TOO_SMALL) { 1608838ee4b4SRob Clark info = malloc(bs); 1609838ee4b4SRob Clark EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, 1610838ee4b4SRob Clark &bs, info)); 1611838ee4b4SRob Clark } 1612838ee4b4SRob Clark if (ret != EFI_SUCCESS) 1613838ee4b4SRob Clark goto error; 1614838ee4b4SRob Clark 1615838ee4b4SRob Clark ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer); 1616838ee4b4SRob Clark if (ret) 1617838ee4b4SRob Clark goto error; 1618838ee4b4SRob Clark 1619b6dd5777SHeinrich Schuchardt bs = info->file_size; 1620b6dd5777SHeinrich Schuchardt EFI_CALL(ret = f->read(f, &bs, *buffer)); 1621838ee4b4SRob Clark 1622838ee4b4SRob Clark error: 1623838ee4b4SRob Clark free(info); 1624838ee4b4SRob Clark EFI_CALL(f->close(f)); 1625838ee4b4SRob Clark 1626838ee4b4SRob Clark if (ret != EFI_SUCCESS) { 1627838ee4b4SRob Clark efi_free_pool(*buffer); 1628838ee4b4SRob Clark *buffer = NULL; 1629838ee4b4SRob Clark } 1630838ee4b4SRob Clark 1631838ee4b4SRob Clark return ret; 1632838ee4b4SRob Clark } 1633838ee4b4SRob Clark 16346b03cd10SHeinrich Schuchardt /** 163578a88f79SMario Six * efi_load_image() - load an EFI image into memory 16366b03cd10SHeinrich Schuchardt * @boot_policy: true for request originating from the boot manager 16376b03cd10SHeinrich Schuchardt * @parent_image: the caller's image handle 16386b03cd10SHeinrich Schuchardt * @file_path: the path of the image to load 16396b03cd10SHeinrich Schuchardt * @source_buffer: memory location from which the image is installed 164078a88f79SMario Six * @source_size: size of the memory area from which the image is installed 16416b03cd10SHeinrich Schuchardt * @image_handle: handle for the newly installed image 164278a88f79SMario Six * 164378a88f79SMario Six * This function implements the LoadImage service. 164478a88f79SMario Six * 164578a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification 164678a88f79SMario Six * for details. 164778a88f79SMario Six * 164878a88f79SMario Six * Return: status code 1649332468f7SHeinrich Schuchardt */ 1650bee91169SAlexander Graf static efi_status_t EFIAPI efi_load_image(bool boot_policy, 1651bee91169SAlexander Graf efi_handle_t parent_image, 1652bee91169SAlexander Graf struct efi_device_path *file_path, 1653bee91169SAlexander Graf void *source_buffer, 16547fb96a10SHeinrich Schuchardt efi_uintn_t source_size, 1655bee91169SAlexander Graf efi_handle_t *image_handle) 1656bee91169SAlexander Graf { 16571c3b2f4aSTom Rini struct efi_loaded_image *info = NULL; 1658c982874eSHeinrich Schuchardt struct efi_loaded_image_obj **image_obj = 1659c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj **)image_handle; 1660b9b17598SHeinrich Schuchardt efi_status_t ret; 1661bee91169SAlexander Graf 16627fb96a10SHeinrich Schuchardt EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, 1663bee91169SAlexander Graf file_path, source_buffer, source_size, image_handle); 1664838ee4b4SRob Clark 166528a4fd46SHeinrich Schuchardt if (!image_handle || !parent_image) { 166628a4fd46SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 166728a4fd46SHeinrich Schuchardt goto error; 166828a4fd46SHeinrich Schuchardt } 166928a4fd46SHeinrich Schuchardt 167028a4fd46SHeinrich Schuchardt if (!source_buffer && !file_path) { 167128a4fd46SHeinrich Schuchardt ret = EFI_NOT_FOUND; 167228a4fd46SHeinrich Schuchardt goto error; 167328a4fd46SHeinrich Schuchardt } 167428a4fd46SHeinrich Schuchardt 1675838ee4b4SRob Clark if (!source_buffer) { 1676838ee4b4SRob Clark struct efi_device_path *dp, *fp; 1677838ee4b4SRob Clark 16789975fe96SRob Clark ret = efi_load_image_from_path(file_path, &source_buffer); 1679b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1680b9b17598SHeinrich Schuchardt goto failure; 1681838ee4b4SRob Clark /* 1682838ee4b4SRob Clark * split file_path which contains both the device and 1683838ee4b4SRob Clark * file parts: 1684838ee4b4SRob Clark */ 1685838ee4b4SRob Clark efi_dp_split_file_path(file_path, &dp, &fp); 1686c982874eSHeinrich Schuchardt ret = efi_setup_loaded_image(dp, fp, image_obj, &info); 1687b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1688b9b17598SHeinrich Schuchardt goto failure; 1689838ee4b4SRob Clark } else { 1690b72aaa87SHeinrich Schuchardt /* In this case, file_path is the "device" path, i.e. 1691838ee4b4SRob Clark * something like a HARDWARE_DEVICE:MEMORY_MAPPED 1692838ee4b4SRob Clark */ 1693c982874eSHeinrich Schuchardt ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info); 1694b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1695c982874eSHeinrich Schuchardt goto error; 1696838ee4b4SRob Clark } 1697c982874eSHeinrich Schuchardt (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info); 1698c982874eSHeinrich Schuchardt if (!(*image_obj)->entry) { 1699b9b17598SHeinrich Schuchardt ret = EFI_UNSUPPORTED; 1700b9b17598SHeinrich Schuchardt goto failure; 1701bee91169SAlexander Graf } 170232fc2ac3SHeinrich Schuchardt info->system_table = &systab; 170332fc2ac3SHeinrich Schuchardt info->parent_handle = parent_image; 1704bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1705b9b17598SHeinrich Schuchardt failure: 1706c982874eSHeinrich Schuchardt efi_delete_handle(*image_handle); 1707c982874eSHeinrich Schuchardt *image_handle = NULL; 1708b9b17598SHeinrich Schuchardt free(info); 170928a4fd46SHeinrich Schuchardt error: 1710b9b17598SHeinrich Schuchardt return EFI_EXIT(ret); 1711bee91169SAlexander Graf } 1712bee91169SAlexander Graf 17136b03cd10SHeinrich Schuchardt /** 1714b72aaa87SHeinrich Schuchardt * efi_start_image() - call the entry point of an image 17156b03cd10SHeinrich Schuchardt * @image_handle: handle of the image 17166b03cd10SHeinrich Schuchardt * @exit_data_size: size of the buffer 17176b03cd10SHeinrich Schuchardt * @exit_data: buffer to receive the exit data of the called image 171878a88f79SMario Six * 171978a88f79SMario Six * This function implements the StartImage service. 172078a88f79SMario Six * 172178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 172278a88f79SMario Six * details. 172378a88f79SMario Six * 172478a88f79SMario Six * Return: status code 1725332468f7SHeinrich Schuchardt */ 1726bee91169SAlexander Graf static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, 1727cc8e3417SHeinrich Schuchardt efi_uintn_t *exit_data_size, 1728cc8e3417SHeinrich Schuchardt u16 **exit_data) 1729bee91169SAlexander Graf { 1730c982874eSHeinrich Schuchardt struct efi_loaded_image_obj *image_obj = 1731c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj *)image_handle; 1732727a1afbSHeinrich Schuchardt efi_status_t ret; 1733bee91169SAlexander Graf 1734bee91169SAlexander Graf EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); 1735bee91169SAlexander Graf 1736f31239acSAlexander Graf efi_is_direct_boot = false; 1737f31239acSAlexander Graf 1738bee91169SAlexander Graf /* call the image! */ 1739c982874eSHeinrich Schuchardt if (setjmp(&image_obj->exit_jmp)) { 1740727a1afbSHeinrich Schuchardt /* 1741727a1afbSHeinrich Schuchardt * We called the entry point of the child image with EFI_CALL 1742727a1afbSHeinrich Schuchardt * in the lines below. The child image called the Exit() boot 1743727a1afbSHeinrich Schuchardt * service efi_exit() which executed the long jump that brought 1744727a1afbSHeinrich Schuchardt * us to the current line. This implies that the second half 1745727a1afbSHeinrich Schuchardt * of the EFI_CALL macro has not been executed. 1746727a1afbSHeinrich Schuchardt */ 1747727a1afbSHeinrich Schuchardt #ifdef CONFIG_ARM 1748727a1afbSHeinrich Schuchardt /* 1749727a1afbSHeinrich Schuchardt * efi_exit() called efi_restore_gd(). We have to undo this 1750727a1afbSHeinrich Schuchardt * otherwise __efi_entry_check() will put the wrong value into 1751727a1afbSHeinrich Schuchardt * app_gd. 1752727a1afbSHeinrich Schuchardt */ 1753727a1afbSHeinrich Schuchardt gd = app_gd; 1754727a1afbSHeinrich Schuchardt #endif 1755727a1afbSHeinrich Schuchardt /* 1756727a1afbSHeinrich Schuchardt * To get ready to call EFI_EXIT below we have to execute the 1757727a1afbSHeinrich Schuchardt * missed out steps of EFI_CALL. 1758727a1afbSHeinrich Schuchardt */ 1759727a1afbSHeinrich Schuchardt assert(__efi_entry_check()); 1760727a1afbSHeinrich Schuchardt debug("%sEFI: %lu returned by started image\n", 1761727a1afbSHeinrich Schuchardt __efi_nesting_dec(), 1762c982874eSHeinrich Schuchardt (unsigned long)((uintptr_t)image_obj->exit_status & 1763727a1afbSHeinrich Schuchardt ~EFI_ERROR_MASK)); 1764c982874eSHeinrich Schuchardt return EFI_EXIT(image_obj->exit_status); 1765a86aeaf2SAlexander Graf } 1766a86aeaf2SAlexander Graf 1767c982874eSHeinrich Schuchardt ret = EFI_CALL(image_obj->entry(image_handle, &systab)); 1768bee91169SAlexander Graf 176956672bf5SAlexander Graf /* 177056672bf5SAlexander Graf * Usually UEFI applications call Exit() instead of returning. 1771b72aaa87SHeinrich Schuchardt * But because the world doesn't consist of ponies and unicorns, 177256672bf5SAlexander Graf * we're happy to emulate that behavior on behalf of a payload 177356672bf5SAlexander Graf * that forgot. 177456672bf5SAlexander Graf */ 177556672bf5SAlexander Graf return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL)); 1776bee91169SAlexander Graf } 1777bee91169SAlexander Graf 17786b03cd10SHeinrich Schuchardt /** 177978a88f79SMario Six * efi_exit() - leave an EFI application or driver 17806b03cd10SHeinrich Schuchardt * @image_handle: handle of the application or driver that is exiting 17816b03cd10SHeinrich Schuchardt * @exit_status: status code 17826b03cd10SHeinrich Schuchardt * @exit_data_size: size of the buffer in bytes 17836b03cd10SHeinrich Schuchardt * @exit_data: buffer with data describing an error 178478a88f79SMario Six * 178578a88f79SMario Six * This function implements the Exit service. 178678a88f79SMario Six * 178778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 178878a88f79SMario Six * details. 178978a88f79SMario Six * 179078a88f79SMario Six * Return: status code 1791332468f7SHeinrich Schuchardt */ 1792a86aeaf2SAlexander Graf static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, 1793ab9efa97SHeinrich Schuchardt efi_status_t exit_status, 1794cc8e3417SHeinrich Schuchardt efi_uintn_t exit_data_size, 1795cc8e3417SHeinrich Schuchardt u16 *exit_data) 1796bee91169SAlexander Graf { 179744549d62SHeinrich Schuchardt /* 179844549d62SHeinrich Schuchardt * TODO: We should call the unload procedure of the loaded 179944549d62SHeinrich Schuchardt * image protocol. 180044549d62SHeinrich Schuchardt */ 1801c982874eSHeinrich Schuchardt struct efi_loaded_image_obj *image_obj = 1802c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj *)image_handle; 1803a86aeaf2SAlexander Graf 1804cc8e3417SHeinrich Schuchardt EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, 1805bee91169SAlexander Graf exit_data_size, exit_data); 1806a86aeaf2SAlexander Graf 1807a148920eSAlexander Graf /* Make sure entry/exit counts for EFI world cross-overs match */ 1808727a1afbSHeinrich Schuchardt EFI_EXIT(exit_status); 1809da94073bSHeinrich Schuchardt 1810a148920eSAlexander Graf /* 1811a148920eSAlexander Graf * But longjmp out with the U-Boot gd, not the application's, as 1812a148920eSAlexander Graf * the other end is a setjmp call inside EFI context. 1813a148920eSAlexander Graf */ 1814a148920eSAlexander Graf efi_restore_gd(); 1815a148920eSAlexander Graf 1816c982874eSHeinrich Schuchardt image_obj->exit_status = exit_status; 1817c982874eSHeinrich Schuchardt longjmp(&image_obj->exit_jmp, 1); 1818a86aeaf2SAlexander Graf 1819a86aeaf2SAlexander Graf panic("EFI application exited"); 1820bee91169SAlexander Graf } 1821bee91169SAlexander Graf 18226b03cd10SHeinrich Schuchardt /** 182378a88f79SMario Six * efi_unload_image() - unload an EFI image 182478a88f79SMario Six * @image_handle: handle of the image to be unloaded 1825332468f7SHeinrich Schuchardt * 1826332468f7SHeinrich Schuchardt * This function implements the UnloadImage service. 1827332468f7SHeinrich Schuchardt * 182878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 182978a88f79SMario Six * details. 183078a88f79SMario Six * 183178a88f79SMario Six * Return: status code 1832332468f7SHeinrich Schuchardt */ 18332074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) 1834bee91169SAlexander Graf { 1835bee91169SAlexander Graf struct efi_object *efiobj; 1836bee91169SAlexander Graf 1837bee91169SAlexander Graf EFI_ENTRY("%p", image_handle); 1838bee91169SAlexander Graf efiobj = efi_search_obj(image_handle); 1839bee91169SAlexander Graf if (efiobj) 1840bee91169SAlexander Graf list_del(&efiobj->link); 1841bee91169SAlexander Graf 1842bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1843bee91169SAlexander Graf } 1844bee91169SAlexander Graf 18456b03cd10SHeinrich Schuchardt /** 1846f31239acSAlexander Graf * efi_exit_caches() - fix up caches for EFI payloads if necessary 1847f31239acSAlexander Graf */ 1848f31239acSAlexander Graf static void efi_exit_caches(void) 1849f31239acSAlexander Graf { 1850f31239acSAlexander Graf #if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) 1851f31239acSAlexander Graf /* 1852f31239acSAlexander Graf * Grub on 32bit ARM needs to have caches disabled before jumping into 1853f31239acSAlexander Graf * a zImage, but does not know of all cache layers. Give it a hand. 1854f31239acSAlexander Graf */ 1855f31239acSAlexander Graf if (efi_is_direct_boot) 1856f31239acSAlexander Graf cleanup_before_linux(); 1857f31239acSAlexander Graf #endif 1858f31239acSAlexander Graf } 1859f31239acSAlexander Graf 1860f31239acSAlexander Graf /** 186178a88f79SMario Six * efi_exit_boot_services() - stop all boot services 186278a88f79SMario Six * @image_handle: handle of the loaded image 186378a88f79SMario Six * @map_key: key of the memory map 1864332468f7SHeinrich Schuchardt * 1865332468f7SHeinrich Schuchardt * This function implements the ExitBootServices service. 186678a88f79SMario Six * 1867332468f7SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification 1868332468f7SHeinrich Schuchardt * for details. 1869332468f7SHeinrich Schuchardt * 187078a88f79SMario Six * All timer events are disabled. For exit boot services events the 187178a88f79SMario Six * notification function is called. The boot services are disabled in the 187278a88f79SMario Six * system table. 1873cc20ed03SHeinrich Schuchardt * 187478a88f79SMario Six * Return: status code 1875332468f7SHeinrich Schuchardt */ 18762074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, 1877bee91169SAlexander Graf unsigned long map_key) 1878bee91169SAlexander Graf { 187943bce442SHeinrich Schuchardt struct efi_event *evt; 1880152a263cSHeinrich Schuchardt 1881bee91169SAlexander Graf EFI_ENTRY("%p, %ld", image_handle, map_key); 1882bee91169SAlexander Graf 18831fcb7ea2SHeinrich Schuchardt /* Check that the caller has read the current memory map */ 18841fcb7ea2SHeinrich Schuchardt if (map_key != efi_memory_map_key) 18851fcb7ea2SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 18861fcb7ea2SHeinrich Schuchardt 1887cc20ed03SHeinrich Schuchardt /* Make sure that notification functions are not called anymore */ 1888cc20ed03SHeinrich Schuchardt efi_tpl = TPL_HIGH_LEVEL; 1889cc20ed03SHeinrich Schuchardt 1890cc20ed03SHeinrich Schuchardt /* Check if ExitBootServices has already been called */ 1891cc20ed03SHeinrich Schuchardt if (!systab.boottime) 1892cc20ed03SHeinrich Schuchardt return EFI_EXIT(EFI_SUCCESS); 1893cc20ed03SHeinrich Schuchardt 1894b095f3c8SHeinrich Schuchardt /* Add related events to the event group */ 1895b095f3c8SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 1896b095f3c8SHeinrich Schuchardt if (evt->type == EVT_SIGNAL_EXIT_BOOT_SERVICES) 1897b095f3c8SHeinrich Schuchardt evt->group = &efi_guid_event_group_exit_boot_services; 1898b095f3c8SHeinrich Schuchardt } 1899152a263cSHeinrich Schuchardt /* Notify that ExitBootServices is invoked. */ 190043bce442SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 1901b095f3c8SHeinrich Schuchardt if (evt->group && 1902b095f3c8SHeinrich Schuchardt !guidcmp(evt->group, 1903b095f3c8SHeinrich Schuchardt &efi_guid_event_group_exit_boot_services)) { 190443bce442SHeinrich Schuchardt efi_signal_event(evt, false); 1905b095f3c8SHeinrich Schuchardt break; 1906b095f3c8SHeinrich Schuchardt } 1907152a263cSHeinrich Schuchardt } 1908152a263cSHeinrich Schuchardt 1909b72aaa87SHeinrich Schuchardt /* TODO: Should persist EFI variables here */ 1910ad644e7cSRob Clark 1911b7b8410aSAlexander Graf board_quiesce_devices(); 1912b7b8410aSAlexander Graf 1913f31239acSAlexander Graf /* Fix up caches for EFI payloads if necessary */ 1914f31239acSAlexander Graf efi_exit_caches(); 1915f31239acSAlexander Graf 1916bee91169SAlexander Graf /* This stops all lingering devices */ 1917bee91169SAlexander Graf bootm_disable_interrupts(); 1918bee91169SAlexander Graf 1919cc20ed03SHeinrich Schuchardt /* Disable boot time services */ 1920cc20ed03SHeinrich Schuchardt systab.con_in_handle = NULL; 1921cc20ed03SHeinrich Schuchardt systab.con_in = NULL; 1922cc20ed03SHeinrich Schuchardt systab.con_out_handle = NULL; 1923cc20ed03SHeinrich Schuchardt systab.con_out = NULL; 1924cc20ed03SHeinrich Schuchardt systab.stderr_handle = NULL; 1925cc20ed03SHeinrich Schuchardt systab.std_err = NULL; 1926cc20ed03SHeinrich Schuchardt systab.boottime = NULL; 1927cc20ed03SHeinrich Schuchardt 1928cc20ed03SHeinrich Schuchardt /* Recalculate CRC32 */ 1929640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&systab.hdr); 1930cc20ed03SHeinrich Schuchardt 1931bee91169SAlexander Graf /* Give the payload some time to boot */ 1932b3d60900SHeinrich Schuchardt efi_set_watchdog(0); 1933bee91169SAlexander Graf WATCHDOG_RESET(); 1934bee91169SAlexander Graf 1935bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1936bee91169SAlexander Graf } 1937bee91169SAlexander Graf 19386b03cd10SHeinrich Schuchardt /** 193978a88f79SMario Six * efi_get_next_monotonic_count() - get next value of the counter 194078a88f79SMario Six * @count: returned value of the counter 1941332468f7SHeinrich Schuchardt * 1942332468f7SHeinrich Schuchardt * This function implements the NextMonotonicCount service. 1943332468f7SHeinrich Schuchardt * 194478a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 194578a88f79SMario Six * details. 194678a88f79SMario Six * 194778a88f79SMario Six * Return: status code 1948332468f7SHeinrich Schuchardt */ 1949bee91169SAlexander Graf static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) 1950bee91169SAlexander Graf { 1951ab9efa97SHeinrich Schuchardt static uint64_t mono; 1952ab9efa97SHeinrich Schuchardt 1953bee91169SAlexander Graf EFI_ENTRY("%p", count); 1954bee91169SAlexander Graf *count = mono++; 1955bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1956bee91169SAlexander Graf } 1957bee91169SAlexander Graf 19586b03cd10SHeinrich Schuchardt /** 195978a88f79SMario Six * efi_stall() - sleep 19606b03cd10SHeinrich Schuchardt * @microseconds: period to sleep in microseconds 196178a88f79SMario Six * 196278a88f79SMario Six * This function implements the Stall service. 196378a88f79SMario Six * 196478a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 196578a88f79SMario Six * details. 196678a88f79SMario Six * 196778a88f79SMario Six * Return: status code 1968332468f7SHeinrich Schuchardt */ 1969bee91169SAlexander Graf static efi_status_t EFIAPI efi_stall(unsigned long microseconds) 1970bee91169SAlexander Graf { 1971bee91169SAlexander Graf EFI_ENTRY("%ld", microseconds); 1972bee91169SAlexander Graf udelay(microseconds); 1973bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1974bee91169SAlexander Graf } 1975bee91169SAlexander Graf 19766b03cd10SHeinrich Schuchardt /** 197778a88f79SMario Six * efi_set_watchdog_timer() - reset the watchdog timer 19786b03cd10SHeinrich Schuchardt * @timeout: seconds before reset by watchdog 19796b03cd10SHeinrich Schuchardt * @watchdog_code: code to be logged when resetting 19806b03cd10SHeinrich Schuchardt * @data_size: size of buffer in bytes 19816b03cd10SHeinrich Schuchardt * @watchdog_data: buffer with data describing the reset reason 198278a88f79SMario Six * 198378a88f79SMario Six * This function implements the SetWatchdogTimer service. 198478a88f79SMario Six * 198578a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 198678a88f79SMario Six * details. 198778a88f79SMario Six * 198878a88f79SMario Six * Return: status code 1989332468f7SHeinrich Schuchardt */ 1990bee91169SAlexander Graf static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, 1991bee91169SAlexander Graf uint64_t watchdog_code, 1992bee91169SAlexander Graf unsigned long data_size, 1993bee91169SAlexander Graf uint16_t *watchdog_data) 1994bee91169SAlexander Graf { 1995dee37fc9SMasahiro Yamada EFI_ENTRY("%ld, 0x%llx, %ld, %p", timeout, watchdog_code, 1996bee91169SAlexander Graf data_size, watchdog_data); 1997b3d60900SHeinrich Schuchardt return EFI_EXIT(efi_set_watchdog(timeout)); 1998bee91169SAlexander Graf } 1999bee91169SAlexander Graf 20006b03cd10SHeinrich Schuchardt /** 200178a88f79SMario Six * efi_close_protocol() - close a protocol 20026b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be closed 20036b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to close 20046b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 20056b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 200678a88f79SMario Six * 200778a88f79SMario Six * This function implements the CloseProtocol service. 200878a88f79SMario Six * 200978a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 201078a88f79SMario Six * details. 201178a88f79SMario Six * 201278a88f79SMario Six * Return: status code 2013332468f7SHeinrich Schuchardt */ 20142074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, 20155a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, 20162074f700SHeinrich Schuchardt efi_handle_t agent_handle, 20172074f700SHeinrich Schuchardt efi_handle_t controller_handle) 2018bee91169SAlexander Graf { 20193b8a489cSHeinrich Schuchardt struct efi_handler *handler; 20203b8a489cSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 20213b8a489cSHeinrich Schuchardt struct efi_open_protocol_info_item *pos; 20223b8a489cSHeinrich Schuchardt efi_status_t r; 20233b8a489cSHeinrich Schuchardt 2024778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle, 2025bee91169SAlexander Graf controller_handle); 20263b8a489cSHeinrich Schuchardt 20273b8a489cSHeinrich Schuchardt if (!agent_handle) { 20283b8a489cSHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 20293b8a489cSHeinrich Schuchardt goto out; 20303b8a489cSHeinrich Schuchardt } 20313b8a489cSHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 20323b8a489cSHeinrich Schuchardt if (r != EFI_SUCCESS) 20333b8a489cSHeinrich Schuchardt goto out; 20343b8a489cSHeinrich Schuchardt 20353b8a489cSHeinrich Schuchardt r = EFI_NOT_FOUND; 20363b8a489cSHeinrich Schuchardt list_for_each_entry_safe(item, pos, &handler->open_infos, link) { 20373b8a489cSHeinrich Schuchardt if (item->info.agent_handle == agent_handle && 20383b8a489cSHeinrich Schuchardt item->info.controller_handle == controller_handle) { 20393b8a489cSHeinrich Schuchardt efi_delete_open_info(item); 20403b8a489cSHeinrich Schuchardt r = EFI_SUCCESS; 20413b8a489cSHeinrich Schuchardt break; 20423b8a489cSHeinrich Schuchardt } 20433b8a489cSHeinrich Schuchardt } 20443b8a489cSHeinrich Schuchardt out: 20453b8a489cSHeinrich Schuchardt return EFI_EXIT(r); 2046bee91169SAlexander Graf } 2047bee91169SAlexander Graf 20486b03cd10SHeinrich Schuchardt /** 204978a88f79SMario Six * efi_open_protocol_information() - provide information about then open status 20506b03cd10SHeinrich Schuchardt * of a protocol on a handle 20516b03cd10SHeinrich Schuchardt * @handle: handle for which the information shall be retrieved 20526b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 20536b03cd10SHeinrich Schuchardt * @entry_buffer: buffer to receive the open protocol information 20546b03cd10SHeinrich Schuchardt * @entry_count: number of entries available in the buffer 205578a88f79SMario Six * 205678a88f79SMario Six * This function implements the OpenProtocolInformation service. 205778a88f79SMario Six * 205878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 205978a88f79SMario Six * details. 206078a88f79SMario Six * 206178a88f79SMario Six * Return: status code 2062332468f7SHeinrich Schuchardt */ 2063ab9efa97SHeinrich Schuchardt static efi_status_t EFIAPI efi_open_protocol_information( 2064ab9efa97SHeinrich Schuchardt efi_handle_t handle, const efi_guid_t *protocol, 2065bee91169SAlexander Graf struct efi_open_protocol_info_entry **entry_buffer, 2066f5a2a938SHeinrich Schuchardt efi_uintn_t *entry_count) 2067bee91169SAlexander Graf { 2068e3fbbc36SHeinrich Schuchardt unsigned long buffer_size; 2069e3fbbc36SHeinrich Schuchardt unsigned long count; 2070e3fbbc36SHeinrich Schuchardt struct efi_handler *handler; 2071e3fbbc36SHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2072e3fbbc36SHeinrich Schuchardt efi_status_t r; 2073e3fbbc36SHeinrich Schuchardt 2074778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer, 2075bee91169SAlexander Graf entry_count); 2076e3fbbc36SHeinrich Schuchardt 2077e3fbbc36SHeinrich Schuchardt /* Check parameters */ 2078e3fbbc36SHeinrich Schuchardt if (!entry_buffer) { 2079e3fbbc36SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 2080e3fbbc36SHeinrich Schuchardt goto out; 2081e3fbbc36SHeinrich Schuchardt } 2082e3fbbc36SHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 2083e3fbbc36SHeinrich Schuchardt if (r != EFI_SUCCESS) 2084e3fbbc36SHeinrich Schuchardt goto out; 2085e3fbbc36SHeinrich Schuchardt 2086e3fbbc36SHeinrich Schuchardt /* Count entries */ 2087e3fbbc36SHeinrich Schuchardt count = 0; 2088e3fbbc36SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2089e3fbbc36SHeinrich Schuchardt if (item->info.open_count) 2090e3fbbc36SHeinrich Schuchardt ++count; 2091e3fbbc36SHeinrich Schuchardt } 2092e3fbbc36SHeinrich Schuchardt *entry_count = count; 2093e3fbbc36SHeinrich Schuchardt *entry_buffer = NULL; 2094e3fbbc36SHeinrich Schuchardt if (!count) { 2095e3fbbc36SHeinrich Schuchardt r = EFI_SUCCESS; 2096e3fbbc36SHeinrich Schuchardt goto out; 2097e3fbbc36SHeinrich Schuchardt } 2098e3fbbc36SHeinrich Schuchardt 2099e3fbbc36SHeinrich Schuchardt /* Copy entries */ 2100e3fbbc36SHeinrich Schuchardt buffer_size = count * sizeof(struct efi_open_protocol_info_entry); 2101eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2102e3fbbc36SHeinrich Schuchardt (void **)entry_buffer); 2103e3fbbc36SHeinrich Schuchardt if (r != EFI_SUCCESS) 2104e3fbbc36SHeinrich Schuchardt goto out; 2105e3fbbc36SHeinrich Schuchardt list_for_each_entry_reverse(item, &handler->open_infos, link) { 2106e3fbbc36SHeinrich Schuchardt if (item->info.open_count) 2107e3fbbc36SHeinrich Schuchardt (*entry_buffer)[--count] = item->info; 2108e3fbbc36SHeinrich Schuchardt } 2109e3fbbc36SHeinrich Schuchardt out: 2110e3fbbc36SHeinrich Schuchardt return EFI_EXIT(r); 2111bee91169SAlexander Graf } 2112bee91169SAlexander Graf 21136b03cd10SHeinrich Schuchardt /** 211478a88f79SMario Six * efi_protocols_per_handle() - get protocols installed on a handle 21156b03cd10SHeinrich Schuchardt * @handle: handle for which the information is retrieved 21166b03cd10SHeinrich Schuchardt * @protocol_buffer: buffer with protocol GUIDs 21176b03cd10SHeinrich Schuchardt * @protocol_buffer_count: number of entries in the buffer 211878a88f79SMario Six * 211978a88f79SMario Six * This function implements the ProtocolsPerHandleService. 212078a88f79SMario Six * 212178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 212278a88f79SMario Six * details. 212378a88f79SMario Six * 212478a88f79SMario Six * Return: status code 2125332468f7SHeinrich Schuchardt */ 21262074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_protocols_per_handle( 21272074f700SHeinrich Schuchardt efi_handle_t handle, efi_guid_t ***protocol_buffer, 2128f5a2a938SHeinrich Schuchardt efi_uintn_t *protocol_buffer_count) 2129bee91169SAlexander Graf { 2130c0ebfc86Sxypron.glpk@gmx.de unsigned long buffer_size; 2131c0ebfc86Sxypron.glpk@gmx.de struct efi_object *efiobj; 213269fb6b1aSHeinrich Schuchardt struct list_head *protocol_handle; 2133c0ebfc86Sxypron.glpk@gmx.de efi_status_t r; 2134c0ebfc86Sxypron.glpk@gmx.de 2135bee91169SAlexander Graf EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, 2136bee91169SAlexander Graf protocol_buffer_count); 2137c0ebfc86Sxypron.glpk@gmx.de 2138c0ebfc86Sxypron.glpk@gmx.de if (!handle || !protocol_buffer || !protocol_buffer_count) 2139c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 2140c0ebfc86Sxypron.glpk@gmx.de 2141c0ebfc86Sxypron.glpk@gmx.de *protocol_buffer = NULL; 2142661c8327SRob Clark *protocol_buffer_count = 0; 2143c0ebfc86Sxypron.glpk@gmx.de 214469fb6b1aSHeinrich Schuchardt efiobj = efi_search_obj(handle); 214569fb6b1aSHeinrich Schuchardt if (!efiobj) 214669fb6b1aSHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 2147c0ebfc86Sxypron.glpk@gmx.de 2148c0ebfc86Sxypron.glpk@gmx.de /* Count protocols */ 214969fb6b1aSHeinrich Schuchardt list_for_each(protocol_handle, &efiobj->protocols) { 2150c0ebfc86Sxypron.glpk@gmx.de ++*protocol_buffer_count; 2151c0ebfc86Sxypron.glpk@gmx.de } 215269fb6b1aSHeinrich Schuchardt 2153b72aaa87SHeinrich Schuchardt /* Copy GUIDs */ 2154c0ebfc86Sxypron.glpk@gmx.de if (*protocol_buffer_count) { 215569fb6b1aSHeinrich Schuchardt size_t j = 0; 215669fb6b1aSHeinrich Schuchardt 215769fb6b1aSHeinrich Schuchardt buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count; 2158eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2159c0ebfc86Sxypron.glpk@gmx.de (void **)protocol_buffer); 2160c0ebfc86Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 2161c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(r); 216269fb6b1aSHeinrich Schuchardt list_for_each(protocol_handle, &efiobj->protocols) { 216369fb6b1aSHeinrich Schuchardt struct efi_handler *protocol; 216469fb6b1aSHeinrich Schuchardt 216569fb6b1aSHeinrich Schuchardt protocol = list_entry(protocol_handle, 216669fb6b1aSHeinrich Schuchardt struct efi_handler, link); 216769fb6b1aSHeinrich Schuchardt (*protocol_buffer)[j] = (void *)protocol->guid; 2168c0ebfc86Sxypron.glpk@gmx.de ++j; 2169c0ebfc86Sxypron.glpk@gmx.de } 2170c0ebfc86Sxypron.glpk@gmx.de } 2171c0ebfc86Sxypron.glpk@gmx.de 2172c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(EFI_SUCCESS); 2173bee91169SAlexander Graf } 2174bee91169SAlexander Graf 21756b03cd10SHeinrich Schuchardt /** 217678a88f79SMario Six * efi_locate_handle_buffer() - locate handles implementing a protocol 21776b03cd10SHeinrich Schuchardt * @search_type: selection criterion 21786b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 21796b03cd10SHeinrich Schuchardt * @search_key: registration key 21806b03cd10SHeinrich Schuchardt * @no_handles: number of returned handles 21816b03cd10SHeinrich Schuchardt * @buffer: buffer with the returned handles 218278a88f79SMario Six * 218378a88f79SMario Six * This function implements the LocateHandleBuffer service. 218478a88f79SMario Six * 218578a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 218678a88f79SMario Six * details. 218778a88f79SMario Six * 218878a88f79SMario Six * Return: status code 2189332468f7SHeinrich Schuchardt */ 2190bee91169SAlexander Graf static efi_status_t EFIAPI efi_locate_handle_buffer( 2191bee91169SAlexander Graf enum efi_locate_search_type search_type, 21925a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, void *search_key, 2193f5a2a938SHeinrich Schuchardt efi_uintn_t *no_handles, efi_handle_t **buffer) 2194bee91169SAlexander Graf { 2195c2e703f9Sxypron.glpk@gmx.de efi_status_t r; 2196f5a2a938SHeinrich Schuchardt efi_uintn_t buffer_size = 0; 2197c2e703f9Sxypron.glpk@gmx.de 2198778e6af8SRob Clark EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, 2199bee91169SAlexander Graf no_handles, buffer); 2200c2e703f9Sxypron.glpk@gmx.de 2201c2e703f9Sxypron.glpk@gmx.de if (!no_handles || !buffer) { 2202c2e703f9Sxypron.glpk@gmx.de r = EFI_INVALID_PARAMETER; 2203c2e703f9Sxypron.glpk@gmx.de goto out; 2204c2e703f9Sxypron.glpk@gmx.de } 2205c2e703f9Sxypron.glpk@gmx.de *no_handles = 0; 2206c2e703f9Sxypron.glpk@gmx.de *buffer = NULL; 2207c2e703f9Sxypron.glpk@gmx.de r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, 2208c2e703f9Sxypron.glpk@gmx.de *buffer); 2209c2e703f9Sxypron.glpk@gmx.de if (r != EFI_BUFFER_TOO_SMALL) 2210c2e703f9Sxypron.glpk@gmx.de goto out; 2211eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2212c2e703f9Sxypron.glpk@gmx.de (void **)buffer); 2213c2e703f9Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 2214c2e703f9Sxypron.glpk@gmx.de goto out; 2215c2e703f9Sxypron.glpk@gmx.de r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, 2216c2e703f9Sxypron.glpk@gmx.de *buffer); 2217c2e703f9Sxypron.glpk@gmx.de if (r == EFI_SUCCESS) 22182074f700SHeinrich Schuchardt *no_handles = buffer_size / sizeof(efi_handle_t); 2219c2e703f9Sxypron.glpk@gmx.de out: 2220c2e703f9Sxypron.glpk@gmx.de return EFI_EXIT(r); 2221bee91169SAlexander Graf } 2222bee91169SAlexander Graf 22236b03cd10SHeinrich Schuchardt /** 222478a88f79SMario Six * efi_locate_protocol() - find an interface implementing a protocol 22256b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 22266b03cd10SHeinrich Schuchardt * @registration: registration key passed to the notification function 22276b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 222878a88f79SMario Six * 222978a88f79SMario Six * This function implements the LocateProtocol service. 223078a88f79SMario Six * 223178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 223278a88f79SMario Six * details. 223378a88f79SMario Six * 223478a88f79SMario Six * Return: status code 2235332468f7SHeinrich Schuchardt */ 22365a9682d0SHeinrich Schuchardt static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, 2237bee91169SAlexander Graf void *registration, 2238bee91169SAlexander Graf void **protocol_interface) 2239bee91169SAlexander Graf { 224088adae5eSxypron.glpk@gmx.de struct list_head *lhandle; 22419172cd91SHeinrich Schuchardt efi_status_t ret; 2242bee91169SAlexander Graf 2243778e6af8SRob Clark EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface); 224488adae5eSxypron.glpk@gmx.de 224588adae5eSxypron.glpk@gmx.de if (!protocol || !protocol_interface) 224688adae5eSxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 224788adae5eSxypron.glpk@gmx.de 224888adae5eSxypron.glpk@gmx.de list_for_each(lhandle, &efi_obj_list) { 224988adae5eSxypron.glpk@gmx.de struct efi_object *efiobj; 22509172cd91SHeinrich Schuchardt struct efi_handler *handler; 225188adae5eSxypron.glpk@gmx.de 225288adae5eSxypron.glpk@gmx.de efiobj = list_entry(lhandle, struct efi_object, link); 225388adae5eSxypron.glpk@gmx.de 2254fae0118eSHeinrich Schuchardt ret = efi_search_protocol(efiobj, protocol, &handler); 22559172cd91SHeinrich Schuchardt if (ret == EFI_SUCCESS) { 22569172cd91SHeinrich Schuchardt *protocol_interface = handler->protocol_interface; 2257bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 2258bee91169SAlexander Graf } 2259bee91169SAlexander Graf } 226088adae5eSxypron.glpk@gmx.de *protocol_interface = NULL; 2261bee91169SAlexander Graf 2262bee91169SAlexander Graf return EFI_EXIT(EFI_NOT_FOUND); 2263bee91169SAlexander Graf } 2264bee91169SAlexander Graf 22656b03cd10SHeinrich Schuchardt /** 226678a88f79SMario Six * efi_locate_device_path() - Get the device path and handle of an device 22676b03cd10SHeinrich Schuchardt * implementing a protocol 22686b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 22696b03cd10SHeinrich Schuchardt * @device_path: device path 22706b03cd10SHeinrich Schuchardt * @device: handle of the device 227178a88f79SMario Six * 227278a88f79SMario Six * This function implements the LocateDevicePath service. 227378a88f79SMario Six * 227478a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 227578a88f79SMario Six * details. 227678a88f79SMario Six * 227778a88f79SMario Six * Return: status code 2278ae2c85c1SHeinrich Schuchardt */ 2279ae2c85c1SHeinrich Schuchardt static efi_status_t EFIAPI efi_locate_device_path( 2280ae2c85c1SHeinrich Schuchardt const efi_guid_t *protocol, 2281ae2c85c1SHeinrich Schuchardt struct efi_device_path **device_path, 2282ae2c85c1SHeinrich Schuchardt efi_handle_t *device) 2283ae2c85c1SHeinrich Schuchardt { 2284ae2c85c1SHeinrich Schuchardt struct efi_device_path *dp; 2285ae2c85c1SHeinrich Schuchardt size_t i; 2286ae2c85c1SHeinrich Schuchardt struct efi_handler *handler; 2287ae2c85c1SHeinrich Schuchardt efi_handle_t *handles; 2288ae2c85c1SHeinrich Schuchardt size_t len, len_dp; 2289ae2c85c1SHeinrich Schuchardt size_t len_best = 0; 2290ae2c85c1SHeinrich Schuchardt efi_uintn_t no_handles; 2291ae2c85c1SHeinrich Schuchardt u8 *remainder; 2292ae2c85c1SHeinrich Schuchardt efi_status_t ret; 2293ae2c85c1SHeinrich Schuchardt 2294ae2c85c1SHeinrich Schuchardt EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); 2295ae2c85c1SHeinrich Schuchardt 2296ae2c85c1SHeinrich Schuchardt if (!protocol || !device_path || !*device_path || !device) { 2297ae2c85c1SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 2298ae2c85c1SHeinrich Schuchardt goto out; 2299ae2c85c1SHeinrich Schuchardt } 2300ae2c85c1SHeinrich Schuchardt 2301ae2c85c1SHeinrich Schuchardt /* Find end of device path */ 2302f6dd3f35SHeinrich Schuchardt len = efi_dp_instance_size(*device_path); 2303ae2c85c1SHeinrich Schuchardt 2304ae2c85c1SHeinrich Schuchardt /* Get all handles implementing the protocol */ 2305ae2c85c1SHeinrich Schuchardt ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, 2306ae2c85c1SHeinrich Schuchardt &no_handles, &handles)); 2307ae2c85c1SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2308ae2c85c1SHeinrich Schuchardt goto out; 2309ae2c85c1SHeinrich Schuchardt 2310ae2c85c1SHeinrich Schuchardt for (i = 0; i < no_handles; ++i) { 2311ae2c85c1SHeinrich Schuchardt /* Find the device path protocol */ 2312ae2c85c1SHeinrich Schuchardt ret = efi_search_protocol(handles[i], &efi_guid_device_path, 2313ae2c85c1SHeinrich Schuchardt &handler); 2314ae2c85c1SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2315ae2c85c1SHeinrich Schuchardt continue; 2316ae2c85c1SHeinrich Schuchardt dp = (struct efi_device_path *)handler->protocol_interface; 2317f6dd3f35SHeinrich Schuchardt len_dp = efi_dp_instance_size(dp); 2318ae2c85c1SHeinrich Schuchardt /* 2319ae2c85c1SHeinrich Schuchardt * This handle can only be a better fit 2320ae2c85c1SHeinrich Schuchardt * if its device path length is longer than the best fit and 2321ae2c85c1SHeinrich Schuchardt * if its device path length is shorter of equal the searched 2322ae2c85c1SHeinrich Schuchardt * device path. 2323ae2c85c1SHeinrich Schuchardt */ 2324ae2c85c1SHeinrich Schuchardt if (len_dp <= len_best || len_dp > len) 2325ae2c85c1SHeinrich Schuchardt continue; 2326ae2c85c1SHeinrich Schuchardt /* Check if dp is a subpath of device_path */ 2327ae2c85c1SHeinrich Schuchardt if (memcmp(*device_path, dp, len_dp)) 2328ae2c85c1SHeinrich Schuchardt continue; 2329ae2c85c1SHeinrich Schuchardt *device = handles[i]; 2330ae2c85c1SHeinrich Schuchardt len_best = len_dp; 2331ae2c85c1SHeinrich Schuchardt } 2332ae2c85c1SHeinrich Schuchardt if (len_best) { 2333ae2c85c1SHeinrich Schuchardt remainder = (u8 *)*device_path + len_best; 2334ae2c85c1SHeinrich Schuchardt *device_path = (struct efi_device_path *)remainder; 2335ae2c85c1SHeinrich Schuchardt ret = EFI_SUCCESS; 2336ae2c85c1SHeinrich Schuchardt } else { 2337ae2c85c1SHeinrich Schuchardt ret = EFI_NOT_FOUND; 2338ae2c85c1SHeinrich Schuchardt } 2339ae2c85c1SHeinrich Schuchardt out: 2340ae2c85c1SHeinrich Schuchardt return EFI_EXIT(ret); 2341ae2c85c1SHeinrich Schuchardt } 2342ae2c85c1SHeinrich Schuchardt 23436b03cd10SHeinrich Schuchardt /** 234478a88f79SMario Six * efi_install_multiple_protocol_interfaces() - Install multiple protocol 234578a88f79SMario Six * interfaces 234678a88f79SMario Six * @handle: handle on which the protocol interfaces shall be installed 234778a88f79SMario Six * @...: NULL terminated argument list with pairs of protocol GUIDS and 234878a88f79SMario Six * interfaces 2349332468f7SHeinrich Schuchardt * 2350332468f7SHeinrich Schuchardt * This function implements the MultipleProtocolInterfaces service. 2351332468f7SHeinrich Schuchardt * 235278a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 235378a88f79SMario Six * details. 235478a88f79SMario Six * 235578a88f79SMario Six * Return: status code 2356332468f7SHeinrich Schuchardt */ 2357faea1041SHeinrich Schuchardt static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces 2358faea1041SHeinrich Schuchardt (efi_handle_t *handle, ...) 2359bee91169SAlexander Graf { 2360bee91169SAlexander Graf EFI_ENTRY("%p", handle); 236158b83586Sxypron.glpk@gmx.de 2362beb077a2SAlexander Graf efi_va_list argptr; 23635a9682d0SHeinrich Schuchardt const efi_guid_t *protocol; 236458b83586Sxypron.glpk@gmx.de void *protocol_interface; 236558b83586Sxypron.glpk@gmx.de efi_status_t r = EFI_SUCCESS; 236658b83586Sxypron.glpk@gmx.de int i = 0; 236758b83586Sxypron.glpk@gmx.de 236858b83586Sxypron.glpk@gmx.de if (!handle) 236958b83586Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 237058b83586Sxypron.glpk@gmx.de 2371beb077a2SAlexander Graf efi_va_start(argptr, handle); 237258b83586Sxypron.glpk@gmx.de for (;;) { 2373beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 237458b83586Sxypron.glpk@gmx.de if (!protocol) 237558b83586Sxypron.glpk@gmx.de break; 2376beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 23771760ef57SHeinrich Schuchardt r = EFI_CALL(efi_install_protocol_interface( 23781760ef57SHeinrich Schuchardt handle, protocol, 237958b83586Sxypron.glpk@gmx.de EFI_NATIVE_INTERFACE, 23801760ef57SHeinrich Schuchardt protocol_interface)); 238158b83586Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 238258b83586Sxypron.glpk@gmx.de break; 238358b83586Sxypron.glpk@gmx.de i++; 238458b83586Sxypron.glpk@gmx.de } 2385beb077a2SAlexander Graf efi_va_end(argptr); 238658b83586Sxypron.glpk@gmx.de if (r == EFI_SUCCESS) 238758b83586Sxypron.glpk@gmx.de return EFI_EXIT(r); 238858b83586Sxypron.glpk@gmx.de 238962471e46SHeinrich Schuchardt /* If an error occurred undo all changes. */ 2390beb077a2SAlexander Graf efi_va_start(argptr, handle); 239158b83586Sxypron.glpk@gmx.de for (; i; --i) { 2392beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2393beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 2394faea1041SHeinrich Schuchardt EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol, 2395cd534083SHeinrich Schuchardt protocol_interface)); 239658b83586Sxypron.glpk@gmx.de } 2397beb077a2SAlexander Graf efi_va_end(argptr); 239858b83586Sxypron.glpk@gmx.de 239958b83586Sxypron.glpk@gmx.de return EFI_EXIT(r); 2400bee91169SAlexander Graf } 2401bee91169SAlexander Graf 24026b03cd10SHeinrich Schuchardt /** 240378a88f79SMario Six * efi_uninstall_multiple_protocol_interfaces() - uninstall multiple protocol 240478a88f79SMario Six * interfaces 240578a88f79SMario Six * @handle: handle from which the protocol interfaces shall be removed 240678a88f79SMario Six * @...: NULL terminated argument list with pairs of protocol GUIDS and 24076b03cd10SHeinrich Schuchardt * interfaces 2408332468f7SHeinrich Schuchardt * 2409332468f7SHeinrich Schuchardt * This function implements the UninstallMultipleProtocolInterfaces service. 2410332468f7SHeinrich Schuchardt * 241178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 241278a88f79SMario Six * details. 241378a88f79SMario Six * 241478a88f79SMario Six * Return: status code 2415332468f7SHeinrich Schuchardt */ 2416bee91169SAlexander Graf static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( 2417faea1041SHeinrich Schuchardt efi_handle_t handle, ...) 2418bee91169SAlexander Graf { 2419bee91169SAlexander Graf EFI_ENTRY("%p", handle); 2420843ce54cSHeinrich Schuchardt 2421beb077a2SAlexander Graf efi_va_list argptr; 2422843ce54cSHeinrich Schuchardt const efi_guid_t *protocol; 2423843ce54cSHeinrich Schuchardt void *protocol_interface; 2424843ce54cSHeinrich Schuchardt efi_status_t r = EFI_SUCCESS; 2425843ce54cSHeinrich Schuchardt size_t i = 0; 2426843ce54cSHeinrich Schuchardt 2427843ce54cSHeinrich Schuchardt if (!handle) 2428bee91169SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 2429843ce54cSHeinrich Schuchardt 2430beb077a2SAlexander Graf efi_va_start(argptr, handle); 2431843ce54cSHeinrich Schuchardt for (;;) { 2432beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2433843ce54cSHeinrich Schuchardt if (!protocol) 2434843ce54cSHeinrich Schuchardt break; 2435beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 24369b47f13bSHeinrich Schuchardt r = efi_uninstall_protocol(handle, protocol, 24379b47f13bSHeinrich Schuchardt protocol_interface); 2438843ce54cSHeinrich Schuchardt if (r != EFI_SUCCESS) 2439843ce54cSHeinrich Schuchardt break; 2440843ce54cSHeinrich Schuchardt i++; 2441843ce54cSHeinrich Schuchardt } 2442beb077a2SAlexander Graf efi_va_end(argptr); 24439b47f13bSHeinrich Schuchardt if (r == EFI_SUCCESS) { 24449b47f13bSHeinrich Schuchardt /* If the last protocol has been removed, delete the handle. */ 24459b47f13bSHeinrich Schuchardt if (list_empty(&handle->protocols)) { 24469b47f13bSHeinrich Schuchardt list_del(&handle->link); 24479b47f13bSHeinrich Schuchardt free(handle); 24489b47f13bSHeinrich Schuchardt } 2449843ce54cSHeinrich Schuchardt return EFI_EXIT(r); 24509b47f13bSHeinrich Schuchardt } 2451843ce54cSHeinrich Schuchardt 2452843ce54cSHeinrich Schuchardt /* If an error occurred undo all changes. */ 2453beb077a2SAlexander Graf efi_va_start(argptr, handle); 2454843ce54cSHeinrich Schuchardt for (; i; --i) { 2455beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2456beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 2457843ce54cSHeinrich Schuchardt EFI_CALL(efi_install_protocol_interface(&handle, protocol, 2458843ce54cSHeinrich Schuchardt EFI_NATIVE_INTERFACE, 2459843ce54cSHeinrich Schuchardt protocol_interface)); 2460843ce54cSHeinrich Schuchardt } 2461beb077a2SAlexander Graf efi_va_end(argptr); 2462843ce54cSHeinrich Schuchardt 2463e2373021SHeinrich Schuchardt /* In case of an error always return EFI_INVALID_PARAMETER */ 2464e2373021SHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 2465bee91169SAlexander Graf } 2466bee91169SAlexander Graf 24676b03cd10SHeinrich Schuchardt /** 246878a88f79SMario Six * efi_calculate_crc32() - calculate cyclic redundancy code 24696b03cd10SHeinrich Schuchardt * @data: buffer with data 24706b03cd10SHeinrich Schuchardt * @data_size: size of buffer in bytes 24716b03cd10SHeinrich Schuchardt * @crc32_p: cyclic redundancy code 247278a88f79SMario Six * 247378a88f79SMario Six * This function implements the CalculateCrc32 service. 247478a88f79SMario Six * 247578a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 247678a88f79SMario Six * details. 247778a88f79SMario Six * 247878a88f79SMario Six * Return: status code 2479332468f7SHeinrich Schuchardt */ 24808aa8360eSHeinrich Schuchardt static efi_status_t EFIAPI efi_calculate_crc32(const void *data, 24818aa8360eSHeinrich Schuchardt efi_uintn_t data_size, 24828aa8360eSHeinrich Schuchardt u32 *crc32_p) 2483bee91169SAlexander Graf { 24848aa8360eSHeinrich Schuchardt EFI_ENTRY("%p, %zu", data, data_size); 2485bee91169SAlexander Graf *crc32_p = crc32(0, data, data_size); 2486bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 2487bee91169SAlexander Graf } 2488bee91169SAlexander Graf 24896b03cd10SHeinrich Schuchardt /** 249078a88f79SMario Six * efi_copy_mem() - copy memory 24916b03cd10SHeinrich Schuchardt * @destination: destination of the copy operation 24926b03cd10SHeinrich Schuchardt * @source: source of the copy operation 24936b03cd10SHeinrich Schuchardt * @length: number of bytes to copy 249478a88f79SMario Six * 249578a88f79SMario Six * This function implements the CopyMem service. 249678a88f79SMario Six * 249778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 249878a88f79SMario Six * details. 2499332468f7SHeinrich Schuchardt */ 2500fc05a959SHeinrich Schuchardt static void EFIAPI efi_copy_mem(void *destination, const void *source, 2501fc05a959SHeinrich Schuchardt size_t length) 2502bee91169SAlexander Graf { 2503fc05a959SHeinrich Schuchardt EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length); 25040bc81a71SHeinrich Schuchardt memmove(destination, source, length); 2505f7c78176SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 2506bee91169SAlexander Graf } 2507bee91169SAlexander Graf 25086b03cd10SHeinrich Schuchardt /** 250978a88f79SMario Six * efi_set_mem() - Fill memory with a byte value. 25106b03cd10SHeinrich Schuchardt * @buffer: buffer to fill 25116b03cd10SHeinrich Schuchardt * @size: size of buffer in bytes 25126b03cd10SHeinrich Schuchardt * @value: byte to copy to the buffer 251378a88f79SMario Six * 251478a88f79SMario Six * This function implements the SetMem service. 251578a88f79SMario Six * 251678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 251778a88f79SMario Six * details. 2518332468f7SHeinrich Schuchardt */ 2519fc05a959SHeinrich Schuchardt static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) 2520bee91169SAlexander Graf { 2521fc05a959SHeinrich Schuchardt EFI_ENTRY("%p, %ld, 0x%x", buffer, (unsigned long)size, value); 2522bee91169SAlexander Graf memset(buffer, value, size); 2523f7c78176SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 2524bee91169SAlexander Graf } 2525bee91169SAlexander Graf 25266b03cd10SHeinrich Schuchardt /** 252778a88f79SMario Six * efi_protocol_open() - open protocol interface on a handle 25286b03cd10SHeinrich Schuchardt * @handler: handler of a protocol 25296b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 25306b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 25316b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 25326b03cd10SHeinrich Schuchardt * @attributes: attributes indicating how to open the protocol 253378a88f79SMario Six * 253478a88f79SMario Six * Return: status code 2535191a41ccSHeinrich Schuchardt */ 2536191a41ccSHeinrich Schuchardt static efi_status_t efi_protocol_open( 2537191a41ccSHeinrich Schuchardt struct efi_handler *handler, 2538191a41ccSHeinrich Schuchardt void **protocol_interface, void *agent_handle, 2539191a41ccSHeinrich Schuchardt void *controller_handle, uint32_t attributes) 2540191a41ccSHeinrich Schuchardt { 2541191a41ccSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2542191a41ccSHeinrich Schuchardt struct efi_open_protocol_info_entry *match = NULL; 2543191a41ccSHeinrich Schuchardt bool opened_by_driver = false; 2544191a41ccSHeinrich Schuchardt bool opened_exclusive = false; 2545191a41ccSHeinrich Schuchardt 2546191a41ccSHeinrich Schuchardt /* If there is no agent, only return the interface */ 2547191a41ccSHeinrich Schuchardt if (!agent_handle) 2548191a41ccSHeinrich Schuchardt goto out; 2549191a41ccSHeinrich Schuchardt 2550191a41ccSHeinrich Schuchardt /* For TEST_PROTOCOL ignore interface attribute */ 2551191a41ccSHeinrich Schuchardt if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) 2552191a41ccSHeinrich Schuchardt *protocol_interface = NULL; 2553191a41ccSHeinrich Schuchardt 2554191a41ccSHeinrich Schuchardt /* 2555191a41ccSHeinrich Schuchardt * Check if the protocol is already opened by a driver with the same 2556191a41ccSHeinrich Schuchardt * attributes or opened exclusively 2557191a41ccSHeinrich Schuchardt */ 2558191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2559191a41ccSHeinrich Schuchardt if (item->info.agent_handle == agent_handle) { 2560191a41ccSHeinrich Schuchardt if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) && 2561191a41ccSHeinrich Schuchardt (item->info.attributes == attributes)) 2562191a41ccSHeinrich Schuchardt return EFI_ALREADY_STARTED; 2563191a41ccSHeinrich Schuchardt } 2564191a41ccSHeinrich Schuchardt if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) 2565191a41ccSHeinrich Schuchardt opened_exclusive = true; 2566191a41ccSHeinrich Schuchardt } 2567191a41ccSHeinrich Schuchardt 2568191a41ccSHeinrich Schuchardt /* Only one controller can open the protocol exclusively */ 2569191a41ccSHeinrich Schuchardt if (opened_exclusive && attributes & 2570191a41ccSHeinrich Schuchardt (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER)) 2571191a41ccSHeinrich Schuchardt return EFI_ACCESS_DENIED; 2572191a41ccSHeinrich Schuchardt 2573191a41ccSHeinrich Schuchardt /* Prepare exclusive opening */ 2574191a41ccSHeinrich Schuchardt if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { 2575191a41ccSHeinrich Schuchardt /* Try to disconnect controllers */ 2576191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2577191a41ccSHeinrich Schuchardt if (item->info.attributes == 2578191a41ccSHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_DRIVER) 2579191a41ccSHeinrich Schuchardt EFI_CALL(efi_disconnect_controller( 2580191a41ccSHeinrich Schuchardt item->info.controller_handle, 2581191a41ccSHeinrich Schuchardt item->info.agent_handle, 2582191a41ccSHeinrich Schuchardt NULL)); 2583191a41ccSHeinrich Schuchardt } 2584191a41ccSHeinrich Schuchardt opened_by_driver = false; 2585191a41ccSHeinrich Schuchardt /* Check if all controllers are disconnected */ 2586191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2587191a41ccSHeinrich Schuchardt if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) 2588191a41ccSHeinrich Schuchardt opened_by_driver = true; 2589191a41ccSHeinrich Schuchardt } 25904f37fa47SHeinrich Schuchardt /* Only one controller can be connected */ 2591191a41ccSHeinrich Schuchardt if (opened_by_driver) 2592191a41ccSHeinrich Schuchardt return EFI_ACCESS_DENIED; 2593191a41ccSHeinrich Schuchardt } 2594191a41ccSHeinrich Schuchardt 2595191a41ccSHeinrich Schuchardt /* Find existing entry */ 2596191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2597191a41ccSHeinrich Schuchardt if (item->info.agent_handle == agent_handle && 2598191a41ccSHeinrich Schuchardt item->info.controller_handle == controller_handle) 2599191a41ccSHeinrich Schuchardt match = &item->info; 2600191a41ccSHeinrich Schuchardt } 2601191a41ccSHeinrich Schuchardt /* None found, create one */ 2602191a41ccSHeinrich Schuchardt if (!match) { 2603191a41ccSHeinrich Schuchardt match = efi_create_open_info(handler); 2604191a41ccSHeinrich Schuchardt if (!match) 2605191a41ccSHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 2606191a41ccSHeinrich Schuchardt } 2607191a41ccSHeinrich Schuchardt 2608191a41ccSHeinrich Schuchardt match->agent_handle = agent_handle; 2609191a41ccSHeinrich Schuchardt match->controller_handle = controller_handle; 2610191a41ccSHeinrich Schuchardt match->attributes = attributes; 2611191a41ccSHeinrich Schuchardt match->open_count++; 2612191a41ccSHeinrich Schuchardt 2613191a41ccSHeinrich Schuchardt out: 2614191a41ccSHeinrich Schuchardt /* For TEST_PROTOCOL ignore interface attribute. */ 2615191a41ccSHeinrich Schuchardt if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) 2616191a41ccSHeinrich Schuchardt *protocol_interface = handler->protocol_interface; 2617191a41ccSHeinrich Schuchardt 2618191a41ccSHeinrich Schuchardt return EFI_SUCCESS; 2619191a41ccSHeinrich Schuchardt } 2620191a41ccSHeinrich Schuchardt 26216b03cd10SHeinrich Schuchardt /** 262278a88f79SMario Six * efi_open_protocol() - open protocol interface on a handle 26236b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be opened 26246b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 26256b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 26266b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 26276b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 26286b03cd10SHeinrich Schuchardt * @attributes: attributes indicating how to open the protocol 262978a88f79SMario Six * 263078a88f79SMario Six * This function implements the OpenProtocol interface. 263178a88f79SMario Six * 263278a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 263378a88f79SMario Six * details. 263478a88f79SMario Six * 263578a88f79SMario Six * Return: status code 2636332468f7SHeinrich Schuchardt */ 2637faea1041SHeinrich Schuchardt static efi_status_t EFIAPI efi_open_protocol 2638faea1041SHeinrich Schuchardt (efi_handle_t handle, const efi_guid_t *protocol, 2639faea1041SHeinrich Schuchardt void **protocol_interface, efi_handle_t agent_handle, 2640faea1041SHeinrich Schuchardt efi_handle_t controller_handle, uint32_t attributes) 2641bee91169SAlexander Graf { 264280286e8fSHeinrich Schuchardt struct efi_handler *handler; 264369baec67Sxypron.glpk@gmx.de efi_status_t r = EFI_INVALID_PARAMETER; 2644bee91169SAlexander Graf 2645778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol, 2646bee91169SAlexander Graf protocol_interface, agent_handle, controller_handle, 2647bee91169SAlexander Graf attributes); 2648b5349f74Sxypron.glpk@gmx.de 264969baec67Sxypron.glpk@gmx.de if (!handle || !protocol || 265069baec67Sxypron.glpk@gmx.de (!protocol_interface && attributes != 265169baec67Sxypron.glpk@gmx.de EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) { 265269baec67Sxypron.glpk@gmx.de goto out; 265369baec67Sxypron.glpk@gmx.de } 265469baec67Sxypron.glpk@gmx.de 265569baec67Sxypron.glpk@gmx.de switch (attributes) { 265669baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: 265769baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_GET_PROTOCOL: 265869baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_TEST_PROTOCOL: 265969baec67Sxypron.glpk@gmx.de break; 266069baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: 266169baec67Sxypron.glpk@gmx.de if (controller_handle == handle) 266269baec67Sxypron.glpk@gmx.de goto out; 2663191a41ccSHeinrich Schuchardt /* fall-through */ 266469baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_DRIVER: 266569baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE: 2666191a41ccSHeinrich Schuchardt /* Check that the controller handle is valid */ 2667191a41ccSHeinrich Schuchardt if (!efi_search_obj(controller_handle)) 266869baec67Sxypron.glpk@gmx.de goto out; 2669191a41ccSHeinrich Schuchardt /* fall-through */ 267069baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_EXCLUSIVE: 2671191a41ccSHeinrich Schuchardt /* Check that the agent handle is valid */ 2672191a41ccSHeinrich Schuchardt if (!efi_search_obj(agent_handle)) 267369baec67Sxypron.glpk@gmx.de goto out; 267469baec67Sxypron.glpk@gmx.de break; 267569baec67Sxypron.glpk@gmx.de default: 2676b5349f74Sxypron.glpk@gmx.de goto out; 2677b5349f74Sxypron.glpk@gmx.de } 2678b5349f74Sxypron.glpk@gmx.de 267980286e8fSHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 268080286e8fSHeinrich Schuchardt if (r != EFI_SUCCESS) 2681bee91169SAlexander Graf goto out; 2682bee91169SAlexander Graf 2683191a41ccSHeinrich Schuchardt r = efi_protocol_open(handler, protocol_interface, agent_handle, 2684191a41ccSHeinrich Schuchardt controller_handle, attributes); 2685bee91169SAlexander Graf out: 2686bee91169SAlexander Graf return EFI_EXIT(r); 2687bee91169SAlexander Graf } 2688bee91169SAlexander Graf 26896b03cd10SHeinrich Schuchardt /** 269078a88f79SMario Six * efi_handle_protocol() - get interface of a protocol on a handle 26916b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be opened 26926b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 26936b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 269478a88f79SMario Six * 269578a88f79SMario Six * This function implements the HandleProtocol service. 269678a88f79SMario Six * 269778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 269878a88f79SMario Six * details. 269978a88f79SMario Six * 270078a88f79SMario Six * Return: status code 2701332468f7SHeinrich Schuchardt */ 27022074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, 27035a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, 2704bee91169SAlexander Graf void **protocol_interface) 2705bee91169SAlexander Graf { 27068e1d329fSxypron.glpk@gmx.de return efi_open_protocol(handle, protocol, protocol_interface, NULL, 27078e1d329fSxypron.glpk@gmx.de NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); 2708bee91169SAlexander Graf } 2709bee91169SAlexander Graf 27106b03cd10SHeinrich Schuchardt /** 271178a88f79SMario Six * efi_bind_controller() - bind a single driver to a controller 27126b03cd10SHeinrich Schuchardt * @controller_handle: controller handle 27136b03cd10SHeinrich Schuchardt * @driver_image_handle: driver handle 27146b03cd10SHeinrich Schuchardt * @remain_device_path: remaining path 271578a88f79SMario Six * 271678a88f79SMario Six * Return: status code 27176b03cd10SHeinrich Schuchardt */ 2718f0959dbeSHeinrich Schuchardt static efi_status_t efi_bind_controller( 2719f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2720f0959dbeSHeinrich Schuchardt efi_handle_t driver_image_handle, 2721f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path) 2722f0959dbeSHeinrich Schuchardt { 2723f0959dbeSHeinrich Schuchardt struct efi_driver_binding_protocol *binding_protocol; 2724f0959dbeSHeinrich Schuchardt efi_status_t r; 2725f0959dbeSHeinrich Schuchardt 2726f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_open_protocol(driver_image_handle, 2727f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2728f0959dbeSHeinrich Schuchardt (void **)&binding_protocol, 2729f0959dbeSHeinrich Schuchardt driver_image_handle, NULL, 2730f0959dbeSHeinrich Schuchardt EFI_OPEN_PROTOCOL_GET_PROTOCOL)); 2731f0959dbeSHeinrich Schuchardt if (r != EFI_SUCCESS) 2732f0959dbeSHeinrich Schuchardt return r; 2733f0959dbeSHeinrich Schuchardt r = EFI_CALL(binding_protocol->supported(binding_protocol, 2734f0959dbeSHeinrich Schuchardt controller_handle, 2735f0959dbeSHeinrich Schuchardt remain_device_path)); 2736f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2737f0959dbeSHeinrich Schuchardt r = EFI_CALL(binding_protocol->start(binding_protocol, 2738f0959dbeSHeinrich Schuchardt controller_handle, 2739f0959dbeSHeinrich Schuchardt remain_device_path)); 2740f0959dbeSHeinrich Schuchardt EFI_CALL(efi_close_protocol(driver_image_handle, 2741f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2742f0959dbeSHeinrich Schuchardt driver_image_handle, NULL)); 2743f0959dbeSHeinrich Schuchardt return r; 2744f0959dbeSHeinrich Schuchardt } 2745f0959dbeSHeinrich Schuchardt 27466b03cd10SHeinrich Schuchardt /** 274778a88f79SMario Six * efi_connect_single_controller() - connect a single driver to a controller 27486b03cd10SHeinrich Schuchardt * @controller_handle: controller 27496b03cd10SHeinrich Schuchardt * @driver_image_handle: driver 2750b72aaa87SHeinrich Schuchardt * @remain_device_path: remaining path 275178a88f79SMario Six * 275278a88f79SMario Six * Return: status code 27536b03cd10SHeinrich Schuchardt */ 2754f0959dbeSHeinrich Schuchardt static efi_status_t efi_connect_single_controller( 2755f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2756f0959dbeSHeinrich Schuchardt efi_handle_t *driver_image_handle, 2757f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path) 2758f0959dbeSHeinrich Schuchardt { 2759f0959dbeSHeinrich Schuchardt efi_handle_t *buffer; 2760f0959dbeSHeinrich Schuchardt size_t count; 2761f0959dbeSHeinrich Schuchardt size_t i; 2762f0959dbeSHeinrich Schuchardt efi_status_t r; 2763f0959dbeSHeinrich Schuchardt size_t connected = 0; 2764f0959dbeSHeinrich Schuchardt 2765f0959dbeSHeinrich Schuchardt /* Get buffer with all handles with driver binding protocol */ 2766f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, 2767f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2768f0959dbeSHeinrich Schuchardt NULL, &count, &buffer)); 2769f0959dbeSHeinrich Schuchardt if (r != EFI_SUCCESS) 2770f0959dbeSHeinrich Schuchardt return r; 2771f0959dbeSHeinrich Schuchardt 2772f0959dbeSHeinrich Schuchardt /* Context Override */ 2773f0959dbeSHeinrich Schuchardt if (driver_image_handle) { 2774f0959dbeSHeinrich Schuchardt for (; *driver_image_handle; ++driver_image_handle) { 2775f0959dbeSHeinrich Schuchardt for (i = 0; i < count; ++i) { 2776f0959dbeSHeinrich Schuchardt if (buffer[i] == *driver_image_handle) { 2777f0959dbeSHeinrich Schuchardt buffer[i] = NULL; 2778f0959dbeSHeinrich Schuchardt r = efi_bind_controller( 2779f0959dbeSHeinrich Schuchardt controller_handle, 2780f0959dbeSHeinrich Schuchardt *driver_image_handle, 2781f0959dbeSHeinrich Schuchardt remain_device_path); 2782f0959dbeSHeinrich Schuchardt /* 2783f0959dbeSHeinrich Schuchardt * For drivers that do not support the 2784f0959dbeSHeinrich Schuchardt * controller or are already connected 2785f0959dbeSHeinrich Schuchardt * we receive an error code here. 2786f0959dbeSHeinrich Schuchardt */ 2787f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2788f0959dbeSHeinrich Schuchardt ++connected; 2789f0959dbeSHeinrich Schuchardt } 2790f0959dbeSHeinrich Schuchardt } 2791f0959dbeSHeinrich Schuchardt } 2792f0959dbeSHeinrich Schuchardt } 2793f0959dbeSHeinrich Schuchardt 2794f0959dbeSHeinrich Schuchardt /* 2795f0959dbeSHeinrich Schuchardt * TODO: Some overrides are not yet implemented: 2796f0959dbeSHeinrich Schuchardt * - Platform Driver Override 2797f0959dbeSHeinrich Schuchardt * - Driver Family Override Search 2798f0959dbeSHeinrich Schuchardt * - Bus Specific Driver Override 2799f0959dbeSHeinrich Schuchardt */ 2800f0959dbeSHeinrich Schuchardt 2801f0959dbeSHeinrich Schuchardt /* Driver Binding Search */ 2802f0959dbeSHeinrich Schuchardt for (i = 0; i < count; ++i) { 2803f0959dbeSHeinrich Schuchardt if (buffer[i]) { 2804f0959dbeSHeinrich Schuchardt r = efi_bind_controller(controller_handle, 2805f0959dbeSHeinrich Schuchardt buffer[i], 2806f0959dbeSHeinrich Schuchardt remain_device_path); 2807f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2808f0959dbeSHeinrich Schuchardt ++connected; 2809f0959dbeSHeinrich Schuchardt } 2810f0959dbeSHeinrich Schuchardt } 2811f0959dbeSHeinrich Schuchardt 2812f0959dbeSHeinrich Schuchardt efi_free_pool(buffer); 2813f0959dbeSHeinrich Schuchardt if (!connected) 2814f0959dbeSHeinrich Schuchardt return EFI_NOT_FOUND; 2815f0959dbeSHeinrich Schuchardt return EFI_SUCCESS; 2816f0959dbeSHeinrich Schuchardt } 2817f0959dbeSHeinrich Schuchardt 28186b03cd10SHeinrich Schuchardt /** 281978a88f79SMario Six * efi_connect_controller() - connect a controller to a driver 282078a88f79SMario Six * @controller_handle: handle of the controller 282178a88f79SMario Six * @driver_image_handle: handle of the driver 282278a88f79SMario Six * @remain_device_path: device path of a child controller 282378a88f79SMario Six * @recursive: true to connect all child controllers 2824f0959dbeSHeinrich Schuchardt * 2825f0959dbeSHeinrich Schuchardt * This function implements the ConnectController service. 282678a88f79SMario Six * 282778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 282878a88f79SMario Six * details. 2829f0959dbeSHeinrich Schuchardt * 2830f0959dbeSHeinrich Schuchardt * First all driver binding protocol handles are tried for binding drivers. 2831b72aaa87SHeinrich Schuchardt * Afterwards all handles that have opened a protocol of the controller 2832f0959dbeSHeinrich Schuchardt * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. 2833f0959dbeSHeinrich Schuchardt * 283478a88f79SMario Six * Return: status code 2835f0959dbeSHeinrich Schuchardt */ 2836f0959dbeSHeinrich Schuchardt static efi_status_t EFIAPI efi_connect_controller( 2837f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2838f0959dbeSHeinrich Schuchardt efi_handle_t *driver_image_handle, 2839f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path, 2840f0959dbeSHeinrich Schuchardt bool recursive) 2841f0959dbeSHeinrich Schuchardt { 2842f0959dbeSHeinrich Schuchardt efi_status_t r; 2843f0959dbeSHeinrich Schuchardt efi_status_t ret = EFI_NOT_FOUND; 2844f0959dbeSHeinrich Schuchardt struct efi_object *efiobj; 2845f0959dbeSHeinrich Schuchardt 2846d178836bSHeinrich Schuchardt EFI_ENTRY("%p, %p, %pD, %d", controller_handle, driver_image_handle, 2847f0959dbeSHeinrich Schuchardt remain_device_path, recursive); 2848f0959dbeSHeinrich Schuchardt 2849f0959dbeSHeinrich Schuchardt efiobj = efi_search_obj(controller_handle); 2850f0959dbeSHeinrich Schuchardt if (!efiobj) { 2851f0959dbeSHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 2852f0959dbeSHeinrich Schuchardt goto out; 2853f0959dbeSHeinrich Schuchardt } 2854f0959dbeSHeinrich Schuchardt 2855f0959dbeSHeinrich Schuchardt r = efi_connect_single_controller(controller_handle, 2856f0959dbeSHeinrich Schuchardt driver_image_handle, 2857f0959dbeSHeinrich Schuchardt remain_device_path); 2858f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2859f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2860f0959dbeSHeinrich Schuchardt if (recursive) { 2861f0959dbeSHeinrich Schuchardt struct efi_handler *handler; 2862f0959dbeSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2863f0959dbeSHeinrich Schuchardt 2864f0959dbeSHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 2865f0959dbeSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2866f0959dbeSHeinrich Schuchardt if (item->info.attributes & 2867f0959dbeSHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 2868f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_connect_controller( 2869f0959dbeSHeinrich Schuchardt item->info.controller_handle, 2870f0959dbeSHeinrich Schuchardt driver_image_handle, 2871f0959dbeSHeinrich Schuchardt remain_device_path, 2872f0959dbeSHeinrich Schuchardt recursive)); 2873f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2874f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2875f0959dbeSHeinrich Schuchardt } 2876f0959dbeSHeinrich Schuchardt } 2877f0959dbeSHeinrich Schuchardt } 2878f0959dbeSHeinrich Schuchardt } 2879f0959dbeSHeinrich Schuchardt /* Check for child controller specified by end node */ 2880f0959dbeSHeinrich Schuchardt if (ret != EFI_SUCCESS && remain_device_path && 2881f0959dbeSHeinrich Schuchardt remain_device_path->type == DEVICE_PATH_TYPE_END) 2882f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2883f0959dbeSHeinrich Schuchardt out: 2884f0959dbeSHeinrich Schuchardt return EFI_EXIT(ret); 2885f0959dbeSHeinrich Schuchardt } 2886f0959dbeSHeinrich Schuchardt 28876b03cd10SHeinrich Schuchardt /** 288878a88f79SMario Six * efi_reinstall_protocol_interface() - reinstall protocol interface 288978a88f79SMario Six * @handle: handle on which the protocol shall be reinstalled 289078a88f79SMario Six * @protocol: GUID of the protocol to be installed 289178a88f79SMario Six * @old_interface: interface to be removed 289278a88f79SMario Six * @new_interface: interface to be installed 2893e861a120SHeinrich Schuchardt * 2894e861a120SHeinrich Schuchardt * This function implements the ReinstallProtocolInterface service. 289578a88f79SMario Six * 289678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 289778a88f79SMario Six * details. 2898e861a120SHeinrich Schuchardt * 2899e861a120SHeinrich Schuchardt * The old interface is uninstalled. The new interface is installed. 2900e861a120SHeinrich Schuchardt * Drivers are connected. 2901e861a120SHeinrich Schuchardt * 290278a88f79SMario Six * Return: status code 2903e861a120SHeinrich Schuchardt */ 2904e861a120SHeinrich Schuchardt static efi_status_t EFIAPI efi_reinstall_protocol_interface( 2905e861a120SHeinrich Schuchardt efi_handle_t handle, const efi_guid_t *protocol, 2906e861a120SHeinrich Schuchardt void *old_interface, void *new_interface) 2907e861a120SHeinrich Schuchardt { 2908e861a120SHeinrich Schuchardt efi_status_t ret; 2909e861a120SHeinrich Schuchardt 2910e861a120SHeinrich Schuchardt EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface, 2911e861a120SHeinrich Schuchardt new_interface); 29129b47f13bSHeinrich Schuchardt 29139b47f13bSHeinrich Schuchardt /* Uninstall protocol but do not delete handle */ 29149b47f13bSHeinrich Schuchardt ret = efi_uninstall_protocol(handle, protocol, old_interface); 2915e861a120SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2916e861a120SHeinrich Schuchardt goto out; 29179b47f13bSHeinrich Schuchardt 29189b47f13bSHeinrich Schuchardt /* Install the new protocol */ 29199b47f13bSHeinrich Schuchardt ret = efi_add_protocol(handle, protocol, new_interface); 29209b47f13bSHeinrich Schuchardt /* 29219b47f13bSHeinrich Schuchardt * The UEFI spec does not specify what should happen to the handle 29229b47f13bSHeinrich Schuchardt * if in case of an error no protocol interface remains on the handle. 29239b47f13bSHeinrich Schuchardt * So let's do nothing here. 29249b47f13bSHeinrich Schuchardt */ 2925e861a120SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2926e861a120SHeinrich Schuchardt goto out; 2927e861a120SHeinrich Schuchardt /* 2928e861a120SHeinrich Schuchardt * The returned status code has to be ignored. 2929e861a120SHeinrich Schuchardt * Do not create an error if no suitable driver for the handle exists. 2930e861a120SHeinrich Schuchardt */ 2931e861a120SHeinrich Schuchardt EFI_CALL(efi_connect_controller(handle, NULL, NULL, true)); 2932e861a120SHeinrich Schuchardt out: 2933e861a120SHeinrich Schuchardt return EFI_EXIT(ret); 2934e861a120SHeinrich Schuchardt } 2935e861a120SHeinrich Schuchardt 29366b03cd10SHeinrich Schuchardt /** 293778a88f79SMario Six * efi_get_child_controllers() - get all child controllers associated to a driver 29386b03cd10SHeinrich Schuchardt * @efiobj: handle of the controller 29396b03cd10SHeinrich Schuchardt * @driver_handle: handle of the driver 29406b03cd10SHeinrich Schuchardt * @number_of_children: number of child controllers 29416b03cd10SHeinrich Schuchardt * @child_handle_buffer: handles of the the child controllers 294278a88f79SMario Six * 294378a88f79SMario Six * The allocated buffer has to be freed with free(). 294478a88f79SMario Six * 294578a88f79SMario Six * Return: status code 29463f9b0042SHeinrich Schuchardt */ 29473f9b0042SHeinrich Schuchardt static efi_status_t efi_get_child_controllers( 29483f9b0042SHeinrich Schuchardt struct efi_object *efiobj, 29493f9b0042SHeinrich Schuchardt efi_handle_t driver_handle, 29503f9b0042SHeinrich Schuchardt efi_uintn_t *number_of_children, 29513f9b0042SHeinrich Schuchardt efi_handle_t **child_handle_buffer) 29523f9b0042SHeinrich Schuchardt { 29533f9b0042SHeinrich Schuchardt struct efi_handler *handler; 29543f9b0042SHeinrich Schuchardt struct efi_open_protocol_info_item *item; 29553f9b0042SHeinrich Schuchardt efi_uintn_t count = 0, i; 29563f9b0042SHeinrich Schuchardt bool duplicate; 29573f9b0042SHeinrich Schuchardt 29583f9b0042SHeinrich Schuchardt /* Count all child controller associations */ 29593f9b0042SHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 29603f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 29613f9b0042SHeinrich Schuchardt if (item->info.agent_handle == driver_handle && 29623f9b0042SHeinrich Schuchardt item->info.attributes & 29633f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) 29643f9b0042SHeinrich Schuchardt ++count; 29653f9b0042SHeinrich Schuchardt } 29663f9b0042SHeinrich Schuchardt } 29673f9b0042SHeinrich Schuchardt /* 29683f9b0042SHeinrich Schuchardt * Create buffer. In case of duplicate child controller assignments 29693f9b0042SHeinrich Schuchardt * the buffer will be too large. But that does not harm. 29703f9b0042SHeinrich Schuchardt */ 29713f9b0042SHeinrich Schuchardt *number_of_children = 0; 29723f9b0042SHeinrich Schuchardt *child_handle_buffer = calloc(count, sizeof(efi_handle_t)); 29733f9b0042SHeinrich Schuchardt if (!*child_handle_buffer) 29743f9b0042SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 29753f9b0042SHeinrich Schuchardt /* Copy unique child handles */ 29763f9b0042SHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 29773f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 29783f9b0042SHeinrich Schuchardt if (item->info.agent_handle == driver_handle && 29793f9b0042SHeinrich Schuchardt item->info.attributes & 29803f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 29813f9b0042SHeinrich Schuchardt /* Check this is a new child controller */ 29823f9b0042SHeinrich Schuchardt duplicate = false; 29833f9b0042SHeinrich Schuchardt for (i = 0; i < *number_of_children; ++i) { 29843f9b0042SHeinrich Schuchardt if ((*child_handle_buffer)[i] == 29853f9b0042SHeinrich Schuchardt item->info.controller_handle) 29863f9b0042SHeinrich Schuchardt duplicate = true; 29873f9b0042SHeinrich Schuchardt } 29883f9b0042SHeinrich Schuchardt /* Copy handle to buffer */ 29893f9b0042SHeinrich Schuchardt if (!duplicate) { 29903f9b0042SHeinrich Schuchardt i = (*number_of_children)++; 29913f9b0042SHeinrich Schuchardt (*child_handle_buffer)[i] = 29923f9b0042SHeinrich Schuchardt item->info.controller_handle; 29933f9b0042SHeinrich Schuchardt } 29943f9b0042SHeinrich Schuchardt } 29953f9b0042SHeinrich Schuchardt } 29963f9b0042SHeinrich Schuchardt } 29973f9b0042SHeinrich Schuchardt return EFI_SUCCESS; 29983f9b0042SHeinrich Schuchardt } 29993f9b0042SHeinrich Schuchardt 30006b03cd10SHeinrich Schuchardt /** 300178a88f79SMario Six * efi_disconnect_controller() - disconnect a controller from a driver 30026b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 30036b03cd10SHeinrich Schuchardt * @driver_image_handle: handle of the driver 30046b03cd10SHeinrich Schuchardt * @child_handle: handle of the child to destroy 300578a88f79SMario Six * 300678a88f79SMario Six * This function implements the DisconnectController service. 300778a88f79SMario Six * 300878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 300978a88f79SMario Six * details. 301078a88f79SMario Six * 301178a88f79SMario Six * Return: status code 30123f9b0042SHeinrich Schuchardt */ 30133f9b0042SHeinrich Schuchardt static efi_status_t EFIAPI efi_disconnect_controller( 30143f9b0042SHeinrich Schuchardt efi_handle_t controller_handle, 30153f9b0042SHeinrich Schuchardt efi_handle_t driver_image_handle, 30163f9b0042SHeinrich Schuchardt efi_handle_t child_handle) 30173f9b0042SHeinrich Schuchardt { 30183f9b0042SHeinrich Schuchardt struct efi_driver_binding_protocol *binding_protocol; 30193f9b0042SHeinrich Schuchardt efi_handle_t *child_handle_buffer = NULL; 30203f9b0042SHeinrich Schuchardt size_t number_of_children = 0; 30213f9b0042SHeinrich Schuchardt efi_status_t r; 30223f9b0042SHeinrich Schuchardt size_t stop_count = 0; 30233f9b0042SHeinrich Schuchardt struct efi_object *efiobj; 30243f9b0042SHeinrich Schuchardt 30253f9b0042SHeinrich Schuchardt EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle, 30263f9b0042SHeinrich Schuchardt child_handle); 30273f9b0042SHeinrich Schuchardt 30283f9b0042SHeinrich Schuchardt efiobj = efi_search_obj(controller_handle); 30293f9b0042SHeinrich Schuchardt if (!efiobj) { 30303f9b0042SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 30313f9b0042SHeinrich Schuchardt goto out; 30323f9b0042SHeinrich Schuchardt } 30333f9b0042SHeinrich Schuchardt 30343f9b0042SHeinrich Schuchardt if (child_handle && !efi_search_obj(child_handle)) { 30353f9b0042SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 30363f9b0042SHeinrich Schuchardt goto out; 30373f9b0042SHeinrich Schuchardt } 30383f9b0042SHeinrich Schuchardt 30393f9b0042SHeinrich Schuchardt /* If no driver handle is supplied, disconnect all drivers */ 30403f9b0042SHeinrich Schuchardt if (!driver_image_handle) { 30413f9b0042SHeinrich Schuchardt r = efi_disconnect_all_drivers(efiobj, NULL, child_handle); 30423f9b0042SHeinrich Schuchardt goto out; 30433f9b0042SHeinrich Schuchardt } 30443f9b0042SHeinrich Schuchardt 30453f9b0042SHeinrich Schuchardt /* Create list of child handles */ 30463f9b0042SHeinrich Schuchardt if (child_handle) { 30473f9b0042SHeinrich Schuchardt number_of_children = 1; 30483f9b0042SHeinrich Schuchardt child_handle_buffer = &child_handle; 30493f9b0042SHeinrich Schuchardt } else { 30503f9b0042SHeinrich Schuchardt efi_get_child_controllers(efiobj, 30513f9b0042SHeinrich Schuchardt driver_image_handle, 30523f9b0042SHeinrich Schuchardt &number_of_children, 30533f9b0042SHeinrich Schuchardt &child_handle_buffer); 30543f9b0042SHeinrich Schuchardt } 30553f9b0042SHeinrich Schuchardt 30563f9b0042SHeinrich Schuchardt /* Get the driver binding protocol */ 30573f9b0042SHeinrich Schuchardt r = EFI_CALL(efi_open_protocol(driver_image_handle, 30583f9b0042SHeinrich Schuchardt &efi_guid_driver_binding_protocol, 30593f9b0042SHeinrich Schuchardt (void **)&binding_protocol, 30603f9b0042SHeinrich Schuchardt driver_image_handle, NULL, 30613f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_GET_PROTOCOL)); 30623f9b0042SHeinrich Schuchardt if (r != EFI_SUCCESS) 30633f9b0042SHeinrich Schuchardt goto out; 30643f9b0042SHeinrich Schuchardt /* Remove the children */ 30653f9b0042SHeinrich Schuchardt if (number_of_children) { 30663f9b0042SHeinrich Schuchardt r = EFI_CALL(binding_protocol->stop(binding_protocol, 30673f9b0042SHeinrich Schuchardt controller_handle, 30683f9b0042SHeinrich Schuchardt number_of_children, 30693f9b0042SHeinrich Schuchardt child_handle_buffer)); 30703f9b0042SHeinrich Schuchardt if (r == EFI_SUCCESS) 30713f9b0042SHeinrich Schuchardt ++stop_count; 30723f9b0042SHeinrich Schuchardt } 30733f9b0042SHeinrich Schuchardt /* Remove the driver */ 30743f9b0042SHeinrich Schuchardt if (!child_handle) 30753f9b0042SHeinrich Schuchardt r = EFI_CALL(binding_protocol->stop(binding_protocol, 30763f9b0042SHeinrich Schuchardt controller_handle, 30773f9b0042SHeinrich Schuchardt 0, NULL)); 30783f9b0042SHeinrich Schuchardt if (r == EFI_SUCCESS) 30793f9b0042SHeinrich Schuchardt ++stop_count; 30803f9b0042SHeinrich Schuchardt EFI_CALL(efi_close_protocol(driver_image_handle, 30813f9b0042SHeinrich Schuchardt &efi_guid_driver_binding_protocol, 30823f9b0042SHeinrich Schuchardt driver_image_handle, NULL)); 30833f9b0042SHeinrich Schuchardt 30843f9b0042SHeinrich Schuchardt if (stop_count) 30853f9b0042SHeinrich Schuchardt r = EFI_SUCCESS; 30863f9b0042SHeinrich Schuchardt else 30873f9b0042SHeinrich Schuchardt r = EFI_NOT_FOUND; 30883f9b0042SHeinrich Schuchardt out: 30893f9b0042SHeinrich Schuchardt if (!child_handle) 30903f9b0042SHeinrich Schuchardt free(child_handle_buffer); 30913f9b0042SHeinrich Schuchardt return EFI_EXIT(r); 30923f9b0042SHeinrich Schuchardt } 30933f9b0042SHeinrich Schuchardt 3094640adadfSHeinrich Schuchardt static struct efi_boot_services efi_boot_services = { 3095bee91169SAlexander Graf .hdr = { 3096112f2430SHeinrich Schuchardt .signature = EFI_BOOT_SERVICES_SIGNATURE, 3097112f2430SHeinrich Schuchardt .revision = EFI_SPECIFICATION_VERSION, 309871c846abSHeinrich Schuchardt .headersize = sizeof(struct efi_boot_services), 3099bee91169SAlexander Graf }, 3100bee91169SAlexander Graf .raise_tpl = efi_raise_tpl, 3101bee91169SAlexander Graf .restore_tpl = efi_restore_tpl, 3102bee91169SAlexander Graf .allocate_pages = efi_allocate_pages_ext, 3103bee91169SAlexander Graf .free_pages = efi_free_pages_ext, 3104bee91169SAlexander Graf .get_memory_map = efi_get_memory_map_ext, 3105ead1274bSStefan Brüns .allocate_pool = efi_allocate_pool_ext, 310642417bc8SStefan Brüns .free_pool = efi_free_pool_ext, 310749deb455Sxypron.glpk@gmx.de .create_event = efi_create_event_ext, 3108bfc72462Sxypron.glpk@gmx.de .set_timer = efi_set_timer_ext, 3109bee91169SAlexander Graf .wait_for_event = efi_wait_for_event, 3110c6841592Sxypron.glpk@gmx.de .signal_event = efi_signal_event_ext, 3111bee91169SAlexander Graf .close_event = efi_close_event, 3112bee91169SAlexander Graf .check_event = efi_check_event, 31131760ef57SHeinrich Schuchardt .install_protocol_interface = efi_install_protocol_interface, 3114bee91169SAlexander Graf .reinstall_protocol_interface = efi_reinstall_protocol_interface, 3115cd534083SHeinrich Schuchardt .uninstall_protocol_interface = efi_uninstall_protocol_interface, 3116bee91169SAlexander Graf .handle_protocol = efi_handle_protocol, 3117bee91169SAlexander Graf .reserved = NULL, 3118bee91169SAlexander Graf .register_protocol_notify = efi_register_protocol_notify, 311926329584Sxypron.glpk@gmx.de .locate_handle = efi_locate_handle_ext, 3120bee91169SAlexander Graf .locate_device_path = efi_locate_device_path, 3121488bf12dSAlexander Graf .install_configuration_table = efi_install_configuration_table_ext, 3122bee91169SAlexander Graf .load_image = efi_load_image, 3123bee91169SAlexander Graf .start_image = efi_start_image, 3124a86aeaf2SAlexander Graf .exit = efi_exit, 3125bee91169SAlexander Graf .unload_image = efi_unload_image, 3126bee91169SAlexander Graf .exit_boot_services = efi_exit_boot_services, 3127bee91169SAlexander Graf .get_next_monotonic_count = efi_get_next_monotonic_count, 3128bee91169SAlexander Graf .stall = efi_stall, 3129bee91169SAlexander Graf .set_watchdog_timer = efi_set_watchdog_timer, 3130bee91169SAlexander Graf .connect_controller = efi_connect_controller, 3131bee91169SAlexander Graf .disconnect_controller = efi_disconnect_controller, 3132bee91169SAlexander Graf .open_protocol = efi_open_protocol, 3133bee91169SAlexander Graf .close_protocol = efi_close_protocol, 3134bee91169SAlexander Graf .open_protocol_information = efi_open_protocol_information, 3135bee91169SAlexander Graf .protocols_per_handle = efi_protocols_per_handle, 3136bee91169SAlexander Graf .locate_handle_buffer = efi_locate_handle_buffer, 3137bee91169SAlexander Graf .locate_protocol = efi_locate_protocol, 3138ab9efa97SHeinrich Schuchardt .install_multiple_protocol_interfaces = 3139ab9efa97SHeinrich Schuchardt efi_install_multiple_protocol_interfaces, 3140ab9efa97SHeinrich Schuchardt .uninstall_multiple_protocol_interfaces = 3141ab9efa97SHeinrich Schuchardt efi_uninstall_multiple_protocol_interfaces, 3142bee91169SAlexander Graf .calculate_crc32 = efi_calculate_crc32, 3143bee91169SAlexander Graf .copy_mem = efi_copy_mem, 3144bee91169SAlexander Graf .set_mem = efi_set_mem, 31459f0930e5SHeinrich Schuchardt .create_event_ex = efi_create_event_ex, 3146bee91169SAlexander Graf }; 3147bee91169SAlexander Graf 31480b386537SHeinrich Schuchardt static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; 3149bee91169SAlexander Graf 31503c63db9cSAlexander Graf struct efi_system_table __efi_runtime_data systab = { 3151bee91169SAlexander Graf .hdr = { 3152bee91169SAlexander Graf .signature = EFI_SYSTEM_TABLE_SIGNATURE, 3153112f2430SHeinrich Schuchardt .revision = EFI_SPECIFICATION_VERSION, 315471c846abSHeinrich Schuchardt .headersize = sizeof(struct efi_system_table), 3155bee91169SAlexander Graf }, 31560b386537SHeinrich Schuchardt .fw_vendor = firmware_vendor, 31570b386537SHeinrich Schuchardt .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8, 3158bee91169SAlexander Graf .con_in = (void *)&efi_con_in, 3159bee91169SAlexander Graf .con_out = (void *)&efi_con_out, 3160bee91169SAlexander Graf .std_err = (void *)&efi_con_out, 3161bee91169SAlexander Graf .runtime = (void *)&efi_runtime_services, 3162bee91169SAlexander Graf .boottime = (void *)&efi_boot_services, 3163bee91169SAlexander Graf .nr_tables = 0, 31644182a129SHeinrich Schuchardt .tables = NULL, 3165bee91169SAlexander Graf }; 3166640adadfSHeinrich Schuchardt 3167640adadfSHeinrich Schuchardt /** 3168640adadfSHeinrich Schuchardt * efi_initialize_system_table() - Initialize system table 3169640adadfSHeinrich Schuchardt * 31700414359aSHeinrich Schuchardt * Return: status code 3171640adadfSHeinrich Schuchardt */ 3172640adadfSHeinrich Schuchardt efi_status_t efi_initialize_system_table(void) 3173640adadfSHeinrich Schuchardt { 31744182a129SHeinrich Schuchardt efi_status_t ret; 31754182a129SHeinrich Schuchardt 31764182a129SHeinrich Schuchardt /* Allocate configuration table array */ 31774182a129SHeinrich Schuchardt ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA, 31784182a129SHeinrich Schuchardt EFI_MAX_CONFIGURATION_TABLES * 31794182a129SHeinrich Schuchardt sizeof(struct efi_configuration_table), 31804182a129SHeinrich Schuchardt (void **)&systab.tables); 31814182a129SHeinrich Schuchardt 3182b72aaa87SHeinrich Schuchardt /* Set CRC32 field in table headers */ 3183640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&systab.hdr); 3184640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&efi_runtime_services.hdr); 3185640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&efi_boot_services.hdr); 31864182a129SHeinrich Schuchardt 31874182a129SHeinrich Schuchardt return ret; 3188640adadfSHeinrich Schuchardt } 3189