diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c index 3d04af0ea9..4abeab8655 100644 --- a/xen/arch/x86/hvm/svm/emulate.c +++ b/xen/arch/x86/hvm/svm/emulate.c @@ -75,6 +75,7 @@ static const struct { [INSTR_STGI] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 4) }, [INSTR_CLGI] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 5) }, [INSTR_INVLPGA] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 7) }, + [INSTR_RDTSCP] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 7, 1) }, [INSTR_INVD] = { X86EMUL_OPC(0x0f, 0x08) }, [INSTR_WBINVD] = { X86EMUL_OPC(0x0f, 0x09) }, [INSTR_WRMSR] = { X86EMUL_OPC(0x0f, 0x30) }, diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 40937bfa47..9464394b0d 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -2279,14 +2279,28 @@ static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb, hvm_hlt(regs->eflags); } -static void svm_vmexit_do_rdtsc(struct cpu_user_regs *regs) +static void svm_vmexit_do_rdtsc(struct cpu_user_regs *regs, bool rdtscp) { + struct vcpu *curr = current; + const struct domain *currd = curr->domain; + enum instruction_index insn = rdtscp ? INSTR_RDTSCP : INSTR_RDTSC; unsigned int inst_len; - if ( (inst_len = __get_instruction_length(current, INSTR_RDTSC)) == 0 ) + if ( rdtscp && !currd->arch.cpuid->extd.rdtscp && + currd->arch.tsc_mode != TSC_MODE_PVRDTSCP ) + { + hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC); return; + } + + if ( (inst_len = __get_instruction_length(curr, insn)) == 0 ) + return; + __update_guest_eip(regs, inst_len); + if ( rdtscp ) + regs->rcx = hvm_msr_tsc_aux(curr); + hvm_rdtsc_intercept(regs); } @@ -2968,10 +2982,8 @@ void svm_vmexit_handler(struct cpu_user_regs *regs) break; case VMEXIT_RDTSCP: - regs->rcx = hvm_msr_tsc_aux(v); - /* fall through */ case VMEXIT_RDTSC: - svm_vmexit_do_rdtsc(regs); + svm_vmexit_do_rdtsc(regs, exit_reason == VMEXIT_RDTSCP); break; case VMEXIT_MONITOR: diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 7f77d1fd28..2166b0dfe4 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -3589,6 +3589,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) unsigned long exit_qualification, exit_reason, idtv_info, intr_info = 0; unsigned int vector = 0, mode; struct vcpu *v = current; + struct domain *currd = v->domain; __vmread(GUEST_RIP, ®s->rip); __vmread(GUEST_RSP, ®s->rsp); @@ -3956,6 +3957,13 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) vmx_invlpg_intercept(exit_qualification); break; case EXIT_REASON_RDTSCP: + if ( !currd->arch.cpuid->extd.rdtscp && + currd->arch.tsc_mode != TSC_MODE_PVRDTSCP ) + { + hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC); + break; + } + regs->rcx = hvm_msr_tsc_aux(v); /* fall through */ case EXIT_REASON_RDTSC: diff --git a/xen/include/asm-x86/hvm/svm/emulate.h b/xen/include/asm-x86/hvm/svm/emulate.h index 3de8236301..ca92abbe28 100644 --- a/xen/include/asm-x86/hvm/svm/emulate.h +++ b/xen/include/asm-x86/hvm/svm/emulate.h @@ -30,6 +30,7 @@ enum instruction_index { INSTR_HLT, INSTR_INT3, INSTR_RDTSC, + INSTR_RDTSCP, INSTR_PAUSE, INSTR_XSETBV, INSTR_VMRUN,