|
|
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
17: * License along with this library; if not, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: */
20: #include "exec.h"
21:
22: //#define DEBUG_PCALL
23:
24: #if 0
25: #define raise_exception_err(a, b)\
26: do {\
1.1.1.3 ! root 27: if (logfile)\
! 28: fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
1.1 root 29: (raise_exception_err)(a, b);\
30: } while (0)
31: #endif
32:
33: const uint8_t parity_table[256] = {
34: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
35: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
36: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
40: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
43: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
45: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
52: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
58: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
59: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
60: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
61: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
62: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
64: CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
65: 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
66: };
67:
68: /* modulo 17 table */
69: const uint8_t rclw_table[32] = {
70: 0, 1, 2, 3, 4, 5, 6, 7,
71: 8, 9,10,11,12,13,14,15,
72: 16, 0, 1, 2, 3, 4, 5, 6,
73: 7, 8, 9,10,11,12,13,14,
74: };
75:
76: /* modulo 9 table */
77: const uint8_t rclb_table[32] = {
78: 0, 1, 2, 3, 4, 5, 6, 7,
79: 8, 0, 1, 2, 3, 4, 5, 6,
80: 7, 8, 0, 1, 2, 3, 4, 5,
81: 6, 7, 8, 0, 1, 2, 3, 4,
82: };
83:
84: const CPU86_LDouble f15rk[7] =
85: {
86: 0.00000000000000000000L,
87: 1.00000000000000000000L,
88: 3.14159265358979323851L, /*pi*/
89: 0.30102999566398119523L, /*lg2*/
90: 0.69314718055994530943L, /*ln2*/
91: 1.44269504088896340739L, /*l2e*/
92: 3.32192809488736234781L, /*l2t*/
93: };
94:
95: /* thread support */
96:
97: spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
98:
99: void cpu_lock(void)
100: {
101: spin_lock(&global_cpu_lock);
102: }
103:
104: void cpu_unlock(void)
105: {
106: spin_unlock(&global_cpu_lock);
107: }
108:
109: void cpu_loop_exit(void)
110: {
111: /* NOTE: the register at this point must be saved by hand because
112: longjmp restore them */
113: regs_to_env();
114: longjmp(env->jmp_env, 1);
115: }
116:
117: /* return non zero if error */
118: static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
119: int selector)
120: {
121: SegmentCache *dt;
122: int index;
123: target_ulong ptr;
124:
125: if (selector & 0x4)
126: dt = &env->ldt;
127: else
128: dt = &env->gdt;
129: index = selector & ~7;
130: if ((index + 7) > dt->limit)
131: return -1;
132: ptr = dt->base + index;
133: *e1_ptr = ldl_kernel(ptr);
134: *e2_ptr = ldl_kernel(ptr + 4);
135: return 0;
136: }
137:
138: static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
139: {
140: unsigned int limit;
141: limit = (e1 & 0xffff) | (e2 & 0x000f0000);
142: if (e2 & DESC_G_MASK)
143: limit = (limit << 12) | 0xfff;
144: return limit;
145: }
146:
147: static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
148: {
149: return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
150: }
151:
152: static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
153: {
154: sc->base = get_seg_base(e1, e2);
155: sc->limit = get_seg_limit(e1, e2);
156: sc->flags = e2;
157: }
158:
159: /* init the segment cache in vm86 mode. */
160: static inline void load_seg_vm(int seg, int selector)
161: {
162: selector &= 0xffff;
163: cpu_x86_load_seg_cache(env, seg, selector,
164: (selector << 4), 0xffff, 0);
165: }
166:
167: static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
168: uint32_t *esp_ptr, int dpl)
169: {
170: int type, index, shift;
171:
172: #if 0
173: {
174: int i;
175: printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
176: for(i=0;i<env->tr.limit;i++) {
177: printf("%02x ", env->tr.base[i]);
178: if ((i & 7) == 7) printf("\n");
179: }
180: printf("\n");
181: }
182: #endif
183:
184: if (!(env->tr.flags & DESC_P_MASK))
185: cpu_abort(env, "invalid tss");
186: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
187: if ((type & 7) != 1)
188: cpu_abort(env, "invalid tss type");
189: shift = type >> 3;
190: index = (dpl * 4 + 2) << shift;
191: if (index + (4 << shift) - 1 > env->tr.limit)
192: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
193: if (shift == 0) {
194: *esp_ptr = lduw_kernel(env->tr.base + index);
195: *ss_ptr = lduw_kernel(env->tr.base + index + 2);
196: } else {
197: *esp_ptr = ldl_kernel(env->tr.base + index);
198: *ss_ptr = lduw_kernel(env->tr.base + index + 4);
199: }
200: }
201:
202: /* XXX: merge with load_seg() */
203: static void tss_load_seg(int seg_reg, int selector)
204: {
205: uint32_t e1, e2;
206: int rpl, dpl, cpl;
207:
208: if ((selector & 0xfffc) != 0) {
209: if (load_segment(&e1, &e2, selector) != 0)
210: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
211: if (!(e2 & DESC_S_MASK))
212: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
213: rpl = selector & 3;
214: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
215: cpl = env->hflags & HF_CPL_MASK;
216: if (seg_reg == R_CS) {
217: if (!(e2 & DESC_CS_MASK))
218: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
1.1.1.3 ! root 219: /* XXX: is it correct ? */
1.1 root 220: if (dpl != rpl)
221: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
222: if ((e2 & DESC_C_MASK) && dpl > rpl)
223: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
224: } else if (seg_reg == R_SS) {
225: /* SS must be writable data */
226: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
227: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
228: if (dpl != cpl || dpl != rpl)
229: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230: } else {
231: /* not readable code */
232: if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
233: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
234: /* if data or non conforming code, checks the rights */
235: if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
236: if (dpl < cpl || dpl < rpl)
237: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
238: }
239: }
240: if (!(e2 & DESC_P_MASK))
241: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
242: cpu_x86_load_seg_cache(env, seg_reg, selector,
243: get_seg_base(e1, e2),
244: get_seg_limit(e1, e2),
245: e2);
246: } else {
247: if (seg_reg == R_SS || seg_reg == R_CS)
248: raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
249: }
250: }
251:
252: #define SWITCH_TSS_JMP 0
253: #define SWITCH_TSS_IRET 1
254: #define SWITCH_TSS_CALL 2
255:
256: /* XXX: restore CPU state in registers (PowerPC case) */
257: static void switch_tss(int tss_selector,
258: uint32_t e1, uint32_t e2, int source,
259: uint32_t next_eip)
260: {
261: int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
262: target_ulong tss_base;
263: uint32_t new_regs[8], new_segs[6];
264: uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
265: uint32_t old_eflags, eflags_mask;
266: SegmentCache *dt;
267: int index;
268: target_ulong ptr;
269:
270: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
271: #ifdef DEBUG_PCALL
272: if (loglevel & CPU_LOG_PCALL)
273: fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
274: #endif
275:
276: /* if task gate, we read the TSS segment and we load it */
277: if (type == 5) {
278: if (!(e2 & DESC_P_MASK))
279: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
280: tss_selector = e1 >> 16;
281: if (tss_selector & 4)
282: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
283: if (load_segment(&e1, &e2, tss_selector) != 0)
284: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
285: if (e2 & DESC_S_MASK)
286: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
287: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
288: if ((type & 7) != 1)
289: raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
290: }
291:
292: if (!(e2 & DESC_P_MASK))
293: raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
294:
295: if (type & 8)
296: tss_limit_max = 103;
297: else
298: tss_limit_max = 43;
299: tss_limit = get_seg_limit(e1, e2);
300: tss_base = get_seg_base(e1, e2);
301: if ((tss_selector & 4) != 0 ||
302: tss_limit < tss_limit_max)
303: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
304: old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
305: if (old_type & 8)
306: old_tss_limit_max = 103;
307: else
308: old_tss_limit_max = 43;
309:
310: /* read all the registers from the new TSS */
311: if (type & 8) {
312: /* 32 bit */
313: new_cr3 = ldl_kernel(tss_base + 0x1c);
314: new_eip = ldl_kernel(tss_base + 0x20);
315: new_eflags = ldl_kernel(tss_base + 0x24);
316: for(i = 0; i < 8; i++)
317: new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
318: for(i = 0; i < 6; i++)
319: new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
320: new_ldt = lduw_kernel(tss_base + 0x60);
321: new_trap = ldl_kernel(tss_base + 0x64);
322: } else {
323: /* 16 bit */
324: new_cr3 = 0;
325: new_eip = lduw_kernel(tss_base + 0x0e);
326: new_eflags = lduw_kernel(tss_base + 0x10);
327: for(i = 0; i < 8; i++)
328: new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
329: for(i = 0; i < 4; i++)
330: new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
331: new_ldt = lduw_kernel(tss_base + 0x2a);
332: new_segs[R_FS] = 0;
333: new_segs[R_GS] = 0;
334: new_trap = 0;
335: }
336:
337: /* NOTE: we must avoid memory exceptions during the task switch,
338: so we make dummy accesses before */
339: /* XXX: it can still fail in some cases, so a bigger hack is
340: necessary to valid the TLB after having done the accesses */
341:
342: v1 = ldub_kernel(env->tr.base);
1.1.1.2 root 343: v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
1.1 root 344: stb_kernel(env->tr.base, v1);
345: stb_kernel(env->tr.base + old_tss_limit_max, v2);
346:
347: /* clear busy bit (it is restartable) */
348: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
349: target_ulong ptr;
350: uint32_t e2;
351: ptr = env->gdt.base + (env->tr.selector & ~7);
352: e2 = ldl_kernel(ptr + 4);
353: e2 &= ~DESC_TSS_BUSY_MASK;
354: stl_kernel(ptr + 4, e2);
355: }
356: old_eflags = compute_eflags();
357: if (source == SWITCH_TSS_IRET)
358: old_eflags &= ~NT_MASK;
359:
360: /* save the current state in the old TSS */
361: if (type & 8) {
362: /* 32 bit */
363: stl_kernel(env->tr.base + 0x20, next_eip);
364: stl_kernel(env->tr.base + 0x24, old_eflags);
365: stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
366: stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
367: stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
368: stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
369: stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
370: stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
371: stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
372: stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
373: for(i = 0; i < 6; i++)
374: stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
375: } else {
376: /* 16 bit */
377: stw_kernel(env->tr.base + 0x0e, next_eip);
378: stw_kernel(env->tr.base + 0x10, old_eflags);
379: stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
380: stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
381: stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
382: stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
383: stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
384: stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
385: stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
386: stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
387: for(i = 0; i < 4; i++)
388: stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
389: }
390:
391: /* now if an exception occurs, it will occurs in the next task
392: context */
393:
394: if (source == SWITCH_TSS_CALL) {
395: stw_kernel(tss_base, env->tr.selector);
396: new_eflags |= NT_MASK;
397: }
398:
399: /* set busy bit */
400: if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
401: target_ulong ptr;
402: uint32_t e2;
403: ptr = env->gdt.base + (tss_selector & ~7);
404: e2 = ldl_kernel(ptr + 4);
405: e2 |= DESC_TSS_BUSY_MASK;
406: stl_kernel(ptr + 4, e2);
407: }
408:
409: /* set the new CPU state */
410: /* from this point, any exception which occurs can give problems */
411: env->cr[0] |= CR0_TS_MASK;
412: env->hflags |= HF_TS_MASK;
413: env->tr.selector = tss_selector;
414: env->tr.base = tss_base;
415: env->tr.limit = tss_limit;
416: env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
417:
418: if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
419: cpu_x86_update_cr3(env, new_cr3);
420: }
421:
422: /* load all registers without an exception, then reload them with
423: possible exception */
424: env->eip = new_eip;
425: eflags_mask = TF_MASK | AC_MASK | ID_MASK |
426: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
427: if (!(type & 8))
428: eflags_mask &= 0xffff;
429: load_eflags(new_eflags, eflags_mask);
430: /* XXX: what to do in 16 bit case ? */
431: EAX = new_regs[0];
432: ECX = new_regs[1];
433: EDX = new_regs[2];
434: EBX = new_regs[3];
435: ESP = new_regs[4];
436: EBP = new_regs[5];
437: ESI = new_regs[6];
438: EDI = new_regs[7];
439: if (new_eflags & VM_MASK) {
440: for(i = 0; i < 6; i++)
441: load_seg_vm(i, new_segs[i]);
442: /* in vm86, CPL is always 3 */
443: cpu_x86_set_cpl(env, 3);
444: } else {
445: /* CPL is set the RPL of CS */
446: cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
447: /* first just selectors as the rest may trigger exceptions */
448: for(i = 0; i < 6; i++)
449: cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
450: }
451:
452: env->ldt.selector = new_ldt & ~4;
453: env->ldt.base = 0;
454: env->ldt.limit = 0;
455: env->ldt.flags = 0;
456:
457: /* load the LDT */
458: if (new_ldt & 4)
459: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
460:
461: if ((new_ldt & 0xfffc) != 0) {
462: dt = &env->gdt;
463: index = new_ldt & ~7;
464: if ((index + 7) > dt->limit)
465: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
466: ptr = dt->base + index;
467: e1 = ldl_kernel(ptr);
468: e2 = ldl_kernel(ptr + 4);
469: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
470: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
471: if (!(e2 & DESC_P_MASK))
472: raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
473: load_seg_cache_raw_dt(&env->ldt, e1, e2);
474: }
475:
476: /* load the segments */
477: if (!(new_eflags & VM_MASK)) {
478: tss_load_seg(R_CS, new_segs[R_CS]);
479: tss_load_seg(R_SS, new_segs[R_SS]);
480: tss_load_seg(R_ES, new_segs[R_ES]);
481: tss_load_seg(R_DS, new_segs[R_DS]);
482: tss_load_seg(R_FS, new_segs[R_FS]);
483: tss_load_seg(R_GS, new_segs[R_GS]);
484: }
485:
486: /* check that EIP is in the CS segment limits */
487: if (new_eip > env->segs[R_CS].limit) {
488: /* XXX: different exception if CALL ? */
489: raise_exception_err(EXCP0D_GPF, 0);
490: }
491: }
492:
493: /* check if Port I/O is allowed in TSS */
494: static inline void check_io(int addr, int size)
495: {
496: int io_offset, val, mask;
497:
498: /* TSS must be a valid 32 bit one */
499: if (!(env->tr.flags & DESC_P_MASK) ||
500: ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
501: env->tr.limit < 103)
502: goto fail;
503: io_offset = lduw_kernel(env->tr.base + 0x66);
504: io_offset += (addr >> 3);
505: /* Note: the check needs two bytes */
506: if ((io_offset + 1) > env->tr.limit)
507: goto fail;
508: val = lduw_kernel(env->tr.base + io_offset);
509: val >>= (addr & 7);
510: mask = (1 << size) - 1;
511: /* all bits must be zero to allow the I/O */
512: if ((val & mask) != 0) {
513: fail:
514: raise_exception_err(EXCP0D_GPF, 0);
515: }
516: }
517:
518: void check_iob_T0(void)
519: {
520: check_io(T0, 1);
521: }
522:
523: void check_iow_T0(void)
524: {
525: check_io(T0, 2);
526: }
527:
528: void check_iol_T0(void)
529: {
530: check_io(T0, 4);
531: }
532:
533: void check_iob_DX(void)
534: {
535: check_io(EDX & 0xffff, 1);
536: }
537:
538: void check_iow_DX(void)
539: {
540: check_io(EDX & 0xffff, 2);
541: }
542:
543: void check_iol_DX(void)
544: {
545: check_io(EDX & 0xffff, 4);
546: }
547:
548: static inline unsigned int get_sp_mask(unsigned int e2)
549: {
550: if (e2 & DESC_B_MASK)
551: return 0xffffffff;
552: else
553: return 0xffff;
554: }
555:
556: /* XXX: add a is_user flag to have proper security support */
557: #define PUSHW(ssp, sp, sp_mask, val)\
558: {\
559: sp -= 2;\
560: stw_kernel((ssp) + (sp & (sp_mask)), (val));\
561: }
562:
563: #define PUSHL(ssp, sp, sp_mask, val)\
564: {\
565: sp -= 4;\
566: stl_kernel((ssp) + (sp & (sp_mask)), (val));\
567: }
568:
569: #define POPW(ssp, sp, sp_mask, val)\
570: {\
571: val = lduw_kernel((ssp) + (sp & (sp_mask)));\
572: sp += 2;\
573: }
574:
575: #define POPL(ssp, sp, sp_mask, val)\
576: {\
577: val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
578: sp += 4;\
579: }
580:
581: /* protected mode interrupt */
582: static void do_interrupt_protected(int intno, int is_int, int error_code,
583: unsigned int next_eip, int is_hw)
584: {
585: SegmentCache *dt;
586: target_ulong ptr, ssp;
587: int type, dpl, selector, ss_dpl, cpl, sp_mask;
588: int has_error_code, new_stack, shift;
589: uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
590: uint32_t old_eip;
591:
592: has_error_code = 0;
593: if (!is_int && !is_hw) {
594: switch(intno) {
595: case 8:
596: case 10:
597: case 11:
598: case 12:
599: case 13:
600: case 14:
601: case 17:
602: has_error_code = 1;
603: break;
604: }
605: }
606: if (is_int)
607: old_eip = next_eip;
608: else
609: old_eip = env->eip;
610:
611: dt = &env->idt;
612: if (intno * 8 + 7 > dt->limit)
613: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
614: ptr = dt->base + intno * 8;
615: e1 = ldl_kernel(ptr);
616: e2 = ldl_kernel(ptr + 4);
617: /* check gate type */
618: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
619: switch(type) {
620: case 5: /* task gate */
621: /* must do that check here to return the correct error code */
622: if (!(e2 & DESC_P_MASK))
623: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
624: switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
625: if (has_error_code) {
626: int mask, type;
627: /* push the error code */
628: type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
629: shift = type >> 3;
630: if (env->segs[R_SS].flags & DESC_B_MASK)
631: mask = 0xffffffff;
632: else
633: mask = 0xffff;
634: esp = (ESP - (2 << shift)) & mask;
635: ssp = env->segs[R_SS].base + esp;
636: if (shift)
637: stl_kernel(ssp, error_code);
638: else
639: stw_kernel(ssp, error_code);
640: ESP = (esp & mask) | (ESP & ~mask);
641: }
642: return;
643: case 6: /* 286 interrupt gate */
644: case 7: /* 286 trap gate */
645: case 14: /* 386 interrupt gate */
646: case 15: /* 386 trap gate */
647: break;
648: default:
649: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
650: break;
651: }
652: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
653: cpl = env->hflags & HF_CPL_MASK;
654: /* check privledge if software int */
655: if (is_int && dpl < cpl)
656: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
657: /* check valid bit */
658: if (!(e2 & DESC_P_MASK))
659: raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
660: selector = e1 >> 16;
661: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
662: if ((selector & 0xfffc) == 0)
663: raise_exception_err(EXCP0D_GPF, 0);
664:
665: if (load_segment(&e1, &e2, selector) != 0)
666: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
667: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
668: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
669: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
670: if (dpl > cpl)
671: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
672: if (!(e2 & DESC_P_MASK))
673: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
674: if (!(e2 & DESC_C_MASK) && dpl < cpl) {
675: /* to inner priviledge */
676: get_ss_esp_from_tss(&ss, &esp, dpl);
677: if ((ss & 0xfffc) == 0)
678: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
679: if ((ss & 3) != dpl)
680: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
681: if (load_segment(&ss_e1, &ss_e2, ss) != 0)
682: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
683: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
684: if (ss_dpl != dpl)
685: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
686: if (!(ss_e2 & DESC_S_MASK) ||
687: (ss_e2 & DESC_CS_MASK) ||
688: !(ss_e2 & DESC_W_MASK))
689: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
690: if (!(ss_e2 & DESC_P_MASK))
691: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
692: new_stack = 1;
693: sp_mask = get_sp_mask(ss_e2);
694: ssp = get_seg_base(ss_e1, ss_e2);
695: } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
696: /* to same priviledge */
697: if (env->eflags & VM_MASK)
698: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
699: new_stack = 0;
700: sp_mask = get_sp_mask(env->segs[R_SS].flags);
701: ssp = env->segs[R_SS].base;
702: esp = ESP;
703: dpl = cpl;
704: } else {
705: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
706: new_stack = 0; /* avoid warning */
707: sp_mask = 0; /* avoid warning */
708: ssp = 0; /* avoid warning */
709: esp = 0; /* avoid warning */
710: }
711:
712: shift = type >> 3;
713:
714: #if 0
715: /* XXX: check that enough room is available */
716: push_size = 6 + (new_stack << 2) + (has_error_code << 1);
717: if (env->eflags & VM_MASK)
718: push_size += 8;
719: push_size <<= shift;
720: #endif
721: if (shift == 1) {
722: if (new_stack) {
723: if (env->eflags & VM_MASK) {
724: PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
725: PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
726: PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
727: PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
728: }
729: PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
730: PUSHL(ssp, esp, sp_mask, ESP);
731: }
732: PUSHL(ssp, esp, sp_mask, compute_eflags());
733: PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
734: PUSHL(ssp, esp, sp_mask, old_eip);
735: if (has_error_code) {
736: PUSHL(ssp, esp, sp_mask, error_code);
737: }
738: } else {
739: if (new_stack) {
740: if (env->eflags & VM_MASK) {
741: PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
742: PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
743: PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
744: PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
745: }
746: PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
747: PUSHW(ssp, esp, sp_mask, ESP);
748: }
749: PUSHW(ssp, esp, sp_mask, compute_eflags());
750: PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
751: PUSHW(ssp, esp, sp_mask, old_eip);
752: if (has_error_code) {
753: PUSHW(ssp, esp, sp_mask, error_code);
754: }
755: }
756:
757: if (new_stack) {
758: if (env->eflags & VM_MASK) {
759: cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
760: cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
761: cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
762: cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
763: }
764: ss = (ss & ~3) | dpl;
765: cpu_x86_load_seg_cache(env, R_SS, ss,
766: ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
767: }
768: ESP = (ESP & ~sp_mask) | (esp & sp_mask);
769:
770: selector = (selector & ~3) | dpl;
771: cpu_x86_load_seg_cache(env, R_CS, selector,
772: get_seg_base(e1, e2),
773: get_seg_limit(e1, e2),
774: e2);
775: cpu_x86_set_cpl(env, dpl);
776: env->eip = offset;
777:
778: /* interrupt gate clear IF mask */
779: if ((type & 1) == 0) {
780: env->eflags &= ~IF_MASK;
781: }
782: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
783: }
784:
785: #ifdef TARGET_X86_64
786:
787: #define PUSHQ(sp, val)\
788: {\
789: sp -= 8;\
790: stq_kernel(sp, (val));\
791: }
792:
793: #define POPQ(sp, val)\
794: {\
795: val = ldq_kernel(sp);\
796: sp += 8;\
797: }
798:
799: static inline target_ulong get_rsp_from_tss(int level)
800: {
801: int index;
802:
803: #if 0
804: printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
805: env->tr.base, env->tr.limit);
806: #endif
807:
808: if (!(env->tr.flags & DESC_P_MASK))
809: cpu_abort(env, "invalid tss");
810: index = 8 * level + 4;
811: if ((index + 7) > env->tr.limit)
812: raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
813: return ldq_kernel(env->tr.base + index);
814: }
815:
816: /* 64 bit interrupt */
817: static void do_interrupt64(int intno, int is_int, int error_code,
818: target_ulong next_eip, int is_hw)
819: {
820: SegmentCache *dt;
821: target_ulong ptr;
822: int type, dpl, selector, cpl, ist;
823: int has_error_code, new_stack;
824: uint32_t e1, e2, e3, ss;
825: target_ulong old_eip, esp, offset;
826:
827: has_error_code = 0;
828: if (!is_int && !is_hw) {
829: switch(intno) {
830: case 8:
831: case 10:
832: case 11:
833: case 12:
834: case 13:
835: case 14:
836: case 17:
837: has_error_code = 1;
838: break;
839: }
840: }
841: if (is_int)
842: old_eip = next_eip;
843: else
844: old_eip = env->eip;
845:
846: dt = &env->idt;
847: if (intno * 16 + 15 > dt->limit)
848: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
849: ptr = dt->base + intno * 16;
850: e1 = ldl_kernel(ptr);
851: e2 = ldl_kernel(ptr + 4);
852: e3 = ldl_kernel(ptr + 8);
853: /* check gate type */
854: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
855: switch(type) {
856: case 14: /* 386 interrupt gate */
857: case 15: /* 386 trap gate */
858: break;
859: default:
860: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
861: break;
862: }
863: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
864: cpl = env->hflags & HF_CPL_MASK;
865: /* check privledge if software int */
866: if (is_int && dpl < cpl)
867: raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
868: /* check valid bit */
869: if (!(e2 & DESC_P_MASK))
870: raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
871: selector = e1 >> 16;
872: offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
873: ist = e2 & 7;
874: if ((selector & 0xfffc) == 0)
875: raise_exception_err(EXCP0D_GPF, 0);
876:
877: if (load_segment(&e1, &e2, selector) != 0)
878: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
879: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
880: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
881: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
882: if (dpl > cpl)
883: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
884: if (!(e2 & DESC_P_MASK))
885: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
886: if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
887: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
888: if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
889: /* to inner priviledge */
890: if (ist != 0)
891: esp = get_rsp_from_tss(ist + 3);
892: else
893: esp = get_rsp_from_tss(dpl);
1.1.1.3 ! root 894: esp &= ~0xfLL; /* align stack */
1.1 root 895: ss = 0;
896: new_stack = 1;
897: } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
898: /* to same priviledge */
899: if (env->eflags & VM_MASK)
900: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
901: new_stack = 0;
1.1.1.3 ! root 902: if (ist != 0)
! 903: esp = get_rsp_from_tss(ist + 3);
! 904: else
! 905: esp = ESP;
! 906: esp &= ~0xfLL; /* align stack */
1.1 root 907: dpl = cpl;
908: } else {
909: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
910: new_stack = 0; /* avoid warning */
911: esp = 0; /* avoid warning */
912: }
913:
914: PUSHQ(esp, env->segs[R_SS].selector);
915: PUSHQ(esp, ESP);
916: PUSHQ(esp, compute_eflags());
917: PUSHQ(esp, env->segs[R_CS].selector);
918: PUSHQ(esp, old_eip);
919: if (has_error_code) {
920: PUSHQ(esp, error_code);
921: }
922:
923: if (new_stack) {
924: ss = 0 | dpl;
925: cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
926: }
927: ESP = esp;
928:
929: selector = (selector & ~3) | dpl;
930: cpu_x86_load_seg_cache(env, R_CS, selector,
931: get_seg_base(e1, e2),
932: get_seg_limit(e1, e2),
933: e2);
934: cpu_x86_set_cpl(env, dpl);
935: env->eip = offset;
936:
937: /* interrupt gate clear IF mask */
938: if ((type & 1) == 0) {
939: env->eflags &= ~IF_MASK;
940: }
941: env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
942: }
943: #endif
944:
945: void helper_syscall(int next_eip_addend)
946: {
947: int selector;
948:
949: if (!(env->efer & MSR_EFER_SCE)) {
950: raise_exception_err(EXCP06_ILLOP, 0);
951: }
952: selector = (env->star >> 32) & 0xffff;
953: #ifdef TARGET_X86_64
954: if (env->hflags & HF_LMA_MASK) {
1.1.1.3 ! root 955: int code64;
! 956:
1.1 root 957: ECX = env->eip + next_eip_addend;
958: env->regs[11] = compute_eflags();
1.1.1.3 ! root 959:
! 960: code64 = env->hflags & HF_CS64_MASK;
1.1 root 961:
962: cpu_x86_set_cpl(env, 0);
963: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
964: 0, 0xffffffff,
965: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
966: DESC_S_MASK |
967: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
968: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
969: 0, 0xffffffff,
970: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
971: DESC_S_MASK |
972: DESC_W_MASK | DESC_A_MASK);
973: env->eflags &= ~env->fmask;
1.1.1.3 ! root 974: if (code64)
1.1 root 975: env->eip = env->lstar;
976: else
977: env->eip = env->cstar;
978: } else
979: #endif
980: {
981: ECX = (uint32_t)(env->eip + next_eip_addend);
982:
983: cpu_x86_set_cpl(env, 0);
984: cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
985: 0, 0xffffffff,
986: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
987: DESC_S_MASK |
988: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
989: cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
990: 0, 0xffffffff,
991: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
992: DESC_S_MASK |
993: DESC_W_MASK | DESC_A_MASK);
994: env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
995: env->eip = (uint32_t)env->star;
996: }
997: }
998:
999: void helper_sysret(int dflag)
1000: {
1001: int cpl, selector;
1002:
1003: if (!(env->efer & MSR_EFER_SCE)) {
1004: raise_exception_err(EXCP06_ILLOP, 0);
1005: }
1006: cpl = env->hflags & HF_CPL_MASK;
1007: if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1008: raise_exception_err(EXCP0D_GPF, 0);
1009: }
1010: selector = (env->star >> 48) & 0xffff;
1011: #ifdef TARGET_X86_64
1012: if (env->hflags & HF_LMA_MASK) {
1013: if (dflag == 2) {
1014: cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1015: 0, 0xffffffff,
1016: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1017: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1018: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1019: DESC_L_MASK);
1020: env->eip = ECX;
1021: } else {
1022: cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1023: 0, 0xffffffff,
1024: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1025: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1026: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1027: env->eip = (uint32_t)ECX;
1028: }
1029: cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1030: 0, 0xffffffff,
1031: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1032: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1033: DESC_W_MASK | DESC_A_MASK);
1034: load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1035: IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1036: cpu_x86_set_cpl(env, 3);
1037: } else
1038: #endif
1039: {
1040: cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1041: 0, 0xffffffff,
1042: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1043: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1044: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1045: env->eip = (uint32_t)ECX;
1046: cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1047: 0, 0xffffffff,
1048: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1049: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1050: DESC_W_MASK | DESC_A_MASK);
1051: env->eflags |= IF_MASK;
1052: cpu_x86_set_cpl(env, 3);
1053: }
1054: #ifdef USE_KQEMU
1055: if (kqemu_is_ok(env)) {
1056: if (env->hflags & HF_LMA_MASK)
1057: CC_OP = CC_OP_EFLAGS;
1058: env->exception_index = -1;
1059: cpu_loop_exit();
1060: }
1061: #endif
1062: }
1063:
1064: /* real mode interrupt */
1065: static void do_interrupt_real(int intno, int is_int, int error_code,
1066: unsigned int next_eip)
1067: {
1068: SegmentCache *dt;
1069: target_ulong ptr, ssp;
1070: int selector;
1071: uint32_t offset, esp;
1072: uint32_t old_cs, old_eip;
1073:
1074: /* real mode (simpler !) */
1075: dt = &env->idt;
1076: if (intno * 4 + 3 > dt->limit)
1077: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1078: ptr = dt->base + intno * 4;
1079: offset = lduw_kernel(ptr);
1080: selector = lduw_kernel(ptr + 2);
1081: esp = ESP;
1082: ssp = env->segs[R_SS].base;
1083: if (is_int)
1084: old_eip = next_eip;
1085: else
1086: old_eip = env->eip;
1087: old_cs = env->segs[R_CS].selector;
1088: /* XXX: use SS segment size ? */
1089: PUSHW(ssp, esp, 0xffff, compute_eflags());
1090: PUSHW(ssp, esp, 0xffff, old_cs);
1091: PUSHW(ssp, esp, 0xffff, old_eip);
1092:
1093: /* update processor state */
1094: ESP = (ESP & ~0xffff) | (esp & 0xffff);
1095: env->eip = offset;
1096: env->segs[R_CS].selector = selector;
1097: env->segs[R_CS].base = (selector << 4);
1098: env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1099: }
1100:
1101: /* fake user mode interrupt */
1102: void do_interrupt_user(int intno, int is_int, int error_code,
1103: target_ulong next_eip)
1104: {
1105: SegmentCache *dt;
1106: target_ulong ptr;
1107: int dpl, cpl;
1108: uint32_t e2;
1109:
1110: dt = &env->idt;
1111: ptr = dt->base + (intno * 8);
1112: e2 = ldl_kernel(ptr + 4);
1113:
1114: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1115: cpl = env->hflags & HF_CPL_MASK;
1116: /* check privledge if software int */
1117: if (is_int && dpl < cpl)
1118: raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1119:
1120: /* Since we emulate only user space, we cannot do more than
1121: exiting the emulation with the suitable exception and error
1122: code */
1123: if (is_int)
1124: EIP = next_eip;
1125: }
1126:
1127: /*
1128: * Begin execution of an interruption. is_int is TRUE if coming from
1129: * the int instruction. next_eip is the EIP value AFTER the interrupt
1130: * instruction. It is only relevant if is_int is TRUE.
1131: */
1132: void do_interrupt(int intno, int is_int, int error_code,
1133: target_ulong next_eip, int is_hw)
1134: {
1.1.1.3 ! root 1135: if (loglevel & CPU_LOG_INT) {
1.1 root 1136: if ((env->cr[0] & CR0_PE_MASK)) {
1137: static int count;
1138: fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1139: count, intno, error_code, is_int,
1140: env->hflags & HF_CPL_MASK,
1141: env->segs[R_CS].selector, EIP,
1142: (int)env->segs[R_CS].base + EIP,
1143: env->segs[R_SS].selector, ESP);
1144: if (intno == 0x0e) {
1145: fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1146: } else {
1147: fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1148: }
1149: fprintf(logfile, "\n");
1150: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1.1.1.3 ! root 1151: #if 0
1.1 root 1152: {
1153: int i;
1154: uint8_t *ptr;
1155: fprintf(logfile, " code=");
1156: ptr = env->segs[R_CS].base + env->eip;
1157: for(i = 0; i < 16; i++) {
1158: fprintf(logfile, " %02x", ldub(ptr + i));
1159: }
1160: fprintf(logfile, "\n");
1161: }
1162: #endif
1163: count++;
1164: }
1165: }
1166: if (env->cr[0] & CR0_PE_MASK) {
1167: #if TARGET_X86_64
1168: if (env->hflags & HF_LMA_MASK) {
1169: do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1170: } else
1171: #endif
1172: {
1173: do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1174: }
1175: } else {
1176: do_interrupt_real(intno, is_int, error_code, next_eip);
1177: }
1178: }
1179:
1180: /*
1181: * Signal an interruption. It is executed in the main CPU loop.
1182: * is_int is TRUE if coming from the int instruction. next_eip is the
1183: * EIP value AFTER the interrupt instruction. It is only relevant if
1184: * is_int is TRUE.
1185: */
1186: void raise_interrupt(int intno, int is_int, int error_code,
1187: int next_eip_addend)
1188: {
1189: env->exception_index = intno;
1190: env->error_code = error_code;
1191: env->exception_is_int = is_int;
1192: env->exception_next_eip = env->eip + next_eip_addend;
1193: cpu_loop_exit();
1194: }
1195:
1196: /* same as raise_exception_err, but do not restore global registers */
1197: static void raise_exception_err_norestore(int exception_index, int error_code)
1198: {
1199: env->exception_index = exception_index;
1200: env->error_code = error_code;
1201: env->exception_is_int = 0;
1202: env->exception_next_eip = 0;
1203: longjmp(env->jmp_env, 1);
1204: }
1205:
1206: /* shortcuts to generate exceptions */
1207:
1208: void (raise_exception_err)(int exception_index, int error_code)
1209: {
1210: raise_interrupt(exception_index, 0, error_code, 0);
1211: }
1212:
1213: void raise_exception(int exception_index)
1214: {
1215: raise_interrupt(exception_index, 0, 0, 0);
1216: }
1217:
1218: #ifdef BUGGY_GCC_DIV64
1219: /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1220: call it from another function */
1221: uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1222: {
1223: *q_ptr = num / den;
1224: return num % den;
1225: }
1226:
1227: int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1228: {
1229: *q_ptr = num / den;
1230: return num % den;
1231: }
1232: #endif
1233:
1234: void helper_divl_EAX_T0(void)
1235: {
1236: unsigned int den, r;
1237: uint64_t num, q;
1238:
1239: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1240: den = T0;
1241: if (den == 0) {
1242: raise_exception(EXCP00_DIVZ);
1243: }
1244: #ifdef BUGGY_GCC_DIV64
1245: r = div32(&q, num, den);
1246: #else
1247: q = (num / den);
1248: r = (num % den);
1249: #endif
1250: if (q > 0xffffffff)
1251: raise_exception(EXCP00_DIVZ);
1252: EAX = (uint32_t)q;
1253: EDX = (uint32_t)r;
1254: }
1255:
1256: void helper_idivl_EAX_T0(void)
1257: {
1258: int den, r;
1259: int64_t num, q;
1260:
1261: num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1262: den = T0;
1263: if (den == 0) {
1264: raise_exception(EXCP00_DIVZ);
1265: }
1266: #ifdef BUGGY_GCC_DIV64
1267: r = idiv32(&q, num, den);
1268: #else
1269: q = (num / den);
1270: r = (num % den);
1271: #endif
1272: if (q != (int32_t)q)
1273: raise_exception(EXCP00_DIVZ);
1274: EAX = (uint32_t)q;
1275: EDX = (uint32_t)r;
1276: }
1277:
1278: void helper_cmpxchg8b(void)
1279: {
1280: uint64_t d;
1281: int eflags;
1282:
1283: eflags = cc_table[CC_OP].compute_all();
1284: d = ldq(A0);
1285: if (d == (((uint64_t)EDX << 32) | EAX)) {
1286: stq(A0, ((uint64_t)ECX << 32) | EBX);
1287: eflags |= CC_Z;
1288: } else {
1289: EDX = d >> 32;
1290: EAX = d;
1291: eflags &= ~CC_Z;
1292: }
1293: CC_SRC = eflags;
1294: }
1295:
1296: void helper_cpuid(void)
1297: {
1298: uint32_t index;
1299: index = (uint32_t)EAX;
1300:
1301: /* test if maximum index reached */
1302: if (index & 0x80000000) {
1303: if (index > env->cpuid_xlevel)
1304: index = env->cpuid_level;
1305: } else {
1306: if (index > env->cpuid_level)
1307: index = env->cpuid_level;
1308: }
1309:
1310: switch(index) {
1311: case 0:
1312: EAX = env->cpuid_level;
1313: EBX = env->cpuid_vendor1;
1314: EDX = env->cpuid_vendor2;
1315: ECX = env->cpuid_vendor3;
1316: break;
1317: case 1:
1318: EAX = env->cpuid_version;
1319: EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
1320: ECX = env->cpuid_ext_features;
1321: EDX = env->cpuid_features;
1322: break;
1323: case 2:
1324: /* cache info: needed for Pentium Pro compatibility */
1325: EAX = 0x410601;
1326: EBX = 0;
1327: ECX = 0;
1328: EDX = 0;
1329: break;
1330: case 0x80000000:
1331: EAX = env->cpuid_xlevel;
1332: EBX = env->cpuid_vendor1;
1333: EDX = env->cpuid_vendor2;
1334: ECX = env->cpuid_vendor3;
1335: break;
1336: case 0x80000001:
1337: EAX = env->cpuid_features;
1338: EBX = 0;
1339: ECX = 0;
1340: EDX = env->cpuid_ext2_features;
1341: break;
1342: case 0x80000002:
1343: case 0x80000003:
1344: case 0x80000004:
1345: EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
1346: EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
1347: ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
1348: EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
1349: break;
1350: case 0x80000005:
1351: /* cache info (L1 cache) */
1352: EAX = 0x01ff01ff;
1353: EBX = 0x01ff01ff;
1354: ECX = 0x40020140;
1355: EDX = 0x40020140;
1356: break;
1357: case 0x80000006:
1358: /* cache info (L2 cache) */
1359: EAX = 0;
1360: EBX = 0x42004200;
1361: ECX = 0x02008140;
1362: EDX = 0;
1363: break;
1364: case 0x80000008:
1365: /* virtual & phys address size in low 2 bytes. */
1366: EAX = 0x00003028;
1367: EBX = 0;
1368: ECX = 0;
1369: EDX = 0;
1370: break;
1371: default:
1372: /* reserved values: zero */
1373: EAX = 0;
1374: EBX = 0;
1375: ECX = 0;
1376: EDX = 0;
1377: break;
1378: }
1379: }
1380:
1381: void helper_enter_level(int level, int data32)
1382: {
1383: target_ulong ssp;
1384: uint32_t esp_mask, esp, ebp;
1385:
1386: esp_mask = get_sp_mask(env->segs[R_SS].flags);
1387: ssp = env->segs[R_SS].base;
1388: ebp = EBP;
1389: esp = ESP;
1390: if (data32) {
1391: /* 32 bit */
1392: esp -= 4;
1393: while (--level) {
1394: esp -= 4;
1395: ebp -= 4;
1396: stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1397: }
1398: esp -= 4;
1399: stl(ssp + (esp & esp_mask), T1);
1400: } else {
1401: /* 16 bit */
1402: esp -= 2;
1403: while (--level) {
1404: esp -= 2;
1405: ebp -= 2;
1406: stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1407: }
1408: esp -= 2;
1409: stw(ssp + (esp & esp_mask), T1);
1410: }
1411: }
1412:
1413: #ifdef TARGET_X86_64
1414: void helper_enter64_level(int level, int data64)
1415: {
1416: target_ulong esp, ebp;
1417: ebp = EBP;
1418: esp = ESP;
1419:
1420: if (data64) {
1421: /* 64 bit */
1422: esp -= 8;
1423: while (--level) {
1424: esp -= 8;
1425: ebp -= 8;
1426: stq(esp, ldq(ebp));
1427: }
1428: esp -= 8;
1429: stq(esp, T1);
1430: } else {
1431: /* 16 bit */
1432: esp -= 2;
1433: while (--level) {
1434: esp -= 2;
1435: ebp -= 2;
1436: stw(esp, lduw(ebp));
1437: }
1438: esp -= 2;
1439: stw(esp, T1);
1440: }
1441: }
1442: #endif
1443:
1444: void helper_lldt_T0(void)
1445: {
1446: int selector;
1447: SegmentCache *dt;
1448: uint32_t e1, e2;
1449: int index, entry_limit;
1450: target_ulong ptr;
1451:
1452: selector = T0 & 0xffff;
1453: if ((selector & 0xfffc) == 0) {
1454: /* XXX: NULL selector case: invalid LDT */
1455: env->ldt.base = 0;
1456: env->ldt.limit = 0;
1457: } else {
1458: if (selector & 0x4)
1459: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1460: dt = &env->gdt;
1461: index = selector & ~7;
1462: #ifdef TARGET_X86_64
1463: if (env->hflags & HF_LMA_MASK)
1464: entry_limit = 15;
1465: else
1466: #endif
1467: entry_limit = 7;
1468: if ((index + entry_limit) > dt->limit)
1469: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1470: ptr = dt->base + index;
1471: e1 = ldl_kernel(ptr);
1472: e2 = ldl_kernel(ptr + 4);
1473: if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1474: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1475: if (!(e2 & DESC_P_MASK))
1476: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1477: #ifdef TARGET_X86_64
1478: if (env->hflags & HF_LMA_MASK) {
1479: uint32_t e3;
1480: e3 = ldl_kernel(ptr + 8);
1481: load_seg_cache_raw_dt(&env->ldt, e1, e2);
1482: env->ldt.base |= (target_ulong)e3 << 32;
1483: } else
1484: #endif
1485: {
1486: load_seg_cache_raw_dt(&env->ldt, e1, e2);
1487: }
1488: }
1489: env->ldt.selector = selector;
1490: }
1491:
1492: void helper_ltr_T0(void)
1493: {
1494: int selector;
1495: SegmentCache *dt;
1496: uint32_t e1, e2;
1497: int index, type, entry_limit;
1498: target_ulong ptr;
1499:
1500: selector = T0 & 0xffff;
1501: if ((selector & 0xfffc) == 0) {
1502: /* NULL selector case: invalid TR */
1503: env->tr.base = 0;
1504: env->tr.limit = 0;
1505: env->tr.flags = 0;
1506: } else {
1507: if (selector & 0x4)
1508: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1509: dt = &env->gdt;
1510: index = selector & ~7;
1511: #ifdef TARGET_X86_64
1512: if (env->hflags & HF_LMA_MASK)
1513: entry_limit = 15;
1514: else
1515: #endif
1516: entry_limit = 7;
1517: if ((index + entry_limit) > dt->limit)
1518: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1519: ptr = dt->base + index;
1520: e1 = ldl_kernel(ptr);
1521: e2 = ldl_kernel(ptr + 4);
1522: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1523: if ((e2 & DESC_S_MASK) ||
1524: (type != 1 && type != 9))
1525: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1526: if (!(e2 & DESC_P_MASK))
1527: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1528: #ifdef TARGET_X86_64
1529: if (env->hflags & HF_LMA_MASK) {
1530: uint32_t e3;
1531: e3 = ldl_kernel(ptr + 8);
1532: load_seg_cache_raw_dt(&env->tr, e1, e2);
1533: env->tr.base |= (target_ulong)e3 << 32;
1534: } else
1535: #endif
1536: {
1537: load_seg_cache_raw_dt(&env->tr, e1, e2);
1538: }
1539: e2 |= DESC_TSS_BUSY_MASK;
1540: stl_kernel(ptr + 4, e2);
1541: }
1542: env->tr.selector = selector;
1543: }
1544:
1545: /* only works if protected mode and not VM86. seg_reg must be != R_CS */
1546: void load_seg(int seg_reg, int selector)
1547: {
1548: uint32_t e1, e2;
1549: int cpl, dpl, rpl;
1550: SegmentCache *dt;
1551: int index;
1552: target_ulong ptr;
1553:
1554: selector &= 0xffff;
1555: cpl = env->hflags & HF_CPL_MASK;
1556: if ((selector & 0xfffc) == 0) {
1557: /* null selector case */
1558: if (seg_reg == R_SS
1559: #ifdef TARGET_X86_64
1560: && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
1561: #endif
1562: )
1563: raise_exception_err(EXCP0D_GPF, 0);
1564: cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
1565: } else {
1566:
1567: if (selector & 0x4)
1568: dt = &env->ldt;
1569: else
1570: dt = &env->gdt;
1571: index = selector & ~7;
1572: if ((index + 7) > dt->limit)
1573: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1574: ptr = dt->base + index;
1575: e1 = ldl_kernel(ptr);
1576: e2 = ldl_kernel(ptr + 4);
1577:
1578: if (!(e2 & DESC_S_MASK))
1579: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1580: rpl = selector & 3;
1581: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1582: if (seg_reg == R_SS) {
1583: /* must be writable segment */
1584: if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1585: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1586: if (rpl != cpl || dpl != cpl)
1587: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1588: } else {
1589: /* must be readable segment */
1590: if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1591: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1592:
1593: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1594: /* if not conforming code, test rights */
1.1.1.2 root 1595: if (dpl < cpl || dpl < rpl)
1.1 root 1596: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1597: }
1598: }
1599:
1600: if (!(e2 & DESC_P_MASK)) {
1601: if (seg_reg == R_SS)
1602: raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1603: else
1604: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1605: }
1606:
1607: /* set the access bit if not already set */
1608: if (!(e2 & DESC_A_MASK)) {
1609: e2 |= DESC_A_MASK;
1610: stl_kernel(ptr + 4, e2);
1611: }
1612:
1613: cpu_x86_load_seg_cache(env, seg_reg, selector,
1614: get_seg_base(e1, e2),
1615: get_seg_limit(e1, e2),
1616: e2);
1617: #if 0
1618: fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
1619: selector, (unsigned long)sc->base, sc->limit, sc->flags);
1620: #endif
1621: }
1622: }
1623:
1624: /* protected mode jump */
1625: void helper_ljmp_protected_T0_T1(int next_eip_addend)
1626: {
1627: int new_cs, gate_cs, type;
1628: uint32_t e1, e2, cpl, dpl, rpl, limit;
1629: target_ulong new_eip, next_eip;
1630:
1631: new_cs = T0;
1632: new_eip = T1;
1633: if ((new_cs & 0xfffc) == 0)
1634: raise_exception_err(EXCP0D_GPF, 0);
1635: if (load_segment(&e1, &e2, new_cs) != 0)
1636: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1637: cpl = env->hflags & HF_CPL_MASK;
1638: if (e2 & DESC_S_MASK) {
1639: if (!(e2 & DESC_CS_MASK))
1640: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1641: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1642: if (e2 & DESC_C_MASK) {
1643: /* conforming code segment */
1644: if (dpl > cpl)
1645: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1646: } else {
1647: /* non conforming code segment */
1648: rpl = new_cs & 3;
1649: if (rpl > cpl)
1650: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1651: if (dpl != cpl)
1652: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1653: }
1654: if (!(e2 & DESC_P_MASK))
1655: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1656: limit = get_seg_limit(e1, e2);
1657: if (new_eip > limit &&
1658: !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
1659: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1660: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1661: get_seg_base(e1, e2), limit, e2);
1662: EIP = new_eip;
1663: } else {
1664: /* jump to call or task gate */
1665: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1666: rpl = new_cs & 3;
1667: cpl = env->hflags & HF_CPL_MASK;
1668: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1669: switch(type) {
1670: case 1: /* 286 TSS */
1671: case 9: /* 386 TSS */
1672: case 5: /* task gate */
1673: if (dpl < cpl || dpl < rpl)
1674: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1675: next_eip = env->eip + next_eip_addend;
1676: switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
1677: break;
1678: case 4: /* 286 call gate */
1679: case 12: /* 386 call gate */
1680: if ((dpl < cpl) || (dpl < rpl))
1681: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1682: if (!(e2 & DESC_P_MASK))
1683: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1684: gate_cs = e1 >> 16;
1685: new_eip = (e1 & 0xffff);
1686: if (type == 12)
1687: new_eip |= (e2 & 0xffff0000);
1688: if (load_segment(&e1, &e2, gate_cs) != 0)
1689: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1690: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1691: /* must be code segment */
1692: if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
1693: (DESC_S_MASK | DESC_CS_MASK)))
1694: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1695: if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1696: (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1697: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1698: if (!(e2 & DESC_P_MASK))
1699: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1700: limit = get_seg_limit(e1, e2);
1701: if (new_eip > limit)
1702: raise_exception_err(EXCP0D_GPF, 0);
1703: cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1704: get_seg_base(e1, e2), limit, e2);
1705: EIP = new_eip;
1706: break;
1707: default:
1708: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1709: break;
1710: }
1711: }
1712: }
1713:
1714: /* real mode call */
1715: void helper_lcall_real_T0_T1(int shift, int next_eip)
1716: {
1717: int new_cs, new_eip;
1718: uint32_t esp, esp_mask;
1719: target_ulong ssp;
1720:
1721: new_cs = T0;
1722: new_eip = T1;
1723: esp = ESP;
1724: esp_mask = get_sp_mask(env->segs[R_SS].flags);
1725: ssp = env->segs[R_SS].base;
1726: if (shift) {
1727: PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1728: PUSHL(ssp, esp, esp_mask, next_eip);
1729: } else {
1730: PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1731: PUSHW(ssp, esp, esp_mask, next_eip);
1732: }
1733:
1734: ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1735: env->eip = new_eip;
1736: env->segs[R_CS].selector = new_cs;
1737: env->segs[R_CS].base = (new_cs << 4);
1738: }
1739:
1740: /* protected mode call */
1741: void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
1742: {
1.1.1.2 root 1743: int new_cs, new_stack, i;
1.1 root 1744: uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1745: uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1746: uint32_t val, limit, old_sp_mask;
1.1.1.2 root 1747: target_ulong ssp, old_ssp, next_eip, new_eip;
1.1 root 1748:
1749: new_cs = T0;
1750: new_eip = T1;
1751: next_eip = env->eip + next_eip_addend;
1752: #ifdef DEBUG_PCALL
1753: if (loglevel & CPU_LOG_PCALL) {
1754: fprintf(logfile, "lcall %04x:%08x s=%d\n",
1.1.1.2 root 1755: new_cs, (uint32_t)new_eip, shift);
1.1 root 1756: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1757: }
1758: #endif
1759: if ((new_cs & 0xfffc) == 0)
1760: raise_exception_err(EXCP0D_GPF, 0);
1761: if (load_segment(&e1, &e2, new_cs) != 0)
1762: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1763: cpl = env->hflags & HF_CPL_MASK;
1764: #ifdef DEBUG_PCALL
1765: if (loglevel & CPU_LOG_PCALL) {
1766: fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1767: }
1768: #endif
1769: if (e2 & DESC_S_MASK) {
1770: if (!(e2 & DESC_CS_MASK))
1771: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1772: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1773: if (e2 & DESC_C_MASK) {
1774: /* conforming code segment */
1775: if (dpl > cpl)
1776: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1777: } else {
1778: /* non conforming code segment */
1779: rpl = new_cs & 3;
1780: if (rpl > cpl)
1781: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1782: if (dpl != cpl)
1783: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1784: }
1785: if (!(e2 & DESC_P_MASK))
1786: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1787:
1788: #ifdef TARGET_X86_64
1789: /* XXX: check 16/32 bit cases in long mode */
1790: if (shift == 2) {
1791: target_ulong rsp;
1792: /* 64 bit case */
1793: rsp = ESP;
1794: PUSHQ(rsp, env->segs[R_CS].selector);
1795: PUSHQ(rsp, next_eip);
1796: /* from this point, not restartable */
1797: ESP = rsp;
1798: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1799: get_seg_base(e1, e2),
1800: get_seg_limit(e1, e2), e2);
1801: EIP = new_eip;
1802: } else
1803: #endif
1804: {
1805: sp = ESP;
1806: sp_mask = get_sp_mask(env->segs[R_SS].flags);
1807: ssp = env->segs[R_SS].base;
1808: if (shift) {
1809: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1810: PUSHL(ssp, sp, sp_mask, next_eip);
1811: } else {
1812: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1813: PUSHW(ssp, sp, sp_mask, next_eip);
1814: }
1815:
1816: limit = get_seg_limit(e1, e2);
1817: if (new_eip > limit)
1818: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1819: /* from this point, not restartable */
1820: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1821: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1822: get_seg_base(e1, e2), limit, e2);
1823: EIP = new_eip;
1824: }
1825: } else {
1826: /* check gate type */
1827: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1828: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1829: rpl = new_cs & 3;
1830: switch(type) {
1831: case 1: /* available 286 TSS */
1832: case 9: /* available 386 TSS */
1833: case 5: /* task gate */
1834: if (dpl < cpl || dpl < rpl)
1835: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1836: switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
1837: return;
1838: case 4: /* 286 call gate */
1839: case 12: /* 386 call gate */
1840: break;
1841: default:
1842: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1843: break;
1844: }
1845: shift = type >> 3;
1846:
1847: if (dpl < cpl || dpl < rpl)
1848: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1849: /* check valid bit */
1850: if (!(e2 & DESC_P_MASK))
1851: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1852: selector = e1 >> 16;
1853: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1854: param_count = e2 & 0x1f;
1855: if ((selector & 0xfffc) == 0)
1856: raise_exception_err(EXCP0D_GPF, 0);
1857:
1858: if (load_segment(&e1, &e2, selector) != 0)
1859: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1860: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1861: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1862: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1863: if (dpl > cpl)
1864: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1865: if (!(e2 & DESC_P_MASK))
1866: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1867:
1868: if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1869: /* to inner priviledge */
1870: get_ss_esp_from_tss(&ss, &sp, dpl);
1871: #ifdef DEBUG_PCALL
1872: if (loglevel & CPU_LOG_PCALL)
1873: fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
1874: ss, sp, param_count, ESP);
1875: #endif
1876: if ((ss & 0xfffc) == 0)
1877: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1878: if ((ss & 3) != dpl)
1879: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1880: if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1881: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1882: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1883: if (ss_dpl != dpl)
1884: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1885: if (!(ss_e2 & DESC_S_MASK) ||
1886: (ss_e2 & DESC_CS_MASK) ||
1887: !(ss_e2 & DESC_W_MASK))
1888: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1889: if (!(ss_e2 & DESC_P_MASK))
1890: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1891:
1892: // push_size = ((param_count * 2) + 8) << shift;
1893:
1894: old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1895: old_ssp = env->segs[R_SS].base;
1896:
1897: sp_mask = get_sp_mask(ss_e2);
1898: ssp = get_seg_base(ss_e1, ss_e2);
1899: if (shift) {
1900: PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1901: PUSHL(ssp, sp, sp_mask, ESP);
1902: for(i = param_count - 1; i >= 0; i--) {
1903: val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1904: PUSHL(ssp, sp, sp_mask, val);
1905: }
1906: } else {
1907: PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1908: PUSHW(ssp, sp, sp_mask, ESP);
1909: for(i = param_count - 1; i >= 0; i--) {
1910: val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1911: PUSHW(ssp, sp, sp_mask, val);
1912: }
1913: }
1914: new_stack = 1;
1915: } else {
1916: /* to same priviledge */
1917: sp = ESP;
1918: sp_mask = get_sp_mask(env->segs[R_SS].flags);
1919: ssp = env->segs[R_SS].base;
1920: // push_size = (4 << shift);
1921: new_stack = 0;
1922: }
1923:
1924: if (shift) {
1925: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1926: PUSHL(ssp, sp, sp_mask, next_eip);
1927: } else {
1928: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1929: PUSHW(ssp, sp, sp_mask, next_eip);
1930: }
1931:
1932: /* from this point, not restartable */
1933:
1934: if (new_stack) {
1935: ss = (ss & ~3) | dpl;
1936: cpu_x86_load_seg_cache(env, R_SS, ss,
1937: ssp,
1938: get_seg_limit(ss_e1, ss_e2),
1939: ss_e2);
1940: }
1941:
1942: selector = (selector & ~3) | dpl;
1943: cpu_x86_load_seg_cache(env, R_CS, selector,
1944: get_seg_base(e1, e2),
1945: get_seg_limit(e1, e2),
1946: e2);
1947: cpu_x86_set_cpl(env, dpl);
1948: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1949: EIP = offset;
1950: }
1951: #ifdef USE_KQEMU
1952: if (kqemu_is_ok(env)) {
1953: env->exception_index = -1;
1954: cpu_loop_exit();
1955: }
1956: #endif
1957: }
1958:
1959: /* real and vm86 mode iret */
1960: void helper_iret_real(int shift)
1961: {
1962: uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1963: target_ulong ssp;
1964: int eflags_mask;
1965:
1966: sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1967: sp = ESP;
1968: ssp = env->segs[R_SS].base;
1969: if (shift == 1) {
1970: /* 32 bits */
1971: POPL(ssp, sp, sp_mask, new_eip);
1972: POPL(ssp, sp, sp_mask, new_cs);
1973: new_cs &= 0xffff;
1974: POPL(ssp, sp, sp_mask, new_eflags);
1975: } else {
1976: /* 16 bits */
1977: POPW(ssp, sp, sp_mask, new_eip);
1978: POPW(ssp, sp, sp_mask, new_cs);
1979: POPW(ssp, sp, sp_mask, new_eflags);
1980: }
1981: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1982: load_seg_vm(R_CS, new_cs);
1983: env->eip = new_eip;
1984: if (env->eflags & VM_MASK)
1985: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
1986: else
1987: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
1988: if (shift == 0)
1989: eflags_mask &= 0xffff;
1990: load_eflags(new_eflags, eflags_mask);
1991: }
1992:
1993: static inline void validate_seg(int seg_reg, int cpl)
1994: {
1995: int dpl;
1996: uint32_t e2;
1.1.1.2 root 1997:
1998: /* XXX: on x86_64, we do not want to nullify FS and GS because
1999: they may still contain a valid base. I would be interested to
2000: know how a real x86_64 CPU behaves */
2001: if ((seg_reg == R_FS || seg_reg == R_GS) &&
2002: (env->segs[seg_reg].selector & 0xfffc) == 0)
2003: return;
2004:
1.1 root 2005: e2 = env->segs[seg_reg].flags;
2006: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2007: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2008: /* data or non conforming code segment */
2009: if (dpl < cpl) {
2010: cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2011: }
2012: }
2013: }
2014:
2015: /* protected mode iret */
2016: static inline void helper_ret_protected(int shift, int is_iret, int addend)
2017: {
2018: uint32_t new_cs, new_eflags, new_ss;
2019: uint32_t new_es, new_ds, new_fs, new_gs;
2020: uint32_t e1, e2, ss_e1, ss_e2;
2021: int cpl, dpl, rpl, eflags_mask, iopl;
2022: target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2023:
2024: #ifdef TARGET_X86_64
2025: if (shift == 2)
2026: sp_mask = -1;
2027: else
2028: #endif
2029: sp_mask = get_sp_mask(env->segs[R_SS].flags);
2030: sp = ESP;
2031: ssp = env->segs[R_SS].base;
2032: new_eflags = 0; /* avoid warning */
2033: #ifdef TARGET_X86_64
2034: if (shift == 2) {
2035: POPQ(sp, new_eip);
2036: POPQ(sp, new_cs);
2037: new_cs &= 0xffff;
2038: if (is_iret) {
2039: POPQ(sp, new_eflags);
2040: }
2041: } else
2042: #endif
2043: if (shift == 1) {
2044: /* 32 bits */
2045: POPL(ssp, sp, sp_mask, new_eip);
2046: POPL(ssp, sp, sp_mask, new_cs);
2047: new_cs &= 0xffff;
2048: if (is_iret) {
2049: POPL(ssp, sp, sp_mask, new_eflags);
2050: if (new_eflags & VM_MASK)
2051: goto return_to_vm86;
2052: }
2053: } else {
2054: /* 16 bits */
2055: POPW(ssp, sp, sp_mask, new_eip);
2056: POPW(ssp, sp, sp_mask, new_cs);
2057: if (is_iret)
2058: POPW(ssp, sp, sp_mask, new_eflags);
2059: }
2060: #ifdef DEBUG_PCALL
2061: if (loglevel & CPU_LOG_PCALL) {
2062: fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2063: new_cs, new_eip, shift, addend);
2064: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2065: }
2066: #endif
2067: if ((new_cs & 0xfffc) == 0)
2068: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2069: if (load_segment(&e1, &e2, new_cs) != 0)
2070: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2071: if (!(e2 & DESC_S_MASK) ||
2072: !(e2 & DESC_CS_MASK))
2073: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2074: cpl = env->hflags & HF_CPL_MASK;
2075: rpl = new_cs & 3;
2076: if (rpl < cpl)
2077: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2078: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2079: if (e2 & DESC_C_MASK) {
2080: if (dpl > rpl)
2081: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2082: } else {
2083: if (dpl != rpl)
2084: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2085: }
2086: if (!(e2 & DESC_P_MASK))
2087: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2088:
2089: sp += addend;
2090: if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2091: ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2092: /* return to same priledge level */
2093: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2094: get_seg_base(e1, e2),
2095: get_seg_limit(e1, e2),
2096: e2);
2097: } else {
2098: /* return to different priviledge level */
2099: #ifdef TARGET_X86_64
2100: if (shift == 2) {
2101: POPQ(sp, new_esp);
2102: POPQ(sp, new_ss);
2103: new_ss &= 0xffff;
2104: } else
2105: #endif
2106: if (shift == 1) {
2107: /* 32 bits */
2108: POPL(ssp, sp, sp_mask, new_esp);
2109: POPL(ssp, sp, sp_mask, new_ss);
2110: new_ss &= 0xffff;
2111: } else {
2112: /* 16 bits */
2113: POPW(ssp, sp, sp_mask, new_esp);
2114: POPW(ssp, sp, sp_mask, new_ss);
2115: }
2116: #ifdef DEBUG_PCALL
2117: if (loglevel & CPU_LOG_PCALL) {
2118: fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2119: new_ss, new_esp);
2120: }
2121: #endif
2122: if ((new_ss & 0xfffc) == 0) {
2123: #ifdef TARGET_X86_64
2124: /* NULL ss is allowed in long mode if cpl != 3*/
2125: if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2126: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2127: 0, 0xffffffff,
2128: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2129: DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2130: DESC_W_MASK | DESC_A_MASK);
2131: } else
2132: #endif
2133: {
2134: raise_exception_err(EXCP0D_GPF, 0);
2135: }
2136: } else {
2137: if ((new_ss & 3) != rpl)
2138: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2139: if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2140: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2141: if (!(ss_e2 & DESC_S_MASK) ||
2142: (ss_e2 & DESC_CS_MASK) ||
2143: !(ss_e2 & DESC_W_MASK))
2144: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2145: dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2146: if (dpl != rpl)
2147: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2148: if (!(ss_e2 & DESC_P_MASK))
2149: raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2150: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2151: get_seg_base(ss_e1, ss_e2),
2152: get_seg_limit(ss_e1, ss_e2),
2153: ss_e2);
2154: }
2155:
2156: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2157: get_seg_base(e1, e2),
2158: get_seg_limit(e1, e2),
2159: e2);
2160: cpu_x86_set_cpl(env, rpl);
2161: sp = new_esp;
2162: #ifdef TARGET_X86_64
2163: if (env->hflags & HF_CS64_MASK)
2164: sp_mask = -1;
2165: else
2166: #endif
2167: sp_mask = get_sp_mask(ss_e2);
2168:
2169: /* validate data segments */
1.1.1.2 root 2170: validate_seg(R_ES, rpl);
2171: validate_seg(R_DS, rpl);
2172: validate_seg(R_FS, rpl);
2173: validate_seg(R_GS, rpl);
1.1 root 2174:
2175: sp += addend;
2176: }
2177: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2178: env->eip = new_eip;
2179: if (is_iret) {
2180: /* NOTE: 'cpl' is the _old_ CPL */
2181: eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2182: if (cpl == 0)
2183: eflags_mask |= IOPL_MASK;
2184: iopl = (env->eflags >> IOPL_SHIFT) & 3;
2185: if (cpl <= iopl)
2186: eflags_mask |= IF_MASK;
2187: if (shift == 0)
2188: eflags_mask &= 0xffff;
2189: load_eflags(new_eflags, eflags_mask);
2190: }
2191: return;
2192:
2193: return_to_vm86:
2194: POPL(ssp, sp, sp_mask, new_esp);
2195: POPL(ssp, sp, sp_mask, new_ss);
2196: POPL(ssp, sp, sp_mask, new_es);
2197: POPL(ssp, sp, sp_mask, new_ds);
2198: POPL(ssp, sp, sp_mask, new_fs);
2199: POPL(ssp, sp, sp_mask, new_gs);
2200:
2201: /* modify processor state */
2202: load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2203: IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2204: load_seg_vm(R_CS, new_cs & 0xffff);
2205: cpu_x86_set_cpl(env, 3);
2206: load_seg_vm(R_SS, new_ss & 0xffff);
2207: load_seg_vm(R_ES, new_es & 0xffff);
2208: load_seg_vm(R_DS, new_ds & 0xffff);
2209: load_seg_vm(R_FS, new_fs & 0xffff);
2210: load_seg_vm(R_GS, new_gs & 0xffff);
2211:
2212: env->eip = new_eip & 0xffff;
2213: ESP = new_esp;
2214: }
2215:
2216: void helper_iret_protected(int shift, int next_eip)
2217: {
2218: int tss_selector, type;
2219: uint32_t e1, e2;
2220:
2221: /* specific case for TSS */
2222: if (env->eflags & NT_MASK) {
2223: #ifdef TARGET_X86_64
2224: if (env->hflags & HF_LMA_MASK)
2225: raise_exception_err(EXCP0D_GPF, 0);
2226: #endif
2227: tss_selector = lduw_kernel(env->tr.base + 0);
2228: if (tss_selector & 4)
2229: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2230: if (load_segment(&e1, &e2, tss_selector) != 0)
2231: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2232: type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2233: /* NOTE: we check both segment and busy TSS */
2234: if (type != 3)
2235: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2236: switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2237: } else {
2238: helper_ret_protected(shift, 1, 0);
2239: }
2240: #ifdef USE_KQEMU
2241: if (kqemu_is_ok(env)) {
2242: CC_OP = CC_OP_EFLAGS;
2243: env->exception_index = -1;
2244: cpu_loop_exit();
2245: }
2246: #endif
2247: }
2248:
2249: void helper_lret_protected(int shift, int addend)
2250: {
2251: helper_ret_protected(shift, 0, addend);
2252: #ifdef USE_KQEMU
2253: if (kqemu_is_ok(env)) {
2254: env->exception_index = -1;
2255: cpu_loop_exit();
2256: }
2257: #endif
2258: }
2259:
2260: void helper_sysenter(void)
2261: {
2262: if (env->sysenter_cs == 0) {
2263: raise_exception_err(EXCP0D_GPF, 0);
2264: }
2265: env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2266: cpu_x86_set_cpl(env, 0);
2267: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2268: 0, 0xffffffff,
2269: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2270: DESC_S_MASK |
2271: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2272: cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2273: 0, 0xffffffff,
2274: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2275: DESC_S_MASK |
2276: DESC_W_MASK | DESC_A_MASK);
2277: ESP = env->sysenter_esp;
2278: EIP = env->sysenter_eip;
2279: }
2280:
2281: void helper_sysexit(void)
2282: {
2283: int cpl;
2284:
2285: cpl = env->hflags & HF_CPL_MASK;
2286: if (env->sysenter_cs == 0 || cpl != 0) {
2287: raise_exception_err(EXCP0D_GPF, 0);
2288: }
2289: cpu_x86_set_cpl(env, 3);
2290: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2291: 0, 0xffffffff,
2292: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2293: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2294: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2295: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2296: 0, 0xffffffff,
2297: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2298: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2299: DESC_W_MASK | DESC_A_MASK);
2300: ESP = ECX;
2301: EIP = EDX;
2302: #ifdef USE_KQEMU
2303: if (kqemu_is_ok(env)) {
2304: env->exception_index = -1;
2305: cpu_loop_exit();
2306: }
2307: #endif
2308: }
2309:
2310: void helper_movl_crN_T0(int reg)
2311: {
2312: #if !defined(CONFIG_USER_ONLY)
2313: switch(reg) {
2314: case 0:
2315: cpu_x86_update_cr0(env, T0);
2316: break;
2317: case 3:
2318: cpu_x86_update_cr3(env, T0);
2319: break;
2320: case 4:
2321: cpu_x86_update_cr4(env, T0);
2322: break;
2323: case 8:
2324: cpu_set_apic_tpr(env, T0);
2325: break;
2326: default:
2327: env->cr[reg] = T0;
2328: break;
2329: }
2330: #endif
2331: }
2332:
2333: /* XXX: do more */
2334: void helper_movl_drN_T0(int reg)
2335: {
2336: env->dr[reg] = T0;
2337: }
2338:
2339: void helper_invlpg(target_ulong addr)
2340: {
2341: cpu_x86_flush_tlb(env, addr);
2342: }
2343:
2344: void helper_rdtsc(void)
2345: {
2346: uint64_t val;
2347:
2348: if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2349: raise_exception(EXCP0D_GPF);
2350: }
2351: val = cpu_get_tsc(env);
2352: EAX = (uint32_t)(val);
2353: EDX = (uint32_t)(val >> 32);
2354: }
2355:
2356: #if defined(CONFIG_USER_ONLY)
2357: void helper_wrmsr(void)
2358: {
2359: }
2360:
2361: void helper_rdmsr(void)
2362: {
2363: }
2364: #else
2365: void helper_wrmsr(void)
2366: {
2367: uint64_t val;
2368:
2369: val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2370:
2371: switch((uint32_t)ECX) {
2372: case MSR_IA32_SYSENTER_CS:
2373: env->sysenter_cs = val & 0xffff;
2374: break;
2375: case MSR_IA32_SYSENTER_ESP:
2376: env->sysenter_esp = val;
2377: break;
2378: case MSR_IA32_SYSENTER_EIP:
2379: env->sysenter_eip = val;
2380: break;
2381: case MSR_IA32_APICBASE:
2382: cpu_set_apic_base(env, val);
2383: break;
2384: case MSR_EFER:
2385: {
2386: uint64_t update_mask;
2387: update_mask = 0;
2388: if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
2389: update_mask |= MSR_EFER_SCE;
2390: if (env->cpuid_ext2_features & CPUID_EXT2_LM)
2391: update_mask |= MSR_EFER_LME;
2392: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
2393: update_mask |= MSR_EFER_FFXSR;
2394: if (env->cpuid_ext2_features & CPUID_EXT2_NX)
2395: update_mask |= MSR_EFER_NXE;
2396: env->efer = (env->efer & ~update_mask) |
2397: (val & update_mask);
2398: }
2399: break;
2400: case MSR_STAR:
2401: env->star = val;
2402: break;
2403: case MSR_PAT:
2404: env->pat = val;
2405: break;
2406: #ifdef TARGET_X86_64
2407: case MSR_LSTAR:
2408: env->lstar = val;
2409: break;
2410: case MSR_CSTAR:
2411: env->cstar = val;
2412: break;
2413: case MSR_FMASK:
2414: env->fmask = val;
2415: break;
2416: case MSR_FSBASE:
2417: env->segs[R_FS].base = val;
2418: break;
2419: case MSR_GSBASE:
2420: env->segs[R_GS].base = val;
2421: break;
2422: case MSR_KERNELGSBASE:
2423: env->kernelgsbase = val;
2424: break;
2425: #endif
2426: default:
2427: /* XXX: exception ? */
2428: break;
2429: }
2430: }
2431:
2432: void helper_rdmsr(void)
2433: {
2434: uint64_t val;
2435: switch((uint32_t)ECX) {
2436: case MSR_IA32_SYSENTER_CS:
2437: val = env->sysenter_cs;
2438: break;
2439: case MSR_IA32_SYSENTER_ESP:
2440: val = env->sysenter_esp;
2441: break;
2442: case MSR_IA32_SYSENTER_EIP:
2443: val = env->sysenter_eip;
2444: break;
2445: case MSR_IA32_APICBASE:
2446: val = cpu_get_apic_base(env);
2447: break;
2448: case MSR_EFER:
2449: val = env->efer;
2450: break;
2451: case MSR_STAR:
2452: val = env->star;
2453: break;
2454: case MSR_PAT:
2455: val = env->pat;
2456: break;
2457: #ifdef TARGET_X86_64
2458: case MSR_LSTAR:
2459: val = env->lstar;
2460: break;
2461: case MSR_CSTAR:
2462: val = env->cstar;
2463: break;
2464: case MSR_FMASK:
2465: val = env->fmask;
2466: break;
2467: case MSR_FSBASE:
2468: val = env->segs[R_FS].base;
2469: break;
2470: case MSR_GSBASE:
2471: val = env->segs[R_GS].base;
2472: break;
2473: case MSR_KERNELGSBASE:
2474: val = env->kernelgsbase;
2475: break;
2476: #endif
2477: default:
2478: /* XXX: exception ? */
2479: val = 0;
2480: break;
2481: }
2482: EAX = (uint32_t)(val);
2483: EDX = (uint32_t)(val >> 32);
2484: }
2485: #endif
2486:
2487: void helper_lsl(void)
2488: {
2489: unsigned int selector, limit;
2490: uint32_t e1, e2, eflags;
2491: int rpl, dpl, cpl, type;
2492:
2493: eflags = cc_table[CC_OP].compute_all();
2494: selector = T0 & 0xffff;
2495: if (load_segment(&e1, &e2, selector) != 0)
2496: goto fail;
2497: rpl = selector & 3;
2498: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2499: cpl = env->hflags & HF_CPL_MASK;
2500: if (e2 & DESC_S_MASK) {
2501: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2502: /* conforming */
2503: } else {
2504: if (dpl < cpl || dpl < rpl)
2505: goto fail;
2506: }
2507: } else {
2508: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2509: switch(type) {
2510: case 1:
2511: case 2:
2512: case 3:
2513: case 9:
2514: case 11:
2515: break;
2516: default:
2517: goto fail;
2518: }
2519: if (dpl < cpl || dpl < rpl) {
2520: fail:
2521: CC_SRC = eflags & ~CC_Z;
2522: return;
2523: }
2524: }
2525: limit = get_seg_limit(e1, e2);
2526: T1 = limit;
2527: CC_SRC = eflags | CC_Z;
2528: }
2529:
2530: void helper_lar(void)
2531: {
2532: unsigned int selector;
2533: uint32_t e1, e2, eflags;
2534: int rpl, dpl, cpl, type;
2535:
2536: eflags = cc_table[CC_OP].compute_all();
2537: selector = T0 & 0xffff;
2538: if ((selector & 0xfffc) == 0)
2539: goto fail;
2540: if (load_segment(&e1, &e2, selector) != 0)
2541: goto fail;
2542: rpl = selector & 3;
2543: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2544: cpl = env->hflags & HF_CPL_MASK;
2545: if (e2 & DESC_S_MASK) {
2546: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2547: /* conforming */
2548: } else {
2549: if (dpl < cpl || dpl < rpl)
2550: goto fail;
2551: }
2552: } else {
2553: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2554: switch(type) {
2555: case 1:
2556: case 2:
2557: case 3:
2558: case 4:
2559: case 5:
2560: case 9:
2561: case 11:
2562: case 12:
2563: break;
2564: default:
2565: goto fail;
2566: }
2567: if (dpl < cpl || dpl < rpl) {
2568: fail:
2569: CC_SRC = eflags & ~CC_Z;
2570: return;
2571: }
2572: }
2573: T1 = e2 & 0x00f0ff00;
2574: CC_SRC = eflags | CC_Z;
2575: }
2576:
2577: void helper_verr(void)
2578: {
2579: unsigned int selector;
2580: uint32_t e1, e2, eflags;
2581: int rpl, dpl, cpl;
2582:
2583: eflags = cc_table[CC_OP].compute_all();
2584: selector = T0 & 0xffff;
2585: if ((selector & 0xfffc) == 0)
2586: goto fail;
2587: if (load_segment(&e1, &e2, selector) != 0)
2588: goto fail;
2589: if (!(e2 & DESC_S_MASK))
2590: goto fail;
2591: rpl = selector & 3;
2592: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2593: cpl = env->hflags & HF_CPL_MASK;
2594: if (e2 & DESC_CS_MASK) {
2595: if (!(e2 & DESC_R_MASK))
2596: goto fail;
2597: if (!(e2 & DESC_C_MASK)) {
2598: if (dpl < cpl || dpl < rpl)
2599: goto fail;
2600: }
2601: } else {
2602: if (dpl < cpl || dpl < rpl) {
2603: fail:
2604: CC_SRC = eflags & ~CC_Z;
2605: return;
2606: }
2607: }
2608: CC_SRC = eflags | CC_Z;
2609: }
2610:
2611: void helper_verw(void)
2612: {
2613: unsigned int selector;
2614: uint32_t e1, e2, eflags;
2615: int rpl, dpl, cpl;
2616:
2617: eflags = cc_table[CC_OP].compute_all();
2618: selector = T0 & 0xffff;
2619: if ((selector & 0xfffc) == 0)
2620: goto fail;
2621: if (load_segment(&e1, &e2, selector) != 0)
2622: goto fail;
2623: if (!(e2 & DESC_S_MASK))
2624: goto fail;
2625: rpl = selector & 3;
2626: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2627: cpl = env->hflags & HF_CPL_MASK;
2628: if (e2 & DESC_CS_MASK) {
2629: goto fail;
2630: } else {
2631: if (dpl < cpl || dpl < rpl)
2632: goto fail;
2633: if (!(e2 & DESC_W_MASK)) {
2634: fail:
2635: CC_SRC = eflags & ~CC_Z;
2636: return;
2637: }
2638: }
2639: CC_SRC = eflags | CC_Z;
2640: }
2641:
2642: /* FPU helpers */
2643:
2644: void helper_fldt_ST0_A0(void)
2645: {
2646: int new_fpstt;
2647: new_fpstt = (env->fpstt - 1) & 7;
2648: env->fpregs[new_fpstt].d = helper_fldt(A0);
2649: env->fpstt = new_fpstt;
2650: env->fptags[new_fpstt] = 0; /* validate stack entry */
2651: }
2652:
2653: void helper_fstt_ST0_A0(void)
2654: {
2655: helper_fstt(ST0, A0);
2656: }
2657:
2658: void fpu_set_exception(int mask)
2659: {
2660: env->fpus |= mask;
2661: if (env->fpus & (~env->fpuc & FPUC_EM))
2662: env->fpus |= FPUS_SE | FPUS_B;
2663: }
2664:
2665: CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
2666: {
2667: if (b == 0.0)
2668: fpu_set_exception(FPUS_ZE);
2669: return a / b;
2670: }
2671:
2672: void fpu_raise_exception(void)
2673: {
2674: if (env->cr[0] & CR0_NE_MASK) {
2675: raise_exception(EXCP10_COPR);
2676: }
2677: #if !defined(CONFIG_USER_ONLY)
2678: else {
2679: cpu_set_ferr(env);
2680: }
2681: #endif
2682: }
2683:
2684: /* BCD ops */
2685:
2686: void helper_fbld_ST0_A0(void)
2687: {
2688: CPU86_LDouble tmp;
2689: uint64_t val;
2690: unsigned int v;
2691: int i;
2692:
2693: val = 0;
2694: for(i = 8; i >= 0; i--) {
2695: v = ldub(A0 + i);
2696: val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2697: }
2698: tmp = val;
2699: if (ldub(A0 + 9) & 0x80)
2700: tmp = -tmp;
2701: fpush();
2702: ST0 = tmp;
2703: }
2704:
2705: void helper_fbst_ST0_A0(void)
2706: {
2707: int v;
2708: target_ulong mem_ref, mem_end;
2709: int64_t val;
2710:
2711: val = floatx_to_int64(ST0, &env->fp_status);
2712: mem_ref = A0;
2713: mem_end = mem_ref + 9;
2714: if (val < 0) {
2715: stb(mem_end, 0x80);
2716: val = -val;
2717: } else {
2718: stb(mem_end, 0x00);
2719: }
2720: while (mem_ref < mem_end) {
2721: if (val == 0)
2722: break;
2723: v = val % 100;
2724: val = val / 100;
2725: v = ((v / 10) << 4) | (v % 10);
2726: stb(mem_ref++, v);
2727: }
2728: while (mem_ref < mem_end) {
2729: stb(mem_ref++, 0);
2730: }
2731: }
2732:
2733: void helper_f2xm1(void)
2734: {
2735: ST0 = pow(2.0,ST0) - 1.0;
2736: }
2737:
2738: void helper_fyl2x(void)
2739: {
2740: CPU86_LDouble fptemp;
2741:
2742: fptemp = ST0;
2743: if (fptemp>0.0){
2744: fptemp = log(fptemp)/log(2.0); /* log2(ST) */
2745: ST1 *= fptemp;
2746: fpop();
2747: } else {
2748: env->fpus &= (~0x4700);
2749: env->fpus |= 0x400;
2750: }
2751: }
2752:
2753: void helper_fptan(void)
2754: {
2755: CPU86_LDouble fptemp;
2756:
2757: fptemp = ST0;
2758: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2759: env->fpus |= 0x400;
2760: } else {
2761: ST0 = tan(fptemp);
2762: fpush();
2763: ST0 = 1.0;
2764: env->fpus &= (~0x400); /* C2 <-- 0 */
2765: /* the above code is for |arg| < 2**52 only */
2766: }
2767: }
2768:
2769: void helper_fpatan(void)
2770: {
2771: CPU86_LDouble fptemp, fpsrcop;
2772:
2773: fpsrcop = ST1;
2774: fptemp = ST0;
2775: ST1 = atan2(fpsrcop,fptemp);
2776: fpop();
2777: }
2778:
2779: void helper_fxtract(void)
2780: {
2781: CPU86_LDoubleU temp;
2782: unsigned int expdif;
2783:
2784: temp.d = ST0;
2785: expdif = EXPD(temp) - EXPBIAS;
2786: /*DP exponent bias*/
2787: ST0 = expdif;
2788: fpush();
2789: BIASEXPONENT(temp);
2790: ST0 = temp.d;
2791: }
2792:
2793: void helper_fprem1(void)
2794: {
2795: CPU86_LDouble dblq, fpsrcop, fptemp;
2796: CPU86_LDoubleU fpsrcop1, fptemp1;
2797: int expdif;
2798: int q;
2799:
2800: fpsrcop = ST0;
2801: fptemp = ST1;
2802: fpsrcop1.d = fpsrcop;
2803: fptemp1.d = fptemp;
2804: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2805: if (expdif < 53) {
2806: dblq = fpsrcop / fptemp;
2807: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2808: ST0 = fpsrcop - fptemp*dblq;
2809: q = (int)dblq; /* cutting off top bits is assumed here */
2810: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2811: /* (C0,C1,C3) <-- (q2,q1,q0) */
2812: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2813: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2814: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2815: } else {
2816: env->fpus |= 0x400; /* C2 <-- 1 */
2817: fptemp = pow(2.0, expdif-50);
2818: fpsrcop = (ST0 / ST1) / fptemp;
2819: /* fpsrcop = integer obtained by rounding to the nearest */
2820: fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2821: floor(fpsrcop): ceil(fpsrcop);
2822: ST0 -= (ST1 * fpsrcop * fptemp);
2823: }
2824: }
2825:
2826: void helper_fprem(void)
2827: {
2828: CPU86_LDouble dblq, fpsrcop, fptemp;
2829: CPU86_LDoubleU fpsrcop1, fptemp1;
2830: int expdif;
2831: int q;
2832:
2833: fpsrcop = ST0;
2834: fptemp = ST1;
2835: fpsrcop1.d = fpsrcop;
2836: fptemp1.d = fptemp;
2837: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2838: if ( expdif < 53 ) {
2839: dblq = fpsrcop / fptemp;
2840: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2841: ST0 = fpsrcop - fptemp*dblq;
2842: q = (int)dblq; /* cutting off top bits is assumed here */
2843: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2844: /* (C0,C1,C3) <-- (q2,q1,q0) */
2845: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2846: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2847: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2848: } else {
2849: env->fpus |= 0x400; /* C2 <-- 1 */
2850: fptemp = pow(2.0, expdif-50);
2851: fpsrcop = (ST0 / ST1) / fptemp;
2852: /* fpsrcop = integer obtained by chopping */
2853: fpsrcop = (fpsrcop < 0.0)?
2854: -(floor(fabs(fpsrcop))): floor(fpsrcop);
2855: ST0 -= (ST1 * fpsrcop * fptemp);
2856: }
2857: }
2858:
2859: void helper_fyl2xp1(void)
2860: {
2861: CPU86_LDouble fptemp;
2862:
2863: fptemp = ST0;
2864: if ((fptemp+1.0)>0.0) {
2865: fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2866: ST1 *= fptemp;
2867: fpop();
2868: } else {
2869: env->fpus &= (~0x4700);
2870: env->fpus |= 0x400;
2871: }
2872: }
2873:
2874: void helper_fsqrt(void)
2875: {
2876: CPU86_LDouble fptemp;
2877:
2878: fptemp = ST0;
2879: if (fptemp<0.0) {
2880: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2881: env->fpus |= 0x400;
2882: }
2883: ST0 = sqrt(fptemp);
2884: }
2885:
2886: void helper_fsincos(void)
2887: {
2888: CPU86_LDouble fptemp;
2889:
2890: fptemp = ST0;
2891: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2892: env->fpus |= 0x400;
2893: } else {
2894: ST0 = sin(fptemp);
2895: fpush();
2896: ST0 = cos(fptemp);
2897: env->fpus &= (~0x400); /* C2 <-- 0 */
2898: /* the above code is for |arg| < 2**63 only */
2899: }
2900: }
2901:
2902: void helper_frndint(void)
2903: {
2904: ST0 = floatx_round_to_int(ST0, &env->fp_status);
2905: }
2906:
2907: void helper_fscale(void)
2908: {
2909: ST0 = ldexp (ST0, (int)(ST1));
2910: }
2911:
2912: void helper_fsin(void)
2913: {
2914: CPU86_LDouble fptemp;
2915:
2916: fptemp = ST0;
2917: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2918: env->fpus |= 0x400;
2919: } else {
2920: ST0 = sin(fptemp);
2921: env->fpus &= (~0x400); /* C2 <-- 0 */
2922: /* the above code is for |arg| < 2**53 only */
2923: }
2924: }
2925:
2926: void helper_fcos(void)
2927: {
2928: CPU86_LDouble fptemp;
2929:
2930: fptemp = ST0;
2931: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2932: env->fpus |= 0x400;
2933: } else {
2934: ST0 = cos(fptemp);
2935: env->fpus &= (~0x400); /* C2 <-- 0 */
2936: /* the above code is for |arg5 < 2**63 only */
2937: }
2938: }
2939:
2940: void helper_fxam_ST0(void)
2941: {
2942: CPU86_LDoubleU temp;
2943: int expdif;
2944:
2945: temp.d = ST0;
2946:
2947: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2948: if (SIGND(temp))
2949: env->fpus |= 0x200; /* C1 <-- 1 */
2950:
2951: expdif = EXPD(temp);
2952: if (expdif == MAXEXPD) {
2953: if (MANTD(temp) == 0)
2954: env->fpus |= 0x500 /*Infinity*/;
2955: else
2956: env->fpus |= 0x100 /*NaN*/;
2957: } else if (expdif == 0) {
2958: if (MANTD(temp) == 0)
2959: env->fpus |= 0x4000 /*Zero*/;
2960: else
2961: env->fpus |= 0x4400 /*Denormal*/;
2962: } else {
2963: env->fpus |= 0x400;
2964: }
2965: }
2966:
2967: void helper_fstenv(target_ulong ptr, int data32)
2968: {
2969: int fpus, fptag, exp, i;
2970: uint64_t mant;
2971: CPU86_LDoubleU tmp;
2972:
2973: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2974: fptag = 0;
2975: for (i=7; i>=0; i--) {
2976: fptag <<= 2;
2977: if (env->fptags[i]) {
2978: fptag |= 3;
2979: } else {
2980: tmp.d = env->fpregs[i].d;
2981: exp = EXPD(tmp);
2982: mant = MANTD(tmp);
2983: if (exp == 0 && mant == 0) {
2984: /* zero */
2985: fptag |= 1;
2986: } else if (exp == 0 || exp == MAXEXPD
2987: #ifdef USE_X86LDOUBLE
2988: || (mant & (1LL << 63)) == 0
2989: #endif
2990: ) {
2991: /* NaNs, infinity, denormal */
2992: fptag |= 2;
2993: }
2994: }
2995: }
2996: if (data32) {
2997: /* 32 bit */
2998: stl(ptr, env->fpuc);
2999: stl(ptr + 4, fpus);
3000: stl(ptr + 8, fptag);
3001: stl(ptr + 12, 0); /* fpip */
3002: stl(ptr + 16, 0); /* fpcs */
3003: stl(ptr + 20, 0); /* fpoo */
3004: stl(ptr + 24, 0); /* fpos */
3005: } else {
3006: /* 16 bit */
3007: stw(ptr, env->fpuc);
3008: stw(ptr + 2, fpus);
3009: stw(ptr + 4, fptag);
3010: stw(ptr + 6, 0);
3011: stw(ptr + 8, 0);
3012: stw(ptr + 10, 0);
3013: stw(ptr + 12, 0);
3014: }
3015: }
3016:
3017: void helper_fldenv(target_ulong ptr, int data32)
3018: {
3019: int i, fpus, fptag;
3020:
3021: if (data32) {
3022: env->fpuc = lduw(ptr);
3023: fpus = lduw(ptr + 4);
3024: fptag = lduw(ptr + 8);
3025: }
3026: else {
3027: env->fpuc = lduw(ptr);
3028: fpus = lduw(ptr + 2);
3029: fptag = lduw(ptr + 4);
3030: }
3031: env->fpstt = (fpus >> 11) & 7;
3032: env->fpus = fpus & ~0x3800;
3033: for(i = 0;i < 8; i++) {
3034: env->fptags[i] = ((fptag & 3) == 3);
3035: fptag >>= 2;
3036: }
3037: }
3038:
3039: void helper_fsave(target_ulong ptr, int data32)
3040: {
3041: CPU86_LDouble tmp;
3042: int i;
3043:
3044: helper_fstenv(ptr, data32);
3045:
3046: ptr += (14 << data32);
3047: for(i = 0;i < 8; i++) {
3048: tmp = ST(i);
3049: helper_fstt(tmp, ptr);
3050: ptr += 10;
3051: }
3052:
3053: /* fninit */
3054: env->fpus = 0;
3055: env->fpstt = 0;
3056: env->fpuc = 0x37f;
3057: env->fptags[0] = 1;
3058: env->fptags[1] = 1;
3059: env->fptags[2] = 1;
3060: env->fptags[3] = 1;
3061: env->fptags[4] = 1;
3062: env->fptags[5] = 1;
3063: env->fptags[6] = 1;
3064: env->fptags[7] = 1;
3065: }
3066:
3067: void helper_frstor(target_ulong ptr, int data32)
3068: {
3069: CPU86_LDouble tmp;
3070: int i;
3071:
3072: helper_fldenv(ptr, data32);
3073: ptr += (14 << data32);
3074:
3075: for(i = 0;i < 8; i++) {
3076: tmp = helper_fldt(ptr);
3077: ST(i) = tmp;
3078: ptr += 10;
3079: }
3080: }
3081:
3082: void helper_fxsave(target_ulong ptr, int data64)
3083: {
3084: int fpus, fptag, i, nb_xmm_regs;
3085: CPU86_LDouble tmp;
3086: target_ulong addr;
3087:
3088: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3089: fptag = 0;
3090: for(i = 0; i < 8; i++) {
3091: fptag |= (env->fptags[i] << i);
3092: }
3093: stw(ptr, env->fpuc);
3094: stw(ptr + 2, fpus);
3095: stw(ptr + 4, fptag ^ 0xff);
3096:
3097: addr = ptr + 0x20;
3098: for(i = 0;i < 8; i++) {
3099: tmp = ST(i);
3100: helper_fstt(tmp, addr);
3101: addr += 16;
3102: }
3103:
3104: if (env->cr[4] & CR4_OSFXSR_MASK) {
3105: /* XXX: finish it */
3106: stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3107: stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3108: nb_xmm_regs = 8 << data64;
3109: addr = ptr + 0xa0;
3110: for(i = 0; i < nb_xmm_regs; i++) {
3111: stq(addr, env->xmm_regs[i].XMM_Q(0));
3112: stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3113: addr += 16;
3114: }
3115: }
3116: }
3117:
3118: void helper_fxrstor(target_ulong ptr, int data64)
3119: {
3120: int i, fpus, fptag, nb_xmm_regs;
3121: CPU86_LDouble tmp;
3122: target_ulong addr;
3123:
3124: env->fpuc = lduw(ptr);
3125: fpus = lduw(ptr + 2);
3126: fptag = lduw(ptr + 4);
3127: env->fpstt = (fpus >> 11) & 7;
3128: env->fpus = fpus & ~0x3800;
3129: fptag ^= 0xff;
3130: for(i = 0;i < 8; i++) {
3131: env->fptags[i] = ((fptag >> i) & 1);
3132: }
3133:
3134: addr = ptr + 0x20;
3135: for(i = 0;i < 8; i++) {
3136: tmp = helper_fldt(addr);
3137: ST(i) = tmp;
3138: addr += 16;
3139: }
3140:
3141: if (env->cr[4] & CR4_OSFXSR_MASK) {
3142: /* XXX: finish it */
3143: env->mxcsr = ldl(ptr + 0x18);
3144: //ldl(ptr + 0x1c);
3145: nb_xmm_regs = 8 << data64;
3146: addr = ptr + 0xa0;
3147: for(i = 0; i < nb_xmm_regs; i++) {
3148: env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3149: env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3150: addr += 16;
3151: }
3152: }
3153: }
3154:
3155: #ifndef USE_X86LDOUBLE
3156:
3157: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3158: {
3159: CPU86_LDoubleU temp;
3160: int e;
3161:
3162: temp.d = f;
3163: /* mantissa */
3164: *pmant = (MANTD(temp) << 11) | (1LL << 63);
3165: /* exponent + sign */
3166: e = EXPD(temp) - EXPBIAS + 16383;
3167: e |= SIGND(temp) >> 16;
3168: *pexp = e;
3169: }
3170:
3171: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3172: {
3173: CPU86_LDoubleU temp;
3174: int e;
3175: uint64_t ll;
3176:
3177: /* XXX: handle overflow ? */
3178: e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3179: e |= (upper >> 4) & 0x800; /* sign */
3180: ll = (mant >> 11) & ((1LL << 52) - 1);
3181: #ifdef __arm__
3182: temp.l.upper = (e << 20) | (ll >> 32);
3183: temp.l.lower = ll;
3184: #else
3185: temp.ll = ll | ((uint64_t)e << 52);
3186: #endif
3187: return temp.d;
3188: }
3189:
3190: #else
3191:
3192: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3193: {
3194: CPU86_LDoubleU temp;
3195:
3196: temp.d = f;
3197: *pmant = temp.l.lower;
3198: *pexp = temp.l.upper;
3199: }
3200:
3201: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3202: {
3203: CPU86_LDoubleU temp;
3204:
3205: temp.l.upper = upper;
3206: temp.l.lower = mant;
3207: return temp.d;
3208: }
3209: #endif
3210:
3211: #ifdef TARGET_X86_64
3212:
3213: //#define DEBUG_MULDIV
3214:
3215: static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3216: {
3217: *plow += a;
3218: /* carry test */
3219: if (*plow < a)
3220: (*phigh)++;
3221: *phigh += b;
3222: }
3223:
3224: static void neg128(uint64_t *plow, uint64_t *phigh)
3225: {
3226: *plow = ~ *plow;
3227: *phigh = ~ *phigh;
3228: add128(plow, phigh, 1, 0);
3229: }
3230:
3231: static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3232: {
3233: uint32_t a0, a1, b0, b1;
3234: uint64_t v;
3235:
3236: a0 = a;
3237: a1 = a >> 32;
3238:
3239: b0 = b;
3240: b1 = b >> 32;
3241:
3242: v = (uint64_t)a0 * (uint64_t)b0;
3243: *plow = v;
3244: *phigh = 0;
3245:
3246: v = (uint64_t)a0 * (uint64_t)b1;
3247: add128(plow, phigh, v << 32, v >> 32);
3248:
3249: v = (uint64_t)a1 * (uint64_t)b0;
3250: add128(plow, phigh, v << 32, v >> 32);
3251:
3252: v = (uint64_t)a1 * (uint64_t)b1;
3253: *phigh += v;
3254: #ifdef DEBUG_MULDIV
3255: printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
3256: a, b, *phigh, *plow);
3257: #endif
3258: }
3259:
3260: static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
3261: {
3262: int sa, sb;
3263: sa = (a < 0);
3264: if (sa)
3265: a = -a;
3266: sb = (b < 0);
3267: if (sb)
3268: b = -b;
3269: mul64(plow, phigh, a, b);
3270: if (sa ^ sb) {
3271: neg128(plow, phigh);
3272: }
3273: }
3274:
3275: /* return TRUE if overflow */
3276: static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3277: {
3278: uint64_t q, r, a1, a0;
1.1.1.2 root 3279: int i, qb, ab;
1.1 root 3280:
3281: a0 = *plow;
3282: a1 = *phigh;
3283: if (a1 == 0) {
3284: q = a0 / b;
3285: r = a0 % b;
3286: *plow = q;
3287: *phigh = r;
3288: } else {
3289: if (a1 >= b)
3290: return 1;
3291: /* XXX: use a better algorithm */
3292: for(i = 0; i < 64; i++) {
1.1.1.2 root 3293: ab = a1 >> 63;
1.1 root 3294: a1 = (a1 << 1) | (a0 >> 63);
1.1.1.2 root 3295: if (ab || a1 >= b) {
1.1 root 3296: a1 -= b;
3297: qb = 1;
3298: } else {
3299: qb = 0;
3300: }
3301: a0 = (a0 << 1) | qb;
3302: }
3303: #if defined(DEBUG_MULDIV)
3304: printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n",
3305: *phigh, *plow, b, a0, a1);
3306: #endif
3307: *plow = a0;
3308: *phigh = a1;
3309: }
3310: return 0;
3311: }
3312:
3313: /* return TRUE if overflow */
3314: static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3315: {
3316: int sa, sb;
3317: sa = ((int64_t)*phigh < 0);
3318: if (sa)
3319: neg128(plow, phigh);
3320: sb = (b < 0);
3321: if (sb)
3322: b = -b;
3323: if (div64(plow, phigh, b) != 0)
3324: return 1;
3325: if (sa ^ sb) {
3326: if (*plow > (1ULL << 63))
3327: return 1;
3328: *plow = - *plow;
3329: } else {
3330: if (*plow >= (1ULL << 63))
3331: return 1;
3332: }
3333: if (sa)
3334: *phigh = - *phigh;
3335: return 0;
3336: }
3337:
3338: void helper_mulq_EAX_T0(void)
3339: {
3340: uint64_t r0, r1;
3341:
3342: mul64(&r0, &r1, EAX, T0);
3343: EAX = r0;
3344: EDX = r1;
3345: CC_DST = r0;
3346: CC_SRC = r1;
3347: }
3348:
3349: void helper_imulq_EAX_T0(void)
3350: {
3351: uint64_t r0, r1;
3352:
3353: imul64(&r0, &r1, EAX, T0);
3354: EAX = r0;
3355: EDX = r1;
3356: CC_DST = r0;
3357: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3358: }
3359:
3360: void helper_imulq_T0_T1(void)
3361: {
3362: uint64_t r0, r1;
3363:
3364: imul64(&r0, &r1, T0, T1);
3365: T0 = r0;
3366: CC_DST = r0;
3367: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3368: }
3369:
3370: void helper_divq_EAX_T0(void)
3371: {
3372: uint64_t r0, r1;
3373: if (T0 == 0) {
3374: raise_exception(EXCP00_DIVZ);
3375: }
3376: r0 = EAX;
3377: r1 = EDX;
3378: if (div64(&r0, &r1, T0))
3379: raise_exception(EXCP00_DIVZ);
3380: EAX = r0;
3381: EDX = r1;
3382: }
3383:
3384: void helper_idivq_EAX_T0(void)
3385: {
3386: uint64_t r0, r1;
3387: if (T0 == 0) {
3388: raise_exception(EXCP00_DIVZ);
3389: }
3390: r0 = EAX;
3391: r1 = EDX;
3392: if (idiv64(&r0, &r1, T0))
3393: raise_exception(EXCP00_DIVZ);
3394: EAX = r0;
3395: EDX = r1;
3396: }
3397:
1.1.1.3 ! root 3398: void helper_bswapq_T0(void)
! 3399: {
! 3400: T0 = bswap64(T0);
! 3401: }
1.1 root 3402: #endif
3403:
3404: float approx_rsqrt(float a)
3405: {
3406: return 1.0 / sqrt(a);
3407: }
3408:
3409: float approx_rcp(float a)
3410: {
3411: return 1.0 / a;
3412: }
3413:
3414: void update_fp_status(void)
3415: {
3416: int rnd_type;
3417:
3418: /* set rounding mode */
3419: switch(env->fpuc & RC_MASK) {
3420: default:
3421: case RC_NEAR:
3422: rnd_type = float_round_nearest_even;
3423: break;
3424: case RC_DOWN:
3425: rnd_type = float_round_down;
3426: break;
3427: case RC_UP:
3428: rnd_type = float_round_up;
3429: break;
3430: case RC_CHOP:
3431: rnd_type = float_round_to_zero;
3432: break;
3433: }
3434: set_float_rounding_mode(rnd_type, &env->fp_status);
3435: #ifdef FLOATX80
3436: switch((env->fpuc >> 8) & 3) {
3437: case 0:
3438: rnd_type = 32;
3439: break;
3440: case 2:
3441: rnd_type = 64;
3442: break;
3443: case 3:
3444: default:
3445: rnd_type = 80;
3446: break;
3447: }
3448: set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3449: #endif
3450: }
3451:
3452: #if !defined(CONFIG_USER_ONLY)
3453:
3454: #define MMUSUFFIX _mmu
3455: #define GETPC() (__builtin_return_address(0))
3456:
3457: #define SHIFT 0
3458: #include "softmmu_template.h"
3459:
3460: #define SHIFT 1
3461: #include "softmmu_template.h"
3462:
3463: #define SHIFT 2
3464: #include "softmmu_template.h"
3465:
3466: #define SHIFT 3
3467: #include "softmmu_template.h"
3468:
3469: #endif
3470:
3471: /* try to fill the TLB and return an exception if error. If retaddr is
3472: NULL, it means that the function was called in C code (i.e. not
3473: from generated code or from helper.c) */
3474: /* XXX: fix it to restore all registers */
3475: void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
3476: {
3477: TranslationBlock *tb;
3478: int ret;
3479: unsigned long pc;
3480: CPUX86State *saved_env;
3481:
3482: /* XXX: hack to restore env in all cases, even if not called from
3483: generated code */
3484: saved_env = env;
3485: env = cpu_single_env;
3486:
3487: ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
3488: if (ret) {
3489: if (retaddr) {
3490: /* now we have a real cpu fault */
3491: pc = (unsigned long)retaddr;
3492: tb = tb_find_pc(pc);
3493: if (tb) {
3494: /* the PC is inside the translated code. It means that we have
3495: a virtual CPU fault */
3496: cpu_restore_state(tb, env, pc, NULL);
3497: }
3498: }
3499: if (retaddr)
1.1.1.2 root 3500: raise_exception_err(env->exception_index, env->error_code);
1.1 root 3501: else
1.1.1.2 root 3502: raise_exception_err_norestore(env->exception_index, env->error_code);
1.1 root 3503: }
3504: env = saved_env;
3505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.