|
|
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);
1.1.1.4 ! root 1677: CC_OP = CC_OP_EFLAGS;
1.1 root 1678: break;
1679: case 4: /* 286 call gate */
1680: case 12: /* 386 call gate */
1681: if ((dpl < cpl) || (dpl < rpl))
1682: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1683: if (!(e2 & DESC_P_MASK))
1684: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1685: gate_cs = e1 >> 16;
1686: new_eip = (e1 & 0xffff);
1687: if (type == 12)
1688: new_eip |= (e2 & 0xffff0000);
1689: if (load_segment(&e1, &e2, gate_cs) != 0)
1690: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1691: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1692: /* must be code segment */
1693: if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
1694: (DESC_S_MASK | DESC_CS_MASK)))
1695: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1696: if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1697: (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1698: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1699: if (!(e2 & DESC_P_MASK))
1700: raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1701: limit = get_seg_limit(e1, e2);
1702: if (new_eip > limit)
1703: raise_exception_err(EXCP0D_GPF, 0);
1704: cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1705: get_seg_base(e1, e2), limit, e2);
1706: EIP = new_eip;
1707: break;
1708: default:
1709: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1710: break;
1711: }
1712: }
1713: }
1714:
1715: /* real mode call */
1716: void helper_lcall_real_T0_T1(int shift, int next_eip)
1717: {
1718: int new_cs, new_eip;
1719: uint32_t esp, esp_mask;
1720: target_ulong ssp;
1721:
1722: new_cs = T0;
1723: new_eip = T1;
1724: esp = ESP;
1725: esp_mask = get_sp_mask(env->segs[R_SS].flags);
1726: ssp = env->segs[R_SS].base;
1727: if (shift) {
1728: PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1729: PUSHL(ssp, esp, esp_mask, next_eip);
1730: } else {
1731: PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1732: PUSHW(ssp, esp, esp_mask, next_eip);
1733: }
1734:
1735: ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1736: env->eip = new_eip;
1737: env->segs[R_CS].selector = new_cs;
1738: env->segs[R_CS].base = (new_cs << 4);
1739: }
1740:
1741: /* protected mode call */
1742: void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
1743: {
1.1.1.2 root 1744: int new_cs, new_stack, i;
1.1 root 1745: uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1746: uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1747: uint32_t val, limit, old_sp_mask;
1.1.1.2 root 1748: target_ulong ssp, old_ssp, next_eip, new_eip;
1.1 root 1749:
1750: new_cs = T0;
1751: new_eip = T1;
1752: next_eip = env->eip + next_eip_addend;
1753: #ifdef DEBUG_PCALL
1754: if (loglevel & CPU_LOG_PCALL) {
1755: fprintf(logfile, "lcall %04x:%08x s=%d\n",
1.1.1.2 root 1756: new_cs, (uint32_t)new_eip, shift);
1.1 root 1757: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1758: }
1759: #endif
1760: if ((new_cs & 0xfffc) == 0)
1761: raise_exception_err(EXCP0D_GPF, 0);
1762: if (load_segment(&e1, &e2, new_cs) != 0)
1763: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1764: cpl = env->hflags & HF_CPL_MASK;
1765: #ifdef DEBUG_PCALL
1766: if (loglevel & CPU_LOG_PCALL) {
1767: fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1768: }
1769: #endif
1770: if (e2 & DESC_S_MASK) {
1771: if (!(e2 & DESC_CS_MASK))
1772: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1773: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1774: if (e2 & DESC_C_MASK) {
1775: /* conforming code segment */
1776: if (dpl > cpl)
1777: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1778: } else {
1779: /* non conforming code segment */
1780: rpl = new_cs & 3;
1781: if (rpl > cpl)
1782: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1783: if (dpl != cpl)
1784: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1785: }
1786: if (!(e2 & DESC_P_MASK))
1787: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1788:
1789: #ifdef TARGET_X86_64
1790: /* XXX: check 16/32 bit cases in long mode */
1791: if (shift == 2) {
1792: target_ulong rsp;
1793: /* 64 bit case */
1794: rsp = ESP;
1795: PUSHQ(rsp, env->segs[R_CS].selector);
1796: PUSHQ(rsp, next_eip);
1797: /* from this point, not restartable */
1798: ESP = rsp;
1799: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1800: get_seg_base(e1, e2),
1801: get_seg_limit(e1, e2), e2);
1802: EIP = new_eip;
1803: } else
1804: #endif
1805: {
1806: sp = ESP;
1807: sp_mask = get_sp_mask(env->segs[R_SS].flags);
1808: ssp = env->segs[R_SS].base;
1809: if (shift) {
1810: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1811: PUSHL(ssp, sp, sp_mask, next_eip);
1812: } else {
1813: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1814: PUSHW(ssp, sp, sp_mask, next_eip);
1815: }
1816:
1817: limit = get_seg_limit(e1, e2);
1818: if (new_eip > limit)
1819: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1820: /* from this point, not restartable */
1821: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1822: cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1823: get_seg_base(e1, e2), limit, e2);
1824: EIP = new_eip;
1825: }
1826: } else {
1827: /* check gate type */
1828: type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1829: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1830: rpl = new_cs & 3;
1831: switch(type) {
1832: case 1: /* available 286 TSS */
1833: case 9: /* available 386 TSS */
1834: case 5: /* task gate */
1835: if (dpl < cpl || dpl < rpl)
1836: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1837: switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
1.1.1.4 ! root 1838: CC_OP = CC_OP_EFLAGS;
1.1 root 1839: return;
1840: case 4: /* 286 call gate */
1841: case 12: /* 386 call gate */
1842: break;
1843: default:
1844: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1845: break;
1846: }
1847: shift = type >> 3;
1848:
1849: if (dpl < cpl || dpl < rpl)
1850: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1851: /* check valid bit */
1852: if (!(e2 & DESC_P_MASK))
1853: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1854: selector = e1 >> 16;
1855: offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1856: param_count = e2 & 0x1f;
1857: if ((selector & 0xfffc) == 0)
1858: raise_exception_err(EXCP0D_GPF, 0);
1859:
1860: if (load_segment(&e1, &e2, selector) != 0)
1861: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1862: if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1863: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1864: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1865: if (dpl > cpl)
1866: raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1867: if (!(e2 & DESC_P_MASK))
1868: raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1869:
1870: if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1871: /* to inner priviledge */
1872: get_ss_esp_from_tss(&ss, &sp, dpl);
1873: #ifdef DEBUG_PCALL
1874: if (loglevel & CPU_LOG_PCALL)
1875: fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
1876: ss, sp, param_count, ESP);
1877: #endif
1878: if ((ss & 0xfffc) == 0)
1879: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1880: if ((ss & 3) != dpl)
1881: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1882: if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1883: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1884: ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1885: if (ss_dpl != dpl)
1886: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1887: if (!(ss_e2 & DESC_S_MASK) ||
1888: (ss_e2 & DESC_CS_MASK) ||
1889: !(ss_e2 & DESC_W_MASK))
1890: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1891: if (!(ss_e2 & DESC_P_MASK))
1892: raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1893:
1894: // push_size = ((param_count * 2) + 8) << shift;
1895:
1896: old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1897: old_ssp = env->segs[R_SS].base;
1898:
1899: sp_mask = get_sp_mask(ss_e2);
1900: ssp = get_seg_base(ss_e1, ss_e2);
1901: if (shift) {
1902: PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1903: PUSHL(ssp, sp, sp_mask, ESP);
1904: for(i = param_count - 1; i >= 0; i--) {
1905: val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1906: PUSHL(ssp, sp, sp_mask, val);
1907: }
1908: } else {
1909: PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1910: PUSHW(ssp, sp, sp_mask, ESP);
1911: for(i = param_count - 1; i >= 0; i--) {
1912: val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1913: PUSHW(ssp, sp, sp_mask, val);
1914: }
1915: }
1916: new_stack = 1;
1917: } else {
1918: /* to same priviledge */
1919: sp = ESP;
1920: sp_mask = get_sp_mask(env->segs[R_SS].flags);
1921: ssp = env->segs[R_SS].base;
1922: // push_size = (4 << shift);
1923: new_stack = 0;
1924: }
1925:
1926: if (shift) {
1927: PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1928: PUSHL(ssp, sp, sp_mask, next_eip);
1929: } else {
1930: PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1931: PUSHW(ssp, sp, sp_mask, next_eip);
1932: }
1933:
1934: /* from this point, not restartable */
1935:
1936: if (new_stack) {
1937: ss = (ss & ~3) | dpl;
1938: cpu_x86_load_seg_cache(env, R_SS, ss,
1939: ssp,
1940: get_seg_limit(ss_e1, ss_e2),
1941: ss_e2);
1942: }
1943:
1944: selector = (selector & ~3) | dpl;
1945: cpu_x86_load_seg_cache(env, R_CS, selector,
1946: get_seg_base(e1, e2),
1947: get_seg_limit(e1, e2),
1948: e2);
1949: cpu_x86_set_cpl(env, dpl);
1950: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1951: EIP = offset;
1952: }
1953: #ifdef USE_KQEMU
1954: if (kqemu_is_ok(env)) {
1955: env->exception_index = -1;
1956: cpu_loop_exit();
1957: }
1958: #endif
1959: }
1960:
1961: /* real and vm86 mode iret */
1962: void helper_iret_real(int shift)
1963: {
1964: uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1965: target_ulong ssp;
1966: int eflags_mask;
1967:
1968: sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1969: sp = ESP;
1970: ssp = env->segs[R_SS].base;
1971: if (shift == 1) {
1972: /* 32 bits */
1973: POPL(ssp, sp, sp_mask, new_eip);
1974: POPL(ssp, sp, sp_mask, new_cs);
1975: new_cs &= 0xffff;
1976: POPL(ssp, sp, sp_mask, new_eflags);
1977: } else {
1978: /* 16 bits */
1979: POPW(ssp, sp, sp_mask, new_eip);
1980: POPW(ssp, sp, sp_mask, new_cs);
1981: POPW(ssp, sp, sp_mask, new_eflags);
1982: }
1983: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1984: load_seg_vm(R_CS, new_cs);
1985: env->eip = new_eip;
1986: if (env->eflags & VM_MASK)
1987: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
1988: else
1989: eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
1990: if (shift == 0)
1991: eflags_mask &= 0xffff;
1992: load_eflags(new_eflags, eflags_mask);
1993: }
1994:
1995: static inline void validate_seg(int seg_reg, int cpl)
1996: {
1997: int dpl;
1998: uint32_t e2;
1.1.1.2 root 1999:
2000: /* XXX: on x86_64, we do not want to nullify FS and GS because
2001: they may still contain a valid base. I would be interested to
2002: know how a real x86_64 CPU behaves */
2003: if ((seg_reg == R_FS || seg_reg == R_GS) &&
2004: (env->segs[seg_reg].selector & 0xfffc) == 0)
2005: return;
2006:
1.1 root 2007: e2 = env->segs[seg_reg].flags;
2008: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2009: if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2010: /* data or non conforming code segment */
2011: if (dpl < cpl) {
2012: cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2013: }
2014: }
2015: }
2016:
2017: /* protected mode iret */
2018: static inline void helper_ret_protected(int shift, int is_iret, int addend)
2019: {
2020: uint32_t new_cs, new_eflags, new_ss;
2021: uint32_t new_es, new_ds, new_fs, new_gs;
2022: uint32_t e1, e2, ss_e1, ss_e2;
2023: int cpl, dpl, rpl, eflags_mask, iopl;
2024: target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2025:
2026: #ifdef TARGET_X86_64
2027: if (shift == 2)
2028: sp_mask = -1;
2029: else
2030: #endif
2031: sp_mask = get_sp_mask(env->segs[R_SS].flags);
2032: sp = ESP;
2033: ssp = env->segs[R_SS].base;
2034: new_eflags = 0; /* avoid warning */
2035: #ifdef TARGET_X86_64
2036: if (shift == 2) {
2037: POPQ(sp, new_eip);
2038: POPQ(sp, new_cs);
2039: new_cs &= 0xffff;
2040: if (is_iret) {
2041: POPQ(sp, new_eflags);
2042: }
2043: } else
2044: #endif
2045: if (shift == 1) {
2046: /* 32 bits */
2047: POPL(ssp, sp, sp_mask, new_eip);
2048: POPL(ssp, sp, sp_mask, new_cs);
2049: new_cs &= 0xffff;
2050: if (is_iret) {
2051: POPL(ssp, sp, sp_mask, new_eflags);
2052: if (new_eflags & VM_MASK)
2053: goto return_to_vm86;
2054: }
2055: } else {
2056: /* 16 bits */
2057: POPW(ssp, sp, sp_mask, new_eip);
2058: POPW(ssp, sp, sp_mask, new_cs);
2059: if (is_iret)
2060: POPW(ssp, sp, sp_mask, new_eflags);
2061: }
2062: #ifdef DEBUG_PCALL
2063: if (loglevel & CPU_LOG_PCALL) {
2064: fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2065: new_cs, new_eip, shift, addend);
2066: cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2067: }
2068: #endif
2069: if ((new_cs & 0xfffc) == 0)
2070: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2071: if (load_segment(&e1, &e2, new_cs) != 0)
2072: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2073: if (!(e2 & DESC_S_MASK) ||
2074: !(e2 & DESC_CS_MASK))
2075: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2076: cpl = env->hflags & HF_CPL_MASK;
2077: rpl = new_cs & 3;
2078: if (rpl < cpl)
2079: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2080: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2081: if (e2 & DESC_C_MASK) {
2082: if (dpl > rpl)
2083: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2084: } else {
2085: if (dpl != rpl)
2086: raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2087: }
2088: if (!(e2 & DESC_P_MASK))
2089: raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2090:
2091: sp += addend;
2092: if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2093: ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2094: /* return to same priledge level */
2095: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2096: get_seg_base(e1, e2),
2097: get_seg_limit(e1, e2),
2098: e2);
2099: } else {
2100: /* return to different priviledge level */
2101: #ifdef TARGET_X86_64
2102: if (shift == 2) {
2103: POPQ(sp, new_esp);
2104: POPQ(sp, new_ss);
2105: new_ss &= 0xffff;
2106: } else
2107: #endif
2108: if (shift == 1) {
2109: /* 32 bits */
2110: POPL(ssp, sp, sp_mask, new_esp);
2111: POPL(ssp, sp, sp_mask, new_ss);
2112: new_ss &= 0xffff;
2113: } else {
2114: /* 16 bits */
2115: POPW(ssp, sp, sp_mask, new_esp);
2116: POPW(ssp, sp, sp_mask, new_ss);
2117: }
2118: #ifdef DEBUG_PCALL
2119: if (loglevel & CPU_LOG_PCALL) {
2120: fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2121: new_ss, new_esp);
2122: }
2123: #endif
2124: if ((new_ss & 0xfffc) == 0) {
2125: #ifdef TARGET_X86_64
2126: /* NULL ss is allowed in long mode if cpl != 3*/
2127: if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2128: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2129: 0, 0xffffffff,
2130: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2131: DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2132: DESC_W_MASK | DESC_A_MASK);
2133: } else
2134: #endif
2135: {
2136: raise_exception_err(EXCP0D_GPF, 0);
2137: }
2138: } else {
2139: if ((new_ss & 3) != rpl)
2140: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2141: if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2142: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2143: if (!(ss_e2 & DESC_S_MASK) ||
2144: (ss_e2 & DESC_CS_MASK) ||
2145: !(ss_e2 & DESC_W_MASK))
2146: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2147: dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2148: if (dpl != rpl)
2149: raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2150: if (!(ss_e2 & DESC_P_MASK))
2151: raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2152: cpu_x86_load_seg_cache(env, R_SS, new_ss,
2153: get_seg_base(ss_e1, ss_e2),
2154: get_seg_limit(ss_e1, ss_e2),
2155: ss_e2);
2156: }
2157:
2158: cpu_x86_load_seg_cache(env, R_CS, new_cs,
2159: get_seg_base(e1, e2),
2160: get_seg_limit(e1, e2),
2161: e2);
2162: cpu_x86_set_cpl(env, rpl);
2163: sp = new_esp;
2164: #ifdef TARGET_X86_64
2165: if (env->hflags & HF_CS64_MASK)
2166: sp_mask = -1;
2167: else
2168: #endif
2169: sp_mask = get_sp_mask(ss_e2);
2170:
2171: /* validate data segments */
1.1.1.2 root 2172: validate_seg(R_ES, rpl);
2173: validate_seg(R_DS, rpl);
2174: validate_seg(R_FS, rpl);
2175: validate_seg(R_GS, rpl);
1.1 root 2176:
2177: sp += addend;
2178: }
2179: ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2180: env->eip = new_eip;
2181: if (is_iret) {
2182: /* NOTE: 'cpl' is the _old_ CPL */
2183: eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2184: if (cpl == 0)
2185: eflags_mask |= IOPL_MASK;
2186: iopl = (env->eflags >> IOPL_SHIFT) & 3;
2187: if (cpl <= iopl)
2188: eflags_mask |= IF_MASK;
2189: if (shift == 0)
2190: eflags_mask &= 0xffff;
2191: load_eflags(new_eflags, eflags_mask);
2192: }
2193: return;
2194:
2195: return_to_vm86:
2196: POPL(ssp, sp, sp_mask, new_esp);
2197: POPL(ssp, sp, sp_mask, new_ss);
2198: POPL(ssp, sp, sp_mask, new_es);
2199: POPL(ssp, sp, sp_mask, new_ds);
2200: POPL(ssp, sp, sp_mask, new_fs);
2201: POPL(ssp, sp, sp_mask, new_gs);
2202:
2203: /* modify processor state */
2204: load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2205: IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2206: load_seg_vm(R_CS, new_cs & 0xffff);
2207: cpu_x86_set_cpl(env, 3);
2208: load_seg_vm(R_SS, new_ss & 0xffff);
2209: load_seg_vm(R_ES, new_es & 0xffff);
2210: load_seg_vm(R_DS, new_ds & 0xffff);
2211: load_seg_vm(R_FS, new_fs & 0xffff);
2212: load_seg_vm(R_GS, new_gs & 0xffff);
2213:
2214: env->eip = new_eip & 0xffff;
2215: ESP = new_esp;
2216: }
2217:
2218: void helper_iret_protected(int shift, int next_eip)
2219: {
2220: int tss_selector, type;
2221: uint32_t e1, e2;
2222:
2223: /* specific case for TSS */
2224: if (env->eflags & NT_MASK) {
2225: #ifdef TARGET_X86_64
2226: if (env->hflags & HF_LMA_MASK)
2227: raise_exception_err(EXCP0D_GPF, 0);
2228: #endif
2229: tss_selector = lduw_kernel(env->tr.base + 0);
2230: if (tss_selector & 4)
2231: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2232: if (load_segment(&e1, &e2, tss_selector) != 0)
2233: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2234: type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2235: /* NOTE: we check both segment and busy TSS */
2236: if (type != 3)
2237: raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2238: switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2239: } else {
2240: helper_ret_protected(shift, 1, 0);
2241: }
2242: #ifdef USE_KQEMU
2243: if (kqemu_is_ok(env)) {
2244: CC_OP = CC_OP_EFLAGS;
2245: env->exception_index = -1;
2246: cpu_loop_exit();
2247: }
2248: #endif
2249: }
2250:
2251: void helper_lret_protected(int shift, int addend)
2252: {
2253: helper_ret_protected(shift, 0, addend);
2254: #ifdef USE_KQEMU
2255: if (kqemu_is_ok(env)) {
2256: env->exception_index = -1;
2257: cpu_loop_exit();
2258: }
2259: #endif
2260: }
2261:
2262: void helper_sysenter(void)
2263: {
2264: if (env->sysenter_cs == 0) {
2265: raise_exception_err(EXCP0D_GPF, 0);
2266: }
2267: env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2268: cpu_x86_set_cpl(env, 0);
2269: cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2270: 0, 0xffffffff,
2271: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2272: DESC_S_MASK |
2273: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2274: cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2275: 0, 0xffffffff,
2276: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2277: DESC_S_MASK |
2278: DESC_W_MASK | DESC_A_MASK);
2279: ESP = env->sysenter_esp;
2280: EIP = env->sysenter_eip;
2281: }
2282:
2283: void helper_sysexit(void)
2284: {
2285: int cpl;
2286:
2287: cpl = env->hflags & HF_CPL_MASK;
2288: if (env->sysenter_cs == 0 || cpl != 0) {
2289: raise_exception_err(EXCP0D_GPF, 0);
2290: }
2291: cpu_x86_set_cpl(env, 3);
2292: cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2293: 0, 0xffffffff,
2294: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2295: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2296: DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2297: cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2298: 0, 0xffffffff,
2299: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2300: DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2301: DESC_W_MASK | DESC_A_MASK);
2302: ESP = ECX;
2303: EIP = EDX;
2304: #ifdef USE_KQEMU
2305: if (kqemu_is_ok(env)) {
2306: env->exception_index = -1;
2307: cpu_loop_exit();
2308: }
2309: #endif
2310: }
2311:
2312: void helper_movl_crN_T0(int reg)
2313: {
2314: #if !defined(CONFIG_USER_ONLY)
2315: switch(reg) {
2316: case 0:
2317: cpu_x86_update_cr0(env, T0);
2318: break;
2319: case 3:
2320: cpu_x86_update_cr3(env, T0);
2321: break;
2322: case 4:
2323: cpu_x86_update_cr4(env, T0);
2324: break;
2325: case 8:
2326: cpu_set_apic_tpr(env, T0);
2327: break;
2328: default:
2329: env->cr[reg] = T0;
2330: break;
2331: }
2332: #endif
2333: }
2334:
2335: /* XXX: do more */
2336: void helper_movl_drN_T0(int reg)
2337: {
2338: env->dr[reg] = T0;
2339: }
2340:
2341: void helper_invlpg(target_ulong addr)
2342: {
2343: cpu_x86_flush_tlb(env, addr);
2344: }
2345:
2346: void helper_rdtsc(void)
2347: {
2348: uint64_t val;
2349:
2350: if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2351: raise_exception(EXCP0D_GPF);
2352: }
2353: val = cpu_get_tsc(env);
2354: EAX = (uint32_t)(val);
2355: EDX = (uint32_t)(val >> 32);
2356: }
2357:
2358: #if defined(CONFIG_USER_ONLY)
2359: void helper_wrmsr(void)
2360: {
2361: }
2362:
2363: void helper_rdmsr(void)
2364: {
2365: }
2366: #else
2367: void helper_wrmsr(void)
2368: {
2369: uint64_t val;
2370:
2371: val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2372:
2373: switch((uint32_t)ECX) {
2374: case MSR_IA32_SYSENTER_CS:
2375: env->sysenter_cs = val & 0xffff;
2376: break;
2377: case MSR_IA32_SYSENTER_ESP:
2378: env->sysenter_esp = val;
2379: break;
2380: case MSR_IA32_SYSENTER_EIP:
2381: env->sysenter_eip = val;
2382: break;
2383: case MSR_IA32_APICBASE:
2384: cpu_set_apic_base(env, val);
2385: break;
2386: case MSR_EFER:
2387: {
2388: uint64_t update_mask;
2389: update_mask = 0;
2390: if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
2391: update_mask |= MSR_EFER_SCE;
2392: if (env->cpuid_ext2_features & CPUID_EXT2_LM)
2393: update_mask |= MSR_EFER_LME;
2394: if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
2395: update_mask |= MSR_EFER_FFXSR;
2396: if (env->cpuid_ext2_features & CPUID_EXT2_NX)
2397: update_mask |= MSR_EFER_NXE;
2398: env->efer = (env->efer & ~update_mask) |
2399: (val & update_mask);
2400: }
2401: break;
2402: case MSR_STAR:
2403: env->star = val;
2404: break;
2405: case MSR_PAT:
2406: env->pat = val;
2407: break;
2408: #ifdef TARGET_X86_64
2409: case MSR_LSTAR:
2410: env->lstar = val;
2411: break;
2412: case MSR_CSTAR:
2413: env->cstar = val;
2414: break;
2415: case MSR_FMASK:
2416: env->fmask = val;
2417: break;
2418: case MSR_FSBASE:
2419: env->segs[R_FS].base = val;
2420: break;
2421: case MSR_GSBASE:
2422: env->segs[R_GS].base = val;
2423: break;
2424: case MSR_KERNELGSBASE:
2425: env->kernelgsbase = val;
2426: break;
2427: #endif
2428: default:
2429: /* XXX: exception ? */
2430: break;
2431: }
2432: }
2433:
2434: void helper_rdmsr(void)
2435: {
2436: uint64_t val;
2437: switch((uint32_t)ECX) {
2438: case MSR_IA32_SYSENTER_CS:
2439: val = env->sysenter_cs;
2440: break;
2441: case MSR_IA32_SYSENTER_ESP:
2442: val = env->sysenter_esp;
2443: break;
2444: case MSR_IA32_SYSENTER_EIP:
2445: val = env->sysenter_eip;
2446: break;
2447: case MSR_IA32_APICBASE:
2448: val = cpu_get_apic_base(env);
2449: break;
2450: case MSR_EFER:
2451: val = env->efer;
2452: break;
2453: case MSR_STAR:
2454: val = env->star;
2455: break;
2456: case MSR_PAT:
2457: val = env->pat;
2458: break;
2459: #ifdef TARGET_X86_64
2460: case MSR_LSTAR:
2461: val = env->lstar;
2462: break;
2463: case MSR_CSTAR:
2464: val = env->cstar;
2465: break;
2466: case MSR_FMASK:
2467: val = env->fmask;
2468: break;
2469: case MSR_FSBASE:
2470: val = env->segs[R_FS].base;
2471: break;
2472: case MSR_GSBASE:
2473: val = env->segs[R_GS].base;
2474: break;
2475: case MSR_KERNELGSBASE:
2476: val = env->kernelgsbase;
2477: break;
2478: #endif
2479: default:
2480: /* XXX: exception ? */
2481: val = 0;
2482: break;
2483: }
2484: EAX = (uint32_t)(val);
2485: EDX = (uint32_t)(val >> 32);
2486: }
2487: #endif
2488:
2489: void helper_lsl(void)
2490: {
2491: unsigned int selector, limit;
2492: uint32_t e1, e2, eflags;
2493: int rpl, dpl, cpl, type;
2494:
2495: eflags = cc_table[CC_OP].compute_all();
2496: selector = T0 & 0xffff;
2497: if (load_segment(&e1, &e2, selector) != 0)
2498: goto fail;
2499: rpl = selector & 3;
2500: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2501: cpl = env->hflags & HF_CPL_MASK;
2502: if (e2 & DESC_S_MASK) {
2503: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2504: /* conforming */
2505: } else {
2506: if (dpl < cpl || dpl < rpl)
2507: goto fail;
2508: }
2509: } else {
2510: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2511: switch(type) {
2512: case 1:
2513: case 2:
2514: case 3:
2515: case 9:
2516: case 11:
2517: break;
2518: default:
2519: goto fail;
2520: }
2521: if (dpl < cpl || dpl < rpl) {
2522: fail:
2523: CC_SRC = eflags & ~CC_Z;
2524: return;
2525: }
2526: }
2527: limit = get_seg_limit(e1, e2);
2528: T1 = limit;
2529: CC_SRC = eflags | CC_Z;
2530: }
2531:
2532: void helper_lar(void)
2533: {
2534: unsigned int selector;
2535: uint32_t e1, e2, eflags;
2536: int rpl, dpl, cpl, type;
2537:
2538: eflags = cc_table[CC_OP].compute_all();
2539: selector = T0 & 0xffff;
2540: if ((selector & 0xfffc) == 0)
2541: goto fail;
2542: if (load_segment(&e1, &e2, selector) != 0)
2543: goto fail;
2544: rpl = selector & 3;
2545: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2546: cpl = env->hflags & HF_CPL_MASK;
2547: if (e2 & DESC_S_MASK) {
2548: if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2549: /* conforming */
2550: } else {
2551: if (dpl < cpl || dpl < rpl)
2552: goto fail;
2553: }
2554: } else {
2555: type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2556: switch(type) {
2557: case 1:
2558: case 2:
2559: case 3:
2560: case 4:
2561: case 5:
2562: case 9:
2563: case 11:
2564: case 12:
2565: break;
2566: default:
2567: goto fail;
2568: }
2569: if (dpl < cpl || dpl < rpl) {
2570: fail:
2571: CC_SRC = eflags & ~CC_Z;
2572: return;
2573: }
2574: }
2575: T1 = e2 & 0x00f0ff00;
2576: CC_SRC = eflags | CC_Z;
2577: }
2578:
2579: void helper_verr(void)
2580: {
2581: unsigned int selector;
2582: uint32_t e1, e2, eflags;
2583: int rpl, dpl, cpl;
2584:
2585: eflags = cc_table[CC_OP].compute_all();
2586: selector = T0 & 0xffff;
2587: if ((selector & 0xfffc) == 0)
2588: goto fail;
2589: if (load_segment(&e1, &e2, selector) != 0)
2590: goto fail;
2591: if (!(e2 & DESC_S_MASK))
2592: goto fail;
2593: rpl = selector & 3;
2594: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2595: cpl = env->hflags & HF_CPL_MASK;
2596: if (e2 & DESC_CS_MASK) {
2597: if (!(e2 & DESC_R_MASK))
2598: goto fail;
2599: if (!(e2 & DESC_C_MASK)) {
2600: if (dpl < cpl || dpl < rpl)
2601: goto fail;
2602: }
2603: } else {
2604: if (dpl < cpl || dpl < rpl) {
2605: fail:
2606: CC_SRC = eflags & ~CC_Z;
2607: return;
2608: }
2609: }
2610: CC_SRC = eflags | CC_Z;
2611: }
2612:
2613: void helper_verw(void)
2614: {
2615: unsigned int selector;
2616: uint32_t e1, e2, eflags;
2617: int rpl, dpl, cpl;
2618:
2619: eflags = cc_table[CC_OP].compute_all();
2620: selector = T0 & 0xffff;
2621: if ((selector & 0xfffc) == 0)
2622: goto fail;
2623: if (load_segment(&e1, &e2, selector) != 0)
2624: goto fail;
2625: if (!(e2 & DESC_S_MASK))
2626: goto fail;
2627: rpl = selector & 3;
2628: dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2629: cpl = env->hflags & HF_CPL_MASK;
2630: if (e2 & DESC_CS_MASK) {
2631: goto fail;
2632: } else {
2633: if (dpl < cpl || dpl < rpl)
2634: goto fail;
2635: if (!(e2 & DESC_W_MASK)) {
2636: fail:
2637: CC_SRC = eflags & ~CC_Z;
2638: return;
2639: }
2640: }
2641: CC_SRC = eflags | CC_Z;
2642: }
2643:
2644: /* FPU helpers */
2645:
2646: void helper_fldt_ST0_A0(void)
2647: {
2648: int new_fpstt;
2649: new_fpstt = (env->fpstt - 1) & 7;
2650: env->fpregs[new_fpstt].d = helper_fldt(A0);
2651: env->fpstt = new_fpstt;
2652: env->fptags[new_fpstt] = 0; /* validate stack entry */
2653: }
2654:
2655: void helper_fstt_ST0_A0(void)
2656: {
2657: helper_fstt(ST0, A0);
2658: }
2659:
2660: void fpu_set_exception(int mask)
2661: {
2662: env->fpus |= mask;
2663: if (env->fpus & (~env->fpuc & FPUC_EM))
2664: env->fpus |= FPUS_SE | FPUS_B;
2665: }
2666:
2667: CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
2668: {
2669: if (b == 0.0)
2670: fpu_set_exception(FPUS_ZE);
2671: return a / b;
2672: }
2673:
2674: void fpu_raise_exception(void)
2675: {
2676: if (env->cr[0] & CR0_NE_MASK) {
2677: raise_exception(EXCP10_COPR);
2678: }
2679: #if !defined(CONFIG_USER_ONLY)
2680: else {
2681: cpu_set_ferr(env);
2682: }
2683: #endif
2684: }
2685:
2686: /* BCD ops */
2687:
2688: void helper_fbld_ST0_A0(void)
2689: {
2690: CPU86_LDouble tmp;
2691: uint64_t val;
2692: unsigned int v;
2693: int i;
2694:
2695: val = 0;
2696: for(i = 8; i >= 0; i--) {
2697: v = ldub(A0 + i);
2698: val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2699: }
2700: tmp = val;
2701: if (ldub(A0 + 9) & 0x80)
2702: tmp = -tmp;
2703: fpush();
2704: ST0 = tmp;
2705: }
2706:
2707: void helper_fbst_ST0_A0(void)
2708: {
2709: int v;
2710: target_ulong mem_ref, mem_end;
2711: int64_t val;
2712:
2713: val = floatx_to_int64(ST0, &env->fp_status);
2714: mem_ref = A0;
2715: mem_end = mem_ref + 9;
2716: if (val < 0) {
2717: stb(mem_end, 0x80);
2718: val = -val;
2719: } else {
2720: stb(mem_end, 0x00);
2721: }
2722: while (mem_ref < mem_end) {
2723: if (val == 0)
2724: break;
2725: v = val % 100;
2726: val = val / 100;
2727: v = ((v / 10) << 4) | (v % 10);
2728: stb(mem_ref++, v);
2729: }
2730: while (mem_ref < mem_end) {
2731: stb(mem_ref++, 0);
2732: }
2733: }
2734:
2735: void helper_f2xm1(void)
2736: {
2737: ST0 = pow(2.0,ST0) - 1.0;
2738: }
2739:
2740: void helper_fyl2x(void)
2741: {
2742: CPU86_LDouble fptemp;
2743:
2744: fptemp = ST0;
2745: if (fptemp>0.0){
2746: fptemp = log(fptemp)/log(2.0); /* log2(ST) */
2747: ST1 *= fptemp;
2748: fpop();
2749: } else {
2750: env->fpus &= (~0x4700);
2751: env->fpus |= 0x400;
2752: }
2753: }
2754:
2755: void helper_fptan(void)
2756: {
2757: CPU86_LDouble fptemp;
2758:
2759: fptemp = ST0;
2760: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2761: env->fpus |= 0x400;
2762: } else {
2763: ST0 = tan(fptemp);
2764: fpush();
2765: ST0 = 1.0;
2766: env->fpus &= (~0x400); /* C2 <-- 0 */
2767: /* the above code is for |arg| < 2**52 only */
2768: }
2769: }
2770:
2771: void helper_fpatan(void)
2772: {
2773: CPU86_LDouble fptemp, fpsrcop;
2774:
2775: fpsrcop = ST1;
2776: fptemp = ST0;
2777: ST1 = atan2(fpsrcop,fptemp);
2778: fpop();
2779: }
2780:
2781: void helper_fxtract(void)
2782: {
2783: CPU86_LDoubleU temp;
2784: unsigned int expdif;
2785:
2786: temp.d = ST0;
2787: expdif = EXPD(temp) - EXPBIAS;
2788: /*DP exponent bias*/
2789: ST0 = expdif;
2790: fpush();
2791: BIASEXPONENT(temp);
2792: ST0 = temp.d;
2793: }
2794:
2795: void helper_fprem1(void)
2796: {
2797: CPU86_LDouble dblq, fpsrcop, fptemp;
2798: CPU86_LDoubleU fpsrcop1, fptemp1;
2799: int expdif;
2800: int q;
2801:
2802: fpsrcop = ST0;
2803: fptemp = ST1;
2804: fpsrcop1.d = fpsrcop;
2805: fptemp1.d = fptemp;
2806: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2807: if (expdif < 53) {
2808: dblq = fpsrcop / fptemp;
2809: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2810: ST0 = fpsrcop - fptemp*dblq;
2811: q = (int)dblq; /* cutting off top bits is assumed here */
2812: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2813: /* (C0,C1,C3) <-- (q2,q1,q0) */
2814: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2815: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2816: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2817: } else {
2818: env->fpus |= 0x400; /* C2 <-- 1 */
2819: fptemp = pow(2.0, expdif-50);
2820: fpsrcop = (ST0 / ST1) / fptemp;
2821: /* fpsrcop = integer obtained by rounding to the nearest */
2822: fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2823: floor(fpsrcop): ceil(fpsrcop);
2824: ST0 -= (ST1 * fpsrcop * fptemp);
2825: }
2826: }
2827:
2828: void helper_fprem(void)
2829: {
2830: CPU86_LDouble dblq, fpsrcop, fptemp;
2831: CPU86_LDoubleU fpsrcop1, fptemp1;
2832: int expdif;
2833: int q;
2834:
2835: fpsrcop = ST0;
2836: fptemp = ST1;
2837: fpsrcop1.d = fpsrcop;
2838: fptemp1.d = fptemp;
2839: expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2840: if ( expdif < 53 ) {
2841: dblq = fpsrcop / fptemp;
2842: dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2843: ST0 = fpsrcop - fptemp*dblq;
2844: q = (int)dblq; /* cutting off top bits is assumed here */
2845: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2846: /* (C0,C1,C3) <-- (q2,q1,q0) */
2847: env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2848: env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2849: env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2850: } else {
2851: env->fpus |= 0x400; /* C2 <-- 1 */
2852: fptemp = pow(2.0, expdif-50);
2853: fpsrcop = (ST0 / ST1) / fptemp;
2854: /* fpsrcop = integer obtained by chopping */
2855: fpsrcop = (fpsrcop < 0.0)?
2856: -(floor(fabs(fpsrcop))): floor(fpsrcop);
2857: ST0 -= (ST1 * fpsrcop * fptemp);
2858: }
2859: }
2860:
2861: void helper_fyl2xp1(void)
2862: {
2863: CPU86_LDouble fptemp;
2864:
2865: fptemp = ST0;
2866: if ((fptemp+1.0)>0.0) {
2867: fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2868: ST1 *= fptemp;
2869: fpop();
2870: } else {
2871: env->fpus &= (~0x4700);
2872: env->fpus |= 0x400;
2873: }
2874: }
2875:
2876: void helper_fsqrt(void)
2877: {
2878: CPU86_LDouble fptemp;
2879:
2880: fptemp = ST0;
2881: if (fptemp<0.0) {
2882: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2883: env->fpus |= 0x400;
2884: }
2885: ST0 = sqrt(fptemp);
2886: }
2887:
2888: void helper_fsincos(void)
2889: {
2890: CPU86_LDouble fptemp;
2891:
2892: fptemp = ST0;
2893: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2894: env->fpus |= 0x400;
2895: } else {
2896: ST0 = sin(fptemp);
2897: fpush();
2898: ST0 = cos(fptemp);
2899: env->fpus &= (~0x400); /* C2 <-- 0 */
2900: /* the above code is for |arg| < 2**63 only */
2901: }
2902: }
2903:
2904: void helper_frndint(void)
2905: {
2906: ST0 = floatx_round_to_int(ST0, &env->fp_status);
2907: }
2908:
2909: void helper_fscale(void)
2910: {
2911: ST0 = ldexp (ST0, (int)(ST1));
2912: }
2913:
2914: void helper_fsin(void)
2915: {
2916: CPU86_LDouble fptemp;
2917:
2918: fptemp = ST0;
2919: if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2920: env->fpus |= 0x400;
2921: } else {
2922: ST0 = sin(fptemp);
2923: env->fpus &= (~0x400); /* C2 <-- 0 */
2924: /* the above code is for |arg| < 2**53 only */
2925: }
2926: }
2927:
2928: void helper_fcos(void)
2929: {
2930: CPU86_LDouble fptemp;
2931:
2932: fptemp = ST0;
2933: if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2934: env->fpus |= 0x400;
2935: } else {
2936: ST0 = cos(fptemp);
2937: env->fpus &= (~0x400); /* C2 <-- 0 */
2938: /* the above code is for |arg5 < 2**63 only */
2939: }
2940: }
2941:
2942: void helper_fxam_ST0(void)
2943: {
2944: CPU86_LDoubleU temp;
2945: int expdif;
2946:
2947: temp.d = ST0;
2948:
2949: env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2950: if (SIGND(temp))
2951: env->fpus |= 0x200; /* C1 <-- 1 */
2952:
1.1.1.4 ! root 2953: /* XXX: test fptags too */
1.1 root 2954: expdif = EXPD(temp);
2955: if (expdif == MAXEXPD) {
1.1.1.4 ! root 2956: #ifdef USE_X86LDOUBLE
! 2957: if (MANTD(temp) == 0x8000000000000000ULL)
! 2958: #else
1.1 root 2959: if (MANTD(temp) == 0)
1.1.1.4 ! root 2960: #endif
1.1 root 2961: env->fpus |= 0x500 /*Infinity*/;
2962: else
2963: env->fpus |= 0x100 /*NaN*/;
2964: } else if (expdif == 0) {
2965: if (MANTD(temp) == 0)
2966: env->fpus |= 0x4000 /*Zero*/;
2967: else
2968: env->fpus |= 0x4400 /*Denormal*/;
2969: } else {
2970: env->fpus |= 0x400;
2971: }
2972: }
2973:
2974: void helper_fstenv(target_ulong ptr, int data32)
2975: {
2976: int fpus, fptag, exp, i;
2977: uint64_t mant;
2978: CPU86_LDoubleU tmp;
2979:
2980: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2981: fptag = 0;
2982: for (i=7; i>=0; i--) {
2983: fptag <<= 2;
2984: if (env->fptags[i]) {
2985: fptag |= 3;
2986: } else {
2987: tmp.d = env->fpregs[i].d;
2988: exp = EXPD(tmp);
2989: mant = MANTD(tmp);
2990: if (exp == 0 && mant == 0) {
2991: /* zero */
2992: fptag |= 1;
2993: } else if (exp == 0 || exp == MAXEXPD
2994: #ifdef USE_X86LDOUBLE
2995: || (mant & (1LL << 63)) == 0
2996: #endif
2997: ) {
2998: /* NaNs, infinity, denormal */
2999: fptag |= 2;
3000: }
3001: }
3002: }
3003: if (data32) {
3004: /* 32 bit */
3005: stl(ptr, env->fpuc);
3006: stl(ptr + 4, fpus);
3007: stl(ptr + 8, fptag);
3008: stl(ptr + 12, 0); /* fpip */
3009: stl(ptr + 16, 0); /* fpcs */
3010: stl(ptr + 20, 0); /* fpoo */
3011: stl(ptr + 24, 0); /* fpos */
3012: } else {
3013: /* 16 bit */
3014: stw(ptr, env->fpuc);
3015: stw(ptr + 2, fpus);
3016: stw(ptr + 4, fptag);
3017: stw(ptr + 6, 0);
3018: stw(ptr + 8, 0);
3019: stw(ptr + 10, 0);
3020: stw(ptr + 12, 0);
3021: }
3022: }
3023:
3024: void helper_fldenv(target_ulong ptr, int data32)
3025: {
3026: int i, fpus, fptag;
3027:
3028: if (data32) {
3029: env->fpuc = lduw(ptr);
3030: fpus = lduw(ptr + 4);
3031: fptag = lduw(ptr + 8);
3032: }
3033: else {
3034: env->fpuc = lduw(ptr);
3035: fpus = lduw(ptr + 2);
3036: fptag = lduw(ptr + 4);
3037: }
3038: env->fpstt = (fpus >> 11) & 7;
3039: env->fpus = fpus & ~0x3800;
3040: for(i = 0;i < 8; i++) {
3041: env->fptags[i] = ((fptag & 3) == 3);
3042: fptag >>= 2;
3043: }
3044: }
3045:
3046: void helper_fsave(target_ulong ptr, int data32)
3047: {
3048: CPU86_LDouble tmp;
3049: int i;
3050:
3051: helper_fstenv(ptr, data32);
3052:
3053: ptr += (14 << data32);
3054: for(i = 0;i < 8; i++) {
3055: tmp = ST(i);
3056: helper_fstt(tmp, ptr);
3057: ptr += 10;
3058: }
3059:
3060: /* fninit */
3061: env->fpus = 0;
3062: env->fpstt = 0;
3063: env->fpuc = 0x37f;
3064: env->fptags[0] = 1;
3065: env->fptags[1] = 1;
3066: env->fptags[2] = 1;
3067: env->fptags[3] = 1;
3068: env->fptags[4] = 1;
3069: env->fptags[5] = 1;
3070: env->fptags[6] = 1;
3071: env->fptags[7] = 1;
3072: }
3073:
3074: void helper_frstor(target_ulong ptr, int data32)
3075: {
3076: CPU86_LDouble tmp;
3077: int i;
3078:
3079: helper_fldenv(ptr, data32);
3080: ptr += (14 << data32);
3081:
3082: for(i = 0;i < 8; i++) {
3083: tmp = helper_fldt(ptr);
3084: ST(i) = tmp;
3085: ptr += 10;
3086: }
3087: }
3088:
3089: void helper_fxsave(target_ulong ptr, int data64)
3090: {
3091: int fpus, fptag, i, nb_xmm_regs;
3092: CPU86_LDouble tmp;
3093: target_ulong addr;
3094:
3095: fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3096: fptag = 0;
3097: for(i = 0; i < 8; i++) {
3098: fptag |= (env->fptags[i] << i);
3099: }
3100: stw(ptr, env->fpuc);
3101: stw(ptr + 2, fpus);
3102: stw(ptr + 4, fptag ^ 0xff);
3103:
3104: addr = ptr + 0x20;
3105: for(i = 0;i < 8; i++) {
3106: tmp = ST(i);
3107: helper_fstt(tmp, addr);
3108: addr += 16;
3109: }
3110:
3111: if (env->cr[4] & CR4_OSFXSR_MASK) {
3112: /* XXX: finish it */
3113: stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3114: stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3115: nb_xmm_regs = 8 << data64;
3116: addr = ptr + 0xa0;
3117: for(i = 0; i < nb_xmm_regs; i++) {
3118: stq(addr, env->xmm_regs[i].XMM_Q(0));
3119: stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3120: addr += 16;
3121: }
3122: }
3123: }
3124:
3125: void helper_fxrstor(target_ulong ptr, int data64)
3126: {
3127: int i, fpus, fptag, nb_xmm_regs;
3128: CPU86_LDouble tmp;
3129: target_ulong addr;
3130:
3131: env->fpuc = lduw(ptr);
3132: fpus = lduw(ptr + 2);
3133: fptag = lduw(ptr + 4);
3134: env->fpstt = (fpus >> 11) & 7;
3135: env->fpus = fpus & ~0x3800;
3136: fptag ^= 0xff;
3137: for(i = 0;i < 8; i++) {
3138: env->fptags[i] = ((fptag >> i) & 1);
3139: }
3140:
3141: addr = ptr + 0x20;
3142: for(i = 0;i < 8; i++) {
3143: tmp = helper_fldt(addr);
3144: ST(i) = tmp;
3145: addr += 16;
3146: }
3147:
3148: if (env->cr[4] & CR4_OSFXSR_MASK) {
3149: /* XXX: finish it */
3150: env->mxcsr = ldl(ptr + 0x18);
3151: //ldl(ptr + 0x1c);
3152: nb_xmm_regs = 8 << data64;
3153: addr = ptr + 0xa0;
3154: for(i = 0; i < nb_xmm_regs; i++) {
3155: env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3156: env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3157: addr += 16;
3158: }
3159: }
3160: }
3161:
3162: #ifndef USE_X86LDOUBLE
3163:
3164: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3165: {
3166: CPU86_LDoubleU temp;
3167: int e;
3168:
3169: temp.d = f;
3170: /* mantissa */
3171: *pmant = (MANTD(temp) << 11) | (1LL << 63);
3172: /* exponent + sign */
3173: e = EXPD(temp) - EXPBIAS + 16383;
3174: e |= SIGND(temp) >> 16;
3175: *pexp = e;
3176: }
3177:
3178: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3179: {
3180: CPU86_LDoubleU temp;
3181: int e;
3182: uint64_t ll;
3183:
3184: /* XXX: handle overflow ? */
3185: e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3186: e |= (upper >> 4) & 0x800; /* sign */
3187: ll = (mant >> 11) & ((1LL << 52) - 1);
3188: #ifdef __arm__
3189: temp.l.upper = (e << 20) | (ll >> 32);
3190: temp.l.lower = ll;
3191: #else
3192: temp.ll = ll | ((uint64_t)e << 52);
3193: #endif
3194: return temp.d;
3195: }
3196:
3197: #else
3198:
3199: void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3200: {
3201: CPU86_LDoubleU temp;
3202:
3203: temp.d = f;
3204: *pmant = temp.l.lower;
3205: *pexp = temp.l.upper;
3206: }
3207:
3208: CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3209: {
3210: CPU86_LDoubleU temp;
3211:
3212: temp.l.upper = upper;
3213: temp.l.lower = mant;
3214: return temp.d;
3215: }
3216: #endif
3217:
3218: #ifdef TARGET_X86_64
3219:
3220: //#define DEBUG_MULDIV
3221:
3222: static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3223: {
3224: *plow += a;
3225: /* carry test */
3226: if (*plow < a)
3227: (*phigh)++;
3228: *phigh += b;
3229: }
3230:
3231: static void neg128(uint64_t *plow, uint64_t *phigh)
3232: {
3233: *plow = ~ *plow;
3234: *phigh = ~ *phigh;
3235: add128(plow, phigh, 1, 0);
3236: }
3237:
3238: static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3239: {
3240: uint32_t a0, a1, b0, b1;
3241: uint64_t v;
3242:
3243: a0 = a;
3244: a1 = a >> 32;
3245:
3246: b0 = b;
3247: b1 = b >> 32;
3248:
3249: v = (uint64_t)a0 * (uint64_t)b0;
3250: *plow = v;
3251: *phigh = 0;
3252:
3253: v = (uint64_t)a0 * (uint64_t)b1;
3254: add128(plow, phigh, v << 32, v >> 32);
3255:
3256: v = (uint64_t)a1 * (uint64_t)b0;
3257: add128(plow, phigh, v << 32, v >> 32);
3258:
3259: v = (uint64_t)a1 * (uint64_t)b1;
3260: *phigh += v;
3261: #ifdef DEBUG_MULDIV
1.1.1.4 ! root 3262: printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
1.1 root 3263: a, b, *phigh, *plow);
3264: #endif
3265: }
3266:
3267: static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
3268: {
3269: int sa, sb;
3270: sa = (a < 0);
3271: if (sa)
3272: a = -a;
3273: sb = (b < 0);
3274: if (sb)
3275: b = -b;
3276: mul64(plow, phigh, a, b);
3277: if (sa ^ sb) {
3278: neg128(plow, phigh);
3279: }
3280: }
3281:
3282: /* return TRUE if overflow */
3283: static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3284: {
3285: uint64_t q, r, a1, a0;
1.1.1.2 root 3286: int i, qb, ab;
1.1 root 3287:
3288: a0 = *plow;
3289: a1 = *phigh;
3290: if (a1 == 0) {
3291: q = a0 / b;
3292: r = a0 % b;
3293: *plow = q;
3294: *phigh = r;
3295: } else {
3296: if (a1 >= b)
3297: return 1;
3298: /* XXX: use a better algorithm */
3299: for(i = 0; i < 64; i++) {
1.1.1.2 root 3300: ab = a1 >> 63;
1.1 root 3301: a1 = (a1 << 1) | (a0 >> 63);
1.1.1.2 root 3302: if (ab || a1 >= b) {
1.1 root 3303: a1 -= b;
3304: qb = 1;
3305: } else {
3306: qb = 0;
3307: }
3308: a0 = (a0 << 1) | qb;
3309: }
3310: #if defined(DEBUG_MULDIV)
1.1.1.4 ! root 3311: printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
1.1 root 3312: *phigh, *plow, b, a0, a1);
3313: #endif
3314: *plow = a0;
3315: *phigh = a1;
3316: }
3317: return 0;
3318: }
3319:
3320: /* return TRUE if overflow */
3321: static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3322: {
3323: int sa, sb;
3324: sa = ((int64_t)*phigh < 0);
3325: if (sa)
3326: neg128(plow, phigh);
3327: sb = (b < 0);
3328: if (sb)
3329: b = -b;
3330: if (div64(plow, phigh, b) != 0)
3331: return 1;
3332: if (sa ^ sb) {
3333: if (*plow > (1ULL << 63))
3334: return 1;
3335: *plow = - *plow;
3336: } else {
3337: if (*plow >= (1ULL << 63))
3338: return 1;
3339: }
3340: if (sa)
3341: *phigh = - *phigh;
3342: return 0;
3343: }
3344:
3345: void helper_mulq_EAX_T0(void)
3346: {
3347: uint64_t r0, r1;
3348:
3349: mul64(&r0, &r1, EAX, T0);
3350: EAX = r0;
3351: EDX = r1;
3352: CC_DST = r0;
3353: CC_SRC = r1;
3354: }
3355:
3356: void helper_imulq_EAX_T0(void)
3357: {
3358: uint64_t r0, r1;
3359:
3360: imul64(&r0, &r1, EAX, T0);
3361: EAX = r0;
3362: EDX = r1;
3363: CC_DST = r0;
3364: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3365: }
3366:
3367: void helper_imulq_T0_T1(void)
3368: {
3369: uint64_t r0, r1;
3370:
3371: imul64(&r0, &r1, T0, T1);
3372: T0 = r0;
3373: CC_DST = r0;
3374: CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3375: }
3376:
3377: void helper_divq_EAX_T0(void)
3378: {
3379: uint64_t r0, r1;
3380: if (T0 == 0) {
3381: raise_exception(EXCP00_DIVZ);
3382: }
3383: r0 = EAX;
3384: r1 = EDX;
3385: if (div64(&r0, &r1, T0))
3386: raise_exception(EXCP00_DIVZ);
3387: EAX = r0;
3388: EDX = r1;
3389: }
3390:
3391: void helper_idivq_EAX_T0(void)
3392: {
3393: uint64_t r0, r1;
3394: if (T0 == 0) {
3395: raise_exception(EXCP00_DIVZ);
3396: }
3397: r0 = EAX;
3398: r1 = EDX;
3399: if (idiv64(&r0, &r1, T0))
3400: raise_exception(EXCP00_DIVZ);
3401: EAX = r0;
3402: EDX = r1;
3403: }
3404:
1.1.1.3 root 3405: void helper_bswapq_T0(void)
3406: {
3407: T0 = bswap64(T0);
3408: }
1.1 root 3409: #endif
3410:
1.1.1.4 ! root 3411: void helper_hlt(void)
! 3412: {
! 3413: env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
! 3414: env->hflags |= HF_HALTED_MASK;
! 3415: env->exception_index = EXCP_HLT;
! 3416: cpu_loop_exit();
! 3417: }
! 3418:
! 3419: void helper_monitor(void)
! 3420: {
! 3421: if (ECX != 0)
! 3422: raise_exception(EXCP0D_GPF);
! 3423: /* XXX: store address ? */
! 3424: }
! 3425:
! 3426: void helper_mwait(void)
! 3427: {
! 3428: if (ECX != 0)
! 3429: raise_exception(EXCP0D_GPF);
! 3430: /* XXX: not complete but not completely erroneous */
! 3431: if (env->cpu_index != 0 || env->next_cpu != NULL) {
! 3432: /* more than one CPU: do not sleep because another CPU may
! 3433: wake this one */
! 3434: } else {
! 3435: helper_hlt();
! 3436: }
! 3437: }
! 3438:
1.1 root 3439: float approx_rsqrt(float a)
3440: {
3441: return 1.0 / sqrt(a);
3442: }
3443:
3444: float approx_rcp(float a)
3445: {
3446: return 1.0 / a;
3447: }
3448:
3449: void update_fp_status(void)
3450: {
3451: int rnd_type;
3452:
3453: /* set rounding mode */
3454: switch(env->fpuc & RC_MASK) {
3455: default:
3456: case RC_NEAR:
3457: rnd_type = float_round_nearest_even;
3458: break;
3459: case RC_DOWN:
3460: rnd_type = float_round_down;
3461: break;
3462: case RC_UP:
3463: rnd_type = float_round_up;
3464: break;
3465: case RC_CHOP:
3466: rnd_type = float_round_to_zero;
3467: break;
3468: }
3469: set_float_rounding_mode(rnd_type, &env->fp_status);
3470: #ifdef FLOATX80
3471: switch((env->fpuc >> 8) & 3) {
3472: case 0:
3473: rnd_type = 32;
3474: break;
3475: case 2:
3476: rnd_type = 64;
3477: break;
3478: case 3:
3479: default:
3480: rnd_type = 80;
3481: break;
3482: }
3483: set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3484: #endif
3485: }
3486:
3487: #if !defined(CONFIG_USER_ONLY)
3488:
3489: #define MMUSUFFIX _mmu
3490: #define GETPC() (__builtin_return_address(0))
3491:
3492: #define SHIFT 0
3493: #include "softmmu_template.h"
3494:
3495: #define SHIFT 1
3496: #include "softmmu_template.h"
3497:
3498: #define SHIFT 2
3499: #include "softmmu_template.h"
3500:
3501: #define SHIFT 3
3502: #include "softmmu_template.h"
3503:
3504: #endif
3505:
3506: /* try to fill the TLB and return an exception if error. If retaddr is
3507: NULL, it means that the function was called in C code (i.e. not
3508: from generated code or from helper.c) */
3509: /* XXX: fix it to restore all registers */
3510: void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
3511: {
3512: TranslationBlock *tb;
3513: int ret;
3514: unsigned long pc;
3515: CPUX86State *saved_env;
3516:
3517: /* XXX: hack to restore env in all cases, even if not called from
3518: generated code */
3519: saved_env = env;
3520: env = cpu_single_env;
3521:
3522: ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
3523: if (ret) {
3524: if (retaddr) {
3525: /* now we have a real cpu fault */
3526: pc = (unsigned long)retaddr;
3527: tb = tb_find_pc(pc);
3528: if (tb) {
3529: /* the PC is inside the translated code. It means that we have
3530: a virtual CPU fault */
3531: cpu_restore_state(tb, env, pc, NULL);
3532: }
3533: }
3534: if (retaddr)
1.1.1.2 root 3535: raise_exception_err(env->exception_index, env->error_code);
1.1 root 3536: else
1.1.1.2 root 3537: raise_exception_err_norestore(env->exception_index, env->error_code);
1.1 root 3538: }
3539: env = saved_env;
3540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.