1 /******************************************************************************
2 * x86_emulate.c
3 *
4 * Wrapper for generic x86 instruction decoder and emulator.
5 *
6 * Copyright (c) 2008, Citrix Systems, Inc.
7 *
8 * Authors:
9 * Keir Fraser <keir@xen.org>
10 */
11
12 #include <xen/domain_page.h>
13 #include <xen/err.h>
14 #include <xen/event.h>
15 #include <asm/x86_emulate.h>
16 #include <asm/processor.h> /* current_cpu_info */
17 #include <asm/xstate.h>
18 #include <asm/amd.h> /* cpu_has_amd_erratum() */
19 #include <asm/debugreg.h>
20
21 /* Avoid namespace pollution. */
22 #undef cmpxchg
23 #undef cpuid
24 #undef wbinvd
25
26 #define r(name) r ## name
27
28 #define cpu_has_amd_erratum(nr) \
29 cpu_has_amd_erratum(¤t_cpu_data, AMD_ERRATUM_##nr)
30
31 #define get_stub(stb) ({ \
32 BUILD_BUG_ON(STUB_BUF_SIZE / 2 < MAX_INST_LEN + 1); \
33 ASSERT(!(stb).ptr); \
34 (stb).addr = this_cpu(stubs.addr) + STUB_BUF_SIZE / 2; \
35 memset(((stb).ptr = map_domain_page(_mfn(this_cpu(stubs.mfn)))) + \
36 ((stb).addr & ~PAGE_MASK), 0xcc, STUB_BUF_SIZE / 2); \
37 })
38 #define put_stub(stb) ({ \
39 if ( (stb).ptr ) \
40 { \
41 unmap_domain_page((stb).ptr); \
42 (stb).ptr = NULL; \
43 } \
44 })
45
46 #define FXSAVE_AREA current->arch.fpu_ctxt
47
48 #ifndef CONFIG_HVM
49 # define X86EMUL_NO_FPU
50 # define X86EMUL_NO_MMX
51 # define X86EMUL_NO_SIMD
52 #endif
53
54 #include "x86_emulate/x86_emulate.c"
55
x86emul_read_xcr(unsigned int reg,uint64_t * val,struct x86_emulate_ctxt * ctxt)56 int x86emul_read_xcr(unsigned int reg, uint64_t *val,
57 struct x86_emulate_ctxt *ctxt)
58 {
59 switch ( reg )
60 {
61 case 0:
62 *val = current->arch.xcr0;
63 return X86EMUL_OKAY;
64
65 case 1:
66 if ( current->domain->arch.cpuid->xstate.xgetbv1 )
67 break;
68 /* fall through */
69 default:
70 x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt);
71 return X86EMUL_EXCEPTION;
72 }
73
74 *val = xgetbv(reg);
75
76 return X86EMUL_OKAY;
77 }
78
79 /* Note: May be called with ctxt=NULL. */
x86emul_write_xcr(unsigned int reg,uint64_t val,struct x86_emulate_ctxt * ctxt)80 int x86emul_write_xcr(unsigned int reg, uint64_t val,
81 struct x86_emulate_ctxt *ctxt)
82 {
83 switch ( reg )
84 {
85 case 0:
86 break;
87
88 default:
89 gp_fault:
90 if ( ctxt )
91 x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt);
92 return X86EMUL_EXCEPTION;
93 }
94
95 if ( unlikely(handle_xsetbv(reg, val) != 0) )
96 goto gp_fault;
97
98 return X86EMUL_OKAY;
99 }
100
101 #ifdef CONFIG_PV
102 /* Called with NULL ctxt in hypercall context. */
x86emul_read_dr(unsigned int reg,unsigned long * val,struct x86_emulate_ctxt * ctxt)103 int x86emul_read_dr(unsigned int reg, unsigned long *val,
104 struct x86_emulate_ctxt *ctxt)
105 {
106 struct vcpu *curr = current;
107
108 /* HVM support requires a bit more plumbing before it will work. */
109 ASSERT(is_pv_vcpu(curr));
110
111 switch ( reg )
112 {
113 case 0 ... 3:
114 *val = array_access_nospec(curr->arch.dr, reg);
115 break;
116
117 case 4:
118 if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE )
119 goto ud_fault;
120
121 /* Fallthrough */
122 case 6:
123 *val = curr->arch.dr6;
124 break;
125
126 case 5:
127 if ( curr->arch.pv.ctrlreg[4] & X86_CR4_DE )
128 goto ud_fault;
129
130 /* Fallthrough */
131 case 7:
132 *val = curr->arch.dr7 | curr->arch.pv.dr7_emul;
133 break;
134
135 ud_fault:
136 default:
137 if ( ctxt )
138 x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt);
139
140 return X86EMUL_EXCEPTION;
141 }
142
143 return X86EMUL_OKAY;
144 }
145
x86emul_write_dr(unsigned int reg,unsigned long val,struct x86_emulate_ctxt * ctxt)146 int x86emul_write_dr(unsigned int reg, unsigned long val,
147 struct x86_emulate_ctxt *ctxt)
148 {
149 struct vcpu *curr = current;
150
151 /* HVM support requires a bit more plumbing before it will work. */
152 ASSERT(is_pv_vcpu(curr));
153
154 switch ( set_debugreg(curr, reg, val) )
155 {
156 case 0:
157 return X86EMUL_OKAY;
158
159 case -ENODEV:
160 x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt);
161 return X86EMUL_EXCEPTION;
162
163 default:
164 x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt);
165 return X86EMUL_EXCEPTION;
166 }
167 }
168 #endif /* CONFIG_PV */
169
x86emul_cpuid(uint32_t leaf,uint32_t subleaf,struct cpuid_leaf * res,struct x86_emulate_ctxt * ctxt)170 int x86emul_cpuid(uint32_t leaf, uint32_t subleaf,
171 struct cpuid_leaf *res, struct x86_emulate_ctxt *ctxt)
172 {
173 guest_cpuid(current, leaf, subleaf, res);
174
175 return X86EMUL_OKAY;
176 }
177
178 /*
179 * Local variables:
180 * mode: C
181 * c-file-style: "BSD"
182 * c-basic-offset: 4
183 * tab-width: 4
184 * indent-tabs-mode: nil
185 * End:
186 */
187