150149ea3SAlexander Graf /* 250149ea3SAlexander Graf * EFI application runtime services 350149ea3SAlexander Graf * 450149ea3SAlexander Graf * Copyright (c) 2016 Alexander Graf 550149ea3SAlexander Graf * 650149ea3SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 750149ea3SAlexander Graf */ 850149ea3SAlexander Graf 950149ea3SAlexander Graf #include <common.h> 1050149ea3SAlexander Graf #include <command.h> 1150149ea3SAlexander Graf #include <dm.h> 1250149ea3SAlexander Graf #include <efi_loader.h> 1350149ea3SAlexander Graf #include <rtc.h> 1450149ea3SAlexander Graf #include <asm/global_data.h> 1550149ea3SAlexander Graf 1650149ea3SAlexander Graf /* For manual relocation support */ 1750149ea3SAlexander Graf DECLARE_GLOBAL_DATA_PTR; 1850149ea3SAlexander Graf 1980a4800eSAlexander Graf struct efi_runtime_mmio_list { 2080a4800eSAlexander Graf struct list_head link; 2180a4800eSAlexander Graf void **ptr; 2280a4800eSAlexander Graf u64 paddr; 2380a4800eSAlexander Graf u64 len; 2480a4800eSAlexander Graf }; 2580a4800eSAlexander Graf 2680a4800eSAlexander Graf /* This list contains all runtime available mmio regions */ 2780a4800eSAlexander Graf LIST_HEAD(efi_runtime_mmio); 2880a4800eSAlexander Graf 29*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); 30*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_device_error(void); 31*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); 3250149ea3SAlexander Graf 3336c37a84SAlexander Graf #ifdef CONFIG_SYS_CACHELINE_SIZE 3436c37a84SAlexander Graf #define EFI_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE 3536c37a84SAlexander Graf #else 3636c37a84SAlexander Graf /* Just use the greatest cache flush alignment requirement I'm aware of */ 3736c37a84SAlexander Graf #define EFI_CACHELINE_SIZE 128 3836c37a84SAlexander Graf #endif 3936c37a84SAlexander Graf 4050149ea3SAlexander Graf #if defined(CONFIG_ARM64) 4150149ea3SAlexander Graf #define R_RELATIVE 1027 4250149ea3SAlexander Graf #define R_MASK 0xffffffffULL 4350149ea3SAlexander Graf #define IS_RELA 1 4450149ea3SAlexander Graf #elif defined(CONFIG_ARM) 4550149ea3SAlexander Graf #define R_RELATIVE 23 4650149ea3SAlexander Graf #define R_MASK 0xffULL 4765e4c0b1SSimon Glass #elif defined(CONFIG_X86) 4865e4c0b1SSimon Glass #include <asm/elf.h> 4965e4c0b1SSimon Glass #define R_RELATIVE R_386_RELATIVE 5065e4c0b1SSimon Glass #define R_MASK 0xffULL 5150149ea3SAlexander Graf #else 5250149ea3SAlexander Graf #error Need to add relocation awareness 5350149ea3SAlexander Graf #endif 5450149ea3SAlexander Graf 5550149ea3SAlexander Graf struct elf_rel { 5650149ea3SAlexander Graf ulong *offset; 5750149ea3SAlexander Graf ulong info; 5850149ea3SAlexander Graf }; 5950149ea3SAlexander Graf 6050149ea3SAlexander Graf struct elf_rela { 6150149ea3SAlexander Graf ulong *offset; 6250149ea3SAlexander Graf ulong info; 6350149ea3SAlexander Graf long addend; 6450149ea3SAlexander Graf }; 6550149ea3SAlexander Graf 6650149ea3SAlexander Graf /* 6750149ea3SAlexander Graf * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI 6850149ea3SAlexander Graf * payload are running concurrently at the same time. In this mode, we can 6950149ea3SAlexander Graf * handle a good number of runtime callbacks 7050149ea3SAlexander Graf */ 7150149ea3SAlexander Graf 7280a4800eSAlexander Graf static void EFIAPI efi_reset_system_boottime( 7380a4800eSAlexander Graf enum efi_reset_type reset_type, 7450149ea3SAlexander Graf efi_status_t reset_status, 7550149ea3SAlexander Graf unsigned long data_size, void *reset_data) 7650149ea3SAlexander Graf { 7750149ea3SAlexander Graf EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size, 7850149ea3SAlexander Graf reset_data); 7950149ea3SAlexander Graf 8050149ea3SAlexander Graf switch (reset_type) { 8150149ea3SAlexander Graf case EFI_RESET_COLD: 8250149ea3SAlexander Graf case EFI_RESET_WARM: 8350149ea3SAlexander Graf do_reset(NULL, 0, 0, NULL); 8450149ea3SAlexander Graf break; 8550149ea3SAlexander Graf case EFI_RESET_SHUTDOWN: 8650149ea3SAlexander Graf /* We don't have anything to map this to */ 8750149ea3SAlexander Graf break; 8850149ea3SAlexander Graf } 8950149ea3SAlexander Graf 9080a4800eSAlexander Graf while (1) { } 9150149ea3SAlexander Graf } 9250149ea3SAlexander Graf 9380a4800eSAlexander Graf static efi_status_t EFIAPI efi_get_time_boottime( 9480a4800eSAlexander Graf struct efi_time *time, 9550149ea3SAlexander Graf struct efi_time_cap *capabilities) 9650149ea3SAlexander Graf { 9750149ea3SAlexander Graf #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC) 9850149ea3SAlexander Graf struct rtc_time tm; 9950149ea3SAlexander Graf int r; 10050149ea3SAlexander Graf struct udevice *dev; 10150149ea3SAlexander Graf 10250149ea3SAlexander Graf EFI_ENTRY("%p %p", time, capabilities); 10350149ea3SAlexander Graf 10450149ea3SAlexander Graf r = uclass_get_device(UCLASS_RTC, 0, &dev); 10550149ea3SAlexander Graf if (r) 10650149ea3SAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 10750149ea3SAlexander Graf 10850149ea3SAlexander Graf r = dm_rtc_get(dev, &tm); 10950149ea3SAlexander Graf if (r) 11050149ea3SAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 11150149ea3SAlexander Graf 11250149ea3SAlexander Graf memset(time, 0, sizeof(*time)); 11350149ea3SAlexander Graf time->year = tm.tm_year; 11450149ea3SAlexander Graf time->month = tm.tm_mon; 11550149ea3SAlexander Graf time->day = tm.tm_mday; 11650149ea3SAlexander Graf time->hour = tm.tm_hour; 11750149ea3SAlexander Graf time->minute = tm.tm_min; 11850149ea3SAlexander Graf time->daylight = tm.tm_isdst; 11950149ea3SAlexander Graf 12050149ea3SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 12150149ea3SAlexander Graf #else 12250149ea3SAlexander Graf return EFI_DEVICE_ERROR; 12350149ea3SAlexander Graf #endif 12450149ea3SAlexander Graf } 12550149ea3SAlexander Graf 12680a4800eSAlexander Graf /* Boards may override the helpers below to implement RTS functionality */ 12780a4800eSAlexander Graf 128*3c63db9cSAlexander Graf void __weak __efi_runtime EFIAPI efi_reset_system( 12980a4800eSAlexander Graf enum efi_reset_type reset_type, 13080a4800eSAlexander Graf efi_status_t reset_status, 13180a4800eSAlexander Graf unsigned long data_size, void *reset_data) 13280a4800eSAlexander Graf { 13380a4800eSAlexander Graf /* Nothing we can do */ 13480a4800eSAlexander Graf while (1) { } 13580a4800eSAlexander Graf } 13680a4800eSAlexander Graf 13780a4800eSAlexander Graf void __weak efi_reset_system_init(void) 13880a4800eSAlexander Graf { 13980a4800eSAlexander Graf } 14080a4800eSAlexander Graf 141*3c63db9cSAlexander Graf efi_status_t __weak __efi_runtime EFIAPI efi_get_time( 14280a4800eSAlexander Graf struct efi_time *time, 14380a4800eSAlexander Graf struct efi_time_cap *capabilities) 14480a4800eSAlexander Graf { 14580a4800eSAlexander Graf /* Nothing we can do */ 14680a4800eSAlexander Graf return EFI_DEVICE_ERROR; 14780a4800eSAlexander Graf } 14880a4800eSAlexander Graf 14980a4800eSAlexander Graf void __weak efi_get_time_init(void) 15080a4800eSAlexander Graf { 15180a4800eSAlexander Graf } 15280a4800eSAlexander Graf 15350149ea3SAlexander Graf struct efi_runtime_detach_list_struct { 15450149ea3SAlexander Graf void *ptr; 15550149ea3SAlexander Graf void *patchto; 15650149ea3SAlexander Graf }; 15750149ea3SAlexander Graf 15850149ea3SAlexander Graf static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { 15950149ea3SAlexander Graf { 16050149ea3SAlexander Graf /* do_reset is gone */ 16150149ea3SAlexander Graf .ptr = &efi_runtime_services.reset_system, 16280a4800eSAlexander Graf .patchto = efi_reset_system, 16350149ea3SAlexander Graf }, { 16450149ea3SAlexander Graf /* invalidate_*cache_all are gone */ 16550149ea3SAlexander Graf .ptr = &efi_runtime_services.set_virtual_address_map, 16650149ea3SAlexander Graf .patchto = &efi_invalid_parameter, 16750149ea3SAlexander Graf }, { 16850149ea3SAlexander Graf /* RTC accessors are gone */ 16950149ea3SAlexander Graf .ptr = &efi_runtime_services.get_time, 17080a4800eSAlexander Graf .patchto = &efi_get_time, 171ae874405SAlexander Graf }, { 172ae874405SAlexander Graf /* Clean up system table */ 173ae874405SAlexander Graf .ptr = &systab.con_in, 174ae874405SAlexander Graf .patchto = NULL, 175ae874405SAlexander Graf }, { 176ae874405SAlexander Graf /* Clean up system table */ 177ae874405SAlexander Graf .ptr = &systab.con_out, 178ae874405SAlexander Graf .patchto = NULL, 179ae874405SAlexander Graf }, { 180ae874405SAlexander Graf /* Clean up system table */ 181ae874405SAlexander Graf .ptr = &systab.std_err, 182ae874405SAlexander Graf .patchto = NULL, 183ae874405SAlexander Graf }, { 184ae874405SAlexander Graf /* Clean up system table */ 185ae874405SAlexander Graf .ptr = &systab.boottime, 186ae874405SAlexander Graf .patchto = NULL, 18750149ea3SAlexander Graf }, 18850149ea3SAlexander Graf }; 18950149ea3SAlexander Graf 19050149ea3SAlexander Graf static bool efi_runtime_tobedetached(void *p) 19150149ea3SAlexander Graf { 19250149ea3SAlexander Graf int i; 19350149ea3SAlexander Graf 19450149ea3SAlexander Graf for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) 19550149ea3SAlexander Graf if (efi_runtime_detach_list[i].ptr == p) 19650149ea3SAlexander Graf return true; 19750149ea3SAlexander Graf 19850149ea3SAlexander Graf return false; 19950149ea3SAlexander Graf } 20050149ea3SAlexander Graf 20150149ea3SAlexander Graf static void efi_runtime_detach(ulong offset) 20250149ea3SAlexander Graf { 20350149ea3SAlexander Graf int i; 20450149ea3SAlexander Graf ulong patchoff = offset - (ulong)gd->relocaddr; 20550149ea3SAlexander Graf 20650149ea3SAlexander Graf for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) { 20750149ea3SAlexander Graf ulong patchto = (ulong)efi_runtime_detach_list[i].patchto; 20850149ea3SAlexander Graf ulong *p = efi_runtime_detach_list[i].ptr; 20950149ea3SAlexander Graf ulong newaddr = patchto ? (patchto + patchoff) : 0; 21050149ea3SAlexander Graf 211edcef3baSAlexander Graf debug("%s: Setting %p to %lx\n", __func__, p, newaddr); 21250149ea3SAlexander Graf *p = newaddr; 21350149ea3SAlexander Graf } 21450149ea3SAlexander Graf } 21550149ea3SAlexander Graf 21650149ea3SAlexander Graf /* Relocate EFI runtime to uboot_reloc_base = offset */ 21750149ea3SAlexander Graf void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) 21850149ea3SAlexander Graf { 21950149ea3SAlexander Graf #ifdef IS_RELA 22050149ea3SAlexander Graf struct elf_rela *rel = (void*)&__efi_runtime_rel_start; 22150149ea3SAlexander Graf #else 22250149ea3SAlexander Graf struct elf_rel *rel = (void*)&__efi_runtime_rel_start; 22350149ea3SAlexander Graf static ulong lastoff = CONFIG_SYS_TEXT_BASE; 22450149ea3SAlexander Graf #endif 22550149ea3SAlexander Graf 226edcef3baSAlexander Graf debug("%s: Relocating to offset=%lx\n", __func__, offset); 22750149ea3SAlexander Graf for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) { 22850149ea3SAlexander Graf ulong base = CONFIG_SYS_TEXT_BASE; 22950149ea3SAlexander Graf ulong *p; 23050149ea3SAlexander Graf ulong newaddr; 23150149ea3SAlexander Graf 23250149ea3SAlexander Graf p = (void*)((ulong)rel->offset - base) + gd->relocaddr; 23350149ea3SAlexander Graf 23450149ea3SAlexander Graf if ((rel->info & R_MASK) != R_RELATIVE) { 23550149ea3SAlexander Graf continue; 23650149ea3SAlexander Graf } 23750149ea3SAlexander Graf 23850149ea3SAlexander Graf #ifdef IS_RELA 23950149ea3SAlexander Graf newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE; 24050149ea3SAlexander Graf #else 24150149ea3SAlexander Graf newaddr = *p - lastoff + offset; 24250149ea3SAlexander Graf #endif 24350149ea3SAlexander Graf 24450149ea3SAlexander Graf /* Check if the relocation is inside bounds */ 24550149ea3SAlexander Graf if (map && ((newaddr < map->virtual_start) || 24650149ea3SAlexander Graf newaddr > (map->virtual_start + (map->num_pages << 12)))) { 24750149ea3SAlexander Graf if (!efi_runtime_tobedetached(p)) 24850149ea3SAlexander Graf printf("U-Boot EFI: Relocation at %p is out of " 24950149ea3SAlexander Graf "range (%lx)\n", p, newaddr); 25050149ea3SAlexander Graf continue; 25150149ea3SAlexander Graf } 25250149ea3SAlexander Graf 253edcef3baSAlexander Graf debug("%s: Setting %p to %lx\n", __func__, p, newaddr); 25450149ea3SAlexander Graf *p = newaddr; 25536c37a84SAlexander Graf flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1), 25636c37a84SAlexander Graf ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE)); 25750149ea3SAlexander Graf } 25850149ea3SAlexander Graf 25950149ea3SAlexander Graf #ifndef IS_RELA 26050149ea3SAlexander Graf lastoff = offset; 26150149ea3SAlexander Graf #endif 26250149ea3SAlexander Graf 26350149ea3SAlexander Graf invalidate_icache_all(); 26450149ea3SAlexander Graf } 26550149ea3SAlexander Graf 26650149ea3SAlexander Graf static efi_status_t EFIAPI efi_set_virtual_address_map( 26750149ea3SAlexander Graf unsigned long memory_map_size, 26850149ea3SAlexander Graf unsigned long descriptor_size, 26950149ea3SAlexander Graf uint32_t descriptor_version, 27050149ea3SAlexander Graf struct efi_mem_desc *virtmap) 27150149ea3SAlexander Graf { 27250149ea3SAlexander Graf ulong runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL; 27350149ea3SAlexander Graf int n = memory_map_size / descriptor_size; 27450149ea3SAlexander Graf int i; 27550149ea3SAlexander Graf 27650149ea3SAlexander Graf EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size, 27750149ea3SAlexander Graf descriptor_version, virtmap); 27850149ea3SAlexander Graf 27980a4800eSAlexander Graf /* Rebind mmio pointers */ 28080a4800eSAlexander Graf for (i = 0; i < n; i++) { 28180a4800eSAlexander Graf struct efi_mem_desc *map = (void*)virtmap + 28280a4800eSAlexander Graf (descriptor_size * i); 28380a4800eSAlexander Graf struct list_head *lhandle; 28480a4800eSAlexander Graf efi_physical_addr_t map_start = map->physical_start; 28580a4800eSAlexander Graf efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT; 28680a4800eSAlexander Graf efi_physical_addr_t map_end = map_start + map_len; 28780a4800eSAlexander Graf 28880a4800eSAlexander Graf /* Adjust all mmio pointers in this region */ 28980a4800eSAlexander Graf list_for_each(lhandle, &efi_runtime_mmio) { 29080a4800eSAlexander Graf struct efi_runtime_mmio_list *lmmio; 29180a4800eSAlexander Graf 29280a4800eSAlexander Graf lmmio = list_entry(lhandle, 29380a4800eSAlexander Graf struct efi_runtime_mmio_list, 29480a4800eSAlexander Graf link); 29580a4800eSAlexander Graf if ((map_start <= lmmio->paddr) && 29680a4800eSAlexander Graf (map_end >= lmmio->paddr)) { 29780a4800eSAlexander Graf u64 off = map->virtual_start - map_start; 29880a4800eSAlexander Graf uintptr_t new_addr = lmmio->paddr + off; 29980a4800eSAlexander Graf *lmmio->ptr = (void *)new_addr; 30080a4800eSAlexander Graf } 30180a4800eSAlexander Graf } 30280a4800eSAlexander Graf } 30380a4800eSAlexander Graf 30480a4800eSAlexander Graf /* Move the actual runtime code over */ 30550149ea3SAlexander Graf for (i = 0; i < n; i++) { 30650149ea3SAlexander Graf struct efi_mem_desc *map; 30750149ea3SAlexander Graf 30850149ea3SAlexander Graf map = (void*)virtmap + (descriptor_size * i); 30950149ea3SAlexander Graf if (map->type == EFI_RUNTIME_SERVICES_CODE) { 31080a4800eSAlexander Graf ulong new_offset = map->virtual_start - 31180a4800eSAlexander Graf (runtime_start - gd->relocaddr); 31250149ea3SAlexander Graf 31350149ea3SAlexander Graf efi_runtime_relocate(new_offset, map); 31450149ea3SAlexander Graf /* Once we're virtual, we can no longer handle 31550149ea3SAlexander Graf complex callbacks */ 31650149ea3SAlexander Graf efi_runtime_detach(new_offset); 31750149ea3SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 31850149ea3SAlexander Graf } 31950149ea3SAlexander Graf } 32050149ea3SAlexander Graf 32150149ea3SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 32250149ea3SAlexander Graf } 32350149ea3SAlexander Graf 32480a4800eSAlexander Graf void efi_add_runtime_mmio(void *mmio_ptr, u64 len) 32580a4800eSAlexander Graf { 32680a4800eSAlexander Graf struct efi_runtime_mmio_list *newmmio; 32780a4800eSAlexander Graf 32880a4800eSAlexander Graf u64 pages = (len + EFI_PAGE_SIZE - 1) >> EFI_PAGE_SHIFT; 32980a4800eSAlexander Graf efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false); 33080a4800eSAlexander Graf 33180a4800eSAlexander Graf newmmio = calloc(1, sizeof(*newmmio)); 33280a4800eSAlexander Graf newmmio->ptr = mmio_ptr; 33380a4800eSAlexander Graf newmmio->paddr = *(uintptr_t *)mmio_ptr; 33480a4800eSAlexander Graf newmmio->len = len; 33580a4800eSAlexander Graf list_add_tail(&newmmio->link, &efi_runtime_mmio); 33680a4800eSAlexander Graf } 33780a4800eSAlexander Graf 33850149ea3SAlexander Graf /* 33950149ea3SAlexander Graf * In the second stage, U-Boot has disappeared. To isolate our runtime code 34050149ea3SAlexander Graf * that at this point still exists from the rest, we put it into a special 34150149ea3SAlexander Graf * section. 34250149ea3SAlexander Graf * 34350149ea3SAlexander Graf * !!WARNING!! 34450149ea3SAlexander Graf * 34550149ea3SAlexander Graf * This means that we can not rely on any code outside of this file in any 34650149ea3SAlexander Graf * function or variable below this line. 34750149ea3SAlexander Graf * 34850149ea3SAlexander Graf * Please keep everything fully self-contained and annotated with 349*3c63db9cSAlexander Graf * __efi_runtime and __efi_runtime_data markers. 35050149ea3SAlexander Graf */ 35150149ea3SAlexander Graf 35250149ea3SAlexander Graf /* 35350149ea3SAlexander Graf * Relocate the EFI runtime stub to a different place. We need to call this 35450149ea3SAlexander Graf * the first time we expose the runtime interface to a user and on set virtual 35550149ea3SAlexander Graf * address map calls. 35650149ea3SAlexander Graf */ 35750149ea3SAlexander Graf 358*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void) 35950149ea3SAlexander Graf { 36050149ea3SAlexander Graf return EFI_UNSUPPORTED; 36150149ea3SAlexander Graf } 36250149ea3SAlexander Graf 363*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_device_error(void) 36450149ea3SAlexander Graf { 36550149ea3SAlexander Graf return EFI_DEVICE_ERROR; 36650149ea3SAlexander Graf } 36750149ea3SAlexander Graf 368*3c63db9cSAlexander Graf static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void) 36950149ea3SAlexander Graf { 37050149ea3SAlexander Graf return EFI_INVALID_PARAMETER; 37150149ea3SAlexander Graf } 37250149ea3SAlexander Graf 373*3c63db9cSAlexander Graf struct efi_runtime_services __efi_runtime_data efi_runtime_services = { 37450149ea3SAlexander Graf .hdr = { 37550149ea3SAlexander Graf .signature = EFI_RUNTIME_SERVICES_SIGNATURE, 37650149ea3SAlexander Graf .revision = EFI_RUNTIME_SERVICES_REVISION, 37750149ea3SAlexander Graf .headersize = sizeof(struct efi_table_hdr), 37850149ea3SAlexander Graf }, 37980a4800eSAlexander Graf .get_time = &efi_get_time_boottime, 38050149ea3SAlexander Graf .set_time = (void *)&efi_device_error, 38150149ea3SAlexander Graf .get_wakeup_time = (void *)&efi_unimplemented, 38250149ea3SAlexander Graf .set_wakeup_time = (void *)&efi_unimplemented, 38350149ea3SAlexander Graf .set_virtual_address_map = &efi_set_virtual_address_map, 38450149ea3SAlexander Graf .convert_pointer = (void *)&efi_invalid_parameter, 38550149ea3SAlexander Graf .get_variable = (void *)&efi_device_error, 38650149ea3SAlexander Graf .get_next_variable = (void *)&efi_device_error, 38750149ea3SAlexander Graf .set_variable = (void *)&efi_device_error, 38850149ea3SAlexander Graf .get_next_high_mono_count = (void *)&efi_device_error, 38980a4800eSAlexander Graf .reset_system = &efi_reset_system_boottime, 39050149ea3SAlexander Graf }; 391