Coverage Report

Created: 2017-10-25 09:10

/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
 */