1
2
3
4
5
6
7
8#include <common.h>
9#include <command.h>
10#include <cpu_func.h>
11#include <dm.h>
12#include <elf.h>
13#include <efi_loader.h>
14#include <log.h>
15#include <malloc.h>
16#include <rtc.h>
17#include <u-boot/crc.h>
18
19
20DECLARE_GLOBAL_DATA_PTR;
21
22
23static const efi_guid_t efi_rt_properties_table_guid =
24 EFI_RT_PROPERTIES_TABLE_GUID;
25
26struct efi_runtime_mmio_list {
27 struct list_head link;
28 void **ptr;
29 u64 paddr;
30 u64 len;
31};
32
33
34LIST_HEAD(efi_runtime_mmio);
35
36static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void);
37
38
39
40
41
42
43#if defined(__aarch64__)
44#define R_RELATIVE R_AARCH64_RELATIVE
45#define R_MASK 0xffffffffULL
46#define IS_RELA 1
47#elif defined(__arm__)
48#define R_RELATIVE R_ARM_RELATIVE
49#define R_MASK 0xffULL
50#elif defined(__i386__)
51#define R_RELATIVE R_386_RELATIVE
52#define R_MASK 0xffULL
53#elif defined(__x86_64__)
54#define R_RELATIVE R_X86_64_RELATIVE
55#define R_MASK 0xffffffffULL
56#define IS_RELA 1
57#elif defined(__riscv)
58#define R_RELATIVE R_RISCV_RELATIVE
59#define R_MASK 0xffULL
60#define IS_RELA 1
61
62struct dyn_sym {
63 ulong foo1;
64 ulong addr;
65 u32 foo2;
66 u32 foo3;
67};
68#if (__riscv_xlen == 32)
69#define R_ABSOLUTE R_RISCV_32
70#define SYM_INDEX 8
71#elif (__riscv_xlen == 64)
72#define R_ABSOLUTE R_RISCV_64
73#define SYM_INDEX 32
74#else
75#error unknown riscv target
76#endif
77#else
78#error Need to add relocation awareness
79#endif
80
81struct elf_rel {
82 ulong *offset;
83 ulong info;
84};
85
86struct elf_rela {
87 ulong *offset;
88 ulong info;
89 long addend;
90};
91
92static __efi_runtime_data struct efi_mem_desc *efi_virtmap;
93static __efi_runtime_data efi_uintn_t efi_descriptor_count;
94static __efi_runtime_data efi_uintn_t efi_descriptor_size;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110efi_status_t efi_init_runtime_supported(void)
111{
112 efi_status_t ret;
113 struct efi_rt_properties_table *rt_table;
114
115 ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA,
116 sizeof(struct efi_rt_properties_table),
117 (void **)&rt_table);
118 if (ret != EFI_SUCCESS)
119 return ret;
120
121 rt_table->version = EFI_RT_PROPERTIES_TABLE_VERSION;
122 rt_table->length = sizeof(struct efi_rt_properties_table);
123 rt_table->runtime_services_supported =
124 EFI_RT_SUPPORTED_GET_VARIABLE |
125 EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME |
126 EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP |
127 EFI_RT_SUPPORTED_CONVERT_POINTER;
128
129
130
131
132
133#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET
134 rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM;
135#endif
136
137 ret = efi_install_configuration_table(&efi_rt_properties_table_guid,
138 rt_table);
139 return ret;
140}
141
142
143
144
145
146
147
148
149
150
151
152
153
154void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n)
155{
156 u8 *d = dest;
157 const u8 *s = src;
158
159 for (; n; --n)
160 *d++ = *s++;
161}
162
163
164
165
166
167
168void __efi_runtime efi_update_table_header_crc32(struct efi_table_hdr *table)
169{
170 table->crc32 = 0;
171 table->crc32 = crc32(0, (const unsigned char *)table,
172 table->headersize);
173}
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189static void EFIAPI efi_reset_system_boottime(
190 enum efi_reset_type reset_type,
191 efi_status_t reset_status,
192 unsigned long data_size, void *reset_data)
193{
194 struct efi_event *evt;
195
196 EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
197 reset_data);
198
199
200 list_for_each_entry(evt, &efi_events, link) {
201 if (evt->group &&
202 !guidcmp(evt->group,
203 &efi_guid_event_group_reset_system)) {
204 efi_signal_event(evt);
205 break;
206 }
207 }
208 switch (reset_type) {
209 case EFI_RESET_COLD:
210 case EFI_RESET_WARM:
211 case EFI_RESET_PLATFORM_SPECIFIC:
212 do_reset(NULL, 0, 0, NULL);
213 break;
214 case EFI_RESET_SHUTDOWN:
215#ifdef CONFIG_CMD_POWEROFF
216 do_poweroff(NULL, 0, 0, NULL);
217#endif
218 break;
219 }
220
221 while (1) { }
222}
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237static efi_status_t EFIAPI efi_get_time_boottime(
238 struct efi_time *time,
239 struct efi_time_cap *capabilities)
240{
241#ifdef CONFIG_EFI_GET_TIME
242 efi_status_t ret = EFI_SUCCESS;
243 struct rtc_time tm;
244 struct udevice *dev;
245
246 EFI_ENTRY("%p %p", time, capabilities);
247
248 if (!time) {
249 ret = EFI_INVALID_PARAMETER;
250 goto out;
251 }
252 if (uclass_get_device(UCLASS_RTC, 0, &dev) ||
253 dm_rtc_get(dev, &tm)) {
254 ret = EFI_UNSUPPORTED;
255 goto out;
256 }
257 if (dm_rtc_get(dev, &tm)) {
258 ret = EFI_DEVICE_ERROR;
259 goto out;
260 }
261
262 memset(time, 0, sizeof(*time));
263 time->year = tm.tm_year;
264 time->month = tm.tm_mon;
265 time->day = tm.tm_mday;
266 time->hour = tm.tm_hour;
267 time->minute = tm.tm_min;
268 time->second = tm.tm_sec;
269 if (tm.tm_isdst)
270 time->daylight =
271 EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT;
272 time->timezone = EFI_UNSPECIFIED_TIMEZONE;
273
274 if (capabilities) {
275
276 capabilities->resolution = 1;
277 capabilities->accuracy = 100000000;
278 capabilities->sets_to_zero = false;
279 }
280out:
281 return EFI_EXIT(ret);
282#else
283 EFI_ENTRY("%p %p", time, capabilities);
284 return EFI_EXIT(EFI_UNSUPPORTED);
285#endif
286}
287
288#ifdef CONFIG_EFI_SET_TIME
289
290
291
292
293
294
295
296static int efi_validate_time(struct efi_time *time)
297{
298 return (!time ||
299 time->year < 1900 || time->year > 9999 ||
300 !time->month || time->month > 12 || !time->day ||
301 time->day > rtc_month_days(time->month - 1, time->year) ||
302 time->hour > 23 || time->minute > 59 || time->second > 59 ||
303 time->nanosecond > 999999999 ||
304 time->daylight &
305 ~(EFI_TIME_IN_DAYLIGHT | EFI_TIME_ADJUST_DAYLIGHT) ||
306 ((time->timezone < -1440 || time->timezone > 1440) &&
307 time->timezone != EFI_UNSPECIFIED_TIMEZONE));
308}
309
310#endif
311
312
313
314
315
316
317
318
319
320
321
322
323
324static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time)
325{
326#ifdef CONFIG_EFI_SET_TIME
327 efi_status_t ret = EFI_SUCCESS;
328 struct rtc_time tm;
329 struct udevice *dev;
330
331 EFI_ENTRY("%p", time);
332
333 if (efi_validate_time(time)) {
334 ret = EFI_INVALID_PARAMETER;
335 goto out;
336 }
337
338 if (uclass_get_device(UCLASS_RTC, 0, &dev)) {
339 ret = EFI_UNSUPPORTED;
340 goto out;
341 }
342
343 memset(&tm, 0, sizeof(tm));
344 tm.tm_year = time->year;
345 tm.tm_mon = time->month;
346 tm.tm_mday = time->day;
347 tm.tm_hour = time->hour;
348 tm.tm_min = time->minute;
349 tm.tm_sec = time->second;
350 tm.tm_isdst = time->daylight ==
351 (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT);
352
353 rtc_calc_weekday(&tm);
354
355 if (dm_rtc_set(dev, &tm))
356 ret = EFI_DEVICE_ERROR;
357out:
358 return EFI_EXIT(ret);
359#else
360 EFI_ENTRY("%p", time);
361 return EFI_EXIT(EFI_UNSUPPORTED);
362#endif
363}
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381void __weak __efi_runtime EFIAPI efi_reset_system(
382 enum efi_reset_type reset_type,
383 efi_status_t reset_status,
384 unsigned long data_size, void *reset_data)
385{
386 return;
387}
388
389
390
391
392
393
394efi_status_t __weak efi_reset_system_init(void)
395{
396 return EFI_SUCCESS;
397}
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413efi_status_t __weak __efi_runtime EFIAPI efi_get_time(
414 struct efi_time *time,
415 struct efi_time_cap *capabilities)
416{
417 return EFI_UNSUPPORTED;
418}
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time)
434{
435 return EFI_UNSUPPORTED;
436}
437
438
439
440
441
442
443
444
445static bool efi_is_runtime_service_pointer(void *p)
446{
447 return (p >= (void *)&efi_runtime_services.get_time &&
448 p <= (void *)&efi_runtime_services.query_variable_info) ||
449 p == (void *)&efi_events.prev ||
450 p == (void *)&efi_events.next;
451}
452
453
454
455
456void efi_runtime_detach(void)
457{
458 efi_runtime_services.reset_system = efi_reset_system;
459 efi_runtime_services.get_time = efi_get_time;
460 efi_runtime_services.set_time = efi_set_time;
461
462
463 efi_update_table_header_crc32(&efi_runtime_services.hdr);
464}
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
483 efi_uintn_t memory_map_size,
484 efi_uintn_t descriptor_size,
485 uint32_t descriptor_version,
486 struct efi_mem_desc *virtmap)
487{
488 return EFI_UNSUPPORTED;
489}
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime(
505 efi_uintn_t debug_disposition, void **address)
506{
507 return EFI_UNSUPPORTED;
508}
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523__efi_runtime efi_status_t EFIAPI
524efi_convert_pointer(efi_uintn_t debug_disposition, void **address)
525{
526 efi_physical_addr_t addr;
527 efi_uintn_t i;
528 efi_status_t ret = EFI_NOT_FOUND;
529
530 if (!efi_virtmap) {
531 ret = EFI_UNSUPPORTED;
532 goto out;
533 }
534
535 if (!address) {
536 ret = EFI_INVALID_PARAMETER;
537 goto out;
538 }
539 if (!*address) {
540 if (debug_disposition & EFI_OPTIONAL_PTR)
541 return EFI_SUCCESS;
542 else
543 return EFI_INVALID_PARAMETER;
544 }
545
546 addr = (uintptr_t)*address;
547 for (i = 0; i < efi_descriptor_count; i++) {
548 struct efi_mem_desc *map = (void *)efi_virtmap +
549 (efi_descriptor_size * i);
550
551 if (addr >= map->physical_start &&
552 (addr < map->physical_start
553 + (map->num_pages << EFI_PAGE_SHIFT))) {
554 *address = (void *)(uintptr_t)
555 (addr + map->virtual_start -
556 map->physical_start);
557
558 ret = EFI_SUCCESS;
559 break;
560 }
561 }
562
563out:
564 return ret;
565}
566
567static __efi_runtime void efi_relocate_runtime_table(ulong offset)
568{
569 ulong patchoff;
570 void **pos;
571
572
573 patchoff = offset - gd->relocaddr;
574 for (pos = (void **)&efi_runtime_services.get_time;
575 pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) {
576 if (*pos)
577 *pos += patchoff;
578 }
579
580
581
582
583
584 efi_runtime_services.set_virtual_address_map =
585 &efi_set_virtual_address_map_runtime;
586
587
588
589
590
591 efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime;
592
593
594
595
596
597
598
599
600 efi_update_table_header_crc32(&efi_runtime_services.hdr);
601}
602
603
604void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map)
605{
606#ifdef IS_RELA
607 struct elf_rela *rel = (void*)&__efi_runtime_rel_start;
608#else
609 struct elf_rel *rel = (void*)&__efi_runtime_rel_start;
610 static ulong lastoff = CONFIG_SYS_TEXT_BASE;
611#endif
612
613 debug("%s: Relocating to offset=%lx\n", __func__, offset);
614 for (; (ulong)rel < (ulong)&__efi_runtime_rel_stop; rel++) {
615 ulong base = CONFIG_SYS_TEXT_BASE;
616 ulong *p;
617 ulong newaddr;
618
619 p = (void*)((ulong)rel->offset - base) + gd->relocaddr;
620
621
622
623
624
625 if (map && efi_is_runtime_service_pointer(p))
626 continue;
627
628 debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__,
629 rel->info, *p, rel->offset);
630
631 switch (rel->info & R_MASK) {
632 case R_RELATIVE:
633#ifdef IS_RELA
634 newaddr = rel->addend + offset - CONFIG_SYS_TEXT_BASE;
635#else
636 newaddr = *p - lastoff + offset;
637#endif
638 break;
639#ifdef R_ABSOLUTE
640 case R_ABSOLUTE: {
641 ulong symidx = rel->info >> SYM_INDEX;
642 extern struct dyn_sym __dyn_sym_start[];
643 newaddr = __dyn_sym_start[symidx].addr + offset;
644#ifdef IS_RELA
645 newaddr -= CONFIG_SYS_TEXT_BASE;
646#endif
647 break;
648 }
649#endif
650 default:
651 printf("%s: Unknown relocation type %llx\n",
652 __func__, rel->info & R_MASK);
653 continue;
654 }
655
656
657 if (map && ((newaddr < map->virtual_start) ||
658 newaddr > (map->virtual_start +
659 (map->num_pages << EFI_PAGE_SHIFT)))) {
660 printf("%s: Relocation at %p is out of range (%lx)\n",
661 __func__, p, newaddr);
662 continue;
663 }
664
665 debug("%s: Setting %p to %lx\n", __func__, p, newaddr);
666 *p = newaddr;
667 flush_dcache_range((ulong)p & ~(EFI_CACHELINE_SIZE - 1),
668 ALIGN((ulong)&p[1], EFI_CACHELINE_SIZE));
669 }
670
671#ifndef IS_RELA
672 lastoff = offset;
673#endif
674
675 invalidate_icache_all();
676}
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692static efi_status_t EFIAPI efi_set_virtual_address_map(
693 efi_uintn_t memory_map_size,
694 efi_uintn_t descriptor_size,
695 uint32_t descriptor_version,
696 struct efi_mem_desc *virtmap)
697{
698 efi_uintn_t n = memory_map_size / descriptor_size;
699 efi_uintn_t i;
700 efi_status_t ret = EFI_INVALID_PARAMETER;
701 int rt_code_sections = 0;
702 struct efi_event *event;
703
704 EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size,
705 descriptor_version, virtmap);
706
707 if (descriptor_version != EFI_MEMORY_DESCRIPTOR_VERSION ||
708 descriptor_size < sizeof(struct efi_mem_desc))
709 goto out;
710
711 efi_virtmap = virtmap;
712 efi_descriptor_size = descriptor_size;
713 efi_descriptor_count = n;
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728 for (i = 0; i < n; i++) {
729 struct efi_mem_desc *map = (void*)virtmap +
730 (descriptor_size * i);
731
732 if (map->type == EFI_RUNTIME_SERVICES_CODE)
733 rt_code_sections++;
734 }
735
736 if (rt_code_sections != 1) {
737
738
739
740
741 goto out;
742 }
743
744
745 list_for_each_entry(event, &efi_events, link) {
746 if (event->notify_function)
747 EFI_CALL_VOID(event->notify_function(
748 event, event->notify_context));
749 }
750
751
752 for (i = 0; i < n; i++) {
753 struct efi_mem_desc *map = (void*)virtmap +
754 (descriptor_size * i);
755 struct list_head *lhandle;
756 efi_physical_addr_t map_start = map->physical_start;
757 efi_physical_addr_t map_len = map->num_pages << EFI_PAGE_SHIFT;
758 efi_physical_addr_t map_end = map_start + map_len;
759 u64 off = map->virtual_start - map_start;
760
761
762 list_for_each(lhandle, &efi_runtime_mmio) {
763 struct efi_runtime_mmio_list *lmmio;
764
765 lmmio = list_entry(lhandle,
766 struct efi_runtime_mmio_list,
767 link);
768 if ((map_start <= lmmio->paddr) &&
769 (map_end >= lmmio->paddr)) {
770 uintptr_t new_addr = lmmio->paddr + off;
771 *lmmio->ptr = (void *)new_addr;
772 }
773 }
774 if ((map_start <= (uintptr_t)systab.tables) &&
775 (map_end >= (uintptr_t)systab.tables)) {
776 char *ptr = (char *)systab.tables;
777
778 ptr += off;
779 systab.tables = (struct efi_configuration_table *)ptr;
780 }
781 }
782
783
784 for (i = 0; i < n; i++) {
785 struct efi_mem_desc *map;
786
787 map = (void*)virtmap + (descriptor_size * i);
788 if (map->type == EFI_RUNTIME_SERVICES_CODE) {
789 ulong new_offset = map->virtual_start -
790 map->physical_start + gd->relocaddr;
791
792 efi_relocate_runtime_table(new_offset);
793 efi_runtime_relocate(new_offset, map);
794 ret = EFI_SUCCESS;
795 goto out;
796 }
797 }
798
799out:
800 return EFI_EXIT(ret);
801}
802
803
804
805
806
807
808
809
810
811
812
813
814efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
815{
816 struct efi_runtime_mmio_list *newmmio;
817 uint64_t addr = *(uintptr_t *)mmio_ptr;
818 efi_status_t ret;
819
820 ret = efi_add_memory_map(addr, len, EFI_MMAP_IO);
821 if (ret != EFI_SUCCESS)
822 return EFI_OUT_OF_RESOURCES;
823
824 newmmio = calloc(1, sizeof(*newmmio));
825 if (!newmmio)
826 return EFI_OUT_OF_RESOURCES;
827 newmmio->ptr = mmio_ptr;
828 newmmio->paddr = *(uintptr_t *)mmio_ptr;
829 newmmio->len = len;
830 list_add_tail(&newmmio->link, &efi_runtime_mmio);
831
832 return EFI_SUCCESS;
833}
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
865{
866 return EFI_UNSUPPORTED;
867}
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882efi_status_t __efi_runtime EFIAPI efi_update_capsule(
883 struct efi_capsule_header **capsule_header_array,
884 efi_uintn_t capsule_count,
885 u64 scatter_gather_list)
886{
887 return EFI_UNSUPPORTED;
888}
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
905 struct efi_capsule_header **capsule_header_array,
906 efi_uintn_t capsule_count,
907 u64 *maximum_capsule_size,
908 u32 *reset_type)
909{
910 return EFI_UNSUPPORTED;
911}
912
913struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
914 .hdr = {
915 .signature = EFI_RUNTIME_SERVICES_SIGNATURE,
916 .revision = EFI_SPECIFICATION_VERSION,
917 .headersize = sizeof(struct efi_runtime_services),
918 },
919 .get_time = &efi_get_time_boottime,
920 .set_time = &efi_set_time_boottime,
921 .get_wakeup_time = (void *)&efi_unimplemented,
922 .set_wakeup_time = (void *)&efi_unimplemented,
923 .set_virtual_address_map = &efi_set_virtual_address_map,
924 .convert_pointer = efi_convert_pointer,
925 .get_variable = efi_get_variable,
926 .get_next_variable_name = efi_get_next_variable_name,
927 .set_variable = efi_set_variable,
928 .get_next_high_mono_count = (void *)&efi_unimplemented,
929 .reset_system = &efi_reset_system_boottime,
930 .update_capsule = efi_update_capsule,
931 .query_capsule_caps = efi_query_capsule_caps,
932 .query_variable_info = efi_query_variable_info,
933};
934