Skip to content

Commit 7ff76d5

Browse files
aprzywaravikivity
authored andcommitted
KVM: SVM: enhance MOV CR intercept handler
Newer SVM implementations provide the GPR number in the VMCB, so that the emulation path is no longer necesarry to handle CR register access intercepts. Implement the handling in svm.c and use it when the info is provided. Signed-off-by: Andre Przywara <[email protected]> Signed-off-by: Marcelo Tosatti <[email protected]>
1 parent ddce97a commit 7ff76d5

File tree

2 files changed

+81
-11
lines changed

2 files changed

+81
-11
lines changed

arch/x86/include/asm/svm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ struct __attribute__ ((__packed__)) vmcb {
260260
#define SVM_EXITINFOSHIFT_TS_REASON_JMP 38
261261
#define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44
262262

263+
#define SVM_EXITINFO_REG_MASK 0x0F
264+
263265
#define SVM_EXIT_READ_CR0 0x000
264266
#define SVM_EXIT_READ_CR3 0x003
265267
#define SVM_EXIT_READ_CR4 0x004

arch/x86/kvm/svm.c

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,12 +2660,80 @@ static int emulate_on_interception(struct vcpu_svm *svm)
26602660
return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE;
26612661
}
26622662

2663+
#define CR_VALID (1ULL << 63)
2664+
2665+
static int cr_interception(struct vcpu_svm *svm)
2666+
{
2667+
int reg, cr;
2668+
unsigned long val;
2669+
int err;
2670+
2671+
if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
2672+
return emulate_on_interception(svm);
2673+
2674+
if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0))
2675+
return emulate_on_interception(svm);
2676+
2677+
reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK;
2678+
cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0;
2679+
2680+
err = 0;
2681+
if (cr >= 16) { /* mov to cr */
2682+
cr -= 16;
2683+
val = kvm_register_read(&svm->vcpu, reg);
2684+
switch (cr) {
2685+
case 0:
2686+
err = kvm_set_cr0(&svm->vcpu, val);
2687+
break;
2688+
case 3:
2689+
err = kvm_set_cr3(&svm->vcpu, val);
2690+
break;
2691+
case 4:
2692+
err = kvm_set_cr4(&svm->vcpu, val);
2693+
break;
2694+
case 8:
2695+
err = kvm_set_cr8(&svm->vcpu, val);
2696+
break;
2697+
default:
2698+
WARN(1, "unhandled write to CR%d", cr);
2699+
kvm_queue_exception(&svm->vcpu, UD_VECTOR);
2700+
return 1;
2701+
}
2702+
} else { /* mov from cr */
2703+
switch (cr) {
2704+
case 0:
2705+
val = kvm_read_cr0(&svm->vcpu);
2706+
break;
2707+
case 2:
2708+
val = svm->vcpu.arch.cr2;
2709+
break;
2710+
case 3:
2711+
val = svm->vcpu.arch.cr3;
2712+
break;
2713+
case 4:
2714+
val = kvm_read_cr4(&svm->vcpu);
2715+
break;
2716+
case 8:
2717+
val = kvm_get_cr8(&svm->vcpu);
2718+
break;
2719+
default:
2720+
WARN(1, "unhandled read from CR%d", cr);
2721+
kvm_queue_exception(&svm->vcpu, UD_VECTOR);
2722+
return 1;
2723+
}
2724+
kvm_register_write(&svm->vcpu, reg, val);
2725+
}
2726+
kvm_complete_insn_gp(&svm->vcpu, err);
2727+
2728+
return 1;
2729+
}
2730+
26632731
static int cr0_write_interception(struct vcpu_svm *svm)
26642732
{
26652733
struct kvm_vcpu *vcpu = &svm->vcpu;
26662734
int r;
26672735

2668-
r = emulate_instruction(&svm->vcpu, 0);
2736+
r = cr_interception(svm);
26692737

26702738
if (svm->nested.vmexit_rip) {
26712739
kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip);
@@ -2674,7 +2742,7 @@ static int cr0_write_interception(struct vcpu_svm *svm)
26742742
svm->nested.vmexit_rip = 0;
26752743
}
26762744

2677-
return r == EMULATE_DONE;
2745+
return r;
26782746
}
26792747

26802748
static int cr8_write_interception(struct vcpu_svm *svm)
@@ -2684,13 +2752,13 @@ static int cr8_write_interception(struct vcpu_svm *svm)
26842752

26852753
u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
26862754
/* instruction emulation calls kvm_set_cr8() */
2687-
r = emulate_instruction(&svm->vcpu, 0);
2755+
r = cr_interception(svm);
26882756
if (irqchip_in_kernel(svm->vcpu.kvm)) {
26892757
clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
2690-
return r == EMULATE_DONE;
2758+
return r;
26912759
}
26922760
if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
2693-
return r == EMULATE_DONE;
2761+
return r;
26942762
kvm_run->exit_reason = KVM_EXIT_SET_TPR;
26952763
return 0;
26962764
}
@@ -2933,14 +3001,14 @@ static int pause_interception(struct vcpu_svm *svm)
29333001
}
29343002

29353003
static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
2936-
[SVM_EXIT_READ_CR0] = emulate_on_interception,
2937-
[SVM_EXIT_READ_CR3] = emulate_on_interception,
2938-
[SVM_EXIT_READ_CR4] = emulate_on_interception,
2939-
[SVM_EXIT_READ_CR8] = emulate_on_interception,
3004+
[SVM_EXIT_READ_CR0] = cr_interception,
3005+
[SVM_EXIT_READ_CR3] = cr_interception,
3006+
[SVM_EXIT_READ_CR4] = cr_interception,
3007+
[SVM_EXIT_READ_CR8] = cr_interception,
29403008
[SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception,
29413009
[SVM_EXIT_WRITE_CR0] = cr0_write_interception,
2942-
[SVM_EXIT_WRITE_CR3] = emulate_on_interception,
2943-
[SVM_EXIT_WRITE_CR4] = emulate_on_interception,
3010+
[SVM_EXIT_WRITE_CR3] = cr_interception,
3011+
[SVM_EXIT_WRITE_CR4] = cr_interception,
29443012
[SVM_EXIT_WRITE_CR8] = cr8_write_interception,
29453013
[SVM_EXIT_READ_DR0] = emulate_on_interception,
29463014
[SVM_EXIT_READ_DR1] = emulate_on_interception,

0 commit comments

Comments
 (0)