|
1 /* |
|
2 * i386 execution defines |
|
3 * |
|
4 * Copyright (c) 2003 Fabrice Bellard |
|
5 * |
|
6 * This library is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU Lesser General Public |
|
8 * License as published by the Free Software Foundation; either |
|
9 * version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 * Lesser General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Lesser General Public |
|
17 * License along with this library; if not, write to the Free Software |
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
19 */ |
|
20 #include "config.h" |
|
21 #include "dyngen-exec.h" |
|
22 |
|
23 /* XXX: factorize this mess */ |
|
24 #ifdef TARGET_X86_64 |
|
25 #define TARGET_LONG_BITS 64 |
|
26 #else |
|
27 #define TARGET_LONG_BITS 32 |
|
28 #endif |
|
29 |
|
30 #include "cpu-defs.h" |
|
31 |
|
32 register struct CPUX86State *env asm(AREG0); |
|
33 |
|
34 #include "qemu-log.h" |
|
35 |
|
36 #define EAX (env->regs[R_EAX]) |
|
37 #define ECX (env->regs[R_ECX]) |
|
38 #define EDX (env->regs[R_EDX]) |
|
39 #define EBX (env->regs[R_EBX]) |
|
40 #define ESP (env->regs[R_ESP]) |
|
41 #define EBP (env->regs[R_EBP]) |
|
42 #define ESI (env->regs[R_ESI]) |
|
43 #define EDI (env->regs[R_EDI]) |
|
44 #define EIP (env->eip) |
|
45 #define DF (env->df) |
|
46 |
|
47 #define CC_SRC (env->cc_src) |
|
48 #define CC_DST (env->cc_dst) |
|
49 #define CC_OP (env->cc_op) |
|
50 |
|
51 /* float macros */ |
|
52 #define FT0 (env->ft0) |
|
53 #define ST0 (env->fpregs[env->fpstt].d) |
|
54 #define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) |
|
55 #define ST1 ST(1) |
|
56 |
|
57 #include "cpu.h" |
|
58 #include "exec-all.h" |
|
59 |
|
60 /* op_helper.c */ |
|
61 void do_interrupt(int intno, int is_int, int error_code, |
|
62 target_ulong next_eip, int is_hw); |
|
63 void do_interrupt_user(int intno, int is_int, int error_code, |
|
64 target_ulong next_eip); |
|
65 void raise_exception_err(int exception_index, int error_code); |
|
66 void raise_exception(int exception_index); |
|
67 void do_smm_enter(void); |
|
68 |
|
69 /* n must be a constant to be efficient */ |
|
70 static inline target_long lshift(target_long x, int n) |
|
71 { |
|
72 if (n >= 0) |
|
73 return x << n; |
|
74 else |
|
75 return x >> (-n); |
|
76 } |
|
77 |
|
78 #include "helper.h" |
|
79 |
|
80 static inline void svm_check_intercept(uint32_t type) |
|
81 { |
|
82 helper_svm_check_intercept_param(type, 0); |
|
83 } |
|
84 |
|
85 #if !defined(CONFIG_USER_ONLY) |
|
86 |
|
87 #include "softmmu_exec.h" |
|
88 |
|
89 #endif /* !defined(CONFIG_USER_ONLY) */ |
|
90 |
|
91 #ifdef USE_X86LDOUBLE |
|
92 /* use long double functions */ |
|
93 #define floatx_to_int32 floatx80_to_int32 |
|
94 #define floatx_to_int64 floatx80_to_int64 |
|
95 #define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero |
|
96 #define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero |
|
97 #define int32_to_floatx int32_to_floatx80 |
|
98 #define int64_to_floatx int64_to_floatx80 |
|
99 #define float32_to_floatx float32_to_floatx80 |
|
100 #define float64_to_floatx float64_to_floatx80 |
|
101 #define floatx_to_float32 floatx80_to_float32 |
|
102 #define floatx_to_float64 floatx80_to_float64 |
|
103 #define floatx_abs floatx80_abs |
|
104 #define floatx_chs floatx80_chs |
|
105 #define floatx_round_to_int floatx80_round_to_int |
|
106 #define floatx_compare floatx80_compare |
|
107 #define floatx_compare_quiet floatx80_compare_quiet |
|
108 #else |
|
109 #define floatx_to_int32 float64_to_int32 |
|
110 #define floatx_to_int64 float64_to_int64 |
|
111 #define floatx_to_int32_round_to_zero float64_to_int32_round_to_zero |
|
112 #define floatx_to_int64_round_to_zero float64_to_int64_round_to_zero |
|
113 #define int32_to_floatx int32_to_float64 |
|
114 #define int64_to_floatx int64_to_float64 |
|
115 #define float32_to_floatx float32_to_float64 |
|
116 #define float64_to_floatx(x, e) (x) |
|
117 #define floatx_to_float32 float64_to_float32 |
|
118 #define floatx_to_float64(x, e) (x) |
|
119 #define floatx_abs float64_abs |
|
120 #define floatx_chs float64_chs |
|
121 #define floatx_round_to_int float64_round_to_int |
|
122 #define floatx_compare float64_compare |
|
123 #define floatx_compare_quiet float64_compare_quiet |
|
124 #endif |
|
125 |
|
126 #define RC_MASK 0xc00 |
|
127 #define RC_NEAR 0x000 |
|
128 #define RC_DOWN 0x400 |
|
129 #define RC_UP 0x800 |
|
130 #define RC_CHOP 0xc00 |
|
131 |
|
132 #define MAXTAN 9223372036854775808.0 |
|
133 |
|
134 #ifdef USE_X86LDOUBLE |
|
135 |
|
136 /* only for x86 */ |
|
137 typedef union { |
|
138 long double d; |
|
139 struct { |
|
140 unsigned long long lower; |
|
141 unsigned short upper; |
|
142 } l; |
|
143 } CPU86_LDoubleU; |
|
144 |
|
145 /* the following deal with x86 long double-precision numbers */ |
|
146 #define MAXEXPD 0x7fff |
|
147 #define EXPBIAS 16383 |
|
148 #define EXPD(fp) (fp.l.upper & 0x7fff) |
|
149 #define SIGND(fp) ((fp.l.upper) & 0x8000) |
|
150 #define MANTD(fp) (fp.l.lower) |
|
151 #define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS |
|
152 |
|
153 #else |
|
154 |
|
155 /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ |
|
156 typedef union { |
|
157 double d; |
|
158 #if !defined(WORDS_BIGENDIAN) && !defined(__arm__) |
|
159 struct { |
|
160 uint32_t lower; |
|
161 int32_t upper; |
|
162 } l; |
|
163 #else |
|
164 struct { |
|
165 int32_t upper; |
|
166 uint32_t lower; |
|
167 } l; |
|
168 #endif |
|
169 #ifndef __arm__ |
|
170 int64_t ll; |
|
171 #endif |
|
172 } CPU86_LDoubleU; |
|
173 |
|
174 /* the following deal with IEEE double-precision numbers */ |
|
175 #define MAXEXPD 0x7ff |
|
176 #define EXPBIAS 1023 |
|
177 #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) |
|
178 #define SIGND(fp) ((fp.l.upper) & 0x80000000) |
|
179 #ifdef __arm__ |
|
180 #define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) |
|
181 #else |
|
182 #define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) |
|
183 #endif |
|
184 #define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) |
|
185 #endif |
|
186 |
|
187 static inline void fpush(void) |
|
188 { |
|
189 env->fpstt = (env->fpstt - 1) & 7; |
|
190 env->fptags[env->fpstt] = 0; /* validate stack entry */ |
|
191 } |
|
192 |
|
193 static inline void fpop(void) |
|
194 { |
|
195 env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ |
|
196 env->fpstt = (env->fpstt + 1) & 7; |
|
197 } |
|
198 |
|
199 #ifndef USE_X86LDOUBLE |
|
200 static inline CPU86_LDouble helper_fldt(target_ulong ptr) |
|
201 { |
|
202 CPU86_LDoubleU temp; |
|
203 int upper, e; |
|
204 uint64_t ll; |
|
205 |
|
206 /* mantissa */ |
|
207 upper = lduw(ptr + 8); |
|
208 /* XXX: handle overflow ? */ |
|
209 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ |
|
210 e |= (upper >> 4) & 0x800; /* sign */ |
|
211 ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); |
|
212 #ifdef __arm__ |
|
213 temp.l.upper = (e << 20) | (ll >> 32); |
|
214 temp.l.lower = ll; |
|
215 #else |
|
216 temp.ll = ll | ((uint64_t)e << 52); |
|
217 #endif |
|
218 return temp.d; |
|
219 } |
|
220 |
|
221 static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) |
|
222 { |
|
223 CPU86_LDoubleU temp; |
|
224 int e; |
|
225 |
|
226 temp.d = f; |
|
227 /* mantissa */ |
|
228 stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); |
|
229 /* exponent + sign */ |
|
230 e = EXPD(temp) - EXPBIAS + 16383; |
|
231 e |= SIGND(temp) >> 16; |
|
232 stw(ptr + 8, e); |
|
233 } |
|
234 #else |
|
235 |
|
236 /* we use memory access macros */ |
|
237 |
|
238 static inline CPU86_LDouble helper_fldt(target_ulong ptr) |
|
239 { |
|
240 CPU86_LDoubleU temp; |
|
241 |
|
242 temp.l.lower = ldq(ptr); |
|
243 temp.l.upper = lduw(ptr + 8); |
|
244 return temp.d; |
|
245 } |
|
246 |
|
247 static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) |
|
248 { |
|
249 CPU86_LDoubleU temp; |
|
250 |
|
251 temp.d = f; |
|
252 stq(ptr, temp.l.lower); |
|
253 stw(ptr + 8, temp.l.upper); |
|
254 } |
|
255 |
|
256 #endif /* USE_X86LDOUBLE */ |
|
257 |
|
258 #define FPUS_IE (1 << 0) |
|
259 #define FPUS_DE (1 << 1) |
|
260 #define FPUS_ZE (1 << 2) |
|
261 #define FPUS_OE (1 << 3) |
|
262 #define FPUS_UE (1 << 4) |
|
263 #define FPUS_PE (1 << 5) |
|
264 #define FPUS_SF (1 << 6) |
|
265 #define FPUS_SE (1 << 7) |
|
266 #define FPUS_B (1 << 15) |
|
267 |
|
268 #define FPUC_EM 0x3f |
|
269 |
|
270 static inline uint32_t compute_eflags(void) |
|
271 { |
|
272 return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); |
|
273 } |
|
274 |
|
275 /* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ |
|
276 static inline void load_eflags(int eflags, int update_mask) |
|
277 { |
|
278 CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
|
279 DF = 1 - (2 * ((eflags >> 10) & 1)); |
|
280 env->eflags = (env->eflags & ~update_mask) | |
|
281 (eflags & update_mask) | 0x2; |
|
282 } |
|
283 |
|
284 static inline void env_to_regs(void) |
|
285 { |
|
286 #ifdef reg_EAX |
|
287 EAX = env->regs[R_EAX]; |
|
288 #endif |
|
289 #ifdef reg_ECX |
|
290 ECX = env->regs[R_ECX]; |
|
291 #endif |
|
292 #ifdef reg_EDX |
|
293 EDX = env->regs[R_EDX]; |
|
294 #endif |
|
295 #ifdef reg_EBX |
|
296 EBX = env->regs[R_EBX]; |
|
297 #endif |
|
298 #ifdef reg_ESP |
|
299 ESP = env->regs[R_ESP]; |
|
300 #endif |
|
301 #ifdef reg_EBP |
|
302 EBP = env->regs[R_EBP]; |
|
303 #endif |
|
304 #ifdef reg_ESI |
|
305 ESI = env->regs[R_ESI]; |
|
306 #endif |
|
307 #ifdef reg_EDI |
|
308 EDI = env->regs[R_EDI]; |
|
309 #endif |
|
310 } |
|
311 |
|
312 static inline void regs_to_env(void) |
|
313 { |
|
314 #ifdef reg_EAX |
|
315 env->regs[R_EAX] = EAX; |
|
316 #endif |
|
317 #ifdef reg_ECX |
|
318 env->regs[R_ECX] = ECX; |
|
319 #endif |
|
320 #ifdef reg_EDX |
|
321 env->regs[R_EDX] = EDX; |
|
322 #endif |
|
323 #ifdef reg_EBX |
|
324 env->regs[R_EBX] = EBX; |
|
325 #endif |
|
326 #ifdef reg_ESP |
|
327 env->regs[R_ESP] = ESP; |
|
328 #endif |
|
329 #ifdef reg_EBP |
|
330 env->regs[R_EBP] = EBP; |
|
331 #endif |
|
332 #ifdef reg_ESI |
|
333 env->regs[R_ESI] = ESI; |
|
334 #endif |
|
335 #ifdef reg_EDI |
|
336 env->regs[R_EDI] = EDI; |
|
337 #endif |
|
338 } |
|
339 |
|
340 static inline int cpu_halted(CPUState *env) { |
|
341 /* handle exit of HALTED state */ |
|
342 if (!env->halted) |
|
343 return 0; |
|
344 /* disable halt condition */ |
|
345 if (((env->interrupt_request & CPU_INTERRUPT_HARD) && |
|
346 (env->eflags & IF_MASK)) || |
|
347 (env->interrupt_request & CPU_INTERRUPT_NMI)) { |
|
348 env->halted = 0; |
|
349 return 0; |
|
350 } |
|
351 return EXCP_HALTED; |
|
352 } |
|
353 |
|
354 /* load efer and update the corresponding hflags. XXX: do consistency |
|
355 checks with cpuid bits ? */ |
|
356 static inline void cpu_load_efer(CPUState *env, uint64_t val) |
|
357 { |
|
358 env->efer = val; |
|
359 env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); |
|
360 if (env->efer & MSR_EFER_LMA) |
|
361 env->hflags |= HF_LMA_MASK; |
|
362 if (env->efer & MSR_EFER_SVME) |
|
363 env->hflags |= HF_SVME_MASK; |
|
364 } |