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