diff options
author | Matt Fleming <matt.fleming@intel.com> | 2014-01-10 13:48:30 -0500 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2014-03-04 16:43:14 -0500 |
commit | 4f9dbcfc40299ddaa780fe8c1cd74998c1be3af5 (patch) | |
tree | f6d2f85b23fae5ee8d9da79f30c47351aa890d5b /arch/x86/platform/efi/efi.c | |
parent | b8ff87a6158886771677e6dc8139bac6e3cba717 (diff) |
x86/efi: Add mixed runtime services support
Setup the runtime services based on whether we're booting in EFI native
mode or not. For non-native mode we need to thunk from 64-bit into
32-bit mode before invoking the EFI runtime services.
Using the runtime services after SetVirtualAddressMap() is slightly more
complicated because we need to ensure that all the addresses we pass to
the firmware are below the 4GB boundary so that they can be addressed
with 32-bit pointers, see efi_setup_page_tables().
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch/x86/platform/efi/efi.c')
-rw-r--r-- | arch/x86/platform/efi/efi.c | 127 |
1 files changed, 97 insertions, 30 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index b96ae7918a16..39f5b7bba695 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -588,37 +588,85 @@ static int __init efi_systab_init(void *phys) | |||
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
590 | 590 | ||
591 | static int __init efi_runtime_init(void) | 591 | static int __init efi_runtime_init32(void) |
592 | { | 592 | { |
593 | efi_runtime_services_t *runtime; | 593 | efi_runtime_services_32_t *runtime; |
594 | |||
595 | runtime = early_ioremap((unsigned long)efi.systab->runtime, | ||
596 | sizeof(efi_runtime_services_32_t)); | ||
597 | if (!runtime) { | ||
598 | pr_err("Could not map the runtime service table!\n"); | ||
599 | return -ENOMEM; | ||
600 | } | ||
594 | 601 | ||
595 | /* | 602 | /* |
596 | * Check out the runtime services table. We need to map | 603 | * We will only need *early* access to the following two |
597 | * the runtime services table so that we can grab the physical | 604 | * EFI runtime services before set_virtual_address_map |
598 | * address of several of the EFI runtime functions, needed to | 605 | * is invoked. |
599 | * set the firmware into virtual mode. | ||
600 | */ | 606 | */ |
607 | efi_phys.get_time = (efi_get_time_t *) | ||
608 | (unsigned long)runtime->get_time; | ||
609 | efi_phys.set_virtual_address_map = | ||
610 | (efi_set_virtual_address_map_t *) | ||
611 | (unsigned long)runtime->set_virtual_address_map; | ||
612 | /* | ||
613 | * Make efi_get_time can be called before entering | ||
614 | * virtual mode. | ||
615 | */ | ||
616 | efi.get_time = phys_efi_get_time; | ||
617 | early_iounmap(runtime, sizeof(efi_runtime_services_32_t)); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int __init efi_runtime_init64(void) | ||
623 | { | ||
624 | efi_runtime_services_64_t *runtime; | ||
625 | |||
601 | runtime = early_ioremap((unsigned long)efi.systab->runtime, | 626 | runtime = early_ioremap((unsigned long)efi.systab->runtime, |
602 | sizeof(efi_runtime_services_t)); | 627 | sizeof(efi_runtime_services_64_t)); |
603 | if (!runtime) { | 628 | if (!runtime) { |
604 | pr_err("Could not map the runtime service table!\n"); | 629 | pr_err("Could not map the runtime service table!\n"); |
605 | return -ENOMEM; | 630 | return -ENOMEM; |
606 | } | 631 | } |
632 | |||
607 | /* | 633 | /* |
608 | * We will only need *early* access to the following | 634 | * We will only need *early* access to the following two |
609 | * two EFI runtime services before set_virtual_address_map | 635 | * EFI runtime services before set_virtual_address_map |
610 | * is invoked. | 636 | * is invoked. |
611 | */ | 637 | */ |
612 | efi_phys.get_time = (efi_get_time_t *)runtime->get_time; | 638 | efi_phys.get_time = (efi_get_time_t *) |
639 | (unsigned long)runtime->get_time; | ||
613 | efi_phys.set_virtual_address_map = | 640 | efi_phys.set_virtual_address_map = |
614 | (efi_set_virtual_address_map_t *) | 641 | (efi_set_virtual_address_map_t *) |
615 | runtime->set_virtual_address_map; | 642 | (unsigned long)runtime->set_virtual_address_map; |
616 | /* | 643 | /* |
617 | * Make efi_get_time can be called before entering | 644 | * Make efi_get_time can be called before entering |
618 | * virtual mode. | 645 | * virtual mode. |
619 | */ | 646 | */ |
620 | efi.get_time = phys_efi_get_time; | 647 | efi.get_time = phys_efi_get_time; |
621 | early_iounmap(runtime, sizeof(efi_runtime_services_t)); | 648 | early_iounmap(runtime, sizeof(efi_runtime_services_64_t)); |
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int __init efi_runtime_init(void) | ||
654 | { | ||
655 | int rv; | ||
656 | |||
657 | /* | ||
658 | * Check out the runtime services table. We need to map | ||
659 | * the runtime services table so that we can grab the physical | ||
660 | * address of several of the EFI runtime functions, needed to | ||
661 | * set the firmware into virtual mode. | ||
662 | */ | ||
663 | if (efi_enabled(EFI_64BIT)) | ||
664 | rv = efi_runtime_init64(); | ||
665 | else | ||
666 | rv = efi_runtime_init32(); | ||
667 | |||
668 | if (rv) | ||
669 | return rv; | ||
622 | 670 | ||
623 | return 0; | 671 | return 0; |
624 | } | 672 | } |
@@ -841,6 +889,22 @@ void __init old_map_region(efi_memory_desc_t *md) | |||
841 | (unsigned long long)md->phys_addr); | 889 | (unsigned long long)md->phys_addr); |
842 | } | 890 | } |
843 | 891 | ||
892 | static void native_runtime_setup(void) | ||
893 | { | ||
894 | efi.get_time = virt_efi_get_time; | ||
895 | efi.set_time = virt_efi_set_time; | ||
896 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | ||
897 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | ||
898 | efi.get_variable = virt_efi_get_variable; | ||
899 | efi.get_next_variable = virt_efi_get_next_variable; | ||
900 | efi.set_variable = virt_efi_set_variable; | ||
901 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | ||
902 | efi.reset_system = virt_efi_reset_system; | ||
903 | efi.query_variable_info = virt_efi_query_variable_info; | ||
904 | efi.update_capsule = virt_efi_update_capsule; | ||
905 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | ||
906 | } | ||
907 | |||
844 | /* Merge contiguous regions of the same type and attribute */ | 908 | /* Merge contiguous regions of the same type and attribute */ |
845 | static void __init efi_merge_regions(void) | 909 | static void __init efi_merge_regions(void) |
846 | { | 910 | { |
@@ -1023,11 +1087,20 @@ void __init efi_enter_virtual_mode(void) | |||
1023 | efi_sync_low_kernel_mappings(); | 1087 | efi_sync_low_kernel_mappings(); |
1024 | 1088 | ||
1025 | if (!efi_setup) { | 1089 | if (!efi_setup) { |
1026 | status = phys_efi_set_virtual_address_map( | 1090 | if (efi_is_native()) { |
1027 | memmap.desc_size * count, | 1091 | status = phys_efi_set_virtual_address_map( |
1028 | memmap.desc_size, | 1092 | memmap.desc_size * count, |
1029 | memmap.desc_version, | 1093 | memmap.desc_size, |
1030 | (efi_memory_desc_t *)__pa(new_memmap)); | 1094 | memmap.desc_version, |
1095 | (efi_memory_desc_t *)__pa(new_memmap)); | ||
1096 | } else { | ||
1097 | status = efi_thunk_set_virtual_address_map( | ||
1098 | efi_phys.set_virtual_address_map, | ||
1099 | memmap.desc_size * count, | ||
1100 | memmap.desc_size, | ||
1101 | memmap.desc_version, | ||
1102 | (efi_memory_desc_t *)__pa(new_memmap)); | ||
1103 | } | ||
1031 | 1104 | ||
1032 | if (status != EFI_SUCCESS) { | 1105 | if (status != EFI_SUCCESS) { |
1033 | pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", | 1106 | pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", |
@@ -1043,19 +1116,13 @@ void __init efi_enter_virtual_mode(void) | |||
1043 | * Call EFI services through wrapper functions. | 1116 | * Call EFI services through wrapper functions. |
1044 | */ | 1117 | */ |
1045 | efi.runtime_version = efi_systab.hdr.revision; | 1118 | efi.runtime_version = efi_systab.hdr.revision; |
1046 | efi.get_time = virt_efi_get_time; | 1119 | |
1047 | efi.set_time = virt_efi_set_time; | 1120 | if (efi_is_native()) |
1048 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | 1121 | native_runtime_setup(); |
1049 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | 1122 | else |
1050 | efi.get_variable = virt_efi_get_variable; | 1123 | efi_thunk_runtime_setup(); |
1051 | efi.get_next_variable = virt_efi_get_next_variable; | 1124 | |
1052 | efi.set_variable = virt_efi_set_variable; | ||
1053 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | ||
1054 | efi.reset_system = virt_efi_reset_system; | ||
1055 | efi.set_virtual_address_map = NULL; | 1125 | efi.set_virtual_address_map = NULL; |
1056 | efi.query_variable_info = virt_efi_query_variable_info; | ||
1057 | efi.update_capsule = virt_efi_update_capsule; | ||
1058 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | ||
1059 | 1126 | ||
1060 | efi_runtime_mkexec(); | 1127 | efi_runtime_mkexec(); |
1061 | 1128 | ||