Skip to content

Commit 5ef8acb

Browse files
ouptonbonzini
authored andcommitted
KVM: nVMX: Emulate MTF when performing instruction emulation
Since commit 5f3d45e ("kvm/x86: add support for MONITOR_TRAP_FLAG"), KVM has allowed an L1 guest to use the monitor trap flag processor-based execution control for its L2 guest. KVM simply forwards any MTF VM-exits to the L1 guest, which works for normal instruction execution. However, when KVM needs to emulate an instruction on the behalf of an L2 guest, the monitor trap flag is not emulated. Add the necessary logic to kvm_skip_emulated_instruction() to synthesize an MTF VM-exit to L1 upon instruction emulation for L2. Fixes: 5f3d45e ("kvm/x86: add support for MONITOR_TRAP_FLAG") Signed-off-by: Oliver Upton <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent dd58f3c commit 5ef8acb

File tree

8 files changed

+83
-2
lines changed

8 files changed

+83
-2
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,7 @@ struct kvm_x86_ops {
11221122
int (*handle_exit)(struct kvm_vcpu *vcpu,
11231123
enum exit_fastpath_completion exit_fastpath);
11241124
int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
1125+
void (*update_emulated_instruction)(struct kvm_vcpu *vcpu);
11251126
void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
11261127
u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu);
11271128
void (*patch_hypercall)(struct kvm_vcpu *vcpu,

arch/x86/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ struct kvm_sync_regs {
390390
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
391391
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
392392
#define KVM_STATE_NESTED_EVMCS 0x00000004
393+
#define KVM_STATE_NESTED_MTF_PENDING 0x00000008
393394

394395
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
395396
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002

arch/x86/kvm/svm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7439,6 +7439,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
74397439
.run = svm_vcpu_run,
74407440
.handle_exit = handle_exit,
74417441
.skip_emulated_instruction = skip_emulated_instruction,
7442+
.update_emulated_instruction = NULL,
74427443
.set_interrupt_shadow = svm_set_interrupt_shadow,
74437444
.get_interrupt_shadow = svm_get_interrupt_shadow,
74447445
.patch_hypercall = svm_patch_hypercall,

arch/x86/kvm/vmx/nested.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3609,8 +3609,15 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
36093609
unsigned long exit_qual;
36103610
bool block_nested_events =
36113611
vmx->nested.nested_run_pending || kvm_event_needs_reinjection(vcpu);
3612+
bool mtf_pending = vmx->nested.mtf_pending;
36123613
struct kvm_lapic *apic = vcpu->arch.apic;
36133614

3615+
/*
3616+
* Clear the MTF state. If a higher priority VM-exit is delivered first,
3617+
* this state is discarded.
3618+
*/
3619+
vmx->nested.mtf_pending = false;
3620+
36143621
if (lapic_in_kernel(vcpu) &&
36153622
test_bit(KVM_APIC_INIT, &apic->pending_events)) {
36163623
if (block_nested_events)
@@ -3621,8 +3628,28 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
36213628
return 0;
36223629
}
36233630

3631+
/*
3632+
* Process any exceptions that are not debug traps before MTF.
3633+
*/
3634+
if (vcpu->arch.exception.pending &&
3635+
!vmx_pending_dbg_trap(vcpu) &&
3636+
nested_vmx_check_exception(vcpu, &exit_qual)) {
3637+
if (block_nested_events)
3638+
return -EBUSY;
3639+
nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
3640+
return 0;
3641+
}
3642+
3643+
if (mtf_pending) {
3644+
if (block_nested_events)
3645+
return -EBUSY;
3646+
nested_vmx_update_pending_dbg(vcpu);
3647+
nested_vmx_vmexit(vcpu, EXIT_REASON_MONITOR_TRAP_FLAG, 0, 0);
3648+
return 0;
3649+
}
3650+
36243651
if (vcpu->arch.exception.pending &&
3625-
nested_vmx_check_exception(vcpu, &exit_qual)) {
3652+
nested_vmx_check_exception(vcpu, &exit_qual)) {
36263653
if (block_nested_events)
36273654
return -EBUSY;
36283655
nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
@@ -5712,6 +5739,9 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
57125739

57135740
if (vmx->nested.nested_run_pending)
57145741
kvm_state.flags |= KVM_STATE_NESTED_RUN_PENDING;
5742+
5743+
if (vmx->nested.mtf_pending)
5744+
kvm_state.flags |= KVM_STATE_NESTED_MTF_PENDING;
57155745
}
57165746
}
57175747

@@ -5892,6 +5922,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
58925922
vmx->nested.nested_run_pending =
58935923
!!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
58945924

5925+
vmx->nested.mtf_pending =
5926+
!!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
5927+
58955928
ret = -EINVAL;
58965929
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
58975930
vmcs12->vmcs_link_pointer != -1ull) {

arch/x86/kvm/vmx/nested.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
174174
return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
175175
}
176176

177+
static inline int nested_cpu_has_mtf(struct vmcs12 *vmcs12)
178+
{
179+
return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG);
180+
}
181+
177182
static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
178183
{
179184
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);

arch/x86/kvm/vmx/vmx.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,40 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
16031603
return 1;
16041604
}
16051605

1606+
1607+
/*
1608+
* Recognizes a pending MTF VM-exit and records the nested state for later
1609+
* delivery.
1610+
*/
1611+
static void vmx_update_emulated_instruction(struct kvm_vcpu *vcpu)
1612+
{
1613+
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
1614+
struct vcpu_vmx *vmx = to_vmx(vcpu);
1615+
1616+
if (!is_guest_mode(vcpu))
1617+
return;
1618+
1619+
/*
1620+
* Per the SDM, MTF takes priority over debug-trap exceptions besides
1621+
* T-bit traps. As instruction emulation is completed (i.e. at the
1622+
* instruction boundary), any #DB exception pending delivery must be a
1623+
* debug-trap. Record the pending MTF state to be delivered in
1624+
* vmx_check_nested_events().
1625+
*/
1626+
if (nested_cpu_has_mtf(vmcs12) &&
1627+
(!vcpu->arch.exception.pending ||
1628+
vcpu->arch.exception.nr == DB_VECTOR))
1629+
vmx->nested.mtf_pending = true;
1630+
else
1631+
vmx->nested.mtf_pending = false;
1632+
}
1633+
1634+
static int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu)
1635+
{
1636+
vmx_update_emulated_instruction(vcpu);
1637+
return skip_emulated_instruction(vcpu);
1638+
}
1639+
16061640
static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
16071641
{
16081642
/*
@@ -7796,7 +7830,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
77967830

77977831
.run = vmx_vcpu_run,
77987832
.handle_exit = vmx_handle_exit,
7799-
.skip_emulated_instruction = skip_emulated_instruction,
7833+
.skip_emulated_instruction = vmx_skip_emulated_instruction,
7834+
.update_emulated_instruction = vmx_update_emulated_instruction,
78007835
.set_interrupt_shadow = vmx_set_interrupt_shadow,
78017836
.get_interrupt_shadow = vmx_get_interrupt_shadow,
78027837
.patch_hypercall = vmx_patch_hypercall,

arch/x86/kvm/vmx/vmx.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ struct nested_vmx {
150150
/* L2 must run next, and mustn't decide to exit to L1. */
151151
bool nested_run_pending;
152152

153+
/* Pending MTF VM-exit into L1. */
154+
bool mtf_pending;
155+
153156
struct loaded_vmcs vmcs02;
154157

155158
/*

arch/x86/kvm/x86.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6891,6 +6891,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
68916891
kvm_rip_write(vcpu, ctxt->eip);
68926892
if (r && ctxt->tf)
68936893
r = kvm_vcpu_do_singlestep(vcpu);
6894+
if (kvm_x86_ops->update_emulated_instruction)
6895+
kvm_x86_ops->update_emulated_instruction(vcpu);
68946896
__kvm_set_rflags(vcpu, ctxt->eflags);
68956897
}
68966898

0 commit comments

Comments
 (0)