Skip to content

Commit 3fe3980

Browse files
Marc ZyngierAlex Shi
authored andcommitted
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> (cherry picked from commit 1e947bad0b63b351cbdd9ad55ea5bf7e31c76036) Signed-off-by: Alex Shi <alex.shi@linaro.org>
1 parent 6f7056c commit 3fe3980

2 files changed

Lines changed: 121 additions & 59 deletions

File tree

arch/arm/kvm/arm.c

Lines changed: 114 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
964964
}
965965
}
966966

967+
static void cpu_init_stage2(void *dummy)
968+
{
969+
__cpu_init_stage2();
970+
}
971+
967972
static void cpu_init_hyp_mode(void *dummy)
968973
{
969974
phys_addr_t boot_pgd_ptr;
@@ -1033,6 +1038,82 @@ static inline void hyp_cpu_pm_init(void)
10331038
}
10341039
#endif
10351040

1041+
static void teardown_common_resources(void)
1042+
{
1043+
free_percpu(kvm_host_cpu_state);
1044+
}
1045+
1046+
static int init_common_resources(void)
1047+
{
1048+
kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
1049+
if (!kvm_host_cpu_state) {
1050+
kvm_err("Cannot allocate host CPU state\n");
1051+
return -ENOMEM;
1052+
}
1053+
1054+
return 0;
1055+
}
1056+
1057+
static int init_subsystems(void)
1058+
{
1059+
int err;
1060+
1061+
/*
1062+
* Init HYP view of VGIC
1063+
*/
1064+
err = kvm_vgic_hyp_init();
1065+
switch (err) {
1066+
case 0:
1067+
vgic_present = true;
1068+
break;
1069+
case -ENODEV:
1070+
case -ENXIO:
1071+
vgic_present = false;
1072+
break;
1073+
default:
1074+
return err;
1075+
}
1076+
1077+
/*
1078+
* Init HYP architected timer support
1079+
*/
1080+
err = kvm_timer_hyp_init();
1081+
if (err)
1082+
return err;
1083+
1084+
kvm_perf_init();
1085+
kvm_coproc_table_init();
1086+
1087+
return 0;
1088+
}
1089+
1090+
static void teardown_hyp_mode(void)
1091+
{
1092+
int cpu;
1093+
1094+
if (is_kernel_in_hyp_mode())
1095+
return;
1096+
1097+
free_hyp_pgds();
1098+
for_each_possible_cpu(cpu)
1099+
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
1100+
}
1101+
1102+
static int init_vhe_mode(void)
1103+
{
1104+
/*
1105+
* Execute the init code on each CPU.
1106+
*/
1107+
on_each_cpu(cpu_init_stage2, NULL, 1);
1108+
1109+
/* set size of VMID supported by CPU */
1110+
kvm_vmid_bits = kvm_get_vmid_bits();
1111+
kvm_info("%d-bit VMID\n", kvm_vmid_bits);
1112+
1113+
kvm_info("VHE mode initialized successfully\n");
1114+
return 0;
1115+
}
1116+
10361117
/**
10371118
* Inits Hyp-mode on all online CPUs
10381119
*/
@@ -1063,7 +1144,7 @@ static int init_hyp_mode(void)
10631144
stack_page = __get_free_page(GFP_KERNEL);
10641145
if (!stack_page) {
10651146
err = -ENOMEM;
1066-
goto out_free_stack_pages;
1147+
goto out_err;
10671148
}
10681149

10691150
per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
@@ -1076,14 +1157,14 @@ static int init_hyp_mode(void)
10761157
kvm_ksym_ref(__kvm_hyp_code_end));
10771158
if (err) {
10781159
kvm_err("Cannot map world-switch code\n");
1079-
goto out_free_mappings;
1160+
goto out_err;
10801161
}
10811162

10821163
err = create_hyp_mappings(kvm_ksym_ref(__start_rodata),
10831164
kvm_ksym_ref(__end_rodata));
10841165
if (err) {
10851166
kvm_err("Cannot map rodata section\n");
1086-
goto out_free_mappings;
1167+
goto out_err;
10871168
}
10881169

10891170
/*
@@ -1095,20 +1176,10 @@ static int init_hyp_mode(void)
10951176

10961177
if (err) {
10971178
kvm_err("Cannot map hyp stack\n");
1098-
goto out_free_mappings;
1179+
goto out_err;
10991180
}
11001181
}
11011182

1102-
/*
1103-
* Map the host CPU structures
1104-
*/
1105-
kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
1106-
if (!kvm_host_cpu_state) {
1107-
err = -ENOMEM;
1108-
kvm_err("Cannot allocate host CPU state\n");
1109-
goto out_free_mappings;
1110-
}
1111-
11121183
for_each_possible_cpu(cpu) {
11131184
kvm_cpu_context_t *cpu_ctxt;
11141185

@@ -1117,7 +1188,7 @@ static int init_hyp_mode(void)
11171188

11181189
if (err) {
11191190
kvm_err("Cannot map host CPU state: %d\n", err);
1120-
goto out_free_context;
1191+
goto out_err;
11211192
}
11221193
}
11231194

@@ -1126,34 +1197,22 @@ static int init_hyp_mode(void)
11261197
*/
11271198
on_each_cpu(cpu_init_hyp_mode, NULL, 1);
11281199

1129-
/*
1130-
* Init HYP view of VGIC
1131-
*/
1132-
err = kvm_vgic_hyp_init();
1133-
switch (err) {
1134-
case 0:
1135-
vgic_present = true;
1136-
break;
1137-
case -ENODEV:
1138-
case -ENXIO:
1139-
vgic_present = false;
1140-
break;
1141-
default:
1142-
goto out_free_context;
1143-
}
1144-
1145-
/*
1146-
* Init HYP architected timer support
1147-
*/
1148-
err = kvm_timer_hyp_init();
1149-
if (err)
1150-
goto out_free_context;
1151-
11521200
#ifndef CONFIG_HOTPLUG_CPU
11531201
free_boot_hyp_pgd();
11541202
#endif
11551203

1156-
kvm_perf_init();
1204+
cpu_notifier_register_begin();
1205+
1206+
err = __register_cpu_notifier(&hyp_init_cpu_nb);
1207+
1208+
cpu_notifier_register_done();
1209+
1210+
if (err) {
1211+
kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
1212+
goto out_err;
1213+
}
1214+
1215+
hyp_cpu_pm_init();
11571216

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

11641223
return 0;
1165-
out_free_context:
1166-
free_percpu(kvm_host_cpu_state);
1167-
out_free_mappings:
1168-
free_hyp_pgds();
1169-
out_free_stack_pages:
1170-
for_each_possible_cpu(cpu)
1171-
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
1224+
11721225
out_err:
1226+
teardown_hyp_mode();
11731227
kvm_err("error initializing Hyp mode: %d\n", err);
11741228
return err;
11751229
}
@@ -1213,26 +1267,27 @@ int kvm_arch_init(void *opaque)
12131267
}
12141268
}
12151269

1216-
cpu_notifier_register_begin();
1217-
1218-
err = init_hyp_mode();
1270+
err = init_common_resources();
12191271
if (err)
1220-
goto out_err;
1272+
return err;
12211273

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

1230-
hyp_cpu_pm_init();
1281+
err = init_subsystems();
1282+
if (err)
1283+
goto out_hyp;
12311284

1232-
kvm_coproc_table_init();
12331285
return 0;
1286+
1287+
out_hyp:
1288+
teardown_hyp_mode();
12341289
out_err:
1235-
cpu_notifier_register_done();
1290+
teardown_common_resources();
12361291
return err;
12371292
}
12381293

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)