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