Skip to content

Commit 26778aa

Browse files
author
Marc Zyngier
committed
KVM: arm64: Commit pending PC adjustemnts before returning to userspace
KVM currently updates PC (and the corresponding exception state) using a two phase approach: first by setting a set of flags, then by converting these flags into a state update when the vcpu is about to enter the guest. However, this creates a disconnect with userspace if the vcpu thread returns there with any exception/PC flag set. In this case, the exposed context is wrong, as userspace doesn't have access to these flags (they aren't architectural). It also means that these flags are preserved across a reset, which isn't expected. To solve this problem, force an explicit synchronisation of the exception state on vcpu exit to userspace. As an optimisation for nVHE systems, only perform this when there is something pending. Reported-by: Zenghui Yu <[email protected]> Reviewed-by: Alexandru Elisei <[email protected]> Reviewed-by: Zenghui Yu <[email protected]> Tested-by: Zenghui Yu <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Cc: [email protected] # 5.11
1 parent f5e3068 commit 26778aa

File tree

4 files changed

+22
-2
lines changed

4 files changed

+22
-2
lines changed

arch/arm64/include/asm/kvm_asm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#define __KVM_HOST_SMCCC_FUNC___pkvm_cpu_set_vector 18
6464
#define __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize 19
6565
#define __KVM_HOST_SMCCC_FUNC___pkvm_mark_hyp 20
66+
#define __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc 21
6667

6768
#ifndef __ASSEMBLY__
6869

arch/arm64/kvm/arm.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
897897

898898
kvm_sigset_deactivate(vcpu);
899899

900+
/*
901+
* In the unlikely event that we are returning to userspace
902+
* with pending exceptions or PC adjustment, commit these
903+
* adjustments in order to give userspace a consistent view of
904+
* the vcpu state. Note that this relies on __kvm_adjust_pc()
905+
* being preempt-safe on VHE.
906+
*/
907+
if (unlikely(vcpu->arch.flags & (KVM_ARM64_PENDING_EXCEPTION |
908+
KVM_ARM64_INCREMENT_PC)))
909+
kvm_call_hyp(__kvm_adjust_pc, vcpu);
910+
900911
vcpu_put(vcpu);
901912
return ret;
902913
}

arch/arm64/kvm/hyp/exception.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)
331331
}
332332

333333
/*
334-
* Adjust the guest PC on entry, depending on flags provided by EL1
335-
* for the purpose of emulation (MMIO, sysreg) or exception injection.
334+
* Adjust the guest PC (and potentially exception state) depending on
335+
* flags provided by the emulation code.
336336
*/
337337
void __kvm_adjust_pc(struct kvm_vcpu *vcpu)
338338
{

arch/arm64/kvm/hyp/nvhe/hyp-main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
2828
cpu_reg(host_ctxt, 1) = __kvm_vcpu_run(kern_hyp_va(vcpu));
2929
}
3030

31+
static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
32+
{
33+
DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
34+
35+
__kvm_adjust_pc(kern_hyp_va(vcpu));
36+
}
37+
3138
static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
3239
{
3340
__kvm_flush_vm_context();
@@ -170,6 +177,7 @@ typedef void (*hcall_t)(struct kvm_cpu_context *);
170177

171178
static const hcall_t host_hcall[] = {
172179
HANDLE_FUNC(__kvm_vcpu_run),
180+
HANDLE_FUNC(__kvm_adjust_pc),
173181
HANDLE_FUNC(__kvm_flush_vm_context),
174182
HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
175183
HANDLE_FUNC(__kvm_tlb_flush_vmid),

0 commit comments

Comments
 (0)