1*50149ea3SAlexander Graf /* 2*50149ea3SAlexander Graf * EFI application runtime services 3*50149ea3SAlexander Graf * 4*50149ea3SAlexander Graf * Copyright (c) 2016 Alexander Graf 5*50149ea3SAlexander Graf * 6*50149ea3SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7*50149ea3SAlexander Graf */ 8*50149ea3SAlexander Graf 9*50149ea3SAlexander Graf #include <common.h> 10*50149ea3SAlexander Graf #include <command.h> 11*50149ea3SAlexander Graf #include <dm.h> 12*50149ea3SAlexander Graf #include <efi_loader.h> 13*50149ea3SAlexander Graf #include <rtc.h> 14*50149ea3SAlexander Graf #include <asm/global_data.h> 15*50149ea3SAlexander Graf 16*50149ea3SAlexander Graf /* For manual relocation support */ 17*50149ea3SAlexander Graf DECLARE_GLOBAL_DATA_PTR; 18*50149ea3SAlexander Graf 19*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void); 20*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void); 21*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void); 22*50149ea3SAlexander Graf 23*50149ea3SAlexander Graf #if defined(CONFIG_ARM64) 24*50149ea3SAlexander Graf #define R_RELATIVE 1027 25*50149ea3SAlexander Graf #define R_MASK 0xffffffffULL 26*50149ea3SAlexander Graf #define IS_RELA 1 27*50149ea3SAlexander Graf #elif defined(CONFIG_ARM) 28*50149ea3SAlexander Graf #define R_RELATIVE 23 29*50149ea3SAlexander Graf #define R_MASK 0xffULL 30*50149ea3SAlexander Graf #else 31*50149ea3SAlexander Graf #error Need to add relocation awareness 32*50149ea3SAlexander Graf #endif 33*50149ea3SAlexander Graf 34*50149ea3SAlexander Graf struct elf_rel { 35*50149ea3SAlexander Graf ulong *offset; 36*50149ea3SAlexander Graf ulong info; 37*50149ea3SAlexander Graf }; 38*50149ea3SAlexander Graf 39*50149ea3SAlexander Graf struct elf_rela { 40*50149ea3SAlexander Graf ulong *offset; 41*50149ea3SAlexander Graf ulong info; 42*50149ea3SAlexander Graf long addend; 43*50149ea3SAlexander Graf }; 44*50149ea3SAlexander Graf 45*50149ea3SAlexander Graf /* 46*50149ea3SAlexander Graf * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI 47*50149ea3SAlexander Graf * payload are running concurrently at the same time. In this mode, we can 48*50149ea3SAlexander Graf * handle a good number of runtime callbacks 49*50149ea3SAlexander Graf */ 50*50149ea3SAlexander Graf 51*50149ea3SAlexander Graf static void EFIAPI efi_reset_system(enum efi_reset_type reset_type, 52*50149ea3SAlexander Graf efi_status_t reset_status, 53*50149ea3SAlexander Graf unsigned long data_size, void *reset_data) 54*50149ea3SAlexander Graf { 55*50149ea3SAlexander Graf EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size, 56*50149ea3SAlexander Graf reset_data); 57*50149ea3SAlexander Graf 58*50149ea3SAlexander Graf switch (reset_type) { 59*50149ea3SAlexander Graf case EFI_RESET_COLD: 60*50149ea3SAlexander Graf case EFI_RESET_WARM: 61*50149ea3SAlexander Graf do_reset(NULL, 0, 0, NULL); 62*50149ea3SAlexander Graf break; 63*50149ea3SAlexander Graf case EFI_RESET_SHUTDOWN: 64*50149ea3SAlexander Graf /* We don't have anything to map this to */ 65*50149ea3SAlexander Graf break; 66*50149ea3SAlexander Graf } 67*50149ea3SAlexander Graf 68*50149ea3SAlexander Graf EFI_EXIT(EFI_SUCCESS); 69*50149ea3SAlexander Graf } 70*50149ea3SAlexander Graf 71*50149ea3SAlexander Graf static efi_status_t EFIAPI efi_get_time(struct efi_time *time, 72*50149ea3SAlexander Graf struct efi_time_cap *capabilities) 73*50149ea3SAlexander Graf { 74*50149ea3SAlexander Graf #if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC) 75*50149ea3SAlexander Graf struct rtc_time tm; 76*50149ea3SAlexander Graf int r; 77*50149ea3SAlexander Graf struct udevice *dev; 78*50149ea3SAlexander Graf 79*50149ea3SAlexander Graf EFI_ENTRY("%p %p", time, capabilities); 80*50149ea3SAlexander Graf 81*50149ea3SAlexander Graf r = uclass_get_device(UCLASS_RTC, 0, &dev); 82*50149ea3SAlexander Graf if (r) 83*50149ea3SAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 84*50149ea3SAlexander Graf 85*50149ea3SAlexander Graf r = dm_rtc_get(dev, &tm); 86*50149ea3SAlexander Graf if (r) 87*50149ea3SAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 88*50149ea3SAlexander Graf 89*50149ea3SAlexander Graf memset(time, 0, sizeof(*time)); 90*50149ea3SAlexander Graf time->year = tm.tm_year; 91*50149ea3SAlexander Graf time->month = tm.tm_mon; 92*50149ea3SAlexander Graf time->day = tm.tm_mday; 93*50149ea3SAlexander Graf time->hour = tm.tm_hour; 94*50149ea3SAlexander Graf time->minute = tm.tm_min; 95*50149ea3SAlexander Graf time->daylight = tm.tm_isdst; 96*50149ea3SAlexander Graf 97*50149ea3SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 98*50149ea3SAlexander Graf #else 99*50149ea3SAlexander Graf return EFI_DEVICE_ERROR; 100*50149ea3SAlexander Graf #endif 101*50149ea3SAlexander Graf } 102*50149ea3SAlexander Graf 103*50149ea3SAlexander Graf struct efi_runtime_detach_list_struct { 104*50149ea3SAlexander Graf void *ptr; 105*50149ea3SAlexander Graf void *patchto; 106*50149ea3SAlexander Graf }; 107*50149ea3SAlexander Graf 108*50149ea3SAlexander Graf static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { 109*50149ea3SAlexander Graf { 110*50149ea3SAlexander Graf /* do_reset is gone */ 111*50149ea3SAlexander Graf .ptr = &efi_runtime_services.reset_system, 112*50149ea3SAlexander Graf .patchto = NULL, 113*50149ea3SAlexander Graf }, { 114*50149ea3SAlexander Graf /* invalidate_*cache_all are gone */ 115*50149ea3SAlexander Graf .ptr = &efi_runtime_services.set_virtual_address_map, 116*50149ea3SAlexander Graf .patchto = &efi_invalid_parameter, 117*50149ea3SAlexander Graf }, { 118*50149ea3SAlexander Graf /* RTC accessors are gone */ 119*50149ea3SAlexander Graf .ptr = &efi_runtime_services.get_time, 120*50149ea3SAlexander Graf .patchto = &efi_device_error, 121*50149ea3SAlexander Graf }, 122*50149ea3SAlexander Graf }; 123*50149ea3SAlexander Graf 124*50149ea3SAlexander Graf static bool efi_runtime_tobedetached(void *p) 125*50149ea3SAlexander Graf { 126*50149ea3SAlexander Graf int i; 127*50149ea3SAlexander Graf 128*50149ea3SAlexander Graf for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) 129*50149ea3SAlexander Graf if (efi_runtime_detach_list[i].ptr == p) 130*50149ea3SAlexander Graf return true; 131*50149ea3SAlexander Graf 132*50149ea3SAlexander Graf return false; 133*50149ea3SAlexander Graf } 134*50149ea3SAlexander Graf 135*50149ea3SAlexander Graf static void efi_runtime_detach(ulong offset) 136*50149ea3SAlexander Graf { 137*50149ea3SAlexander Graf int i; 138*50149ea3SAlexander Graf ulong patchoff = offset - (ulong)gd->relocaddr; 139*50149ea3SAlexander Graf 140*50149ea3SAlexander Graf for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) { 141*50149ea3SAlexander Graf ulong patchto = (ulong)efi_runtime_detach_list[i].patchto; 142*50149ea3SAlexander Graf ulong *p = efi_runtime_detach_list[i].ptr; 143*50149ea3SAlexander Graf ulong newaddr = patchto ? (patchto + patchoff) : 0; 144*50149ea3SAlexander Graf 145*50149ea3SAlexander Graf #ifdef DEBUG_EFI 146*50149ea3SAlexander Graf printf("%s: Setting %p to %lx\n", __func__, p, newaddr); 147*50149ea3SAlexander Graf #endif 148*50149ea3SAlexander Graf *p = newaddr; 149*50149ea3SAlexander Graf } 150*50149ea3SAlexander Graf } 151*50149ea3SAlexander Graf 152*50149ea3SAlexander Graf /* Relocate EFI runtime to uboot_reloc_base = offset */ 153*50149ea3SAlexander Graf void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) 154*50149ea3SAlexander Graf { 155*50149ea3SAlexander Graf #ifdef IS_RELA 156*50149ea3SAlexander Graf struct elf_rela *rel = (void*)&__efi_runtime_rel_start; 157*50149ea3SAlexander Graf #else 158*50149ea3SAlexander Graf struct elf_rel *rel = (void*)&__efi_runtime_rel_start; 159*50149ea3SAlexander Graf static ulong lastoff = CONFIG_SYS_TEXT_BASE; 160*50149ea3SAlexander Graf #endif 161*50149ea3SAlexander Graf 162*50149ea3SAlexander Graf #ifdef DEBUG_EFI 163*50149ea3SAlexander Graf printf("%s: Relocating to offset=%lx\n", __func__, offset); 164*50149ea3SAlexander Graf #endif 165*50149ea3SAlexander Graf 166*50149ea3SAlexander Graf for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) { 167*50149ea3SAlexander Graf ulong base = CONFIG_SYS_TEXT_BASE; 168*50149ea3SAlexander Graf ulong *p; 169*50149ea3SAlexander Graf ulong newaddr; 170*50149ea3SAlexander Graf 171*50149ea3SAlexander Graf p = (void*)((ulong)rel->offset - base) + gd->relocaddr; 172*50149ea3SAlexander Graf 173*50149ea3SAlexander Graf if ((rel->info & R_MASK) != R_RELATIVE) { 174*50149ea3SAlexander Graf continue; 175*50149ea3SAlexander Graf } 176*50149ea3SAlexander Graf 177*50149ea3SAlexander Graf #ifdef IS_RELA 178*50149ea3SAlexander Graf newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE; 179*50149ea3SAlexander Graf #else 180*50149ea3SAlexander Graf newaddr = *p - lastoff + offset; 181*50149ea3SAlexander Graf #endif 182*50149ea3SAlexander Graf 183*50149ea3SAlexander Graf /* Check if the relocation is inside bounds */ 184*50149ea3SAlexander Graf if (map && ((newaddr < map->virtual_start) || 185*50149ea3SAlexander Graf newaddr > (map->virtual_start + (map->num_pages << 12)))) { 186*50149ea3SAlexander Graf if (!efi_runtime_tobedetached(p)) 187*50149ea3SAlexander Graf printf("U-Boot EFI: Relocation at %p is out of " 188*50149ea3SAlexander Graf "range (%lx)\n", p, newaddr); 189*50149ea3SAlexander Graf continue; 190*50149ea3SAlexander Graf } 191*50149ea3SAlexander Graf 192*50149ea3SAlexander Graf #ifdef DEBUG_EFI 193*50149ea3SAlexander Graf printf("%s: Setting %p to %lx\n", __func__, p, newaddr); 194*50149ea3SAlexander Graf #endif 195*50149ea3SAlexander Graf 196*50149ea3SAlexander Graf *p = newaddr; 197*50149ea3SAlexander Graf flush_dcache_range((ulong)p, (ulong)&p[1]); 198*50149ea3SAlexander Graf } 199*50149ea3SAlexander Graf 200*50149ea3SAlexander Graf #ifndef IS_RELA 201*50149ea3SAlexander Graf lastoff = offset; 202*50149ea3SAlexander Graf #endif 203*50149ea3SAlexander Graf 204*50149ea3SAlexander Graf invalidate_icache_all(); 205*50149ea3SAlexander Graf } 206*50149ea3SAlexander Graf 207*50149ea3SAlexander Graf static efi_status_t EFIAPI efi_set_virtual_address_map( 208*50149ea3SAlexander Graf unsigned long memory_map_size, 209*50149ea3SAlexander Graf unsigned long descriptor_size, 210*50149ea3SAlexander Graf uint32_t descriptor_version, 211*50149ea3SAlexander Graf struct efi_mem_desc *virtmap) 212*50149ea3SAlexander Graf { 213*50149ea3SAlexander Graf ulong runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL; 214*50149ea3SAlexander Graf int n = memory_map_size / descriptor_size; 215*50149ea3SAlexander Graf int i; 216*50149ea3SAlexander Graf 217*50149ea3SAlexander Graf EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size, 218*50149ea3SAlexander Graf descriptor_version, virtmap); 219*50149ea3SAlexander Graf 220*50149ea3SAlexander Graf for (i = 0; i < n; i++) { 221*50149ea3SAlexander Graf struct efi_mem_desc *map; 222*50149ea3SAlexander Graf 223*50149ea3SAlexander Graf map = (void*)virtmap + (descriptor_size * i); 224*50149ea3SAlexander Graf if (map->type == EFI_RUNTIME_SERVICES_CODE) { 225*50149ea3SAlexander Graf ulong new_offset = map->virtual_start - (runtime_start - gd->relocaddr); 226*50149ea3SAlexander Graf 227*50149ea3SAlexander Graf efi_runtime_relocate(new_offset, map); 228*50149ea3SAlexander Graf /* Once we're virtual, we can no longer handle 229*50149ea3SAlexander Graf complex callbacks */ 230*50149ea3SAlexander Graf efi_runtime_detach(new_offset); 231*50149ea3SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 232*50149ea3SAlexander Graf } 233*50149ea3SAlexander Graf } 234*50149ea3SAlexander Graf 235*50149ea3SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 236*50149ea3SAlexander Graf } 237*50149ea3SAlexander Graf 238*50149ea3SAlexander Graf /* 239*50149ea3SAlexander Graf * In the second stage, U-Boot has disappeared. To isolate our runtime code 240*50149ea3SAlexander Graf * that at this point still exists from the rest, we put it into a special 241*50149ea3SAlexander Graf * section. 242*50149ea3SAlexander Graf * 243*50149ea3SAlexander Graf * !!WARNING!! 244*50149ea3SAlexander Graf * 245*50149ea3SAlexander Graf * This means that we can not rely on any code outside of this file in any 246*50149ea3SAlexander Graf * function or variable below this line. 247*50149ea3SAlexander Graf * 248*50149ea3SAlexander Graf * Please keep everything fully self-contained and annotated with 249*50149ea3SAlexander Graf * EFI_RUNTIME_TEXT and EFI_RUNTIME_DATA markers. 250*50149ea3SAlexander Graf */ 251*50149ea3SAlexander Graf 252*50149ea3SAlexander Graf /* 253*50149ea3SAlexander Graf * Relocate the EFI runtime stub to a different place. We need to call this 254*50149ea3SAlexander Graf * the first time we expose the runtime interface to a user and on set virtual 255*50149ea3SAlexander Graf * address map calls. 256*50149ea3SAlexander Graf */ 257*50149ea3SAlexander Graf 258*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_unimplemented(void) 259*50149ea3SAlexander Graf { 260*50149ea3SAlexander Graf return EFI_UNSUPPORTED; 261*50149ea3SAlexander Graf } 262*50149ea3SAlexander Graf 263*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_device_error(void) 264*50149ea3SAlexander Graf { 265*50149ea3SAlexander Graf return EFI_DEVICE_ERROR; 266*50149ea3SAlexander Graf } 267*50149ea3SAlexander Graf 268*50149ea3SAlexander Graf static efi_status_t EFI_RUNTIME_TEXT EFIAPI efi_invalid_parameter(void) 269*50149ea3SAlexander Graf { 270*50149ea3SAlexander Graf return EFI_INVALID_PARAMETER; 271*50149ea3SAlexander Graf } 272*50149ea3SAlexander Graf 273*50149ea3SAlexander Graf struct efi_runtime_services EFI_RUNTIME_DATA efi_runtime_services = { 274*50149ea3SAlexander Graf .hdr = { 275*50149ea3SAlexander Graf .signature = EFI_RUNTIME_SERVICES_SIGNATURE, 276*50149ea3SAlexander Graf .revision = EFI_RUNTIME_SERVICES_REVISION, 277*50149ea3SAlexander Graf .headersize = sizeof(struct efi_table_hdr), 278*50149ea3SAlexander Graf }, 279*50149ea3SAlexander Graf .get_time = &efi_get_time, 280*50149ea3SAlexander Graf .set_time = (void *)&efi_device_error, 281*50149ea3SAlexander Graf .get_wakeup_time = (void *)&efi_unimplemented, 282*50149ea3SAlexander Graf .set_wakeup_time = (void *)&efi_unimplemented, 283*50149ea3SAlexander Graf .set_virtual_address_map = &efi_set_virtual_address_map, 284*50149ea3SAlexander Graf .convert_pointer = (void *)&efi_invalid_parameter, 285*50149ea3SAlexander Graf .get_variable = (void *)&efi_device_error, 286*50149ea3SAlexander Graf .get_next_variable = (void *)&efi_device_error, 287*50149ea3SAlexander Graf .set_variable = (void *)&efi_device_error, 288*50149ea3SAlexander Graf .get_next_high_mono_count = (void *)&efi_device_error, 289*50149ea3SAlexander Graf .reset_system = &efi_reset_system, 290*50149ea3SAlexander Graf }; 291