[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.9] x86/hvm: Corrections to RDTSCP intercept handling



commit 3a3f48a59e4269c6111e2c30f31a49d76322bf65
Author:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
AuthorDate: Fri Feb 1 12:04:41 2019 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Fri Feb 1 12:04:41 2019 +0100

    x86/hvm: Corrections to RDTSCP intercept handling
    
    For both VT-x and SVM, the RDTSCP intercept will trigger if the pipeline
    supports the instruction, but the guest may not have RDTSCP in its 
featureset.
    Bring the vmexit handlers in line with the main emulator behaviour by
    optionally handing back #UD.
    
    Next on the AMD side, if RDTSCP actually ends up being intercepted on a 
debug
    build or first-gen SVM hardware which lacks NRIP, we first update regs->rcx,
    then call __get_instruction_length() asking for RDTSC.  As the two
    instructions are different (and indeed, different lengths!),
    __get_instruction_length_from_list() fails and hands back a #GP fault.
    
    This can demonstrated by putting a guest into tsc_mode="always emulate" and
    executing an RDTSCP instruction:
    
      (d1) --- Xen Test Framework ---
      (d1) Environment: HVM 64bit (Long mode 4 levels)
      (d1) Test rdtscp
      (d1) TSC mode 1
      (XEN) emulate.c:147:d1v0 __get_instruction_length: Mismatch between 
expected and actual instruction:
      (XEN) emulate.c:152:d1v0   insn_index 8, opcode 0xf0031 modrm 0
      (XEN) emulate.c:154:d1v0   rip 0x10475f, nextrip 0x104762, len 3
      (XEN) SVM insn len emulation failed (1): d1v0 64bit @ 0008:0010475f -> 0f 
01 f9 0f 31 5b 31 ff 31 c0 e9 c2 db ff ff 00
      (d1) ******************************
      (d1) PANIC: Unhandled exception at 0008:000000000010475f
      (d1) Vec 13 #GP[0000]
      (d1) ******************************
    
    First, teach __get_instruction_length() to cope with RDTSCP, and improve
    svm_vmexit_do_rdtsc() to ask for the correct instruction.  Move the 
regs->rcx
    adjustment into this function to ensure it gets done after we are done
    potentially raising faults.
    
    Reported-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
    Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Reviewed-by: Brian Woods <brian.woods@xxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
    Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    master commit: 3fd3fda9c26fc3c4f77250f795ed7ff9d38e2ec6
    master date: 2018-12-17 16:28:03 +0000
---
 xen/arch/x86/hvm/svm/emulate.c        |  1 +
 xen/arch/x86/hvm/svm/svm.c            | 22 +++++++++++++++++-----
 xen/arch/x86/hvm/vmx/vmx.c            |  8 ++++++++
 xen/include/asm-x86/hvm/svm/emulate.h |  1 +
 4 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
index e1a158103c..2614af1363 100644
--- a/xen/arch/x86/hvm/svm/emulate.c
+++ b/xen/arch/x86/hvm/svm/emulate.c
@@ -74,6 +74,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 155a1877b8..55b1498e9d 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2226,14 +2226,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);
 }
 
@@ -2854,10 +2868,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 9f97f388c9..5042a86515 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -3628,6 +3628,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,    &regs->rip);
     __vmread(GUEST_RSP,    &regs->rsp);
@@ -3991,6 +3992,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 7c1dcd186a..ccb654f1dd 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,
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.9

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.