|
|
1.1 root 1: /*
2: * i386 helpers
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
1.1.1.3 root 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 18: */
1.1.1.5 root 19:
1.1.1.7 root 20: #include <math.h>
1.1.1.8 root 21: #include "cpu.h"
22: #include "dyngen-exec.h"
1.1 root 23: #include "host-utils.h"
1.1.1.5 root 24: #include "ioport.h"
1.1.1.8 root 25: #include "qemu-log.h"
26: #include "cpu-defs.h"
27: #include "helper.h"
1.1 root 28:
1.1.1.8 root 29: #if !defined(CONFIG_USER_ONLY)
30: #include "softmmu_exec.h"
31: #endif /* !defined(CONFIG_USER_ONLY) */
1.1 root 32:
1.1.1.8 root 33: //#define DEBUG_PCALL
1.1 root 34:
35: #ifdef DEBUG_PCALL
36: # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
37: # define LOG_PCALL_STATE(env) \
38: log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
39: #else
40: # define LOG_PCALL(...) do { } while (0)
41: # define LOG_PCALL_STATE(env) do { } while (0)
42: #endif
43:
1.1.1.8 root 44: /* n must be a constant to be efficient */
45: static inline target_long lshift(target_long x, int n)
46: {
47: if (n >= 0) {
48: return x << n;
49: } else {
50: return x >> (-n);
51: }
52: }
53:
1.1.1.9 ! root 54: #define FPU_RC_MASK 0xc00
! 55: #define FPU_RC_NEAR 0x000
! 56: #define FPU_RC_DOWN 0x400
! 57: #define FPU_RC_UP 0x800
! 58: #define FPU_RC_CHOP 0xc00
1.1.1.8 root 59:
60: #define MAXTAN 9223372036854775808.0
61:
62: /* the following deal with x86 long double-precision numbers */
63: #define MAXEXPD 0x7fff
64: #define EXPBIAS 16383
65: #define EXPD(fp) (fp.l.upper & 0x7fff)
66: #define SIGND(fp) ((fp.l.upper) & 0x8000)
67: #define MANTD(fp) (fp.l.lower)
68: #define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
69:
70: static inline void fpush(void)
71: {
72: env->fpstt = (env->fpstt - 1) & 7;
73: env->fptags[env->fpstt] = 0; /* validate stack entry */
74: }
75:
76: static inline void fpop(void)
77: {
78: env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
79: env->fpstt = (env->fpstt + 1) & 7;
80: }
81:
82: static inline floatx80 helper_fldt(target_ulong ptr)
83: {
84: CPU_LDoubleU temp;
85:
86: temp.l.lower = ldq(ptr);
87: temp.l.upper = lduw(ptr + 8);
88: return temp.d;
89: }
90:
91: static inline void helper_fstt(floatx80 f, target_ulong ptr)
92: {
93: CPU_LDoubleU temp;
94:
95: temp.d = f;
96: stq(ptr, temp.l.lower);
97: stw(ptr + 8, temp.l.upper);
98: }
99:
100: #define FPUS_IE (1 << 0)
101: #define FPUS_DE (1 << 1)
102: #define FPUS_ZE (1 << 2)
103: #define FPUS_OE (1 << 3)
104: #define FPUS_UE (1 << 4)
105: #define FPUS_PE (1 << 5)
106: #define FPUS_SF (1 << 6)
107: #define FPUS_SE (1 << 7)
108: #define FPUS_B (1 << 15)
109:
110: #define FPUC_EM 0x3f
111:
112: static inline uint32_t compute_eflags(void)
113: {
114: return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
115: }
116:
117: /* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
118: static inline void load_eflags(int eflags, int update_mask)
119: {
120: CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
121: DF = 1 - (2 * ((eflags >> 10) & 1));
122: env->eflags = (env->eflags & ~update_mask) |
123: (eflags & update_mask) | 0x2;
124: }
125:
126: /* load efer and update the corresponding hflags. XXX: do consistency
127: checks with cpuid bits ? */
1.1.1.9 ! root 128: static inline void cpu_load_efer(CPUX86State *env, uint64_t val)
1.1.1.8 root 129: {
130: env->efer = val;
131: env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
132: if (env->efer & MSR_EFER_LMA) {
133: env->hflags |= HF_LMA_MASK;
134: }
135: if (env->efer & MSR_EFER_SVME) {
136: env->hflags |= HF_SVME_MASK;
137: }
138: }
1.1 root 139:
140: #if 0
141: #define raise_exception_err(a, b)\
142: do {\
143: qemu_log("raise_exception line=%d\n", __LINE__);\
144: (raise_exception_err)(a, b);\
145: } while (0)
146: #endif
147:
1.1.1.8 root 148: static void QEMU_NORETURN raise_exception_err(int exception_index,
149: int error_code);
150:
1.1 root 151: static const uint8_t parity_table[256] = {
152: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
153: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
154: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
155: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
156: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
157: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
158: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
159: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
160: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
161: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
162: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
163: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
164: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
165: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
166: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
167: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
168: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
169: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
170: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
171: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
172: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
173: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
174: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
175: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
176: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
177: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
178: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
179: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
180: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
181: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
182: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
183: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
184: };
185:
186: /* modulo 17 table */
187: static const uint8_t rclw_table[32] = {
188: 0, 1, 2, 3, 4, 5, 6, 7,
189: 8, 9,10,11,12,13,14,15,
190: 16, 0, 1, 2, 3, 4, 5, 6,
191: 7, 8, 9,10,11,12,13,14,
192: };
193:
194: /* modulo 9 table */
195: static const uint8_t rclb_table[32] = {
196: 0, 1, 2, 3, 4, 5, 6, 7,
197: 8, 0, 1, 2, 3, 4, 5, 6,
198: 7, 8, 0, 1, 2, 3, 4, 5,
199: 6, 7, 8, 0, 1, 2, 3, 4,
200: };
201:
1.1.1.7 root 202: #define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
203: #define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
204: #define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
1.1 root 205:
206: /* broken thread support */
207:
208: static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
209:
210: void helper_lock(void)
211: {
212: spin_lock(&global_cpu_lock);
213: }
214:
215: void helper_unlock(void)
216: {
217: spin_unlock(&global_cpu_lock);
218: }
219:
220: void helper_write_eflags(target_ulong t0, uint32_t update_mask)
221: {
222: load_eflags(t0, update_mask);
223: }
224:
225: target_ulong helper_read_eflags(void)
226: {
227: uint32_t eflags;
228: eflags = helper_cc_compute_all(CC_OP);
229: eflags |= (DF & DF_MASK);
230: eflags |= env->eflags & ~(VM_MASK | RF_MASK);
231: return eflags;
232: }
233:
234: /* return non zero if error */
235: static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
236: int selector)
237: {
238: SegmentCache *dt;
239: int index;
240: target_ulong ptr;
241:
242: if (selector & 0x4)
243: dt = &env->ldt;
244: else
245: dt = &env->gdt;
246: index = selector & ~7;
247: if ((index + 7) > dt->limit)
248: return -1;
249: ptr = dt->base + index;
250: *e1_ptr = ldl_kernel(ptr);
251: *e2_ptr = ldl_kernel(ptr + 4);
252: return 0;
253: }
254:
255: static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
256: {
257: unsigned int limit;
258: limit = (e1 & 0xffff) | (e2 & 0x000f0000);
259: if (e2 & DESC_G_MASK)
260: limit = (limit << 12) | 0xfff;
261: return limit;
262: }
263:
264: static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
265: {
266: return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
267: }
268:
269: static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
270: {
271: sc->base = get_seg_base(e1, e2);
272: sc->limit = get_seg_limit(e1, e2);
273: sc->flags = e2;
274: }
275:
276: /* init the segment cache in vm86 mode. */
277: static inline void load_seg_vm(int seg, int selector)
278: {
279: selector &= 0xffff;
280: cpu_x86_load_seg_cache(env, seg, selector,
281: (selector << 4), 0xffff, 0);
282: }
283:
284: static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
285: uint32_t *esp_ptr, int dpl)
286: {
287: int type, index, shift;
288:
289: #if 0
290: {
291: int i;
292: printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
293: for(i=0;i<env->tr.limit;i++) {
294: printf("%02x ", env->tr.base[i]);
295: if ((i & 7) == 7) printf("\n");
296: }
297: printf("\n");
298: }
299: #endif
300:
301: if (!(env->tr.flags & DESC_P_MASK))
302: cpu_abort(env, "invalid tss");
303: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
304: if ((type & 7) != 1)
305: cpu_abort(env, "invalid tss type");
306: shift = type >> 3;
307: index = (dpl * 4 + 2) << shift;
308: if (index + (4 << shift) - 1 > env->tr.limit)
309: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
310: if (shift == 0) {
311: *esp_ptr = lduw_kernel(env->tr.base + index);
312: *ss_ptr = lduw_kernel(env->tr.base + index + 2);
313: } else {
314: *esp_ptr = ldl_kernel(env->tr.base + index);
315: *ss_ptr = lduw_kernel(env->tr.base + index + 4);
316: }
317: }
318:
319: /* XXX: merge with load_seg() */
320: static void tss_load_seg(int seg_reg, int selector)
321: {
322: uint32_t e1, e2;
323: int rpl, dpl, cpl;
324:
325: if ((selector & 0xfffc) != 0) {
326: if (load_segment(&e1, &e2, selector) != 0)
327: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
328: if (!(e2 & DESC_S_MASK))
329: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
330: rpl = selector & 3;
331: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
332: cpl = env->hflags & HF_CPL_MASK;
333: if (seg_reg == R_CS) {
334: if (!(e2 & DESC_CS_MASK))
335: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
336: /* XXX: is it correct ? */
337: if (dpl != rpl)
338: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
339: if ((e2 & DESC_C_MASK) && dpl > rpl)
340: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
341: } else if (seg_reg == R_SS) {
342: /* SS must be writable data */
343: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
344: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
345: if (dpl != cpl || dpl != rpl)
346: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
347: } else {
348: /* not readable code */
349: if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
350: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
351: /* if data or non conforming code, checks the rights */
352: if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
353: if (dpl < cpl || dpl < rpl)
354: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
355: }
356: }
357: if (!(e2 & DESC_P_MASK))
358: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
359: cpu_x86_load_seg_cache(env, seg_reg, selector,
360: get_seg_base(e1, e2),
361: get_seg_limit(e1, e2),
362: e2);
363: } else {
364: if (seg_reg == R_SS || seg_reg == R_CS)
365: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
366: }
367: }
368:
369: #define SWITCH_TSS_JMP 0
370: #define SWITCH_TSS_IRET 1
371: #define SWITCH_TSS_CALL 2
372:
373: /* XXX: restore CPU state in registers (PowerPC case) */
374: static void switch_tss(int tss_selector,
375: uint32_t e1, uint32_t e2, int source,
376: uint32_t next_eip)
377: {
378: int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
379: target_ulong tss_base;
380: uint32_t new_regs[8], new_segs[6];
381: uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
382: uint32_t old_eflags, eflags_mask;
383: SegmentCache *dt;
384: int index;
385: target_ulong ptr;
386:
387: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
388: LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
389:
390: /* if task gate, we read the TSS segment and we load it */
391: if (type == 5) {
392: if (!(e2 & DESC_P_MASK))
393: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
394: tss_selector = e1 >> 16;
395: if (tss_selector & 4)
396: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
397: if (load_segment(&e1, &e2, tss_selector) != 0)
398: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
399: if (e2 & DESC_S_MASK)
400: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
401: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
402: if ((type & 7) != 1)
403: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
404: }
405:
406: if (!(e2 & DESC_P_MASK))
407: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
408:
409: if (type & 8)
410: tss_limit_max = 103;
411: else
412: tss_limit_max = 43;
413: tss_limit = get_seg_limit(e1, e2);
414: tss_base = get_seg_base(e1, e2);
415: if ((tss_selector & 4) != 0 ||
416: tss_limit < tss_limit_max)
417: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
418: old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
419: if (old_type & 8)
420: old_tss_limit_max = 103;
421: else
422: old_tss_limit_max = 43;
423:
424: /* read all the registers from the new TSS */
425: if (type & 8) {
426: /* 32 bit */
427: new_cr3 = ldl_kernel(tss_base + 0x1c);
428: new_eip = ldl_kernel(tss_base + 0x20);
429: new_eflags = ldl_kernel(tss_base + 0x24);
430: for(i = 0; i < 8; i++)
431: new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
432: for(i = 0; i < 6; i++)
433: new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
434: new_ldt = lduw_kernel(tss_base + 0x60);
435: new_trap = ldl_kernel(tss_base + 0x64);
436: } else {
437: /* 16 bit */
438: new_cr3 = 0;
439: new_eip = lduw_kernel(tss_base + 0x0e);
440: new_eflags = lduw_kernel(tss_base + 0x10);
441: for(i = 0; i < 8; i++)
442: new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
443: for(i = 0; i < 4; i++)
444: new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
445: new_ldt = lduw_kernel(tss_base + 0x2a);
446: new_segs[R_FS] = 0;
447: new_segs[R_GS] = 0;
448: new_trap = 0;
449: }
1.1.1.6 root 450: /* XXX: avoid a compiler warning, see
451: http://support.amd.com/us/Processor_TechDocs/24593.pdf
452: chapters 12.2.5 and 13.2.4 on how to implement TSS Trap bit */
453: (void)new_trap;
1.1 root 454:
455: /* NOTE: we must avoid memory exceptions during the task switch,
456: so we make dummy accesses before */
457: /* XXX: it can still fail in some cases, so a bigger hack is
458: necessary to valid the TLB after having done the accesses */
459:
460: v1 = ldub_kernel(env->tr.base);
461: v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
462: stb_kernel(env->tr.base, v1);
463: stb_kernel(env->tr.base + old_tss_limit_max, v2);
464:
465: /* clear busy bit (it is restartable) */
466: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
467: target_ulong ptr;
468: uint32_t e2;
469: ptr = env->gdt.base + (env->tr.selector & ~7);
470: e2 = ldl_kernel(ptr + 4);
471: e2 &= ~DESC_TSS_BUSY_MASK;
472: stl_kernel(ptr + 4, e2);
473: }
474: old_eflags = compute_eflags();
475: if (source == SWITCH_TSS_IRET)
476: old_eflags &= ~NT_MASK;
477:
478: /* save the current state in the old TSS */
479: if (type & 8) {
480: /* 32 bit */
481: stl_kernel(env->tr.base + 0x20, next_eip);
482: stl_kernel(env->tr.base + 0x24, old_eflags);
483: stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
484: stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
485: stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
486: stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
487: stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
488: stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
489: stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
490: stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
491: for(i = 0; i < 6; i++)
492: stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
493: } else {
494: /* 16 bit */
495: stw_kernel(env->tr.base + 0x0e, next_eip);
496: stw_kernel(env->tr.base + 0x10, old_eflags);
497: stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
498: stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
499: stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
500: stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
501: stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
502: stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
503: stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
504: stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
505: for(i = 0; i < 4; i++)
506: stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
507: }
508:
509: /* now if an exception occurs, it will occurs in the next task
510: context */
511:
512: if (source == SWITCH_TSS_CALL) {
513: stw_kernel(tss_base, env->tr.selector);
514: new_eflags |= NT_MASK;
515: }
516:
517: /* set busy bit */
518: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
519: target_ulong ptr;
520: uint32_t e2;
521: ptr = env->gdt.base + (tss_selector & ~7);
522: e2 = ldl_kernel(ptr + 4);
523: e2 |= DESC_TSS_BUSY_MASK;
524: stl_kernel(ptr + 4, e2);
525: }
526:
527: /* set the new CPU state */
528: /* from this point, any exception which occurs can give problems */
529: env->cr[0] |= CR0_TS_MASK;
530: env->hflags |= HF_TS_MASK;
531: env->tr.selector = tss_selector;
532: env->tr.base = tss_base;
533: env->tr.limit = tss_limit;
534: env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
535:
536: if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
537: cpu_x86_update_cr3(env, new_cr3);
538: }
539:
540: /* load all registers without an exception, then reload them with
541: possible exception */
542: env->eip = new_eip;
543: eflags_mask = TF_MASK | AC_MASK | ID_MASK |
544: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
545: if (!(type & 8))
546: eflags_mask &= 0xffff;
547: load_eflags(new_eflags, eflags_mask);
548: /* XXX: what to do in 16 bit case ? */
549: EAX = new_regs[0];
550: ECX = new_regs[1];
551: EDX = new_regs[2];
552: EBX = new_regs[3];
553: ESP = new_regs[4];
554: EBP = new_regs[5];
555: ESI = new_regs[6];
556: EDI = new_regs[7];
557: if (new_eflags & VM_MASK) {
558: for(i = 0; i < 6; i++)
559: load_seg_vm(i, new_segs[i]);
560: /* in vm86, CPL is always 3 */
561: cpu_x86_set_cpl(env, 3);
562: } else {
563: /* CPL is set the RPL of CS */
564: cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
565: /* first just selectors as the rest may trigger exceptions */
566: for(i = 0; i < 6; i++)
567: cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
568: }
569:
570: env->ldt.selector = new_ldt & ~4;
571: env->ldt.base = 0;
572: env->ldt.limit = 0;
573: env->ldt.flags = 0;
574:
575: /* load the LDT */
576: if (new_ldt & 4)
577: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
578:
579: if ((new_ldt & 0xfffc) != 0) {
580: dt = &env->gdt;
581: index = new_ldt & ~7;
582: if ((index + 7) > dt->limit)
583: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
584: ptr = dt->base + index;
585: e1 = ldl_kernel(ptr);
586: e2 = ldl_kernel(ptr + 4);
587: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
588: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
589: if (!(e2 & DESC_P_MASK))
590: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
591: load_seg_cache_raw_dt(&env->ldt, e1, e2);
592: }
593:
594: /* load the segments */
595: if (!(new_eflags & VM_MASK)) {
596: tss_load_seg(R_CS, new_segs[R_CS]);
597: tss_load_seg(R_SS, new_segs[R_SS]);
598: tss_load_seg(R_ES, new_segs[R_ES]);
599: tss_load_seg(R_DS, new_segs[R_DS]);
600: tss_load_seg(R_FS, new_segs[R_FS]);
601: tss_load_seg(R_GS, new_segs[R_GS]);
602: }
603:
604: /* check that EIP is in the CS segment limits */
605: if (new_eip > env->segs[R_CS].limit) {
606: /* XXX: different exception if CALL ? */
607: raise_exception_err(EXCP0D_GPF, 0);
608: }
609:
610: #ifndef CONFIG_USER_ONLY
611: /* reset local breakpoints */
612: if (env->dr[7] & 0x55) {
613: for (i = 0; i < 4; i++) {
614: if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
615: hw_breakpoint_remove(env, i);
616: }
617: env->dr[7] &= ~0x55;
618: }
619: #endif
620: }
621:
622: /* check if Port I/O is allowed in TSS */
623: static inline void check_io(int addr, int size)
624: {
625: int io_offset, val, mask;
626:
627: /* TSS must be a valid 32 bit one */
628: if (!(env->tr.flags & DESC_P_MASK) ||
629: ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
630: env->tr.limit < 103)
631: goto fail;
632: io_offset = lduw_kernel(env->tr.base + 0x66);
633: io_offset += (addr >> 3);
634: /* Note: the check needs two bytes */
635: if ((io_offset + 1) > env->tr.limit)
636: goto fail;
637: val = lduw_kernel(env->tr.base + io_offset);
638: val >>= (addr & 7);
639: mask = (1 << size) - 1;
640: /* all bits must be zero to allow the I/O */
641: if ((val & mask) != 0) {
642: fail:
643: raise_exception_err(EXCP0D_GPF, 0);
644: }
645: }
646:
647: void helper_check_iob(uint32_t t0)
648: {
649: check_io(t0, 1);
650: }
651:
652: void helper_check_iow(uint32_t t0)
653: {
654: check_io(t0, 2);
655: }
656:
657: void helper_check_iol(uint32_t t0)
658: {
659: check_io(t0, 4);
660: }
661:
662: void helper_outb(uint32_t port, uint32_t data)
663: {
1.1.1.4 root 664: cpu_outb(port, data & 0xff);
1.1 root 665: }
666:
667: target_ulong helper_inb(uint32_t port)
668: {
1.1.1.4 root 669: return cpu_inb(port);
1.1 root 670: }
671:
672: void helper_outw(uint32_t port, uint32_t data)
673: {
1.1.1.4 root 674: cpu_outw(port, data & 0xffff);
1.1 root 675: }
676:
677: target_ulong helper_inw(uint32_t port)
678: {
1.1.1.4 root 679: return cpu_inw(port);
1.1 root 680: }
681:
682: void helper_outl(uint32_t port, uint32_t data)
683: {
1.1.1.4 root 684: cpu_outl(port, data);
1.1 root 685: }
686:
687: target_ulong helper_inl(uint32_t port)
688: {
1.1.1.4 root 689: return cpu_inl(port);
1.1 root 690: }
691:
692: static inline unsigned int get_sp_mask(unsigned int e2)
693: {
694: if (e2 & DESC_B_MASK)
695: return 0xffffffff;
696: else
697: return 0xffff;
698: }
699:
1.1.1.3 root 700: static int exeption_has_error_code(int intno)
701: {
702: switch(intno) {
703: case 8:
704: case 10:
705: case 11:
706: case 12:
707: case 13:
708: case 14:
709: case 17:
710: return 1;
711: }
712: return 0;
713: }
714:
1.1 root 715: #ifdef TARGET_X86_64
716: #define SET_ESP(val, sp_mask)\
717: do {\
718: if ((sp_mask) == 0xffff)\
719: ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
720: else if ((sp_mask) == 0xffffffffLL)\
721: ESP = (uint32_t)(val);\
722: else\
723: ESP = (val);\
724: } while (0)
725: #else
726: #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
727: #endif
728:
729: /* in 64-bit machines, this can overflow. So this segment addition macro
730: * can be used to trim the value to 32-bit whenever needed */
731: #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
732:
733: /* XXX: add a is_user flag to have proper security support */
734: #define PUSHW(ssp, sp, sp_mask, val)\
735: {\
736: sp -= 2;\
737: stw_kernel((ssp) + (sp & (sp_mask)), (val));\
738: }
739:
740: #define PUSHL(ssp, sp, sp_mask, val)\
741: {\
742: sp -= 4;\
743: stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
744: }
745:
746: #define POPW(ssp, sp, sp_mask, val)\
747: {\
748: val = lduw_kernel((ssp) + (sp & (sp_mask)));\
749: sp += 2;\
750: }
751:
752: #define POPL(ssp, sp, sp_mask, val)\
753: {\
754: val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
755: sp += 4;\
756: }
757:
758: /* protected mode interrupt */
759: static void do_interrupt_protected(int intno, int is_int, int error_code,
760: unsigned int next_eip, int is_hw)
761: {
762: SegmentCache *dt;
763: target_ulong ptr, ssp;
764: int type, dpl, selector, ss_dpl, cpl;
765: int has_error_code, new_stack, shift;
766: uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
767: uint32_t old_eip, sp_mask;
768:
769: has_error_code = 0;
1.1.1.3 root 770: if (!is_int && !is_hw)
771: has_error_code = exeption_has_error_code(intno);
1.1 root 772: if (is_int)
773: old_eip = next_eip;
774: else
775: old_eip = env->eip;
776:
777: dt = &env->idt;
778: if (intno * 8 + 7 > dt->limit)
779: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
780: ptr = dt->base + intno * 8;
781: e1 = ldl_kernel(ptr);
782: e2 = ldl_kernel(ptr + 4);
783: /* check gate type */
784: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
785: switch(type) {
786: case 5: /* task gate */
787: /* must do that check here to return the correct error code */
788: if (!(e2 & DESC_P_MASK))
789: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
790: switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
791: if (has_error_code) {
792: int type;
793: uint32_t mask;
794: /* push the error code */
795: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
796: shift = type >> 3;
797: if (env->segs[R_SS].flags & DESC_B_MASK)
798: mask = 0xffffffff;
799: else
800: mask = 0xffff;
801: esp = (ESP - (2 << shift)) & mask;
802: ssp = env->segs[R_SS].base + esp;
803: if (shift)
804: stl_kernel(ssp, error_code);
805: else
806: stw_kernel(ssp, error_code);
807: SET_ESP(esp, mask);
808: }
809: return;
810: case 6: /* 286 interrupt gate */
811: case 7: /* 286 trap gate */
812: case 14: /* 386 interrupt gate */
813: case 15: /* 386 trap gate */
814: break;
815: default:
816: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
817: break;
818: }
819: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
820: cpl = env->hflags & HF_CPL_MASK;
821: /* check privilege if software int */
822: if (is_int && dpl < cpl)
823: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
824: /* check valid bit */
825: if (!(e2 & DESC_P_MASK))
826: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
827: selector = e1 >> 16;
828: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
829: if ((selector & 0xfffc) == 0)
830: raise_exception_err(EXCP0D_GPF, 0);
831:
832: if (load_segment(&e1, &e2, selector) != 0)
833: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
834: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
835: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
836: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
837: if (dpl > cpl)
838: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
839: if (!(e2 & DESC_P_MASK))
840: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
841: if (!(e2 & DESC_C_MASK) && dpl < cpl) {
842: /* to inner privilege */
843: get_ss_esp_from_tss(&ss, &esp, dpl);
844: if ((ss & 0xfffc) == 0)
845: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
846: if ((ss & 3) != dpl)
847: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
848: if (load_segment(&ss_e1, &ss_e2, ss) != 0)
849: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
850: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
851: if (ss_dpl != dpl)
852: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
853: if (!(ss_e2 & DESC_S_MASK) ||
854: (ss_e2 & DESC_CS_MASK) ||
855: !(ss_e2 & DESC_W_MASK))
856: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
857: if (!(ss_e2 & DESC_P_MASK))
858: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
859: new_stack = 1;
860: sp_mask = get_sp_mask(ss_e2);
861: ssp = get_seg_base(ss_e1, ss_e2);
862: } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
863: /* to same privilege */
864: if (env->eflags & VM_MASK)
865: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
866: new_stack = 0;
867: sp_mask = get_sp_mask(env->segs[R_SS].flags);
868: ssp = env->segs[R_SS].base;
869: esp = ESP;
870: dpl = cpl;
871: } else {
872: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
873: new_stack = 0; /* avoid warning */
874: sp_mask = 0; /* avoid warning */
875: ssp = 0; /* avoid warning */
876: esp = 0; /* avoid warning */
877: }
878:
879: shift = type >> 3;
880:
881: #if 0
882: /* XXX: check that enough room is available */
883: push_size = 6 + (new_stack << 2) + (has_error_code << 1);
884: if (env->eflags & VM_MASK)
885: push_size += 8;
886: push_size <<= shift;
887: #endif
888: if (shift == 1) {
889: if (new_stack) {
890: if (env->eflags & VM_MASK) {
891: PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
892: PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
893: PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
894: PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
895: }
896: PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
897: PUSHL(ssp, esp, sp_mask, ESP);
898: }
899: PUSHL(ssp, esp, sp_mask, compute_eflags());
900: PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
901: PUSHL(ssp, esp, sp_mask, old_eip);
902: if (has_error_code) {
903: PUSHL(ssp, esp, sp_mask, error_code);
904: }
905: } else {
906: if (new_stack) {
907: if (env->eflags & VM_MASK) {
908: PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
909: PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
910: PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
911: PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
912: }
913: PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
914: PUSHW(ssp, esp, sp_mask, ESP);
915: }
916: PUSHW(ssp, esp, sp_mask, compute_eflags());
917: PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
918: PUSHW(ssp, esp, sp_mask, old_eip);
919: if (has_error_code) {
920: PUSHW(ssp, esp, sp_mask, error_code);
921: }
922: }
923:
924: if (new_stack) {
925: if (env->eflags & VM_MASK) {
926: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
927: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
928: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
929: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
930: }
931: ss = (ss & ~3) | dpl;
932: cpu_x86_load_seg_cache(env, R_SS, ss,
933: ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
934: }
935: SET_ESP(esp, sp_mask);
936:
937: selector = (selector & ~3) | dpl;
938: cpu_x86_load_seg_cache(env, R_CS, selector,
939: get_seg_base(e1, e2),
940: get_seg_limit(e1, e2),
941: e2);
942: cpu_x86_set_cpl(env, dpl);
943: env->eip = offset;
944:
945: /* interrupt gate clear IF mask */
946: if ((type & 1) == 0) {
947: env->eflags &= ~IF_MASK;
948: }
949: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
950: }
951:
952: #ifdef TARGET_X86_64
953:
954: #define PUSHQ(sp, val)\
955: {\
956: sp -= 8;\
957: stq_kernel(sp, (val));\
958: }
959:
960: #define POPQ(sp, val)\
961: {\
962: val = ldq_kernel(sp);\
963: sp += 8;\
964: }
965:
966: static inline target_ulong get_rsp_from_tss(int level)
967: {
968: int index;
969:
970: #if 0
971: printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
972: env->tr.base, env->tr.limit);
973: #endif
974:
975: if (!(env->tr.flags & DESC_P_MASK))
976: cpu_abort(env, "invalid tss");
977: index = 8 * level + 4;
978: if ((index + 7) > env->tr.limit)
979: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
980: return ldq_kernel(env->tr.base + index);
981: }
982:
983: /* 64 bit interrupt */
984: static void do_interrupt64(int intno, int is_int, int error_code,
985: target_ulong next_eip, int is_hw)
986: {
987: SegmentCache *dt;
988: target_ulong ptr;
989: int type, dpl, selector, cpl, ist;
990: int has_error_code, new_stack;
991: uint32_t e1, e2, e3, ss;
992: target_ulong old_eip, esp, offset;
993:
994: has_error_code = 0;
1.1.1.3 root 995: if (!is_int && !is_hw)
996: has_error_code = exeption_has_error_code(intno);
1.1 root 997: if (is_int)
998: old_eip = next_eip;
999: else
1000: old_eip = env->eip;
1001:
1002: dt = &env->idt;
1003: if (intno * 16 + 15 > dt->limit)
1004: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1005: ptr = dt->base + intno * 16;
1006: e1 = ldl_kernel(ptr);
1007: e2 = ldl_kernel(ptr + 4);
1008: e3 = ldl_kernel(ptr + 8);
1009: /* check gate type */
1010: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1011: switch(type) {
1012: case 14: /* 386 interrupt gate */
1013: case 15: /* 386 trap gate */
1014: break;
1015: default:
1016: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1017: break;
1018: }
1019: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1020: cpl = env->hflags & HF_CPL_MASK;
1021: /* check privilege if software int */
1022: if (is_int && dpl < cpl)
1023: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1024: /* check valid bit */
1025: if (!(e2 & DESC_P_MASK))
1026: raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
1027: selector = e1 >> 16;
1028: offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1029: ist = e2 & 7;
1030: if ((selector & 0xfffc) == 0)
1031: raise_exception_err(EXCP0D_GPF, 0);
1032:
1033: if (load_segment(&e1, &e2, selector) != 0)
1034: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1035: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1036: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1037: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1038: if (dpl > cpl)
1039: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1040: if (!(e2 & DESC_P_MASK))
1041: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1042: if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
1043: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1044: if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
1045: /* to inner privilege */
1046: if (ist != 0)
1047: esp = get_rsp_from_tss(ist + 3);
1048: else
1049: esp = get_rsp_from_tss(dpl);
1050: esp &= ~0xfLL; /* align stack */
1051: ss = 0;
1052: new_stack = 1;
1053: } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
1054: /* to same privilege */
1055: if (env->eflags & VM_MASK)
1056: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1057: new_stack = 0;
1058: if (ist != 0)
1059: esp = get_rsp_from_tss(ist + 3);
1060: else
1061: esp = ESP;
1062: esp &= ~0xfLL; /* align stack */
1063: dpl = cpl;
1064: } else {
1065: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1066: new_stack = 0; /* avoid warning */
1067: esp = 0; /* avoid warning */
1068: }
1069:
1070: PUSHQ(esp, env->segs[R_SS].selector);
1071: PUSHQ(esp, ESP);
1072: PUSHQ(esp, compute_eflags());
1073: PUSHQ(esp, env->segs[R_CS].selector);
1074: PUSHQ(esp, old_eip);
1075: if (has_error_code) {
1076: PUSHQ(esp, error_code);
1077: }
1078:
1079: if (new_stack) {
1080: ss = 0 | dpl;
1081: cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
1082: }
1083: ESP = esp;
1084:
1085: selector = (selector & ~3) | dpl;
1086: cpu_x86_load_seg_cache(env, R_CS, selector,
1087: get_seg_base(e1, e2),
1088: get_seg_limit(e1, e2),
1089: e2);
1090: cpu_x86_set_cpl(env, dpl);
1091: env->eip = offset;
1092:
1093: /* interrupt gate clear IF mask */
1094: if ((type & 1) == 0) {
1095: env->eflags &= ~IF_MASK;
1096: }
1097: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
1098: }
1099: #endif
1100:
1101: #ifdef TARGET_X86_64
1102: #if defined(CONFIG_USER_ONLY)
1103: void helper_syscall(int next_eip_addend)
1104: {
1105: env->exception_index = EXCP_SYSCALL;
1106: env->exception_next_eip = env->eip + next_eip_addend;
1.1.1.7 root 1107: cpu_loop_exit(env);
1.1 root 1108: }
1109: #else
1110: void helper_syscall(int next_eip_addend)
1111: {
1112: int selector;
1113:
1114: if (!(env->efer & MSR_EFER_SCE)) {
1115: raise_exception_err(EXCP06_ILLOP, 0);
1116: }
1117: selector = (env->star >> 32) & 0xffff;
1118: if (env->hflags & HF_LMA_MASK) {
1119: int code64;
1120:
1121: ECX = env->eip + next_eip_addend;
1122: env->regs[11] = compute_eflags();
1123:
1124: code64 = env->hflags & HF_CS64_MASK;
1125:
1126: cpu_x86_set_cpl(env, 0);
1127: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1128: 0, 0xffffffff,
1129: DESC_G_MASK | DESC_P_MASK |
1130: DESC_S_MASK |
1131: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1132: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1133: 0, 0xffffffff,
1134: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1135: DESC_S_MASK |
1136: DESC_W_MASK | DESC_A_MASK);
1137: env->eflags &= ~env->fmask;
1138: load_eflags(env->eflags, 0);
1139: if (code64)
1140: env->eip = env->lstar;
1141: else
1142: env->eip = env->cstar;
1143: } else {
1144: ECX = (uint32_t)(env->eip + next_eip_addend);
1145:
1146: cpu_x86_set_cpl(env, 0);
1147: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1148: 0, 0xffffffff,
1149: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1150: DESC_S_MASK |
1151: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1152: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1153: 0, 0xffffffff,
1154: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1155: DESC_S_MASK |
1156: DESC_W_MASK | DESC_A_MASK);
1157: env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1158: env->eip = (uint32_t)env->star;
1159: }
1160: }
1161: #endif
1162: #endif
1163:
1164: #ifdef TARGET_X86_64
1165: void helper_sysret(int dflag)
1166: {
1167: int cpl, selector;
1168:
1169: if (!(env->efer & MSR_EFER_SCE)) {
1170: raise_exception_err(EXCP06_ILLOP, 0);
1171: }
1172: cpl = env->hflags & HF_CPL_MASK;
1173: if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1174: raise_exception_err(EXCP0D_GPF, 0);
1175: }
1176: selector = (env->star >> 48) & 0xffff;
1177: if (env->hflags & HF_LMA_MASK) {
1178: if (dflag == 2) {
1179: cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1180: 0, 0xffffffff,
1181: DESC_G_MASK | DESC_P_MASK |
1182: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1183: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1184: DESC_L_MASK);
1185: env->eip = ECX;
1186: } else {
1187: cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1188: 0, 0xffffffff,
1189: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1190: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1191: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1192: env->eip = (uint32_t)ECX;
1193: }
1194: cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1195: 0, 0xffffffff,
1196: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1197: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1198: DESC_W_MASK | DESC_A_MASK);
1199: load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1200: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1201: cpu_x86_set_cpl(env, 3);
1202: } else {
1203: cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1204: 0, 0xffffffff,
1205: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1206: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1207: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1208: env->eip = (uint32_t)ECX;
1209: cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1210: 0, 0xffffffff,
1211: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1212: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1213: DESC_W_MASK | DESC_A_MASK);
1214: env->eflags |= IF_MASK;
1215: cpu_x86_set_cpl(env, 3);
1216: }
1217: }
1218: #endif
1219:
1220: /* real mode interrupt */
1221: static void do_interrupt_real(int intno, int is_int, int error_code,
1222: unsigned int next_eip)
1223: {
1224: SegmentCache *dt;
1225: target_ulong ptr, ssp;
1226: int selector;
1227: uint32_t offset, esp;
1228: uint32_t old_cs, old_eip;
1229:
1230: /* real mode (simpler !) */
1231: dt = &env->idt;
1232: if (intno * 4 + 3 > dt->limit)
1233: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1234: ptr = dt->base + intno * 4;
1235: offset = lduw_kernel(ptr);
1236: selector = lduw_kernel(ptr + 2);
1237: esp = ESP;
1238: ssp = env->segs[R_SS].base;
1239: if (is_int)
1240: old_eip = next_eip;
1241: else
1242: old_eip = env->eip;
1243: old_cs = env->segs[R_CS].selector;
1244: /* XXX: use SS segment size ? */
1245: PUSHW(ssp, esp, 0xffff, compute_eflags());
1246: PUSHW(ssp, esp, 0xffff, old_cs);
1247: PUSHW(ssp, esp, 0xffff, old_eip);
1248:
1249: /* update processor state */
1250: ESP = (ESP & ~0xffff) | (esp & 0xffff);
1251: env->eip = offset;
1252: env->segs[R_CS].selector = selector;
1253: env->segs[R_CS].base = (selector << 4);
1254: env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1255: }
1256:
1.1.1.7 root 1257: #if defined(CONFIG_USER_ONLY)
1.1 root 1258: /* fake user mode interrupt */
1.1.1.7 root 1259: static void do_interrupt_user(int intno, int is_int, int error_code,
1260: target_ulong next_eip)
1.1 root 1261: {
1262: SegmentCache *dt;
1263: target_ulong ptr;
1264: int dpl, cpl, shift;
1265: uint32_t e2;
1266:
1267: dt = &env->idt;
1268: if (env->hflags & HF_LMA_MASK) {
1269: shift = 4;
1270: } else {
1271: shift = 3;
1272: }
1273: ptr = dt->base + (intno << shift);
1274: e2 = ldl_kernel(ptr + 4);
1275:
1276: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1277: cpl = env->hflags & HF_CPL_MASK;
1278: /* check privilege if software int */
1279: if (is_int && dpl < cpl)
1280: raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1281:
1282: /* Since we emulate only user space, we cannot do more than
1283: exiting the emulation with the suitable exception and error
1284: code */
1285: if (is_int)
1286: EIP = next_eip;
1287: }
1288:
1.1.1.7 root 1289: #else
1290:
1.1.1.3 root 1291: static void handle_even_inj(int intno, int is_int, int error_code,
1292: int is_hw, int rm)
1293: {
1294: uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1295: if (!(event_inj & SVM_EVTINJ_VALID)) {
1296: int type;
1297: if (is_int)
1298: type = SVM_EVTINJ_TYPE_SOFT;
1299: else
1300: type = SVM_EVTINJ_TYPE_EXEPT;
1301: event_inj = intno | type | SVM_EVTINJ_VALID;
1302: if (!rm && exeption_has_error_code(intno)) {
1303: event_inj |= SVM_EVTINJ_VALID_ERR;
1304: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
1305: }
1306: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
1307: }
1308: }
1309: #endif
1310:
1.1 root 1311: /*
1312: * Begin execution of an interruption. is_int is TRUE if coming from
1313: * the int instruction. next_eip is the EIP value AFTER the interrupt
1314: * instruction. It is only relevant if is_int is TRUE.
1315: */
1.1.1.7 root 1316: static void do_interrupt_all(int intno, int is_int, int error_code,
1317: target_ulong next_eip, int is_hw)
1.1 root 1318: {
1319: if (qemu_loglevel_mask(CPU_LOG_INT)) {
1320: if ((env->cr[0] & CR0_PE_MASK)) {
1321: static int count;
1322: qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1323: count, intno, error_code, is_int,
1324: env->hflags & HF_CPL_MASK,
1325: env->segs[R_CS].selector, EIP,
1326: (int)env->segs[R_CS].base + EIP,
1327: env->segs[R_SS].selector, ESP);
1328: if (intno == 0x0e) {
1329: qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
1330: } else {
1331: qemu_log(" EAX=" TARGET_FMT_lx, EAX);
1332: }
1333: qemu_log("\n");
1334: log_cpu_state(env, X86_DUMP_CCOP);
1335: #if 0
1336: {
1337: int i;
1.1.1.5 root 1338: target_ulong ptr;
1.1 root 1339: qemu_log(" code=");
1340: ptr = env->segs[R_CS].base + env->eip;
1341: for(i = 0; i < 16; i++) {
1342: qemu_log(" %02x", ldub(ptr + i));
1343: }
1344: qemu_log("\n");
1345: }
1346: #endif
1347: count++;
1348: }
1349: }
1350: if (env->cr[0] & CR0_PE_MASK) {
1.1.1.3 root 1351: #if !defined(CONFIG_USER_ONLY)
1352: if (env->hflags & HF_SVMI_MASK)
1353: handle_even_inj(intno, is_int, error_code, is_hw, 0);
1354: #endif
1.1 root 1355: #ifdef TARGET_X86_64
1356: if (env->hflags & HF_LMA_MASK) {
1357: do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1358: } else
1359: #endif
1360: {
1361: do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1362: }
1363: } else {
1.1.1.3 root 1364: #if !defined(CONFIG_USER_ONLY)
1365: if (env->hflags & HF_SVMI_MASK)
1366: handle_even_inj(intno, is_int, error_code, is_hw, 1);
1367: #endif
1.1 root 1368: do_interrupt_real(intno, is_int, error_code, next_eip);
1369: }
1.1.1.3 root 1370:
1371: #if !defined(CONFIG_USER_ONLY)
1372: if (env->hflags & HF_SVMI_MASK) {
1373: uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1374: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
1375: }
1376: #endif
1.1 root 1377: }
1378:
1.1.1.9 ! root 1379: void do_interrupt(CPUX86State *env1)
1.1.1.7 root 1380: {
1.1.1.9 ! root 1381: CPUX86State *saved_env;
1.1.1.7 root 1382:
1383: saved_env = env;
1384: env = env1;
1385: #if defined(CONFIG_USER_ONLY)
1386: /* if user mode only, we simulate a fake exception
1387: which will be handled outside the cpu execution
1388: loop */
1389: do_interrupt_user(env->exception_index,
1390: env->exception_is_int,
1391: env->error_code,
1392: env->exception_next_eip);
1393: /* successfully delivered */
1394: env->old_exception = -1;
1395: #else
1396: /* simulate a real cpu exception. On i386, it can
1397: trigger new exceptions, but we do not handle
1398: double or triple faults yet. */
1399: do_interrupt_all(env->exception_index,
1400: env->exception_is_int,
1401: env->error_code,
1402: env->exception_next_eip, 0);
1403: /* successfully delivered */
1404: env->old_exception = -1;
1405: #endif
1406: env = saved_env;
1407: }
1408:
1.1.1.9 ! root 1409: void do_interrupt_x86_hardirq(CPUX86State *env1, int intno, int is_hw)
1.1.1.7 root 1410: {
1.1.1.9 ! root 1411: CPUX86State *saved_env;
1.1.1.7 root 1412:
1413: saved_env = env;
1414: env = env1;
1415: do_interrupt_all(intno, 0, 0, 0, is_hw);
1416: env = saved_env;
1417: }
1418:
1.1 root 1419: /* This should come from sysemu.h - if we could include it here... */
1420: void qemu_system_reset_request(void);
1421:
1422: /*
1423: * Check nested exceptions and change to double or triple fault if
1424: * needed. It should only be called, if this is not an interrupt.
1425: * Returns the new exception number.
1426: */
1427: static int check_exception(int intno, int *error_code)
1428: {
1429: int first_contributory = env->old_exception == 0 ||
1430: (env->old_exception >= 10 &&
1431: env->old_exception <= 13);
1432: int second_contributory = intno == 0 ||
1433: (intno >= 10 && intno <= 13);
1434:
1435: qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
1436: env->old_exception, intno);
1437:
1438: #if !defined(CONFIG_USER_ONLY)
1439: if (env->old_exception == EXCP08_DBLE) {
1440: if (env->hflags & HF_SVMI_MASK)
1441: helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
1442:
1443: qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
1444:
1445: qemu_system_reset_request();
1446: return EXCP_HLT;
1447: }
1448: #endif
1449:
1450: if ((first_contributory && second_contributory)
1451: || (env->old_exception == EXCP0E_PAGE &&
1452: (second_contributory || (intno == EXCP0E_PAGE)))) {
1453: intno = EXCP08_DBLE;
1454: *error_code = 0;
1455: }
1456:
1457: if (second_contributory || (intno == EXCP0E_PAGE) ||
1458: (intno == EXCP08_DBLE))
1459: env->old_exception = intno;
1460:
1461: return intno;
1462: }
1463:
1464: /*
1465: * Signal an interruption. It is executed in the main CPU loop.
1466: * is_int is TRUE if coming from the int instruction. next_eip is the
1467: * EIP value AFTER the interrupt instruction. It is only relevant if
1468: * is_int is TRUE.
1469: */
1470: static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
1471: int next_eip_addend)
1472: {
1473: if (!is_int) {
1474: helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1475: intno = check_exception(intno, &error_code);
1476: } else {
1477: helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
1478: }
1479:
1480: env->exception_index = intno;
1481: env->error_code = error_code;
1482: env->exception_is_int = is_int;
1483: env->exception_next_eip = env->eip + next_eip_addend;
1.1.1.7 root 1484: cpu_loop_exit(env);
1.1 root 1485: }
1486:
1487: /* shortcuts to generate exceptions */
1488:
1.1.1.8 root 1489: static void QEMU_NORETURN raise_exception_err(int exception_index,
1490: int error_code)
1.1 root 1491: {
1492: raise_interrupt(exception_index, 0, error_code, 0);
1493: }
1494:
1.1.1.9 ! root 1495: void raise_exception_err_env(CPUX86State *nenv, int exception_index,
1.1.1.8 root 1496: int error_code)
1497: {
1498: env = nenv;
1499: raise_interrupt(exception_index, 0, error_code, 0);
1500: }
1501:
1502: static void QEMU_NORETURN raise_exception(int exception_index)
1.1 root 1503: {
1504: raise_interrupt(exception_index, 0, 0, 0);
1505: }
1506:
1.1.1.9 ! root 1507: void raise_exception_env(int exception_index, CPUX86State *nenv)
1.1.1.5 root 1508: {
1509: env = nenv;
1510: raise_exception(exception_index);
1511: }
1.1 root 1512: /* SMM support */
1513:
1514: #if defined(CONFIG_USER_ONLY)
1515:
1.1.1.9 ! root 1516: void do_smm_enter(CPUX86State *env1)
1.1 root 1517: {
1518: }
1519:
1520: void helper_rsm(void)
1521: {
1522: }
1523:
1524: #else
1525:
1526: #ifdef TARGET_X86_64
1527: #define SMM_REVISION_ID 0x00020064
1528: #else
1529: #define SMM_REVISION_ID 0x00020000
1530: #endif
1531:
1.1.1.9 ! root 1532: void do_smm_enter(CPUX86State *env1)
1.1 root 1533: {
1534: target_ulong sm_state;
1535: SegmentCache *dt;
1536: int i, offset;
1.1.1.9 ! root 1537: CPUX86State *saved_env;
1.1.1.7 root 1538:
1539: saved_env = env;
1540: env = env1;
1.1 root 1541:
1542: qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
1543: log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
1544:
1545: env->hflags |= HF_SMM_MASK;
1546: cpu_smm_update(env);
1547:
1548: sm_state = env->smbase + 0x8000;
1549:
1550: #ifdef TARGET_X86_64
1551: for(i = 0; i < 6; i++) {
1552: dt = &env->segs[i];
1553: offset = 0x7e00 + i * 16;
1554: stw_phys(sm_state + offset, dt->selector);
1555: stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1556: stl_phys(sm_state + offset + 4, dt->limit);
1557: stq_phys(sm_state + offset + 8, dt->base);
1558: }
1559:
1560: stq_phys(sm_state + 0x7e68, env->gdt.base);
1561: stl_phys(sm_state + 0x7e64, env->gdt.limit);
1562:
1563: stw_phys(sm_state + 0x7e70, env->ldt.selector);
1564: stq_phys(sm_state + 0x7e78, env->ldt.base);
1565: stl_phys(sm_state + 0x7e74, env->ldt.limit);
1566: stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1567:
1568: stq_phys(sm_state + 0x7e88, env->idt.base);
1569: stl_phys(sm_state + 0x7e84, env->idt.limit);
1570:
1571: stw_phys(sm_state + 0x7e90, env->tr.selector);
1572: stq_phys(sm_state + 0x7e98, env->tr.base);
1573: stl_phys(sm_state + 0x7e94, env->tr.limit);
1574: stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1575:
1576: stq_phys(sm_state + 0x7ed0, env->efer);
1577:
1578: stq_phys(sm_state + 0x7ff8, EAX);
1579: stq_phys(sm_state + 0x7ff0, ECX);
1580: stq_phys(sm_state + 0x7fe8, EDX);
1581: stq_phys(sm_state + 0x7fe0, EBX);
1582: stq_phys(sm_state + 0x7fd8, ESP);
1583: stq_phys(sm_state + 0x7fd0, EBP);
1584: stq_phys(sm_state + 0x7fc8, ESI);
1585: stq_phys(sm_state + 0x7fc0, EDI);
1586: for(i = 8; i < 16; i++)
1587: stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1588: stq_phys(sm_state + 0x7f78, env->eip);
1589: stl_phys(sm_state + 0x7f70, compute_eflags());
1590: stl_phys(sm_state + 0x7f68, env->dr[6]);
1591: stl_phys(sm_state + 0x7f60, env->dr[7]);
1592:
1593: stl_phys(sm_state + 0x7f48, env->cr[4]);
1594: stl_phys(sm_state + 0x7f50, env->cr[3]);
1595: stl_phys(sm_state + 0x7f58, env->cr[0]);
1596:
1597: stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1598: stl_phys(sm_state + 0x7f00, env->smbase);
1599: #else
1600: stl_phys(sm_state + 0x7ffc, env->cr[0]);
1601: stl_phys(sm_state + 0x7ff8, env->cr[3]);
1602: stl_phys(sm_state + 0x7ff4, compute_eflags());
1603: stl_phys(sm_state + 0x7ff0, env->eip);
1604: stl_phys(sm_state + 0x7fec, EDI);
1605: stl_phys(sm_state + 0x7fe8, ESI);
1606: stl_phys(sm_state + 0x7fe4, EBP);
1607: stl_phys(sm_state + 0x7fe0, ESP);
1608: stl_phys(sm_state + 0x7fdc, EBX);
1609: stl_phys(sm_state + 0x7fd8, EDX);
1610: stl_phys(sm_state + 0x7fd4, ECX);
1611: stl_phys(sm_state + 0x7fd0, EAX);
1612: stl_phys(sm_state + 0x7fcc, env->dr[6]);
1613: stl_phys(sm_state + 0x7fc8, env->dr[7]);
1614:
1615: stl_phys(sm_state + 0x7fc4, env->tr.selector);
1616: stl_phys(sm_state + 0x7f64, env->tr.base);
1617: stl_phys(sm_state + 0x7f60, env->tr.limit);
1618: stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1619:
1620: stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1621: stl_phys(sm_state + 0x7f80, env->ldt.base);
1622: stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1623: stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1624:
1625: stl_phys(sm_state + 0x7f74, env->gdt.base);
1626: stl_phys(sm_state + 0x7f70, env->gdt.limit);
1627:
1628: stl_phys(sm_state + 0x7f58, env->idt.base);
1629: stl_phys(sm_state + 0x7f54, env->idt.limit);
1630:
1631: for(i = 0; i < 6; i++) {
1632: dt = &env->segs[i];
1633: if (i < 3)
1634: offset = 0x7f84 + i * 12;
1635: else
1636: offset = 0x7f2c + (i - 3) * 12;
1637: stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1638: stl_phys(sm_state + offset + 8, dt->base);
1639: stl_phys(sm_state + offset + 4, dt->limit);
1640: stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1641: }
1642: stl_phys(sm_state + 0x7f14, env->cr[4]);
1643:
1644: stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1645: stl_phys(sm_state + 0x7ef8, env->smbase);
1646: #endif
1647: /* init SMM cpu state */
1648:
1649: #ifdef TARGET_X86_64
1650: cpu_load_efer(env, 0);
1651: #endif
1652: load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1653: env->eip = 0x00008000;
1654: cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1655: 0xffffffff, 0);
1656: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1657: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1658: cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1659: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1660: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1661:
1662: cpu_x86_update_cr0(env,
1663: env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1664: cpu_x86_update_cr4(env, 0);
1665: env->dr[7] = 0x00000400;
1666: CC_OP = CC_OP_EFLAGS;
1.1.1.7 root 1667: env = saved_env;
1.1 root 1668: }
1669:
1670: void helper_rsm(void)
1671: {
1672: target_ulong sm_state;
1673: int i, offset;
1674: uint32_t val;
1675:
1676: sm_state = env->smbase + 0x8000;
1677: #ifdef TARGET_X86_64
1678: cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
1679:
1680: for(i = 0; i < 6; i++) {
1681: offset = 0x7e00 + i * 16;
1682: cpu_x86_load_seg_cache(env, i,
1683: lduw_phys(sm_state + offset),
1684: ldq_phys(sm_state + offset + 8),
1685: ldl_phys(sm_state + offset + 4),
1686: (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1687: }
1688:
1689: env->gdt.base = ldq_phys(sm_state + 0x7e68);
1690: env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1691:
1692: env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1693: env->ldt.base = ldq_phys(sm_state + 0x7e78);
1694: env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1695: env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1696:
1697: env->idt.base = ldq_phys(sm_state + 0x7e88);
1698: env->idt.limit = ldl_phys(sm_state + 0x7e84);
1699:
1700: env->tr.selector = lduw_phys(sm_state + 0x7e90);
1701: env->tr.base = ldq_phys(sm_state + 0x7e98);
1702: env->tr.limit = ldl_phys(sm_state + 0x7e94);
1703: env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1704:
1705: EAX = ldq_phys(sm_state + 0x7ff8);
1706: ECX = ldq_phys(sm_state + 0x7ff0);
1707: EDX = ldq_phys(sm_state + 0x7fe8);
1708: EBX = ldq_phys(sm_state + 0x7fe0);
1709: ESP = ldq_phys(sm_state + 0x7fd8);
1710: EBP = ldq_phys(sm_state + 0x7fd0);
1711: ESI = ldq_phys(sm_state + 0x7fc8);
1712: EDI = ldq_phys(sm_state + 0x7fc0);
1713: for(i = 8; i < 16; i++)
1714: env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1715: env->eip = ldq_phys(sm_state + 0x7f78);
1716: load_eflags(ldl_phys(sm_state + 0x7f70),
1717: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1718: env->dr[6] = ldl_phys(sm_state + 0x7f68);
1719: env->dr[7] = ldl_phys(sm_state + 0x7f60);
1720:
1721: cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1722: cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1723: cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1724:
1725: val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1726: if (val & 0x20000) {
1727: env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1728: }
1729: #else
1730: cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1731: cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1732: load_eflags(ldl_phys(sm_state + 0x7ff4),
1733: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1734: env->eip = ldl_phys(sm_state + 0x7ff0);
1735: EDI = ldl_phys(sm_state + 0x7fec);
1736: ESI = ldl_phys(sm_state + 0x7fe8);
1737: EBP = ldl_phys(sm_state + 0x7fe4);
1738: ESP = ldl_phys(sm_state + 0x7fe0);
1739: EBX = ldl_phys(sm_state + 0x7fdc);
1740: EDX = ldl_phys(sm_state + 0x7fd8);
1741: ECX = ldl_phys(sm_state + 0x7fd4);
1742: EAX = ldl_phys(sm_state + 0x7fd0);
1743: env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1744: env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1745:
1746: env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1747: env->tr.base = ldl_phys(sm_state + 0x7f64);
1748: env->tr.limit = ldl_phys(sm_state + 0x7f60);
1749: env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1750:
1751: env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1752: env->ldt.base = ldl_phys(sm_state + 0x7f80);
1753: env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1754: env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1755:
1756: env->gdt.base = ldl_phys(sm_state + 0x7f74);
1757: env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1758:
1759: env->idt.base = ldl_phys(sm_state + 0x7f58);
1760: env->idt.limit = ldl_phys(sm_state + 0x7f54);
1761:
1762: for(i = 0; i < 6; i++) {
1763: if (i < 3)
1764: offset = 0x7f84 + i * 12;
1765: else
1766: offset = 0x7f2c + (i - 3) * 12;
1767: cpu_x86_load_seg_cache(env, i,
1768: ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1769: ldl_phys(sm_state + offset + 8),
1770: ldl_phys(sm_state + offset + 4),
1771: (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1772: }
1773: cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1774:
1775: val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1776: if (val & 0x20000) {
1777: env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1778: }
1779: #endif
1780: CC_OP = CC_OP_EFLAGS;
1781: env->hflags &= ~HF_SMM_MASK;
1782: cpu_smm_update(env);
1783:
1784: qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
1785: log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
1786: }
1787:
1788: #endif /* !CONFIG_USER_ONLY */
1789:
1790:
1791: /* division, flags are undefined */
1792:
1793: void helper_divb_AL(target_ulong t0)
1794: {
1795: unsigned int num, den, q, r;
1796:
1797: num = (EAX & 0xffff);
1798: den = (t0 & 0xff);
1799: if (den == 0) {
1800: raise_exception(EXCP00_DIVZ);
1801: }
1802: q = (num / den);
1803: if (q > 0xff)
1804: raise_exception(EXCP00_DIVZ);
1805: q &= 0xff;
1806: r = (num % den) & 0xff;
1807: EAX = (EAX & ~0xffff) | (r << 8) | q;
1808: }
1809:
1810: void helper_idivb_AL(target_ulong t0)
1811: {
1812: int num, den, q, r;
1813:
1814: num = (int16_t)EAX;
1815: den = (int8_t)t0;
1816: if (den == 0) {
1817: raise_exception(EXCP00_DIVZ);
1818: }
1819: q = (num / den);
1820: if (q != (int8_t)q)
1821: raise_exception(EXCP00_DIVZ);
1822: q &= 0xff;
1823: r = (num % den) & 0xff;
1824: EAX = (EAX & ~0xffff) | (r << 8) | q;
1825: }
1826:
1827: void helper_divw_AX(target_ulong t0)
1828: {
1829: unsigned int num, den, q, r;
1830:
1831: num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1832: den = (t0 & 0xffff);
1833: if (den == 0) {
1834: raise_exception(EXCP00_DIVZ);
1835: }
1836: q = (num / den);
1837: if (q > 0xffff)
1838: raise_exception(EXCP00_DIVZ);
1839: q &= 0xffff;
1840: r = (num % den) & 0xffff;
1841: EAX = (EAX & ~0xffff) | q;
1842: EDX = (EDX & ~0xffff) | r;
1843: }
1844:
1845: void helper_idivw_AX(target_ulong t0)
1846: {
1847: int num, den, q, r;
1848:
1849: num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1850: den = (int16_t)t0;
1851: if (den == 0) {
1852: raise_exception(EXCP00_DIVZ);
1853: }
1854: q = (num / den);
1855: if (q != (int16_t)q)
1856: raise_exception(EXCP00_DIVZ);
1857: q &= 0xffff;
1858: r = (num % den) & 0xffff;
1859: EAX = (EAX & ~0xffff) | q;
1860: EDX = (EDX & ~0xffff) | r;
1861: }
1862:
1863: void helper_divl_EAX(target_ulong t0)
1864: {
1865: unsigned int den, r;
1866: uint64_t num, q;
1867:
1868: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1869: den = t0;
1870: if (den == 0) {
1871: raise_exception(EXCP00_DIVZ);
1872: }
1873: q = (num / den);
1874: r = (num % den);
1875: if (q > 0xffffffff)
1876: raise_exception(EXCP00_DIVZ);
1877: EAX = (uint32_t)q;
1878: EDX = (uint32_t)r;
1879: }
1880:
1881: void helper_idivl_EAX(target_ulong t0)
1882: {
1883: int den, r;
1884: int64_t num, q;
1885:
1886: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1887: den = t0;
1888: if (den == 0) {
1889: raise_exception(EXCP00_DIVZ);
1890: }
1891: q = (num / den);
1892: r = (num % den);
1893: if (q != (int32_t)q)
1894: raise_exception(EXCP00_DIVZ);
1895: EAX = (uint32_t)q;
1896: EDX = (uint32_t)r;
1897: }
1898:
1899: /* bcd */
1900:
1901: /* XXX: exception */
1902: void helper_aam(int base)
1903: {
1904: int al, ah;
1905: al = EAX & 0xff;
1906: ah = al / base;
1907: al = al % base;
1908: EAX = (EAX & ~0xffff) | al | (ah << 8);
1909: CC_DST = al;
1910: }
1911:
1912: void helper_aad(int base)
1913: {
1914: int al, ah;
1915: al = EAX & 0xff;
1916: ah = (EAX >> 8) & 0xff;
1917: al = ((ah * base) + al) & 0xff;
1918: EAX = (EAX & ~0xffff) | al;
1919: CC_DST = al;
1920: }
1921:
1922: void helper_aaa(void)
1923: {
1924: int icarry;
1925: int al, ah, af;
1926: int eflags;
1927:
1928: eflags = helper_cc_compute_all(CC_OP);
1929: af = eflags & CC_A;
1930: al = EAX & 0xff;
1931: ah = (EAX >> 8) & 0xff;
1932:
1933: icarry = (al > 0xf9);
1934: if (((al & 0x0f) > 9 ) || af) {
1935: al = (al + 6) & 0x0f;
1936: ah = (ah + 1 + icarry) & 0xff;
1937: eflags |= CC_C | CC_A;
1938: } else {
1939: eflags &= ~(CC_C | CC_A);
1940: al &= 0x0f;
1941: }
1942: EAX = (EAX & ~0xffff) | al | (ah << 8);
1943: CC_SRC = eflags;
1944: }
1945:
1946: void helper_aas(void)
1947: {
1948: int icarry;
1949: int al, ah, af;
1950: int eflags;
1951:
1952: eflags = helper_cc_compute_all(CC_OP);
1953: af = eflags & CC_A;
1954: al = EAX & 0xff;
1955: ah = (EAX >> 8) & 0xff;
1956:
1957: icarry = (al < 6);
1958: if (((al & 0x0f) > 9 ) || af) {
1959: al = (al - 6) & 0x0f;
1960: ah = (ah - 1 - icarry) & 0xff;
1961: eflags |= CC_C | CC_A;
1962: } else {
1963: eflags &= ~(CC_C | CC_A);
1964: al &= 0x0f;
1965: }
1966: EAX = (EAX & ~0xffff) | al | (ah << 8);
1967: CC_SRC = eflags;
1968: }
1969:
1970: void helper_daa(void)
1971: {
1.1.1.8 root 1972: int old_al, al, af, cf;
1.1 root 1973: int eflags;
1974:
1975: eflags = helper_cc_compute_all(CC_OP);
1976: cf = eflags & CC_C;
1977: af = eflags & CC_A;
1.1.1.8 root 1978: old_al = al = EAX & 0xff;
1.1 root 1979:
1980: eflags = 0;
1981: if (((al & 0x0f) > 9 ) || af) {
1982: al = (al + 6) & 0xff;
1983: eflags |= CC_A;
1984: }
1.1.1.8 root 1985: if ((old_al > 0x99) || cf) {
1.1 root 1986: al = (al + 0x60) & 0xff;
1987: eflags |= CC_C;
1988: }
1989: EAX = (EAX & ~0xff) | al;
1990: /* well, speed is not an issue here, so we compute the flags by hand */
1991: eflags |= (al == 0) << 6; /* zf */
1992: eflags |= parity_table[al]; /* pf */
1993: eflags |= (al & 0x80); /* sf */
1994: CC_SRC = eflags;
1995: }
1996:
1997: void helper_das(void)
1998: {
1999: int al, al1, af, cf;
2000: int eflags;
2001:
2002: eflags = helper_cc_compute_all(CC_OP);
2003: cf = eflags & CC_C;
2004: af = eflags & CC_A;
2005: al = EAX & 0xff;
2006:
2007: eflags = 0;
2008: al1 = al;
2009: if (((al & 0x0f) > 9 ) || af) {
2010: eflags |= CC_A;
2011: if (al < 6 || cf)
2012: eflags |= CC_C;
2013: al = (al - 6) & 0xff;
2014: }
2015: if ((al1 > 0x99) || cf) {
2016: al = (al - 0x60) & 0xff;
2017: eflags |= CC_C;
2018: }
2019: EAX = (EAX & ~0xff) | al;
2020: /* well, speed is not an issue here, so we compute the flags by hand */
2021: eflags |= (al == 0) << 6; /* zf */
2022: eflags |= parity_table[al]; /* pf */
2023: eflags |= (al & 0x80); /* sf */
2024: CC_SRC = eflags;
2025: }
2026:
2027: void helper_into(int next_eip_addend)
2028: {
2029: int eflags;
2030: eflags = helper_cc_compute_all(CC_OP);
2031: if (eflags & CC_O) {
2032: raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
2033: }
2034: }
2035:
2036: void helper_cmpxchg8b(target_ulong a0)
2037: {
2038: uint64_t d;
2039: int eflags;
2040:
2041: eflags = helper_cc_compute_all(CC_OP);
2042: d = ldq(a0);
2043: if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
2044: stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
2045: eflags |= CC_Z;
2046: } else {
2047: /* always do the store */
2048: stq(a0, d);
2049: EDX = (uint32_t)(d >> 32);
2050: EAX = (uint32_t)d;
2051: eflags &= ~CC_Z;
2052: }
2053: CC_SRC = eflags;
2054: }
2055:
2056: #ifdef TARGET_X86_64
2057: void helper_cmpxchg16b(target_ulong a0)
2058: {
2059: uint64_t d0, d1;
2060: int eflags;
2061:
2062: if ((a0 & 0xf) != 0)
2063: raise_exception(EXCP0D_GPF);
2064: eflags = helper_cc_compute_all(CC_OP);
2065: d0 = ldq(a0);
2066: d1 = ldq(a0 + 8);
2067: if (d0 == EAX && d1 == EDX) {
2068: stq(a0, EBX);
2069: stq(a0 + 8, ECX);
2070: eflags |= CC_Z;
2071: } else {
2072: /* always do the store */
2073: stq(a0, d0);
2074: stq(a0 + 8, d1);
2075: EDX = d1;
2076: EAX = d0;
2077: eflags &= ~CC_Z;
2078: }
2079: CC_SRC = eflags;
2080: }
2081: #endif
2082:
2083: void helper_single_step(void)
2084: {
2085: #ifndef CONFIG_USER_ONLY
2086: check_hw_breakpoints(env, 1);
2087: env->dr[6] |= DR6_BS;
2088: #endif
2089: raise_exception(EXCP01_DB);
2090: }
2091:
2092: void helper_cpuid(void)
2093: {
2094: uint32_t eax, ebx, ecx, edx;
2095:
2096: helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
2097:
2098: cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
2099: EAX = eax;
2100: EBX = ebx;
2101: ECX = ecx;
2102: EDX = edx;
2103: }
2104:
2105: void helper_enter_level(int level, int data32, target_ulong t1)
2106: {
2107: target_ulong ssp;
2108: uint32_t esp_mask, esp, ebp;
2109:
2110: esp_mask = get_sp_mask(env->segs[R_SS].flags);
2111: ssp = env->segs[R_SS].base;
2112: ebp = EBP;
2113: esp = ESP;
2114: if (data32) {
2115: /* 32 bit */
2116: esp -= 4;
2117: while (--level) {
2118: esp -= 4;
2119: ebp -= 4;
2120: stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
2121: }
2122: esp -= 4;
2123: stl(ssp + (esp & esp_mask), t1);
2124: } else {
2125: /* 16 bit */
2126: esp -= 2;
2127: while (--level) {
2128: esp -= 2;
2129: ebp -= 2;
2130: stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
2131: }
2132: esp -= 2;
2133: stw(ssp + (esp & esp_mask), t1);
2134: }
2135: }
2136:
2137: #ifdef TARGET_X86_64
2138: void helper_enter64_level(int level, int data64, target_ulong t1)
2139: {
2140: target_ulong esp, ebp;
2141: ebp = EBP;
2142: esp = ESP;
2143:
2144: if (data64) {
2145: /* 64 bit */
2146: esp -= 8;
2147: while (--level) {
2148: esp -= 8;
2149: ebp -= 8;
2150: stq(esp, ldq(ebp));
2151: }
2152: esp -= 8;
2153: stq(esp, t1);
2154: } else {
2155: /* 16 bit */
2156: esp -= 2;
2157: while (--level) {
2158: esp -= 2;
2159: ebp -= 2;
2160: stw(esp, lduw(ebp));
2161: }
2162: esp -= 2;
2163: stw(esp, t1);
2164: }
2165: }
2166: #endif
2167:
2168: void helper_lldt(int selector)
2169: {
2170: SegmentCache *dt;
2171: uint32_t e1, e2;
2172: int index, entry_limit;
2173: target_ulong ptr;
2174:
2175: selector &= 0xffff;
2176: if ((selector & 0xfffc) == 0) {
2177: /* XXX: NULL selector case: invalid LDT */
2178: env->ldt.base = 0;
2179: env->ldt.limit = 0;
2180: } else {
2181: if (selector & 0x4)
2182: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2183: dt = &env->gdt;
2184: index = selector & ~7;
2185: #ifdef TARGET_X86_64
2186: if (env->hflags & HF_LMA_MASK)
2187: entry_limit = 15;
2188: else
2189: #endif
2190: entry_limit = 7;
2191: if ((index + entry_limit) > dt->limit)
2192: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2193: ptr = dt->base + index;
2194: e1 = ldl_kernel(ptr);
2195: e2 = ldl_kernel(ptr + 4);
2196: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
2197: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2198: if (!(e2 & DESC_P_MASK))
2199: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2200: #ifdef TARGET_X86_64
2201: if (env->hflags & HF_LMA_MASK) {
2202: uint32_t e3;
2203: e3 = ldl_kernel(ptr + 8);
2204: load_seg_cache_raw_dt(&env->ldt, e1, e2);
2205: env->ldt.base |= (target_ulong)e3 << 32;
2206: } else
2207: #endif
2208: {
2209: load_seg_cache_raw_dt(&env->ldt, e1, e2);
2210: }
2211: }
2212: env->ldt.selector = selector;
2213: }
2214:
2215: void helper_ltr(int selector)
2216: {
2217: SegmentCache *dt;
2218: uint32_t e1, e2;
2219: int index, type, entry_limit;
2220: target_ulong ptr;
2221:
2222: selector &= 0xffff;
2223: if ((selector & 0xfffc) == 0) {
2224: /* NULL selector case: invalid TR */
2225: env->tr.base = 0;
2226: env->tr.limit = 0;
2227: env->tr.flags = 0;
2228: } else {
2229: if (selector & 0x4)
2230: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2231: dt = &env->gdt;
2232: index = selector & ~7;
2233: #ifdef TARGET_X86_64
2234: if (env->hflags & HF_LMA_MASK)
2235: entry_limit = 15;
2236: else
2237: #endif
2238: entry_limit = 7;
2239: if ((index + entry_limit) > dt->limit)
2240: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2241: ptr = dt->base + index;
2242: e1 = ldl_kernel(ptr);
2243: e2 = ldl_kernel(ptr + 4);
2244: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2245: if ((e2 & DESC_S_MASK) ||
2246: (type != 1 && type != 9))
2247: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2248: if (!(e2 & DESC_P_MASK))
2249: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2250: #ifdef TARGET_X86_64
2251: if (env->hflags & HF_LMA_MASK) {
2252: uint32_t e3, e4;
2253: e3 = ldl_kernel(ptr + 8);
2254: e4 = ldl_kernel(ptr + 12);
2255: if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2256: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2257: load_seg_cache_raw_dt(&env->tr, e1, e2);
2258: env->tr.base |= (target_ulong)e3 << 32;
2259: } else
2260: #endif
2261: {
2262: load_seg_cache_raw_dt(&env->tr, e1, e2);
2263: }
2264: e2 |= DESC_TSS_BUSY_MASK;
2265: stl_kernel(ptr + 4, e2);
2266: }
2267: env->tr.selector = selector;
2268: }
2269:
2270: /* only works if protected mode and not VM86. seg_reg must be != R_CS */
2271: void helper_load_seg(int seg_reg, int selector)
2272: {
2273: uint32_t e1, e2;
2274: int cpl, dpl, rpl;
2275: SegmentCache *dt;
2276: int index;
2277: target_ulong ptr;
2278:
2279: selector &= 0xffff;
2280: cpl = env->hflags & HF_CPL_MASK;
2281: if ((selector & 0xfffc) == 0) {
2282: /* null selector case */
2283: if (seg_reg == R_SS
2284: #ifdef TARGET_X86_64
2285: && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2286: #endif
2287: )
2288: raise_exception_err(EXCP0D_GPF, 0);
2289: cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2290: } else {
2291:
2292: if (selector & 0x4)
2293: dt = &env->ldt;
2294: else
2295: dt = &env->gdt;
2296: index = selector & ~7;
2297: if ((index + 7) > dt->limit)
2298: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2299: ptr = dt->base + index;
2300: e1 = ldl_kernel(ptr);
2301: e2 = ldl_kernel(ptr + 4);
2302:
2303: if (!(e2 & DESC_S_MASK))
2304: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2305: rpl = selector & 3;
2306: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2307: if (seg_reg == R_SS) {
2308: /* must be writable segment */
2309: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2310: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2311: if (rpl != cpl || dpl != cpl)
2312: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2313: } else {
2314: /* must be readable segment */
2315: if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2316: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2317:
2318: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2319: /* if not conforming code, test rights */
2320: if (dpl < cpl || dpl < rpl)
2321: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2322: }
2323: }
2324:
2325: if (!(e2 & DESC_P_MASK)) {
2326: if (seg_reg == R_SS)
2327: raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2328: else
2329: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2330: }
2331:
2332: /* set the access bit if not already set */
2333: if (!(e2 & DESC_A_MASK)) {
2334: e2 |= DESC_A_MASK;
2335: stl_kernel(ptr + 4, e2);
2336: }
2337:
2338: cpu_x86_load_seg_cache(env, seg_reg, selector,
2339: get_seg_base(e1, e2),
2340: get_seg_limit(e1, e2),
2341: e2);
2342: #if 0
2343: qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2344: selector, (unsigned long)sc->base, sc->limit, sc->flags);
2345: #endif
2346: }
2347: }
2348:
2349: /* protected mode jump */
2350: void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2351: int next_eip_addend)
2352: {
2353: int gate_cs, type;
2354: uint32_t e1, e2, cpl, dpl, rpl, limit;
2355: target_ulong next_eip;
2356:
2357: if ((new_cs & 0xfffc) == 0)
2358: raise_exception_err(EXCP0D_GPF, 0);
2359: if (load_segment(&e1, &e2, new_cs) != 0)
2360: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2361: cpl = env->hflags & HF_CPL_MASK;
2362: if (e2 & DESC_S_MASK) {
2363: if (!(e2 & DESC_CS_MASK))
2364: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2365: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2366: if (e2 & DESC_C_MASK) {
2367: /* conforming code segment */
2368: if (dpl > cpl)
2369: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2370: } else {
2371: /* non conforming code segment */
2372: rpl = new_cs & 3;
2373: if (rpl > cpl)
2374: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2375: if (dpl != cpl)
2376: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2377: }
2378: if (!(e2 & DESC_P_MASK))
2379: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2380: limit = get_seg_limit(e1, e2);
2381: if (new_eip > limit &&
2382: !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2383: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2384: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2385: get_seg_base(e1, e2), limit, e2);
2386: EIP = new_eip;
2387: } else {
2388: /* jump to call or task gate */
2389: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2390: rpl = new_cs & 3;
2391: cpl = env->hflags & HF_CPL_MASK;
2392: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2393: switch(type) {
2394: case 1: /* 286 TSS */
2395: case 9: /* 386 TSS */
2396: case 5: /* task gate */
2397: if (dpl < cpl || dpl < rpl)
2398: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2399: next_eip = env->eip + next_eip_addend;
2400: switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2401: CC_OP = CC_OP_EFLAGS;
2402: break;
2403: case 4: /* 286 call gate */
2404: case 12: /* 386 call gate */
2405: if ((dpl < cpl) || (dpl < rpl))
2406: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2407: if (!(e2 & DESC_P_MASK))
2408: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2409: gate_cs = e1 >> 16;
2410: new_eip = (e1 & 0xffff);
2411: if (type == 12)
2412: new_eip |= (e2 & 0xffff0000);
2413: if (load_segment(&e1, &e2, gate_cs) != 0)
2414: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2415: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2416: /* must be code segment */
2417: if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2418: (DESC_S_MASK | DESC_CS_MASK)))
2419: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2420: if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2421: (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2422: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2423: if (!(e2 & DESC_P_MASK))
2424: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2425: limit = get_seg_limit(e1, e2);
2426: if (new_eip > limit)
2427: raise_exception_err(EXCP0D_GPF, 0);
2428: cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2429: get_seg_base(e1, e2), limit, e2);
2430: EIP = new_eip;
2431: break;
2432: default:
2433: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2434: break;
2435: }
2436: }
2437: }
2438:
2439: /* real mode call */
2440: void helper_lcall_real(int new_cs, target_ulong new_eip1,
2441: int shift, int next_eip)
2442: {
2443: int new_eip;
2444: uint32_t esp, esp_mask;
2445: target_ulong ssp;
2446:
2447: new_eip = new_eip1;
2448: esp = ESP;
2449: esp_mask = get_sp_mask(env->segs[R_SS].flags);
2450: ssp = env->segs[R_SS].base;
2451: if (shift) {
2452: PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2453: PUSHL(ssp, esp, esp_mask, next_eip);
2454: } else {
2455: PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2456: PUSHW(ssp, esp, esp_mask, next_eip);
2457: }
2458:
2459: SET_ESP(esp, esp_mask);
2460: env->eip = new_eip;
2461: env->segs[R_CS].selector = new_cs;
2462: env->segs[R_CS].base = (new_cs << 4);
2463: }
2464:
2465: /* protected mode call */
2466: void helper_lcall_protected(int new_cs, target_ulong new_eip,
2467: int shift, int next_eip_addend)
2468: {
2469: int new_stack, i;
2470: uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2471: uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
2472: uint32_t val, limit, old_sp_mask;
2473: target_ulong ssp, old_ssp, next_eip;
2474:
2475: next_eip = env->eip + next_eip_addend;
2476: LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
2477: LOG_PCALL_STATE(env);
2478: if ((new_cs & 0xfffc) == 0)
2479: raise_exception_err(EXCP0D_GPF, 0);
2480: if (load_segment(&e1, &e2, new_cs) != 0)
2481: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2482: cpl = env->hflags & HF_CPL_MASK;
2483: LOG_PCALL("desc=%08x:%08x\n", e1, e2);
2484: if (e2 & DESC_S_MASK) {
2485: if (!(e2 & DESC_CS_MASK))
2486: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2487: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2488: if (e2 & DESC_C_MASK) {
2489: /* conforming code segment */
2490: if (dpl > cpl)
2491: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2492: } else {
2493: /* non conforming code segment */
2494: rpl = new_cs & 3;
2495: if (rpl > cpl)
2496: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2497: if (dpl != cpl)
2498: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2499: }
2500: if (!(e2 & DESC_P_MASK))
2501: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2502:
2503: #ifdef TARGET_X86_64
2504: /* XXX: check 16/32 bit cases in long mode */
2505: if (shift == 2) {
2506: target_ulong rsp;
2507: /* 64 bit case */
2508: rsp = ESP;
2509: PUSHQ(rsp, env->segs[R_CS].selector);
2510: PUSHQ(rsp, next_eip);
2511: /* from this point, not restartable */
2512: ESP = rsp;
2513: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2514: get_seg_base(e1, e2),
2515: get_seg_limit(e1, e2), e2);
2516: EIP = new_eip;
2517: } else
2518: #endif
2519: {
2520: sp = ESP;
2521: sp_mask = get_sp_mask(env->segs[R_SS].flags);
2522: ssp = env->segs[R_SS].base;
2523: if (shift) {
2524: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2525: PUSHL(ssp, sp, sp_mask, next_eip);
2526: } else {
2527: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2528: PUSHW(ssp, sp, sp_mask, next_eip);
2529: }
2530:
2531: limit = get_seg_limit(e1, e2);
2532: if (new_eip > limit)
2533: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2534: /* from this point, not restartable */
2535: SET_ESP(sp, sp_mask);
2536: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2537: get_seg_base(e1, e2), limit, e2);
2538: EIP = new_eip;
2539: }
2540: } else {
2541: /* check gate type */
2542: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2543: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2544: rpl = new_cs & 3;
2545: switch(type) {
2546: case 1: /* available 286 TSS */
2547: case 9: /* available 386 TSS */
2548: case 5: /* task gate */
2549: if (dpl < cpl || dpl < rpl)
2550: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2551: switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2552: CC_OP = CC_OP_EFLAGS;
2553: return;
2554: case 4: /* 286 call gate */
2555: case 12: /* 386 call gate */
2556: break;
2557: default:
2558: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2559: break;
2560: }
2561: shift = type >> 3;
2562:
2563: if (dpl < cpl || dpl < rpl)
2564: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2565: /* check valid bit */
2566: if (!(e2 & DESC_P_MASK))
2567: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2568: selector = e1 >> 16;
2569: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2570: param_count = e2 & 0x1f;
2571: if ((selector & 0xfffc) == 0)
2572: raise_exception_err(EXCP0D_GPF, 0);
2573:
2574: if (load_segment(&e1, &e2, selector) != 0)
2575: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2576: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2577: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2578: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2579: if (dpl > cpl)
2580: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2581: if (!(e2 & DESC_P_MASK))
2582: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2583:
2584: if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2585: /* to inner privilege */
2586: get_ss_esp_from_tss(&ss, &sp, dpl);
2587: LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2588: ss, sp, param_count, ESP);
2589: if ((ss & 0xfffc) == 0)
2590: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2591: if ((ss & 3) != dpl)
2592: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2593: if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2594: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2595: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2596: if (ss_dpl != dpl)
2597: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2598: if (!(ss_e2 & DESC_S_MASK) ||
2599: (ss_e2 & DESC_CS_MASK) ||
2600: !(ss_e2 & DESC_W_MASK))
2601: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2602: if (!(ss_e2 & DESC_P_MASK))
2603: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2604:
2605: // push_size = ((param_count * 2) + 8) << shift;
2606:
2607: old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2608: old_ssp = env->segs[R_SS].base;
2609:
2610: sp_mask = get_sp_mask(ss_e2);
2611: ssp = get_seg_base(ss_e1, ss_e2);
2612: if (shift) {
2613: PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2614: PUSHL(ssp, sp, sp_mask, ESP);
2615: for(i = param_count - 1; i >= 0; i--) {
2616: val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2617: PUSHL(ssp, sp, sp_mask, val);
2618: }
2619: } else {
2620: PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2621: PUSHW(ssp, sp, sp_mask, ESP);
2622: for(i = param_count - 1; i >= 0; i--) {
2623: val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2624: PUSHW(ssp, sp, sp_mask, val);
2625: }
2626: }
2627: new_stack = 1;
2628: } else {
2629: /* to same privilege */
2630: sp = ESP;
2631: sp_mask = get_sp_mask(env->segs[R_SS].flags);
2632: ssp = env->segs[R_SS].base;
2633: // push_size = (4 << shift);
2634: new_stack = 0;
2635: }
2636:
2637: if (shift) {
2638: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2639: PUSHL(ssp, sp, sp_mask, next_eip);
2640: } else {
2641: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2642: PUSHW(ssp, sp, sp_mask, next_eip);
2643: }
2644:
2645: /* from this point, not restartable */
2646:
2647: if (new_stack) {
2648: ss = (ss & ~3) | dpl;
2649: cpu_x86_load_seg_cache(env, R_SS, ss,
2650: ssp,
2651: get_seg_limit(ss_e1, ss_e2),
2652: ss_e2);
2653: }
2654:
2655: selector = (selector & ~3) | dpl;
2656: cpu_x86_load_seg_cache(env, R_CS, selector,
2657: get_seg_base(e1, e2),
2658: get_seg_limit(e1, e2),
2659: e2);
2660: cpu_x86_set_cpl(env, dpl);
2661: SET_ESP(sp, sp_mask);
2662: EIP = offset;
2663: }
2664: }
2665:
2666: /* real and vm86 mode iret */
2667: void helper_iret_real(int shift)
2668: {
2669: uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2670: target_ulong ssp;
2671: int eflags_mask;
2672:
2673: sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2674: sp = ESP;
2675: ssp = env->segs[R_SS].base;
2676: if (shift == 1) {
2677: /* 32 bits */
2678: POPL(ssp, sp, sp_mask, new_eip);
2679: POPL(ssp, sp, sp_mask, new_cs);
2680: new_cs &= 0xffff;
2681: POPL(ssp, sp, sp_mask, new_eflags);
2682: } else {
2683: /* 16 bits */
2684: POPW(ssp, sp, sp_mask, new_eip);
2685: POPW(ssp, sp, sp_mask, new_cs);
2686: POPW(ssp, sp, sp_mask, new_eflags);
2687: }
2688: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2689: env->segs[R_CS].selector = new_cs;
2690: env->segs[R_CS].base = (new_cs << 4);
2691: env->eip = new_eip;
2692: if (env->eflags & VM_MASK)
2693: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2694: else
2695: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2696: if (shift == 0)
2697: eflags_mask &= 0xffff;
2698: load_eflags(new_eflags, eflags_mask);
2699: env->hflags2 &= ~HF2_NMI_MASK;
2700: }
2701:
2702: static inline void validate_seg(int seg_reg, int cpl)
2703: {
2704: int dpl;
2705: uint32_t e2;
2706:
2707: /* XXX: on x86_64, we do not want to nullify FS and GS because
2708: they may still contain a valid base. I would be interested to
2709: know how a real x86_64 CPU behaves */
2710: if ((seg_reg == R_FS || seg_reg == R_GS) &&
2711: (env->segs[seg_reg].selector & 0xfffc) == 0)
2712: return;
2713:
2714: e2 = env->segs[seg_reg].flags;
2715: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2716: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2717: /* data or non conforming code segment */
2718: if (dpl < cpl) {
2719: cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2720: }
2721: }
2722: }
2723:
2724: /* protected mode iret */
2725: static inline void helper_ret_protected(int shift, int is_iret, int addend)
2726: {
2727: uint32_t new_cs, new_eflags, new_ss;
2728: uint32_t new_es, new_ds, new_fs, new_gs;
2729: uint32_t e1, e2, ss_e1, ss_e2;
2730: int cpl, dpl, rpl, eflags_mask, iopl;
2731: target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2732:
2733: #ifdef TARGET_X86_64
2734: if (shift == 2)
2735: sp_mask = -1;
2736: else
2737: #endif
2738: sp_mask = get_sp_mask(env->segs[R_SS].flags);
2739: sp = ESP;
2740: ssp = env->segs[R_SS].base;
2741: new_eflags = 0; /* avoid warning */
2742: #ifdef TARGET_X86_64
2743: if (shift == 2) {
2744: POPQ(sp, new_eip);
2745: POPQ(sp, new_cs);
2746: new_cs &= 0xffff;
2747: if (is_iret) {
2748: POPQ(sp, new_eflags);
2749: }
2750: } else
2751: #endif
2752: if (shift == 1) {
2753: /* 32 bits */
2754: POPL(ssp, sp, sp_mask, new_eip);
2755: POPL(ssp, sp, sp_mask, new_cs);
2756: new_cs &= 0xffff;
2757: if (is_iret) {
2758: POPL(ssp, sp, sp_mask, new_eflags);
2759: if (new_eflags & VM_MASK)
2760: goto return_to_vm86;
2761: }
2762: } else {
2763: /* 16 bits */
2764: POPW(ssp, sp, sp_mask, new_eip);
2765: POPW(ssp, sp, sp_mask, new_cs);
2766: if (is_iret)
2767: POPW(ssp, sp, sp_mask, new_eflags);
2768: }
2769: LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2770: new_cs, new_eip, shift, addend);
2771: LOG_PCALL_STATE(env);
2772: if ((new_cs & 0xfffc) == 0)
2773: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2774: if (load_segment(&e1, &e2, new_cs) != 0)
2775: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2776: if (!(e2 & DESC_S_MASK) ||
2777: !(e2 & DESC_CS_MASK))
2778: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2779: cpl = env->hflags & HF_CPL_MASK;
2780: rpl = new_cs & 3;
2781: if (rpl < cpl)
2782: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2783: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2784: if (e2 & DESC_C_MASK) {
2785: if (dpl > rpl)
2786: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2787: } else {
2788: if (dpl != rpl)
2789: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2790: }
2791: if (!(e2 & DESC_P_MASK))
2792: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2793:
2794: sp += addend;
2795: if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2796: ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2797: /* return to same privilege level */
2798: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2799: get_seg_base(e1, e2),
2800: get_seg_limit(e1, e2),
2801: e2);
2802: } else {
2803: /* return to different privilege level */
2804: #ifdef TARGET_X86_64
2805: if (shift == 2) {
2806: POPQ(sp, new_esp);
2807: POPQ(sp, new_ss);
2808: new_ss &= 0xffff;
2809: } else
2810: #endif
2811: if (shift == 1) {
2812: /* 32 bits */
2813: POPL(ssp, sp, sp_mask, new_esp);
2814: POPL(ssp, sp, sp_mask, new_ss);
2815: new_ss &= 0xffff;
2816: } else {
2817: /* 16 bits */
2818: POPW(ssp, sp, sp_mask, new_esp);
2819: POPW(ssp, sp, sp_mask, new_ss);
2820: }
2821: LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
2822: new_ss, new_esp);
2823: if ((new_ss & 0xfffc) == 0) {
2824: #ifdef TARGET_X86_64
2825: /* NULL ss is allowed in long mode if cpl != 3*/
2826: /* XXX: test CS64 ? */
2827: if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2828: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2829: 0, 0xffffffff,
2830: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2831: DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2832: DESC_W_MASK | DESC_A_MASK);
2833: ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2834: } else
2835: #endif
2836: {
2837: raise_exception_err(EXCP0D_GPF, 0);
2838: }
2839: } else {
2840: if ((new_ss & 3) != rpl)
2841: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2842: if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2843: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2844: if (!(ss_e2 & DESC_S_MASK) ||
2845: (ss_e2 & DESC_CS_MASK) ||
2846: !(ss_e2 & DESC_W_MASK))
2847: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2848: dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2849: if (dpl != rpl)
2850: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2851: if (!(ss_e2 & DESC_P_MASK))
2852: raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2853: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2854: get_seg_base(ss_e1, ss_e2),
2855: get_seg_limit(ss_e1, ss_e2),
2856: ss_e2);
2857: }
2858:
2859: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2860: get_seg_base(e1, e2),
2861: get_seg_limit(e1, e2),
2862: e2);
2863: cpu_x86_set_cpl(env, rpl);
2864: sp = new_esp;
2865: #ifdef TARGET_X86_64
2866: if (env->hflags & HF_CS64_MASK)
2867: sp_mask = -1;
2868: else
2869: #endif
2870: sp_mask = get_sp_mask(ss_e2);
2871:
2872: /* validate data segments */
2873: validate_seg(R_ES, rpl);
2874: validate_seg(R_DS, rpl);
2875: validate_seg(R_FS, rpl);
2876: validate_seg(R_GS, rpl);
2877:
2878: sp += addend;
2879: }
2880: SET_ESP(sp, sp_mask);
2881: env->eip = new_eip;
2882: if (is_iret) {
2883: /* NOTE: 'cpl' is the _old_ CPL */
2884: eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2885: if (cpl == 0)
2886: eflags_mask |= IOPL_MASK;
2887: iopl = (env->eflags >> IOPL_SHIFT) & 3;
2888: if (cpl <= iopl)
2889: eflags_mask |= IF_MASK;
2890: if (shift == 0)
2891: eflags_mask &= 0xffff;
2892: load_eflags(new_eflags, eflags_mask);
2893: }
2894: return;
2895:
2896: return_to_vm86:
2897: POPL(ssp, sp, sp_mask, new_esp);
2898: POPL(ssp, sp, sp_mask, new_ss);
2899: POPL(ssp, sp, sp_mask, new_es);
2900: POPL(ssp, sp, sp_mask, new_ds);
2901: POPL(ssp, sp, sp_mask, new_fs);
2902: POPL(ssp, sp, sp_mask, new_gs);
2903:
2904: /* modify processor state */
2905: load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2906: IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2907: load_seg_vm(R_CS, new_cs & 0xffff);
2908: cpu_x86_set_cpl(env, 3);
2909: load_seg_vm(R_SS, new_ss & 0xffff);
2910: load_seg_vm(R_ES, new_es & 0xffff);
2911: load_seg_vm(R_DS, new_ds & 0xffff);
2912: load_seg_vm(R_FS, new_fs & 0xffff);
2913: load_seg_vm(R_GS, new_gs & 0xffff);
2914:
2915: env->eip = new_eip & 0xffff;
2916: ESP = new_esp;
2917: }
2918:
2919: void helper_iret_protected(int shift, int next_eip)
2920: {
2921: int tss_selector, type;
2922: uint32_t e1, e2;
2923:
2924: /* specific case for TSS */
2925: if (env->eflags & NT_MASK) {
2926: #ifdef TARGET_X86_64
2927: if (env->hflags & HF_LMA_MASK)
2928: raise_exception_err(EXCP0D_GPF, 0);
2929: #endif
2930: tss_selector = lduw_kernel(env->tr.base + 0);
2931: if (tss_selector & 4)
2932: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2933: if (load_segment(&e1, &e2, tss_selector) != 0)
2934: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2935: type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2936: /* NOTE: we check both segment and busy TSS */
2937: if (type != 3)
2938: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2939: switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2940: } else {
2941: helper_ret_protected(shift, 1, 0);
2942: }
2943: env->hflags2 &= ~HF2_NMI_MASK;
2944: }
2945:
2946: void helper_lret_protected(int shift, int addend)
2947: {
2948: helper_ret_protected(shift, 0, addend);
2949: }
2950:
2951: void helper_sysenter(void)
2952: {
2953: if (env->sysenter_cs == 0) {
2954: raise_exception_err(EXCP0D_GPF, 0);
2955: }
2956: env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2957: cpu_x86_set_cpl(env, 0);
2958:
2959: #ifdef TARGET_X86_64
2960: if (env->hflags & HF_LMA_MASK) {
2961: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2962: 0, 0xffffffff,
2963: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2964: DESC_S_MASK |
2965: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2966: } else
2967: #endif
2968: {
2969: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2970: 0, 0xffffffff,
2971: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2972: DESC_S_MASK |
2973: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2974: }
2975: cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2976: 0, 0xffffffff,
2977: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2978: DESC_S_MASK |
2979: DESC_W_MASK | DESC_A_MASK);
2980: ESP = env->sysenter_esp;
2981: EIP = env->sysenter_eip;
2982: }
2983:
2984: void helper_sysexit(int dflag)
2985: {
2986: int cpl;
2987:
2988: cpl = env->hflags & HF_CPL_MASK;
2989: if (env->sysenter_cs == 0 || cpl != 0) {
2990: raise_exception_err(EXCP0D_GPF, 0);
2991: }
2992: cpu_x86_set_cpl(env, 3);
2993: #ifdef TARGET_X86_64
2994: if (dflag == 2) {
2995: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
2996: 0, 0xffffffff,
2997: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2998: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2999: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
3000: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
3001: 0, 0xffffffff,
3002: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3003: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3004: DESC_W_MASK | DESC_A_MASK);
3005: } else
3006: #endif
3007: {
3008: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
3009: 0, 0xffffffff,
3010: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3011: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3012: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
3013: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
3014: 0, 0xffffffff,
3015: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3016: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3017: DESC_W_MASK | DESC_A_MASK);
3018: }
3019: ESP = ECX;
3020: EIP = EDX;
3021: }
3022:
3023: #if defined(CONFIG_USER_ONLY)
3024: target_ulong helper_read_crN(int reg)
3025: {
3026: return 0;
3027: }
3028:
3029: void helper_write_crN(int reg, target_ulong t0)
3030: {
3031: }
3032:
3033: void helper_movl_drN_T0(int reg, target_ulong t0)
3034: {
3035: }
3036: #else
3037: target_ulong helper_read_crN(int reg)
3038: {
3039: target_ulong val;
3040:
3041: helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
3042: switch(reg) {
3043: default:
3044: val = env->cr[reg];
3045: break;
3046: case 8:
3047: if (!(env->hflags2 & HF2_VINTR_MASK)) {
1.1.1.5 root 3048: val = cpu_get_apic_tpr(env->apic_state);
1.1 root 3049: } else {
3050: val = env->v_tpr;
3051: }
3052: break;
3053: }
3054: return val;
3055: }
3056:
3057: void helper_write_crN(int reg, target_ulong t0)
3058: {
3059: helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
3060: switch(reg) {
3061: case 0:
3062: cpu_x86_update_cr0(env, t0);
3063: break;
3064: case 3:
3065: cpu_x86_update_cr3(env, t0);
3066: break;
3067: case 4:
3068: cpu_x86_update_cr4(env, t0);
3069: break;
3070: case 8:
3071: if (!(env->hflags2 & HF2_VINTR_MASK)) {
1.1.1.5 root 3072: cpu_set_apic_tpr(env->apic_state, t0);
1.1 root 3073: }
3074: env->v_tpr = t0 & 0x0f;
3075: break;
3076: default:
3077: env->cr[reg] = t0;
3078: break;
3079: }
3080: }
3081:
3082: void helper_movl_drN_T0(int reg, target_ulong t0)
3083: {
3084: int i;
3085:
3086: if (reg < 4) {
3087: hw_breakpoint_remove(env, reg);
3088: env->dr[reg] = t0;
3089: hw_breakpoint_insert(env, reg);
3090: } else if (reg == 7) {
3091: for (i = 0; i < 4; i++)
3092: hw_breakpoint_remove(env, i);
3093: env->dr[7] = t0;
3094: for (i = 0; i < 4; i++)
3095: hw_breakpoint_insert(env, i);
3096: } else
3097: env->dr[reg] = t0;
3098: }
3099: #endif
3100:
3101: void helper_lmsw(target_ulong t0)
3102: {
3103: /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
3104: if already set to one. */
3105: t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
3106: helper_write_crN(0, t0);
3107: }
3108:
3109: void helper_clts(void)
3110: {
3111: env->cr[0] &= ~CR0_TS_MASK;
3112: env->hflags &= ~HF_TS_MASK;
3113: }
3114:
3115: void helper_invlpg(target_ulong addr)
3116: {
3117: helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
3118: tlb_flush_page(env, addr);
3119: }
3120:
3121: void helper_rdtsc(void)
3122: {
3123: uint64_t val;
3124:
3125: if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
3126: raise_exception(EXCP0D_GPF);
3127: }
3128: helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
3129:
3130: val = cpu_get_tsc(env) + env->tsc_offset;
3131: EAX = (uint32_t)(val);
3132: EDX = (uint32_t)(val >> 32);
3133: }
3134:
1.1.1.4 root 3135: void helper_rdtscp(void)
3136: {
3137: helper_rdtsc();
3138: ECX = (uint32_t)(env->tsc_aux);
3139: }
3140:
1.1 root 3141: void helper_rdpmc(void)
3142: {
3143: if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
3144: raise_exception(EXCP0D_GPF);
3145: }
3146: helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
3147:
3148: /* currently unimplemented */
3149: raise_exception_err(EXCP06_ILLOP, 0);
3150: }
3151:
3152: #if defined(CONFIG_USER_ONLY)
3153: void helper_wrmsr(void)
3154: {
3155: }
3156:
3157: void helper_rdmsr(void)
3158: {
3159: }
3160: #else
3161: void helper_wrmsr(void)
3162: {
3163: uint64_t val;
3164:
3165: helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
3166:
3167: val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
3168:
3169: switch((uint32_t)ECX) {
3170: case MSR_IA32_SYSENTER_CS:
3171: env->sysenter_cs = val & 0xffff;
3172: break;
3173: case MSR_IA32_SYSENTER_ESP:
3174: env->sysenter_esp = val;
3175: break;
3176: case MSR_IA32_SYSENTER_EIP:
3177: env->sysenter_eip = val;
3178: break;
3179: case MSR_IA32_APICBASE:
1.1.1.5 root 3180: cpu_set_apic_base(env->apic_state, val);
1.1 root 3181: break;
3182: case MSR_EFER:
3183: {
3184: uint64_t update_mask;
3185: update_mask = 0;
3186: if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3187: update_mask |= MSR_EFER_SCE;
3188: if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3189: update_mask |= MSR_EFER_LME;
3190: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3191: update_mask |= MSR_EFER_FFXSR;
3192: if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3193: update_mask |= MSR_EFER_NXE;
3194: if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
3195: update_mask |= MSR_EFER_SVME;
3196: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3197: update_mask |= MSR_EFER_FFXSR;
3198: cpu_load_efer(env, (env->efer & ~update_mask) |
3199: (val & update_mask));
3200: }
3201: break;
3202: case MSR_STAR:
3203: env->star = val;
3204: break;
3205: case MSR_PAT:
3206: env->pat = val;
3207: break;
3208: case MSR_VM_HSAVE_PA:
3209: env->vm_hsave = val;
3210: break;
3211: #ifdef TARGET_X86_64
3212: case MSR_LSTAR:
3213: env->lstar = val;
3214: break;
3215: case MSR_CSTAR:
3216: env->cstar = val;
3217: break;
3218: case MSR_FMASK:
3219: env->fmask = val;
3220: break;
3221: case MSR_FSBASE:
3222: env->segs[R_FS].base = val;
3223: break;
3224: case MSR_GSBASE:
3225: env->segs[R_GS].base = val;
3226: break;
3227: case MSR_KERNELGSBASE:
3228: env->kernelgsbase = val;
3229: break;
3230: #endif
3231: case MSR_MTRRphysBase(0):
3232: case MSR_MTRRphysBase(1):
3233: case MSR_MTRRphysBase(2):
3234: case MSR_MTRRphysBase(3):
3235: case MSR_MTRRphysBase(4):
3236: case MSR_MTRRphysBase(5):
3237: case MSR_MTRRphysBase(6):
3238: case MSR_MTRRphysBase(7):
3239: env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
3240: break;
3241: case MSR_MTRRphysMask(0):
3242: case MSR_MTRRphysMask(1):
3243: case MSR_MTRRphysMask(2):
3244: case MSR_MTRRphysMask(3):
3245: case MSR_MTRRphysMask(4):
3246: case MSR_MTRRphysMask(5):
3247: case MSR_MTRRphysMask(6):
3248: case MSR_MTRRphysMask(7):
3249: env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
3250: break;
3251: case MSR_MTRRfix64K_00000:
3252: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
3253: break;
3254: case MSR_MTRRfix16K_80000:
3255: case MSR_MTRRfix16K_A0000:
3256: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
3257: break;
3258: case MSR_MTRRfix4K_C0000:
3259: case MSR_MTRRfix4K_C8000:
3260: case MSR_MTRRfix4K_D0000:
3261: case MSR_MTRRfix4K_D8000:
3262: case MSR_MTRRfix4K_E0000:
3263: case MSR_MTRRfix4K_E8000:
3264: case MSR_MTRRfix4K_F0000:
3265: case MSR_MTRRfix4K_F8000:
3266: env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
3267: break;
3268: case MSR_MTRRdefType:
3269: env->mtrr_deftype = val;
3270: break;
1.1.1.3 root 3271: case MSR_MCG_STATUS:
3272: env->mcg_status = val;
3273: break;
3274: case MSR_MCG_CTL:
3275: if ((env->mcg_cap & MCG_CTL_P)
3276: && (val == 0 || val == ~(uint64_t)0))
3277: env->mcg_ctl = val;
3278: break;
1.1.1.4 root 3279: case MSR_TSC_AUX:
3280: env->tsc_aux = val;
3281: break;
1.1.1.8 root 3282: case MSR_IA32_MISC_ENABLE:
3283: env->msr_ia32_misc_enable = val;
3284: break;
1.1 root 3285: default:
1.1.1.3 root 3286: if ((uint32_t)ECX >= MSR_MC0_CTL
3287: && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
3288: uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
3289: if ((offset & 0x3) != 0
3290: || (val == 0 || val == ~(uint64_t)0))
3291: env->mce_banks[offset] = val;
3292: break;
3293: }
1.1 root 3294: /* XXX: exception ? */
3295: break;
3296: }
3297: }
3298:
3299: void helper_rdmsr(void)
3300: {
3301: uint64_t val;
3302:
3303: helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3304:
3305: switch((uint32_t)ECX) {
3306: case MSR_IA32_SYSENTER_CS:
3307: val = env->sysenter_cs;
3308: break;
3309: case MSR_IA32_SYSENTER_ESP:
3310: val = env->sysenter_esp;
3311: break;
3312: case MSR_IA32_SYSENTER_EIP:
3313: val = env->sysenter_eip;
3314: break;
3315: case MSR_IA32_APICBASE:
1.1.1.5 root 3316: val = cpu_get_apic_base(env->apic_state);
1.1 root 3317: break;
3318: case MSR_EFER:
3319: val = env->efer;
3320: break;
3321: case MSR_STAR:
3322: val = env->star;
3323: break;
3324: case MSR_PAT:
3325: val = env->pat;
3326: break;
3327: case MSR_VM_HSAVE_PA:
3328: val = env->vm_hsave;
3329: break;
3330: case MSR_IA32_PERF_STATUS:
3331: /* tsc_increment_by_tick */
3332: val = 1000ULL;
3333: /* CPU multiplier */
3334: val |= (((uint64_t)4ULL) << 40);
3335: break;
3336: #ifdef TARGET_X86_64
3337: case MSR_LSTAR:
3338: val = env->lstar;
3339: break;
3340: case MSR_CSTAR:
3341: val = env->cstar;
3342: break;
3343: case MSR_FMASK:
3344: val = env->fmask;
3345: break;
3346: case MSR_FSBASE:
3347: val = env->segs[R_FS].base;
3348: break;
3349: case MSR_GSBASE:
3350: val = env->segs[R_GS].base;
3351: break;
3352: case MSR_KERNELGSBASE:
3353: val = env->kernelgsbase;
3354: break;
1.1.1.4 root 3355: case MSR_TSC_AUX:
3356: val = env->tsc_aux;
1.1 root 3357: break;
3358: #endif
3359: case MSR_MTRRphysBase(0):
3360: case MSR_MTRRphysBase(1):
3361: case MSR_MTRRphysBase(2):
3362: case MSR_MTRRphysBase(3):
3363: case MSR_MTRRphysBase(4):
3364: case MSR_MTRRphysBase(5):
3365: case MSR_MTRRphysBase(6):
3366: case MSR_MTRRphysBase(7):
3367: val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
3368: break;
3369: case MSR_MTRRphysMask(0):
3370: case MSR_MTRRphysMask(1):
3371: case MSR_MTRRphysMask(2):
3372: case MSR_MTRRphysMask(3):
3373: case MSR_MTRRphysMask(4):
3374: case MSR_MTRRphysMask(5):
3375: case MSR_MTRRphysMask(6):
3376: case MSR_MTRRphysMask(7):
3377: val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
3378: break;
3379: case MSR_MTRRfix64K_00000:
3380: val = env->mtrr_fixed[0];
3381: break;
3382: case MSR_MTRRfix16K_80000:
3383: case MSR_MTRRfix16K_A0000:
3384: val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
3385: break;
3386: case MSR_MTRRfix4K_C0000:
3387: case MSR_MTRRfix4K_C8000:
3388: case MSR_MTRRfix4K_D0000:
3389: case MSR_MTRRfix4K_D8000:
3390: case MSR_MTRRfix4K_E0000:
3391: case MSR_MTRRfix4K_E8000:
3392: case MSR_MTRRfix4K_F0000:
3393: case MSR_MTRRfix4K_F8000:
3394: val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
3395: break;
3396: case MSR_MTRRdefType:
3397: val = env->mtrr_deftype;
3398: break;
3399: case MSR_MTRRcap:
3400: if (env->cpuid_features & CPUID_MTRR)
3401: val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
3402: else
3403: /* XXX: exception ? */
3404: val = 0;
3405: break;
1.1.1.3 root 3406: case MSR_MCG_CAP:
3407: val = env->mcg_cap;
3408: break;
3409: case MSR_MCG_CTL:
3410: if (env->mcg_cap & MCG_CTL_P)
3411: val = env->mcg_ctl;
3412: else
3413: val = 0;
3414: break;
3415: case MSR_MCG_STATUS:
3416: val = env->mcg_status;
3417: break;
1.1.1.8 root 3418: case MSR_IA32_MISC_ENABLE:
3419: val = env->msr_ia32_misc_enable;
3420: break;
1.1 root 3421: default:
1.1.1.3 root 3422: if ((uint32_t)ECX >= MSR_MC0_CTL
3423: && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
3424: uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
3425: val = env->mce_banks[offset];
3426: break;
3427: }
1.1 root 3428: /* XXX: exception ? */
3429: val = 0;
3430: break;
3431: }
3432: EAX = (uint32_t)(val);
3433: EDX = (uint32_t)(val >> 32);
3434: }
3435: #endif
3436:
3437: target_ulong helper_lsl(target_ulong selector1)
3438: {
3439: unsigned int limit;
3440: uint32_t e1, e2, eflags, selector;
3441: int rpl, dpl, cpl, type;
3442:
3443: selector = selector1 & 0xffff;
3444: eflags = helper_cc_compute_all(CC_OP);
1.1.1.2 root 3445: if ((selector & 0xfffc) == 0)
3446: goto fail;
1.1 root 3447: if (load_segment(&e1, &e2, selector) != 0)
3448: goto fail;
3449: rpl = selector & 3;
3450: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3451: cpl = env->hflags & HF_CPL_MASK;
3452: if (e2 & DESC_S_MASK) {
3453: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3454: /* conforming */
3455: } else {
3456: if (dpl < cpl || dpl < rpl)
3457: goto fail;
3458: }
3459: } else {
3460: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3461: switch(type) {
3462: case 1:
3463: case 2:
3464: case 3:
3465: case 9:
3466: case 11:
3467: break;
3468: default:
3469: goto fail;
3470: }
3471: if (dpl < cpl || dpl < rpl) {
3472: fail:
3473: CC_SRC = eflags & ~CC_Z;
3474: return 0;
3475: }
3476: }
3477: limit = get_seg_limit(e1, e2);
3478: CC_SRC = eflags | CC_Z;
3479: return limit;
3480: }
3481:
3482: target_ulong helper_lar(target_ulong selector1)
3483: {
3484: uint32_t e1, e2, eflags, selector;
3485: int rpl, dpl, cpl, type;
3486:
3487: selector = selector1 & 0xffff;
3488: eflags = helper_cc_compute_all(CC_OP);
3489: if ((selector & 0xfffc) == 0)
3490: goto fail;
3491: if (load_segment(&e1, &e2, selector) != 0)
3492: goto fail;
3493: rpl = selector & 3;
3494: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3495: cpl = env->hflags & HF_CPL_MASK;
3496: if (e2 & DESC_S_MASK) {
3497: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3498: /* conforming */
3499: } else {
3500: if (dpl < cpl || dpl < rpl)
3501: goto fail;
3502: }
3503: } else {
3504: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3505: switch(type) {
3506: case 1:
3507: case 2:
3508: case 3:
3509: case 4:
3510: case 5:
3511: case 9:
3512: case 11:
3513: case 12:
3514: break;
3515: default:
3516: goto fail;
3517: }
3518: if (dpl < cpl || dpl < rpl) {
3519: fail:
3520: CC_SRC = eflags & ~CC_Z;
3521: return 0;
3522: }
3523: }
3524: CC_SRC = eflags | CC_Z;
3525: return e2 & 0x00f0ff00;
3526: }
3527:
3528: void helper_verr(target_ulong selector1)
3529: {
3530: uint32_t e1, e2, eflags, selector;
3531: int rpl, dpl, cpl;
3532:
3533: selector = selector1 & 0xffff;
3534: eflags = helper_cc_compute_all(CC_OP);
3535: if ((selector & 0xfffc) == 0)
3536: goto fail;
3537: if (load_segment(&e1, &e2, selector) != 0)
3538: goto fail;
3539: if (!(e2 & DESC_S_MASK))
3540: goto fail;
3541: rpl = selector & 3;
3542: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3543: cpl = env->hflags & HF_CPL_MASK;
3544: if (e2 & DESC_CS_MASK) {
3545: if (!(e2 & DESC_R_MASK))
3546: goto fail;
3547: if (!(e2 & DESC_C_MASK)) {
3548: if (dpl < cpl || dpl < rpl)
3549: goto fail;
3550: }
3551: } else {
3552: if (dpl < cpl || dpl < rpl) {
3553: fail:
3554: CC_SRC = eflags & ~CC_Z;
3555: return;
3556: }
3557: }
3558: CC_SRC = eflags | CC_Z;
3559: }
3560:
3561: void helper_verw(target_ulong selector1)
3562: {
3563: uint32_t e1, e2, eflags, selector;
3564: int rpl, dpl, cpl;
3565:
3566: selector = selector1 & 0xffff;
3567: eflags = helper_cc_compute_all(CC_OP);
3568: if ((selector & 0xfffc) == 0)
3569: goto fail;
3570: if (load_segment(&e1, &e2, selector) != 0)
3571: goto fail;
3572: if (!(e2 & DESC_S_MASK))
3573: goto fail;
3574: rpl = selector & 3;
3575: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3576: cpl = env->hflags & HF_CPL_MASK;
3577: if (e2 & DESC_CS_MASK) {
3578: goto fail;
3579: } else {
3580: if (dpl < cpl || dpl < rpl)
3581: goto fail;
3582: if (!(e2 & DESC_W_MASK)) {
3583: fail:
3584: CC_SRC = eflags & ~CC_Z;
3585: return;
3586: }
3587: }
3588: CC_SRC = eflags | CC_Z;
3589: }
3590:
3591: /* x87 FPU helpers */
3592:
1.1.1.7 root 3593: static inline double floatx80_to_double(floatx80 a)
3594: {
3595: union {
3596: float64 f64;
3597: double d;
3598: } u;
3599:
3600: u.f64 = floatx80_to_float64(a, &env->fp_status);
3601: return u.d;
3602: }
3603:
3604: static inline floatx80 double_to_floatx80(double a)
3605: {
3606: union {
3607: float64 f64;
3608: double d;
3609: } u;
3610:
3611: u.d = a;
3612: return float64_to_floatx80(u.f64, &env->fp_status);
3613: }
3614:
1.1 root 3615: static void fpu_set_exception(int mask)
3616: {
3617: env->fpus |= mask;
3618: if (env->fpus & (~env->fpuc & FPUC_EM))
3619: env->fpus |= FPUS_SE | FPUS_B;
3620: }
3621:
1.1.1.7 root 3622: static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
1.1 root 3623: {
1.1.1.7 root 3624: if (floatx80_is_zero(b)) {
1.1 root 3625: fpu_set_exception(FPUS_ZE);
1.1.1.7 root 3626: }
3627: return floatx80_div(a, b, &env->fp_status);
1.1 root 3628: }
3629:
3630: static void fpu_raise_exception(void)
3631: {
3632: if (env->cr[0] & CR0_NE_MASK) {
3633: raise_exception(EXCP10_COPR);
3634: }
3635: #if !defined(CONFIG_USER_ONLY)
3636: else {
3637: cpu_set_ferr(env);
3638: }
3639: #endif
3640: }
3641:
3642: void helper_flds_FT0(uint32_t val)
3643: {
3644: union {
3645: float32 f;
3646: uint32_t i;
3647: } u;
3648: u.i = val;
1.1.1.7 root 3649: FT0 = float32_to_floatx80(u.f, &env->fp_status);
1.1 root 3650: }
3651:
3652: void helper_fldl_FT0(uint64_t val)
3653: {
3654: union {
3655: float64 f;
3656: uint64_t i;
3657: } u;
3658: u.i = val;
1.1.1.7 root 3659: FT0 = float64_to_floatx80(u.f, &env->fp_status);
1.1 root 3660: }
3661:
3662: void helper_fildl_FT0(int32_t val)
3663: {
1.1.1.7 root 3664: FT0 = int32_to_floatx80(val, &env->fp_status);
1.1 root 3665: }
3666:
3667: void helper_flds_ST0(uint32_t val)
3668: {
3669: int new_fpstt;
3670: union {
3671: float32 f;
3672: uint32_t i;
3673: } u;
3674: new_fpstt = (env->fpstt - 1) & 7;
3675: u.i = val;
1.1.1.7 root 3676: env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
1.1 root 3677: env->fpstt = new_fpstt;
3678: env->fptags[new_fpstt] = 0; /* validate stack entry */
3679: }
3680:
3681: void helper_fldl_ST0(uint64_t val)
3682: {
3683: int new_fpstt;
3684: union {
3685: float64 f;
3686: uint64_t i;
3687: } u;
3688: new_fpstt = (env->fpstt - 1) & 7;
3689: u.i = val;
1.1.1.7 root 3690: env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
1.1 root 3691: env->fpstt = new_fpstt;
3692: env->fptags[new_fpstt] = 0; /* validate stack entry */
3693: }
3694:
3695: void helper_fildl_ST0(int32_t val)
3696: {
3697: int new_fpstt;
3698: new_fpstt = (env->fpstt - 1) & 7;
1.1.1.7 root 3699: env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
1.1 root 3700: env->fpstt = new_fpstt;
3701: env->fptags[new_fpstt] = 0; /* validate stack entry */
3702: }
3703:
3704: void helper_fildll_ST0(int64_t val)
3705: {
3706: int new_fpstt;
3707: new_fpstt = (env->fpstt - 1) & 7;
1.1.1.7 root 3708: env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
1.1 root 3709: env->fpstt = new_fpstt;
3710: env->fptags[new_fpstt] = 0; /* validate stack entry */
3711: }
3712:
3713: uint32_t helper_fsts_ST0(void)
3714: {
3715: union {
3716: float32 f;
3717: uint32_t i;
3718: } u;
1.1.1.7 root 3719: u.f = floatx80_to_float32(ST0, &env->fp_status);
1.1 root 3720: return u.i;
3721: }
3722:
3723: uint64_t helper_fstl_ST0(void)
3724: {
3725: union {
3726: float64 f;
3727: uint64_t i;
3728: } u;
1.1.1.7 root 3729: u.f = floatx80_to_float64(ST0, &env->fp_status);
1.1 root 3730: return u.i;
3731: }
3732:
3733: int32_t helper_fist_ST0(void)
3734: {
3735: int32_t val;
1.1.1.7 root 3736: val = floatx80_to_int32(ST0, &env->fp_status);
1.1 root 3737: if (val != (int16_t)val)
3738: val = -32768;
3739: return val;
3740: }
3741:
3742: int32_t helper_fistl_ST0(void)
3743: {
3744: int32_t val;
1.1.1.7 root 3745: val = floatx80_to_int32(ST0, &env->fp_status);
1.1 root 3746: return val;
3747: }
3748:
3749: int64_t helper_fistll_ST0(void)
3750: {
3751: int64_t val;
1.1.1.7 root 3752: val = floatx80_to_int64(ST0, &env->fp_status);
1.1 root 3753: return val;
3754: }
3755:
3756: int32_t helper_fistt_ST0(void)
3757: {
3758: int32_t val;
1.1.1.7 root 3759: val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
1.1 root 3760: if (val != (int16_t)val)
3761: val = -32768;
3762: return val;
3763: }
3764:
3765: int32_t helper_fisttl_ST0(void)
3766: {
3767: int32_t val;
1.1.1.7 root 3768: val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
1.1 root 3769: return val;
3770: }
3771:
3772: int64_t helper_fisttll_ST0(void)
3773: {
3774: int64_t val;
1.1.1.7 root 3775: val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
1.1 root 3776: return val;
3777: }
3778:
3779: void helper_fldt_ST0(target_ulong ptr)
3780: {
3781: int new_fpstt;
3782: new_fpstt = (env->fpstt - 1) & 7;
3783: env->fpregs[new_fpstt].d = helper_fldt(ptr);
3784: env->fpstt = new_fpstt;
3785: env->fptags[new_fpstt] = 0; /* validate stack entry */
3786: }
3787:
3788: void helper_fstt_ST0(target_ulong ptr)
3789: {
3790: helper_fstt(ST0, ptr);
3791: }
3792:
3793: void helper_fpush(void)
3794: {
3795: fpush();
3796: }
3797:
3798: void helper_fpop(void)
3799: {
3800: fpop();
3801: }
3802:
3803: void helper_fdecstp(void)
3804: {
3805: env->fpstt = (env->fpstt - 1) & 7;
3806: env->fpus &= (~0x4700);
3807: }
3808:
3809: void helper_fincstp(void)
3810: {
3811: env->fpstt = (env->fpstt + 1) & 7;
3812: env->fpus &= (~0x4700);
3813: }
3814:
3815: /* FPU move */
3816:
3817: void helper_ffree_STN(int st_index)
3818: {
3819: env->fptags[(env->fpstt + st_index) & 7] = 1;
3820: }
3821:
3822: void helper_fmov_ST0_FT0(void)
3823: {
3824: ST0 = FT0;
3825: }
3826:
3827: void helper_fmov_FT0_STN(int st_index)
3828: {
3829: FT0 = ST(st_index);
3830: }
3831:
3832: void helper_fmov_ST0_STN(int st_index)
3833: {
3834: ST0 = ST(st_index);
3835: }
3836:
3837: void helper_fmov_STN_ST0(int st_index)
3838: {
3839: ST(st_index) = ST0;
3840: }
3841:
3842: void helper_fxchg_ST0_STN(int st_index)
3843: {
1.1.1.7 root 3844: floatx80 tmp;
1.1 root 3845: tmp = ST(st_index);
3846: ST(st_index) = ST0;
3847: ST0 = tmp;
3848: }
3849:
3850: /* FPU operations */
3851:
3852: static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
3853:
3854: void helper_fcom_ST0_FT0(void)
3855: {
3856: int ret;
3857:
1.1.1.7 root 3858: ret = floatx80_compare(ST0, FT0, &env->fp_status);
1.1 root 3859: env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
3860: }
3861:
3862: void helper_fucom_ST0_FT0(void)
3863: {
3864: int ret;
3865:
1.1.1.7 root 3866: ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
1.1 root 3867: env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
3868: }
3869:
3870: static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
3871:
3872: void helper_fcomi_ST0_FT0(void)
3873: {
3874: int eflags;
3875: int ret;
3876:
1.1.1.7 root 3877: ret = floatx80_compare(ST0, FT0, &env->fp_status);
1.1 root 3878: eflags = helper_cc_compute_all(CC_OP);
3879: eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3880: CC_SRC = eflags;
3881: }
3882:
3883: void helper_fucomi_ST0_FT0(void)
3884: {
3885: int eflags;
3886: int ret;
3887:
1.1.1.7 root 3888: ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
1.1 root 3889: eflags = helper_cc_compute_all(CC_OP);
3890: eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3891: CC_SRC = eflags;
3892: }
3893:
3894: void helper_fadd_ST0_FT0(void)
3895: {
1.1.1.7 root 3896: ST0 = floatx80_add(ST0, FT0, &env->fp_status);
1.1 root 3897: }
3898:
3899: void helper_fmul_ST0_FT0(void)
3900: {
1.1.1.7 root 3901: ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
1.1 root 3902: }
3903:
3904: void helper_fsub_ST0_FT0(void)
3905: {
1.1.1.7 root 3906: ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
1.1 root 3907: }
3908:
3909: void helper_fsubr_ST0_FT0(void)
3910: {
1.1.1.7 root 3911: ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
1.1 root 3912: }
3913:
3914: void helper_fdiv_ST0_FT0(void)
3915: {
3916: ST0 = helper_fdiv(ST0, FT0);
3917: }
3918:
3919: void helper_fdivr_ST0_FT0(void)
3920: {
3921: ST0 = helper_fdiv(FT0, ST0);
3922: }
3923:
3924: /* fp operations between STN and ST0 */
3925:
3926: void helper_fadd_STN_ST0(int st_index)
3927: {
1.1.1.7 root 3928: ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
1.1 root 3929: }
3930:
3931: void helper_fmul_STN_ST0(int st_index)
3932: {
1.1.1.7 root 3933: ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
1.1 root 3934: }
3935:
3936: void helper_fsub_STN_ST0(int st_index)
3937: {
1.1.1.7 root 3938: ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
1.1 root 3939: }
3940:
3941: void helper_fsubr_STN_ST0(int st_index)
3942: {
1.1.1.7 root 3943: ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
1.1 root 3944: }
3945:
3946: void helper_fdiv_STN_ST0(int st_index)
3947: {
1.1.1.7 root 3948: floatx80 *p;
1.1 root 3949: p = &ST(st_index);
3950: *p = helper_fdiv(*p, ST0);
3951: }
3952:
3953: void helper_fdivr_STN_ST0(int st_index)
3954: {
1.1.1.7 root 3955: floatx80 *p;
1.1 root 3956: p = &ST(st_index);
3957: *p = helper_fdiv(ST0, *p);
3958: }
3959:
3960: /* misc FPU operations */
3961: void helper_fchs_ST0(void)
3962: {
1.1.1.7 root 3963: ST0 = floatx80_chs(ST0);
1.1 root 3964: }
3965:
3966: void helper_fabs_ST0(void)
3967: {
1.1.1.7 root 3968: ST0 = floatx80_abs(ST0);
1.1 root 3969: }
3970:
3971: void helper_fld1_ST0(void)
3972: {
1.1.1.7 root 3973: ST0 = floatx80_one;
1.1 root 3974: }
3975:
3976: void helper_fldl2t_ST0(void)
3977: {
1.1.1.7 root 3978: ST0 = floatx80_l2t;
1.1 root 3979: }
3980:
3981: void helper_fldl2e_ST0(void)
3982: {
1.1.1.7 root 3983: ST0 = floatx80_l2e;
1.1 root 3984: }
3985:
3986: void helper_fldpi_ST0(void)
3987: {
1.1.1.7 root 3988: ST0 = floatx80_pi;
1.1 root 3989: }
3990:
3991: void helper_fldlg2_ST0(void)
3992: {
1.1.1.7 root 3993: ST0 = floatx80_lg2;
1.1 root 3994: }
3995:
3996: void helper_fldln2_ST0(void)
3997: {
1.1.1.7 root 3998: ST0 = floatx80_ln2;
1.1 root 3999: }
4000:
4001: void helper_fldz_ST0(void)
4002: {
1.1.1.7 root 4003: ST0 = floatx80_zero;
1.1 root 4004: }
4005:
4006: void helper_fldz_FT0(void)
4007: {
1.1.1.7 root 4008: FT0 = floatx80_zero;
1.1 root 4009: }
4010:
4011: uint32_t helper_fnstsw(void)
4012: {
4013: return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4014: }
4015:
4016: uint32_t helper_fnstcw(void)
4017: {
4018: return env->fpuc;
4019: }
4020:
4021: static void update_fp_status(void)
4022: {
4023: int rnd_type;
4024:
4025: /* set rounding mode */
1.1.1.9 ! root 4026: switch(env->fpuc & FPU_RC_MASK) {
1.1 root 4027: default:
1.1.1.9 ! root 4028: case FPU_RC_NEAR:
1.1 root 4029: rnd_type = float_round_nearest_even;
4030: break;
1.1.1.9 ! root 4031: case FPU_RC_DOWN:
1.1 root 4032: rnd_type = float_round_down;
4033: break;
1.1.1.9 ! root 4034: case FPU_RC_UP:
1.1 root 4035: rnd_type = float_round_up;
4036: break;
1.1.1.9 ! root 4037: case FPU_RC_CHOP:
1.1 root 4038: rnd_type = float_round_to_zero;
4039: break;
4040: }
4041: set_float_rounding_mode(rnd_type, &env->fp_status);
4042: switch((env->fpuc >> 8) & 3) {
4043: case 0:
4044: rnd_type = 32;
4045: break;
4046: case 2:
4047: rnd_type = 64;
4048: break;
4049: case 3:
4050: default:
4051: rnd_type = 80;
4052: break;
4053: }
4054: set_floatx80_rounding_precision(rnd_type, &env->fp_status);
4055: }
4056:
4057: void helper_fldcw(uint32_t val)
4058: {
4059: env->fpuc = val;
4060: update_fp_status();
4061: }
4062:
4063: void helper_fclex(void)
4064: {
4065: env->fpus &= 0x7f00;
4066: }
4067:
4068: void helper_fwait(void)
4069: {
4070: if (env->fpus & FPUS_SE)
4071: fpu_raise_exception();
4072: }
4073:
4074: void helper_fninit(void)
4075: {
4076: env->fpus = 0;
4077: env->fpstt = 0;
4078: env->fpuc = 0x37f;
4079: env->fptags[0] = 1;
4080: env->fptags[1] = 1;
4081: env->fptags[2] = 1;
4082: env->fptags[3] = 1;
4083: env->fptags[4] = 1;
4084: env->fptags[5] = 1;
4085: env->fptags[6] = 1;
4086: env->fptags[7] = 1;
4087: }
4088:
4089: /* BCD ops */
4090:
4091: void helper_fbld_ST0(target_ulong ptr)
4092: {
1.1.1.7 root 4093: floatx80 tmp;
1.1 root 4094: uint64_t val;
4095: unsigned int v;
4096: int i;
4097:
4098: val = 0;
4099: for(i = 8; i >= 0; i--) {
4100: v = ldub(ptr + i);
4101: val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
4102: }
1.1.1.7 root 4103: tmp = int64_to_floatx80(val, &env->fp_status);
4104: if (ldub(ptr + 9) & 0x80) {
4105: floatx80_chs(tmp);
4106: }
1.1 root 4107: fpush();
4108: ST0 = tmp;
4109: }
4110:
4111: void helper_fbst_ST0(target_ulong ptr)
4112: {
4113: int v;
4114: target_ulong mem_ref, mem_end;
4115: int64_t val;
4116:
1.1.1.7 root 4117: val = floatx80_to_int64(ST0, &env->fp_status);
1.1 root 4118: mem_ref = ptr;
4119: mem_end = mem_ref + 9;
4120: if (val < 0) {
4121: stb(mem_end, 0x80);
4122: val = -val;
4123: } else {
4124: stb(mem_end, 0x00);
4125: }
4126: while (mem_ref < mem_end) {
4127: if (val == 0)
4128: break;
4129: v = val % 100;
4130: val = val / 100;
4131: v = ((v / 10) << 4) | (v % 10);
4132: stb(mem_ref++, v);
4133: }
4134: while (mem_ref < mem_end) {
4135: stb(mem_ref++, 0);
4136: }
4137: }
4138:
4139: void helper_f2xm1(void)
4140: {
1.1.1.7 root 4141: double val = floatx80_to_double(ST0);
4142: val = pow(2.0, val) - 1.0;
4143: ST0 = double_to_floatx80(val);
1.1 root 4144: }
4145:
4146: void helper_fyl2x(void)
4147: {
1.1.1.7 root 4148: double fptemp = floatx80_to_double(ST0);
1.1 root 4149:
4150: if (fptemp>0.0){
1.1.1.7 root 4151: fptemp = log(fptemp)/log(2.0); /* log2(ST) */
4152: fptemp *= floatx80_to_double(ST1);
4153: ST1 = double_to_floatx80(fptemp);
1.1 root 4154: fpop();
4155: } else {
4156: env->fpus &= (~0x4700);
4157: env->fpus |= 0x400;
4158: }
4159: }
4160:
4161: void helper_fptan(void)
4162: {
1.1.1.7 root 4163: double fptemp = floatx80_to_double(ST0);
1.1 root 4164:
4165: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4166: env->fpus |= 0x400;
4167: } else {
1.1.1.7 root 4168: fptemp = tan(fptemp);
4169: ST0 = double_to_floatx80(fptemp);
1.1 root 4170: fpush();
1.1.1.7 root 4171: ST0 = floatx80_one;
1.1 root 4172: env->fpus &= (~0x400); /* C2 <-- 0 */
4173: /* the above code is for |arg| < 2**52 only */
4174: }
4175: }
4176:
4177: void helper_fpatan(void)
4178: {
1.1.1.7 root 4179: double fptemp, fpsrcop;
1.1 root 4180:
1.1.1.7 root 4181: fpsrcop = floatx80_to_double(ST1);
4182: fptemp = floatx80_to_double(ST0);
4183: ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
1.1 root 4184: fpop();
4185: }
4186:
4187: void helper_fxtract(void)
4188: {
1.1.1.7 root 4189: CPU_LDoubleU temp;
1.1 root 4190:
4191: temp.d = ST0;
1.1.1.7 root 4192:
4193: if (floatx80_is_zero(ST0)) {
4194: /* Easy way to generate -inf and raising division by 0 exception */
4195: ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status);
4196: fpush();
4197: ST0 = temp.d;
4198: } else {
4199: int expdif;
4200:
4201: expdif = EXPD(temp) - EXPBIAS;
4202: /*DP exponent bias*/
4203: ST0 = int32_to_floatx80(expdif, &env->fp_status);
4204: fpush();
4205: BIASEXPONENT(temp);
4206: ST0 = temp.d;
4207: }
1.1 root 4208: }
4209:
4210: void helper_fprem1(void)
4211: {
1.1.1.7 root 4212: double st0, st1, dblq, fpsrcop, fptemp;
4213: CPU_LDoubleU fpsrcop1, fptemp1;
1.1 root 4214: int expdif;
4215: signed long long int q;
4216:
1.1.1.7 root 4217: st0 = floatx80_to_double(ST0);
4218: st1 = floatx80_to_double(ST1);
4219:
4220: if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
4221: ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
1.1 root 4222: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4223: return;
4224: }
4225:
1.1.1.7 root 4226: fpsrcop = st0;
4227: fptemp = st1;
4228: fpsrcop1.d = ST0;
4229: fptemp1.d = ST1;
1.1 root 4230: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4231:
4232: if (expdif < 0) {
4233: /* optimisation? taken from the AMD docs */
4234: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4235: /* ST0 is unchanged */
4236: return;
4237: }
4238:
4239: if (expdif < 53) {
4240: dblq = fpsrcop / fptemp;
4241: /* round dblq towards nearest integer */
4242: dblq = rint(dblq);
1.1.1.7 root 4243: st0 = fpsrcop - fptemp * dblq;
1.1 root 4244:
4245: /* convert dblq to q by truncating towards zero */
4246: if (dblq < 0.0)
4247: q = (signed long long int)(-dblq);
4248: else
4249: q = (signed long long int)dblq;
4250:
4251: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4252: /* (C0,C3,C1) <-- (q2,q1,q0) */
4253: env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4254: env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4255: env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4256: } else {
4257: env->fpus |= 0x400; /* C2 <-- 1 */
4258: fptemp = pow(2.0, expdif - 50);
1.1.1.7 root 4259: fpsrcop = (st0 / st1) / fptemp;
1.1 root 4260: /* fpsrcop = integer obtained by chopping */
4261: fpsrcop = (fpsrcop < 0.0) ?
4262: -(floor(fabs(fpsrcop))) : floor(fpsrcop);
1.1.1.7 root 4263: st0 -= (st1 * fpsrcop * fptemp);
1.1 root 4264: }
1.1.1.7 root 4265: ST0 = double_to_floatx80(st0);
1.1 root 4266: }
4267:
4268: void helper_fprem(void)
4269: {
1.1.1.7 root 4270: double st0, st1, dblq, fpsrcop, fptemp;
4271: CPU_LDoubleU fpsrcop1, fptemp1;
1.1 root 4272: int expdif;
4273: signed long long int q;
4274:
1.1.1.7 root 4275: st0 = floatx80_to_double(ST0);
4276: st1 = floatx80_to_double(ST1);
4277:
4278: if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
4279: ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
1.1 root 4280: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4281: return;
4282: }
4283:
1.1.1.7 root 4284: fpsrcop = st0;
4285: fptemp = st1;
4286: fpsrcop1.d = ST0;
4287: fptemp1.d = ST1;
1.1 root 4288: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4289:
4290: if (expdif < 0) {
4291: /* optimisation? taken from the AMD docs */
4292: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4293: /* ST0 is unchanged */
4294: return;
4295: }
4296:
4297: if ( expdif < 53 ) {
4298: dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
4299: /* round dblq towards zero */
4300: dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
1.1.1.7 root 4301: st0 = fpsrcop/*ST0*/ - fptemp * dblq;
1.1 root 4302:
4303: /* convert dblq to q by truncating towards zero */
4304: if (dblq < 0.0)
4305: q = (signed long long int)(-dblq);
4306: else
4307: q = (signed long long int)dblq;
4308:
4309: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4310: /* (C0,C3,C1) <-- (q2,q1,q0) */
4311: env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4312: env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4313: env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4314: } else {
4315: int N = 32 + (expdif % 32); /* as per AMD docs */
4316: env->fpus |= 0x400; /* C2 <-- 1 */
4317: fptemp = pow(2.0, (double)(expdif - N));
1.1.1.7 root 4318: fpsrcop = (st0 / st1) / fptemp;
1.1 root 4319: /* fpsrcop = integer obtained by chopping */
4320: fpsrcop = (fpsrcop < 0.0) ?
4321: -(floor(fabs(fpsrcop))) : floor(fpsrcop);
1.1.1.7 root 4322: st0 -= (st1 * fpsrcop * fptemp);
1.1 root 4323: }
1.1.1.7 root 4324: ST0 = double_to_floatx80(st0);
1.1 root 4325: }
4326:
4327: void helper_fyl2xp1(void)
4328: {
1.1.1.7 root 4329: double fptemp = floatx80_to_double(ST0);
1.1 root 4330:
4331: if ((fptemp+1.0)>0.0) {
4332: fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
1.1.1.7 root 4333: fptemp *= floatx80_to_double(ST1);
4334: ST1 = double_to_floatx80(fptemp);
1.1 root 4335: fpop();
4336: } else {
4337: env->fpus &= (~0x4700);
4338: env->fpus |= 0x400;
4339: }
4340: }
4341:
4342: void helper_fsqrt(void)
4343: {
1.1.1.7 root 4344: if (floatx80_is_neg(ST0)) {
1.1 root 4345: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4346: env->fpus |= 0x400;
4347: }
1.1.1.7 root 4348: ST0 = floatx80_sqrt(ST0, &env->fp_status);
1.1 root 4349: }
4350:
4351: void helper_fsincos(void)
4352: {
1.1.1.7 root 4353: double fptemp = floatx80_to_double(ST0);
1.1 root 4354:
4355: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4356: env->fpus |= 0x400;
4357: } else {
1.1.1.7 root 4358: ST0 = double_to_floatx80(sin(fptemp));
1.1 root 4359: fpush();
1.1.1.7 root 4360: ST0 = double_to_floatx80(cos(fptemp));
1.1 root 4361: env->fpus &= (~0x400); /* C2 <-- 0 */
4362: /* the above code is for |arg| < 2**63 only */
4363: }
4364: }
4365:
4366: void helper_frndint(void)
4367: {
1.1.1.7 root 4368: ST0 = floatx80_round_to_int(ST0, &env->fp_status);
1.1 root 4369: }
4370:
4371: void helper_fscale(void)
4372: {
1.1.1.7 root 4373: if (floatx80_is_any_nan(ST1)) {
4374: ST0 = ST1;
4375: } else {
4376: int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
4377: ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
4378: }
1.1 root 4379: }
4380:
4381: void helper_fsin(void)
4382: {
1.1.1.7 root 4383: double fptemp = floatx80_to_double(ST0);
1.1 root 4384:
4385: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4386: env->fpus |= 0x400;
4387: } else {
1.1.1.7 root 4388: ST0 = double_to_floatx80(sin(fptemp));
1.1 root 4389: env->fpus &= (~0x400); /* C2 <-- 0 */
4390: /* the above code is for |arg| < 2**53 only */
4391: }
4392: }
4393:
4394: void helper_fcos(void)
4395: {
1.1.1.7 root 4396: double fptemp = floatx80_to_double(ST0);
1.1 root 4397:
4398: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4399: env->fpus |= 0x400;
4400: } else {
1.1.1.7 root 4401: ST0 = double_to_floatx80(cos(fptemp));
1.1 root 4402: env->fpus &= (~0x400); /* C2 <-- 0 */
4403: /* the above code is for |arg5 < 2**63 only */
4404: }
4405: }
4406:
4407: void helper_fxam_ST0(void)
4408: {
1.1.1.7 root 4409: CPU_LDoubleU temp;
1.1 root 4410: int expdif;
4411:
4412: temp.d = ST0;
4413:
4414: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4415: if (SIGND(temp))
4416: env->fpus |= 0x200; /* C1 <-- 1 */
4417:
4418: /* XXX: test fptags too */
4419: expdif = EXPD(temp);
4420: if (expdif == MAXEXPD) {
4421: if (MANTD(temp) == 0x8000000000000000ULL)
4422: env->fpus |= 0x500 /*Infinity*/;
4423: else
4424: env->fpus |= 0x100 /*NaN*/;
4425: } else if (expdif == 0) {
4426: if (MANTD(temp) == 0)
4427: env->fpus |= 0x4000 /*Zero*/;
4428: else
4429: env->fpus |= 0x4400 /*Denormal*/;
4430: } else {
4431: env->fpus |= 0x400;
4432: }
4433: }
4434:
4435: void helper_fstenv(target_ulong ptr, int data32)
4436: {
4437: int fpus, fptag, exp, i;
4438: uint64_t mant;
1.1.1.7 root 4439: CPU_LDoubleU tmp;
1.1 root 4440:
4441: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4442: fptag = 0;
4443: for (i=7; i>=0; i--) {
4444: fptag <<= 2;
4445: if (env->fptags[i]) {
4446: fptag |= 3;
4447: } else {
4448: tmp.d = env->fpregs[i].d;
4449: exp = EXPD(tmp);
4450: mant = MANTD(tmp);
4451: if (exp == 0 && mant == 0) {
4452: /* zero */
4453: fptag |= 1;
4454: } else if (exp == 0 || exp == MAXEXPD
4455: || (mant & (1LL << 63)) == 0
4456: ) {
4457: /* NaNs, infinity, denormal */
4458: fptag |= 2;
4459: }
4460: }
4461: }
4462: if (data32) {
4463: /* 32 bit */
4464: stl(ptr, env->fpuc);
4465: stl(ptr + 4, fpus);
4466: stl(ptr + 8, fptag);
4467: stl(ptr + 12, 0); /* fpip */
4468: stl(ptr + 16, 0); /* fpcs */
4469: stl(ptr + 20, 0); /* fpoo */
4470: stl(ptr + 24, 0); /* fpos */
4471: } else {
4472: /* 16 bit */
4473: stw(ptr, env->fpuc);
4474: stw(ptr + 2, fpus);
4475: stw(ptr + 4, fptag);
4476: stw(ptr + 6, 0);
4477: stw(ptr + 8, 0);
4478: stw(ptr + 10, 0);
4479: stw(ptr + 12, 0);
4480: }
4481: }
4482:
4483: void helper_fldenv(target_ulong ptr, int data32)
4484: {
4485: int i, fpus, fptag;
4486:
4487: if (data32) {
4488: env->fpuc = lduw(ptr);
4489: fpus = lduw(ptr + 4);
4490: fptag = lduw(ptr + 8);
4491: }
4492: else {
4493: env->fpuc = lduw(ptr);
4494: fpus = lduw(ptr + 2);
4495: fptag = lduw(ptr + 4);
4496: }
4497: env->fpstt = (fpus >> 11) & 7;
4498: env->fpus = fpus & ~0x3800;
4499: for(i = 0;i < 8; i++) {
4500: env->fptags[i] = ((fptag & 3) == 3);
4501: fptag >>= 2;
4502: }
4503: }
4504:
4505: void helper_fsave(target_ulong ptr, int data32)
4506: {
1.1.1.7 root 4507: floatx80 tmp;
1.1 root 4508: int i;
4509:
4510: helper_fstenv(ptr, data32);
4511:
4512: ptr += (14 << data32);
4513: for(i = 0;i < 8; i++) {
4514: tmp = ST(i);
4515: helper_fstt(tmp, ptr);
4516: ptr += 10;
4517: }
4518:
4519: /* fninit */
4520: env->fpus = 0;
4521: env->fpstt = 0;
4522: env->fpuc = 0x37f;
4523: env->fptags[0] = 1;
4524: env->fptags[1] = 1;
4525: env->fptags[2] = 1;
4526: env->fptags[3] = 1;
4527: env->fptags[4] = 1;
4528: env->fptags[5] = 1;
4529: env->fptags[6] = 1;
4530: env->fptags[7] = 1;
4531: }
4532:
4533: void helper_frstor(target_ulong ptr, int data32)
4534: {
1.1.1.7 root 4535: floatx80 tmp;
1.1 root 4536: int i;
4537:
4538: helper_fldenv(ptr, data32);
4539: ptr += (14 << data32);
4540:
4541: for(i = 0;i < 8; i++) {
4542: tmp = helper_fldt(ptr);
4543: ST(i) = tmp;
4544: ptr += 10;
4545: }
4546: }
4547:
1.1.1.8 root 4548:
4549: #if defined(CONFIG_USER_ONLY)
4550: void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
4551: {
4552: CPUX86State *saved_env;
4553:
4554: saved_env = env;
4555: env = s;
4556: if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
4557: selector &= 0xffff;
4558: cpu_x86_load_seg_cache(env, seg_reg, selector,
4559: (selector << 4), 0xffff, 0);
4560: } else {
4561: helper_load_seg(seg_reg, selector);
4562: }
4563: env = saved_env;
4564: }
4565:
4566: void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
4567: {
4568: CPUX86State *saved_env;
4569:
4570: saved_env = env;
4571: env = s;
4572:
4573: helper_fsave(ptr, data32);
4574:
4575: env = saved_env;
4576: }
4577:
4578: void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
4579: {
4580: CPUX86State *saved_env;
4581:
4582: saved_env = env;
4583: env = s;
4584:
4585: helper_frstor(ptr, data32);
4586:
4587: env = saved_env;
4588: }
4589: #endif
4590:
1.1 root 4591: void helper_fxsave(target_ulong ptr, int data64)
4592: {
4593: int fpus, fptag, i, nb_xmm_regs;
1.1.1.7 root 4594: floatx80 tmp;
1.1 root 4595: target_ulong addr;
4596:
1.1.1.4 root 4597: /* The operand must be 16 byte aligned */
4598: if (ptr & 0xf) {
4599: raise_exception(EXCP0D_GPF);
4600: }
4601:
1.1 root 4602: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4603: fptag = 0;
4604: for(i = 0; i < 8; i++) {
4605: fptag |= (env->fptags[i] << i);
4606: }
4607: stw(ptr, env->fpuc);
4608: stw(ptr + 2, fpus);
4609: stw(ptr + 4, fptag ^ 0xff);
4610: #ifdef TARGET_X86_64
4611: if (data64) {
4612: stq(ptr + 0x08, 0); /* rip */
4613: stq(ptr + 0x10, 0); /* rdp */
4614: } else
4615: #endif
4616: {
4617: stl(ptr + 0x08, 0); /* eip */
4618: stl(ptr + 0x0c, 0); /* sel */
4619: stl(ptr + 0x10, 0); /* dp */
4620: stl(ptr + 0x14, 0); /* sel */
4621: }
4622:
4623: addr = ptr + 0x20;
4624: for(i = 0;i < 8; i++) {
4625: tmp = ST(i);
4626: helper_fstt(tmp, addr);
4627: addr += 16;
4628: }
4629:
4630: if (env->cr[4] & CR4_OSFXSR_MASK) {
4631: /* XXX: finish it */
4632: stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4633: stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4634: if (env->hflags & HF_CS64_MASK)
4635: nb_xmm_regs = 16;
4636: else
4637: nb_xmm_regs = 8;
4638: addr = ptr + 0xa0;
4639: /* Fast FXSAVE leaves out the XMM registers */
4640: if (!(env->efer & MSR_EFER_FFXSR)
4641: || (env->hflags & HF_CPL_MASK)
4642: || !(env->hflags & HF_LMA_MASK)) {
4643: for(i = 0; i < nb_xmm_regs; i++) {
4644: stq(addr, env->xmm_regs[i].XMM_Q(0));
4645: stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4646: addr += 16;
4647: }
4648: }
4649: }
4650: }
4651:
4652: void helper_fxrstor(target_ulong ptr, int data64)
4653: {
4654: int i, fpus, fptag, nb_xmm_regs;
1.1.1.7 root 4655: floatx80 tmp;
1.1 root 4656: target_ulong addr;
4657:
1.1.1.4 root 4658: /* The operand must be 16 byte aligned */
4659: if (ptr & 0xf) {
4660: raise_exception(EXCP0D_GPF);
4661: }
4662:
1.1 root 4663: env->fpuc = lduw(ptr);
4664: fpus = lduw(ptr + 2);
4665: fptag = lduw(ptr + 4);
4666: env->fpstt = (fpus >> 11) & 7;
4667: env->fpus = fpus & ~0x3800;
4668: fptag ^= 0xff;
4669: for(i = 0;i < 8; i++) {
4670: env->fptags[i] = ((fptag >> i) & 1);
4671: }
4672:
4673: addr = ptr + 0x20;
4674: for(i = 0;i < 8; i++) {
4675: tmp = helper_fldt(addr);
4676: ST(i) = tmp;
4677: addr += 16;
4678: }
4679:
4680: if (env->cr[4] & CR4_OSFXSR_MASK) {
4681: /* XXX: finish it */
4682: env->mxcsr = ldl(ptr + 0x18);
4683: //ldl(ptr + 0x1c);
4684: if (env->hflags & HF_CS64_MASK)
4685: nb_xmm_regs = 16;
4686: else
4687: nb_xmm_regs = 8;
4688: addr = ptr + 0xa0;
4689: /* Fast FXRESTORE leaves out the XMM registers */
4690: if (!(env->efer & MSR_EFER_FFXSR)
4691: || (env->hflags & HF_CPL_MASK)
4692: || !(env->hflags & HF_LMA_MASK)) {
4693: for(i = 0; i < nb_xmm_regs; i++) {
4694: env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4695: env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4696: addr += 16;
4697: }
4698: }
4699: }
4700: }
4701:
1.1.1.7 root 4702: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
1.1 root 4703: {
1.1.1.7 root 4704: CPU_LDoubleU temp;
1.1 root 4705:
4706: temp.d = f;
4707: *pmant = temp.l.lower;
4708: *pexp = temp.l.upper;
4709: }
4710:
1.1.1.7 root 4711: floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
1.1 root 4712: {
1.1.1.7 root 4713: CPU_LDoubleU temp;
1.1 root 4714:
4715: temp.l.upper = upper;
4716: temp.l.lower = mant;
4717: return temp.d;
4718: }
4719:
4720: #ifdef TARGET_X86_64
4721:
4722: //#define DEBUG_MULDIV
4723:
4724: static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4725: {
4726: *plow += a;
4727: /* carry test */
4728: if (*plow < a)
4729: (*phigh)++;
4730: *phigh += b;
4731: }
4732:
4733: static void neg128(uint64_t *plow, uint64_t *phigh)
4734: {
4735: *plow = ~ *plow;
4736: *phigh = ~ *phigh;
4737: add128(plow, phigh, 1, 0);
4738: }
4739:
4740: /* return TRUE if overflow */
4741: static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4742: {
4743: uint64_t q, r, a1, a0;
4744: int i, qb, ab;
4745:
4746: a0 = *plow;
4747: a1 = *phigh;
4748: if (a1 == 0) {
4749: q = a0 / b;
4750: r = a0 % b;
4751: *plow = q;
4752: *phigh = r;
4753: } else {
4754: if (a1 >= b)
4755: return 1;
4756: /* XXX: use a better algorithm */
4757: for(i = 0; i < 64; i++) {
4758: ab = a1 >> 63;
4759: a1 = (a1 << 1) | (a0 >> 63);
4760: if (ab || a1 >= b) {
4761: a1 -= b;
4762: qb = 1;
4763: } else {
4764: qb = 0;
4765: }
4766: a0 = (a0 << 1) | qb;
4767: }
4768: #if defined(DEBUG_MULDIV)
4769: printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
4770: *phigh, *plow, b, a0, a1);
4771: #endif
4772: *plow = a0;
4773: *phigh = a1;
4774: }
4775: return 0;
4776: }
4777:
4778: /* return TRUE if overflow */
4779: static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
4780: {
4781: int sa, sb;
4782: sa = ((int64_t)*phigh < 0);
4783: if (sa)
4784: neg128(plow, phigh);
4785: sb = (b < 0);
4786: if (sb)
4787: b = -b;
4788: if (div64(plow, phigh, b) != 0)
4789: return 1;
4790: if (sa ^ sb) {
4791: if (*plow > (1ULL << 63))
4792: return 1;
4793: *plow = - *plow;
4794: } else {
4795: if (*plow >= (1ULL << 63))
4796: return 1;
4797: }
4798: if (sa)
4799: *phigh = - *phigh;
4800: return 0;
4801: }
4802:
4803: void helper_mulq_EAX_T0(target_ulong t0)
4804: {
4805: uint64_t r0, r1;
4806:
4807: mulu64(&r0, &r1, EAX, t0);
4808: EAX = r0;
4809: EDX = r1;
4810: CC_DST = r0;
4811: CC_SRC = r1;
4812: }
4813:
4814: void helper_imulq_EAX_T0(target_ulong t0)
4815: {
4816: uint64_t r0, r1;
4817:
4818: muls64(&r0, &r1, EAX, t0);
4819: EAX = r0;
4820: EDX = r1;
4821: CC_DST = r0;
4822: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4823: }
4824:
4825: target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
4826: {
4827: uint64_t r0, r1;
4828:
4829: muls64(&r0, &r1, t0, t1);
4830: CC_DST = r0;
4831: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4832: return r0;
4833: }
4834:
4835: void helper_divq_EAX(target_ulong t0)
4836: {
4837: uint64_t r0, r1;
4838: if (t0 == 0) {
4839: raise_exception(EXCP00_DIVZ);
4840: }
4841: r0 = EAX;
4842: r1 = EDX;
4843: if (div64(&r0, &r1, t0))
4844: raise_exception(EXCP00_DIVZ);
4845: EAX = r0;
4846: EDX = r1;
4847: }
4848:
4849: void helper_idivq_EAX(target_ulong t0)
4850: {
4851: uint64_t r0, r1;
4852: if (t0 == 0) {
4853: raise_exception(EXCP00_DIVZ);
4854: }
4855: r0 = EAX;
4856: r1 = EDX;
4857: if (idiv64(&r0, &r1, t0))
4858: raise_exception(EXCP00_DIVZ);
4859: EAX = r0;
4860: EDX = r1;
4861: }
4862: #endif
4863:
4864: static void do_hlt(void)
4865: {
4866: env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
4867: env->halted = 1;
4868: env->exception_index = EXCP_HLT;
1.1.1.7 root 4869: cpu_loop_exit(env);
1.1 root 4870: }
4871:
4872: void helper_hlt(int next_eip_addend)
4873: {
4874: helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
4875: EIP += next_eip_addend;
4876:
4877: do_hlt();
4878: }
4879:
4880: void helper_monitor(target_ulong ptr)
4881: {
4882: if ((uint32_t)ECX != 0)
4883: raise_exception(EXCP0D_GPF);
4884: /* XXX: store address ? */
4885: helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
4886: }
4887:
4888: void helper_mwait(int next_eip_addend)
4889: {
4890: if ((uint32_t)ECX != 0)
4891: raise_exception(EXCP0D_GPF);
4892: helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
4893: EIP += next_eip_addend;
4894:
4895: /* XXX: not complete but not completely erroneous */
4896: if (env->cpu_index != 0 || env->next_cpu != NULL) {
4897: /* more than one CPU: do not sleep because another CPU may
4898: wake this one */
4899: } else {
4900: do_hlt();
4901: }
4902: }
4903:
4904: void helper_debug(void)
4905: {
4906: env->exception_index = EXCP_DEBUG;
1.1.1.7 root 4907: cpu_loop_exit(env);
1.1 root 4908: }
4909:
1.1.1.3 root 4910: void helper_reset_rf(void)
4911: {
4912: env->eflags &= ~RF_MASK;
4913: }
4914:
1.1 root 4915: void helper_raise_interrupt(int intno, int next_eip_addend)
4916: {
4917: raise_interrupt(intno, 1, 0, next_eip_addend);
4918: }
4919:
4920: void helper_raise_exception(int exception_index)
4921: {
4922: raise_exception(exception_index);
4923: }
4924:
4925: void helper_cli(void)
4926: {
4927: env->eflags &= ~IF_MASK;
4928: }
4929:
4930: void helper_sti(void)
4931: {
4932: env->eflags |= IF_MASK;
4933: }
4934:
4935: #if 0
4936: /* vm86plus instructions */
4937: void helper_cli_vm(void)
4938: {
4939: env->eflags &= ~VIF_MASK;
4940: }
4941:
4942: void helper_sti_vm(void)
4943: {
4944: env->eflags |= VIF_MASK;
4945: if (env->eflags & VIP_MASK) {
4946: raise_exception(EXCP0D_GPF);
4947: }
4948: }
4949: #endif
4950:
4951: void helper_set_inhibit_irq(void)
4952: {
4953: env->hflags |= HF_INHIBIT_IRQ_MASK;
4954: }
4955:
4956: void helper_reset_inhibit_irq(void)
4957: {
4958: env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4959: }
4960:
4961: void helper_boundw(target_ulong a0, int v)
4962: {
4963: int low, high;
4964: low = ldsw(a0);
4965: high = ldsw(a0 + 2);
4966: v = (int16_t)v;
4967: if (v < low || v > high) {
4968: raise_exception(EXCP05_BOUND);
4969: }
4970: }
4971:
4972: void helper_boundl(target_ulong a0, int v)
4973: {
4974: int low, high;
4975: low = ldl(a0);
4976: high = ldl(a0 + 4);
4977: if (v < low || v > high) {
4978: raise_exception(EXCP05_BOUND);
4979: }
4980: }
4981:
4982: #if !defined(CONFIG_USER_ONLY)
4983:
4984: #define MMUSUFFIX _mmu
4985:
4986: #define SHIFT 0
4987: #include "softmmu_template.h"
4988:
4989: #define SHIFT 1
4990: #include "softmmu_template.h"
4991:
4992: #define SHIFT 2
4993: #include "softmmu_template.h"
4994:
4995: #define SHIFT 3
4996: #include "softmmu_template.h"
4997:
4998: #endif
4999:
5000: #if !defined(CONFIG_USER_ONLY)
5001: /* try to fill the TLB and return an exception if error. If retaddr is
5002: NULL, it means that the function was called in C code (i.e. not
5003: from generated code or from helper.c) */
5004: /* XXX: fix it to restore all registers */
1.1.1.9 ! root 5005: void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
! 5006: uintptr_t retaddr)
1.1 root 5007: {
5008: TranslationBlock *tb;
5009: int ret;
5010: CPUX86State *saved_env;
5011:
5012: saved_env = env;
1.1.1.8 root 5013: env = env1;
1.1 root 5014:
1.1.1.8 root 5015: ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
1.1 root 5016: if (ret) {
5017: if (retaddr) {
5018: /* now we have a real cpu fault */
1.1.1.9 ! root 5019: tb = tb_find_pc(retaddr);
1.1 root 5020: if (tb) {
5021: /* the PC is inside the translated code. It means that we have
5022: a virtual CPU fault */
1.1.1.9 ! root 5023: cpu_restore_state(tb, env, retaddr);
1.1 root 5024: }
5025: }
5026: raise_exception_err(env->exception_index, env->error_code);
5027: }
5028: env = saved_env;
5029: }
5030: #endif
5031:
5032: /* Secure Virtual Machine helpers */
5033:
5034: #if defined(CONFIG_USER_ONLY)
5035:
5036: void helper_vmrun(int aflag, int next_eip_addend)
5037: {
5038: }
5039: void helper_vmmcall(void)
5040: {
5041: }
5042: void helper_vmload(int aflag)
5043: {
5044: }
5045: void helper_vmsave(int aflag)
5046: {
5047: }
5048: void helper_stgi(void)
5049: {
5050: }
5051: void helper_clgi(void)
5052: {
5053: }
5054: void helper_skinit(void)
5055: {
5056: }
5057: void helper_invlpga(int aflag)
5058: {
5059: }
5060: void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5061: {
5062: }
5063: void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5064: {
5065: }
5066:
1.1.1.9 ! root 5067: void svm_check_intercept(CPUX86State *env1, uint32_t type)
1.1.1.7 root 5068: {
5069: }
5070:
1.1 root 5071: void helper_svm_check_io(uint32_t port, uint32_t param,
5072: uint32_t next_eip_addend)
5073: {
5074: }
5075: #else
5076:
5077: static inline void svm_save_seg(target_phys_addr_t addr,
5078: const SegmentCache *sc)
5079: {
5080: stw_phys(addr + offsetof(struct vmcb_seg, selector),
5081: sc->selector);
5082: stq_phys(addr + offsetof(struct vmcb_seg, base),
5083: sc->base);
5084: stl_phys(addr + offsetof(struct vmcb_seg, limit),
5085: sc->limit);
5086: stw_phys(addr + offsetof(struct vmcb_seg, attrib),
5087: ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
5088: }
5089:
5090: static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
5091: {
5092: unsigned int flags;
5093:
5094: sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
5095: sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
5096: sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
5097: flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
5098: sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
5099: }
5100:
5101: static inline void svm_load_seg_cache(target_phys_addr_t addr,
1.1.1.9 ! root 5102: CPUX86State *env, int seg_reg)
1.1 root 5103: {
5104: SegmentCache sc1, *sc = &sc1;
5105: svm_load_seg(addr, sc);
5106: cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
5107: sc->base, sc->limit, sc->flags);
5108: }
5109:
5110: void helper_vmrun(int aflag, int next_eip_addend)
5111: {
5112: target_ulong addr;
5113: uint32_t event_inj;
5114: uint32_t int_ctl;
5115:
5116: helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
5117:
5118: if (aflag == 2)
5119: addr = EAX;
5120: else
5121: addr = (uint32_t)EAX;
5122:
5123: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
5124:
5125: env->vm_vmcb = addr;
5126:
5127: /* save the current CPU state in the hsave page */
5128: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5129: stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5130:
5131: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5132: stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5133:
5134: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
5135: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
5136: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
5137: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
5138: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
5139: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
5140:
5141: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
5142: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
5143:
5144: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
5145: &env->segs[R_ES]);
5146: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
5147: &env->segs[R_CS]);
5148: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
5149: &env->segs[R_SS]);
5150: svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
5151: &env->segs[R_DS]);
5152:
5153: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
5154: EIP + next_eip_addend);
5155: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
5156: stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
5157:
5158: /* load the interception bitmaps so we do not need to access the
5159: vmcb in svm mode */
5160: env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
5161: env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
5162: env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
5163: env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
5164: env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
5165: env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
5166:
5167: /* enable intercepts */
5168: env->hflags |= HF_SVMI_MASK;
5169:
5170: env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
5171:
5172: env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
5173: env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
5174:
5175: env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
5176: env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
5177:
5178: /* clear exit_info_2 so we behave like the real hardware */
5179: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
5180:
5181: cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
5182: cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
5183: cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
5184: env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
5185: int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5186: env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
5187: if (int_ctl & V_INTR_MASKING_MASK) {
5188: env->v_tpr = int_ctl & V_TPR_MASK;
5189: env->hflags2 |= HF2_VINTR_MASK;
5190: if (env->eflags & IF_MASK)
5191: env->hflags2 |= HF2_HIF_MASK;
5192: }
5193:
5194: cpu_load_efer(env,
5195: ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
5196: env->eflags = 0;
5197: load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
5198: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5199: CC_OP = CC_OP_EFLAGS;
5200:
5201: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
5202: env, R_ES);
5203: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5204: env, R_CS);
5205: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5206: env, R_SS);
5207: svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5208: env, R_DS);
5209:
5210: EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
5211: env->eip = EIP;
5212: ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
5213: EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
5214: env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
5215: env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
5216: cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
5217:
5218: /* FIXME: guest state consistency checks */
5219:
5220: switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
5221: case TLB_CONTROL_DO_NOTHING:
5222: break;
5223: case TLB_CONTROL_FLUSH_ALL_ASID:
5224: /* FIXME: this is not 100% correct but should work for now */
5225: tlb_flush(env, 1);
5226: break;
5227: }
5228:
5229: env->hflags2 |= HF2_GIF_MASK;
5230:
5231: if (int_ctl & V_IRQ_MASK) {
5232: env->interrupt_request |= CPU_INTERRUPT_VIRQ;
5233: }
5234:
5235: /* maybe we need to inject an event */
5236: event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
5237: if (event_inj & SVM_EVTINJ_VALID) {
5238: uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
5239: uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
5240: uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
5241:
5242: qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
5243: /* FIXME: need to implement valid_err */
5244: switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
5245: case SVM_EVTINJ_TYPE_INTR:
5246: env->exception_index = vector;
5247: env->error_code = event_inj_err;
5248: env->exception_is_int = 0;
5249: env->exception_next_eip = -1;
5250: qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
5251: /* XXX: is it always correct ? */
1.1.1.7 root 5252: do_interrupt_all(vector, 0, 0, 0, 1);
1.1 root 5253: break;
5254: case SVM_EVTINJ_TYPE_NMI:
5255: env->exception_index = EXCP02_NMI;
5256: env->error_code = event_inj_err;
5257: env->exception_is_int = 0;
5258: env->exception_next_eip = EIP;
5259: qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
1.1.1.7 root 5260: cpu_loop_exit(env);
1.1 root 5261: break;
5262: case SVM_EVTINJ_TYPE_EXEPT:
5263: env->exception_index = vector;
5264: env->error_code = event_inj_err;
5265: env->exception_is_int = 0;
5266: env->exception_next_eip = -1;
5267: qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
1.1.1.7 root 5268: cpu_loop_exit(env);
1.1 root 5269: break;
5270: case SVM_EVTINJ_TYPE_SOFT:
5271: env->exception_index = vector;
5272: env->error_code = event_inj_err;
5273: env->exception_is_int = 1;
5274: env->exception_next_eip = EIP;
5275: qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
1.1.1.7 root 5276: cpu_loop_exit(env);
1.1 root 5277: break;
5278: }
5279: qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
5280: }
5281: }
5282:
5283: void helper_vmmcall(void)
5284: {
5285: helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
5286: raise_exception(EXCP06_ILLOP);
5287: }
5288:
5289: void helper_vmload(int aflag)
5290: {
5291: target_ulong addr;
5292: helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
5293:
5294: if (aflag == 2)
5295: addr = EAX;
5296: else
5297: addr = (uint32_t)EAX;
5298:
5299: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5300: addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5301: env->segs[R_FS].base);
5302:
5303: svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
5304: env, R_FS);
5305: svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
5306: env, R_GS);
5307: svm_load_seg(addr + offsetof(struct vmcb, save.tr),
5308: &env->tr);
5309: svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
5310: &env->ldt);
5311:
5312: #ifdef TARGET_X86_64
5313: env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
5314: env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
5315: env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
5316: env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
5317: #endif
5318: env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
5319: env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
5320: env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
5321: env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
5322: }
5323:
5324: void helper_vmsave(int aflag)
5325: {
5326: target_ulong addr;
5327: helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
5328:
5329: if (aflag == 2)
5330: addr = EAX;
5331: else
5332: addr = (uint32_t)EAX;
5333:
5334: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5335: addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5336: env->segs[R_FS].base);
5337:
5338: svm_save_seg(addr + offsetof(struct vmcb, save.fs),
5339: &env->segs[R_FS]);
5340: svm_save_seg(addr + offsetof(struct vmcb, save.gs),
5341: &env->segs[R_GS]);
5342: svm_save_seg(addr + offsetof(struct vmcb, save.tr),
5343: &env->tr);
5344: svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
5345: &env->ldt);
5346:
5347: #ifdef TARGET_X86_64
5348: stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
5349: stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
5350: stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
5351: stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
5352: #endif
5353: stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5354: stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5355: stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5356: stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5357: }
5358:
5359: void helper_stgi(void)
5360: {
5361: helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
5362: env->hflags2 |= HF2_GIF_MASK;
5363: }
5364:
5365: void helper_clgi(void)
5366: {
5367: helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
5368: env->hflags2 &= ~HF2_GIF_MASK;
5369: }
5370:
5371: void helper_skinit(void)
5372: {
5373: helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
5374: /* XXX: not implemented */
5375: raise_exception(EXCP06_ILLOP);
5376: }
5377:
5378: void helper_invlpga(int aflag)
5379: {
5380: target_ulong addr;
5381: helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
5382:
5383: if (aflag == 2)
5384: addr = EAX;
5385: else
5386: addr = (uint32_t)EAX;
5387:
5388: /* XXX: could use the ASID to see if it is needed to do the
5389: flush */
5390: tlb_flush_page(env, addr);
5391: }
5392:
5393: void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5394: {
5395: if (likely(!(env->hflags & HF_SVMI_MASK)))
5396: return;
5397: switch(type) {
5398: case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
5399: if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
5400: helper_vmexit(type, param);
5401: }
5402: break;
5403: case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5404: if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
5405: helper_vmexit(type, param);
5406: }
5407: break;
5408: case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
5409: if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
5410: helper_vmexit(type, param);
5411: }
5412: break;
5413: case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
5414: if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
5415: helper_vmexit(type, param);
5416: }
5417: break;
5418: case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
5419: if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
5420: helper_vmexit(type, param);
5421: }
5422: break;
5423: case SVM_EXIT_MSR:
5424: if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
5425: /* FIXME: this should be read in at vmrun (faster this way?) */
5426: uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5427: uint32_t t0, t1;
5428: switch((uint32_t)ECX) {
5429: case 0 ... 0x1fff:
5430: t0 = (ECX * 2) % 8;
1.1.1.6 root 5431: t1 = (ECX * 2) / 8;
1.1 root 5432: break;
5433: case 0xc0000000 ... 0xc0001fff:
5434: t0 = (8192 + ECX - 0xc0000000) * 2;
5435: t1 = (t0 / 8);
5436: t0 %= 8;
5437: break;
5438: case 0xc0010000 ... 0xc0011fff:
5439: t0 = (16384 + ECX - 0xc0010000) * 2;
5440: t1 = (t0 / 8);
5441: t0 %= 8;
5442: break;
5443: default:
5444: helper_vmexit(type, param);
5445: t0 = 0;
5446: t1 = 0;
5447: break;
5448: }
5449: if (ldub_phys(addr + t1) & ((1 << param) << t0))
5450: helper_vmexit(type, param);
5451: }
5452: break;
5453: default:
5454: if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
5455: helper_vmexit(type, param);
5456: }
5457: break;
5458: }
5459: }
5460:
1.1.1.9 ! root 5461: void svm_check_intercept(CPUX86State *env1, uint32_t type)
1.1.1.7 root 5462: {
1.1.1.9 ! root 5463: CPUX86State *saved_env;
1.1.1.7 root 5464:
5465: saved_env = env;
5466: env = env1;
5467: helper_svm_check_intercept_param(type, 0);
5468: env = saved_env;
5469: }
5470:
1.1 root 5471: void helper_svm_check_io(uint32_t port, uint32_t param,
5472: uint32_t next_eip_addend)
5473: {
5474: if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
5475: /* FIXME: this should be read in at vmrun (faster this way?) */
5476: uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5477: uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5478: if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5479: /* next EIP */
5480: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
5481: env->eip + next_eip_addend);
5482: helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5483: }
5484: }
5485: }
5486:
5487: /* Note: currently only 32 bits of exit_code are used */
5488: void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5489: {
5490: uint32_t int_ctl;
5491:
5492: qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5493: exit_code, exit_info_1,
5494: ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5495: EIP);
5496:
5497: if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5498: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5499: env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5500: } else {
5501: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5502: }
5503:
5504: /* Save the VM state in the vmcb */
5505: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
5506: &env->segs[R_ES]);
5507: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5508: &env->segs[R_CS]);
5509: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5510: &env->segs[R_SS]);
5511: svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5512: &env->segs[R_DS]);
5513:
5514: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5515: stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5516:
5517: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5518: stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5519:
5520: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5521: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5522: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5523: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5524: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5525:
5526: int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5527: int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
5528: int_ctl |= env->v_tpr & V_TPR_MASK;
5529: if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
5530: int_ctl |= V_IRQ_MASK;
5531: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
5532:
5533: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5534: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5535: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5536: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5537: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5538: stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5539: stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5540:
5541: /* Reload the host state from vm_hsave */
5542: env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
5543: env->hflags &= ~HF_SVMI_MASK;
5544: env->intercept = 0;
5545: env->intercept_exceptions = 0;
5546: env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
5547: env->tsc_offset = 0;
5548:
5549: env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5550: env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5551:
5552: env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5553: env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5554:
5555: cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5556: cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5557: cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5558: /* we need to set the efer after the crs so the hidden flags get
5559: set properly */
5560: cpu_load_efer(env,
5561: ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
5562: env->eflags = 0;
5563: load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5564: ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5565: CC_OP = CC_OP_EFLAGS;
5566:
5567: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
5568: env, R_ES);
5569: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
5570: env, R_CS);
5571: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
5572: env, R_SS);
5573: svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
5574: env, R_DS);
5575:
5576: EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5577: ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5578: EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5579:
5580: env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5581: env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5582:
5583: /* other setups */
5584: cpu_x86_set_cpl(env, 0);
5585: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5586: stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5587:
1.1.1.3 root 5588: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
5589: ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
5590: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
5591: ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
1.1.1.5 root 5592: stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
1.1.1.3 root 5593:
1.1 root 5594: env->hflags2 &= ~HF2_GIF_MASK;
5595: /* FIXME: Resets the current ASID register to zero (host ASID). */
5596:
5597: /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5598:
5599: /* Clears the TSC_OFFSET inside the processor. */
5600:
5601: /* If the host is in PAE mode, the processor reloads the host's PDPEs
5602: from the page table indicated the host's CR3. If the PDPEs contain
5603: illegal state, the processor causes a shutdown. */
5604:
5605: /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5606: env->cr[0] |= CR0_PE_MASK;
5607: env->eflags &= ~VM_MASK;
5608:
5609: /* Disables all breakpoints in the host DR7 register. */
5610:
5611: /* Checks the reloaded host state for consistency. */
5612:
5613: /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5614: host's code segment or non-canonical (in the case of long mode), a
5615: #GP fault is delivered inside the host.) */
5616:
5617: /* remove any pending exception */
5618: env->exception_index = -1;
5619: env->error_code = 0;
5620: env->old_exception = -1;
5621:
1.1.1.7 root 5622: cpu_loop_exit(env);
1.1 root 5623: }
5624:
5625: #endif
5626:
5627: /* MMX/SSE */
5628: /* XXX: optimize by storing fptt and fptags in the static cpu state */
1.1.1.9 ! root 5629:
! 5630: #define SSE_DAZ 0x0040
! 5631: #define SSE_RC_MASK 0x6000
! 5632: #define SSE_RC_NEAR 0x0000
! 5633: #define SSE_RC_DOWN 0x2000
! 5634: #define SSE_RC_UP 0x4000
! 5635: #define SSE_RC_CHOP 0x6000
! 5636: #define SSE_FZ 0x8000
! 5637:
! 5638: static void update_sse_status(void)
! 5639: {
! 5640: int rnd_type;
! 5641:
! 5642: /* set rounding mode */
! 5643: switch(env->mxcsr & SSE_RC_MASK) {
! 5644: default:
! 5645: case SSE_RC_NEAR:
! 5646: rnd_type = float_round_nearest_even;
! 5647: break;
! 5648: case SSE_RC_DOWN:
! 5649: rnd_type = float_round_down;
! 5650: break;
! 5651: case SSE_RC_UP:
! 5652: rnd_type = float_round_up;
! 5653: break;
! 5654: case SSE_RC_CHOP:
! 5655: rnd_type = float_round_to_zero;
! 5656: break;
! 5657: }
! 5658: set_float_rounding_mode(rnd_type, &env->sse_status);
! 5659:
! 5660: /* set denormals are zero */
! 5661: set_flush_inputs_to_zero((env->mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
! 5662:
! 5663: /* set flush to zero */
! 5664: set_flush_to_zero((env->mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
! 5665: }
! 5666:
! 5667: void helper_ldmxcsr(uint32_t val)
! 5668: {
! 5669: env->mxcsr = val;
! 5670: update_sse_status();
! 5671: }
! 5672:
1.1 root 5673: void helper_enter_mmx(void)
5674: {
5675: env->fpstt = 0;
5676: *(uint32_t *)(env->fptags) = 0;
5677: *(uint32_t *)(env->fptags + 4) = 0;
5678: }
5679:
5680: void helper_emms(void)
5681: {
5682: /* set to empty state */
5683: *(uint32_t *)(env->fptags) = 0x01010101;
5684: *(uint32_t *)(env->fptags + 4) = 0x01010101;
5685: }
5686:
5687: /* XXX: suppress */
5688: void helper_movq(void *d, void *s)
5689: {
5690: *(uint64_t *)d = *(uint64_t *)s;
5691: }
5692:
5693: #define SHIFT 0
5694: #include "ops_sse.h"
5695:
5696: #define SHIFT 1
5697: #include "ops_sse.h"
5698:
5699: #define SHIFT 0
5700: #include "helper_template.h"
5701: #undef SHIFT
5702:
5703: #define SHIFT 1
5704: #include "helper_template.h"
5705: #undef SHIFT
5706:
5707: #define SHIFT 2
5708: #include "helper_template.h"
5709: #undef SHIFT
5710:
5711: #ifdef TARGET_X86_64
5712:
5713: #define SHIFT 3
5714: #include "helper_template.h"
5715: #undef SHIFT
5716:
5717: #endif
5718:
5719: /* bit operations */
5720: target_ulong helper_bsf(target_ulong t0)
5721: {
5722: int count;
5723: target_ulong res;
5724:
5725: res = t0;
5726: count = 0;
5727: while ((res & 1) == 0) {
5728: count++;
5729: res >>= 1;
5730: }
5731: return count;
5732: }
5733:
1.1.1.4 root 5734: target_ulong helper_lzcnt(target_ulong t0, int wordsize)
1.1 root 5735: {
5736: int count;
5737: target_ulong res, mask;
1.1.1.4 root 5738:
5739: if (wordsize > 0 && t0 == 0) {
5740: return wordsize;
5741: }
1.1 root 5742: res = t0;
5743: count = TARGET_LONG_BITS - 1;
5744: mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5745: while ((res & mask) == 0) {
5746: count--;
5747: res <<= 1;
5748: }
1.1.1.4 root 5749: if (wordsize > 0) {
5750: return wordsize - 1 - count;
5751: }
1.1 root 5752: return count;
5753: }
5754:
1.1.1.4 root 5755: target_ulong helper_bsr(target_ulong t0)
5756: {
5757: return helper_lzcnt(t0, 0);
5758: }
1.1 root 5759:
5760: static int compute_all_eflags(void)
5761: {
5762: return CC_SRC;
5763: }
5764:
5765: static int compute_c_eflags(void)
5766: {
5767: return CC_SRC & CC_C;
5768: }
5769:
5770: uint32_t helper_cc_compute_all(int op)
5771: {
5772: switch (op) {
5773: default: /* should never happen */ return 0;
5774:
5775: case CC_OP_EFLAGS: return compute_all_eflags();
5776:
5777: case CC_OP_MULB: return compute_all_mulb();
5778: case CC_OP_MULW: return compute_all_mulw();
5779: case CC_OP_MULL: return compute_all_mull();
5780:
5781: case CC_OP_ADDB: return compute_all_addb();
5782: case CC_OP_ADDW: return compute_all_addw();
5783: case CC_OP_ADDL: return compute_all_addl();
5784:
5785: case CC_OP_ADCB: return compute_all_adcb();
5786: case CC_OP_ADCW: return compute_all_adcw();
5787: case CC_OP_ADCL: return compute_all_adcl();
5788:
5789: case CC_OP_SUBB: return compute_all_subb();
5790: case CC_OP_SUBW: return compute_all_subw();
5791: case CC_OP_SUBL: return compute_all_subl();
5792:
5793: case CC_OP_SBBB: return compute_all_sbbb();
5794: case CC_OP_SBBW: return compute_all_sbbw();
5795: case CC_OP_SBBL: return compute_all_sbbl();
5796:
5797: case CC_OP_LOGICB: return compute_all_logicb();
5798: case CC_OP_LOGICW: return compute_all_logicw();
5799: case CC_OP_LOGICL: return compute_all_logicl();
5800:
5801: case CC_OP_INCB: return compute_all_incb();
5802: case CC_OP_INCW: return compute_all_incw();
5803: case CC_OP_INCL: return compute_all_incl();
5804:
5805: case CC_OP_DECB: return compute_all_decb();
5806: case CC_OP_DECW: return compute_all_decw();
5807: case CC_OP_DECL: return compute_all_decl();
5808:
5809: case CC_OP_SHLB: return compute_all_shlb();
5810: case CC_OP_SHLW: return compute_all_shlw();
5811: case CC_OP_SHLL: return compute_all_shll();
5812:
5813: case CC_OP_SARB: return compute_all_sarb();
5814: case CC_OP_SARW: return compute_all_sarw();
5815: case CC_OP_SARL: return compute_all_sarl();
5816:
5817: #ifdef TARGET_X86_64
5818: case CC_OP_MULQ: return compute_all_mulq();
5819:
5820: case CC_OP_ADDQ: return compute_all_addq();
5821:
5822: case CC_OP_ADCQ: return compute_all_adcq();
5823:
5824: case CC_OP_SUBQ: return compute_all_subq();
5825:
5826: case CC_OP_SBBQ: return compute_all_sbbq();
5827:
5828: case CC_OP_LOGICQ: return compute_all_logicq();
5829:
5830: case CC_OP_INCQ: return compute_all_incq();
5831:
5832: case CC_OP_DECQ: return compute_all_decq();
5833:
5834: case CC_OP_SHLQ: return compute_all_shlq();
5835:
5836: case CC_OP_SARQ: return compute_all_sarq();
5837: #endif
5838: }
5839: }
5840:
1.1.1.9 ! root 5841: uint32_t cpu_cc_compute_all(CPUX86State *env1, int op)
1.1.1.7 root 5842: {
1.1.1.9 ! root 5843: CPUX86State *saved_env;
1.1.1.7 root 5844: uint32_t ret;
5845:
5846: saved_env = env;
5847: env = env1;
5848: ret = helper_cc_compute_all(op);
5849: env = saved_env;
5850: return ret;
5851: }
5852:
1.1 root 5853: uint32_t helper_cc_compute_c(int op)
5854: {
5855: switch (op) {
5856: default: /* should never happen */ return 0;
5857:
5858: case CC_OP_EFLAGS: return compute_c_eflags();
5859:
5860: case CC_OP_MULB: return compute_c_mull();
5861: case CC_OP_MULW: return compute_c_mull();
5862: case CC_OP_MULL: return compute_c_mull();
5863:
5864: case CC_OP_ADDB: return compute_c_addb();
5865: case CC_OP_ADDW: return compute_c_addw();
5866: case CC_OP_ADDL: return compute_c_addl();
5867:
5868: case CC_OP_ADCB: return compute_c_adcb();
5869: case CC_OP_ADCW: return compute_c_adcw();
5870: case CC_OP_ADCL: return compute_c_adcl();
5871:
5872: case CC_OP_SUBB: return compute_c_subb();
5873: case CC_OP_SUBW: return compute_c_subw();
5874: case CC_OP_SUBL: return compute_c_subl();
5875:
5876: case CC_OP_SBBB: return compute_c_sbbb();
5877: case CC_OP_SBBW: return compute_c_sbbw();
5878: case CC_OP_SBBL: return compute_c_sbbl();
5879:
5880: case CC_OP_LOGICB: return compute_c_logicb();
5881: case CC_OP_LOGICW: return compute_c_logicw();
5882: case CC_OP_LOGICL: return compute_c_logicl();
5883:
5884: case CC_OP_INCB: return compute_c_incl();
5885: case CC_OP_INCW: return compute_c_incl();
5886: case CC_OP_INCL: return compute_c_incl();
5887:
5888: case CC_OP_DECB: return compute_c_incl();
5889: case CC_OP_DECW: return compute_c_incl();
5890: case CC_OP_DECL: return compute_c_incl();
5891:
5892: case CC_OP_SHLB: return compute_c_shlb();
5893: case CC_OP_SHLW: return compute_c_shlw();
5894: case CC_OP_SHLL: return compute_c_shll();
5895:
5896: case CC_OP_SARB: return compute_c_sarl();
5897: case CC_OP_SARW: return compute_c_sarl();
5898: case CC_OP_SARL: return compute_c_sarl();
5899:
5900: #ifdef TARGET_X86_64
5901: case CC_OP_MULQ: return compute_c_mull();
5902:
5903: case CC_OP_ADDQ: return compute_c_addq();
5904:
5905: case CC_OP_ADCQ: return compute_c_adcq();
5906:
5907: case CC_OP_SUBQ: return compute_c_subq();
5908:
5909: case CC_OP_SBBQ: return compute_c_sbbq();
5910:
5911: case CC_OP_LOGICQ: return compute_c_logicq();
5912:
5913: case CC_OP_INCQ: return compute_c_incl();
5914:
5915: case CC_OP_DECQ: return compute_c_incl();
5916:
5917: case CC_OP_SHLQ: return compute_c_shlq();
5918:
5919: case CC_OP_SARQ: return compute_c_sarl();
5920: #endif
5921: }
5922: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.