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 156156d92888SHeinrich Schuchardt return ret; 156248b66230SHeinrich Schuchardt failure: 156348b66230SHeinrich Schuchardt printf("ERROR: Failure to install protocols for loaded image\n"); 156456d92888SHeinrich Schuchardt return ret; 156595c5553eSRob Clark } 156695c5553eSRob Clark 15676b03cd10SHeinrich Schuchardt /** 156878a88f79SMario Six * efi_load_image_from_path() - load an image using a file path 15696b03cd10SHeinrich Schuchardt * @file_path: the path of the image to load 15706b03cd10SHeinrich Schuchardt * @buffer: buffer containing the loaded image 157178a88f79SMario Six * 157278a88f79SMario Six * Return: status code 1573332468f7SHeinrich Schuchardt */ 15749975fe96SRob Clark efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, 1575838ee4b4SRob Clark void **buffer) 1576838ee4b4SRob Clark { 1577838ee4b4SRob Clark struct efi_file_info *info = NULL; 1578838ee4b4SRob Clark struct efi_file_handle *f; 1579838ee4b4SRob Clark static efi_status_t ret; 1580b6dd5777SHeinrich Schuchardt efi_uintn_t bs; 1581838ee4b4SRob Clark 1582838ee4b4SRob Clark f = efi_file_from_path(file_path); 1583838ee4b4SRob Clark if (!f) 1584838ee4b4SRob Clark return EFI_DEVICE_ERROR; 1585838ee4b4SRob Clark 1586838ee4b4SRob Clark bs = 0; 1587838ee4b4SRob Clark EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, 1588838ee4b4SRob Clark &bs, info)); 1589838ee4b4SRob Clark if (ret == EFI_BUFFER_TOO_SMALL) { 1590838ee4b4SRob Clark info = malloc(bs); 1591838ee4b4SRob Clark EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, 1592838ee4b4SRob Clark &bs, info)); 1593838ee4b4SRob Clark } 1594838ee4b4SRob Clark if (ret != EFI_SUCCESS) 1595838ee4b4SRob Clark goto error; 1596838ee4b4SRob Clark 1597838ee4b4SRob Clark ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer); 1598838ee4b4SRob Clark if (ret) 1599838ee4b4SRob Clark goto error; 1600838ee4b4SRob Clark 1601b6dd5777SHeinrich Schuchardt bs = info->file_size; 1602b6dd5777SHeinrich Schuchardt EFI_CALL(ret = f->read(f, &bs, *buffer)); 1603838ee4b4SRob Clark 1604838ee4b4SRob Clark error: 1605838ee4b4SRob Clark free(info); 1606838ee4b4SRob Clark EFI_CALL(f->close(f)); 1607838ee4b4SRob Clark 1608838ee4b4SRob Clark if (ret != EFI_SUCCESS) { 1609838ee4b4SRob Clark efi_free_pool(*buffer); 1610838ee4b4SRob Clark *buffer = NULL; 1611838ee4b4SRob Clark } 1612838ee4b4SRob Clark 1613838ee4b4SRob Clark return ret; 1614838ee4b4SRob Clark } 1615838ee4b4SRob Clark 16166b03cd10SHeinrich Schuchardt /** 161778a88f79SMario Six * efi_load_image() - load an EFI image into memory 16186b03cd10SHeinrich Schuchardt * @boot_policy: true for request originating from the boot manager 16196b03cd10SHeinrich Schuchardt * @parent_image: the caller's image handle 16206b03cd10SHeinrich Schuchardt * @file_path: the path of the image to load 16216b03cd10SHeinrich Schuchardt * @source_buffer: memory location from which the image is installed 162278a88f79SMario Six * @source_size: size of the memory area from which the image is installed 16236b03cd10SHeinrich Schuchardt * @image_handle: handle for the newly installed image 162478a88f79SMario Six * 162578a88f79SMario Six * This function implements the LoadImage service. 162678a88f79SMario Six * 162778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification 162878a88f79SMario Six * for details. 162978a88f79SMario Six * 163078a88f79SMario Six * Return: status code 1631332468f7SHeinrich Schuchardt */ 1632bee91169SAlexander Graf static efi_status_t EFIAPI efi_load_image(bool boot_policy, 1633bee91169SAlexander Graf efi_handle_t parent_image, 1634bee91169SAlexander Graf struct efi_device_path *file_path, 1635bee91169SAlexander Graf void *source_buffer, 16367fb96a10SHeinrich Schuchardt efi_uintn_t source_size, 1637bee91169SAlexander Graf efi_handle_t *image_handle) 1638bee91169SAlexander Graf { 16391c3b2f4aSTom Rini struct efi_loaded_image *info = NULL; 1640c982874eSHeinrich Schuchardt struct efi_loaded_image_obj **image_obj = 1641c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj **)image_handle; 1642b9b17598SHeinrich Schuchardt efi_status_t ret; 1643bee91169SAlexander Graf 16447fb96a10SHeinrich Schuchardt EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, 1645bee91169SAlexander Graf file_path, source_buffer, source_size, image_handle); 1646838ee4b4SRob Clark 164728a4fd46SHeinrich Schuchardt if (!image_handle || !parent_image) { 164828a4fd46SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 164928a4fd46SHeinrich Schuchardt goto error; 165028a4fd46SHeinrich Schuchardt } 165128a4fd46SHeinrich Schuchardt 165228a4fd46SHeinrich Schuchardt if (!source_buffer && !file_path) { 165328a4fd46SHeinrich Schuchardt ret = EFI_NOT_FOUND; 165428a4fd46SHeinrich Schuchardt goto error; 165528a4fd46SHeinrich Schuchardt } 165628a4fd46SHeinrich Schuchardt 1657838ee4b4SRob Clark if (!source_buffer) { 1658838ee4b4SRob Clark struct efi_device_path *dp, *fp; 1659838ee4b4SRob Clark 16609975fe96SRob Clark ret = efi_load_image_from_path(file_path, &source_buffer); 1661b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1662b9b17598SHeinrich Schuchardt goto failure; 1663838ee4b4SRob Clark /* 1664838ee4b4SRob Clark * split file_path which contains both the device and 1665838ee4b4SRob Clark * file parts: 1666838ee4b4SRob Clark */ 1667838ee4b4SRob Clark efi_dp_split_file_path(file_path, &dp, &fp); 1668c982874eSHeinrich Schuchardt ret = efi_setup_loaded_image(dp, fp, image_obj, &info); 1669b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1670b9b17598SHeinrich Schuchardt goto failure; 1671838ee4b4SRob Clark } else { 1672b72aaa87SHeinrich Schuchardt /* In this case, file_path is the "device" path, i.e. 1673838ee4b4SRob Clark * something like a HARDWARE_DEVICE:MEMORY_MAPPED 1674838ee4b4SRob Clark */ 1675c982874eSHeinrich Schuchardt ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info); 1676b9b17598SHeinrich Schuchardt if (ret != EFI_SUCCESS) 1677c982874eSHeinrich Schuchardt goto error; 1678838ee4b4SRob Clark } 1679c982874eSHeinrich Schuchardt (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info); 1680c982874eSHeinrich Schuchardt if (!(*image_obj)->entry) { 1681b9b17598SHeinrich Schuchardt ret = EFI_UNSUPPORTED; 1682b9b17598SHeinrich Schuchardt goto failure; 1683bee91169SAlexander Graf } 168432fc2ac3SHeinrich Schuchardt info->system_table = &systab; 168532fc2ac3SHeinrich Schuchardt info->parent_handle = parent_image; 1686bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1687b9b17598SHeinrich Schuchardt failure: 1688c982874eSHeinrich Schuchardt efi_delete_handle(*image_handle); 1689c982874eSHeinrich Schuchardt *image_handle = NULL; 1690b9b17598SHeinrich Schuchardt free(info); 169128a4fd46SHeinrich Schuchardt error: 1692b9b17598SHeinrich Schuchardt return EFI_EXIT(ret); 1693bee91169SAlexander Graf } 1694bee91169SAlexander Graf 16956b03cd10SHeinrich Schuchardt /** 1696b72aaa87SHeinrich Schuchardt * efi_start_image() - call the entry point of an image 16976b03cd10SHeinrich Schuchardt * @image_handle: handle of the image 16986b03cd10SHeinrich Schuchardt * @exit_data_size: size of the buffer 16996b03cd10SHeinrich Schuchardt * @exit_data: buffer to receive the exit data of the called image 170078a88f79SMario Six * 170178a88f79SMario Six * This function implements the StartImage service. 170278a88f79SMario Six * 170378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 170478a88f79SMario Six * details. 170578a88f79SMario Six * 170678a88f79SMario Six * Return: status code 1707332468f7SHeinrich Schuchardt */ 1708bee91169SAlexander Graf static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, 1709cc8e3417SHeinrich Schuchardt efi_uintn_t *exit_data_size, 1710cc8e3417SHeinrich Schuchardt u16 **exit_data) 1711bee91169SAlexander Graf { 1712c982874eSHeinrich Schuchardt struct efi_loaded_image_obj *image_obj = 1713c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj *)image_handle; 1714727a1afbSHeinrich Schuchardt efi_status_t ret; 1715bee91169SAlexander Graf 1716bee91169SAlexander Graf EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); 1717bee91169SAlexander Graf 1718f31239acSAlexander Graf efi_is_direct_boot = false; 1719f31239acSAlexander Graf 1720bee91169SAlexander Graf /* call the image! */ 1721c982874eSHeinrich Schuchardt if (setjmp(&image_obj->exit_jmp)) { 1722727a1afbSHeinrich Schuchardt /* 1723727a1afbSHeinrich Schuchardt * We called the entry point of the child image with EFI_CALL 1724727a1afbSHeinrich Schuchardt * in the lines below. The child image called the Exit() boot 1725727a1afbSHeinrich Schuchardt * service efi_exit() which executed the long jump that brought 1726727a1afbSHeinrich Schuchardt * us to the current line. This implies that the second half 1727727a1afbSHeinrich Schuchardt * of the EFI_CALL macro has not been executed. 1728727a1afbSHeinrich Schuchardt */ 1729727a1afbSHeinrich Schuchardt #ifdef CONFIG_ARM 1730727a1afbSHeinrich Schuchardt /* 1731727a1afbSHeinrich Schuchardt * efi_exit() called efi_restore_gd(). We have to undo this 1732727a1afbSHeinrich Schuchardt * otherwise __efi_entry_check() will put the wrong value into 1733727a1afbSHeinrich Schuchardt * app_gd. 1734727a1afbSHeinrich Schuchardt */ 1735727a1afbSHeinrich Schuchardt gd = app_gd; 1736727a1afbSHeinrich Schuchardt #endif 1737727a1afbSHeinrich Schuchardt /* 1738727a1afbSHeinrich Schuchardt * To get ready to call EFI_EXIT below we have to execute the 1739727a1afbSHeinrich Schuchardt * missed out steps of EFI_CALL. 1740727a1afbSHeinrich Schuchardt */ 1741727a1afbSHeinrich Schuchardt assert(__efi_entry_check()); 1742727a1afbSHeinrich Schuchardt debug("%sEFI: %lu returned by started image\n", 1743727a1afbSHeinrich Schuchardt __efi_nesting_dec(), 1744c982874eSHeinrich Schuchardt (unsigned long)((uintptr_t)image_obj->exit_status & 1745727a1afbSHeinrich Schuchardt ~EFI_ERROR_MASK)); 1746c982874eSHeinrich Schuchardt return EFI_EXIT(image_obj->exit_status); 1747a86aeaf2SAlexander Graf } 1748a86aeaf2SAlexander Graf 1749c982874eSHeinrich Schuchardt ret = EFI_CALL(image_obj->entry(image_handle, &systab)); 1750bee91169SAlexander Graf 175156672bf5SAlexander Graf /* 175256672bf5SAlexander Graf * Usually UEFI applications call Exit() instead of returning. 1753b72aaa87SHeinrich Schuchardt * But because the world doesn't consist of ponies and unicorns, 175456672bf5SAlexander Graf * we're happy to emulate that behavior on behalf of a payload 175556672bf5SAlexander Graf * that forgot. 175656672bf5SAlexander Graf */ 175756672bf5SAlexander Graf return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL)); 1758bee91169SAlexander Graf } 1759bee91169SAlexander Graf 17606b03cd10SHeinrich Schuchardt /** 176178a88f79SMario Six * efi_exit() - leave an EFI application or driver 17626b03cd10SHeinrich Schuchardt * @image_handle: handle of the application or driver that is exiting 17636b03cd10SHeinrich Schuchardt * @exit_status: status code 17646b03cd10SHeinrich Schuchardt * @exit_data_size: size of the buffer in bytes 17656b03cd10SHeinrich Schuchardt * @exit_data: buffer with data describing an error 176678a88f79SMario Six * 176778a88f79SMario Six * This function implements the Exit service. 176878a88f79SMario Six * 176978a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 177078a88f79SMario Six * details. 177178a88f79SMario Six * 177278a88f79SMario Six * Return: status code 1773332468f7SHeinrich Schuchardt */ 1774a86aeaf2SAlexander Graf static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, 1775ab9efa97SHeinrich Schuchardt efi_status_t exit_status, 1776cc8e3417SHeinrich Schuchardt efi_uintn_t exit_data_size, 1777cc8e3417SHeinrich Schuchardt u16 *exit_data) 1778bee91169SAlexander Graf { 177944549d62SHeinrich Schuchardt /* 178044549d62SHeinrich Schuchardt * TODO: We should call the unload procedure of the loaded 178144549d62SHeinrich Schuchardt * image protocol. 178244549d62SHeinrich Schuchardt */ 1783c982874eSHeinrich Schuchardt struct efi_loaded_image_obj *image_obj = 1784c982874eSHeinrich Schuchardt (struct efi_loaded_image_obj *)image_handle; 1785a86aeaf2SAlexander Graf 1786cc8e3417SHeinrich Schuchardt EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, 1787bee91169SAlexander Graf exit_data_size, exit_data); 1788a86aeaf2SAlexander Graf 1789a148920eSAlexander Graf /* Make sure entry/exit counts for EFI world cross-overs match */ 1790727a1afbSHeinrich Schuchardt EFI_EXIT(exit_status); 1791da94073bSHeinrich Schuchardt 1792a148920eSAlexander Graf /* 1793a148920eSAlexander Graf * But longjmp out with the U-Boot gd, not the application's, as 1794a148920eSAlexander Graf * the other end is a setjmp call inside EFI context. 1795a148920eSAlexander Graf */ 1796a148920eSAlexander Graf efi_restore_gd(); 1797a148920eSAlexander Graf 1798c982874eSHeinrich Schuchardt image_obj->exit_status = exit_status; 1799c982874eSHeinrich Schuchardt longjmp(&image_obj->exit_jmp, 1); 1800a86aeaf2SAlexander Graf 1801a86aeaf2SAlexander Graf panic("EFI application exited"); 1802bee91169SAlexander Graf } 1803bee91169SAlexander Graf 18046b03cd10SHeinrich Schuchardt /** 180578a88f79SMario Six * efi_unload_image() - unload an EFI image 180678a88f79SMario Six * @image_handle: handle of the image to be unloaded 1807332468f7SHeinrich Schuchardt * 1808332468f7SHeinrich Schuchardt * This function implements the UnloadImage service. 1809332468f7SHeinrich Schuchardt * 181078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 181178a88f79SMario Six * details. 181278a88f79SMario Six * 181378a88f79SMario Six * Return: status code 1814332468f7SHeinrich Schuchardt */ 18152074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) 1816bee91169SAlexander Graf { 1817bee91169SAlexander Graf struct efi_object *efiobj; 1818bee91169SAlexander Graf 1819bee91169SAlexander Graf EFI_ENTRY("%p", image_handle); 1820bee91169SAlexander Graf efiobj = efi_search_obj(image_handle); 1821bee91169SAlexander Graf if (efiobj) 1822bee91169SAlexander Graf list_del(&efiobj->link); 1823bee91169SAlexander Graf 1824bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1825bee91169SAlexander Graf } 1826bee91169SAlexander Graf 18276b03cd10SHeinrich Schuchardt /** 1828f31239acSAlexander Graf * efi_exit_caches() - fix up caches for EFI payloads if necessary 1829f31239acSAlexander Graf */ 1830f31239acSAlexander Graf static void efi_exit_caches(void) 1831f31239acSAlexander Graf { 1832f31239acSAlexander Graf #if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) 1833f31239acSAlexander Graf /* 1834f31239acSAlexander Graf * Grub on 32bit ARM needs to have caches disabled before jumping into 1835f31239acSAlexander Graf * a zImage, but does not know of all cache layers. Give it a hand. 1836f31239acSAlexander Graf */ 1837f31239acSAlexander Graf if (efi_is_direct_boot) 1838f31239acSAlexander Graf cleanup_before_linux(); 1839f31239acSAlexander Graf #endif 1840f31239acSAlexander Graf } 1841f31239acSAlexander Graf 1842f31239acSAlexander Graf /** 184378a88f79SMario Six * efi_exit_boot_services() - stop all boot services 184478a88f79SMario Six * @image_handle: handle of the loaded image 184578a88f79SMario Six * @map_key: key of the memory map 1846332468f7SHeinrich Schuchardt * 1847332468f7SHeinrich Schuchardt * This function implements the ExitBootServices service. 184878a88f79SMario Six * 1849332468f7SHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification 1850332468f7SHeinrich Schuchardt * for details. 1851332468f7SHeinrich Schuchardt * 185278a88f79SMario Six * All timer events are disabled. For exit boot services events the 185378a88f79SMario Six * notification function is called. The boot services are disabled in the 185478a88f79SMario Six * system table. 1855cc20ed03SHeinrich Schuchardt * 185678a88f79SMario Six * Return: status code 1857332468f7SHeinrich Schuchardt */ 18582074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, 1859bee91169SAlexander Graf unsigned long map_key) 1860bee91169SAlexander Graf { 186143bce442SHeinrich Schuchardt struct efi_event *evt; 1862152a263cSHeinrich Schuchardt 1863bee91169SAlexander Graf EFI_ENTRY("%p, %ld", image_handle, map_key); 1864bee91169SAlexander Graf 18651fcb7ea2SHeinrich Schuchardt /* Check that the caller has read the current memory map */ 18661fcb7ea2SHeinrich Schuchardt if (map_key != efi_memory_map_key) 18671fcb7ea2SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 18681fcb7ea2SHeinrich Schuchardt 1869cc20ed03SHeinrich Schuchardt /* Make sure that notification functions are not called anymore */ 1870cc20ed03SHeinrich Schuchardt efi_tpl = TPL_HIGH_LEVEL; 1871cc20ed03SHeinrich Schuchardt 1872cc20ed03SHeinrich Schuchardt /* Check if ExitBootServices has already been called */ 1873cc20ed03SHeinrich Schuchardt if (!systab.boottime) 1874cc20ed03SHeinrich Schuchardt return EFI_EXIT(EFI_SUCCESS); 1875cc20ed03SHeinrich Schuchardt 1876b095f3c8SHeinrich Schuchardt /* Add related events to the event group */ 1877b095f3c8SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 1878b095f3c8SHeinrich Schuchardt if (evt->type == EVT_SIGNAL_EXIT_BOOT_SERVICES) 1879b095f3c8SHeinrich Schuchardt evt->group = &efi_guid_event_group_exit_boot_services; 1880b095f3c8SHeinrich Schuchardt } 1881152a263cSHeinrich Schuchardt /* Notify that ExitBootServices is invoked. */ 188243bce442SHeinrich Schuchardt list_for_each_entry(evt, &efi_events, link) { 1883b095f3c8SHeinrich Schuchardt if (evt->group && 1884b095f3c8SHeinrich Schuchardt !guidcmp(evt->group, 1885b095f3c8SHeinrich Schuchardt &efi_guid_event_group_exit_boot_services)) { 188643bce442SHeinrich Schuchardt efi_signal_event(evt, false); 1887b095f3c8SHeinrich Schuchardt break; 1888b095f3c8SHeinrich Schuchardt } 1889152a263cSHeinrich Schuchardt } 1890152a263cSHeinrich Schuchardt 1891b72aaa87SHeinrich Schuchardt /* TODO: Should persist EFI variables here */ 1892ad644e7cSRob Clark 1893b7b8410aSAlexander Graf board_quiesce_devices(); 1894b7b8410aSAlexander Graf 1895f31239acSAlexander Graf /* Fix up caches for EFI payloads if necessary */ 1896f31239acSAlexander Graf efi_exit_caches(); 1897f31239acSAlexander Graf 1898bee91169SAlexander Graf /* This stops all lingering devices */ 1899bee91169SAlexander Graf bootm_disable_interrupts(); 1900bee91169SAlexander Graf 1901cc20ed03SHeinrich Schuchardt /* Disable boot time services */ 1902cc20ed03SHeinrich Schuchardt systab.con_in_handle = NULL; 1903cc20ed03SHeinrich Schuchardt systab.con_in = NULL; 1904cc20ed03SHeinrich Schuchardt systab.con_out_handle = NULL; 1905cc20ed03SHeinrich Schuchardt systab.con_out = NULL; 1906cc20ed03SHeinrich Schuchardt systab.stderr_handle = NULL; 1907cc20ed03SHeinrich Schuchardt systab.std_err = NULL; 1908cc20ed03SHeinrich Schuchardt systab.boottime = NULL; 1909cc20ed03SHeinrich Schuchardt 1910cc20ed03SHeinrich Schuchardt /* Recalculate CRC32 */ 1911640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&systab.hdr); 1912cc20ed03SHeinrich Schuchardt 1913bee91169SAlexander Graf /* Give the payload some time to boot */ 1914b3d60900SHeinrich Schuchardt efi_set_watchdog(0); 1915bee91169SAlexander Graf WATCHDOG_RESET(); 1916bee91169SAlexander Graf 1917bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1918bee91169SAlexander Graf } 1919bee91169SAlexander Graf 19206b03cd10SHeinrich Schuchardt /** 192178a88f79SMario Six * efi_get_next_monotonic_count() - get next value of the counter 192278a88f79SMario Six * @count: returned value of the counter 1923332468f7SHeinrich Schuchardt * 1924332468f7SHeinrich Schuchardt * This function implements the NextMonotonicCount service. 1925332468f7SHeinrich Schuchardt * 192678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 192778a88f79SMario Six * details. 192878a88f79SMario Six * 192978a88f79SMario Six * Return: status code 1930332468f7SHeinrich Schuchardt */ 1931bee91169SAlexander Graf static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) 1932bee91169SAlexander Graf { 1933ab9efa97SHeinrich Schuchardt static uint64_t mono; 1934ab9efa97SHeinrich Schuchardt 1935bee91169SAlexander Graf EFI_ENTRY("%p", count); 1936bee91169SAlexander Graf *count = mono++; 1937bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1938bee91169SAlexander Graf } 1939bee91169SAlexander Graf 19406b03cd10SHeinrich Schuchardt /** 194178a88f79SMario Six * efi_stall() - sleep 19426b03cd10SHeinrich Schuchardt * @microseconds: period to sleep in microseconds 194378a88f79SMario Six * 194478a88f79SMario Six * This function implements the Stall service. 194578a88f79SMario Six * 194678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 194778a88f79SMario Six * details. 194878a88f79SMario Six * 194978a88f79SMario Six * Return: status code 1950332468f7SHeinrich Schuchardt */ 1951bee91169SAlexander Graf static efi_status_t EFIAPI efi_stall(unsigned long microseconds) 1952bee91169SAlexander Graf { 1953bee91169SAlexander Graf EFI_ENTRY("%ld", microseconds); 1954bee91169SAlexander Graf udelay(microseconds); 1955bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1956bee91169SAlexander Graf } 1957bee91169SAlexander Graf 19586b03cd10SHeinrich Schuchardt /** 195978a88f79SMario Six * efi_set_watchdog_timer() - reset the watchdog timer 19606b03cd10SHeinrich Schuchardt * @timeout: seconds before reset by watchdog 19616b03cd10SHeinrich Schuchardt * @watchdog_code: code to be logged when resetting 19626b03cd10SHeinrich Schuchardt * @data_size: size of buffer in bytes 19636b03cd10SHeinrich Schuchardt * @watchdog_data: buffer with data describing the reset reason 196478a88f79SMario Six * 196578a88f79SMario Six * This function implements the SetWatchdogTimer service. 196678a88f79SMario Six * 196778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 196878a88f79SMario Six * details. 196978a88f79SMario Six * 197078a88f79SMario Six * Return: status code 1971332468f7SHeinrich Schuchardt */ 1972bee91169SAlexander Graf static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, 1973bee91169SAlexander Graf uint64_t watchdog_code, 1974bee91169SAlexander Graf unsigned long data_size, 1975bee91169SAlexander Graf uint16_t *watchdog_data) 1976bee91169SAlexander Graf { 1977dee37fc9SMasahiro Yamada EFI_ENTRY("%ld, 0x%llx, %ld, %p", timeout, watchdog_code, 1978bee91169SAlexander Graf data_size, watchdog_data); 1979b3d60900SHeinrich Schuchardt return EFI_EXIT(efi_set_watchdog(timeout)); 1980bee91169SAlexander Graf } 1981bee91169SAlexander Graf 19826b03cd10SHeinrich Schuchardt /** 198378a88f79SMario Six * efi_close_protocol() - close a protocol 19846b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be closed 19856b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol to close 19866b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 19876b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 198878a88f79SMario Six * 198978a88f79SMario Six * This function implements the CloseProtocol service. 199078a88f79SMario Six * 199178a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 199278a88f79SMario Six * details. 199378a88f79SMario Six * 199478a88f79SMario Six * Return: status code 1995332468f7SHeinrich Schuchardt */ 19962074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, 19975a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, 19982074f700SHeinrich Schuchardt efi_handle_t agent_handle, 19992074f700SHeinrich Schuchardt efi_handle_t controller_handle) 2000bee91169SAlexander Graf { 20013b8a489cSHeinrich Schuchardt struct efi_handler *handler; 20023b8a489cSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 20033b8a489cSHeinrich Schuchardt struct efi_open_protocol_info_item *pos; 20043b8a489cSHeinrich Schuchardt efi_status_t r; 20053b8a489cSHeinrich Schuchardt 2006778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle, 2007bee91169SAlexander Graf controller_handle); 20083b8a489cSHeinrich Schuchardt 20093b8a489cSHeinrich Schuchardt if (!agent_handle) { 20103b8a489cSHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 20113b8a489cSHeinrich Schuchardt goto out; 20123b8a489cSHeinrich Schuchardt } 20133b8a489cSHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 20143b8a489cSHeinrich Schuchardt if (r != EFI_SUCCESS) 20153b8a489cSHeinrich Schuchardt goto out; 20163b8a489cSHeinrich Schuchardt 20173b8a489cSHeinrich Schuchardt r = EFI_NOT_FOUND; 20183b8a489cSHeinrich Schuchardt list_for_each_entry_safe(item, pos, &handler->open_infos, link) { 20193b8a489cSHeinrich Schuchardt if (item->info.agent_handle == agent_handle && 20203b8a489cSHeinrich Schuchardt item->info.controller_handle == controller_handle) { 20213b8a489cSHeinrich Schuchardt efi_delete_open_info(item); 20223b8a489cSHeinrich Schuchardt r = EFI_SUCCESS; 20233b8a489cSHeinrich Schuchardt break; 20243b8a489cSHeinrich Schuchardt } 20253b8a489cSHeinrich Schuchardt } 20263b8a489cSHeinrich Schuchardt out: 20273b8a489cSHeinrich Schuchardt return EFI_EXIT(r); 2028bee91169SAlexander Graf } 2029bee91169SAlexander Graf 20306b03cd10SHeinrich Schuchardt /** 203178a88f79SMario Six * efi_open_protocol_information() - provide information about then open status 20326b03cd10SHeinrich Schuchardt * of a protocol on a handle 20336b03cd10SHeinrich Schuchardt * @handle: handle for which the information shall be retrieved 20346b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 20356b03cd10SHeinrich Schuchardt * @entry_buffer: buffer to receive the open protocol information 20366b03cd10SHeinrich Schuchardt * @entry_count: number of entries available in the buffer 203778a88f79SMario Six * 203878a88f79SMario Six * This function implements the OpenProtocolInformation service. 203978a88f79SMario Six * 204078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 204178a88f79SMario Six * details. 204278a88f79SMario Six * 204378a88f79SMario Six * Return: status code 2044332468f7SHeinrich Schuchardt */ 2045ab9efa97SHeinrich Schuchardt static efi_status_t EFIAPI efi_open_protocol_information( 2046ab9efa97SHeinrich Schuchardt efi_handle_t handle, const efi_guid_t *protocol, 2047bee91169SAlexander Graf struct efi_open_protocol_info_entry **entry_buffer, 2048f5a2a938SHeinrich Schuchardt efi_uintn_t *entry_count) 2049bee91169SAlexander Graf { 2050e3fbbc36SHeinrich Schuchardt unsigned long buffer_size; 2051e3fbbc36SHeinrich Schuchardt unsigned long count; 2052e3fbbc36SHeinrich Schuchardt struct efi_handler *handler; 2053e3fbbc36SHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2054e3fbbc36SHeinrich Schuchardt efi_status_t r; 2055e3fbbc36SHeinrich Schuchardt 2056778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer, 2057bee91169SAlexander Graf entry_count); 2058e3fbbc36SHeinrich Schuchardt 2059e3fbbc36SHeinrich Schuchardt /* Check parameters */ 2060e3fbbc36SHeinrich Schuchardt if (!entry_buffer) { 2061e3fbbc36SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 2062e3fbbc36SHeinrich Schuchardt goto out; 2063e3fbbc36SHeinrich Schuchardt } 2064e3fbbc36SHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 2065e3fbbc36SHeinrich Schuchardt if (r != EFI_SUCCESS) 2066e3fbbc36SHeinrich Schuchardt goto out; 2067e3fbbc36SHeinrich Schuchardt 2068e3fbbc36SHeinrich Schuchardt /* Count entries */ 2069e3fbbc36SHeinrich Schuchardt count = 0; 2070e3fbbc36SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2071e3fbbc36SHeinrich Schuchardt if (item->info.open_count) 2072e3fbbc36SHeinrich Schuchardt ++count; 2073e3fbbc36SHeinrich Schuchardt } 2074e3fbbc36SHeinrich Schuchardt *entry_count = count; 2075e3fbbc36SHeinrich Schuchardt *entry_buffer = NULL; 2076e3fbbc36SHeinrich Schuchardt if (!count) { 2077e3fbbc36SHeinrich Schuchardt r = EFI_SUCCESS; 2078e3fbbc36SHeinrich Schuchardt goto out; 2079e3fbbc36SHeinrich Schuchardt } 2080e3fbbc36SHeinrich Schuchardt 2081e3fbbc36SHeinrich Schuchardt /* Copy entries */ 2082e3fbbc36SHeinrich Schuchardt buffer_size = count * sizeof(struct efi_open_protocol_info_entry); 2083eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2084e3fbbc36SHeinrich Schuchardt (void **)entry_buffer); 2085e3fbbc36SHeinrich Schuchardt if (r != EFI_SUCCESS) 2086e3fbbc36SHeinrich Schuchardt goto out; 2087e3fbbc36SHeinrich Schuchardt list_for_each_entry_reverse(item, &handler->open_infos, link) { 2088e3fbbc36SHeinrich Schuchardt if (item->info.open_count) 2089e3fbbc36SHeinrich Schuchardt (*entry_buffer)[--count] = item->info; 2090e3fbbc36SHeinrich Schuchardt } 2091e3fbbc36SHeinrich Schuchardt out: 2092e3fbbc36SHeinrich Schuchardt return EFI_EXIT(r); 2093bee91169SAlexander Graf } 2094bee91169SAlexander Graf 20956b03cd10SHeinrich Schuchardt /** 209678a88f79SMario Six * efi_protocols_per_handle() - get protocols installed on a handle 20976b03cd10SHeinrich Schuchardt * @handle: handle for which the information is retrieved 20986b03cd10SHeinrich Schuchardt * @protocol_buffer: buffer with protocol GUIDs 20996b03cd10SHeinrich Schuchardt * @protocol_buffer_count: number of entries in the buffer 210078a88f79SMario Six * 210178a88f79SMario Six * This function implements the ProtocolsPerHandleService. 210278a88f79SMario Six * 210378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 210478a88f79SMario Six * details. 210578a88f79SMario Six * 210678a88f79SMario Six * Return: status code 2107332468f7SHeinrich Schuchardt */ 21082074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_protocols_per_handle( 21092074f700SHeinrich Schuchardt efi_handle_t handle, efi_guid_t ***protocol_buffer, 2110f5a2a938SHeinrich Schuchardt efi_uintn_t *protocol_buffer_count) 2111bee91169SAlexander Graf { 2112c0ebfc86Sxypron.glpk@gmx.de unsigned long buffer_size; 2113c0ebfc86Sxypron.glpk@gmx.de struct efi_object *efiobj; 211469fb6b1aSHeinrich Schuchardt struct list_head *protocol_handle; 2115c0ebfc86Sxypron.glpk@gmx.de efi_status_t r; 2116c0ebfc86Sxypron.glpk@gmx.de 2117bee91169SAlexander Graf EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, 2118bee91169SAlexander Graf protocol_buffer_count); 2119c0ebfc86Sxypron.glpk@gmx.de 2120c0ebfc86Sxypron.glpk@gmx.de if (!handle || !protocol_buffer || !protocol_buffer_count) 2121c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 2122c0ebfc86Sxypron.glpk@gmx.de 2123c0ebfc86Sxypron.glpk@gmx.de *protocol_buffer = NULL; 2124661c8327SRob Clark *protocol_buffer_count = 0; 2125c0ebfc86Sxypron.glpk@gmx.de 212669fb6b1aSHeinrich Schuchardt efiobj = efi_search_obj(handle); 212769fb6b1aSHeinrich Schuchardt if (!efiobj) 212869fb6b1aSHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 2129c0ebfc86Sxypron.glpk@gmx.de 2130c0ebfc86Sxypron.glpk@gmx.de /* Count protocols */ 213169fb6b1aSHeinrich Schuchardt list_for_each(protocol_handle, &efiobj->protocols) { 2132c0ebfc86Sxypron.glpk@gmx.de ++*protocol_buffer_count; 2133c0ebfc86Sxypron.glpk@gmx.de } 213469fb6b1aSHeinrich Schuchardt 2135b72aaa87SHeinrich Schuchardt /* Copy GUIDs */ 2136c0ebfc86Sxypron.glpk@gmx.de if (*protocol_buffer_count) { 213769fb6b1aSHeinrich Schuchardt size_t j = 0; 213869fb6b1aSHeinrich Schuchardt 213969fb6b1aSHeinrich Schuchardt buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count; 2140eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2141c0ebfc86Sxypron.glpk@gmx.de (void **)protocol_buffer); 2142c0ebfc86Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 2143c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(r); 214469fb6b1aSHeinrich Schuchardt list_for_each(protocol_handle, &efiobj->protocols) { 214569fb6b1aSHeinrich Schuchardt struct efi_handler *protocol; 214669fb6b1aSHeinrich Schuchardt 214769fb6b1aSHeinrich Schuchardt protocol = list_entry(protocol_handle, 214869fb6b1aSHeinrich Schuchardt struct efi_handler, link); 214969fb6b1aSHeinrich Schuchardt (*protocol_buffer)[j] = (void *)protocol->guid; 2150c0ebfc86Sxypron.glpk@gmx.de ++j; 2151c0ebfc86Sxypron.glpk@gmx.de } 2152c0ebfc86Sxypron.glpk@gmx.de } 2153c0ebfc86Sxypron.glpk@gmx.de 2154c0ebfc86Sxypron.glpk@gmx.de return EFI_EXIT(EFI_SUCCESS); 2155bee91169SAlexander Graf } 2156bee91169SAlexander Graf 21576b03cd10SHeinrich Schuchardt /** 215878a88f79SMario Six * efi_locate_handle_buffer() - locate handles implementing a protocol 21596b03cd10SHeinrich Schuchardt * @search_type: selection criterion 21606b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 21616b03cd10SHeinrich Schuchardt * @search_key: registration key 21626b03cd10SHeinrich Schuchardt * @no_handles: number of returned handles 21636b03cd10SHeinrich Schuchardt * @buffer: buffer with the returned handles 216478a88f79SMario Six * 216578a88f79SMario Six * This function implements the LocateHandleBuffer service. 216678a88f79SMario Six * 216778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 216878a88f79SMario Six * details. 216978a88f79SMario Six * 217078a88f79SMario Six * Return: status code 2171332468f7SHeinrich Schuchardt */ 2172bee91169SAlexander Graf static efi_status_t EFIAPI efi_locate_handle_buffer( 2173bee91169SAlexander Graf enum efi_locate_search_type search_type, 21745a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, void *search_key, 2175f5a2a938SHeinrich Schuchardt efi_uintn_t *no_handles, efi_handle_t **buffer) 2176bee91169SAlexander Graf { 2177c2e703f9Sxypron.glpk@gmx.de efi_status_t r; 2178f5a2a938SHeinrich Schuchardt efi_uintn_t buffer_size = 0; 2179c2e703f9Sxypron.glpk@gmx.de 2180778e6af8SRob Clark EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, 2181bee91169SAlexander Graf no_handles, buffer); 2182c2e703f9Sxypron.glpk@gmx.de 2183c2e703f9Sxypron.glpk@gmx.de if (!no_handles || !buffer) { 2184c2e703f9Sxypron.glpk@gmx.de r = EFI_INVALID_PARAMETER; 2185c2e703f9Sxypron.glpk@gmx.de goto out; 2186c2e703f9Sxypron.glpk@gmx.de } 2187c2e703f9Sxypron.glpk@gmx.de *no_handles = 0; 2188c2e703f9Sxypron.glpk@gmx.de *buffer = NULL; 2189c2e703f9Sxypron.glpk@gmx.de r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, 2190c2e703f9Sxypron.glpk@gmx.de *buffer); 2191c2e703f9Sxypron.glpk@gmx.de if (r != EFI_BUFFER_TOO_SMALL) 2192c2e703f9Sxypron.glpk@gmx.de goto out; 2193eee6530eSHeinrich Schuchardt r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, 2194c2e703f9Sxypron.glpk@gmx.de (void **)buffer); 2195c2e703f9Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 2196c2e703f9Sxypron.glpk@gmx.de goto out; 2197c2e703f9Sxypron.glpk@gmx.de r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, 2198c2e703f9Sxypron.glpk@gmx.de *buffer); 2199c2e703f9Sxypron.glpk@gmx.de if (r == EFI_SUCCESS) 22002074f700SHeinrich Schuchardt *no_handles = buffer_size / sizeof(efi_handle_t); 2201c2e703f9Sxypron.glpk@gmx.de out: 2202c2e703f9Sxypron.glpk@gmx.de return EFI_EXIT(r); 2203bee91169SAlexander Graf } 2204bee91169SAlexander Graf 22056b03cd10SHeinrich Schuchardt /** 220678a88f79SMario Six * efi_locate_protocol() - find an interface implementing a protocol 22076b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 22086b03cd10SHeinrich Schuchardt * @registration: registration key passed to the notification function 22096b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 221078a88f79SMario Six * 221178a88f79SMario Six * This function implements the LocateProtocol service. 221278a88f79SMario Six * 221378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 221478a88f79SMario Six * details. 221578a88f79SMario Six * 221678a88f79SMario Six * Return: status code 2217332468f7SHeinrich Schuchardt */ 22185a9682d0SHeinrich Schuchardt static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, 2219bee91169SAlexander Graf void *registration, 2220bee91169SAlexander Graf void **protocol_interface) 2221bee91169SAlexander Graf { 222288adae5eSxypron.glpk@gmx.de struct list_head *lhandle; 22239172cd91SHeinrich Schuchardt efi_status_t ret; 2224bee91169SAlexander Graf 2225778e6af8SRob Clark EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface); 222688adae5eSxypron.glpk@gmx.de 222788adae5eSxypron.glpk@gmx.de if (!protocol || !protocol_interface) 222888adae5eSxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 222988adae5eSxypron.glpk@gmx.de 223088adae5eSxypron.glpk@gmx.de list_for_each(lhandle, &efi_obj_list) { 223188adae5eSxypron.glpk@gmx.de struct efi_object *efiobj; 22329172cd91SHeinrich Schuchardt struct efi_handler *handler; 223388adae5eSxypron.glpk@gmx.de 223488adae5eSxypron.glpk@gmx.de efiobj = list_entry(lhandle, struct efi_object, link); 223588adae5eSxypron.glpk@gmx.de 2236fae0118eSHeinrich Schuchardt ret = efi_search_protocol(efiobj, protocol, &handler); 22379172cd91SHeinrich Schuchardt if (ret == EFI_SUCCESS) { 22389172cd91SHeinrich Schuchardt *protocol_interface = handler->protocol_interface; 2239bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 2240bee91169SAlexander Graf } 2241bee91169SAlexander Graf } 224288adae5eSxypron.glpk@gmx.de *protocol_interface = NULL; 2243bee91169SAlexander Graf 2244bee91169SAlexander Graf return EFI_EXIT(EFI_NOT_FOUND); 2245bee91169SAlexander Graf } 2246bee91169SAlexander Graf 22476b03cd10SHeinrich Schuchardt /** 224878a88f79SMario Six * efi_locate_device_path() - Get the device path and handle of an device 22496b03cd10SHeinrich Schuchardt * implementing a protocol 22506b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 22516b03cd10SHeinrich Schuchardt * @device_path: device path 22526b03cd10SHeinrich Schuchardt * @device: handle of the device 225378a88f79SMario Six * 225478a88f79SMario Six * This function implements the LocateDevicePath service. 225578a88f79SMario Six * 225678a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 225778a88f79SMario Six * details. 225878a88f79SMario Six * 225978a88f79SMario Six * Return: status code 2260ae2c85c1SHeinrich Schuchardt */ 2261ae2c85c1SHeinrich Schuchardt static efi_status_t EFIAPI efi_locate_device_path( 2262ae2c85c1SHeinrich Schuchardt const efi_guid_t *protocol, 2263ae2c85c1SHeinrich Schuchardt struct efi_device_path **device_path, 2264ae2c85c1SHeinrich Schuchardt efi_handle_t *device) 2265ae2c85c1SHeinrich Schuchardt { 2266ae2c85c1SHeinrich Schuchardt struct efi_device_path *dp; 2267ae2c85c1SHeinrich Schuchardt size_t i; 2268ae2c85c1SHeinrich Schuchardt struct efi_handler *handler; 2269ae2c85c1SHeinrich Schuchardt efi_handle_t *handles; 2270ae2c85c1SHeinrich Schuchardt size_t len, len_dp; 2271ae2c85c1SHeinrich Schuchardt size_t len_best = 0; 2272ae2c85c1SHeinrich Schuchardt efi_uintn_t no_handles; 2273ae2c85c1SHeinrich Schuchardt u8 *remainder; 2274ae2c85c1SHeinrich Schuchardt efi_status_t ret; 2275ae2c85c1SHeinrich Schuchardt 2276ae2c85c1SHeinrich Schuchardt EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); 2277ae2c85c1SHeinrich Schuchardt 2278ae2c85c1SHeinrich Schuchardt if (!protocol || !device_path || !*device_path || !device) { 2279ae2c85c1SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 2280ae2c85c1SHeinrich Schuchardt goto out; 2281ae2c85c1SHeinrich Schuchardt } 2282ae2c85c1SHeinrich Schuchardt 2283ae2c85c1SHeinrich Schuchardt /* Find end of device path */ 2284f6dd3f35SHeinrich Schuchardt len = efi_dp_instance_size(*device_path); 2285ae2c85c1SHeinrich Schuchardt 2286ae2c85c1SHeinrich Schuchardt /* Get all handles implementing the protocol */ 2287ae2c85c1SHeinrich Schuchardt ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, 2288ae2c85c1SHeinrich Schuchardt &no_handles, &handles)); 2289ae2c85c1SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2290ae2c85c1SHeinrich Schuchardt goto out; 2291ae2c85c1SHeinrich Schuchardt 2292ae2c85c1SHeinrich Schuchardt for (i = 0; i < no_handles; ++i) { 2293ae2c85c1SHeinrich Schuchardt /* Find the device path protocol */ 2294ae2c85c1SHeinrich Schuchardt ret = efi_search_protocol(handles[i], &efi_guid_device_path, 2295ae2c85c1SHeinrich Schuchardt &handler); 2296ae2c85c1SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2297ae2c85c1SHeinrich Schuchardt continue; 2298ae2c85c1SHeinrich Schuchardt dp = (struct efi_device_path *)handler->protocol_interface; 2299f6dd3f35SHeinrich Schuchardt len_dp = efi_dp_instance_size(dp); 2300ae2c85c1SHeinrich Schuchardt /* 2301ae2c85c1SHeinrich Schuchardt * This handle can only be a better fit 2302ae2c85c1SHeinrich Schuchardt * if its device path length is longer than the best fit and 2303ae2c85c1SHeinrich Schuchardt * if its device path length is shorter of equal the searched 2304ae2c85c1SHeinrich Schuchardt * device path. 2305ae2c85c1SHeinrich Schuchardt */ 2306ae2c85c1SHeinrich Schuchardt if (len_dp <= len_best || len_dp > len) 2307ae2c85c1SHeinrich Schuchardt continue; 2308ae2c85c1SHeinrich Schuchardt /* Check if dp is a subpath of device_path */ 2309ae2c85c1SHeinrich Schuchardt if (memcmp(*device_path, dp, len_dp)) 2310ae2c85c1SHeinrich Schuchardt continue; 2311ae2c85c1SHeinrich Schuchardt *device = handles[i]; 2312ae2c85c1SHeinrich Schuchardt len_best = len_dp; 2313ae2c85c1SHeinrich Schuchardt } 2314ae2c85c1SHeinrich Schuchardt if (len_best) { 2315ae2c85c1SHeinrich Schuchardt remainder = (u8 *)*device_path + len_best; 2316ae2c85c1SHeinrich Schuchardt *device_path = (struct efi_device_path *)remainder; 2317ae2c85c1SHeinrich Schuchardt ret = EFI_SUCCESS; 2318ae2c85c1SHeinrich Schuchardt } else { 2319ae2c85c1SHeinrich Schuchardt ret = EFI_NOT_FOUND; 2320ae2c85c1SHeinrich Schuchardt } 2321ae2c85c1SHeinrich Schuchardt out: 2322ae2c85c1SHeinrich Schuchardt return EFI_EXIT(ret); 2323ae2c85c1SHeinrich Schuchardt } 2324ae2c85c1SHeinrich Schuchardt 23256b03cd10SHeinrich Schuchardt /** 232678a88f79SMario Six * efi_install_multiple_protocol_interfaces() - Install multiple protocol 232778a88f79SMario Six * interfaces 232878a88f79SMario Six * @handle: handle on which the protocol interfaces shall be installed 232978a88f79SMario Six * @...: NULL terminated argument list with pairs of protocol GUIDS and 233078a88f79SMario Six * interfaces 2331332468f7SHeinrich Schuchardt * 2332332468f7SHeinrich Schuchardt * This function implements the MultipleProtocolInterfaces service. 2333332468f7SHeinrich Schuchardt * 233478a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 233578a88f79SMario Six * details. 233678a88f79SMario Six * 233778a88f79SMario Six * Return: status code 2338332468f7SHeinrich Schuchardt */ 2339faea1041SHeinrich Schuchardt static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces 2340faea1041SHeinrich Schuchardt (efi_handle_t *handle, ...) 2341bee91169SAlexander Graf { 2342bee91169SAlexander Graf EFI_ENTRY("%p", handle); 234358b83586Sxypron.glpk@gmx.de 2344beb077a2SAlexander Graf efi_va_list argptr; 23455a9682d0SHeinrich Schuchardt const efi_guid_t *protocol; 234658b83586Sxypron.glpk@gmx.de void *protocol_interface; 234758b83586Sxypron.glpk@gmx.de efi_status_t r = EFI_SUCCESS; 234858b83586Sxypron.glpk@gmx.de int i = 0; 234958b83586Sxypron.glpk@gmx.de 235058b83586Sxypron.glpk@gmx.de if (!handle) 235158b83586Sxypron.glpk@gmx.de return EFI_EXIT(EFI_INVALID_PARAMETER); 235258b83586Sxypron.glpk@gmx.de 2353beb077a2SAlexander Graf efi_va_start(argptr, handle); 235458b83586Sxypron.glpk@gmx.de for (;;) { 2355beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 235658b83586Sxypron.glpk@gmx.de if (!protocol) 235758b83586Sxypron.glpk@gmx.de break; 2358beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 23591760ef57SHeinrich Schuchardt r = EFI_CALL(efi_install_protocol_interface( 23601760ef57SHeinrich Schuchardt handle, protocol, 236158b83586Sxypron.glpk@gmx.de EFI_NATIVE_INTERFACE, 23621760ef57SHeinrich Schuchardt protocol_interface)); 236358b83586Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 236458b83586Sxypron.glpk@gmx.de break; 236558b83586Sxypron.glpk@gmx.de i++; 236658b83586Sxypron.glpk@gmx.de } 2367beb077a2SAlexander Graf efi_va_end(argptr); 236858b83586Sxypron.glpk@gmx.de if (r == EFI_SUCCESS) 236958b83586Sxypron.glpk@gmx.de return EFI_EXIT(r); 237058b83586Sxypron.glpk@gmx.de 237162471e46SHeinrich Schuchardt /* If an error occurred undo all changes. */ 2372beb077a2SAlexander Graf efi_va_start(argptr, handle); 237358b83586Sxypron.glpk@gmx.de for (; i; --i) { 2374beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2375beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 2376faea1041SHeinrich Schuchardt EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol, 2377cd534083SHeinrich Schuchardt protocol_interface)); 237858b83586Sxypron.glpk@gmx.de } 2379beb077a2SAlexander Graf efi_va_end(argptr); 238058b83586Sxypron.glpk@gmx.de 238158b83586Sxypron.glpk@gmx.de return EFI_EXIT(r); 2382bee91169SAlexander Graf } 2383bee91169SAlexander Graf 23846b03cd10SHeinrich Schuchardt /** 238578a88f79SMario Six * efi_uninstall_multiple_protocol_interfaces() - uninstall multiple protocol 238678a88f79SMario Six * interfaces 238778a88f79SMario Six * @handle: handle from which the protocol interfaces shall be removed 238878a88f79SMario Six * @...: NULL terminated argument list with pairs of protocol GUIDS and 23896b03cd10SHeinrich Schuchardt * interfaces 2390332468f7SHeinrich Schuchardt * 2391332468f7SHeinrich Schuchardt * This function implements the UninstallMultipleProtocolInterfaces service. 2392332468f7SHeinrich Schuchardt * 239378a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 239478a88f79SMario Six * details. 239578a88f79SMario Six * 239678a88f79SMario Six * Return: status code 2397332468f7SHeinrich Schuchardt */ 2398bee91169SAlexander Graf static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( 2399faea1041SHeinrich Schuchardt efi_handle_t handle, ...) 2400bee91169SAlexander Graf { 2401bee91169SAlexander Graf EFI_ENTRY("%p", handle); 2402843ce54cSHeinrich Schuchardt 2403beb077a2SAlexander Graf efi_va_list argptr; 2404843ce54cSHeinrich Schuchardt const efi_guid_t *protocol; 2405843ce54cSHeinrich Schuchardt void *protocol_interface; 2406843ce54cSHeinrich Schuchardt efi_status_t r = EFI_SUCCESS; 2407843ce54cSHeinrich Schuchardt size_t i = 0; 2408843ce54cSHeinrich Schuchardt 2409843ce54cSHeinrich Schuchardt if (!handle) 2410bee91169SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 2411843ce54cSHeinrich Schuchardt 2412beb077a2SAlexander Graf efi_va_start(argptr, handle); 2413843ce54cSHeinrich Schuchardt for (;;) { 2414beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2415843ce54cSHeinrich Schuchardt if (!protocol) 2416843ce54cSHeinrich Schuchardt break; 2417beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 24189b47f13bSHeinrich Schuchardt r = efi_uninstall_protocol(handle, protocol, 24199b47f13bSHeinrich Schuchardt protocol_interface); 2420843ce54cSHeinrich Schuchardt if (r != EFI_SUCCESS) 2421843ce54cSHeinrich Schuchardt break; 2422843ce54cSHeinrich Schuchardt i++; 2423843ce54cSHeinrich Schuchardt } 2424beb077a2SAlexander Graf efi_va_end(argptr); 24259b47f13bSHeinrich Schuchardt if (r == EFI_SUCCESS) { 24269b47f13bSHeinrich Schuchardt /* If the last protocol has been removed, delete the handle. */ 24279b47f13bSHeinrich Schuchardt if (list_empty(&handle->protocols)) { 24289b47f13bSHeinrich Schuchardt list_del(&handle->link); 24299b47f13bSHeinrich Schuchardt free(handle); 24309b47f13bSHeinrich Schuchardt } 2431843ce54cSHeinrich Schuchardt return EFI_EXIT(r); 24329b47f13bSHeinrich Schuchardt } 2433843ce54cSHeinrich Schuchardt 2434843ce54cSHeinrich Schuchardt /* If an error occurred undo all changes. */ 2435beb077a2SAlexander Graf efi_va_start(argptr, handle); 2436843ce54cSHeinrich Schuchardt for (; i; --i) { 2437beb077a2SAlexander Graf protocol = efi_va_arg(argptr, efi_guid_t*); 2438beb077a2SAlexander Graf protocol_interface = efi_va_arg(argptr, void*); 2439843ce54cSHeinrich Schuchardt EFI_CALL(efi_install_protocol_interface(&handle, protocol, 2440843ce54cSHeinrich Schuchardt EFI_NATIVE_INTERFACE, 2441843ce54cSHeinrich Schuchardt protocol_interface)); 2442843ce54cSHeinrich Schuchardt } 2443beb077a2SAlexander Graf efi_va_end(argptr); 2444843ce54cSHeinrich Schuchardt 2445e2373021SHeinrich Schuchardt /* In case of an error always return EFI_INVALID_PARAMETER */ 2446e2373021SHeinrich Schuchardt return EFI_EXIT(EFI_INVALID_PARAMETER); 2447bee91169SAlexander Graf } 2448bee91169SAlexander Graf 24496b03cd10SHeinrich Schuchardt /** 245078a88f79SMario Six * efi_calculate_crc32() - calculate cyclic redundancy code 24516b03cd10SHeinrich Schuchardt * @data: buffer with data 24526b03cd10SHeinrich Schuchardt * @data_size: size of buffer in bytes 24536b03cd10SHeinrich Schuchardt * @crc32_p: cyclic redundancy code 245478a88f79SMario Six * 245578a88f79SMario Six * This function implements the CalculateCrc32 service. 245678a88f79SMario Six * 245778a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 245878a88f79SMario Six * details. 245978a88f79SMario Six * 246078a88f79SMario Six * Return: status code 2461332468f7SHeinrich Schuchardt */ 24628aa8360eSHeinrich Schuchardt static efi_status_t EFIAPI efi_calculate_crc32(const void *data, 24638aa8360eSHeinrich Schuchardt efi_uintn_t data_size, 24648aa8360eSHeinrich Schuchardt u32 *crc32_p) 2465bee91169SAlexander Graf { 24668aa8360eSHeinrich Schuchardt EFI_ENTRY("%p, %zu", data, data_size); 2467bee91169SAlexander Graf *crc32_p = crc32(0, data, data_size); 2468bee91169SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 2469bee91169SAlexander Graf } 2470bee91169SAlexander Graf 24716b03cd10SHeinrich Schuchardt /** 247278a88f79SMario Six * efi_copy_mem() - copy memory 24736b03cd10SHeinrich Schuchardt * @destination: destination of the copy operation 24746b03cd10SHeinrich Schuchardt * @source: source of the copy operation 24756b03cd10SHeinrich Schuchardt * @length: number of bytes to copy 247678a88f79SMario Six * 247778a88f79SMario Six * This function implements the CopyMem service. 247878a88f79SMario Six * 247978a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 248078a88f79SMario Six * details. 2481332468f7SHeinrich Schuchardt */ 2482fc05a959SHeinrich Schuchardt static void EFIAPI efi_copy_mem(void *destination, const void *source, 2483fc05a959SHeinrich Schuchardt size_t length) 2484bee91169SAlexander Graf { 2485fc05a959SHeinrich Schuchardt EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length); 2486*0bc81a71SHeinrich Schuchardt memmove(destination, source, length); 2487f7c78176SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 2488bee91169SAlexander Graf } 2489bee91169SAlexander Graf 24906b03cd10SHeinrich Schuchardt /** 249178a88f79SMario Six * efi_set_mem() - Fill memory with a byte value. 24926b03cd10SHeinrich Schuchardt * @buffer: buffer to fill 24936b03cd10SHeinrich Schuchardt * @size: size of buffer in bytes 24946b03cd10SHeinrich Schuchardt * @value: byte to copy to the buffer 249578a88f79SMario Six * 249678a88f79SMario Six * This function implements the SetMem service. 249778a88f79SMario Six * 249878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 249978a88f79SMario Six * details. 2500332468f7SHeinrich Schuchardt */ 2501fc05a959SHeinrich Schuchardt static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) 2502bee91169SAlexander Graf { 2503fc05a959SHeinrich Schuchardt EFI_ENTRY("%p, %ld, 0x%x", buffer, (unsigned long)size, value); 2504bee91169SAlexander Graf memset(buffer, value, size); 2505f7c78176SHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS); 2506bee91169SAlexander Graf } 2507bee91169SAlexander Graf 25086b03cd10SHeinrich Schuchardt /** 250978a88f79SMario Six * efi_protocol_open() - open protocol interface on a handle 25106b03cd10SHeinrich Schuchardt * @handler: handler of a protocol 25116b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 25126b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 25136b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 25146b03cd10SHeinrich Schuchardt * @attributes: attributes indicating how to open the protocol 251578a88f79SMario Six * 251678a88f79SMario Six * Return: status code 2517191a41ccSHeinrich Schuchardt */ 2518191a41ccSHeinrich Schuchardt static efi_status_t efi_protocol_open( 2519191a41ccSHeinrich Schuchardt struct efi_handler *handler, 2520191a41ccSHeinrich Schuchardt void **protocol_interface, void *agent_handle, 2521191a41ccSHeinrich Schuchardt void *controller_handle, uint32_t attributes) 2522191a41ccSHeinrich Schuchardt { 2523191a41ccSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2524191a41ccSHeinrich Schuchardt struct efi_open_protocol_info_entry *match = NULL; 2525191a41ccSHeinrich Schuchardt bool opened_by_driver = false; 2526191a41ccSHeinrich Schuchardt bool opened_exclusive = false; 2527191a41ccSHeinrich Schuchardt 2528191a41ccSHeinrich Schuchardt /* If there is no agent, only return the interface */ 2529191a41ccSHeinrich Schuchardt if (!agent_handle) 2530191a41ccSHeinrich Schuchardt goto out; 2531191a41ccSHeinrich Schuchardt 2532191a41ccSHeinrich Schuchardt /* For TEST_PROTOCOL ignore interface attribute */ 2533191a41ccSHeinrich Schuchardt if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) 2534191a41ccSHeinrich Schuchardt *protocol_interface = NULL; 2535191a41ccSHeinrich Schuchardt 2536191a41ccSHeinrich Schuchardt /* 2537191a41ccSHeinrich Schuchardt * Check if the protocol is already opened by a driver with the same 2538191a41ccSHeinrich Schuchardt * attributes or opened exclusively 2539191a41ccSHeinrich Schuchardt */ 2540191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2541191a41ccSHeinrich Schuchardt if (item->info.agent_handle == agent_handle) { 2542191a41ccSHeinrich Schuchardt if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) && 2543191a41ccSHeinrich Schuchardt (item->info.attributes == attributes)) 2544191a41ccSHeinrich Schuchardt return EFI_ALREADY_STARTED; 2545191a41ccSHeinrich Schuchardt } 2546191a41ccSHeinrich Schuchardt if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) 2547191a41ccSHeinrich Schuchardt opened_exclusive = true; 2548191a41ccSHeinrich Schuchardt } 2549191a41ccSHeinrich Schuchardt 2550191a41ccSHeinrich Schuchardt /* Only one controller can open the protocol exclusively */ 2551191a41ccSHeinrich Schuchardt if (opened_exclusive && attributes & 2552191a41ccSHeinrich Schuchardt (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER)) 2553191a41ccSHeinrich Schuchardt return EFI_ACCESS_DENIED; 2554191a41ccSHeinrich Schuchardt 2555191a41ccSHeinrich Schuchardt /* Prepare exclusive opening */ 2556191a41ccSHeinrich Schuchardt if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { 2557191a41ccSHeinrich Schuchardt /* Try to disconnect controllers */ 2558191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2559191a41ccSHeinrich Schuchardt if (item->info.attributes == 2560191a41ccSHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_DRIVER) 2561191a41ccSHeinrich Schuchardt EFI_CALL(efi_disconnect_controller( 2562191a41ccSHeinrich Schuchardt item->info.controller_handle, 2563191a41ccSHeinrich Schuchardt item->info.agent_handle, 2564191a41ccSHeinrich Schuchardt NULL)); 2565191a41ccSHeinrich Schuchardt } 2566191a41ccSHeinrich Schuchardt opened_by_driver = false; 2567191a41ccSHeinrich Schuchardt /* Check if all controllers are disconnected */ 2568191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2569191a41ccSHeinrich Schuchardt if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) 2570191a41ccSHeinrich Schuchardt opened_by_driver = true; 2571191a41ccSHeinrich Schuchardt } 25724f37fa47SHeinrich Schuchardt /* Only one controller can be connected */ 2573191a41ccSHeinrich Schuchardt if (opened_by_driver) 2574191a41ccSHeinrich Schuchardt return EFI_ACCESS_DENIED; 2575191a41ccSHeinrich Schuchardt } 2576191a41ccSHeinrich Schuchardt 2577191a41ccSHeinrich Schuchardt /* Find existing entry */ 2578191a41ccSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2579191a41ccSHeinrich Schuchardt if (item->info.agent_handle == agent_handle && 2580191a41ccSHeinrich Schuchardt item->info.controller_handle == controller_handle) 2581191a41ccSHeinrich Schuchardt match = &item->info; 2582191a41ccSHeinrich Schuchardt } 2583191a41ccSHeinrich Schuchardt /* None found, create one */ 2584191a41ccSHeinrich Schuchardt if (!match) { 2585191a41ccSHeinrich Schuchardt match = efi_create_open_info(handler); 2586191a41ccSHeinrich Schuchardt if (!match) 2587191a41ccSHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 2588191a41ccSHeinrich Schuchardt } 2589191a41ccSHeinrich Schuchardt 2590191a41ccSHeinrich Schuchardt match->agent_handle = agent_handle; 2591191a41ccSHeinrich Schuchardt match->controller_handle = controller_handle; 2592191a41ccSHeinrich Schuchardt match->attributes = attributes; 2593191a41ccSHeinrich Schuchardt match->open_count++; 2594191a41ccSHeinrich Schuchardt 2595191a41ccSHeinrich Schuchardt out: 2596191a41ccSHeinrich Schuchardt /* For TEST_PROTOCOL ignore interface attribute. */ 2597191a41ccSHeinrich Schuchardt if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) 2598191a41ccSHeinrich Schuchardt *protocol_interface = handler->protocol_interface; 2599191a41ccSHeinrich Schuchardt 2600191a41ccSHeinrich Schuchardt return EFI_SUCCESS; 2601191a41ccSHeinrich Schuchardt } 2602191a41ccSHeinrich Schuchardt 26036b03cd10SHeinrich Schuchardt /** 260478a88f79SMario Six * efi_open_protocol() - open protocol interface on a handle 26056b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be opened 26066b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 26076b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 26086b03cd10SHeinrich Schuchardt * @agent_handle: handle of the driver 26096b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 26106b03cd10SHeinrich Schuchardt * @attributes: attributes indicating how to open the protocol 261178a88f79SMario Six * 261278a88f79SMario Six * This function implements the OpenProtocol interface. 261378a88f79SMario Six * 261478a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 261578a88f79SMario Six * details. 261678a88f79SMario Six * 261778a88f79SMario Six * Return: status code 2618332468f7SHeinrich Schuchardt */ 2619faea1041SHeinrich Schuchardt static efi_status_t EFIAPI efi_open_protocol 2620faea1041SHeinrich Schuchardt (efi_handle_t handle, const efi_guid_t *protocol, 2621faea1041SHeinrich Schuchardt void **protocol_interface, efi_handle_t agent_handle, 2622faea1041SHeinrich Schuchardt efi_handle_t controller_handle, uint32_t attributes) 2623bee91169SAlexander Graf { 262480286e8fSHeinrich Schuchardt struct efi_handler *handler; 262569baec67Sxypron.glpk@gmx.de efi_status_t r = EFI_INVALID_PARAMETER; 2626bee91169SAlexander Graf 2627778e6af8SRob Clark EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol, 2628bee91169SAlexander Graf protocol_interface, agent_handle, controller_handle, 2629bee91169SAlexander Graf attributes); 2630b5349f74Sxypron.glpk@gmx.de 263169baec67Sxypron.glpk@gmx.de if (!handle || !protocol || 263269baec67Sxypron.glpk@gmx.de (!protocol_interface && attributes != 263369baec67Sxypron.glpk@gmx.de EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) { 263469baec67Sxypron.glpk@gmx.de goto out; 263569baec67Sxypron.glpk@gmx.de } 263669baec67Sxypron.glpk@gmx.de 263769baec67Sxypron.glpk@gmx.de switch (attributes) { 263869baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: 263969baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_GET_PROTOCOL: 264069baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_TEST_PROTOCOL: 264169baec67Sxypron.glpk@gmx.de break; 264269baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: 264369baec67Sxypron.glpk@gmx.de if (controller_handle == handle) 264469baec67Sxypron.glpk@gmx.de goto out; 2645191a41ccSHeinrich Schuchardt /* fall-through */ 264669baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_DRIVER: 264769baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE: 2648191a41ccSHeinrich Schuchardt /* Check that the controller handle is valid */ 2649191a41ccSHeinrich Schuchardt if (!efi_search_obj(controller_handle)) 265069baec67Sxypron.glpk@gmx.de goto out; 2651191a41ccSHeinrich Schuchardt /* fall-through */ 265269baec67Sxypron.glpk@gmx.de case EFI_OPEN_PROTOCOL_EXCLUSIVE: 2653191a41ccSHeinrich Schuchardt /* Check that the agent handle is valid */ 2654191a41ccSHeinrich Schuchardt if (!efi_search_obj(agent_handle)) 265569baec67Sxypron.glpk@gmx.de goto out; 265669baec67Sxypron.glpk@gmx.de break; 265769baec67Sxypron.glpk@gmx.de default: 2658b5349f74Sxypron.glpk@gmx.de goto out; 2659b5349f74Sxypron.glpk@gmx.de } 2660b5349f74Sxypron.glpk@gmx.de 266180286e8fSHeinrich Schuchardt r = efi_search_protocol(handle, protocol, &handler); 266280286e8fSHeinrich Schuchardt if (r != EFI_SUCCESS) 2663bee91169SAlexander Graf goto out; 2664bee91169SAlexander Graf 2665191a41ccSHeinrich Schuchardt r = efi_protocol_open(handler, protocol_interface, agent_handle, 2666191a41ccSHeinrich Schuchardt controller_handle, attributes); 2667bee91169SAlexander Graf out: 2668bee91169SAlexander Graf return EFI_EXIT(r); 2669bee91169SAlexander Graf } 2670bee91169SAlexander Graf 26716b03cd10SHeinrich Schuchardt /** 267278a88f79SMario Six * efi_handle_protocol() - get interface of a protocol on a handle 26736b03cd10SHeinrich Schuchardt * @handle: handle on which the protocol shall be opened 26746b03cd10SHeinrich Schuchardt * @protocol: GUID of the protocol 26756b03cd10SHeinrich Schuchardt * @protocol_interface: interface implementing the protocol 267678a88f79SMario Six * 267778a88f79SMario Six * This function implements the HandleProtocol service. 267878a88f79SMario Six * 267978a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 268078a88f79SMario Six * details. 268178a88f79SMario Six * 268278a88f79SMario Six * Return: status code 2683332468f7SHeinrich Schuchardt */ 26842074f700SHeinrich Schuchardt static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, 26855a9682d0SHeinrich Schuchardt const efi_guid_t *protocol, 2686bee91169SAlexander Graf void **protocol_interface) 2687bee91169SAlexander Graf { 26888e1d329fSxypron.glpk@gmx.de return efi_open_protocol(handle, protocol, protocol_interface, NULL, 26898e1d329fSxypron.glpk@gmx.de NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); 2690bee91169SAlexander Graf } 2691bee91169SAlexander Graf 26926b03cd10SHeinrich Schuchardt /** 269378a88f79SMario Six * efi_bind_controller() - bind a single driver to a controller 26946b03cd10SHeinrich Schuchardt * @controller_handle: controller handle 26956b03cd10SHeinrich Schuchardt * @driver_image_handle: driver handle 26966b03cd10SHeinrich Schuchardt * @remain_device_path: remaining path 269778a88f79SMario Six * 269878a88f79SMario Six * Return: status code 26996b03cd10SHeinrich Schuchardt */ 2700f0959dbeSHeinrich Schuchardt static efi_status_t efi_bind_controller( 2701f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2702f0959dbeSHeinrich Schuchardt efi_handle_t driver_image_handle, 2703f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path) 2704f0959dbeSHeinrich Schuchardt { 2705f0959dbeSHeinrich Schuchardt struct efi_driver_binding_protocol *binding_protocol; 2706f0959dbeSHeinrich Schuchardt efi_status_t r; 2707f0959dbeSHeinrich Schuchardt 2708f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_open_protocol(driver_image_handle, 2709f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2710f0959dbeSHeinrich Schuchardt (void **)&binding_protocol, 2711f0959dbeSHeinrich Schuchardt driver_image_handle, NULL, 2712f0959dbeSHeinrich Schuchardt EFI_OPEN_PROTOCOL_GET_PROTOCOL)); 2713f0959dbeSHeinrich Schuchardt if (r != EFI_SUCCESS) 2714f0959dbeSHeinrich Schuchardt return r; 2715f0959dbeSHeinrich Schuchardt r = EFI_CALL(binding_protocol->supported(binding_protocol, 2716f0959dbeSHeinrich Schuchardt controller_handle, 2717f0959dbeSHeinrich Schuchardt remain_device_path)); 2718f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2719f0959dbeSHeinrich Schuchardt r = EFI_CALL(binding_protocol->start(binding_protocol, 2720f0959dbeSHeinrich Schuchardt controller_handle, 2721f0959dbeSHeinrich Schuchardt remain_device_path)); 2722f0959dbeSHeinrich Schuchardt EFI_CALL(efi_close_protocol(driver_image_handle, 2723f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2724f0959dbeSHeinrich Schuchardt driver_image_handle, NULL)); 2725f0959dbeSHeinrich Schuchardt return r; 2726f0959dbeSHeinrich Schuchardt } 2727f0959dbeSHeinrich Schuchardt 27286b03cd10SHeinrich Schuchardt /** 272978a88f79SMario Six * efi_connect_single_controller() - connect a single driver to a controller 27306b03cd10SHeinrich Schuchardt * @controller_handle: controller 27316b03cd10SHeinrich Schuchardt * @driver_image_handle: driver 2732b72aaa87SHeinrich Schuchardt * @remain_device_path: remaining path 273378a88f79SMario Six * 273478a88f79SMario Six * Return: status code 27356b03cd10SHeinrich Schuchardt */ 2736f0959dbeSHeinrich Schuchardt static efi_status_t efi_connect_single_controller( 2737f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2738f0959dbeSHeinrich Schuchardt efi_handle_t *driver_image_handle, 2739f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path) 2740f0959dbeSHeinrich Schuchardt { 2741f0959dbeSHeinrich Schuchardt efi_handle_t *buffer; 2742f0959dbeSHeinrich Schuchardt size_t count; 2743f0959dbeSHeinrich Schuchardt size_t i; 2744f0959dbeSHeinrich Schuchardt efi_status_t r; 2745f0959dbeSHeinrich Schuchardt size_t connected = 0; 2746f0959dbeSHeinrich Schuchardt 2747f0959dbeSHeinrich Schuchardt /* Get buffer with all handles with driver binding protocol */ 2748f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, 2749f0959dbeSHeinrich Schuchardt &efi_guid_driver_binding_protocol, 2750f0959dbeSHeinrich Schuchardt NULL, &count, &buffer)); 2751f0959dbeSHeinrich Schuchardt if (r != EFI_SUCCESS) 2752f0959dbeSHeinrich Schuchardt return r; 2753f0959dbeSHeinrich Schuchardt 2754f0959dbeSHeinrich Schuchardt /* Context Override */ 2755f0959dbeSHeinrich Schuchardt if (driver_image_handle) { 2756f0959dbeSHeinrich Schuchardt for (; *driver_image_handle; ++driver_image_handle) { 2757f0959dbeSHeinrich Schuchardt for (i = 0; i < count; ++i) { 2758f0959dbeSHeinrich Schuchardt if (buffer[i] == *driver_image_handle) { 2759f0959dbeSHeinrich Schuchardt buffer[i] = NULL; 2760f0959dbeSHeinrich Schuchardt r = efi_bind_controller( 2761f0959dbeSHeinrich Schuchardt controller_handle, 2762f0959dbeSHeinrich Schuchardt *driver_image_handle, 2763f0959dbeSHeinrich Schuchardt remain_device_path); 2764f0959dbeSHeinrich Schuchardt /* 2765f0959dbeSHeinrich Schuchardt * For drivers that do not support the 2766f0959dbeSHeinrich Schuchardt * controller or are already connected 2767f0959dbeSHeinrich Schuchardt * we receive an error code here. 2768f0959dbeSHeinrich Schuchardt */ 2769f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2770f0959dbeSHeinrich Schuchardt ++connected; 2771f0959dbeSHeinrich Schuchardt } 2772f0959dbeSHeinrich Schuchardt } 2773f0959dbeSHeinrich Schuchardt } 2774f0959dbeSHeinrich Schuchardt } 2775f0959dbeSHeinrich Schuchardt 2776f0959dbeSHeinrich Schuchardt /* 2777f0959dbeSHeinrich Schuchardt * TODO: Some overrides are not yet implemented: 2778f0959dbeSHeinrich Schuchardt * - Platform Driver Override 2779f0959dbeSHeinrich Schuchardt * - Driver Family Override Search 2780f0959dbeSHeinrich Schuchardt * - Bus Specific Driver Override 2781f0959dbeSHeinrich Schuchardt */ 2782f0959dbeSHeinrich Schuchardt 2783f0959dbeSHeinrich Schuchardt /* Driver Binding Search */ 2784f0959dbeSHeinrich Schuchardt for (i = 0; i < count; ++i) { 2785f0959dbeSHeinrich Schuchardt if (buffer[i]) { 2786f0959dbeSHeinrich Schuchardt r = efi_bind_controller(controller_handle, 2787f0959dbeSHeinrich Schuchardt buffer[i], 2788f0959dbeSHeinrich Schuchardt remain_device_path); 2789f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2790f0959dbeSHeinrich Schuchardt ++connected; 2791f0959dbeSHeinrich Schuchardt } 2792f0959dbeSHeinrich Schuchardt } 2793f0959dbeSHeinrich Schuchardt 2794f0959dbeSHeinrich Schuchardt efi_free_pool(buffer); 2795f0959dbeSHeinrich Schuchardt if (!connected) 2796f0959dbeSHeinrich Schuchardt return EFI_NOT_FOUND; 2797f0959dbeSHeinrich Schuchardt return EFI_SUCCESS; 2798f0959dbeSHeinrich Schuchardt } 2799f0959dbeSHeinrich Schuchardt 28006b03cd10SHeinrich Schuchardt /** 280178a88f79SMario Six * efi_connect_controller() - connect a controller to a driver 280278a88f79SMario Six * @controller_handle: handle of the controller 280378a88f79SMario Six * @driver_image_handle: handle of the driver 280478a88f79SMario Six * @remain_device_path: device path of a child controller 280578a88f79SMario Six * @recursive: true to connect all child controllers 2806f0959dbeSHeinrich Schuchardt * 2807f0959dbeSHeinrich Schuchardt * This function implements the ConnectController service. 280878a88f79SMario Six * 280978a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 281078a88f79SMario Six * details. 2811f0959dbeSHeinrich Schuchardt * 2812f0959dbeSHeinrich Schuchardt * First all driver binding protocol handles are tried for binding drivers. 2813b72aaa87SHeinrich Schuchardt * Afterwards all handles that have opened a protocol of the controller 2814f0959dbeSHeinrich Schuchardt * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. 2815f0959dbeSHeinrich Schuchardt * 281678a88f79SMario Six * Return: status code 2817f0959dbeSHeinrich Schuchardt */ 2818f0959dbeSHeinrich Schuchardt static efi_status_t EFIAPI efi_connect_controller( 2819f0959dbeSHeinrich Schuchardt efi_handle_t controller_handle, 2820f0959dbeSHeinrich Schuchardt efi_handle_t *driver_image_handle, 2821f0959dbeSHeinrich Schuchardt struct efi_device_path *remain_device_path, 2822f0959dbeSHeinrich Schuchardt bool recursive) 2823f0959dbeSHeinrich Schuchardt { 2824f0959dbeSHeinrich Schuchardt efi_status_t r; 2825f0959dbeSHeinrich Schuchardt efi_status_t ret = EFI_NOT_FOUND; 2826f0959dbeSHeinrich Schuchardt struct efi_object *efiobj; 2827f0959dbeSHeinrich Schuchardt 2828d178836bSHeinrich Schuchardt EFI_ENTRY("%p, %p, %pD, %d", controller_handle, driver_image_handle, 2829f0959dbeSHeinrich Schuchardt remain_device_path, recursive); 2830f0959dbeSHeinrich Schuchardt 2831f0959dbeSHeinrich Schuchardt efiobj = efi_search_obj(controller_handle); 2832f0959dbeSHeinrich Schuchardt if (!efiobj) { 2833f0959dbeSHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 2834f0959dbeSHeinrich Schuchardt goto out; 2835f0959dbeSHeinrich Schuchardt } 2836f0959dbeSHeinrich Schuchardt 2837f0959dbeSHeinrich Schuchardt r = efi_connect_single_controller(controller_handle, 2838f0959dbeSHeinrich Schuchardt driver_image_handle, 2839f0959dbeSHeinrich Schuchardt remain_device_path); 2840f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2841f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2842f0959dbeSHeinrich Schuchardt if (recursive) { 2843f0959dbeSHeinrich Schuchardt struct efi_handler *handler; 2844f0959dbeSHeinrich Schuchardt struct efi_open_protocol_info_item *item; 2845f0959dbeSHeinrich Schuchardt 2846f0959dbeSHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 2847f0959dbeSHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 2848f0959dbeSHeinrich Schuchardt if (item->info.attributes & 2849f0959dbeSHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 2850f0959dbeSHeinrich Schuchardt r = EFI_CALL(efi_connect_controller( 2851f0959dbeSHeinrich Schuchardt item->info.controller_handle, 2852f0959dbeSHeinrich Schuchardt driver_image_handle, 2853f0959dbeSHeinrich Schuchardt remain_device_path, 2854f0959dbeSHeinrich Schuchardt recursive)); 2855f0959dbeSHeinrich Schuchardt if (r == EFI_SUCCESS) 2856f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2857f0959dbeSHeinrich Schuchardt } 2858f0959dbeSHeinrich Schuchardt } 2859f0959dbeSHeinrich Schuchardt } 2860f0959dbeSHeinrich Schuchardt } 2861f0959dbeSHeinrich Schuchardt /* Check for child controller specified by end node */ 2862f0959dbeSHeinrich Schuchardt if (ret != EFI_SUCCESS && remain_device_path && 2863f0959dbeSHeinrich Schuchardt remain_device_path->type == DEVICE_PATH_TYPE_END) 2864f0959dbeSHeinrich Schuchardt ret = EFI_SUCCESS; 2865f0959dbeSHeinrich Schuchardt out: 2866f0959dbeSHeinrich Schuchardt return EFI_EXIT(ret); 2867f0959dbeSHeinrich Schuchardt } 2868f0959dbeSHeinrich Schuchardt 28696b03cd10SHeinrich Schuchardt /** 287078a88f79SMario Six * efi_reinstall_protocol_interface() - reinstall protocol interface 287178a88f79SMario Six * @handle: handle on which the protocol shall be reinstalled 287278a88f79SMario Six * @protocol: GUID of the protocol to be installed 287378a88f79SMario Six * @old_interface: interface to be removed 287478a88f79SMario Six * @new_interface: interface to be installed 2875e861a120SHeinrich Schuchardt * 2876e861a120SHeinrich Schuchardt * This function implements the ReinstallProtocolInterface service. 287778a88f79SMario Six * 287878a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 287978a88f79SMario Six * details. 2880e861a120SHeinrich Schuchardt * 2881e861a120SHeinrich Schuchardt * The old interface is uninstalled. The new interface is installed. 2882e861a120SHeinrich Schuchardt * Drivers are connected. 2883e861a120SHeinrich Schuchardt * 288478a88f79SMario Six * Return: status code 2885e861a120SHeinrich Schuchardt */ 2886e861a120SHeinrich Schuchardt static efi_status_t EFIAPI efi_reinstall_protocol_interface( 2887e861a120SHeinrich Schuchardt efi_handle_t handle, const efi_guid_t *protocol, 2888e861a120SHeinrich Schuchardt void *old_interface, void *new_interface) 2889e861a120SHeinrich Schuchardt { 2890e861a120SHeinrich Schuchardt efi_status_t ret; 2891e861a120SHeinrich Schuchardt 2892e861a120SHeinrich Schuchardt EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface, 2893e861a120SHeinrich Schuchardt new_interface); 28949b47f13bSHeinrich Schuchardt 28959b47f13bSHeinrich Schuchardt /* Uninstall protocol but do not delete handle */ 28969b47f13bSHeinrich Schuchardt ret = efi_uninstall_protocol(handle, protocol, old_interface); 2897e861a120SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2898e861a120SHeinrich Schuchardt goto out; 28999b47f13bSHeinrich Schuchardt 29009b47f13bSHeinrich Schuchardt /* Install the new protocol */ 29019b47f13bSHeinrich Schuchardt ret = efi_add_protocol(handle, protocol, new_interface); 29029b47f13bSHeinrich Schuchardt /* 29039b47f13bSHeinrich Schuchardt * The UEFI spec does not specify what should happen to the handle 29049b47f13bSHeinrich Schuchardt * if in case of an error no protocol interface remains on the handle. 29059b47f13bSHeinrich Schuchardt * So let's do nothing here. 29069b47f13bSHeinrich Schuchardt */ 2907e861a120SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2908e861a120SHeinrich Schuchardt goto out; 2909e861a120SHeinrich Schuchardt /* 2910e861a120SHeinrich Schuchardt * The returned status code has to be ignored. 2911e861a120SHeinrich Schuchardt * Do not create an error if no suitable driver for the handle exists. 2912e861a120SHeinrich Schuchardt */ 2913e861a120SHeinrich Schuchardt EFI_CALL(efi_connect_controller(handle, NULL, NULL, true)); 2914e861a120SHeinrich Schuchardt out: 2915e861a120SHeinrich Schuchardt return EFI_EXIT(ret); 2916e861a120SHeinrich Schuchardt } 2917e861a120SHeinrich Schuchardt 29186b03cd10SHeinrich Schuchardt /** 291978a88f79SMario Six * efi_get_child_controllers() - get all child controllers associated to a driver 29206b03cd10SHeinrich Schuchardt * @efiobj: handle of the controller 29216b03cd10SHeinrich Schuchardt * @driver_handle: handle of the driver 29226b03cd10SHeinrich Schuchardt * @number_of_children: number of child controllers 29236b03cd10SHeinrich Schuchardt * @child_handle_buffer: handles of the the child controllers 292478a88f79SMario Six * 292578a88f79SMario Six * The allocated buffer has to be freed with free(). 292678a88f79SMario Six * 292778a88f79SMario Six * Return: status code 29283f9b0042SHeinrich Schuchardt */ 29293f9b0042SHeinrich Schuchardt static efi_status_t efi_get_child_controllers( 29303f9b0042SHeinrich Schuchardt struct efi_object *efiobj, 29313f9b0042SHeinrich Schuchardt efi_handle_t driver_handle, 29323f9b0042SHeinrich Schuchardt efi_uintn_t *number_of_children, 29333f9b0042SHeinrich Schuchardt efi_handle_t **child_handle_buffer) 29343f9b0042SHeinrich Schuchardt { 29353f9b0042SHeinrich Schuchardt struct efi_handler *handler; 29363f9b0042SHeinrich Schuchardt struct efi_open_protocol_info_item *item; 29373f9b0042SHeinrich Schuchardt efi_uintn_t count = 0, i; 29383f9b0042SHeinrich Schuchardt bool duplicate; 29393f9b0042SHeinrich Schuchardt 29403f9b0042SHeinrich Schuchardt /* Count all child controller associations */ 29413f9b0042SHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 29423f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 29433f9b0042SHeinrich Schuchardt if (item->info.agent_handle == driver_handle && 29443f9b0042SHeinrich Schuchardt item->info.attributes & 29453f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) 29463f9b0042SHeinrich Schuchardt ++count; 29473f9b0042SHeinrich Schuchardt } 29483f9b0042SHeinrich Schuchardt } 29493f9b0042SHeinrich Schuchardt /* 29503f9b0042SHeinrich Schuchardt * Create buffer. In case of duplicate child controller assignments 29513f9b0042SHeinrich Schuchardt * the buffer will be too large. But that does not harm. 29523f9b0042SHeinrich Schuchardt */ 29533f9b0042SHeinrich Schuchardt *number_of_children = 0; 29543f9b0042SHeinrich Schuchardt *child_handle_buffer = calloc(count, sizeof(efi_handle_t)); 29553f9b0042SHeinrich Schuchardt if (!*child_handle_buffer) 29563f9b0042SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 29573f9b0042SHeinrich Schuchardt /* Copy unique child handles */ 29583f9b0042SHeinrich Schuchardt list_for_each_entry(handler, &efiobj->protocols, link) { 29593f9b0042SHeinrich Schuchardt list_for_each_entry(item, &handler->open_infos, link) { 29603f9b0042SHeinrich Schuchardt if (item->info.agent_handle == driver_handle && 29613f9b0042SHeinrich Schuchardt item->info.attributes & 29623f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 29633f9b0042SHeinrich Schuchardt /* Check this is a new child controller */ 29643f9b0042SHeinrich Schuchardt duplicate = false; 29653f9b0042SHeinrich Schuchardt for (i = 0; i < *number_of_children; ++i) { 29663f9b0042SHeinrich Schuchardt if ((*child_handle_buffer)[i] == 29673f9b0042SHeinrich Schuchardt item->info.controller_handle) 29683f9b0042SHeinrich Schuchardt duplicate = true; 29693f9b0042SHeinrich Schuchardt } 29703f9b0042SHeinrich Schuchardt /* Copy handle to buffer */ 29713f9b0042SHeinrich Schuchardt if (!duplicate) { 29723f9b0042SHeinrich Schuchardt i = (*number_of_children)++; 29733f9b0042SHeinrich Schuchardt (*child_handle_buffer)[i] = 29743f9b0042SHeinrich Schuchardt item->info.controller_handle; 29753f9b0042SHeinrich Schuchardt } 29763f9b0042SHeinrich Schuchardt } 29773f9b0042SHeinrich Schuchardt } 29783f9b0042SHeinrich Schuchardt } 29793f9b0042SHeinrich Schuchardt return EFI_SUCCESS; 29803f9b0042SHeinrich Schuchardt } 29813f9b0042SHeinrich Schuchardt 29826b03cd10SHeinrich Schuchardt /** 298378a88f79SMario Six * efi_disconnect_controller() - disconnect a controller from a driver 29846b03cd10SHeinrich Schuchardt * @controller_handle: handle of the controller 29856b03cd10SHeinrich Schuchardt * @driver_image_handle: handle of the driver 29866b03cd10SHeinrich Schuchardt * @child_handle: handle of the child to destroy 298778a88f79SMario Six * 298878a88f79SMario Six * This function implements the DisconnectController service. 298978a88f79SMario Six * 299078a88f79SMario Six * See the Unified Extensible Firmware Interface (UEFI) specification for 299178a88f79SMario Six * details. 299278a88f79SMario Six * 299378a88f79SMario Six * Return: status code 29943f9b0042SHeinrich Schuchardt */ 29953f9b0042SHeinrich Schuchardt static efi_status_t EFIAPI efi_disconnect_controller( 29963f9b0042SHeinrich Schuchardt efi_handle_t controller_handle, 29973f9b0042SHeinrich Schuchardt efi_handle_t driver_image_handle, 29983f9b0042SHeinrich Schuchardt efi_handle_t child_handle) 29993f9b0042SHeinrich Schuchardt { 30003f9b0042SHeinrich Schuchardt struct efi_driver_binding_protocol *binding_protocol; 30013f9b0042SHeinrich Schuchardt efi_handle_t *child_handle_buffer = NULL; 30023f9b0042SHeinrich Schuchardt size_t number_of_children = 0; 30033f9b0042SHeinrich Schuchardt efi_status_t r; 30043f9b0042SHeinrich Schuchardt size_t stop_count = 0; 30053f9b0042SHeinrich Schuchardt struct efi_object *efiobj; 30063f9b0042SHeinrich Schuchardt 30073f9b0042SHeinrich Schuchardt EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle, 30083f9b0042SHeinrich Schuchardt child_handle); 30093f9b0042SHeinrich Schuchardt 30103f9b0042SHeinrich Schuchardt efiobj = efi_search_obj(controller_handle); 30113f9b0042SHeinrich Schuchardt if (!efiobj) { 30123f9b0042SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 30133f9b0042SHeinrich Schuchardt goto out; 30143f9b0042SHeinrich Schuchardt } 30153f9b0042SHeinrich Schuchardt 30163f9b0042SHeinrich Schuchardt if (child_handle && !efi_search_obj(child_handle)) { 30173f9b0042SHeinrich Schuchardt r = EFI_INVALID_PARAMETER; 30183f9b0042SHeinrich Schuchardt goto out; 30193f9b0042SHeinrich Schuchardt } 30203f9b0042SHeinrich Schuchardt 30213f9b0042SHeinrich Schuchardt /* If no driver handle is supplied, disconnect all drivers */ 30223f9b0042SHeinrich Schuchardt if (!driver_image_handle) { 30233f9b0042SHeinrich Schuchardt r = efi_disconnect_all_drivers(efiobj, NULL, child_handle); 30243f9b0042SHeinrich Schuchardt goto out; 30253f9b0042SHeinrich Schuchardt } 30263f9b0042SHeinrich Schuchardt 30273f9b0042SHeinrich Schuchardt /* Create list of child handles */ 30283f9b0042SHeinrich Schuchardt if (child_handle) { 30293f9b0042SHeinrich Schuchardt number_of_children = 1; 30303f9b0042SHeinrich Schuchardt child_handle_buffer = &child_handle; 30313f9b0042SHeinrich Schuchardt } else { 30323f9b0042SHeinrich Schuchardt efi_get_child_controllers(efiobj, 30333f9b0042SHeinrich Schuchardt driver_image_handle, 30343f9b0042SHeinrich Schuchardt &number_of_children, 30353f9b0042SHeinrich Schuchardt &child_handle_buffer); 30363f9b0042SHeinrich Schuchardt } 30373f9b0042SHeinrich Schuchardt 30383f9b0042SHeinrich Schuchardt /* Get the driver binding protocol */ 30393f9b0042SHeinrich Schuchardt r = EFI_CALL(efi_open_protocol(driver_image_handle, 30403f9b0042SHeinrich Schuchardt &efi_guid_driver_binding_protocol, 30413f9b0042SHeinrich Schuchardt (void **)&binding_protocol, 30423f9b0042SHeinrich Schuchardt driver_image_handle, NULL, 30433f9b0042SHeinrich Schuchardt EFI_OPEN_PROTOCOL_GET_PROTOCOL)); 30443f9b0042SHeinrich Schuchardt if (r != EFI_SUCCESS) 30453f9b0042SHeinrich Schuchardt goto out; 30463f9b0042SHeinrich Schuchardt /* Remove the children */ 30473f9b0042SHeinrich Schuchardt if (number_of_children) { 30483f9b0042SHeinrich Schuchardt r = EFI_CALL(binding_protocol->stop(binding_protocol, 30493f9b0042SHeinrich Schuchardt controller_handle, 30503f9b0042SHeinrich Schuchardt number_of_children, 30513f9b0042SHeinrich Schuchardt child_handle_buffer)); 30523f9b0042SHeinrich Schuchardt if (r == EFI_SUCCESS) 30533f9b0042SHeinrich Schuchardt ++stop_count; 30543f9b0042SHeinrich Schuchardt } 30553f9b0042SHeinrich Schuchardt /* Remove the driver */ 30563f9b0042SHeinrich Schuchardt if (!child_handle) 30573f9b0042SHeinrich Schuchardt r = EFI_CALL(binding_protocol->stop(binding_protocol, 30583f9b0042SHeinrich Schuchardt controller_handle, 30593f9b0042SHeinrich Schuchardt 0, NULL)); 30603f9b0042SHeinrich Schuchardt if (r == EFI_SUCCESS) 30613f9b0042SHeinrich Schuchardt ++stop_count; 30623f9b0042SHeinrich Schuchardt EFI_CALL(efi_close_protocol(driver_image_handle, 30633f9b0042SHeinrich Schuchardt &efi_guid_driver_binding_protocol, 30643f9b0042SHeinrich Schuchardt driver_image_handle, NULL)); 30653f9b0042SHeinrich Schuchardt 30663f9b0042SHeinrich Schuchardt if (stop_count) 30673f9b0042SHeinrich Schuchardt r = EFI_SUCCESS; 30683f9b0042SHeinrich Schuchardt else 30693f9b0042SHeinrich Schuchardt r = EFI_NOT_FOUND; 30703f9b0042SHeinrich Schuchardt out: 30713f9b0042SHeinrich Schuchardt if (!child_handle) 30723f9b0042SHeinrich Schuchardt free(child_handle_buffer); 30733f9b0042SHeinrich Schuchardt return EFI_EXIT(r); 30743f9b0042SHeinrich Schuchardt } 30753f9b0042SHeinrich Schuchardt 3076640adadfSHeinrich Schuchardt static struct efi_boot_services efi_boot_services = { 3077bee91169SAlexander Graf .hdr = { 3078112f2430SHeinrich Schuchardt .signature = EFI_BOOT_SERVICES_SIGNATURE, 3079112f2430SHeinrich Schuchardt .revision = EFI_SPECIFICATION_VERSION, 308071c846abSHeinrich Schuchardt .headersize = sizeof(struct efi_boot_services), 3081bee91169SAlexander Graf }, 3082bee91169SAlexander Graf .raise_tpl = efi_raise_tpl, 3083bee91169SAlexander Graf .restore_tpl = efi_restore_tpl, 3084bee91169SAlexander Graf .allocate_pages = efi_allocate_pages_ext, 3085bee91169SAlexander Graf .free_pages = efi_free_pages_ext, 3086bee91169SAlexander Graf .get_memory_map = efi_get_memory_map_ext, 3087ead1274bSStefan Brüns .allocate_pool = efi_allocate_pool_ext, 308842417bc8SStefan Brüns .free_pool = efi_free_pool_ext, 308949deb455Sxypron.glpk@gmx.de .create_event = efi_create_event_ext, 3090bfc72462Sxypron.glpk@gmx.de .set_timer = efi_set_timer_ext, 3091bee91169SAlexander Graf .wait_for_event = efi_wait_for_event, 3092c6841592Sxypron.glpk@gmx.de .signal_event = efi_signal_event_ext, 3093bee91169SAlexander Graf .close_event = efi_close_event, 3094bee91169SAlexander Graf .check_event = efi_check_event, 30951760ef57SHeinrich Schuchardt .install_protocol_interface = efi_install_protocol_interface, 3096bee91169SAlexander Graf .reinstall_protocol_interface = efi_reinstall_protocol_interface, 3097cd534083SHeinrich Schuchardt .uninstall_protocol_interface = efi_uninstall_protocol_interface, 3098bee91169SAlexander Graf .handle_protocol = efi_handle_protocol, 3099bee91169SAlexander Graf .reserved = NULL, 3100bee91169SAlexander Graf .register_protocol_notify = efi_register_protocol_notify, 310126329584Sxypron.glpk@gmx.de .locate_handle = efi_locate_handle_ext, 3102bee91169SAlexander Graf .locate_device_path = efi_locate_device_path, 3103488bf12dSAlexander Graf .install_configuration_table = efi_install_configuration_table_ext, 3104bee91169SAlexander Graf .load_image = efi_load_image, 3105bee91169SAlexander Graf .start_image = efi_start_image, 3106a86aeaf2SAlexander Graf .exit = efi_exit, 3107bee91169SAlexander Graf .unload_image = efi_unload_image, 3108bee91169SAlexander Graf .exit_boot_services = efi_exit_boot_services, 3109bee91169SAlexander Graf .get_next_monotonic_count = efi_get_next_monotonic_count, 3110bee91169SAlexander Graf .stall = efi_stall, 3111bee91169SAlexander Graf .set_watchdog_timer = efi_set_watchdog_timer, 3112bee91169SAlexander Graf .connect_controller = efi_connect_controller, 3113bee91169SAlexander Graf .disconnect_controller = efi_disconnect_controller, 3114bee91169SAlexander Graf .open_protocol = efi_open_protocol, 3115bee91169SAlexander Graf .close_protocol = efi_close_protocol, 3116bee91169SAlexander Graf .open_protocol_information = efi_open_protocol_information, 3117bee91169SAlexander Graf .protocols_per_handle = efi_protocols_per_handle, 3118bee91169SAlexander Graf .locate_handle_buffer = efi_locate_handle_buffer, 3119bee91169SAlexander Graf .locate_protocol = efi_locate_protocol, 3120ab9efa97SHeinrich Schuchardt .install_multiple_protocol_interfaces = 3121ab9efa97SHeinrich Schuchardt efi_install_multiple_protocol_interfaces, 3122ab9efa97SHeinrich Schuchardt .uninstall_multiple_protocol_interfaces = 3123ab9efa97SHeinrich Schuchardt efi_uninstall_multiple_protocol_interfaces, 3124bee91169SAlexander Graf .calculate_crc32 = efi_calculate_crc32, 3125bee91169SAlexander Graf .copy_mem = efi_copy_mem, 3126bee91169SAlexander Graf .set_mem = efi_set_mem, 31279f0930e5SHeinrich Schuchardt .create_event_ex = efi_create_event_ex, 3128bee91169SAlexander Graf }; 3129bee91169SAlexander Graf 31300b386537SHeinrich Schuchardt static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; 3131bee91169SAlexander Graf 31323c63db9cSAlexander Graf struct efi_system_table __efi_runtime_data systab = { 3133bee91169SAlexander Graf .hdr = { 3134bee91169SAlexander Graf .signature = EFI_SYSTEM_TABLE_SIGNATURE, 3135112f2430SHeinrich Schuchardt .revision = EFI_SPECIFICATION_VERSION, 313671c846abSHeinrich Schuchardt .headersize = sizeof(struct efi_system_table), 3137bee91169SAlexander Graf }, 31380b386537SHeinrich Schuchardt .fw_vendor = firmware_vendor, 31390b386537SHeinrich Schuchardt .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8, 3140bee91169SAlexander Graf .con_in = (void *)&efi_con_in, 3141bee91169SAlexander Graf .con_out = (void *)&efi_con_out, 3142bee91169SAlexander Graf .std_err = (void *)&efi_con_out, 3143bee91169SAlexander Graf .runtime = (void *)&efi_runtime_services, 3144bee91169SAlexander Graf .boottime = (void *)&efi_boot_services, 3145bee91169SAlexander Graf .nr_tables = 0, 31464182a129SHeinrich Schuchardt .tables = NULL, 3147bee91169SAlexander Graf }; 3148640adadfSHeinrich Schuchardt 3149640adadfSHeinrich Schuchardt /** 3150640adadfSHeinrich Schuchardt * efi_initialize_system_table() - Initialize system table 3151640adadfSHeinrich Schuchardt * 31520414359aSHeinrich Schuchardt * Return: status code 3153640adadfSHeinrich Schuchardt */ 3154640adadfSHeinrich Schuchardt efi_status_t efi_initialize_system_table(void) 3155640adadfSHeinrich Schuchardt { 31564182a129SHeinrich Schuchardt efi_status_t ret; 31574182a129SHeinrich Schuchardt 31584182a129SHeinrich Schuchardt /* Allocate configuration table array */ 31594182a129SHeinrich Schuchardt ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA, 31604182a129SHeinrich Schuchardt EFI_MAX_CONFIGURATION_TABLES * 31614182a129SHeinrich Schuchardt sizeof(struct efi_configuration_table), 31624182a129SHeinrich Schuchardt (void **)&systab.tables); 31634182a129SHeinrich Schuchardt 3164b72aaa87SHeinrich Schuchardt /* Set CRC32 field in table headers */ 3165640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&systab.hdr); 3166640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&efi_runtime_services.hdr); 3167640adadfSHeinrich Schuchardt efi_update_table_header_crc32(&efi_boot_services.hdr); 31684182a129SHeinrich Schuchardt 31694182a129SHeinrich Schuchardt return ret; 3170640adadfSHeinrich Schuchardt } 3171