Skip to content

Commit 1e947ba

Browse files
author
Marc Zyngier
committed
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>
1 parent d88701b commit 1e947ba

File tree

2 files changed

+121
-59
lines changed

2 files changed

+121
-59
lines changed

arch/arm/kvm/arm.c

Lines changed: 114 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
967967
}
968968
}
969969

970+
static void cpu_init_stage2(void *dummy)
971+
{
972+
__cpu_init_stage2();
973+
}
974+
970975
static void cpu_init_hyp_mode(void *dummy)
971976
{
972977
phys_addr_t boot_pgd_ptr;
@@ -1036,6 +1041,82 @@ static inline void hyp_cpu_pm_init(void)
10361041
}
10371042
#endif
10381043

1044+
static void teardown_common_resources(void)
1045+
{
1046+
free_percpu(kvm_host_cpu_state);
1047+
}
1048+
1049+
static 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+
1060+
static 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+
1093+
static 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+
1105+
static 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+
10391120
/**
10401121
* Inits Hyp-mode on all online CPUs
10411122
*/
@@ -1066,7 +1147,7 @@ static int init_hyp_mode(void)
10661147
stack_page = __get_free_page(GFP_KERNEL);
10671148
if (!stack_page) {
10681149
err = -ENOMEM;
1069-
goto out_free_stack_pages;
1150+
goto out_err;
10701151
}
10711152

10721153
per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
@@ -1078,13 +1159,13 @@ static int init_hyp_mode(void)
10781159
err = create_hyp_mappings(__hyp_text_start, __hyp_text_end);
10791160
if (err) {
10801161
kvm_err("Cannot map world-switch code\n");
1081-
goto out_free_mappings;
1162+
goto out_err;
10821163
}
10831164

10841165
err = create_hyp_mappings(__start_rodata, __end_rodata);
10851166
if (err) {
10861167
kvm_err("Cannot map rodata section\n");
1087-
goto out_free_mappings;
1168+
goto out_err;
10881169
}
10891170

10901171
/*
@@ -1096,20 +1177,10 @@ static int init_hyp_mode(void)
10961177

10971178
if (err) {
10981179
kvm_err("Cannot map hyp stack\n");
1099-
goto out_free_mappings;
1180+
goto out_err;
11001181
}
11011182
}
11021183

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-
11131184
for_each_possible_cpu(cpu) {
11141185
kvm_cpu_context_t *cpu_ctxt;
11151186

@@ -1118,7 +1189,7 @@ static int init_hyp_mode(void)
11181189

11191190
if (err) {
11201191
kvm_err("Cannot map host CPU state: %d\n", err);
1121-
goto out_free_context;
1192+
goto out_err;
11221193
}
11231194
}
11241195

@@ -1127,34 +1198,22 @@ static int init_hyp_mode(void)
11271198
*/
11281199
on_each_cpu(cpu_init_hyp_mode, NULL, 1);
11291200

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-
11531201
#ifndef CONFIG_HOTPLUG_CPU
11541202
free_boot_hyp_pgd();
11551203
#endif
11561204

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();
11581217

11591218
/* set size of VMID supported by CPU */
11601219
kvm_vmid_bits = kvm_get_vmid_bits();
@@ -1163,14 +1222,9 @@ static int init_hyp_mode(void)
11631222
kvm_info("Hyp mode initialized successfully\n");
11641223

11651224
return 0;
1166-
out_free_context:
1167-
free_percpu(kvm_host_cpu_state);
1168-
out_free_mappings:
1169-
free_hyp_pgds();
1170-
out_free_stack_pages:
1171-
for_each_possible_cpu(cpu)
1172-
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
1225+
11731226
out_err:
1227+
teardown_hyp_mode();
11741228
kvm_err("error initializing Hyp mode: %d\n", err);
11751229
return err;
11761230
}
@@ -1214,26 +1268,27 @@ int kvm_arch_init(void *opaque)
12141268
}
12151269
}
12161270

1217-
cpu_notifier_register_begin();
1218-
1219-
err = init_hyp_mode();
1271+
err = init_common_resources();
12201272
if (err)
1221-
goto out_err;
1273+
return err;
12221274

1223-
err = __register_cpu_notifier(&hyp_init_cpu_nb);
1224-
if (err) {
1225-
kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
1275+
if (is_kernel_in_hyp_mode())
1276+
err = init_vhe_mode();
1277+
else
1278+
err = init_hyp_mode();
1279+
if (err)
12261280
goto out_err;
1227-
}
1228-
1229-
cpu_notifier_register_done();
12301281

1231-
hyp_cpu_pm_init();
1282+
err = init_subsystems();
1283+
if (err)
1284+
goto out_hyp;
12321285

1233-
kvm_coproc_table_init();
12341286
return 0;
1287+
1288+
out_hyp:
1289+
teardown_hyp_mode();
12351290
out_err:
1236-
cpu_notifier_register_done();
1291+
teardown_common_resources();
12371292
return err;
12381293
}
12391294

arch/arm/kvm/mmu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <asm/kvm_mmio.h>
2929
#include <asm/kvm_asm.h>
3030
#include <asm/kvm_emulate.h>
31+
#include <asm/virt.h>
3132

3233
#include "trace.h"
3334

@@ -598,6 +599,9 @@ int create_hyp_mappings(void *from, void *to)
598599
unsigned long start = KERN_TO_HYP((unsigned long)from);
599600
unsigned long end = KERN_TO_HYP((unsigned long)to);
600601

602+
if (is_kernel_in_hyp_mode())
603+
return 0;
604+
601605
start = start & PAGE_MASK;
602606
end = PAGE_ALIGN(end);
603607

@@ -630,6 +634,9 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
630634
unsigned long start = KERN_TO_HYP((unsigned long)from);
631635
unsigned long end = KERN_TO_HYP((unsigned long)to);
632636

637+
if (is_kernel_in_hyp_mode())
638+
return 0;
639+
633640
/* Check for a valid kernel IO mapping */
634641
if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1))
635642
return -EINVAL;

0 commit comments

Comments
 (0)