Skip to content

Commit 07aeb70

Browse files
Fuad TabbaMarc Zyngier
authored andcommitted
KVM: arm64: Reserve pKVM handle during pkvm_init_host_vm()
When a pKVM guest is active, TLB invalidations triggered by host MMU notifiers require a valid hypervisor handle. Currently, this handle is only allocated when the first vCPU is run. However, the guest's memory is associated with the host MMU much earlier, during kvm_arch_init_vm(). This creates a window where an MMU invalidation could occur after the kvm_pgtable pointer checked by the notifiers is set but before the pKVM handle has been created. Fix this by reserving the pKVM handle when the host VM is first set up. Move the call to the __pkvm_reserve_vm hypercall from the first-vCPU-run path into pkvm_init_host_vm(), which is called during initial VM setup. This ensures the handle is available before any subsystem can trigger an MMU notification for the VM. The VM destruction path is updated to call __pkvm_unreserve_vm for cases where a VM was reserved but never fully created at the hypervisor, ensuring the handle is properly released. This fix leverages the two-stage reservation/initialization hypercall interface introduced in preceding patches. Signed-off-by: Fuad Tabba <tabba@google.com> Tested-by: Mark Brown <broonie@kernel.org> Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 256b466 commit 07aeb70

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

arch/arm64/kvm/arm.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
170170
if (ret)
171171
return ret;
172172

173-
ret = pkvm_init_host_vm(kvm);
174-
if (ret)
175-
goto err_unshare_kvm;
176-
177173
if (!zalloc_cpumask_var(&kvm->arch.supported_cpus, GFP_KERNEL_ACCOUNT)) {
178174
ret = -ENOMEM;
179175
goto err_unshare_kvm;
@@ -184,6 +180,16 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
184180
if (ret)
185181
goto err_free_cpumask;
186182

183+
if (is_protected_kvm_enabled()) {
184+
/*
185+
* If any failures occur after this is successful, make sure to
186+
* call __pkvm_unreserve_vm to unreserve the VM in hyp.
187+
*/
188+
ret = pkvm_init_host_vm(kvm);
189+
if (ret)
190+
goto err_free_cpumask;
191+
}
192+
187193
kvm_vgic_early_init(kvm);
188194

189195
kvm_timer_init_vm(kvm);

arch/arm64/kvm/pkvm.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ static void __pkvm_destroy_hyp_vm(struct kvm *kvm)
9090
if (pkvm_hyp_vm_is_created(kvm)) {
9191
WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm,
9292
kvm->arch.pkvm.handle));
93+
} else if (kvm->arch.pkvm.handle) {
94+
/*
95+
* The VM could have been reserved but hyp initialization has
96+
* failed. Make sure to unreserve it.
97+
*/
98+
kvm_call_hyp_nvhe(__pkvm_unreserve_vm, kvm->arch.pkvm.handle);
9399
}
94100

95101
kvm->arch.pkvm.handle = 0;
@@ -160,25 +166,16 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
160166
goto free_pgd;
161167
}
162168

163-
/* Reserve the VM in hyp and obtain a hyp handle for the VM. */
164-
ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm);
165-
if (ret < 0)
166-
goto free_vm;
167-
168-
kvm->arch.pkvm.handle = ret;
169-
170169
/* Donate the VM memory to hyp and let hyp initialize it. */
171170
ret = kvm_call_hyp_nvhe(__pkvm_init_vm, kvm, hyp_vm, pgd);
172171
if (ret)
173-
goto unreserve_vm;
172+
goto free_vm;
174173

175174
kvm->arch.pkvm.is_created = true;
176175
kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
177176
kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE);
178177

179178
return 0;
180-
unreserve_vm:
181-
kvm_call_hyp_nvhe(__pkvm_unreserve_vm, kvm->arch.pkvm.handle);
182179
free_vm:
183180
free_pages_exact(hyp_vm, hyp_vm_sz);
184181
free_pgd:
@@ -224,6 +221,22 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm)
224221

225222
int pkvm_init_host_vm(struct kvm *kvm)
226223
{
224+
int ret;
225+
226+
if (pkvm_hyp_vm_is_created(kvm))
227+
return -EINVAL;
228+
229+
/* VM is already reserved, no need to proceed. */
230+
if (kvm->arch.pkvm.handle)
231+
return 0;
232+
233+
/* Reserve the VM in hyp and obtain a hyp handle for the VM. */
234+
ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm);
235+
if (ret < 0)
236+
return ret;
237+
238+
kvm->arch.pkvm.handle = ret;
239+
227240
return 0;
228241
}
229242

0 commit comments

Comments
 (0)