/root/src/xen/xen/arch/x86/hvm/svm/emulate.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
29 | | static unsigned long svm_nextrip_insn_length(struct vcpu *v) |
30 | 0 | { |
31 | 0 | struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; |
32 | 0 |
|
33 | 0 | if ( !cpu_has_svm_nrips ) |
34 | 0 | return 0; |
35 | 0 |
|
36 | 0 | #ifndef NDEBUG |
37 | 0 | switch ( vmcb->exitcode ) |
38 | 0 | { |
39 | 0 | case VMEXIT_CR0_READ ... VMEXIT_DR15_WRITE: |
40 | 0 | /* faults due to instruction intercepts */ |
41 | 0 | /* (exitcodes 84-95) are reserved */ |
42 | 0 | case VMEXIT_IDTR_READ ... VMEXIT_TR_WRITE: |
43 | 0 | case VMEXIT_RDTSC ... VMEXIT_MSR: |
44 | 0 | case VMEXIT_VMRUN ... VMEXIT_XSETBV: |
45 | 0 | /* ...and the rest of the #VMEXITs */ |
46 | 0 | case VMEXIT_CR0_SEL_WRITE: |
47 | 0 | case VMEXIT_EXCEPTION_BP: |
48 | 0 | break; |
49 | 0 | default: |
50 | 0 | BUG(); |
51 | 0 | } |
52 | 0 | #endif |
53 | 0 |
|
54 | 0 | return vmcb->nextrip - vmcb->rip; |
55 | 0 | } |
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 | | |
85 | | int __get_instruction_length_from_list(struct vcpu *v, |
86 | | const enum instruction_index *list, unsigned int list_count) |
87 | 0 | { |
88 | 0 | struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; |
89 | 0 | struct hvm_emulate_ctxt ctxt; |
90 | 0 | struct x86_emulate_state *state; |
91 | 0 | unsigned long inst_len, j; |
92 | 0 | unsigned int modrm_rm, modrm_reg; |
93 | 0 | int modrm_mod; |
94 | 0 |
|
95 | 0 | /* |
96 | 0 | * In debug builds, always use x86_decode_insn() and compare with |
97 | 0 | * hardware. |
98 | 0 | */ |
99 | 0 | #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 | 0 |
|
109 | 0 | ASSERT(v == current); |
110 | 0 | hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs()); |
111 | 0 | hvm_emulate_init_per_insn(&ctxt, NULL, 0); |
112 | 0 | state = x86_decode_insn(&ctxt.ctxt, hvmemul_insn_fetch); |
113 | 0 | if ( IS_ERR_OR_NULL(state) ) |
114 | 0 | return 0; |
115 | 0 |
|
116 | 0 | inst_len = x86_insn_length(state, &ctxt.ctxt); |
117 | 0 | modrm_mod = x86_insn_modrm(state, &modrm_rm, &modrm_reg); |
118 | 0 | x86_emulate_free_state(state); |
119 | 0 | #ifndef NDEBUG |
120 | 0 | if ( vmcb->exitcode == VMEXIT_IOIO ) |
121 | 0 | j = vmcb->exitinfo2 - vmcb->rip; |
122 | 0 | else |
123 | 0 | j = svm_nextrip_insn_length(v); |
124 | 0 | if ( j && j != inst_len ) |
125 | 0 | { |
126 | 0 | gprintk(XENLOG_WARNING, "insn-len[%02x]=%lu (exp %lu)\n", |
127 | 0 | ctxt.ctxt.opcode, inst_len, j); |
128 | 0 | return j; |
129 | 0 | } |
130 | 0 | #endif |
131 | 0 |
|
132 | 0 | for ( j = 0; j < list_count; j++ ) |
133 | 0 | { |
134 | 0 | unsigned int instr = list[j]; |
135 | 0 |
|
136 | 0 | if ( instr >= ARRAY_SIZE(opc_tab) ) |
137 | 0 | { |
138 | 0 | ASSERT_UNREACHABLE(); |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | if ( opc_tab[instr].opcode == ctxt.ctxt.opcode ) |
142 | 0 | { |
143 | 0 | if ( !opc_tab[instr].modrm.mod ) |
144 | 0 | return inst_len; |
145 | 0 |
|
146 | 0 | if ( modrm_mod == opc_tab[instr].modrm.mod && |
147 | 0 | (modrm_rm & 7) == opc_tab[instr].modrm.rm && |
148 | 0 | (modrm_reg & 7) == opc_tab[instr].modrm.reg ) |
149 | 0 | return inst_len; |
150 | 0 | } |
151 | 0 | } |
152 | 0 |
|
153 | 0 | gdprintk(XENLOG_WARNING, |
154 | 0 | "%s: Mismatch between expected and actual instruction: " |
155 | 0 | "eip = %lx\n", __func__, (unsigned long)vmcb->rip); |
156 | 0 | hvm_inject_hw_exception(TRAP_gp_fault, 0); |
157 | 0 | return 0; |
158 | 0 | } |
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 | | */ |