1 /*
2  * emulate.c: handling SVM emulate instructions help.
3  * Copyright (c) 2005 AMD Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <xen/err.h>
19 #include <xen/init.h>
20 #include <xen/lib.h>
21 #include <xen/trace.h>
22 #include <asm/msr.h>
23 #include <asm/hvm/hvm.h>
24 #include <asm/hvm/support.h>
25 #include <asm/hvm/svm/svm.h>
26 #include <asm/hvm/svm/vmcb.h>
27 #include <asm/hvm/svm/emulate.h>
28 
svm_nextrip_insn_length(struct vcpu * v)29 static unsigned long svm_nextrip_insn_length(struct vcpu *v)
30 {
31     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
32 
33     if ( !cpu_has_svm_nrips )
34         return 0;
35 
36 #ifndef NDEBUG
37     switch ( vmcb->exitcode )
38     {
39     case VMEXIT_CR0_READ ... VMEXIT_DR15_WRITE:
40         /* faults due to instruction intercepts */
41         /* (exitcodes 84-95) are reserved */
42     case VMEXIT_IDTR_READ ... VMEXIT_TR_WRITE:
43     case VMEXIT_RDTSC ... VMEXIT_MSR:
44     case VMEXIT_VMRUN ... VMEXIT_XSETBV:
45         /* ...and the rest of the #VMEXITs */
46     case VMEXIT_CR0_SEL_WRITE:
47     case VMEXIT_EXCEPTION_BP:
48         break;
49     default:
50         BUG();
51     }
52 #endif
53 
54     return vmcb->nextrip - vmcb->rip;
55 }
56 
57 static const struct {
58     unsigned int opcode;
59     struct {
60         unsigned int rm:3;
61         unsigned int reg:3;
62         unsigned int mod:2;
63 #define MODRM(mod, reg, rm) { rm, reg, mod }
64     } modrm;
65 } opc_tab[INSTR_MAX_COUNT] = {
66     [INSTR_PAUSE]   = { X86EMUL_OPC_F3(0, 0x90) },
67     [INSTR_INT3]    = { X86EMUL_OPC(   0, 0xcc) },
68     [INSTR_HLT]     = { X86EMUL_OPC(   0, 0xf4) },
69     [INSTR_XSETBV]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 2, 1) },
70     [INSTR_VMRUN]   = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 0) },
71     [INSTR_VMCALL]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 1) },
72     [INSTR_VMLOAD]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 2) },
73     [INSTR_VMSAVE]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 3) },
74     [INSTR_STGI]    = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 4) },
75     [INSTR_CLGI]    = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 5) },
76     [INSTR_INVLPGA] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 7) },
77     [INSTR_INVD]    = { X86EMUL_OPC(0x0f, 0x08) },
78     [INSTR_WBINVD]  = { X86EMUL_OPC(0x0f, 0x09) },
79     [INSTR_WRMSR]   = { X86EMUL_OPC(0x0f, 0x30) },
80     [INSTR_RDTSC]   = { X86EMUL_OPC(0x0f, 0x31) },
81     [INSTR_RDMSR]   = { X86EMUL_OPC(0x0f, 0x32) },
82     [INSTR_CPUID]   = { X86EMUL_OPC(0x0f, 0xa2) },
83 };
84 
__get_instruction_length_from_list(struct vcpu * v,const enum instruction_index * list,unsigned int list_count)85 int __get_instruction_length_from_list(struct vcpu *v,
86         const enum instruction_index *list, unsigned int list_count)
87 {
88     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
89     struct hvm_emulate_ctxt ctxt;
90     struct x86_emulate_state *state;
91     unsigned long inst_len, j;
92     unsigned int modrm_rm, modrm_reg;
93     int modrm_mod;
94 
95     /*
96      * In debug builds, always use x86_decode_insn() and compare with
97      * hardware.
98      */
99 #ifdef NDEBUG
100     if ( (inst_len = svm_nextrip_insn_length(v)) > MAX_INST_LEN )
101         gprintk(XENLOG_WARNING, "NRip reported inst_len %lu\n", inst_len);
102     else if ( inst_len != 0 )
103         return inst_len;
104 
105     if ( vmcb->exitcode == VMEXIT_IOIO )
106         return vmcb->exitinfo2 - vmcb->rip;
107 #endif
108 
109     ASSERT(v == current);
110     hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
111     hvm_emulate_init_per_insn(&ctxt, NULL, 0);
112     state = x86_decode_insn(&ctxt.ctxt, hvmemul_insn_fetch);
113     if ( IS_ERR_OR_NULL(state) )
114         return 0;
115 
116     inst_len = x86_insn_length(state, &ctxt.ctxt);
117     modrm_mod = x86_insn_modrm(state, &modrm_rm, &modrm_reg);
118     x86_emulate_free_state(state);
119 #ifndef NDEBUG
120     if ( vmcb->exitcode == VMEXIT_IOIO )
121         j = vmcb->exitinfo2 - vmcb->rip;
122     else
123         j = svm_nextrip_insn_length(v);
124     if ( j && j != inst_len )
125     {
126         gprintk(XENLOG_WARNING, "insn-len[%02x]=%lu (exp %lu)\n",
127                 ctxt.ctxt.opcode, inst_len, j);
128         return j;
129     }
130 #endif
131 
132     for ( j = 0; j < list_count; j++ )
133     {
134         unsigned int instr = list[j];
135 
136         if ( instr >= ARRAY_SIZE(opc_tab) )
137         {
138             ASSERT_UNREACHABLE();
139             break;
140         }
141         if ( opc_tab[instr].opcode == ctxt.ctxt.opcode )
142         {
143             if ( !opc_tab[instr].modrm.mod )
144                 return inst_len;
145 
146             if ( modrm_mod == opc_tab[instr].modrm.mod &&
147                  (modrm_rm & 7) == opc_tab[instr].modrm.rm &&
148                  (modrm_reg & 7) == opc_tab[instr].modrm.reg )
149                 return inst_len;
150         }
151     }
152 
153     gdprintk(XENLOG_WARNING,
154              "%s: Mismatch between expected and actual instruction: "
155              "eip = %lx\n",  __func__, (unsigned long)vmcb->rip);
156     hvm_inject_hw_exception(TRAP_gp_fault, 0);
157     return 0;
158 }
159 
160 /*
161  * Local variables:
162  * mode: C
163  * c-file-style: "BSD"
164  * c-basic-offset: 4
165  * tab-width: 4
166  * indent-tabs-mode: nil
167  * End:
168  */
169