Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/lib/efi_loader/efi_runtime.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
 *  EFI application runtime services
4
 *
5
 *  Copyright (c) 2016 Alexander Graf
6
 */
7
8
#define LOG_CATEGORY LOGC_EFI
9
10
#include <command.h>
11
#include <cpu_func.h>
12
#include <dm.h>
13
#include <elf.h>
14
#include <efi_loader.h>
15
#include <efi_variable.h>
16
#include <log.h>
17
#include <malloc.h>
18
#include <rtc.h>
19
#include <asm/global_data.h>
20
#include <u-boot/crc.h>
21
#include <asm/sections.h>
22
23
/* For manual relocation support */
24
DECLARE_GLOBAL_DATA_PTR;
25
26
/* GUID of the runtime properties table */
27
static const efi_guid_t efi_rt_properties_table_guid =
28
        EFI_RT_PROPERTIES_TABLE_GUID;
29
30
struct efi_runtime_mmio_list {
31
  struct list_head link;
32
  void **ptr;
33
  u64 paddr;
34
  u64 len;
35
};
36
37
/* This list contains all runtime available mmio regions */
38
static LIST_HEAD(efi_runtime_mmio);
39
40
static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void);
41
42
/*
43
 * TODO(sjg@chromium.org): These defines and structures should come from the ELF
44
 * header for each architecture (or a generic header) rather than being repeated
45
 * here.
46
 */
47
#if defined(__aarch64__)
48
#define R_RELATIVE  R_AARCH64_RELATIVE
49
#define R_MASK    0xffffffffULL
50
#define IS_RELA   1
51
#elif defined(__arm__)
52
#define R_RELATIVE  R_ARM_RELATIVE
53
#define R_MASK    0xffULL
54
#elif defined(__i386__)
55
#define R_RELATIVE  R_386_RELATIVE
56
#define R_MASK    0xffULL
57
#elif defined(__x86_64__)
58
0
#define R_RELATIVE  R_X86_64_RELATIVE
59
0
#define R_MASK    0xffffffffULL
60
#define IS_RELA   1
61
#elif defined(__riscv)
62
#define R_RELATIVE  R_RISCV_RELATIVE
63
#define R_MASK    0xffULL
64
#define IS_RELA   1
65
66
struct dyn_sym {
67
  ulong foo1;
68
  ulong addr;
69
  u32 foo2;
70
  u32 foo3;
71
};
72
#if (__riscv_xlen == 32)
73
#define R_ABSOLUTE  R_RISCV_32
74
#define SYM_INDEX 8
75
#elif (__riscv_xlen == 64)
76
#define R_ABSOLUTE  R_RISCV_64
77
#define SYM_INDEX 32
78
#else
79
#error unknown riscv target
80
#endif
81
#else
82
#error Need to add relocation awareness
83
#endif
84
85
struct elf_rel {
86
  ulong *offset;
87
  ulong info;
88
};
89
90
struct elf_rela {
91
  ulong *offset;
92
  ulong info;
93
  long addend;
94
};
95
96
static __efi_runtime_data struct efi_mem_desc *efi_virtmap;
97
static __efi_runtime_data efi_uintn_t efi_descriptor_count;
98
static __efi_runtime_data efi_uintn_t efi_descriptor_size;
99
100
/*
101
 * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI
102
 * payload are running concurrently at the same time. In this mode, we can
103
 * handle a good number of runtime callbacks
104
 */
105
106
/**
107
 * efi_init_runtime_supported() - create runtime properties table
108
 *
109
 * Create a configuration table specifying which services are available at
110
 * runtime.
111
 *
112
 * Return:  status code
113
 */
114
efi_status_t efi_init_runtime_supported(void)
115
0
{
116
0
  const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID;
117
0
  efi_status_t ret;
118
0
  struct efi_rt_properties_table *rt_table;
119
120
0
  ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA,
121
0
        sizeof(struct efi_rt_properties_table),
122
0
        (void **)&rt_table);
123
0
  if (ret != EFI_SUCCESS)
124
0
    return ret;
125
126
0
  rt_table->version = EFI_RT_PROPERTIES_TABLE_VERSION;
127
0
  rt_table->length = sizeof(struct efi_rt_properties_table);
128
0
  rt_table->runtime_services_supported =
129
0
        EFI_RT_SUPPORTED_GET_VARIABLE |
130
0
        EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME |
131
0
        EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP |
132
0
        EFI_RT_SUPPORTED_CONVERT_POINTER;
133
134
0
  if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE))
135
0
    rt_table->runtime_services_supported |=
136
0
      EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO;
137
138
0
  if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
139
0
    u8 s = 0;
140
141
0
    ret = efi_set_variable_int(u"RTStorageVolatile",
142
0
             &efi_guid_efi_rt_var_file,
143
0
             EFI_VARIABLE_BOOTSERVICE_ACCESS |
144
0
             EFI_VARIABLE_RUNTIME_ACCESS |
145
0
             EFI_VARIABLE_READ_ONLY,
146
0
             sizeof(EFI_VAR_FILE_NAME),
147
0
             EFI_VAR_FILE_NAME, false);
148
0
    if (ret != EFI_SUCCESS) {
149
0
      log_err("Failed to set RTStorageVolatile\n");
150
0
      return ret;
151
0
    }
152
    /*
153
     * This variable needs to be visible so users can read it,
154
     * but the real contents are going to be filled during
155
     * GetVariable
156
     */
157
0
    ret = efi_set_variable_int(u"VarToFile",
158
0
             &efi_guid_efi_rt_var_file,
159
0
             EFI_VARIABLE_BOOTSERVICE_ACCESS |
160
0
             EFI_VARIABLE_RUNTIME_ACCESS |
161
0
             EFI_VARIABLE_READ_ONLY,
162
0
             sizeof(s),
163
0
             &s, false);
164
0
    if (ret != EFI_SUCCESS) {
165
0
      log_err("Failed to set VarToFile\n");
166
0
      efi_set_variable_int(u"RTStorageVolatile",
167
0
               &efi_guid_efi_rt_var_file,
168
0
               EFI_VARIABLE_BOOTSERVICE_ACCESS |
169
0
               EFI_VARIABLE_RUNTIME_ACCESS |
170
0
               EFI_VARIABLE_READ_ONLY,
171
0
               0, NULL, false);
172
173
0
      return ret;
174
0
    }
175
0
    rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE;
176
0
  }
177
178
  /*
179
   * This value must be synced with efi_runtime_detach_list
180
   * as well as efi_runtime_services.
181
   */
182
0
#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET
183
0
  rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM;
184
0
#endif
185
186
0
  ret = efi_install_configuration_table(&efi_rt_properties_table_guid,
187
0
                rt_table);
188
0
  return ret;
189
0
}
190
191
/**
192
 * efi_memcpy_runtime() - copy memory area
193
 *
194
 * At runtime memcpy() is not available.
195
 *
196
 * Overlapping memory areas can be copied safely if src >= dest.
197
 *
198
 * @dest: destination buffer
199
 * @src:  source buffer
200
 * @n:    number of bytes to copy
201
 * Return:  pointer to destination buffer
202
 */
203
void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n)
204
0
{
205
0
  u8 *d = dest;
206
0
  const u8 *s = src;
207
208
0
  for (; n; --n)
209
0
    *d++ = *s++;
210
0
}
211
212
/**
213
 * efi_update_table_header_crc32() - Update crc32 in table header
214
 *
215
 * @table:  EFI table
216
 */
217
void __efi_runtime efi_update_table_header_crc32(struct efi_table_hdr *table)
218
0
{
219
0
  table->crc32 = 0;
220
0
  table->crc32 = crc32(0, (const unsigned char *)table,
221
0
           table->headersize);
222
0
}
223
224
/**
225
 * efi_reset_system_boottime() - reset system at boot time
226
 *
227
 * This function implements the ResetSystem() runtime service before
228
 * SetVirtualAddressMap() is called.
229
 *
230
 * See the Unified Extensible Firmware Interface (UEFI) specification for
231
 * details.
232
 *
233
 * @reset_type:   type of reset to perform
234
 * @reset_status: status code for the reset
235
 * @data_size:    size of reset_data
236
 * @reset_data:   information about the reset
237
 */
238
static void EFIAPI efi_reset_system_boottime(
239
      enum efi_reset_type reset_type,
240
      efi_status_t reset_status,
241
      unsigned long data_size, void *reset_data)
242
0
{
243
0
  struct efi_event *evt;
244
245
0
  EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
246
0
      reset_data);
247
248
  /* Notify reset */
249
0
  list_for_each_entry(evt, &efi_events, link) {
250
0
    if (evt->group &&
251
0
        !guidcmp(evt->group,
252
0
           &efi_guid_event_group_reset_system)) {
253
0
      efi_signal_event(evt);
254
0
      break;
255
0
    }
256
0
  }
257
0
  switch (reset_type) {
258
0
  case EFI_RESET_COLD:
259
0
  case EFI_RESET_WARM:
260
0
  case EFI_RESET_PLATFORM_SPECIFIC:
261
0
    do_reset(NULL, 0, 0, NULL);
262
0
    break;
263
0
  case EFI_RESET_SHUTDOWN:
264
0
#ifdef CONFIG_CMD_POWEROFF
265
0
    do_poweroff(NULL, 0, 0, NULL);
266
0
#endif
267
0
    break;
268
0
  }
269
270
0
  while (1) { }
271
0
}
272
273
/**
274
 * efi_get_time_boottime() - get current time at boot time
275
 *
276
 * This function implements the GetTime runtime service before
277
 * SetVirtualAddressMap() is called.
278
 *
279
 * See the Unified Extensible Firmware Interface (UEFI) specification
280
 * for details.
281
 *
282
 * @time:   pointer to structure to receive current time
283
 * @capabilities: pointer to structure to receive RTC properties
284
 * Returns:   status code
285
 */
286
static efi_status_t EFIAPI efi_get_time_boottime(
287
      struct efi_time *time,
288
      struct efi_time_cap *capabilities)
289
{
290
#ifdef CONFIG_EFI_GET_TIME
291
  efi_status_t ret = EFI_SUCCESS;
292
  struct rtc_time tm;
293
  struct udevice *dev;
294
295
  EFI_ENTRY("%p %p", time, capabilities);
296
297
  if (!time) {
298
    ret = EFI_INVALID_PARAMETER;
299
    goto out;
300
  }
301
  if (uclass_get_device(UCLASS_RTC, 0, &dev) ||
302
      dm_rtc_get(dev, &tm)) {
303
    ret = EFI_UNSUPPORTED;
304
    goto out;
305
  }
306
  if (dm_rtc_get(dev, &tm)) {
307
    ret = EFI_DEVICE_ERROR;
308
    goto out;
309
  }
310
311
  memset(time, 0, sizeof(*time));
312
  time->year = tm.tm_year;
313
  time->month = tm.tm_mon;
314
  time->day = tm.tm_mday;
315
  time->hour = tm.tm_hour;
316
  time->minute = tm.tm_min;
317
  time->second = tm.tm_sec;
318
  if (tm.tm_isdst > 0)
319
    time->daylight =
320
      EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT;
321
  else if (!tm.tm_isdst)
322
    time->daylight = EFI_TIME_ADJUST_DAYLIGHT;
323
  else
324
    time->daylight = 0;
325
  time->timezone = EFI_UNSPECIFIED_TIMEZONE;
326
327
  if (capabilities) {
328
    /* Set reasonable dummy values */
329
    capabilities->resolution = 1;   /* 1 Hz */
330
    capabilities->accuracy = 100000000; /* 100 ppm */
331
    capabilities->sets_to_zero = false;
332
  }
333
out:
334
  return EFI_EXIT(ret);
335
#else
336
  EFI_ENTRY("%p %p", time, capabilities);
337
  return EFI_EXIT(EFI_UNSUPPORTED);
338
#endif
339
}
340
341
#ifdef CONFIG_EFI_SET_TIME
342
343
/**
344
 * efi_validate_time() - checks if timestamp is valid
345
 *
346
 * @time: timestamp to validate
347
 * Returns: 0 if timestamp is valid, 1 otherwise
348
 */
349
static int efi_validate_time(struct efi_time *time)
350
0
{
351
0
  return (!time ||
352
0
    time->year < 1900 || time->year > 9999 ||
353
0
    !time->month || time->month > 12 || !time->day ||
354
0
    time->day > rtc_month_days(time->month - 1, time->year) ||
355
0
    time->hour > 23 || time->minute > 59 || time->second > 59 ||
356
0
    time->nanosecond > 999999999 ||
357
0
    time->daylight &
358
0
    ~(EFI_TIME_IN_DAYLIGHT | EFI_TIME_ADJUST_DAYLIGHT) ||
359
0
    ((time->timezone < -1440 || time->timezone > 1440) &&
360
0
    time->timezone != EFI_UNSPECIFIED_TIMEZONE));
361
0
}
362
363
#endif
364
365
/**
366
 * efi_set_time_boottime() - set current time
367
 *
368
 * This function implements the SetTime() runtime service before
369
 * SetVirtualAddressMap() is called.
370
 *
371
 * See the Unified Extensible Firmware Interface (UEFI) specification
372
 * for details.
373
 *
374
 * @time:   pointer to structure to with current time
375
 * Returns:   status code
376
 */
377
static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time)
378
{
379
#ifdef CONFIG_EFI_SET_TIME
380
  efi_status_t ret = EFI_SUCCESS;
381
  struct rtc_time tm;
382
  struct udevice *dev;
383
384
  EFI_ENTRY("%p", time);
385
386
  if (efi_validate_time(time)) {
387
    ret = EFI_INVALID_PARAMETER;
388
    goto out;
389
  }
390
391
  if (uclass_get_device(UCLASS_RTC, 0, &dev)) {
392
    ret = EFI_UNSUPPORTED;
393
    goto out;
394
  }
395
396
  memset(&tm, 0, sizeof(tm));
397
  tm.tm_year = time->year;
398
  tm.tm_mon = time->month;
399
  tm.tm_mday = time->day;
400
  tm.tm_hour = time->hour;
401
  tm.tm_min = time->minute;
402
  tm.tm_sec = time->second;
403
  switch (time->daylight) {
404
  case EFI_TIME_ADJUST_DAYLIGHT:
405
    tm.tm_isdst = 0;
406
    break;
407
  case EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT:
408
    tm.tm_isdst = 1;
409
    break;
410
  default:
411
    tm.tm_isdst = -1;
412
    break;
413
  }
414
  /* Calculate day of week */
415
  rtc_calc_weekday(&tm);
416
417
  if (dm_rtc_set(dev, &tm))
418
    ret = EFI_DEVICE_ERROR;
419
out:
420
  return EFI_EXIT(ret);
421
#else
422
  EFI_ENTRY("%p", time);
423
  return EFI_EXIT(EFI_UNSUPPORTED);
424
#endif
425
}
426
/**
427
 * efi_reset_system() - reset system
428
 *
429
 * This function implements the ResetSystem() runtime service after
430
 * SetVirtualAddressMap() is called. As this placeholder cannot reset the
431
 * system it simply return to the caller.
432
 *
433
 * Boards may override the helpers below to implement reset functionality.
434
 *
435
 * See the Unified Extensible Firmware Interface (UEFI) specification for
436
 * details.
437
 *
438
 * @reset_type:   type of reset to perform
439
 * @reset_status: status code for the reset
440
 * @data_size:    size of reset_data
441
 * @reset_data:   information about the reset
442
 */
443
void __weak __efi_runtime EFIAPI efi_reset_system(
444
      enum efi_reset_type reset_type,
445
      efi_status_t reset_status,
446
      unsigned long data_size, void *reset_data)
447
{
448
  return;
449
}
450
451
/**
452
 * efi_reset_system_init() - initialize the reset driver
453
 *
454
 * Boards may override this function to initialize the reset driver.
455
 */
456
efi_status_t __weak efi_reset_system_init(void)
457
0
{
458
0
  return EFI_SUCCESS;
459
0
}
460
461
/**
462
 * efi_get_time() - get current time
463
 *
464
 * This function implements the GetTime runtime service after
465
 * SetVirtualAddressMap() is called. As the U-Boot driver are not available
466
 * anymore only an error code is returned.
467
 *
468
 * See the Unified Extensible Firmware Interface (UEFI) specification
469
 * for details.
470
 *
471
 * @time:   pointer to structure to receive current time
472
 * @capabilities: pointer to structure to receive RTC properties
473
 * Returns:   status code
474
 */
475
efi_status_t __weak __efi_runtime EFIAPI efi_get_time(
476
      struct efi_time *time,
477
      struct efi_time_cap *capabilities)
478
0
{
479
0
  return EFI_UNSUPPORTED;
480
0
}
481
482
/**
483
 * efi_set_time() - set current time
484
 *
485
 * This function implements the SetTime runtime service after
486
 * SetVirtualAddressMap() is called. As the U-Boot driver are not available
487
 * anymore only an error code is returned.
488
 *
489
 * See the Unified Extensible Firmware Interface (UEFI) specification
490
 * for details.
491
 *
492
 * @time:   pointer to structure to with current time
493
 * Returns:   status code
494
 */
495
efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time)
496
0
{
497
0
  return EFI_UNSUPPORTED;
498
0
}
499
500
/**
501
 * efi_update_capsule_unsupported() - process information from operating system
502
 *
503
 * This function implements the UpdateCapsule() runtime service.
504
 *
505
 * See the Unified Extensible Firmware Interface (UEFI) specification for
506
 * details.
507
 *
508
 * @capsule_header_array: pointer to array of virtual pointers
509
 * @capsule_count:    number of pointers in capsule_header_array
510
 * @scatter_gather_list:  pointer to array of physical pointers
511
 * Returns:     status code
512
 */
513
static efi_status_t __efi_runtime EFIAPI efi_update_capsule_unsupported(
514
      struct efi_capsule_header **capsule_header_array,
515
      efi_uintn_t capsule_count,
516
      u64 scatter_gather_list)
517
0
{
518
0
  return EFI_UNSUPPORTED;
519
0
}
520
521
/**
522
 * efi_query_capsule_caps_unsupported() - check if capsule is supported
523
 *
524
 * This function implements the QueryCapsuleCapabilities() runtime service.
525
 *
526
 * See the Unified Extensible Firmware Interface (UEFI) specification for
527
 * details.
528
 *
529
 * @capsule_header_array: pointer to array of virtual pointers
530
 * @capsule_count:    number of pointers in capsule_header_array
531
 * @maximum_capsule_size: maximum capsule size
532
 * @reset_type:     type of reset needed for capsule update
533
 * Returns:     status code
534
 */
535
static efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps_unsupported(
536
      struct efi_capsule_header **capsule_header_array,
537
      efi_uintn_t capsule_count,
538
      u64 *maximum_capsule_size,
539
      u32 *reset_type)
540
0
{
541
0
  return EFI_UNSUPPORTED;
542
0
}
543
544
/**
545
 * efi_is_runtime_service_pointer() - check if pointer points to runtime table
546
 *
547
 * @p:    pointer to check
548
 * Return:  true if the pointer points to a service function pointer in the
549
 *    runtime table
550
 */
551
static bool efi_is_runtime_service_pointer(void *p)
552
0
{
553
0
  return (p >= (void *)&efi_runtime_services.get_time &&
554
0
    p <= (void *)&efi_runtime_services.query_variable_info) ||
555
0
         p == (void *)&efi_events.prev ||
556
0
         p == (void *)&efi_events.next;
557
0
}
558
559
/**
560
 * efi_runtime_detach() - detach unimplemented runtime functions
561
 */
562
void efi_runtime_detach(void)
563
0
{
564
0
  efi_runtime_services.reset_system = efi_reset_system;
565
0
  efi_runtime_services.get_time = efi_get_time;
566
0
  efi_runtime_services.set_time = efi_set_time;
567
0
  if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE)) {
568
    /* won't support at runtime */
569
0
    efi_runtime_services.update_capsule =
570
0
        efi_update_capsule_unsupported;
571
0
    efi_runtime_services.query_capsule_caps =
572
0
        efi_query_capsule_caps_unsupported;
573
0
  }
574
575
  /* Update CRC32 */
576
0
  efi_update_table_header_crc32(&efi_runtime_services.hdr);
577
0
}
578
579
/**
580
 * efi_set_virtual_address_map_runtime() - change from physical to virtual
581
 *             mapping
582
 *
583
 * This function implements the SetVirtualAddressMap() runtime service after
584
 * it is first called.
585
 *
586
 * See the Unified Extensible Firmware Interface (UEFI) specification for
587
 * details.
588
 *
589
 * @memory_map_size:  size of the virtual map
590
 * @descriptor_size:  size of an entry in the map
591
 * @descriptor_version: version of the map entries
592
 * @virtmap:    virtual address mapping information
593
 * Return:    status code EFI_UNSUPPORTED
594
 */
595
static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
596
      efi_uintn_t memory_map_size,
597
      efi_uintn_t descriptor_size,
598
      uint32_t descriptor_version,
599
      struct efi_mem_desc *virtmap)
600
0
{
601
0
  return EFI_UNSUPPORTED;
602
0
}
603
604
/**
605
 * efi_convert_pointer_runtime() - convert from physical to virtual pointer
606
 *
607
 * This function implements the ConvertPointer() runtime service after
608
 * the first call to SetVirtualAddressMap().
609
 *
610
 * See the Unified Extensible Firmware Interface (UEFI) specification for
611
 * details.
612
 *
613
 * @debug_disposition:  indicates if pointer may be converted to NULL
614
 * @address:    pointer to be converted
615
 * Return:    status code EFI_UNSUPPORTED
616
 */
617
static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime(
618
      efi_uintn_t debug_disposition, void **address)
619
0
{
620
0
  return EFI_UNSUPPORTED;
621
0
}
622
623
/**
624
 * efi_convert_pointer() - convert from physical to virtual pointer
625
 *
626
 * This function implements the ConvertPointer() runtime service until
627
 * the first call to SetVirtualAddressMap().
628
 *
629
 * See the Unified Extensible Firmware Interface (UEFI) specification for
630
 * details.
631
 *
632
 * @debug_disposition:  indicates if pointer may be converted to NULL
633
 * @address:    pointer to be converted
634
 * Return:    status code
635
 */
636
__efi_runtime efi_status_t EFIAPI
637
efi_convert_pointer(efi_uintn_t debug_disposition, void **address)
638
0
{
639
0
  efi_physical_addr_t addr;
640
0
  efi_uintn_t i;
641
0
  efi_status_t ret = EFI_NOT_FOUND;
642
643
0
  if (!efi_virtmap) {
644
0
    ret = EFI_UNSUPPORTED;
645
0
    goto out;
646
0
  }
647
648
0
  if (!address) {
649
0
    ret = EFI_INVALID_PARAMETER;
650
0
    goto out;
651
0
  }
652
0
  if (!*address) {
653
0
    if (debug_disposition & EFI_OPTIONAL_PTR)
654
0
      return EFI_SUCCESS;
655
0
    else
656
0
      return EFI_INVALID_PARAMETER;
657
0
  }
658
659
0
  addr = (uintptr_t)*address;
660
0
  for (i = 0; i < efi_descriptor_count; i++) {
661
0
    struct efi_mem_desc *map = (void *)efi_virtmap +
662
0
             (efi_descriptor_size * i);
663
664
0
    if (addr >= map->physical_start &&
665
0
        (addr < map->physical_start
666
0
          + (map->num_pages << EFI_PAGE_SHIFT))) {
667
0
      *address = (void *)(uintptr_t)
668
0
           (addr + map->virtual_start -
669
0
            map->physical_start);
670
671
0
      ret = EFI_SUCCESS;
672
0
      break;
673
0
    }
674
0
  }
675
676
0
out:
677
0
  return ret;
678
0
}
679
680
static __efi_runtime void efi_relocate_runtime_table(ulong offset)
681
0
{
682
0
  ulong patchoff;
683
0
  void **pos;
684
685
  /* Relocate the runtime services pointers */
686
0
  patchoff = offset - gd->relocaddr;
687
0
  for (pos = (void **)&efi_runtime_services.get_time;
688
0
       pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) {
689
0
    if (*pos)
690
0
      *pos += patchoff;
691
0
  }
692
693
  /*
694
   * The entry for SetVirtualAddress() must point to a physical address.
695
   * After the first execution the service must return EFI_UNSUPPORTED.
696
   */
697
0
  efi_runtime_services.set_virtual_address_map =
698
0
      &efi_set_virtual_address_map_runtime;
699
700
  /*
701
   * The entry for ConvertPointer() must point to a physical address.
702
   * The service is not usable after SetVirtualAddress().
703
   */
704
0
  efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime;
705
706
  /*
707
   * TODO: Update UEFI variable RuntimeServicesSupported removing flags
708
   * EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP and
709
   * EFI_RT_SUPPORTED_CONVERT_POINTER as required by the UEFI spec 2.8.
710
   */
711
712
  /* Update CRC32 */
713
0
  efi_update_table_header_crc32(&efi_runtime_services.hdr);
714
0
}
715
716
/* Relocate EFI runtime to uboot_reloc_base = offset */
717
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
718
0
{
719
0
#ifdef IS_RELA
720
0
  struct elf_rela *rel = (void *)__efi_runtime_rel_start;
721
#else
722
  struct elf_rel *rel = (void *)__efi_runtime_rel_start;
723
  static ulong lastoff = CONFIG_TEXT_BASE;
724
#endif
725
726
0
  debug("%s: Relocating to offset=%lx\n", __func__, offset);
727
0
  for (; (uintptr_t)rel < (uintptr_t)__efi_runtime_rel_stop; rel++) {
728
0
    ulong base = CONFIG_TEXT_BASE;
729
0
    ulong *p;
730
0
    ulong newaddr;
731
732
0
    p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
733
734
    /*
735
     * The runtime services table is updated in
736
     * efi_relocate_runtime_table()
737
     */
738
0
    if (map && efi_is_runtime_service_pointer(p))
739
0
      continue;
740
741
0
    debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__,
742
0
          rel->info, *p, rel->offset);
743
744
0
    switch (rel->info & R_MASK) {
745
0
    case R_RELATIVE:
746
0
#ifdef IS_RELA
747
0
    newaddr = rel->addend + offset - CONFIG_TEXT_BASE;
748
#else
749
    newaddr = *p - lastoff + offset;
750
#endif
751
0
      break;
752
#ifdef R_ABSOLUTE
753
    case R_ABSOLUTE: {
754
      ulong symidx = rel->info >> SYM_INDEX;
755
      extern struct dyn_sym __dyn_sym_start[];
756
      newaddr = __dyn_sym_start[symidx].addr + offset;
757
#ifdef IS_RELA
758
      newaddr -= CONFIG_TEXT_BASE;
759
#endif
760
      break;
761
    }
762
#endif
763
0
    default:
764
0
      printf("%s: Unknown relocation type %llx\n",
765
0
             __func__, rel->info & R_MASK);
766
0
      continue;
767
0
    }
768
769
    /* Check if the relocation is inside bounds */
770
0
    if (map && ((newaddr < map->virtual_start) ||
771
0
        newaddr > (map->virtual_start +
772
0
            (map->num_pages << EFI_PAGE_SHIFT)))) {
773
0
      printf("%s: Relocation at %p is out of range (%lx)\n",
774
0
             __func__, p, newaddr);
775
0
      continue;
776
0
    }
777
778
0
    debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
779
0
    *p = newaddr;
780
0
    flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1),
781
0
      ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE));
782
0
  }
783
784
#ifndef IS_RELA
785
  lastoff = offset;
786
#endif
787
788
  /*
789
   * If on x86 a write affects a prefetched instruction,
790
   * the prefetch queue is invalidated.
791
   */
792
0
  if (!CONFIG_IS_ENABLED(X86))
793
0
    invalidate_icache_all();
794
0
}
795
796
/**
797
 * efi_set_virtual_address_map() - change from physical to virtual mapping
798
 *
799
 * This function implements the SetVirtualAddressMap() runtime service.
800
 *
801
 * See the Unified Extensible Firmware Interface (UEFI) specification for
802
 * details.
803
 *
804
 * @memory_map_size:  size of the virtual map
805
 * @descriptor_size:  size of an entry in the map
806
 * @descriptor_version: version of the map entries
807
 * @virtmap:    virtual address mapping information
808
 * Return:    status code
809
 */
810
static efi_status_t EFIAPI efi_set_virtual_address_map(
811
      efi_uintn_t memory_map_size,
812
      efi_uintn_t descriptor_size,
813
      uint32_t descriptor_version,
814
      struct efi_mem_desc *virtmap)
815
{
816
  efi_uintn_t n = memory_map_size / descriptor_size;
817
  efi_uintn_t i;
818
  efi_status_t ret = EFI_INVALID_PARAMETER;
819
  int rt_code_sections = 0;
820
  struct efi_event *event;
821
822
  EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size,
823
      descriptor_version, virtmap);
824
825
  if (descriptor_version != EFI_MEMORY_DESCRIPTOR_VERSION ||
826
      descriptor_size < sizeof(struct efi_mem_desc))
827
    goto out;
828
829
  efi_virtmap = virtmap;
830
  efi_descriptor_size = descriptor_size;
831
  efi_descriptor_count = n;
832
833
  /*
834
   * TODO:
835
   * Further down we are cheating. While really we should implement
836
   * SetVirtualAddressMap() events and ConvertPointer() to allow
837
   * dynamically loaded drivers to expose runtime services, we don't
838
   * today.
839
   *
840
   * So let's ensure we see exactly one single runtime section, as
841
   * that is the built-in one. If we see more (or less), someone must
842
   * have tried adding or removing to that which we don't support yet.
843
   * In that case, let's better fail rather than expose broken runtime
844
   * services.
845
   */
846
  for (i = 0; i < n; i++) {
847
    struct efi_mem_desc *map = (void*)virtmap +
848
             (descriptor_size * i);
849
850
    if (map->type == EFI_RUNTIME_SERVICES_CODE)
851
      rt_code_sections++;
852
  }
853
854
  if (rt_code_sections != 1) {
855
    /*
856
     * We expose exactly one single runtime code section, so
857
     * something is definitely going wrong.
858
     */
859
    goto out;
860
  }
861
862
  /* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
863
  list_for_each_entry(event, &efi_events, link) {
864
    if (event->notify_function)
865
      EFI_CALL_VOID(event->notify_function(
866
          event, event->notify_context));
867
  }
868
869
  /* Rebind mmio pointers */
870
  for (i = 0; i < n; i++) {
871
    struct efi_mem_desc *map = (void*)virtmap +
872
             (descriptor_size * i);
873
    struct list_head *lhandle;
874
    efi_physical_addr_t map_start = map->physical_start;
875
    efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
876
    efi_physical_addr_t map_end = map_start + map_len;
877
    u64 off = map->virtual_start - map_start;
878
879
    /* Adjust all mmio pointers in this region */
880
    list_for_each(lhandle, &efi_runtime_mmio) {
881
      struct efi_runtime_mmio_list *lmmio;
882
883
      lmmio = list_entry(lhandle,
884
             struct efi_runtime_mmio_list,
885
             link);
886
      if ((map_start <= lmmio->paddr) &&
887
          (map_end >= lmmio->paddr)) {
888
        uintptr_t new_addr = lmmio->paddr + off;
889
        *lmmio->ptr = (void *)new_addr;
890
      }
891
    }
892
    if ((map_start <= (uintptr_t)systab.tables) &&
893
        (map_end >= (uintptr_t)systab.tables)) {
894
      char *ptr = (char *)systab.tables;
895
896
      ptr += off;
897
      systab.tables = (struct efi_configuration_table *)ptr;
898
    }
899
  }
900
901
  /* Relocate the runtime. See TODO above */
902
  for (i = 0; i < n; i++) {
903
    struct efi_mem_desc *map;
904
905
    map = (void*)virtmap + (descriptor_size * i);
906
    if (map->type == EFI_RUNTIME_SERVICES_CODE) {
907
      ulong new_offset = map->virtual_start -
908
             map->physical_start + gd->relocaddr;
909
910
      efi_relocate_runtime_table(new_offset);
911
      efi_runtime_relocate(new_offset, map);
912
      ret = EFI_SUCCESS;
913
      goto out;
914
    }
915
  }
916
917
out:
918
  return EFI_EXIT(ret);
919
}
920
921
/**
922
 * efi_add_runtime_mmio() - add memory-mapped IO region
923
 *
924
 * This function adds a memory-mapped IO region to the memory map to make it
925
 * available at runtime.
926
 *
927
 * @mmio_ptr:   pointer to a pointer to the start of the memory-mapped
928
 *      IO region
929
 * @len:    size of the memory-mapped IO region
930
 * Returns:   status code
931
 */
932
efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
933
0
{
934
0
  struct efi_runtime_mmio_list *newmmio;
935
0
  uint64_t addr = *(uintptr_t *)mmio_ptr;
936
0
  efi_status_t ret;
937
938
0
  ret = efi_add_memory_map(addr, len, EFI_MMAP_IO);
939
0
  if (ret != EFI_SUCCESS)
940
0
    return EFI_OUT_OF_RESOURCES;
941
942
0
  newmmio = calloc(1, sizeof(*newmmio));
943
0
  if (!newmmio)
944
0
    return EFI_OUT_OF_RESOURCES;
945
0
  newmmio->ptr = mmio_ptr;
946
0
  newmmio->paddr = *(uintptr_t *)mmio_ptr;
947
0
  newmmio->len = len;
948
0
  list_add_tail(&newmmio->link, &efi_runtime_mmio);
949
950
0
  return EFI_SUCCESS;
951
0
}
952
953
/*
954
 * In the second stage, U-Boot has disappeared. To isolate our runtime code
955
 * that at this point still exists from the rest, we put it into a special
956
 * section.
957
 *
958
 *        !!WARNING!!
959
 *
960
 * This means that we can not rely on any code outside of this file in any
961
 * function or variable below this line.
962
 *
963
 * Please keep everything fully self-contained and annotated with
964
 * __efi_runtime and __efi_runtime_data markers.
965
 */
966
967
/*
968
 * Relocate the EFI runtime stub to a different place. We need to call this
969
 * the first time we expose the runtime interface to a user and on set virtual
970
 * address map calls.
971
 */
972
973
/**
974
 * efi_unimplemented() - replacement function, returns EFI_UNSUPPORTED
975
 *
976
 * This function is used after SetVirtualAddressMap() is called as replacement
977
 * for services that are not available anymore due to constraints of the U-Boot
978
 * implementation.
979
 *
980
 * Return:  EFI_UNSUPPORTED
981
 */
982
static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
983
0
{
984
0
  return EFI_UNSUPPORTED;
985
0
}
986
987
struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
988
  .hdr = {
989
    .signature = EFI_RUNTIME_SERVICES_SIGNATURE,
990
    .revision = EFI_SPECIFICATION_VERSION,
991
    .headersize = sizeof(struct efi_runtime_services),
992
  },
993
  .get_time = &efi_get_time_boottime,
994
  .set_time = &efi_set_time_boottime,
995
  .get_wakeup_time = (void *)&efi_unimplemented,
996
  .set_wakeup_time = (void *)&efi_unimplemented,
997
  .set_virtual_address_map = &efi_set_virtual_address_map,
998
  .convert_pointer = efi_convert_pointer,
999
  .get_variable = efi_get_variable,
1000
  .get_next_variable_name = efi_get_next_variable_name,
1001
  .set_variable = efi_set_variable,
1002
  .get_next_high_mono_count = (void *)&efi_unimplemented,
1003
  .reset_system = &efi_reset_system_boottime,
1004
#ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE
1005
  .update_capsule = efi_update_capsule,
1006
  .query_capsule_caps = efi_query_capsule_caps,
1007
#else
1008
  .update_capsule = efi_update_capsule_unsupported,
1009
  .query_capsule_caps = efi_query_capsule_caps_unsupported,
1010
#endif
1011
  .query_variable_info = efi_query_variable_info,
1012
};