Skip to content

Commit 00f08d9

Browse files
maciejsszmigierobonzini
authored andcommitted
KVM: nSVM: Sync next_rip field from vmcb12 to vmcb02
The next_rip field of a VMCB is *not* an output-only field for a VMRUN. This field value (instead of the saved guest RIP) in used by the CPU for the return address pushed on stack when injecting a software interrupt or INT3 or INTO exception. Make sure this field gets synced from vmcb12 to vmcb02 when entering L2 or loading a nested state and NRIPS is exposed to L1. If NRIPS is supported in hardware but not exposed to L1 (nrips=0 or hidden by userspace), stuff vmcb02's next_rip from the new L2 RIP to emulate a !NRIPS CPU (which saves RIP on the stack as-is). Reviewed-by: Maxim Levitsky <[email protected]> Co-developed-by: Sean Christopherson <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Signed-off-by: Maciej S. Szmigiero <[email protected]> Message-Id: <c2e0a3d78db3ae30530f11d4e9254b452a89f42b.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 5552de7 commit 00f08d9

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

arch/x86/kvm/svm/nested.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
371371
to->nested_ctl = from->nested_ctl;
372372
to->event_inj = from->event_inj;
373373
to->event_inj_err = from->event_inj_err;
374+
to->next_rip = from->next_rip;
374375
to->nested_cr3 = from->nested_cr3;
375376
to->virt_ext = from->virt_ext;
376377
to->pause_filter_count = from->pause_filter_count;
@@ -608,7 +609,8 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12
608609
}
609610
}
610611

611-
static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
612+
static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
613+
unsigned long vmcb12_rip)
612614
{
613615
u32 int_ctl_vmcb01_bits = V_INTR_MASKING_MASK;
614616
u32 int_ctl_vmcb12_bits = V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK;
@@ -662,6 +664,19 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
662664
vmcb02->control.event_inj = svm->nested.ctl.event_inj;
663665
vmcb02->control.event_inj_err = svm->nested.ctl.event_inj_err;
664666

667+
/*
668+
* next_rip is consumed on VMRUN as the return address pushed on the
669+
* stack for injected soft exceptions/interrupts. If nrips is exposed
670+
* to L1, take it verbatim from vmcb12. If nrips is supported in
671+
* hardware but not exposed to L1, stuff the actual L2 RIP to emulate
672+
* what a nrips=0 CPU would do (L1 is responsible for advancing RIP
673+
* prior to injecting the event).
674+
*/
675+
if (svm->nrips_enabled)
676+
vmcb02->control.next_rip = svm->nested.ctl.next_rip;
677+
else if (boot_cpu_has(X86_FEATURE_NRIPS))
678+
vmcb02->control.next_rip = vmcb12_rip;
679+
665680
vmcb02->control.virt_ext = vmcb01->control.virt_ext &
666681
LBR_CTL_ENABLE_MASK;
667682
if (svm->lbrv_enabled)
@@ -745,7 +760,7 @@ int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa,
745760
nested_svm_copy_common_state(svm->vmcb01.ptr, svm->nested.vmcb02.ptr);
746761

747762
svm_switch_vmcb(svm, &svm->nested.vmcb02);
748-
nested_vmcb02_prepare_control(svm);
763+
nested_vmcb02_prepare_control(svm, vmcb12->save.rip);
749764
nested_vmcb02_prepare_save(svm, vmcb12);
750765

751766
ret = nested_svm_load_cr3(&svm->vcpu, svm->nested.save.cr3,
@@ -1418,6 +1433,7 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
14181433
dst->nested_ctl = from->nested_ctl;
14191434
dst->event_inj = from->event_inj;
14201435
dst->event_inj_err = from->event_inj_err;
1436+
dst->next_rip = from->next_rip;
14211437
dst->nested_cr3 = from->nested_cr3;
14221438
dst->virt_ext = from->virt_ext;
14231439
dst->pause_filter_count = from->pause_filter_count;
@@ -1602,7 +1618,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
16021618
nested_copy_vmcb_control_to_cache(svm, ctl);
16031619

16041620
svm_switch_vmcb(svm, &svm->nested.vmcb02);
1605-
nested_vmcb02_prepare_control(svm);
1621+
nested_vmcb02_prepare_control(svm, svm->vmcb->save.rip);
16061622

16071623
/*
16081624
* While the nested guest CR3 is already checked and set by

arch/x86/kvm/svm/svm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ struct vmcb_ctrl_area_cached {
139139
u64 nested_ctl;
140140
u32 event_inj;
141141
u32 event_inj_err;
142+
u64 next_rip;
142143
u64 nested_cr3;
143144
u64 virt_ext;
144145
u32 clean;

0 commit comments

Comments
 (0)