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(&current_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