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