aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-01-29 06:59:54 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2016-02-29 13:34:16 -0500
commit1e947bad0b63b351cbdd9ad55ea5bf7e31c76036 (patch)
tree71e42f0401c96c3a77b91eeb8f4a0b2feace6417 /arch/arm/kvm
parentd88701bea3664cea99b8b7380f63a3bd0ec3ead3 (diff)
arm64: KVM: Skip HYP setup when already running in HYP
With the kernel running at EL2, there is no point trying to configure page tables for HYP, as the kernel is already mapped. Take this opportunity to refactor the whole init a bit, allowing the various parts of the hypervisor bringup to be split across multiple functions. Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm/kvm')
-rw-r--r--arch/arm/kvm/arm.c173
-rw-r--r--arch/arm/kvm/mmu.c7
2 files changed, 121 insertions, 59 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index fcf6c130c986..686350d05174 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -967,6 +967,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
967 } 967 }
968} 968}
969 969
970static void cpu_init_stage2(void *dummy)
971{
972 __cpu_init_stage2();
973}
974
970static void cpu_init_hyp_mode(void *dummy) 975static void cpu_init_hyp_mode(void *dummy)
971{ 976{
972 phys_addr_t boot_pgd_ptr; 977 phys_addr_t boot_pgd_ptr;
@@ -1036,6 +1041,82 @@ static inline void hyp_cpu_pm_init(void)
1036} 1041}
1037#endif 1042#endif
1038 1043
1044static void teardown_common_resources(void)
1045{
1046 free_percpu(kvm_host_cpu_state);
1047}
1048
1049static int init_common_resources(void)
1050{
1051 kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
1052 if (!kvm_host_cpu_state) {
1053 kvm_err("Cannot allocate host CPU state\n");
1054 return -ENOMEM;
1055 }
1056
1057 return 0;
1058}
1059
1060static int init_subsystems(void)
1061{
1062 int err;
1063
1064 /*
1065 * Init HYP view of VGIC
1066 */
1067 err = kvm_vgic_hyp_init();
1068 switch (err) {
1069 case 0:
1070 vgic_present = true;
1071 break;
1072 case -ENODEV:
1073 case -ENXIO:
1074 vgic_present = false;
1075 break;
1076 default:
1077 return err;
1078 }
1079
1080 /*
1081 * Init HYP architected timer support
1082 */
1083 err = kvm_timer_hyp_init();
1084 if (err)
1085 return err;
1086
1087 kvm_perf_init();
1088 kvm_coproc_table_init();
1089
1090 return 0;
1091}
1092
1093static void teardown_hyp_mode(void)
1094{
1095 int cpu;
1096
1097 if (is_kernel_in_hyp_mode())
1098 return;
1099
1100 free_hyp_pgds();
1101 for_each_possible_cpu(cpu)
1102 free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
1103}
1104
1105static int init_vhe_mode(void)
1106{
1107 /*
1108 * Execute the init code on each CPU.
1109 */
1110 on_each_cpu(cpu_init_stage2, NULL, 1);
1111
1112 /* set size of VMID supported by CPU */
1113 kvm_vmid_bits = kvm_get_vmid_bits();
1114 kvm_info("%d-bit VMID\n", kvm_vmid_bits);
1115
1116 kvm_info("VHE mode initialized successfully\n");
1117 return 0;
1118}
1119
1039/** 1120/**
1040 * Inits Hyp-mode on all online CPUs 1121 * Inits Hyp-mode on all online CPUs
1041 */ 1122 */
@@ -1066,7 +1147,7 @@ static int init_hyp_mode(void)
1066 stack_page = __get_free_page(GFP_KERNEL); 1147 stack_page = __get_free_page(GFP_KERNEL);
1067 if (!stack_page) { 1148 if (!stack_page) {
1068 err = -ENOMEM; 1149 err = -ENOMEM;
1069 goto out_free_stack_pages; 1150 goto out_err;
1070 } 1151 }
1071 1152
1072 per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page; 1153 per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
@@ -1078,13 +1159,13 @@ static int init_hyp_mode(void)
1078 err = create_hyp_mappings(__hyp_text_start, __hyp_text_end); 1159 err = create_hyp_mappings(__hyp_text_start, __hyp_text_end);
1079 if (err) { 1160 if (err) {
1080 kvm_err("Cannot map world-switch code\n"); 1161 kvm_err("Cannot map world-switch code\n");
1081 goto out_free_mappings; 1162 goto out_err;
1082 } 1163 }
1083 1164
1084 err = create_hyp_mappings(__start_rodata, __end_rodata); 1165 err = create_hyp_mappings(__start_rodata, __end_rodata);
1085 if (err) { 1166 if (err) {
1086 kvm_err("Cannot map rodata section\n"); 1167 kvm_err("Cannot map rodata section\n");
1087 goto out_free_mappings; 1168 goto out_err;
1088 } 1169 }
1089 1170
1090 /* 1171 /*
@@ -1096,20 +1177,10 @@ static int init_hyp_mode(void)
1096 1177
1097 if (err) { 1178 if (err) {
1098 kvm_err("Cannot map hyp stack\n"); 1179 kvm_err("Cannot map hyp stack\n");
1099 goto out_free_mappings; 1180 goto out_err;
1100 } 1181 }
1101 } 1182 }
1102 1183
1103 /*
1104 * Map the host CPU structures
1105 */
1106 kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
1107 if (!kvm_host_cpu_state) {
1108 err = -ENOMEM;
1109 kvm_err("Cannot allocate host CPU state\n");
1110 goto out_free_mappings;
1111 }
1112
1113 for_each_possible_cpu(cpu) { 1184 for_each_possible_cpu(cpu) {
1114 kvm_cpu_context_t *cpu_ctxt; 1185 kvm_cpu_context_t *cpu_ctxt;
1115 1186
@@ -1118,7 +1189,7 @@ static int init_hyp_mode(void)
1118 1189
1119 if (err) { 1190 if (err) {
1120 kvm_err("Cannot map host CPU state: %d\n", err); 1191 kvm_err("Cannot map host CPU state: %d\n", err);
1121 goto out_free_context; 1192 goto out_err;
1122 } 1193 }
1123 } 1194 }
1124 1195
@@ -1127,34 +1198,22 @@ static int init_hyp_mode(void)
1127 */ 1198 */
1128 on_each_cpu(cpu_init_hyp_mode, NULL, 1); 1199 on_each_cpu(cpu_init_hyp_mode, NULL, 1);
1129 1200
1130 /*
1131 * Init HYP view of VGIC
1132 */
1133 err = kvm_vgic_hyp_init();
1134 switch (err) {
1135 case 0:
1136 vgic_present = true;
1137 break;
1138 case -ENODEV:
1139 case -ENXIO:
1140 vgic_present = false;
1141 break;
1142 default:
1143 goto out_free_context;
1144 }
1145
1146 /*
1147 * Init HYP architected timer support
1148 */
1149 err = kvm_timer_hyp_init();
1150 if (err)
1151 goto out_free_context;
1152
1153#ifndef CONFIG_HOTPLUG_CPU 1201#ifndef CONFIG_HOTPLUG_CPU
1154 free_boot_hyp_pgd(); 1202 free_boot_hyp_pgd();
1155#endif 1203#endif
1156 1204
1157 kvm_perf_init(); 1205 cpu_notifier_register_begin();
1206
1207 err = __register_cpu_notifier(&hyp_init_cpu_nb);
1208
1209 cpu_notifier_register_done();
1210
1211 if (err) {
1212 kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
1213 goto out_err;
1214 }
1215
1216 hyp_cpu_pm_init();
1158 1217
1159 /* set size of VMID supported by CPU */ 1218 /* set size of VMID supported by CPU */
1160 kvm_vmid_bits = kvm_get_vmid_bits(); 1219 kvm_vmid_bits = kvm_get_vmid_bits();
@@ -1163,14 +1222,9 @@ static int init_hyp_mode(void)
1163 kvm_info("Hyp mode initialized successfully\n"); 1222 kvm_info("Hyp mode initialized successfully\n");
1164 1223
1165 return 0; 1224 return 0;
1166out_free_context: 1225
1167 free_percpu(kvm_host_cpu_state);
1168out_free_mappings:
1169 free_hyp_pgds();
1170out_free_stack_pages:
1171 for_each_possible_cpu(cpu)
1172 free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
1173out_err: 1226out_err:
1227 teardown_hyp_mode();
1174 kvm_err("error initializing Hyp mode: %d\n", err); 1228 kvm_err("error initializing Hyp mode: %d\n", err);
1175 return err; 1229 return err;
1176} 1230}
@@ -1214,26 +1268,27 @@ int kvm_arch_init(void *opaque)
1214 } 1268 }
1215 } 1269 }
1216 1270
1217 cpu_notifier_register_begin(); 1271 err = init_common_resources();
1218
1219 err = init_hyp_mode();
1220 if (err) 1272 if (err)
1221 goto out_err; 1273 return err;
1222 1274
1223 err = __register_cpu_notifier(&hyp_init_cpu_nb); 1275 if (is_kernel_in_hyp_mode())
1224 if (err) { 1276 err = init_vhe_mode();
1225 kvm_err("Cannot register HYP init CPU notifier (%d)\n", err); 1277 else
1278 err = init_hyp_mode();
1279 if (err)
1226 goto out_err; 1280 goto out_err;
1227 }
1228
1229 cpu_notifier_register_done();
1230 1281
1231 hyp_cpu_pm_init(); 1282 err = init_subsystems();
1283 if (err)
1284 goto out_hyp;
1232 1285
1233 kvm_coproc_table_init();
1234 return 0; 1286 return 0;
1287
1288out_hyp:
1289 teardown_hyp_mode();
1235out_err: 1290out_err:
1236 cpu_notifier_register_done(); 1291 teardown_common_resources();
1237 return err; 1292 return err;
1238} 1293}
1239 1294
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index c3eb10ea0971..58dbd5c439df 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -28,6 +28,7 @@
28#include <asm/kvm_mmio.h> 28#include <asm/kvm_mmio.h>
29#include <asm/kvm_asm.h> 29#include <asm/kvm_asm.h>
30#include <asm/kvm_emulate.h> 30#include <asm/kvm_emulate.h>
31#include <asm/virt.h>
31 32
32#include "trace.h" 33#include "trace.h"
33 34
@@ -598,6 +599,9 @@ int create_hyp_mappings(void *from, void *to)
598 unsigned long start = KERN_TO_HYP((unsigned long)from); 599 unsigned long start = KERN_TO_HYP((unsigned long)from);
599 unsigned long end = KERN_TO_HYP((unsigned long)to); 600 unsigned long end = KERN_TO_HYP((unsigned long)to);
600 601
602 if (is_kernel_in_hyp_mode())
603 return 0;
604
601 start = start & PAGE_MASK; 605 start = start & PAGE_MASK;
602 end = PAGE_ALIGN(end); 606 end = PAGE_ALIGN(end);
603 607
@@ -630,6 +634,9 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
630 unsigned long start = KERN_TO_HYP((unsigned long)from); 634 unsigned long start = KERN_TO_HYP((unsigned long)from);
631 unsigned long end = KERN_TO_HYP((unsigned long)to); 635 unsigned long end = KERN_TO_HYP((unsigned long)to);
632 636
637 if (is_kernel_in_hyp_mode())
638 return 0;
639
633 /* Check for a valid kernel IO mapping */ 640 /* Check for a valid kernel IO mapping */
634 if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1)) 641 if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1))
635 return -EINVAL; 642 return -EINVAL;