| From fb6d4d340e0532032c808a9933eaaa7b8de435ab Mon Sep 17 00:00:00 2001 |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| Date: Tue, 12 Jul 2016 11:04:26 +0200 |
| Subject: KVM: x86: emulate RDPID |
| |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| |
| commit fb6d4d340e0532032c808a9933eaaa7b8de435ab upstream. |
| |
| This is encoded as F3 0F C7 /7 with a register argument. The register |
| argument is the second array in the group9 GroupDual, while F3 is the |
| fourth element of a Prefix. |
| |
| Reviewed-by: Wanpeng Li <wanpeng.li@hotmail.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/cpuid.c | 7 ++++++- |
| arch/x86/kvm/emulate.c | 22 +++++++++++++++++++++- |
| arch/x86/kvm/vmx.c | 15 +++++++++++++++ |
| 3 files changed, 42 insertions(+), 2 deletions(-) |
| |
| --- a/arch/x86/kvm/cpuid.c |
| +++ b/arch/x86/kvm/cpuid.c |
| @@ -267,13 +267,18 @@ static int __do_cpuid_ent_emulated(struc |
| { |
| switch (func) { |
| case 0: |
| - entry->eax = 1; /* only one leaf currently */ |
| + entry->eax = 7; |
| ++*nent; |
| break; |
| case 1: |
| entry->ecx = F(MOVBE); |
| ++*nent; |
| break; |
| + case 7: |
| + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; |
| + if (index == 0) |
| + entry->ecx = F(RDPID); |
| + ++*nent; |
| default: |
| break; |
| } |
| --- a/arch/x86/kvm/emulate.c |
| +++ b/arch/x86/kvm/emulate.c |
| @@ -3519,6 +3519,16 @@ static int em_cwd(struct x86_emulate_ctx |
| return X86EMUL_CONTINUE; |
| } |
| |
| +static int em_rdpid(struct x86_emulate_ctxt *ctxt) |
| +{ |
| + u64 tsc_aux = 0; |
| + |
| + if (ctxt->ops->get_msr(ctxt, MSR_TSC_AUX, &tsc_aux)) |
| + return emulate_gp(ctxt, 0); |
| + ctxt->dst.val = tsc_aux; |
| + return X86EMUL_CONTINUE; |
| +} |
| + |
| static int em_rdtsc(struct x86_emulate_ctxt *ctxt) |
| { |
| u64 tsc = 0; |
| @@ -4379,10 +4389,20 @@ static const struct opcode group8[] = { |
| F(DstMem | SrcImmByte | Lock | PageTable, em_btc), |
| }; |
| |
| +/* |
| + * The "memory" destination is actually always a register, since we come |
| + * from the register case of group9. |
| + */ |
| +static const struct gprefix pfx_0f_c7_7 = { |
| + N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdtscp), |
| +}; |
| + |
| + |
| static const struct group_dual group9 = { { |
| N, I(DstMem64 | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N, |
| }, { |
| - N, N, N, N, N, N, N, N, |
| + N, N, N, N, N, N, N, |
| + GP(0, &pfx_0f_c7_7), |
| } }; |
| |
| static const struct opcode group11[] = { |
| --- a/arch/x86/kvm/vmx.c |
| +++ b/arch/x86/kvm/vmx.c |
| @@ -10744,6 +10744,21 @@ static int vmx_check_intercept(struct kv |
| struct x86_instruction_info *info, |
| enum x86_intercept_stage stage) |
| { |
| + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); |
| + struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
| + |
| + /* |
| + * RDPID causes #UD if disabled through secondary execution controls. |
| + * Because it is marked as EmulateOnUD, we need to intercept it here. |
| + */ |
| + if (info->intercept == x86_intercept_rdtscp && |
| + !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) { |
| + ctxt->exception.vector = UD_VECTOR; |
| + ctxt->exception.error_code_valid = false; |
| + return X86EMUL_PROPAGATE_FAULT; |
| + } |
| + |
| + /* TODO: check more intercepts... */ |
| return X86EMUL_CONTINUE; |
| } |
| |