diff options
Diffstat (limited to 'arch/x86/platform/efi/efi.c')
-rw-r--r-- | arch/x86/platform/efi/efi.c | 158 |
1 files changed, 102 insertions, 56 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 45d4f7674678..43e7cf6c6111 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -453,9 +453,6 @@ void __init efi_free_boot_services(void) | |||
453 | { | 453 | { |
454 | void *p; | 454 | void *p; |
455 | 455 | ||
456 | if (!efi_is_native()) | ||
457 | return; | ||
458 | |||
459 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | 456 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { |
460 | efi_memory_desc_t *md = p; | 457 | efi_memory_desc_t *md = p; |
461 | unsigned long long start = md->phys_addr; | 458 | unsigned long long start = md->phys_addr; |
@@ -579,37 +576,85 @@ static int __init efi_systab_init(void *phys) | |||
579 | return 0; | 576 | return 0; |
580 | } | 577 | } |
581 | 578 | ||
582 | static int __init efi_runtime_init(void) | 579 | static int __init efi_runtime_init32(void) |
583 | { | 580 | { |
584 | efi_runtime_services_t *runtime; | 581 | efi_runtime_services_32_t *runtime; |
582 | |||
583 | runtime = early_ioremap((unsigned long)efi.systab->runtime, | ||
584 | sizeof(efi_runtime_services_32_t)); | ||
585 | if (!runtime) { | ||
586 | pr_err("Could not map the runtime service table!\n"); | ||
587 | return -ENOMEM; | ||
588 | } | ||
585 | 589 | ||
586 | /* | 590 | /* |
587 | * Check out the runtime services table. We need to map | 591 | * We will only need *early* access to the following two |
588 | * the runtime services table so that we can grab the physical | 592 | * EFI runtime services before set_virtual_address_map |
589 | * address of several of the EFI runtime functions, needed to | 593 | * is invoked. |
590 | * set the firmware into virtual mode. | 594 | */ |
595 | efi_phys.get_time = (efi_get_time_t *) | ||
596 | (unsigned long)runtime->get_time; | ||
597 | efi_phys.set_virtual_address_map = | ||
598 | (efi_set_virtual_address_map_t *) | ||
599 | (unsigned long)runtime->set_virtual_address_map; | ||
600 | /* | ||
601 | * Make efi_get_time can be called before entering | ||
602 | * virtual mode. | ||
591 | */ | 603 | */ |
604 | efi.get_time = phys_efi_get_time; | ||
605 | early_iounmap(runtime, sizeof(efi_runtime_services_32_t)); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static int __init efi_runtime_init64(void) | ||
611 | { | ||
612 | efi_runtime_services_64_t *runtime; | ||
613 | |||
592 | runtime = early_ioremap((unsigned long)efi.systab->runtime, | 614 | runtime = early_ioremap((unsigned long)efi.systab->runtime, |
593 | sizeof(efi_runtime_services_t)); | 615 | sizeof(efi_runtime_services_64_t)); |
594 | if (!runtime) { | 616 | if (!runtime) { |
595 | pr_err("Could not map the runtime service table!\n"); | 617 | pr_err("Could not map the runtime service table!\n"); |
596 | return -ENOMEM; | 618 | return -ENOMEM; |
597 | } | 619 | } |
620 | |||
598 | /* | 621 | /* |
599 | * We will only need *early* access to the following | 622 | * We will only need *early* access to the following two |
600 | * two EFI runtime services before set_virtual_address_map | 623 | * EFI runtime services before set_virtual_address_map |
601 | * is invoked. | 624 | * is invoked. |
602 | */ | 625 | */ |
603 | efi_phys.get_time = (efi_get_time_t *)runtime->get_time; | 626 | efi_phys.get_time = (efi_get_time_t *) |
627 | (unsigned long)runtime->get_time; | ||
604 | efi_phys.set_virtual_address_map = | 628 | efi_phys.set_virtual_address_map = |
605 | (efi_set_virtual_address_map_t *) | 629 | (efi_set_virtual_address_map_t *) |
606 | runtime->set_virtual_address_map; | 630 | (unsigned long)runtime->set_virtual_address_map; |
607 | /* | 631 | /* |
608 | * Make efi_get_time can be called before entering | 632 | * Make efi_get_time can be called before entering |
609 | * virtual mode. | 633 | * virtual mode. |
610 | */ | 634 | */ |
611 | efi.get_time = phys_efi_get_time; | 635 | efi.get_time = phys_efi_get_time; |
612 | early_iounmap(runtime, sizeof(efi_runtime_services_t)); | 636 | early_iounmap(runtime, sizeof(efi_runtime_services_64_t)); |
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int __init efi_runtime_init(void) | ||
642 | { | ||
643 | int rv; | ||
644 | |||
645 | /* | ||
646 | * Check out the runtime services table. We need to map | ||
647 | * the runtime services table so that we can grab the physical | ||
648 | * address of several of the EFI runtime functions, needed to | ||
649 | * set the firmware into virtual mode. | ||
650 | */ | ||
651 | if (efi_enabled(EFI_64BIT)) | ||
652 | rv = efi_runtime_init64(); | ||
653 | else | ||
654 | rv = efi_runtime_init32(); | ||
655 | |||
656 | if (rv) | ||
657 | return rv; | ||
613 | 658 | ||
614 | set_bit(EFI_RUNTIME_SERVICES, &efi.flags); | 659 | set_bit(EFI_RUNTIME_SERVICES, &efi.flags); |
615 | 660 | ||
@@ -747,7 +792,7 @@ void __init efi_init(void) | |||
747 | * that doesn't match the kernel 32/64-bit mode. | 792 | * that doesn't match the kernel 32/64-bit mode. |
748 | */ | 793 | */ |
749 | 794 | ||
750 | if (!efi_is_native()) | 795 | if (!efi_runtime_supported()) |
751 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); | 796 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); |
752 | else { | 797 | else { |
753 | if (disable_runtime || efi_runtime_init()) | 798 | if (disable_runtime || efi_runtime_init()) |
@@ -833,6 +878,22 @@ void __init old_map_region(efi_memory_desc_t *md) | |||
833 | (unsigned long long)md->phys_addr); | 878 | (unsigned long long)md->phys_addr); |
834 | } | 879 | } |
835 | 880 | ||
881 | static void native_runtime_setup(void) | ||
882 | { | ||
883 | efi.get_time = virt_efi_get_time; | ||
884 | efi.set_time = virt_efi_set_time; | ||
885 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | ||
886 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | ||
887 | efi.get_variable = virt_efi_get_variable; | ||
888 | efi.get_next_variable = virt_efi_get_next_variable; | ||
889 | efi.set_variable = virt_efi_set_variable; | ||
890 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | ||
891 | efi.reset_system = virt_efi_reset_system; | ||
892 | efi.query_variable_info = virt_efi_query_variable_info; | ||
893 | efi.update_capsule = virt_efi_update_capsule; | ||
894 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | ||
895 | } | ||
896 | |||
836 | /* Merge contiguous regions of the same type and attribute */ | 897 | /* Merge contiguous regions of the same type and attribute */ |
837 | static void __init efi_merge_regions(void) | 898 | static void __init efi_merge_regions(void) |
838 | { | 899 | { |
@@ -1015,19 +1076,10 @@ static void __init kexec_enter_virtual_mode(void) | |||
1015 | * Call EFI services through wrapper functions. | 1076 | * Call EFI services through wrapper functions. |
1016 | */ | 1077 | */ |
1017 | efi.runtime_version = efi_systab.hdr.revision; | 1078 | efi.runtime_version = efi_systab.hdr.revision; |
1018 | efi.get_time = virt_efi_get_time; | 1079 | |
1019 | efi.set_time = virt_efi_set_time; | 1080 | native_runtime_setup(); |
1020 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | 1081 | |
1021 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | ||
1022 | efi.get_variable = virt_efi_get_variable; | ||
1023 | efi.get_next_variable = virt_efi_get_next_variable; | ||
1024 | efi.set_variable = virt_efi_set_variable; | ||
1025 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | ||
1026 | efi.reset_system = virt_efi_reset_system; | ||
1027 | efi.set_virtual_address_map = NULL; | 1082 | efi.set_virtual_address_map = NULL; |
1028 | efi.query_variable_info = virt_efi_query_variable_info; | ||
1029 | efi.update_capsule = virt_efi_update_capsule; | ||
1030 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | ||
1031 | 1083 | ||
1032 | if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) | 1084 | if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) |
1033 | runtime_code_page_mkexec(); | 1085 | runtime_code_page_mkexec(); |
@@ -1071,15 +1123,6 @@ static void __init __efi_enter_virtual_mode(void) | |||
1071 | 1123 | ||
1072 | efi.systab = NULL; | 1124 | efi.systab = NULL; |
1073 | 1125 | ||
1074 | /* | ||
1075 | * We don't do virtual mode, since we don't do runtime services, on | ||
1076 | * non-native EFI | ||
1077 | */ | ||
1078 | if (!efi_is_native()) { | ||
1079 | efi_unmap_memmap(); | ||
1080 | return; | ||
1081 | } | ||
1082 | |||
1083 | efi_merge_regions(); | 1126 | efi_merge_regions(); |
1084 | new_memmap = efi_map_regions(&count, &pg_shift); | 1127 | new_memmap = efi_map_regions(&count, &pg_shift); |
1085 | if (!new_memmap) { | 1128 | if (!new_memmap) { |
@@ -1097,11 +1140,20 @@ static void __init __efi_enter_virtual_mode(void) | |||
1097 | efi_sync_low_kernel_mappings(); | 1140 | efi_sync_low_kernel_mappings(); |
1098 | efi_dump_pagetable(); | 1141 | efi_dump_pagetable(); |
1099 | 1142 | ||
1100 | status = phys_efi_set_virtual_address_map( | 1143 | if (efi_is_native()) { |
1101 | memmap.desc_size * count, | 1144 | status = phys_efi_set_virtual_address_map( |
1102 | memmap.desc_size, | 1145 | memmap.desc_size * count, |
1103 | memmap.desc_version, | 1146 | memmap.desc_size, |
1104 | (efi_memory_desc_t *)__pa(new_memmap)); | 1147 | memmap.desc_version, |
1148 | (efi_memory_desc_t *)__pa(new_memmap)); | ||
1149 | } else { | ||
1150 | status = efi_thunk_set_virtual_address_map( | ||
1151 | efi_phys.set_virtual_address_map, | ||
1152 | memmap.desc_size * count, | ||
1153 | memmap.desc_size, | ||
1154 | memmap.desc_version, | ||
1155 | (efi_memory_desc_t *)__pa(new_memmap)); | ||
1156 | } | ||
1105 | 1157 | ||
1106 | if (status != EFI_SUCCESS) { | 1158 | if (status != EFI_SUCCESS) { |
1107 | pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", | 1159 | pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", |
@@ -1116,19 +1168,13 @@ static void __init __efi_enter_virtual_mode(void) | |||
1116 | * Call EFI services through wrapper functions. | 1168 | * Call EFI services through wrapper functions. |
1117 | */ | 1169 | */ |
1118 | efi.runtime_version = efi_systab.hdr.revision; | 1170 | efi.runtime_version = efi_systab.hdr.revision; |
1119 | efi.get_time = virt_efi_get_time; | 1171 | |
1120 | efi.set_time = virt_efi_set_time; | 1172 | if (efi_is_native()) |
1121 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | 1173 | native_runtime_setup(); |
1122 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | 1174 | else |
1123 | efi.get_variable = virt_efi_get_variable; | 1175 | efi_thunk_runtime_setup(); |
1124 | efi.get_next_variable = virt_efi_get_next_variable; | 1176 | |
1125 | efi.set_variable = virt_efi_set_variable; | ||
1126 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | ||
1127 | efi.reset_system = virt_efi_reset_system; | ||
1128 | efi.set_virtual_address_map = NULL; | 1177 | efi.set_virtual_address_map = NULL; |
1129 | efi.query_variable_info = virt_efi_query_variable_info; | ||
1130 | efi.update_capsule = virt_efi_update_capsule; | ||
1131 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | ||
1132 | 1178 | ||
1133 | efi_runtime_mkexec(); | 1179 | efi_runtime_mkexec(); |
1134 | 1180 | ||
@@ -1311,7 +1357,7 @@ void __init efi_apply_memmap_quirks(void) | |||
1311 | * firmware/kernel architectures since there is no support for runtime | 1357 | * firmware/kernel architectures since there is no support for runtime |
1312 | * services. | 1358 | * services. |
1313 | */ | 1359 | */ |
1314 | if (!efi_is_native()) { | 1360 | if (!efi_runtime_supported()) { |
1315 | pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); | 1361 | pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); |
1316 | efi_unmap_memmap(); | 1362 | efi_unmap_memmap(); |
1317 | } | 1363 | } |