1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI application runtime services 4 * 5 * Copyright (c) 2016 Alexander Graf 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <dm.h> 11 #include <elf.h> 12 #include <efi_loader.h> 13 #include <rtc.h> 14 15 /* For manual relocation support */ 16 DECLARE_GLOBAL_DATA_PTR; 17 18 struct efi_runtime_mmio_list { 19 struct list_head link; 20 void **ptr; 21 u64 paddr; 22 u64 len; 23 }; 24 25 /* This list contains all runtime available mmio regions */ 26 LIST_HEAD(efi_runtime_mmio); 27 28 static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); 29 static efi_status_t __efi_runtime EFIAPI efi_device_error(void); 30 static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); 31 32 /* 33 * TODO(sjg@chromium.org): These defines and structs should come from the elf 34 * header for each arch (or a generic header) rather than being repeated here. 35 */ 36 #if defined(__aarch64__) 37 #define R_RELATIVE R_AARCH64_RELATIVE 38 #define R_MASK 0xffffffffULL 39 #define IS_RELA 1 40 #elif defined(__arm__) 41 #define R_RELATIVE R_ARM_RELATIVE 42 #define R_MASK 0xffULL 43 #elif defined(__x86_64__) || defined(__i386__) 44 #define R_RELATIVE R_386_RELATIVE 45 #define R_MASK 0xffULL 46 #elif defined(__riscv) 47 #define R_RELATIVE R_RISCV_RELATIVE 48 #define R_MASK 0xffULL 49 #define IS_RELA 1 50 51 struct dyn_sym { 52 ulong foo1; 53 ulong addr; 54 u32 foo2; 55 u32 foo3; 56 }; 57 #if (__riscv_xlen == 32) 58 #define R_ABSOLUTE R_RISCV_32 59 #define SYM_INDEX 8 60 #elif (__riscv_xlen == 64) 61 #define R_ABSOLUTE R_RISCV_64 62 #define SYM_INDEX 32 63 #else 64 #error unknown riscv target 65 #endif 66 #else 67 #error Need to add relocation awareness 68 #endif 69 70 struct elf_rel { 71 ulong *offset; 72 ulong info; 73 }; 74 75 struct elf_rela { 76 ulong *offset; 77 ulong info; 78 long addend; 79 }; 80 81 /* 82 * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI 83 * payload are running concurrently at the same time. In this mode, we can 84 * handle a good number of runtime callbacks 85 */ 86 87 static void EFIAPI efi_reset_system_boottime( 88 enum efi_reset_type reset_type, 89 efi_status_t reset_status, 90 unsigned long data_size, void *reset_data) 91 { 92 struct efi_event *evt; 93 94 EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size, 95 reset_data); 96 97 /* Notify reset */ 98 list_for_each_entry(evt, &efi_events, link) { 99 if (evt->group && 100 !guidcmp(evt->group, 101 &efi_guid_event_group_reset_system)) { 102 efi_signal_event(evt, false); 103 break; 104 } 105 } 106 switch (reset_type) { 107 case EFI_RESET_COLD: 108 case EFI_RESET_WARM: 109 case EFI_RESET_PLATFORM_SPECIFIC: 110 do_reset(NULL, 0, 0, NULL); 111 break; 112 case EFI_RESET_SHUTDOWN: 113 /* We don't have anything to map this to */ 114 break; 115 } 116 117 while (1) { } 118 } 119 120 /** 121 * efi_get_time_boottime - get current time 122 * 123 * This function implements the GetTime runtime service. 124 * See the Unified Extensible Firmware Interface (UEFI) specification 125 * for details. 126 * 127 * @time: pointer to structure to receive current time 128 * @capabilities: pointer to structure to receive RTC properties 129 * Return Value: status code 130 */ 131 static efi_status_t EFIAPI efi_get_time_boottime( 132 struct efi_time *time, 133 struct efi_time_cap *capabilities) 134 { 135 #ifdef CONFIG_DM_RTC 136 efi_status_t ret = EFI_SUCCESS; 137 int r; 138 struct rtc_time tm; 139 struct udevice *dev; 140 141 EFI_ENTRY("%p %p", time, capabilities); 142 143 if (!time) { 144 ret = EFI_INVALID_PARAMETER; 145 goto out; 146 } 147 148 r = uclass_get_device(UCLASS_RTC, 0, &dev); 149 if (!r) 150 r = dm_rtc_get(dev, &tm); 151 if (r) { 152 ret = EFI_DEVICE_ERROR; 153 goto out; 154 } 155 156 memset(time, 0, sizeof(*time)); 157 time->year = tm.tm_year; 158 time->month = tm.tm_mon; 159 time->day = tm.tm_mday; 160 time->hour = tm.tm_hour; 161 time->minute = tm.tm_min; 162 time->second = tm.tm_sec; 163 time->daylight = EFI_TIME_ADJUST_DAYLIGHT; 164 if (tm.tm_isdst > 0) 165 time->daylight |= EFI_TIME_IN_DAYLIGHT; 166 time->timezone = EFI_UNSPECIFIED_TIMEZONE; 167 168 if (capabilities) { 169 /* Set reasonable dummy values */ 170 capabilities->resolution = 1; /* 1 Hz */ 171 capabilities->accuracy = 100000000; /* 100 ppm */ 172 capabilities->sets_to_zero = false; 173 } 174 out: 175 return EFI_EXIT(ret); 176 #else 177 EFI_ENTRY("%p %p", time, capabilities); 178 return EFI_EXIT(EFI_DEVICE_ERROR); 179 #endif 180 } 181 182 /* Boards may override the helpers below to implement RTS functionality */ 183 184 void __weak __efi_runtime EFIAPI efi_reset_system( 185 enum efi_reset_type reset_type, 186 efi_status_t reset_status, 187 unsigned long data_size, void *reset_data) 188 { 189 /* Nothing we can do */ 190 while (1) { } 191 } 192 193 efi_status_t __weak efi_reset_system_init(void) 194 { 195 return EFI_SUCCESS; 196 } 197 198 efi_status_t __weak __efi_runtime EFIAPI efi_get_time( 199 struct efi_time *time, 200 struct efi_time_cap *capabilities) 201 { 202 /* Nothing we can do */ 203 return EFI_DEVICE_ERROR; 204 } 205 206 struct efi_runtime_detach_list_struct { 207 void *ptr; 208 void *patchto; 209 }; 210 211 static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { 212 { 213 /* do_reset is gone */ 214 .ptr = &efi_runtime_services.reset_system, 215 .patchto = efi_reset_system, 216 }, { 217 /* invalidate_*cache_all are gone */ 218 .ptr = &efi_runtime_services.set_virtual_address_map, 219 .patchto = &efi_invalid_parameter, 220 }, { 221 /* RTC accessors are gone */ 222 .ptr = &efi_runtime_services.get_time, 223 .patchto = &efi_get_time, 224 }, { 225 /* Clean up system table */ 226 .ptr = &systab.con_in, 227 .patchto = NULL, 228 }, { 229 /* Clean up system table */ 230 .ptr = &systab.con_out, 231 .patchto = NULL, 232 }, { 233 /* Clean up system table */ 234 .ptr = &systab.std_err, 235 .patchto = NULL, 236 }, { 237 /* Clean up system table */ 238 .ptr = &systab.boottime, 239 .patchto = NULL, 240 }, { 241 .ptr = &efi_runtime_services.get_variable, 242 .patchto = &efi_device_error, 243 }, { 244 .ptr = &efi_runtime_services.get_next_variable_name, 245 .patchto = &efi_device_error, 246 }, { 247 .ptr = &efi_runtime_services.set_variable, 248 .patchto = &efi_device_error, 249 } 250 }; 251 252 static bool efi_runtime_tobedetached(void *p) 253 { 254 int i; 255 256 for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) 257 if (efi_runtime_detach_list[i].ptr == p) 258 return true; 259 260 return false; 261 } 262 263 static void efi_runtime_detach(ulong offset) 264 { 265 int i; 266 ulong patchoff = offset - (ulong)gd->relocaddr; 267 268 for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) { 269 ulong patchto = (ulong)efi_runtime_detach_list[i].patchto; 270 ulong *p = efi_runtime_detach_list[i].ptr; 271 ulong newaddr = patchto ? (patchto + patchoff) : 0; 272 273 debug("%s: Setting %p to %lx\n", __func__, p, newaddr); 274 *p = newaddr; 275 } 276 } 277 278 /* Relocate EFI runtime to uboot_reloc_base = offset */ 279 void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) 280 { 281 #ifdef IS_RELA 282 struct elf_rela *rel = (void*)&__efi_runtime_rel_start; 283 #else 284 struct elf_rel *rel = (void*)&__efi_runtime_rel_start; 285 static ulong lastoff = CONFIG_SYS_TEXT_BASE; 286 #endif 287 288 debug("%s: Relocating to offset=%lx\n", __func__, offset); 289 for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) { 290 ulong base = CONFIG_SYS_TEXT_BASE; 291 ulong *p; 292 ulong newaddr; 293 294 p = (void*)((ulong)rel->offset - base) + gd->relocaddr; 295 296 debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__, rel->info, *p, rel->offset); 297 298 switch (rel->info & R_MASK) { 299 case R_RELATIVE: 300 #ifdef IS_RELA 301 newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE; 302 #else 303 newaddr = *p - lastoff + offset; 304 #endif 305 break; 306 #ifdef R_ABSOLUTE 307 case R_ABSOLUTE: { 308 ulong symidx = rel->info >> SYM_INDEX; 309 extern struct dyn_sym __dyn_sym_start[]; 310 newaddr = __dyn_sym_start[symidx].addr + offset; 311 break; 312 } 313 #endif 314 default: 315 continue; 316 } 317 318 /* Check if the relocation is inside bounds */ 319 if (map && ((newaddr < map->virtual_start) || 320 newaddr > (map->virtual_start + 321 (map->num_pages << EFI_PAGE_SHIFT)))) { 322 if (!efi_runtime_tobedetached(p)) 323 printf("U-Boot EFI: Relocation at %p is out of " 324 "range (%lx)\n", p, newaddr); 325 continue; 326 } 327 328 debug("%s: Setting %p to %lx\n", __func__, p, newaddr); 329 *p = newaddr; 330 flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1), 331 ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE)); 332 } 333 334 #ifndef IS_RELA 335 lastoff = offset; 336 #endif 337 338 invalidate_icache_all(); 339 } 340 341 static efi_status_t EFIAPI efi_set_virtual_address_map( 342 unsigned long memory_map_size, 343 unsigned long descriptor_size, 344 uint32_t descriptor_version, 345 struct efi_mem_desc *virtmap) 346 { 347 ulong runtime_start = (ulong)&__efi_runtime_start & 348 ~(ulong)EFI_PAGE_MASK; 349 int n = memory_map_size / descriptor_size; 350 int i; 351 352 EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size, 353 descriptor_version, virtmap); 354 355 /* Rebind mmio pointers */ 356 for (i = 0; i < n; i++) { 357 struct efi_mem_desc *map = (void*)virtmap + 358 (descriptor_size * i); 359 struct list_head *lhandle; 360 efi_physical_addr_t map_start = map->physical_start; 361 efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT; 362 efi_physical_addr_t map_end = map_start + map_len; 363 364 /* Adjust all mmio pointers in this region */ 365 list_for_each(lhandle, &efi_runtime_mmio) { 366 struct efi_runtime_mmio_list *lmmio; 367 368 lmmio = list_entry(lhandle, 369 struct efi_runtime_mmio_list, 370 link); 371 if ((map_start <= lmmio->paddr) && 372 (map_end >= lmmio->paddr)) { 373 u64 off = map->virtual_start - map_start; 374 uintptr_t new_addr = lmmio->paddr + off; 375 *lmmio->ptr = (void *)new_addr; 376 } 377 } 378 } 379 380 /* Move the actual runtime code over */ 381 for (i = 0; i < n; i++) { 382 struct efi_mem_desc *map; 383 384 map = (void*)virtmap + (descriptor_size * i); 385 if (map->type == EFI_RUNTIME_SERVICES_CODE) { 386 ulong new_offset = map->virtual_start - 387 (runtime_start - gd->relocaddr); 388 389 efi_runtime_relocate(new_offset, map); 390 /* Once we're virtual, we can no longer handle 391 complex callbacks */ 392 efi_runtime_detach(new_offset); 393 return EFI_EXIT(EFI_SUCCESS); 394 } 395 } 396 397 return EFI_EXIT(EFI_INVALID_PARAMETER); 398 } 399 400 efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) 401 { 402 struct efi_runtime_mmio_list *newmmio; 403 u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; 404 uint64_t addr = *(uintptr_t *)mmio_ptr; 405 uint64_t retaddr; 406 407 retaddr = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false); 408 if (retaddr != addr) 409 return EFI_OUT_OF_RESOURCES; 410 411 newmmio = calloc(1, sizeof(*newmmio)); 412 if (!newmmio) 413 return EFI_OUT_OF_RESOURCES; 414 newmmio->ptr = mmio_ptr; 415 newmmio->paddr = *(uintptr_t *)mmio_ptr; 416 newmmio->len = len; 417 list_add_tail(&newmmio->link, &efi_runtime_mmio); 418 419 return EFI_SUCCESS; 420 } 421 422 /* 423 * In the second stage, U-Boot has disappeared. To isolate our runtime code 424 * that at this point still exists from the rest, we put it into a special 425 * section. 426 * 427 * !!WARNING!! 428 * 429 * This means that we can not rely on any code outside of this file in any 430 * function or variable below this line. 431 * 432 * Please keep everything fully self-contained and annotated with 433 * __efi_runtime and __efi_runtime_data markers. 434 */ 435 436 /* 437 * Relocate the EFI runtime stub to a different place. We need to call this 438 * the first time we expose the runtime interface to a user and on set virtual 439 * address map calls. 440 */ 441 442 static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void) 443 { 444 return EFI_UNSUPPORTED; 445 } 446 447 static efi_status_t __efi_runtime EFIAPI efi_device_error(void) 448 { 449 return EFI_DEVICE_ERROR; 450 } 451 452 static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void) 453 { 454 return EFI_INVALID_PARAMETER; 455 } 456 457 efi_status_t __efi_runtime EFIAPI efi_update_capsule( 458 struct efi_capsule_header **capsule_header_array, 459 efi_uintn_t capsule_count, 460 u64 scatter_gather_list) 461 { 462 return EFI_UNSUPPORTED; 463 } 464 465 efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( 466 struct efi_capsule_header **capsule_header_array, 467 efi_uintn_t capsule_count, 468 u64 maximum_capsule_size, 469 u32 reset_type) 470 { 471 return EFI_UNSUPPORTED; 472 } 473 474 efi_status_t __efi_runtime EFIAPI efi_query_variable_info( 475 u32 attributes, 476 u64 *maximum_variable_storage_size, 477 u64 *remaining_variable_storage_size, 478 u64 *maximum_variable_size) 479 { 480 return EFI_UNSUPPORTED; 481 } 482 483 struct efi_runtime_services __efi_runtime_data efi_runtime_services = { 484 .hdr = { 485 .signature = EFI_RUNTIME_SERVICES_SIGNATURE, 486 .revision = EFI_SPECIFICATION_VERSION, 487 .headersize = sizeof(struct efi_runtime_services), 488 }, 489 .get_time = &efi_get_time_boottime, 490 .set_time = (void *)&efi_device_error, 491 .get_wakeup_time = (void *)&efi_unimplemented, 492 .set_wakeup_time = (void *)&efi_unimplemented, 493 .set_virtual_address_map = &efi_set_virtual_address_map, 494 .convert_pointer = (void *)&efi_invalid_parameter, 495 .get_variable = efi_get_variable, 496 .get_next_variable_name = efi_get_next_variable_name, 497 .set_variable = efi_set_variable, 498 .get_next_high_mono_count = (void *)&efi_device_error, 499 .reset_system = &efi_reset_system_boottime, 500 .update_capsule = efi_update_capsule, 501 .query_capsule_caps = efi_query_capsule_caps, 502 .query_variable_info = efi_query_variable_info, 503 }; 504