Preliminary AIX support
[qemu/mini2440.git] / target-i386 / op_helper.c
blob90f685d54cc60431f4d0b349fbdf5f34561438ba
1 /*
2 * i386 helpers
4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #define CPU_NO_GLOBAL_REGS
21 #include "exec.h"
22 #include "host-utils.h"
24 //#define DEBUG_PCALL
26 #if 0
27 #define raise_exception_err(a, b)\
28 do {\
29 if (logfile)\
30 fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
31 (raise_exception_err)(a, b);\
32 } while (0)
33 #endif
35 const uint8_t parity_table[256] = {
36 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
37 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
38 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
40 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
41 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
42 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
43 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
44 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
46 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
49 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
52 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
53 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
57 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
58 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 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
61 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
62 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
64 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
65 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
66 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
67 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
70 /* modulo 17 table */
71 const uint8_t rclw_table[32] = {
72 0, 1, 2, 3, 4, 5, 6, 7,
73 8, 9,10,11,12,13,14,15,
74 16, 0, 1, 2, 3, 4, 5, 6,
75 7, 8, 9,10,11,12,13,14,
78 /* modulo 9 table */
79 const uint8_t rclb_table[32] = {
80 0, 1, 2, 3, 4, 5, 6, 7,
81 8, 0, 1, 2, 3, 4, 5, 6,
82 7, 8, 0, 1, 2, 3, 4, 5,
83 6, 7, 8, 0, 1, 2, 3, 4,
86 const CPU86_LDouble f15rk[7] =
88 0.00000000000000000000L,
89 1.00000000000000000000L,
90 3.14159265358979323851L, /*pi*/
91 0.30102999566398119523L, /*lg2*/
92 0.69314718055994530943L, /*ln2*/
93 1.44269504088896340739L, /*l2e*/
94 3.32192809488736234781L, /*l2t*/
97 /* broken thread support */
99 static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
101 void helper_lock(void)
103 spin_lock(&global_cpu_lock);
106 void helper_unlock(void)
108 spin_unlock(&global_cpu_lock);
111 void helper_write_eflags(target_ulong t0, uint32_t update_mask)
113 load_eflags(t0, update_mask);
116 target_ulong helper_read_eflags(void)
118 uint32_t eflags;
119 eflags = helper_cc_compute_all(CC_OP);
120 eflags |= (DF & DF_MASK);
121 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
122 return eflags;
125 /* return non zero if error */
126 static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
127 int selector)
129 SegmentCache *dt;
130 int index;
131 target_ulong ptr;
133 if (selector & 0x4)
134 dt = &env->ldt;
135 else
136 dt = &env->gdt;
137 index = selector & ~7;
138 if ((index + 7) > dt->limit)
139 return -1;
140 ptr = dt->base + index;
141 *e1_ptr = ldl_kernel(ptr);
142 *e2_ptr = ldl_kernel(ptr + 4);
143 return 0;
146 static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
148 unsigned int limit;
149 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
150 if (e2 & DESC_G_MASK)
151 limit = (limit << 12) | 0xfff;
152 return limit;
155 static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
157 return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
160 static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
162 sc->base = get_seg_base(e1, e2);
163 sc->limit = get_seg_limit(e1, e2);
164 sc->flags = e2;
167 /* init the segment cache in vm86 mode. */
168 static inline void load_seg_vm(int seg, int selector)
170 selector &= 0xffff;
171 cpu_x86_load_seg_cache(env, seg, selector,
172 (selector << 4), 0xffff, 0);
175 static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
176 uint32_t *esp_ptr, int dpl)
178 int type, index, shift;
180 #if 0
182 int i;
183 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
184 for(i=0;i<env->tr.limit;i++) {
185 printf("%02x ", env->tr.base[i]);
186 if ((i & 7) == 7) printf("\n");
188 printf("\n");
190 #endif
192 if (!(env->tr.flags & DESC_P_MASK))
193 cpu_abort(env, "invalid tss");
194 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
195 if ((type & 7) != 1)
196 cpu_abort(env, "invalid tss type");
197 shift = type >> 3;
198 index = (dpl * 4 + 2) << shift;
199 if (index + (4 << shift) - 1 > env->tr.limit)
200 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
201 if (shift == 0) {
202 *esp_ptr = lduw_kernel(env->tr.base + index);
203 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
204 } else {
205 *esp_ptr = ldl_kernel(env->tr.base + index);
206 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
210 /* XXX: merge with load_seg() */
211 static void tss_load_seg(int seg_reg, int selector)
213 uint32_t e1, e2;
214 int rpl, dpl, cpl;
216 if ((selector & 0xfffc) != 0) {
217 if (load_segment(&e1, &e2, selector) != 0)
218 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
219 if (!(e2 & DESC_S_MASK))
220 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
221 rpl = selector & 3;
222 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
223 cpl = env->hflags & HF_CPL_MASK;
224 if (seg_reg == R_CS) {
225 if (!(e2 & DESC_CS_MASK))
226 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
227 /* XXX: is it correct ? */
228 if (dpl != rpl)
229 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230 if ((e2 & DESC_C_MASK) && dpl > rpl)
231 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
232 } else if (seg_reg == R_SS) {
233 /* SS must be writable data */
234 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
235 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
236 if (dpl != cpl || dpl != rpl)
237 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
238 } else {
239 /* not readable code */
240 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
241 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
242 /* if data or non conforming code, checks the rights */
243 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
244 if (dpl < cpl || dpl < rpl)
245 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
248 if (!(e2 & DESC_P_MASK))
249 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
250 cpu_x86_load_seg_cache(env, seg_reg, selector,
251 get_seg_base(e1, e2),
252 get_seg_limit(e1, e2),
253 e2);
254 } else {
255 if (seg_reg == R_SS || seg_reg == R_CS)
256 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
260 #define SWITCH_TSS_JMP 0
261 #define SWITCH_TSS_IRET 1
262 #define SWITCH_TSS_CALL 2
264 /* XXX: restore CPU state in registers (PowerPC case) */
265 static void switch_tss(int tss_selector,
266 uint32_t e1, uint32_t e2, int source,
267 uint32_t next_eip)
269 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
270 target_ulong tss_base;
271 uint32_t new_regs[8], new_segs[6];
272 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
273 uint32_t old_eflags, eflags_mask;
274 SegmentCache *dt;
275 int index;
276 target_ulong ptr;
278 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
279 #ifdef DEBUG_PCALL
280 if (loglevel & CPU_LOG_PCALL)
281 fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
282 #endif
284 /* if task gate, we read the TSS segment and we load it */
285 if (type == 5) {
286 if (!(e2 & DESC_P_MASK))
287 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
288 tss_selector = e1 >> 16;
289 if (tss_selector & 4)
290 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
291 if (load_segment(&e1, &e2, tss_selector) != 0)
292 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
293 if (e2 & DESC_S_MASK)
294 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
295 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
296 if ((type & 7) != 1)
297 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
300 if (!(e2 & DESC_P_MASK))
301 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
303 if (type & 8)
304 tss_limit_max = 103;
305 else
306 tss_limit_max = 43;
307 tss_limit = get_seg_limit(e1, e2);
308 tss_base = get_seg_base(e1, e2);
309 if ((tss_selector & 4) != 0 ||
310 tss_limit < tss_limit_max)
311 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
312 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
313 if (old_type & 8)
314 old_tss_limit_max = 103;
315 else
316 old_tss_limit_max = 43;
318 /* read all the registers from the new TSS */
319 if (type & 8) {
320 /* 32 bit */
321 new_cr3 = ldl_kernel(tss_base + 0x1c);
322 new_eip = ldl_kernel(tss_base + 0x20);
323 new_eflags = ldl_kernel(tss_base + 0x24);
324 for(i = 0; i < 8; i++)
325 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
326 for(i = 0; i < 6; i++)
327 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
328 new_ldt = lduw_kernel(tss_base + 0x60);
329 new_trap = ldl_kernel(tss_base + 0x64);
330 } else {
331 /* 16 bit */
332 new_cr3 = 0;
333 new_eip = lduw_kernel(tss_base + 0x0e);
334 new_eflags = lduw_kernel(tss_base + 0x10);
335 for(i = 0; i < 8; i++)
336 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
337 for(i = 0; i < 4; i++)
338 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
339 new_ldt = lduw_kernel(tss_base + 0x2a);
340 new_segs[R_FS] = 0;
341 new_segs[R_GS] = 0;
342 new_trap = 0;
345 /* NOTE: we must avoid memory exceptions during the task switch,
346 so we make dummy accesses before */
347 /* XXX: it can still fail in some cases, so a bigger hack is
348 necessary to valid the TLB after having done the accesses */
350 v1 = ldub_kernel(env->tr.base);
351 v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
352 stb_kernel(env->tr.base, v1);
353 stb_kernel(env->tr.base + old_tss_limit_max, v2);
355 /* clear busy bit (it is restartable) */
356 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
357 target_ulong ptr;
358 uint32_t e2;
359 ptr = env->gdt.base + (env->tr.selector & ~7);
360 e2 = ldl_kernel(ptr + 4);
361 e2 &= ~DESC_TSS_BUSY_MASK;
362 stl_kernel(ptr + 4, e2);
364 old_eflags = compute_eflags();
365 if (source == SWITCH_TSS_IRET)
366 old_eflags &= ~NT_MASK;
368 /* save the current state in the old TSS */
369 if (type & 8) {
370 /* 32 bit */
371 stl_kernel(env->tr.base + 0x20, next_eip);
372 stl_kernel(env->tr.base + 0x24, old_eflags);
373 stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
374 stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
375 stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
376 stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
377 stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
378 stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
379 stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
380 stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
381 for(i = 0; i < 6; i++)
382 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
383 } else {
384 /* 16 bit */
385 stw_kernel(env->tr.base + 0x0e, next_eip);
386 stw_kernel(env->tr.base + 0x10, old_eflags);
387 stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
388 stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
389 stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
390 stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
391 stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
392 stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
393 stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
394 stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
395 for(i = 0; i < 4; i++)
396 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
399 /* now if an exception occurs, it will occurs in the next task
400 context */
402 if (source == SWITCH_TSS_CALL) {
403 stw_kernel(tss_base, env->tr.selector);
404 new_eflags |= NT_MASK;
407 /* set busy bit */
408 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
409 target_ulong ptr;
410 uint32_t e2;
411 ptr = env->gdt.base + (tss_selector & ~7);
412 e2 = ldl_kernel(ptr + 4);
413 e2 |= DESC_TSS_BUSY_MASK;
414 stl_kernel(ptr + 4, e2);
417 /* set the new CPU state */
418 /* from this point, any exception which occurs can give problems */
419 env->cr[0] |= CR0_TS_MASK;
420 env->hflags |= HF_TS_MASK;
421 env->tr.selector = tss_selector;
422 env->tr.base = tss_base;
423 env->tr.limit = tss_limit;
424 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
426 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
427 cpu_x86_update_cr3(env, new_cr3);
430 /* load all registers without an exception, then reload them with
431 possible exception */
432 env->eip = new_eip;
433 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
434 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
435 if (!(type & 8))
436 eflags_mask &= 0xffff;
437 load_eflags(new_eflags, eflags_mask);
438 /* XXX: what to do in 16 bit case ? */
439 EAX = new_regs[0];
440 ECX = new_regs[1];
441 EDX = new_regs[2];
442 EBX = new_regs[3];
443 ESP = new_regs[4];
444 EBP = new_regs[5];
445 ESI = new_regs[6];
446 EDI = new_regs[7];
447 if (new_eflags & VM_MASK) {
448 for(i = 0; i < 6; i++)
449 load_seg_vm(i, new_segs[i]);
450 /* in vm86, CPL is always 3 */
451 cpu_x86_set_cpl(env, 3);
452 } else {
453 /* CPL is set the RPL of CS */
454 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
455 /* first just selectors as the rest may trigger exceptions */
456 for(i = 0; i < 6; i++)
457 cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
460 env->ldt.selector = new_ldt & ~4;
461 env->ldt.base = 0;
462 env->ldt.limit = 0;
463 env->ldt.flags = 0;
465 /* load the LDT */
466 if (new_ldt & 4)
467 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
469 if ((new_ldt & 0xfffc) != 0) {
470 dt = &env->gdt;
471 index = new_ldt & ~7;
472 if ((index + 7) > dt->limit)
473 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
474 ptr = dt->base + index;
475 e1 = ldl_kernel(ptr);
476 e2 = ldl_kernel(ptr + 4);
477 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
478 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
479 if (!(e2 & DESC_P_MASK))
480 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
481 load_seg_cache_raw_dt(&env->ldt, e1, e2);
484 /* load the segments */
485 if (!(new_eflags & VM_MASK)) {
486 tss_load_seg(R_CS, new_segs[R_CS]);
487 tss_load_seg(R_SS, new_segs[R_SS]);
488 tss_load_seg(R_ES, new_segs[R_ES]);
489 tss_load_seg(R_DS, new_segs[R_DS]);
490 tss_load_seg(R_FS, new_segs[R_FS]);
491 tss_load_seg(R_GS, new_segs[R_GS]);
494 /* check that EIP is in the CS segment limits */
495 if (new_eip > env->segs[R_CS].limit) {
496 /* XXX: different exception if CALL ? */
497 raise_exception_err(EXCP0D_GPF, 0);
501 /* check if Port I/O is allowed in TSS */
502 static inline void check_io(int addr, int size)
504 int io_offset, val, mask;
506 /* TSS must be a valid 32 bit one */
507 if (!(env->tr.flags & DESC_P_MASK) ||
508 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
509 env->tr.limit < 103)
510 goto fail;
511 io_offset = lduw_kernel(env->tr.base + 0x66);
512 io_offset += (addr >> 3);
513 /* Note: the check needs two bytes */
514 if ((io_offset + 1) > env->tr.limit)
515 goto fail;
516 val = lduw_kernel(env->tr.base + io_offset);
517 val >>= (addr & 7);
518 mask = (1 << size) - 1;
519 /* all bits must be zero to allow the I/O */
520 if ((val & mask) != 0) {
521 fail:
522 raise_exception_err(EXCP0D_GPF, 0);
526 void helper_check_iob(uint32_t t0)
528 check_io(t0, 1);
531 void helper_check_iow(uint32_t t0)
533 check_io(t0, 2);
536 void helper_check_iol(uint32_t t0)
538 check_io(t0, 4);
541 void helper_outb(uint32_t port, uint32_t data)
543 cpu_outb(env, port, data & 0xff);
546 target_ulong helper_inb(uint32_t port)
548 return cpu_inb(env, port);
551 void helper_outw(uint32_t port, uint32_t data)
553 cpu_outw(env, port, data & 0xffff);
556 target_ulong helper_inw(uint32_t port)
558 return cpu_inw(env, port);
561 void helper_outl(uint32_t port, uint32_t data)
563 cpu_outl(env, port, data);
566 target_ulong helper_inl(uint32_t port)
568 return cpu_inl(env, port);
571 static inline unsigned int get_sp_mask(unsigned int e2)
573 if (e2 & DESC_B_MASK)
574 return 0xffffffff;
575 else
576 return 0xffff;
579 #ifdef TARGET_X86_64
580 #define SET_ESP(val, sp_mask)\
581 do {\
582 if ((sp_mask) == 0xffff)\
583 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
584 else if ((sp_mask) == 0xffffffffLL)\
585 ESP = (uint32_t)(val);\
586 else\
587 ESP = (val);\
588 } while (0)
589 #else
590 #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
591 #endif
593 /* in 64-bit machines, this can overflow. So this segment addition macro
594 * can be used to trim the value to 32-bit whenever needed */
595 #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
597 /* XXX: add a is_user flag to have proper security support */
598 #define PUSHW(ssp, sp, sp_mask, val)\
600 sp -= 2;\
601 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
604 #define PUSHL(ssp, sp, sp_mask, val)\
606 sp -= 4;\
607 stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
610 #define POPW(ssp, sp, sp_mask, val)\
612 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
613 sp += 2;\
616 #define POPL(ssp, sp, sp_mask, val)\
618 val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
619 sp += 4;\
622 /* protected mode interrupt */
623 static void do_interrupt_protected(int intno, int is_int, int error_code,
624 unsigned int next_eip, int is_hw)
626 SegmentCache *dt;
627 target_ulong ptr, ssp;
628 int type, dpl, selector, ss_dpl, cpl;
629 int has_error_code, new_stack, shift;
630 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
631 uint32_t old_eip, sp_mask;
633 has_error_code = 0;
634 if (!is_int && !is_hw) {
635 switch(intno) {
636 case 8:
637 case 10:
638 case 11:
639 case 12:
640 case 13:
641 case 14:
642 case 17:
643 has_error_code = 1;
644 break;
647 if (is_int)
648 old_eip = next_eip;
649 else
650 old_eip = env->eip;
652 dt = &env->idt;
653 if (intno * 8 + 7 > dt->limit)
654 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
655 ptr = dt->base + intno * 8;
656 e1 = ldl_kernel(ptr);
657 e2 = ldl_kernel(ptr + 4);
658 /* check gate type */
659 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
660 switch(type) {
661 case 5: /* task gate */
662 /* must do that check here to return the correct error code */
663 if (!(e2 & DESC_P_MASK))
664 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
665 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
666 if (has_error_code) {
667 int type;
668 uint32_t mask;
669 /* push the error code */
670 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
671 shift = type >> 3;
672 if (env->segs[R_SS].flags & DESC_B_MASK)
673 mask = 0xffffffff;
674 else
675 mask = 0xffff;
676 esp = (ESP - (2 << shift)) & mask;
677 ssp = env->segs[R_SS].base + esp;
678 if (shift)
679 stl_kernel(ssp, error_code);
680 else
681 stw_kernel(ssp, error_code);
682 SET_ESP(esp, mask);
684 return;
685 case 6: /* 286 interrupt gate */
686 case 7: /* 286 trap gate */
687 case 14: /* 386 interrupt gate */
688 case 15: /* 386 trap gate */
689 break;
690 default:
691 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
692 break;
694 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
695 cpl = env->hflags & HF_CPL_MASK;
696 /* check privilege if software int */
697 if (is_int && dpl < cpl)
698 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
699 /* check valid bit */
700 if (!(e2 & DESC_P_MASK))
701 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
702 selector = e1 >> 16;
703 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
704 if ((selector & 0xfffc) == 0)
705 raise_exception_err(EXCP0D_GPF, 0);
707 if (load_segment(&e1, &e2, selector) != 0)
708 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
709 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
710 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
711 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
712 if (dpl > cpl)
713 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
714 if (!(e2 & DESC_P_MASK))
715 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
716 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
717 /* to inner privilege */
718 get_ss_esp_from_tss(&ss, &esp, dpl);
719 if ((ss & 0xfffc) == 0)
720 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
721 if ((ss & 3) != dpl)
722 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
723 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
724 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
725 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
726 if (ss_dpl != dpl)
727 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
728 if (!(ss_e2 & DESC_S_MASK) ||
729 (ss_e2 & DESC_CS_MASK) ||
730 !(ss_e2 & DESC_W_MASK))
731 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
732 if (!(ss_e2 & DESC_P_MASK))
733 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
734 new_stack = 1;
735 sp_mask = get_sp_mask(ss_e2);
736 ssp = get_seg_base(ss_e1, ss_e2);
737 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
738 /* to same privilege */
739 if (env->eflags & VM_MASK)
740 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
741 new_stack = 0;
742 sp_mask = get_sp_mask(env->segs[R_SS].flags);
743 ssp = env->segs[R_SS].base;
744 esp = ESP;
745 dpl = cpl;
746 } else {
747 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
748 new_stack = 0; /* avoid warning */
749 sp_mask = 0; /* avoid warning */
750 ssp = 0; /* avoid warning */
751 esp = 0; /* avoid warning */
754 shift = type >> 3;
756 #if 0
757 /* XXX: check that enough room is available */
758 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
759 if (env->eflags & VM_MASK)
760 push_size += 8;
761 push_size <<= shift;
762 #endif
763 if (shift == 1) {
764 if (new_stack) {
765 if (env->eflags & VM_MASK) {
766 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
767 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
768 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
769 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
771 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
772 PUSHL(ssp, esp, sp_mask, ESP);
774 PUSHL(ssp, esp, sp_mask, compute_eflags());
775 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
776 PUSHL(ssp, esp, sp_mask, old_eip);
777 if (has_error_code) {
778 PUSHL(ssp, esp, sp_mask, error_code);
780 } else {
781 if (new_stack) {
782 if (env->eflags & VM_MASK) {
783 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
784 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
785 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
786 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
788 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
789 PUSHW(ssp, esp, sp_mask, ESP);
791 PUSHW(ssp, esp, sp_mask, compute_eflags());
792 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
793 PUSHW(ssp, esp, sp_mask, old_eip);
794 if (has_error_code) {
795 PUSHW(ssp, esp, sp_mask, error_code);
799 if (new_stack) {
800 if (env->eflags & VM_MASK) {
801 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
802 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
803 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
804 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
806 ss = (ss & ~3) | dpl;
807 cpu_x86_load_seg_cache(env, R_SS, ss,
808 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
810 SET_ESP(esp, sp_mask);
812 selector = (selector & ~3) | dpl;
813 cpu_x86_load_seg_cache(env, R_CS, selector,
814 get_seg_base(e1, e2),
815 get_seg_limit(e1, e2),
816 e2);
817 cpu_x86_set_cpl(env, dpl);
818 env->eip = offset;
820 /* interrupt gate clear IF mask */
821 if ((type & 1) == 0) {
822 env->eflags &= ~IF_MASK;
824 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
827 #ifdef TARGET_X86_64
829 #define PUSHQ(sp, val)\
831 sp -= 8;\
832 stq_kernel(sp, (val));\
835 #define POPQ(sp, val)\
837 val = ldq_kernel(sp);\
838 sp += 8;\
841 static inline target_ulong get_rsp_from_tss(int level)
843 int index;
845 #if 0
846 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
847 env->tr.base, env->tr.limit);
848 #endif
850 if (!(env->tr.flags & DESC_P_MASK))
851 cpu_abort(env, "invalid tss");
852 index = 8 * level + 4;
853 if ((index + 7) > env->tr.limit)
854 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
855 return ldq_kernel(env->tr.base + index);
858 /* 64 bit interrupt */
859 static void do_interrupt64(int intno, int is_int, int error_code,
860 target_ulong next_eip, int is_hw)
862 SegmentCache *dt;
863 target_ulong ptr;
864 int type, dpl, selector, cpl, ist;
865 int has_error_code, new_stack;
866 uint32_t e1, e2, e3, ss;
867 target_ulong old_eip, esp, offset;
869 has_error_code = 0;
870 if (!is_int && !is_hw) {
871 switch(intno) {
872 case 8:
873 case 10:
874 case 11:
875 case 12:
876 case 13:
877 case 14:
878 case 17:
879 has_error_code = 1;
880 break;
883 if (is_int)
884 old_eip = next_eip;
885 else
886 old_eip = env->eip;
888 dt = &env->idt;
889 if (intno * 16 + 15 > dt->limit)
890 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
891 ptr = dt->base + intno * 16;
892 e1 = ldl_kernel(ptr);
893 e2 = ldl_kernel(ptr + 4);
894 e3 = ldl_kernel(ptr + 8);
895 /* check gate type */
896 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
897 switch(type) {
898 case 14: /* 386 interrupt gate */
899 case 15: /* 386 trap gate */
900 break;
901 default:
902 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
903 break;
905 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
906 cpl = env->hflags & HF_CPL_MASK;
907 /* check privilege if software int */
908 if (is_int && dpl < cpl)
909 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
910 /* check valid bit */
911 if (!(e2 & DESC_P_MASK))
912 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
913 selector = e1 >> 16;
914 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
915 ist = e2 & 7;
916 if ((selector & 0xfffc) == 0)
917 raise_exception_err(EXCP0D_GPF, 0);
919 if (load_segment(&e1, &e2, selector) != 0)
920 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
921 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
922 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
923 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
924 if (dpl > cpl)
925 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
926 if (!(e2 & DESC_P_MASK))
927 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
928 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
929 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
930 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
931 /* to inner privilege */
932 if (ist != 0)
933 esp = get_rsp_from_tss(ist + 3);
934 else
935 esp = get_rsp_from_tss(dpl);
936 esp &= ~0xfLL; /* align stack */
937 ss = 0;
938 new_stack = 1;
939 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
940 /* to same privilege */
941 if (env->eflags & VM_MASK)
942 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
943 new_stack = 0;
944 if (ist != 0)
945 esp = get_rsp_from_tss(ist + 3);
946 else
947 esp = ESP;
948 esp &= ~0xfLL; /* align stack */
949 dpl = cpl;
950 } else {
951 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
952 new_stack = 0; /* avoid warning */
953 esp = 0; /* avoid warning */
956 PUSHQ(esp, env->segs[R_SS].selector);
957 PUSHQ(esp, ESP);
958 PUSHQ(esp, compute_eflags());
959 PUSHQ(esp, env->segs[R_CS].selector);
960 PUSHQ(esp, old_eip);
961 if (has_error_code) {
962 PUSHQ(esp, error_code);
965 if (new_stack) {
966 ss = 0 | dpl;
967 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
969 ESP = esp;
971 selector = (selector & ~3) | dpl;
972 cpu_x86_load_seg_cache(env, R_CS, selector,
973 get_seg_base(e1, e2),
974 get_seg_limit(e1, e2),
975 e2);
976 cpu_x86_set_cpl(env, dpl);
977 env->eip = offset;
979 /* interrupt gate clear IF mask */
980 if ((type & 1) == 0) {
981 env->eflags &= ~IF_MASK;
983 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
985 #endif
987 #if defined(CONFIG_USER_ONLY)
988 void helper_syscall(int next_eip_addend)
990 env->exception_index = EXCP_SYSCALL;
991 env->exception_next_eip = env->eip + next_eip_addend;
992 cpu_loop_exit();
994 #else
995 void helper_syscall(int next_eip_addend)
997 int selector;
999 if (!(env->efer & MSR_EFER_SCE)) {
1000 raise_exception_err(EXCP06_ILLOP, 0);
1002 selector = (env->star >> 32) & 0xffff;
1003 #ifdef TARGET_X86_64
1004 if (env->hflags & HF_LMA_MASK) {
1005 int code64;
1007 ECX = env->eip + next_eip_addend;
1008 env->regs[11] = compute_eflags();
1010 code64 = env->hflags & HF_CS64_MASK;
1012 cpu_x86_set_cpl(env, 0);
1013 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1014 0, 0xffffffff,
1015 DESC_G_MASK | DESC_P_MASK |
1016 DESC_S_MASK |
1017 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1018 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1019 0, 0xffffffff,
1020 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1021 DESC_S_MASK |
1022 DESC_W_MASK | DESC_A_MASK);
1023 env->eflags &= ~env->fmask;
1024 load_eflags(env->eflags, 0);
1025 if (code64)
1026 env->eip = env->lstar;
1027 else
1028 env->eip = env->cstar;
1029 } else
1030 #endif
1032 ECX = (uint32_t)(env->eip + next_eip_addend);
1034 cpu_x86_set_cpl(env, 0);
1035 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1036 0, 0xffffffff,
1037 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1038 DESC_S_MASK |
1039 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1040 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1041 0, 0xffffffff,
1042 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1043 DESC_S_MASK |
1044 DESC_W_MASK | DESC_A_MASK);
1045 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1046 env->eip = (uint32_t)env->star;
1049 #endif
1051 void helper_sysret(int dflag)
1053 int cpl, selector;
1055 if (!(env->efer & MSR_EFER_SCE)) {
1056 raise_exception_err(EXCP06_ILLOP, 0);
1058 cpl = env->hflags & HF_CPL_MASK;
1059 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1060 raise_exception_err(EXCP0D_GPF, 0);
1062 selector = (env->star >> 48) & 0xffff;
1063 #ifdef TARGET_X86_64
1064 if (env->hflags & HF_LMA_MASK) {
1065 if (dflag == 2) {
1066 cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1067 0, 0xffffffff,
1068 DESC_G_MASK | DESC_P_MASK |
1069 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1070 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1071 DESC_L_MASK);
1072 env->eip = ECX;
1073 } else {
1074 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1075 0, 0xffffffff,
1076 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1077 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1078 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1079 env->eip = (uint32_t)ECX;
1081 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1082 0, 0xffffffff,
1083 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1084 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1085 DESC_W_MASK | DESC_A_MASK);
1086 load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1087 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1088 cpu_x86_set_cpl(env, 3);
1089 } else
1090 #endif
1092 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1093 0, 0xffffffff,
1094 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1095 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1096 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1097 env->eip = (uint32_t)ECX;
1098 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1099 0, 0xffffffff,
1100 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1101 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1102 DESC_W_MASK | DESC_A_MASK);
1103 env->eflags |= IF_MASK;
1104 cpu_x86_set_cpl(env, 3);
1106 #ifdef USE_KQEMU
1107 if (kqemu_is_ok(env)) {
1108 if (env->hflags & HF_LMA_MASK)
1109 CC_OP = CC_OP_EFLAGS;
1110 env->exception_index = -1;
1111 cpu_loop_exit();
1113 #endif
1116 /* real mode interrupt */
1117 static void do_interrupt_real(int intno, int is_int, int error_code,
1118 unsigned int next_eip)
1120 SegmentCache *dt;
1121 target_ulong ptr, ssp;
1122 int selector;
1123 uint32_t offset, esp;
1124 uint32_t old_cs, old_eip;
1126 /* real mode (simpler !) */
1127 dt = &env->idt;
1128 if (intno * 4 + 3 > dt->limit)
1129 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1130 ptr = dt->base + intno * 4;
1131 offset = lduw_kernel(ptr);
1132 selector = lduw_kernel(ptr + 2);
1133 esp = ESP;
1134 ssp = env->segs[R_SS].base;
1135 if (is_int)
1136 old_eip = next_eip;
1137 else
1138 old_eip = env->eip;
1139 old_cs = env->segs[R_CS].selector;
1140 /* XXX: use SS segment size ? */
1141 PUSHW(ssp, esp, 0xffff, compute_eflags());
1142 PUSHW(ssp, esp, 0xffff, old_cs);
1143 PUSHW(ssp, esp, 0xffff, old_eip);
1145 /* update processor state */
1146 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1147 env->eip = offset;
1148 env->segs[R_CS].selector = selector;
1149 env->segs[R_CS].base = (selector << 4);
1150 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1153 /* fake user mode interrupt */
1154 void do_interrupt_user(int intno, int is_int, int error_code,
1155 target_ulong next_eip)
1157 SegmentCache *dt;
1158 target_ulong ptr;
1159 int dpl, cpl, shift;
1160 uint32_t e2;
1162 dt = &env->idt;
1163 if (env->hflags & HF_LMA_MASK) {
1164 shift = 4;
1165 } else {
1166 shift = 3;
1168 ptr = dt->base + (intno << shift);
1169 e2 = ldl_kernel(ptr + 4);
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);
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;
1185 * Begin execution of an interruption. is_int is TRUE if coming from
1186 * the int instruction. next_eip is the EIP value AFTER the interrupt
1187 * instruction. It is only relevant if is_int is TRUE.
1189 void do_interrupt(int intno, int is_int, int error_code,
1190 target_ulong next_eip, int is_hw)
1192 if (loglevel & CPU_LOG_INT) {
1193 if ((env->cr[0] & CR0_PE_MASK)) {
1194 static int count;
1195 fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1196 count, intno, error_code, is_int,
1197 env->hflags & HF_CPL_MASK,
1198 env->segs[R_CS].selector, EIP,
1199 (int)env->segs[R_CS].base + EIP,
1200 env->segs[R_SS].selector, ESP);
1201 if (intno == 0x0e) {
1202 fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1203 } else {
1204 fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1206 fprintf(logfile, "\n");
1207 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1208 #if 0
1210 int i;
1211 uint8_t *ptr;
1212 fprintf(logfile, " code=");
1213 ptr = env->segs[R_CS].base + env->eip;
1214 for(i = 0; i < 16; i++) {
1215 fprintf(logfile, " %02x", ldub(ptr + i));
1217 fprintf(logfile, "\n");
1219 #endif
1220 count++;
1223 if (env->cr[0] & CR0_PE_MASK) {
1224 #ifdef TARGET_X86_64
1225 if (env->hflags & HF_LMA_MASK) {
1226 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1227 } else
1228 #endif
1230 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1232 } else {
1233 do_interrupt_real(intno, is_int, error_code, next_eip);
1238 * Check nested exceptions and change to double or triple fault if
1239 * needed. It should only be called, if this is not an interrupt.
1240 * Returns the new exception number.
1242 static int check_exception(int intno, int *error_code)
1244 int first_contributory = env->old_exception == 0 ||
1245 (env->old_exception >= 10 &&
1246 env->old_exception <= 13);
1247 int second_contributory = intno == 0 ||
1248 (intno >= 10 && intno <= 13);
1250 if (loglevel & CPU_LOG_INT)
1251 fprintf(logfile, "check_exception old: 0x%x new 0x%x\n",
1252 env->old_exception, intno);
1254 if (env->old_exception == EXCP08_DBLE)
1255 cpu_abort(env, "triple fault");
1257 if ((first_contributory && second_contributory)
1258 || (env->old_exception == EXCP0E_PAGE &&
1259 (second_contributory || (intno == EXCP0E_PAGE)))) {
1260 intno = EXCP08_DBLE;
1261 *error_code = 0;
1264 if (second_contributory || (intno == EXCP0E_PAGE) ||
1265 (intno == EXCP08_DBLE))
1266 env->old_exception = intno;
1268 return intno;
1272 * Signal an interruption. It is executed in the main CPU loop.
1273 * is_int is TRUE if coming from the int instruction. next_eip is the
1274 * EIP value AFTER the interrupt instruction. It is only relevant if
1275 * is_int is TRUE.
1277 void raise_interrupt(int intno, int is_int, int error_code,
1278 int next_eip_addend)
1280 if (!is_int) {
1281 helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1282 intno = check_exception(intno, &error_code);
1283 } else {
1284 helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
1287 env->exception_index = intno;
1288 env->error_code = error_code;
1289 env->exception_is_int = is_int;
1290 env->exception_next_eip = env->eip + next_eip_addend;
1291 cpu_loop_exit();
1294 /* shortcuts to generate exceptions */
1296 void (raise_exception_err)(int exception_index, int error_code)
1298 raise_interrupt(exception_index, 0, error_code, 0);
1301 void raise_exception(int exception_index)
1303 raise_interrupt(exception_index, 0, 0, 0);
1306 /* SMM support */
1308 #if defined(CONFIG_USER_ONLY)
1310 void do_smm_enter(void)
1314 void helper_rsm(void)
1318 #else
1320 #ifdef TARGET_X86_64
1321 #define SMM_REVISION_ID 0x00020064
1322 #else
1323 #define SMM_REVISION_ID 0x00020000
1324 #endif
1326 void do_smm_enter(void)
1328 target_ulong sm_state;
1329 SegmentCache *dt;
1330 int i, offset;
1332 if (loglevel & CPU_LOG_INT) {
1333 fprintf(logfile, "SMM: enter\n");
1334 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1337 env->hflags |= HF_SMM_MASK;
1338 cpu_smm_update(env);
1340 sm_state = env->smbase + 0x8000;
1342 #ifdef TARGET_X86_64
1343 for(i = 0; i < 6; i++) {
1344 dt = &env->segs[i];
1345 offset = 0x7e00 + i * 16;
1346 stw_phys(sm_state + offset, dt->selector);
1347 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1348 stl_phys(sm_state + offset + 4, dt->limit);
1349 stq_phys(sm_state + offset + 8, dt->base);
1352 stq_phys(sm_state + 0x7e68, env->gdt.base);
1353 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1355 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1356 stq_phys(sm_state + 0x7e78, env->ldt.base);
1357 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1358 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1360 stq_phys(sm_state + 0x7e88, env->idt.base);
1361 stl_phys(sm_state + 0x7e84, env->idt.limit);
1363 stw_phys(sm_state + 0x7e90, env->tr.selector);
1364 stq_phys(sm_state + 0x7e98, env->tr.base);
1365 stl_phys(sm_state + 0x7e94, env->tr.limit);
1366 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1368 stq_phys(sm_state + 0x7ed0, env->efer);
1370 stq_phys(sm_state + 0x7ff8, EAX);
1371 stq_phys(sm_state + 0x7ff0, ECX);
1372 stq_phys(sm_state + 0x7fe8, EDX);
1373 stq_phys(sm_state + 0x7fe0, EBX);
1374 stq_phys(sm_state + 0x7fd8, ESP);
1375 stq_phys(sm_state + 0x7fd0, EBP);
1376 stq_phys(sm_state + 0x7fc8, ESI);
1377 stq_phys(sm_state + 0x7fc0, EDI);
1378 for(i = 8; i < 16; i++)
1379 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1380 stq_phys(sm_state + 0x7f78, env->eip);
1381 stl_phys(sm_state + 0x7f70, compute_eflags());
1382 stl_phys(sm_state + 0x7f68, env->dr[6]);
1383 stl_phys(sm_state + 0x7f60, env->dr[7]);
1385 stl_phys(sm_state + 0x7f48, env->cr[4]);
1386 stl_phys(sm_state + 0x7f50, env->cr[3]);
1387 stl_phys(sm_state + 0x7f58, env->cr[0]);
1389 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1390 stl_phys(sm_state + 0x7f00, env->smbase);
1391 #else
1392 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1393 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1394 stl_phys(sm_state + 0x7ff4, compute_eflags());
1395 stl_phys(sm_state + 0x7ff0, env->eip);
1396 stl_phys(sm_state + 0x7fec, EDI);
1397 stl_phys(sm_state + 0x7fe8, ESI);
1398 stl_phys(sm_state + 0x7fe4, EBP);
1399 stl_phys(sm_state + 0x7fe0, ESP);
1400 stl_phys(sm_state + 0x7fdc, EBX);
1401 stl_phys(sm_state + 0x7fd8, EDX);
1402 stl_phys(sm_state + 0x7fd4, ECX);
1403 stl_phys(sm_state + 0x7fd0, EAX);
1404 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1405 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1407 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1408 stl_phys(sm_state + 0x7f64, env->tr.base);
1409 stl_phys(sm_state + 0x7f60, env->tr.limit);
1410 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1412 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1413 stl_phys(sm_state + 0x7f80, env->ldt.base);
1414 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1415 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1417 stl_phys(sm_state + 0x7f74, env->gdt.base);
1418 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1420 stl_phys(sm_state + 0x7f58, env->idt.base);
1421 stl_phys(sm_state + 0x7f54, env->idt.limit);
1423 for(i = 0; i < 6; i++) {
1424 dt = &env->segs[i];
1425 if (i < 3)
1426 offset = 0x7f84 + i * 12;
1427 else
1428 offset = 0x7f2c + (i - 3) * 12;
1429 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1430 stl_phys(sm_state + offset + 8, dt->base);
1431 stl_phys(sm_state + offset + 4, dt->limit);
1432 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1434 stl_phys(sm_state + 0x7f14, env->cr[4]);
1436 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1437 stl_phys(sm_state + 0x7ef8, env->smbase);
1438 #endif
1439 /* init SMM cpu state */
1441 #ifdef TARGET_X86_64
1442 cpu_load_efer(env, 0);
1443 #endif
1444 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1445 env->eip = 0x00008000;
1446 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1447 0xffffffff, 0);
1448 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1449 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1450 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1451 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1452 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1454 cpu_x86_update_cr0(env,
1455 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1456 cpu_x86_update_cr4(env, 0);
1457 env->dr[7] = 0x00000400;
1458 CC_OP = CC_OP_EFLAGS;
1461 void helper_rsm(void)
1463 target_ulong sm_state;
1464 int i, offset;
1465 uint32_t val;
1467 sm_state = env->smbase + 0x8000;
1468 #ifdef TARGET_X86_64
1469 cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
1471 for(i = 0; i < 6; i++) {
1472 offset = 0x7e00 + i * 16;
1473 cpu_x86_load_seg_cache(env, i,
1474 lduw_phys(sm_state + offset),
1475 ldq_phys(sm_state + offset + 8),
1476 ldl_phys(sm_state + offset + 4),
1477 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1480 env->gdt.base = ldq_phys(sm_state + 0x7e68);
1481 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1483 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1484 env->ldt.base = ldq_phys(sm_state + 0x7e78);
1485 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1486 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1488 env->idt.base = ldq_phys(sm_state + 0x7e88);
1489 env->idt.limit = ldl_phys(sm_state + 0x7e84);
1491 env->tr.selector = lduw_phys(sm_state + 0x7e90);
1492 env->tr.base = ldq_phys(sm_state + 0x7e98);
1493 env->tr.limit = ldl_phys(sm_state + 0x7e94);
1494 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1496 EAX = ldq_phys(sm_state + 0x7ff8);
1497 ECX = ldq_phys(sm_state + 0x7ff0);
1498 EDX = ldq_phys(sm_state + 0x7fe8);
1499 EBX = ldq_phys(sm_state + 0x7fe0);
1500 ESP = ldq_phys(sm_state + 0x7fd8);
1501 EBP = ldq_phys(sm_state + 0x7fd0);
1502 ESI = ldq_phys(sm_state + 0x7fc8);
1503 EDI = ldq_phys(sm_state + 0x7fc0);
1504 for(i = 8; i < 16; i++)
1505 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1506 env->eip = ldq_phys(sm_state + 0x7f78);
1507 load_eflags(ldl_phys(sm_state + 0x7f70),
1508 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1509 env->dr[6] = ldl_phys(sm_state + 0x7f68);
1510 env->dr[7] = ldl_phys(sm_state + 0x7f60);
1512 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1513 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1514 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1516 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1517 if (val & 0x20000) {
1518 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1520 #else
1521 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1522 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1523 load_eflags(ldl_phys(sm_state + 0x7ff4),
1524 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1525 env->eip = ldl_phys(sm_state + 0x7ff0);
1526 EDI = ldl_phys(sm_state + 0x7fec);
1527 ESI = ldl_phys(sm_state + 0x7fe8);
1528 EBP = ldl_phys(sm_state + 0x7fe4);
1529 ESP = ldl_phys(sm_state + 0x7fe0);
1530 EBX = ldl_phys(sm_state + 0x7fdc);
1531 EDX = ldl_phys(sm_state + 0x7fd8);
1532 ECX = ldl_phys(sm_state + 0x7fd4);
1533 EAX = ldl_phys(sm_state + 0x7fd0);
1534 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1535 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1537 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1538 env->tr.base = ldl_phys(sm_state + 0x7f64);
1539 env->tr.limit = ldl_phys(sm_state + 0x7f60);
1540 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1542 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1543 env->ldt.base = ldl_phys(sm_state + 0x7f80);
1544 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1545 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1547 env->gdt.base = ldl_phys(sm_state + 0x7f74);
1548 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1550 env->idt.base = ldl_phys(sm_state + 0x7f58);
1551 env->idt.limit = ldl_phys(sm_state + 0x7f54);
1553 for(i = 0; i < 6; i++) {
1554 if (i < 3)
1555 offset = 0x7f84 + i * 12;
1556 else
1557 offset = 0x7f2c + (i - 3) * 12;
1558 cpu_x86_load_seg_cache(env, i,
1559 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1560 ldl_phys(sm_state + offset + 8),
1561 ldl_phys(sm_state + offset + 4),
1562 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1564 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1566 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1567 if (val & 0x20000) {
1568 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1570 #endif
1571 CC_OP = CC_OP_EFLAGS;
1572 env->hflags &= ~HF_SMM_MASK;
1573 cpu_smm_update(env);
1575 if (loglevel & CPU_LOG_INT) {
1576 fprintf(logfile, "SMM: after RSM\n");
1577 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1581 #endif /* !CONFIG_USER_ONLY */
1584 /* division, flags are undefined */
1586 void helper_divb_AL(target_ulong t0)
1588 unsigned int num, den, q, r;
1590 num = (EAX & 0xffff);
1591 den = (t0 & 0xff);
1592 if (den == 0) {
1593 raise_exception(EXCP00_DIVZ);
1595 q = (num / den);
1596 if (q > 0xff)
1597 raise_exception(EXCP00_DIVZ);
1598 q &= 0xff;
1599 r = (num % den) & 0xff;
1600 EAX = (EAX & ~0xffff) | (r << 8) | q;
1603 void helper_idivb_AL(target_ulong t0)
1605 int num, den, q, r;
1607 num = (int16_t)EAX;
1608 den = (int8_t)t0;
1609 if (den == 0) {
1610 raise_exception(EXCP00_DIVZ);
1612 q = (num / den);
1613 if (q != (int8_t)q)
1614 raise_exception(EXCP00_DIVZ);
1615 q &= 0xff;
1616 r = (num % den) & 0xff;
1617 EAX = (EAX & ~0xffff) | (r << 8) | q;
1620 void helper_divw_AX(target_ulong t0)
1622 unsigned int num, den, q, r;
1624 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1625 den = (t0 & 0xffff);
1626 if (den == 0) {
1627 raise_exception(EXCP00_DIVZ);
1629 q = (num / den);
1630 if (q > 0xffff)
1631 raise_exception(EXCP00_DIVZ);
1632 q &= 0xffff;
1633 r = (num % den) & 0xffff;
1634 EAX = (EAX & ~0xffff) | q;
1635 EDX = (EDX & ~0xffff) | r;
1638 void helper_idivw_AX(target_ulong t0)
1640 int num, den, q, r;
1642 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1643 den = (int16_t)t0;
1644 if (den == 0) {
1645 raise_exception(EXCP00_DIVZ);
1647 q = (num / den);
1648 if (q != (int16_t)q)
1649 raise_exception(EXCP00_DIVZ);
1650 q &= 0xffff;
1651 r = (num % den) & 0xffff;
1652 EAX = (EAX & ~0xffff) | q;
1653 EDX = (EDX & ~0xffff) | r;
1656 void helper_divl_EAX(target_ulong t0)
1658 unsigned int den, r;
1659 uint64_t num, q;
1661 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1662 den = t0;
1663 if (den == 0) {
1664 raise_exception(EXCP00_DIVZ);
1666 q = (num / den);
1667 r = (num % den);
1668 if (q > 0xffffffff)
1669 raise_exception(EXCP00_DIVZ);
1670 EAX = (uint32_t)q;
1671 EDX = (uint32_t)r;
1674 void helper_idivl_EAX(target_ulong t0)
1676 int den, r;
1677 int64_t num, q;
1679 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1680 den = t0;
1681 if (den == 0) {
1682 raise_exception(EXCP00_DIVZ);
1684 q = (num / den);
1685 r = (num % den);
1686 if (q != (int32_t)q)
1687 raise_exception(EXCP00_DIVZ);
1688 EAX = (uint32_t)q;
1689 EDX = (uint32_t)r;
1692 /* bcd */
1694 /* XXX: exception */
1695 void helper_aam(int base)
1697 int al, ah;
1698 al = EAX & 0xff;
1699 ah = al / base;
1700 al = al % base;
1701 EAX = (EAX & ~0xffff) | al | (ah << 8);
1702 CC_DST = al;
1705 void helper_aad(int base)
1707 int al, ah;
1708 al = EAX & 0xff;
1709 ah = (EAX >> 8) & 0xff;
1710 al = ((ah * base) + al) & 0xff;
1711 EAX = (EAX & ~0xffff) | al;
1712 CC_DST = al;
1715 void helper_aaa(void)
1717 int icarry;
1718 int al, ah, af;
1719 int eflags;
1721 eflags = helper_cc_compute_all(CC_OP);
1722 af = eflags & CC_A;
1723 al = EAX & 0xff;
1724 ah = (EAX >> 8) & 0xff;
1726 icarry = (al > 0xf9);
1727 if (((al & 0x0f) > 9 ) || af) {
1728 al = (al + 6) & 0x0f;
1729 ah = (ah + 1 + icarry) & 0xff;
1730 eflags |= CC_C | CC_A;
1731 } else {
1732 eflags &= ~(CC_C | CC_A);
1733 al &= 0x0f;
1735 EAX = (EAX & ~0xffff) | al | (ah << 8);
1736 CC_SRC = eflags;
1737 FORCE_RET();
1740 void helper_aas(void)
1742 int icarry;
1743 int al, ah, af;
1744 int eflags;
1746 eflags = helper_cc_compute_all(CC_OP);
1747 af = eflags & CC_A;
1748 al = EAX & 0xff;
1749 ah = (EAX >> 8) & 0xff;
1751 icarry = (al < 6);
1752 if (((al & 0x0f) > 9 ) || af) {
1753 al = (al - 6) & 0x0f;
1754 ah = (ah - 1 - icarry) & 0xff;
1755 eflags |= CC_C | CC_A;
1756 } else {
1757 eflags &= ~(CC_C | CC_A);
1758 al &= 0x0f;
1760 EAX = (EAX & ~0xffff) | al | (ah << 8);
1761 CC_SRC = eflags;
1762 FORCE_RET();
1765 void helper_daa(void)
1767 int al, af, cf;
1768 int eflags;
1770 eflags = helper_cc_compute_all(CC_OP);
1771 cf = eflags & CC_C;
1772 af = eflags & CC_A;
1773 al = EAX & 0xff;
1775 eflags = 0;
1776 if (((al & 0x0f) > 9 ) || af) {
1777 al = (al + 6) & 0xff;
1778 eflags |= CC_A;
1780 if ((al > 0x9f) || cf) {
1781 al = (al + 0x60) & 0xff;
1782 eflags |= CC_C;
1784 EAX = (EAX & ~0xff) | al;
1785 /* well, speed is not an issue here, so we compute the flags by hand */
1786 eflags |= (al == 0) << 6; /* zf */
1787 eflags |= parity_table[al]; /* pf */
1788 eflags |= (al & 0x80); /* sf */
1789 CC_SRC = eflags;
1790 FORCE_RET();
1793 void helper_das(void)
1795 int al, al1, af, cf;
1796 int eflags;
1798 eflags = helper_cc_compute_all(CC_OP);
1799 cf = eflags & CC_C;
1800 af = eflags & CC_A;
1801 al = EAX & 0xff;
1803 eflags = 0;
1804 al1 = al;
1805 if (((al & 0x0f) > 9 ) || af) {
1806 eflags |= CC_A;
1807 if (al < 6 || cf)
1808 eflags |= CC_C;
1809 al = (al - 6) & 0xff;
1811 if ((al1 > 0x99) || cf) {
1812 al = (al - 0x60) & 0xff;
1813 eflags |= CC_C;
1815 EAX = (EAX & ~0xff) | al;
1816 /* well, speed is not an issue here, so we compute the flags by hand */
1817 eflags |= (al == 0) << 6; /* zf */
1818 eflags |= parity_table[al]; /* pf */
1819 eflags |= (al & 0x80); /* sf */
1820 CC_SRC = eflags;
1821 FORCE_RET();
1824 void helper_into(int next_eip_addend)
1826 int eflags;
1827 eflags = helper_cc_compute_all(CC_OP);
1828 if (eflags & CC_O) {
1829 raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
1833 void helper_cmpxchg8b(target_ulong a0)
1835 uint64_t d;
1836 int eflags;
1838 eflags = helper_cc_compute_all(CC_OP);
1839 d = ldq(a0);
1840 if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
1841 stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
1842 eflags |= CC_Z;
1843 } else {
1844 /* always do the store */
1845 stq(a0, d);
1846 EDX = (uint32_t)(d >> 32);
1847 EAX = (uint32_t)d;
1848 eflags &= ~CC_Z;
1850 CC_SRC = eflags;
1853 #ifdef TARGET_X86_64
1854 void helper_cmpxchg16b(target_ulong a0)
1856 uint64_t d0, d1;
1857 int eflags;
1859 if ((a0 & 0xf) != 0)
1860 raise_exception(EXCP0D_GPF);
1861 eflags = helper_cc_compute_all(CC_OP);
1862 d0 = ldq(a0);
1863 d1 = ldq(a0 + 8);
1864 if (d0 == EAX && d1 == EDX) {
1865 stq(a0, EBX);
1866 stq(a0 + 8, ECX);
1867 eflags |= CC_Z;
1868 } else {
1869 /* always do the store */
1870 stq(a0, d0);
1871 stq(a0 + 8, d1);
1872 EDX = d1;
1873 EAX = d0;
1874 eflags &= ~CC_Z;
1876 CC_SRC = eflags;
1878 #endif
1880 void helper_single_step(void)
1882 env->dr[6] |= 0x4000;
1883 raise_exception(EXCP01_SSTP);
1886 void helper_cpuid(void)
1888 uint32_t eax, ebx, ecx, edx;
1890 helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
1892 cpu_x86_cpuid(env, (uint32_t)EAX, &eax, &ebx, &ecx, &edx);
1893 EAX = eax;
1894 EBX = ebx;
1895 ECX = ecx;
1896 EDX = edx;
1899 void helper_enter_level(int level, int data32, target_ulong t1)
1901 target_ulong ssp;
1902 uint32_t esp_mask, esp, ebp;
1904 esp_mask = get_sp_mask(env->segs[R_SS].flags);
1905 ssp = env->segs[R_SS].base;
1906 ebp = EBP;
1907 esp = ESP;
1908 if (data32) {
1909 /* 32 bit */
1910 esp -= 4;
1911 while (--level) {
1912 esp -= 4;
1913 ebp -= 4;
1914 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1916 esp -= 4;
1917 stl(ssp + (esp & esp_mask), t1);
1918 } else {
1919 /* 16 bit */
1920 esp -= 2;
1921 while (--level) {
1922 esp -= 2;
1923 ebp -= 2;
1924 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1926 esp -= 2;
1927 stw(ssp + (esp & esp_mask), t1);
1931 #ifdef TARGET_X86_64
1932 void helper_enter64_level(int level, int data64, target_ulong t1)
1934 target_ulong esp, ebp;
1935 ebp = EBP;
1936 esp = ESP;
1938 if (data64) {
1939 /* 64 bit */
1940 esp -= 8;
1941 while (--level) {
1942 esp -= 8;
1943 ebp -= 8;
1944 stq(esp, ldq(ebp));
1946 esp -= 8;
1947 stq(esp, t1);
1948 } else {
1949 /* 16 bit */
1950 esp -= 2;
1951 while (--level) {
1952 esp -= 2;
1953 ebp -= 2;
1954 stw(esp, lduw(ebp));
1956 esp -= 2;
1957 stw(esp, t1);
1960 #endif
1962 void helper_lldt(int selector)
1964 SegmentCache *dt;
1965 uint32_t e1, e2;
1966 int index, entry_limit;
1967 target_ulong ptr;
1969 selector &= 0xffff;
1970 if ((selector & 0xfffc) == 0) {
1971 /* XXX: NULL selector case: invalid LDT */
1972 env->ldt.base = 0;
1973 env->ldt.limit = 0;
1974 } else {
1975 if (selector & 0x4)
1976 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1977 dt = &env->gdt;
1978 index = selector & ~7;
1979 #ifdef TARGET_X86_64
1980 if (env->hflags & HF_LMA_MASK)
1981 entry_limit = 15;
1982 else
1983 #endif
1984 entry_limit = 7;
1985 if ((index + entry_limit) > dt->limit)
1986 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1987 ptr = dt->base + index;
1988 e1 = ldl_kernel(ptr);
1989 e2 = ldl_kernel(ptr + 4);
1990 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1991 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1992 if (!(e2 & DESC_P_MASK))
1993 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1994 #ifdef TARGET_X86_64
1995 if (env->hflags & HF_LMA_MASK) {
1996 uint32_t e3;
1997 e3 = ldl_kernel(ptr + 8);
1998 load_seg_cache_raw_dt(&env->ldt, e1, e2);
1999 env->ldt.base |= (target_ulong)e3 << 32;
2000 } else
2001 #endif
2003 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2006 env->ldt.selector = selector;
2009 void helper_ltr(int selector)
2011 SegmentCache *dt;
2012 uint32_t e1, e2;
2013 int index, type, entry_limit;
2014 target_ulong ptr;
2016 selector &= 0xffff;
2017 if ((selector & 0xfffc) == 0) {
2018 /* NULL selector case: invalid TR */
2019 env->tr.base = 0;
2020 env->tr.limit = 0;
2021 env->tr.flags = 0;
2022 } else {
2023 if (selector & 0x4)
2024 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2025 dt = &env->gdt;
2026 index = selector & ~7;
2027 #ifdef TARGET_X86_64
2028 if (env->hflags & HF_LMA_MASK)
2029 entry_limit = 15;
2030 else
2031 #endif
2032 entry_limit = 7;
2033 if ((index + entry_limit) > dt->limit)
2034 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2035 ptr = dt->base + index;
2036 e1 = ldl_kernel(ptr);
2037 e2 = ldl_kernel(ptr + 4);
2038 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2039 if ((e2 & DESC_S_MASK) ||
2040 (type != 1 && type != 9))
2041 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2042 if (!(e2 & DESC_P_MASK))
2043 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2044 #ifdef TARGET_X86_64
2045 if (env->hflags & HF_LMA_MASK) {
2046 uint32_t e3, e4;
2047 e3 = ldl_kernel(ptr + 8);
2048 e4 = ldl_kernel(ptr + 12);
2049 if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2050 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2051 load_seg_cache_raw_dt(&env->tr, e1, e2);
2052 env->tr.base |= (target_ulong)e3 << 32;
2053 } else
2054 #endif
2056 load_seg_cache_raw_dt(&env->tr, e1, e2);
2058 e2 |= DESC_TSS_BUSY_MASK;
2059 stl_kernel(ptr + 4, e2);
2061 env->tr.selector = selector;
2064 /* only works if protected mode and not VM86. seg_reg must be != R_CS */
2065 void helper_load_seg(int seg_reg, int selector)
2067 uint32_t e1, e2;
2068 int cpl, dpl, rpl;
2069 SegmentCache *dt;
2070 int index;
2071 target_ulong ptr;
2073 selector &= 0xffff;
2074 cpl = env->hflags & HF_CPL_MASK;
2075 if ((selector & 0xfffc) == 0) {
2076 /* null selector case */
2077 if (seg_reg == R_SS
2078 #ifdef TARGET_X86_64
2079 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2080 #endif
2082 raise_exception_err(EXCP0D_GPF, 0);
2083 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2084 } else {
2086 if (selector & 0x4)
2087 dt = &env->ldt;
2088 else
2089 dt = &env->gdt;
2090 index = selector & ~7;
2091 if ((index + 7) > dt->limit)
2092 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2093 ptr = dt->base + index;
2094 e1 = ldl_kernel(ptr);
2095 e2 = ldl_kernel(ptr + 4);
2097 if (!(e2 & DESC_S_MASK))
2098 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2099 rpl = selector & 3;
2100 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2101 if (seg_reg == R_SS) {
2102 /* must be writable segment */
2103 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2104 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2105 if (rpl != cpl || dpl != cpl)
2106 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2107 } else {
2108 /* must be readable segment */
2109 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2110 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2112 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2113 /* if not conforming code, test rights */
2114 if (dpl < cpl || dpl < rpl)
2115 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2119 if (!(e2 & DESC_P_MASK)) {
2120 if (seg_reg == R_SS)
2121 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2122 else
2123 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2126 /* set the access bit if not already set */
2127 if (!(e2 & DESC_A_MASK)) {
2128 e2 |= DESC_A_MASK;
2129 stl_kernel(ptr + 4, e2);
2132 cpu_x86_load_seg_cache(env, seg_reg, selector,
2133 get_seg_base(e1, e2),
2134 get_seg_limit(e1, e2),
2135 e2);
2136 #if 0
2137 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2138 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2139 #endif
2143 /* protected mode jump */
2144 void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2145 int next_eip_addend)
2147 int gate_cs, type;
2148 uint32_t e1, e2, cpl, dpl, rpl, limit;
2149 target_ulong next_eip;
2151 if ((new_cs & 0xfffc) == 0)
2152 raise_exception_err(EXCP0D_GPF, 0);
2153 if (load_segment(&e1, &e2, new_cs) != 0)
2154 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2155 cpl = env->hflags & HF_CPL_MASK;
2156 if (e2 & DESC_S_MASK) {
2157 if (!(e2 & DESC_CS_MASK))
2158 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2159 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2160 if (e2 & DESC_C_MASK) {
2161 /* conforming code segment */
2162 if (dpl > cpl)
2163 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2164 } else {
2165 /* non conforming code segment */
2166 rpl = new_cs & 3;
2167 if (rpl > cpl)
2168 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2169 if (dpl != cpl)
2170 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2172 if (!(e2 & DESC_P_MASK))
2173 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2174 limit = get_seg_limit(e1, e2);
2175 if (new_eip > limit &&
2176 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2177 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2178 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2179 get_seg_base(e1, e2), limit, e2);
2180 EIP = new_eip;
2181 } else {
2182 /* jump to call or task gate */
2183 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2184 rpl = new_cs & 3;
2185 cpl = env->hflags & HF_CPL_MASK;
2186 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2187 switch(type) {
2188 case 1: /* 286 TSS */
2189 case 9: /* 386 TSS */
2190 case 5: /* task gate */
2191 if (dpl < cpl || dpl < rpl)
2192 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2193 next_eip = env->eip + next_eip_addend;
2194 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2195 CC_OP = CC_OP_EFLAGS;
2196 break;
2197 case 4: /* 286 call gate */
2198 case 12: /* 386 call gate */
2199 if ((dpl < cpl) || (dpl < rpl))
2200 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2201 if (!(e2 & DESC_P_MASK))
2202 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2203 gate_cs = e1 >> 16;
2204 new_eip = (e1 & 0xffff);
2205 if (type == 12)
2206 new_eip |= (e2 & 0xffff0000);
2207 if (load_segment(&e1, &e2, gate_cs) != 0)
2208 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2209 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2210 /* must be code segment */
2211 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2212 (DESC_S_MASK | DESC_CS_MASK)))
2213 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2214 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2215 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2216 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2217 if (!(e2 & DESC_P_MASK))
2218 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2219 limit = get_seg_limit(e1, e2);
2220 if (new_eip > limit)
2221 raise_exception_err(EXCP0D_GPF, 0);
2222 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2223 get_seg_base(e1, e2), limit, e2);
2224 EIP = new_eip;
2225 break;
2226 default:
2227 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2228 break;
2233 /* real mode call */
2234 void helper_lcall_real(int new_cs, target_ulong new_eip1,
2235 int shift, int next_eip)
2237 int new_eip;
2238 uint32_t esp, esp_mask;
2239 target_ulong ssp;
2241 new_eip = new_eip1;
2242 esp = ESP;
2243 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2244 ssp = env->segs[R_SS].base;
2245 if (shift) {
2246 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2247 PUSHL(ssp, esp, esp_mask, next_eip);
2248 } else {
2249 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2250 PUSHW(ssp, esp, esp_mask, next_eip);
2253 SET_ESP(esp, esp_mask);
2254 env->eip = new_eip;
2255 env->segs[R_CS].selector = new_cs;
2256 env->segs[R_CS].base = (new_cs << 4);
2259 /* protected mode call */
2260 void helper_lcall_protected(int new_cs, target_ulong new_eip,
2261 int shift, int next_eip_addend)
2263 int new_stack, i;
2264 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2265 uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2266 uint32_t val, limit, old_sp_mask;
2267 target_ulong ssp, old_ssp, next_eip;
2269 next_eip = env->eip + next_eip_addend;
2270 #ifdef DEBUG_PCALL
2271 if (loglevel & CPU_LOG_PCALL) {
2272 fprintf(logfile, "lcall %04x:%08x s=%d\n",
2273 new_cs, (uint32_t)new_eip, shift);
2274 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2276 #endif
2277 if ((new_cs & 0xfffc) == 0)
2278 raise_exception_err(EXCP0D_GPF, 0);
2279 if (load_segment(&e1, &e2, new_cs) != 0)
2280 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2281 cpl = env->hflags & HF_CPL_MASK;
2282 #ifdef DEBUG_PCALL
2283 if (loglevel & CPU_LOG_PCALL) {
2284 fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2286 #endif
2287 if (e2 & DESC_S_MASK) {
2288 if (!(e2 & DESC_CS_MASK))
2289 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2290 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2291 if (e2 & DESC_C_MASK) {
2292 /* conforming code segment */
2293 if (dpl > cpl)
2294 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2295 } else {
2296 /* non conforming code segment */
2297 rpl = new_cs & 3;
2298 if (rpl > cpl)
2299 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2300 if (dpl != cpl)
2301 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2303 if (!(e2 & DESC_P_MASK))
2304 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2306 #ifdef TARGET_X86_64
2307 /* XXX: check 16/32 bit cases in long mode */
2308 if (shift == 2) {
2309 target_ulong rsp;
2310 /* 64 bit case */
2311 rsp = ESP;
2312 PUSHQ(rsp, env->segs[R_CS].selector);
2313 PUSHQ(rsp, next_eip);
2314 /* from this point, not restartable */
2315 ESP = rsp;
2316 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2317 get_seg_base(e1, e2),
2318 get_seg_limit(e1, e2), e2);
2319 EIP = new_eip;
2320 } else
2321 #endif
2323 sp = ESP;
2324 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2325 ssp = env->segs[R_SS].base;
2326 if (shift) {
2327 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2328 PUSHL(ssp, sp, sp_mask, next_eip);
2329 } else {
2330 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2331 PUSHW(ssp, sp, sp_mask, next_eip);
2334 limit = get_seg_limit(e1, e2);
2335 if (new_eip > limit)
2336 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2337 /* from this point, not restartable */
2338 SET_ESP(sp, sp_mask);
2339 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2340 get_seg_base(e1, e2), limit, e2);
2341 EIP = new_eip;
2343 } else {
2344 /* check gate type */
2345 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2346 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2347 rpl = new_cs & 3;
2348 switch(type) {
2349 case 1: /* available 286 TSS */
2350 case 9: /* available 386 TSS */
2351 case 5: /* task gate */
2352 if (dpl < cpl || dpl < rpl)
2353 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2354 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2355 CC_OP = CC_OP_EFLAGS;
2356 return;
2357 case 4: /* 286 call gate */
2358 case 12: /* 386 call gate */
2359 break;
2360 default:
2361 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2362 break;
2364 shift = type >> 3;
2366 if (dpl < cpl || dpl < rpl)
2367 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2368 /* check valid bit */
2369 if (!(e2 & DESC_P_MASK))
2370 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2371 selector = e1 >> 16;
2372 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2373 param_count = e2 & 0x1f;
2374 if ((selector & 0xfffc) == 0)
2375 raise_exception_err(EXCP0D_GPF, 0);
2377 if (load_segment(&e1, &e2, selector) != 0)
2378 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2379 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2380 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2381 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2382 if (dpl > cpl)
2383 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2384 if (!(e2 & DESC_P_MASK))
2385 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2387 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2388 /* to inner privilege */
2389 get_ss_esp_from_tss(&ss, &sp, dpl);
2390 #ifdef DEBUG_PCALL
2391 if (loglevel & CPU_LOG_PCALL)
2392 fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2393 ss, sp, param_count, ESP);
2394 #endif
2395 if ((ss & 0xfffc) == 0)
2396 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2397 if ((ss & 3) != dpl)
2398 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2399 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2400 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2401 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2402 if (ss_dpl != dpl)
2403 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2404 if (!(ss_e2 & DESC_S_MASK) ||
2405 (ss_e2 & DESC_CS_MASK) ||
2406 !(ss_e2 & DESC_W_MASK))
2407 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2408 if (!(ss_e2 & DESC_P_MASK))
2409 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2411 // push_size = ((param_count * 2) + 8) << shift;
2413 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2414 old_ssp = env->segs[R_SS].base;
2416 sp_mask = get_sp_mask(ss_e2);
2417 ssp = get_seg_base(ss_e1, ss_e2);
2418 if (shift) {
2419 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2420 PUSHL(ssp, sp, sp_mask, ESP);
2421 for(i = param_count - 1; i >= 0; i--) {
2422 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2423 PUSHL(ssp, sp, sp_mask, val);
2425 } else {
2426 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2427 PUSHW(ssp, sp, sp_mask, ESP);
2428 for(i = param_count - 1; i >= 0; i--) {
2429 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2430 PUSHW(ssp, sp, sp_mask, val);
2433 new_stack = 1;
2434 } else {
2435 /* to same privilege */
2436 sp = ESP;
2437 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2438 ssp = env->segs[R_SS].base;
2439 // push_size = (4 << shift);
2440 new_stack = 0;
2443 if (shift) {
2444 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2445 PUSHL(ssp, sp, sp_mask, next_eip);
2446 } else {
2447 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2448 PUSHW(ssp, sp, sp_mask, next_eip);
2451 /* from this point, not restartable */
2453 if (new_stack) {
2454 ss = (ss & ~3) | dpl;
2455 cpu_x86_load_seg_cache(env, R_SS, ss,
2456 ssp,
2457 get_seg_limit(ss_e1, ss_e2),
2458 ss_e2);
2461 selector = (selector & ~3) | dpl;
2462 cpu_x86_load_seg_cache(env, R_CS, selector,
2463 get_seg_base(e1, e2),
2464 get_seg_limit(e1, e2),
2465 e2);
2466 cpu_x86_set_cpl(env, dpl);
2467 SET_ESP(sp, sp_mask);
2468 EIP = offset;
2470 #ifdef USE_KQEMU
2471 if (kqemu_is_ok(env)) {
2472 env->exception_index = -1;
2473 cpu_loop_exit();
2475 #endif
2478 /* real and vm86 mode iret */
2479 void helper_iret_real(int shift)
2481 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2482 target_ulong ssp;
2483 int eflags_mask;
2485 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2486 sp = ESP;
2487 ssp = env->segs[R_SS].base;
2488 if (shift == 1) {
2489 /* 32 bits */
2490 POPL(ssp, sp, sp_mask, new_eip);
2491 POPL(ssp, sp, sp_mask, new_cs);
2492 new_cs &= 0xffff;
2493 POPL(ssp, sp, sp_mask, new_eflags);
2494 } else {
2495 /* 16 bits */
2496 POPW(ssp, sp, sp_mask, new_eip);
2497 POPW(ssp, sp, sp_mask, new_cs);
2498 POPW(ssp, sp, sp_mask, new_eflags);
2500 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2501 env->segs[R_CS].selector = new_cs;
2502 env->segs[R_CS].base = (new_cs << 4);
2503 env->eip = new_eip;
2504 if (env->eflags & VM_MASK)
2505 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2506 else
2507 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2508 if (shift == 0)
2509 eflags_mask &= 0xffff;
2510 load_eflags(new_eflags, eflags_mask);
2511 env->hflags2 &= ~HF2_NMI_MASK;
2514 static inline void validate_seg(int seg_reg, int cpl)
2516 int dpl;
2517 uint32_t e2;
2519 /* XXX: on x86_64, we do not want to nullify FS and GS because
2520 they may still contain a valid base. I would be interested to
2521 know how a real x86_64 CPU behaves */
2522 if ((seg_reg == R_FS || seg_reg == R_GS) &&
2523 (env->segs[seg_reg].selector & 0xfffc) == 0)
2524 return;
2526 e2 = env->segs[seg_reg].flags;
2527 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2528 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2529 /* data or non conforming code segment */
2530 if (dpl < cpl) {
2531 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2536 /* protected mode iret */
2537 static inline void helper_ret_protected(int shift, int is_iret, int addend)
2539 uint32_t new_cs, new_eflags, new_ss;
2540 uint32_t new_es, new_ds, new_fs, new_gs;
2541 uint32_t e1, e2, ss_e1, ss_e2;
2542 int cpl, dpl, rpl, eflags_mask, iopl;
2543 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2545 #ifdef TARGET_X86_64
2546 if (shift == 2)
2547 sp_mask = -1;
2548 else
2549 #endif
2550 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2551 sp = ESP;
2552 ssp = env->segs[R_SS].base;
2553 new_eflags = 0; /* avoid warning */
2554 #ifdef TARGET_X86_64
2555 if (shift == 2) {
2556 POPQ(sp, new_eip);
2557 POPQ(sp, new_cs);
2558 new_cs &= 0xffff;
2559 if (is_iret) {
2560 POPQ(sp, new_eflags);
2562 } else
2563 #endif
2564 if (shift == 1) {
2565 /* 32 bits */
2566 POPL(ssp, sp, sp_mask, new_eip);
2567 POPL(ssp, sp, sp_mask, new_cs);
2568 new_cs &= 0xffff;
2569 if (is_iret) {
2570 POPL(ssp, sp, sp_mask, new_eflags);
2571 if (new_eflags & VM_MASK)
2572 goto return_to_vm86;
2574 } else {
2575 /* 16 bits */
2576 POPW(ssp, sp, sp_mask, new_eip);
2577 POPW(ssp, sp, sp_mask, new_cs);
2578 if (is_iret)
2579 POPW(ssp, sp, sp_mask, new_eflags);
2581 #ifdef DEBUG_PCALL
2582 if (loglevel & CPU_LOG_PCALL) {
2583 fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2584 new_cs, new_eip, shift, addend);
2585 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2587 #endif
2588 if ((new_cs & 0xfffc) == 0)
2589 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2590 if (load_segment(&e1, &e2, new_cs) != 0)
2591 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2592 if (!(e2 & DESC_S_MASK) ||
2593 !(e2 & DESC_CS_MASK))
2594 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2595 cpl = env->hflags & HF_CPL_MASK;
2596 rpl = new_cs & 3;
2597 if (rpl < cpl)
2598 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2599 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2600 if (e2 & DESC_C_MASK) {
2601 if (dpl > rpl)
2602 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2603 } else {
2604 if (dpl != rpl)
2605 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2607 if (!(e2 & DESC_P_MASK))
2608 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2610 sp += addend;
2611 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2612 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2613 /* return to same privilege level */
2614 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2615 get_seg_base(e1, e2),
2616 get_seg_limit(e1, e2),
2617 e2);
2618 } else {
2619 /* return to different privilege level */
2620 #ifdef TARGET_X86_64
2621 if (shift == 2) {
2622 POPQ(sp, new_esp);
2623 POPQ(sp, new_ss);
2624 new_ss &= 0xffff;
2625 } else
2626 #endif
2627 if (shift == 1) {
2628 /* 32 bits */
2629 POPL(ssp, sp, sp_mask, new_esp);
2630 POPL(ssp, sp, sp_mask, new_ss);
2631 new_ss &= 0xffff;
2632 } else {
2633 /* 16 bits */
2634 POPW(ssp, sp, sp_mask, new_esp);
2635 POPW(ssp, sp, sp_mask, new_ss);
2637 #ifdef DEBUG_PCALL
2638 if (loglevel & CPU_LOG_PCALL) {
2639 fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2640 new_ss, new_esp);
2642 #endif
2643 if ((new_ss & 0xfffc) == 0) {
2644 #ifdef TARGET_X86_64
2645 /* NULL ss is allowed in long mode if cpl != 3*/
2646 /* XXX: test CS64 ? */
2647 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2648 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2649 0, 0xffffffff,
2650 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2651 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2652 DESC_W_MASK | DESC_A_MASK);
2653 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2654 } else
2655 #endif
2657 raise_exception_err(EXCP0D_GPF, 0);
2659 } else {
2660 if ((new_ss & 3) != rpl)
2661 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2662 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2663 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2664 if (!(ss_e2 & DESC_S_MASK) ||
2665 (ss_e2 & DESC_CS_MASK) ||
2666 !(ss_e2 & DESC_W_MASK))
2667 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2668 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2669 if (dpl != rpl)
2670 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2671 if (!(ss_e2 & DESC_P_MASK))
2672 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2673 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2674 get_seg_base(ss_e1, ss_e2),
2675 get_seg_limit(ss_e1, ss_e2),
2676 ss_e2);
2679 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2680 get_seg_base(e1, e2),
2681 get_seg_limit(e1, e2),
2682 e2);
2683 cpu_x86_set_cpl(env, rpl);
2684 sp = new_esp;
2685 #ifdef TARGET_X86_64
2686 if (env->hflags & HF_CS64_MASK)
2687 sp_mask = -1;
2688 else
2689 #endif
2690 sp_mask = get_sp_mask(ss_e2);
2692 /* validate data segments */
2693 validate_seg(R_ES, rpl);
2694 validate_seg(R_DS, rpl);
2695 validate_seg(R_FS, rpl);
2696 validate_seg(R_GS, rpl);
2698 sp += addend;
2700 SET_ESP(sp, sp_mask);
2701 env->eip = new_eip;
2702 if (is_iret) {
2703 /* NOTE: 'cpl' is the _old_ CPL */
2704 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2705 if (cpl == 0)
2706 eflags_mask |= IOPL_MASK;
2707 iopl = (env->eflags >> IOPL_SHIFT) & 3;
2708 if (cpl <= iopl)
2709 eflags_mask |= IF_MASK;
2710 if (shift == 0)
2711 eflags_mask &= 0xffff;
2712 load_eflags(new_eflags, eflags_mask);
2714 return;
2716 return_to_vm86:
2717 POPL(ssp, sp, sp_mask, new_esp);
2718 POPL(ssp, sp, sp_mask, new_ss);
2719 POPL(ssp, sp, sp_mask, new_es);
2720 POPL(ssp, sp, sp_mask, new_ds);
2721 POPL(ssp, sp, sp_mask, new_fs);
2722 POPL(ssp, sp, sp_mask, new_gs);
2724 /* modify processor state */
2725 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2726 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2727 load_seg_vm(R_CS, new_cs & 0xffff);
2728 cpu_x86_set_cpl(env, 3);
2729 load_seg_vm(R_SS, new_ss & 0xffff);
2730 load_seg_vm(R_ES, new_es & 0xffff);
2731 load_seg_vm(R_DS, new_ds & 0xffff);
2732 load_seg_vm(R_FS, new_fs & 0xffff);
2733 load_seg_vm(R_GS, new_gs & 0xffff);
2735 env->eip = new_eip & 0xffff;
2736 ESP = new_esp;
2739 void helper_iret_protected(int shift, int next_eip)
2741 int tss_selector, type;
2742 uint32_t e1, e2;
2744 /* specific case for TSS */
2745 if (env->eflags & NT_MASK) {
2746 #ifdef TARGET_X86_64
2747 if (env->hflags & HF_LMA_MASK)
2748 raise_exception_err(EXCP0D_GPF, 0);
2749 #endif
2750 tss_selector = lduw_kernel(env->tr.base + 0);
2751 if (tss_selector & 4)
2752 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2753 if (load_segment(&e1, &e2, tss_selector) != 0)
2754 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2755 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2756 /* NOTE: we check both segment and busy TSS */
2757 if (type != 3)
2758 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2759 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2760 } else {
2761 helper_ret_protected(shift, 1, 0);
2763 env->hflags2 &= ~HF2_NMI_MASK;
2764 #ifdef USE_KQEMU
2765 if (kqemu_is_ok(env)) {
2766 CC_OP = CC_OP_EFLAGS;
2767 env->exception_index = -1;
2768 cpu_loop_exit();
2770 #endif
2773 void helper_lret_protected(int shift, int addend)
2775 helper_ret_protected(shift, 0, addend);
2776 #ifdef USE_KQEMU
2777 if (kqemu_is_ok(env)) {
2778 env->exception_index = -1;
2779 cpu_loop_exit();
2781 #endif
2784 void helper_sysenter(void)
2786 if (env->sysenter_cs == 0) {
2787 raise_exception_err(EXCP0D_GPF, 0);
2789 env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2790 cpu_x86_set_cpl(env, 0);
2792 #ifdef TARGET_X86_64
2793 if (env->hflags & HF_LMA_MASK) {
2794 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2795 0, 0xffffffff,
2796 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2797 DESC_S_MASK |
2798 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2799 } else
2800 #endif
2802 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2803 0, 0xffffffff,
2804 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2805 DESC_S_MASK |
2806 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2808 cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2809 0, 0xffffffff,
2810 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2811 DESC_S_MASK |
2812 DESC_W_MASK | DESC_A_MASK);
2813 ESP = env->sysenter_esp;
2814 EIP = env->sysenter_eip;
2817 void helper_sysexit(int dflag)
2819 int cpl;
2821 cpl = env->hflags & HF_CPL_MASK;
2822 if (env->sysenter_cs == 0 || cpl != 0) {
2823 raise_exception_err(EXCP0D_GPF, 0);
2825 cpu_x86_set_cpl(env, 3);
2826 #ifdef TARGET_X86_64
2827 if (dflag == 2) {
2828 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
2829 0, 0xffffffff,
2830 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2831 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2832 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2833 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
2834 0, 0xffffffff,
2835 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2836 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2837 DESC_W_MASK | DESC_A_MASK);
2838 } else
2839 #endif
2841 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2842 0, 0xffffffff,
2843 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2844 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2845 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2846 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2847 0, 0xffffffff,
2848 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2849 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2850 DESC_W_MASK | DESC_A_MASK);
2852 ESP = ECX;
2853 EIP = EDX;
2854 #ifdef USE_KQEMU
2855 if (kqemu_is_ok(env)) {
2856 env->exception_index = -1;
2857 cpu_loop_exit();
2859 #endif
2862 #if defined(CONFIG_USER_ONLY)
2863 target_ulong helper_read_crN(int reg)
2865 return 0;
2868 void helper_write_crN(int reg, target_ulong t0)
2871 #else
2872 target_ulong helper_read_crN(int reg)
2874 target_ulong val;
2876 helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
2877 switch(reg) {
2878 default:
2879 val = env->cr[reg];
2880 break;
2881 case 8:
2882 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2883 val = cpu_get_apic_tpr(env);
2884 } else {
2885 val = env->v_tpr;
2887 break;
2889 return val;
2892 void helper_write_crN(int reg, target_ulong t0)
2894 helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
2895 switch(reg) {
2896 case 0:
2897 cpu_x86_update_cr0(env, t0);
2898 break;
2899 case 3:
2900 cpu_x86_update_cr3(env, t0);
2901 break;
2902 case 4:
2903 cpu_x86_update_cr4(env, t0);
2904 break;
2905 case 8:
2906 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2907 cpu_set_apic_tpr(env, t0);
2909 env->v_tpr = t0 & 0x0f;
2910 break;
2911 default:
2912 env->cr[reg] = t0;
2913 break;
2916 #endif
2918 void helper_lmsw(target_ulong t0)
2920 /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
2921 if already set to one. */
2922 t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
2923 helper_write_crN(0, t0);
2926 void helper_clts(void)
2928 env->cr[0] &= ~CR0_TS_MASK;
2929 env->hflags &= ~HF_TS_MASK;
2932 /* XXX: do more */
2933 void helper_movl_drN_T0(int reg, target_ulong t0)
2935 env->dr[reg] = t0;
2938 void helper_invlpg(target_ulong addr)
2940 helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
2941 tlb_flush_page(env, addr);
2944 void helper_rdtsc(void)
2946 uint64_t val;
2948 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2949 raise_exception(EXCP0D_GPF);
2951 helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
2953 val = cpu_get_tsc(env) + env->tsc_offset;
2954 EAX = (uint32_t)(val);
2955 EDX = (uint32_t)(val >> 32);
2958 void helper_rdpmc(void)
2960 if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2961 raise_exception(EXCP0D_GPF);
2963 helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
2965 /* currently unimplemented */
2966 raise_exception_err(EXCP06_ILLOP, 0);
2969 #if defined(CONFIG_USER_ONLY)
2970 void helper_wrmsr(void)
2974 void helper_rdmsr(void)
2977 #else
2978 void helper_wrmsr(void)
2980 uint64_t val;
2982 helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
2984 val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2986 switch((uint32_t)ECX) {
2987 case MSR_IA32_SYSENTER_CS:
2988 env->sysenter_cs = val & 0xffff;
2989 break;
2990 case MSR_IA32_SYSENTER_ESP:
2991 env->sysenter_esp = val;
2992 break;
2993 case MSR_IA32_SYSENTER_EIP:
2994 env->sysenter_eip = val;
2995 break;
2996 case MSR_IA32_APICBASE:
2997 cpu_set_apic_base(env, val);
2998 break;
2999 case MSR_EFER:
3001 uint64_t update_mask;
3002 update_mask = 0;
3003 if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3004 update_mask |= MSR_EFER_SCE;
3005 if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3006 update_mask |= MSR_EFER_LME;
3007 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3008 update_mask |= MSR_EFER_FFXSR;
3009 if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3010 update_mask |= MSR_EFER_NXE;
3011 if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
3012 update_mask |= MSR_EFER_SVME;
3013 cpu_load_efer(env, (env->efer & ~update_mask) |
3014 (val & update_mask));
3016 break;
3017 case MSR_STAR:
3018 env->star = val;
3019 break;
3020 case MSR_PAT:
3021 env->pat = val;
3022 break;
3023 case MSR_VM_HSAVE_PA:
3024 env->vm_hsave = val;
3025 break;
3026 #ifdef TARGET_X86_64
3027 case MSR_LSTAR:
3028 env->lstar = val;
3029 break;
3030 case MSR_CSTAR:
3031 env->cstar = val;
3032 break;
3033 case MSR_FMASK:
3034 env->fmask = val;
3035 break;
3036 case MSR_FSBASE:
3037 env->segs[R_FS].base = val;
3038 break;
3039 case MSR_GSBASE:
3040 env->segs[R_GS].base = val;
3041 break;
3042 case MSR_KERNELGSBASE:
3043 env->kernelgsbase = val;
3044 break;
3045 #endif
3046 default:
3047 /* XXX: exception ? */
3048 break;
3052 void helper_rdmsr(void)
3054 uint64_t val;
3056 helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3058 switch((uint32_t)ECX) {
3059 case MSR_IA32_SYSENTER_CS:
3060 val = env->sysenter_cs;
3061 break;
3062 case MSR_IA32_SYSENTER_ESP:
3063 val = env->sysenter_esp;
3064 break;
3065 case MSR_IA32_SYSENTER_EIP:
3066 val = env->sysenter_eip;
3067 break;
3068 case MSR_IA32_APICBASE:
3069 val = cpu_get_apic_base(env);
3070 break;
3071 case MSR_EFER:
3072 val = env->efer;
3073 break;
3074 case MSR_STAR:
3075 val = env->star;
3076 break;
3077 case MSR_PAT:
3078 val = env->pat;
3079 break;
3080 case MSR_VM_HSAVE_PA:
3081 val = env->vm_hsave;
3082 break;
3083 case MSR_IA32_PERF_STATUS:
3084 /* tsc_increment_by_tick */
3085 val = 1000ULL;
3086 /* CPU multiplier */
3087 val |= (((uint64_t)4ULL) << 40);
3088 break;
3089 #ifdef TARGET_X86_64
3090 case MSR_LSTAR:
3091 val = env->lstar;
3092 break;
3093 case MSR_CSTAR:
3094 val = env->cstar;
3095 break;
3096 case MSR_FMASK:
3097 val = env->fmask;
3098 break;
3099 case MSR_FSBASE:
3100 val = env->segs[R_FS].base;
3101 break;
3102 case MSR_GSBASE:
3103 val = env->segs[R_GS].base;
3104 break;
3105 case MSR_KERNELGSBASE:
3106 val = env->kernelgsbase;
3107 break;
3108 #endif
3109 #ifdef USE_KQEMU
3110 case MSR_QPI_COMMBASE:
3111 if (env->kqemu_enabled) {
3112 val = kqemu_comm_base;
3113 } else {
3114 val = 0;
3116 break;
3117 #endif
3118 default:
3119 /* XXX: exception ? */
3120 val = 0;
3121 break;
3123 EAX = (uint32_t)(val);
3124 EDX = (uint32_t)(val >> 32);
3126 #endif
3128 target_ulong helper_lsl(target_ulong selector1)
3130 unsigned int limit;
3131 uint32_t e1, e2, eflags, selector;
3132 int rpl, dpl, cpl, type;
3134 selector = selector1 & 0xffff;
3135 eflags = helper_cc_compute_all(CC_OP);
3136 if (load_segment(&e1, &e2, selector) != 0)
3137 goto fail;
3138 rpl = selector & 3;
3139 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3140 cpl = env->hflags & HF_CPL_MASK;
3141 if (e2 & DESC_S_MASK) {
3142 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3143 /* conforming */
3144 } else {
3145 if (dpl < cpl || dpl < rpl)
3146 goto fail;
3148 } else {
3149 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3150 switch(type) {
3151 case 1:
3152 case 2:
3153 case 3:
3154 case 9:
3155 case 11:
3156 break;
3157 default:
3158 goto fail;
3160 if (dpl < cpl || dpl < rpl) {
3161 fail:
3162 CC_SRC = eflags & ~CC_Z;
3163 return 0;
3166 limit = get_seg_limit(e1, e2);
3167 CC_SRC = eflags | CC_Z;
3168 return limit;
3171 target_ulong helper_lar(target_ulong selector1)
3173 uint32_t e1, e2, eflags, selector;
3174 int rpl, dpl, cpl, type;
3176 selector = selector1 & 0xffff;
3177 eflags = helper_cc_compute_all(CC_OP);
3178 if ((selector & 0xfffc) == 0)
3179 goto fail;
3180 if (load_segment(&e1, &e2, selector) != 0)
3181 goto fail;
3182 rpl = selector & 3;
3183 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3184 cpl = env->hflags & HF_CPL_MASK;
3185 if (e2 & DESC_S_MASK) {
3186 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3187 /* conforming */
3188 } else {
3189 if (dpl < cpl || dpl < rpl)
3190 goto fail;
3192 } else {
3193 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3194 switch(type) {
3195 case 1:
3196 case 2:
3197 case 3:
3198 case 4:
3199 case 5:
3200 case 9:
3201 case 11:
3202 case 12:
3203 break;
3204 default:
3205 goto fail;
3207 if (dpl < cpl || dpl < rpl) {
3208 fail:
3209 CC_SRC = eflags & ~CC_Z;
3210 return 0;
3213 CC_SRC = eflags | CC_Z;
3214 return e2 & 0x00f0ff00;
3217 void helper_verr(target_ulong selector1)
3219 uint32_t e1, e2, eflags, selector;
3220 int rpl, dpl, cpl;
3222 selector = selector1 & 0xffff;
3223 eflags = helper_cc_compute_all(CC_OP);
3224 if ((selector & 0xfffc) == 0)
3225 goto fail;
3226 if (load_segment(&e1, &e2, selector) != 0)
3227 goto fail;
3228 if (!(e2 & DESC_S_MASK))
3229 goto fail;
3230 rpl = selector & 3;
3231 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3232 cpl = env->hflags & HF_CPL_MASK;
3233 if (e2 & DESC_CS_MASK) {
3234 if (!(e2 & DESC_R_MASK))
3235 goto fail;
3236 if (!(e2 & DESC_C_MASK)) {
3237 if (dpl < cpl || dpl < rpl)
3238 goto fail;
3240 } else {
3241 if (dpl < cpl || dpl < rpl) {
3242 fail:
3243 CC_SRC = eflags & ~CC_Z;
3244 return;
3247 CC_SRC = eflags | CC_Z;
3250 void helper_verw(target_ulong selector1)
3252 uint32_t e1, e2, eflags, selector;
3253 int rpl, dpl, cpl;
3255 selector = selector1 & 0xffff;
3256 eflags = helper_cc_compute_all(CC_OP);
3257 if ((selector & 0xfffc) == 0)
3258 goto fail;
3259 if (load_segment(&e1, &e2, selector) != 0)
3260 goto fail;
3261 if (!(e2 & DESC_S_MASK))
3262 goto fail;
3263 rpl = selector & 3;
3264 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3265 cpl = env->hflags & HF_CPL_MASK;
3266 if (e2 & DESC_CS_MASK) {
3267 goto fail;
3268 } else {
3269 if (dpl < cpl || dpl < rpl)
3270 goto fail;
3271 if (!(e2 & DESC_W_MASK)) {
3272 fail:
3273 CC_SRC = eflags & ~CC_Z;
3274 return;
3277 CC_SRC = eflags | CC_Z;
3280 /* x87 FPU helpers */
3282 static void fpu_set_exception(int mask)
3284 env->fpus |= mask;
3285 if (env->fpus & (~env->fpuc & FPUC_EM))
3286 env->fpus |= FPUS_SE | FPUS_B;
3289 static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3291 if (b == 0.0)
3292 fpu_set_exception(FPUS_ZE);
3293 return a / b;
3296 void fpu_raise_exception(void)
3298 if (env->cr[0] & CR0_NE_MASK) {
3299 raise_exception(EXCP10_COPR);
3301 #if !defined(CONFIG_USER_ONLY)
3302 else {
3303 cpu_set_ferr(env);
3305 #endif
3308 void helper_flds_FT0(uint32_t val)
3310 union {
3311 float32 f;
3312 uint32_t i;
3313 } u;
3314 u.i = val;
3315 FT0 = float32_to_floatx(u.f, &env->fp_status);
3318 void helper_fldl_FT0(uint64_t val)
3320 union {
3321 float64 f;
3322 uint64_t i;
3323 } u;
3324 u.i = val;
3325 FT0 = float64_to_floatx(u.f, &env->fp_status);
3328 void helper_fildl_FT0(int32_t val)
3330 FT0 = int32_to_floatx(val, &env->fp_status);
3333 void helper_flds_ST0(uint32_t val)
3335 int new_fpstt;
3336 union {
3337 float32 f;
3338 uint32_t i;
3339 } u;
3340 new_fpstt = (env->fpstt - 1) & 7;
3341 u.i = val;
3342 env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
3343 env->fpstt = new_fpstt;
3344 env->fptags[new_fpstt] = 0; /* validate stack entry */
3347 void helper_fldl_ST0(uint64_t val)
3349 int new_fpstt;
3350 union {
3351 float64 f;
3352 uint64_t i;
3353 } u;
3354 new_fpstt = (env->fpstt - 1) & 7;
3355 u.i = val;
3356 env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
3357 env->fpstt = new_fpstt;
3358 env->fptags[new_fpstt] = 0; /* validate stack entry */
3361 void helper_fildl_ST0(int32_t val)
3363 int new_fpstt;
3364 new_fpstt = (env->fpstt - 1) & 7;
3365 env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
3366 env->fpstt = new_fpstt;
3367 env->fptags[new_fpstt] = 0; /* validate stack entry */
3370 void helper_fildll_ST0(int64_t val)
3372 int new_fpstt;
3373 new_fpstt = (env->fpstt - 1) & 7;
3374 env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
3375 env->fpstt = new_fpstt;
3376 env->fptags[new_fpstt] = 0; /* validate stack entry */
3379 uint32_t helper_fsts_ST0(void)
3381 union {
3382 float32 f;
3383 uint32_t i;
3384 } u;
3385 u.f = floatx_to_float32(ST0, &env->fp_status);
3386 return u.i;
3389 uint64_t helper_fstl_ST0(void)
3391 union {
3392 float64 f;
3393 uint64_t i;
3394 } u;
3395 u.f = floatx_to_float64(ST0, &env->fp_status);
3396 return u.i;
3399 int32_t helper_fist_ST0(void)
3401 int32_t val;
3402 val = floatx_to_int32(ST0, &env->fp_status);
3403 if (val != (int16_t)val)
3404 val = -32768;
3405 return val;
3408 int32_t helper_fistl_ST0(void)
3410 int32_t val;
3411 val = floatx_to_int32(ST0, &env->fp_status);
3412 return val;
3415 int64_t helper_fistll_ST0(void)
3417 int64_t val;
3418 val = floatx_to_int64(ST0, &env->fp_status);
3419 return val;
3422 int32_t helper_fistt_ST0(void)
3424 int32_t val;
3425 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3426 if (val != (int16_t)val)
3427 val = -32768;
3428 return val;
3431 int32_t helper_fisttl_ST0(void)
3433 int32_t val;
3434 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3435 return val;
3438 int64_t helper_fisttll_ST0(void)
3440 int64_t val;
3441 val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
3442 return val;
3445 void helper_fldt_ST0(target_ulong ptr)
3447 int new_fpstt;
3448 new_fpstt = (env->fpstt - 1) & 7;
3449 env->fpregs[new_fpstt].d = helper_fldt(ptr);
3450 env->fpstt = new_fpstt;
3451 env->fptags[new_fpstt] = 0; /* validate stack entry */
3454 void helper_fstt_ST0(target_ulong ptr)
3456 helper_fstt(ST0, ptr);
3459 void helper_fpush(void)
3461 fpush();
3464 void helper_fpop(void)
3466 fpop();
3469 void helper_fdecstp(void)
3471 env->fpstt = (env->fpstt - 1) & 7;
3472 env->fpus &= (~0x4700);
3475 void helper_fincstp(void)
3477 env->fpstt = (env->fpstt + 1) & 7;
3478 env->fpus &= (~0x4700);
3481 /* FPU move */
3483 void helper_ffree_STN(int st_index)
3485 env->fptags[(env->fpstt + st_index) & 7] = 1;
3488 void helper_fmov_ST0_FT0(void)
3490 ST0 = FT0;
3493 void helper_fmov_FT0_STN(int st_index)
3495 FT0 = ST(st_index);
3498 void helper_fmov_ST0_STN(int st_index)
3500 ST0 = ST(st_index);
3503 void helper_fmov_STN_ST0(int st_index)
3505 ST(st_index) = ST0;
3508 void helper_fxchg_ST0_STN(int st_index)
3510 CPU86_LDouble tmp;
3511 tmp = ST(st_index);
3512 ST(st_index) = ST0;
3513 ST0 = tmp;
3516 /* FPU operations */
3518 static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
3520 void helper_fcom_ST0_FT0(void)
3522 int ret;
3524 ret = floatx_compare(ST0, FT0, &env->fp_status);
3525 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
3526 FORCE_RET();
3529 void helper_fucom_ST0_FT0(void)
3531 int ret;
3533 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3534 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
3535 FORCE_RET();
3538 static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
3540 void helper_fcomi_ST0_FT0(void)
3542 int eflags;
3543 int ret;
3545 ret = floatx_compare(ST0, FT0, &env->fp_status);
3546 eflags = helper_cc_compute_all(CC_OP);
3547 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3548 CC_SRC = eflags;
3549 FORCE_RET();
3552 void helper_fucomi_ST0_FT0(void)
3554 int eflags;
3555 int ret;
3557 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3558 eflags = helper_cc_compute_all(CC_OP);
3559 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3560 CC_SRC = eflags;
3561 FORCE_RET();
3564 void helper_fadd_ST0_FT0(void)
3566 ST0 += FT0;
3569 void helper_fmul_ST0_FT0(void)
3571 ST0 *= FT0;
3574 void helper_fsub_ST0_FT0(void)
3576 ST0 -= FT0;
3579 void helper_fsubr_ST0_FT0(void)
3581 ST0 = FT0 - ST0;
3584 void helper_fdiv_ST0_FT0(void)
3586 ST0 = helper_fdiv(ST0, FT0);
3589 void helper_fdivr_ST0_FT0(void)
3591 ST0 = helper_fdiv(FT0, ST0);
3594 /* fp operations between STN and ST0 */
3596 void helper_fadd_STN_ST0(int st_index)
3598 ST(st_index) += ST0;
3601 void helper_fmul_STN_ST0(int st_index)
3603 ST(st_index) *= ST0;
3606 void helper_fsub_STN_ST0(int st_index)
3608 ST(st_index) -= ST0;
3611 void helper_fsubr_STN_ST0(int st_index)
3613 CPU86_LDouble *p;
3614 p = &ST(st_index);
3615 *p = ST0 - *p;
3618 void helper_fdiv_STN_ST0(int st_index)
3620 CPU86_LDouble *p;
3621 p = &ST(st_index);
3622 *p = helper_fdiv(*p, ST0);
3625 void helper_fdivr_STN_ST0(int st_index)
3627 CPU86_LDouble *p;
3628 p = &ST(st_index);
3629 *p = helper_fdiv(ST0, *p);
3632 /* misc FPU operations */
3633 void helper_fchs_ST0(void)
3635 ST0 = floatx_chs(ST0);
3638 void helper_fabs_ST0(void)
3640 ST0 = floatx_abs(ST0);
3643 void helper_fld1_ST0(void)
3645 ST0 = f15rk[1];
3648 void helper_fldl2t_ST0(void)
3650 ST0 = f15rk[6];
3653 void helper_fldl2e_ST0(void)
3655 ST0 = f15rk[5];
3658 void helper_fldpi_ST0(void)
3660 ST0 = f15rk[2];
3663 void helper_fldlg2_ST0(void)
3665 ST0 = f15rk[3];
3668 void helper_fldln2_ST0(void)
3670 ST0 = f15rk[4];
3673 void helper_fldz_ST0(void)
3675 ST0 = f15rk[0];
3678 void helper_fldz_FT0(void)
3680 FT0 = f15rk[0];
3683 uint32_t helper_fnstsw(void)
3685 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3688 uint32_t helper_fnstcw(void)
3690 return env->fpuc;
3693 static void update_fp_status(void)
3695 int rnd_type;
3697 /* set rounding mode */
3698 switch(env->fpuc & RC_MASK) {
3699 default:
3700 case RC_NEAR:
3701 rnd_type = float_round_nearest_even;
3702 break;
3703 case RC_DOWN:
3704 rnd_type = float_round_down;
3705 break;
3706 case RC_UP:
3707 rnd_type = float_round_up;
3708 break;
3709 case RC_CHOP:
3710 rnd_type = float_round_to_zero;
3711 break;
3713 set_float_rounding_mode(rnd_type, &env->fp_status);
3714 #ifdef FLOATX80
3715 switch((env->fpuc >> 8) & 3) {
3716 case 0:
3717 rnd_type = 32;
3718 break;
3719 case 2:
3720 rnd_type = 64;
3721 break;
3722 case 3:
3723 default:
3724 rnd_type = 80;
3725 break;
3727 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3728 #endif
3731 void helper_fldcw(uint32_t val)
3733 env->fpuc = val;
3734 update_fp_status();
3737 void helper_fclex(void)
3739 env->fpus &= 0x7f00;
3742 void helper_fwait(void)
3744 if (env->fpus & FPUS_SE)
3745 fpu_raise_exception();
3746 FORCE_RET();
3749 void helper_fninit(void)
3751 env->fpus = 0;
3752 env->fpstt = 0;
3753 env->fpuc = 0x37f;
3754 env->fptags[0] = 1;
3755 env->fptags[1] = 1;
3756 env->fptags[2] = 1;
3757 env->fptags[3] = 1;
3758 env->fptags[4] = 1;
3759 env->fptags[5] = 1;
3760 env->fptags[6] = 1;
3761 env->fptags[7] = 1;
3764 /* BCD ops */
3766 void helper_fbld_ST0(target_ulong ptr)
3768 CPU86_LDouble tmp;
3769 uint64_t val;
3770 unsigned int v;
3771 int i;
3773 val = 0;
3774 for(i = 8; i >= 0; i--) {
3775 v = ldub(ptr + i);
3776 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3778 tmp = val;
3779 if (ldub(ptr + 9) & 0x80)
3780 tmp = -tmp;
3781 fpush();
3782 ST0 = tmp;
3785 void helper_fbst_ST0(target_ulong ptr)
3787 int v;
3788 target_ulong mem_ref, mem_end;
3789 int64_t val;
3791 val = floatx_to_int64(ST0, &env->fp_status);
3792 mem_ref = ptr;
3793 mem_end = mem_ref + 9;
3794 if (val < 0) {
3795 stb(mem_end, 0x80);
3796 val = -val;
3797 } else {
3798 stb(mem_end, 0x00);
3800 while (mem_ref < mem_end) {
3801 if (val == 0)
3802 break;
3803 v = val % 100;
3804 val = val / 100;
3805 v = ((v / 10) << 4) | (v % 10);
3806 stb(mem_ref++, v);
3808 while (mem_ref < mem_end) {
3809 stb(mem_ref++, 0);
3813 void helper_f2xm1(void)
3815 ST0 = pow(2.0,ST0) - 1.0;
3818 void helper_fyl2x(void)
3820 CPU86_LDouble fptemp;
3822 fptemp = ST0;
3823 if (fptemp>0.0){
3824 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
3825 ST1 *= fptemp;
3826 fpop();
3827 } else {
3828 env->fpus &= (~0x4700);
3829 env->fpus |= 0x400;
3833 void helper_fptan(void)
3835 CPU86_LDouble fptemp;
3837 fptemp = ST0;
3838 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3839 env->fpus |= 0x400;
3840 } else {
3841 ST0 = tan(fptemp);
3842 fpush();
3843 ST0 = 1.0;
3844 env->fpus &= (~0x400); /* C2 <-- 0 */
3845 /* the above code is for |arg| < 2**52 only */
3849 void helper_fpatan(void)
3851 CPU86_LDouble fptemp, fpsrcop;
3853 fpsrcop = ST1;
3854 fptemp = ST0;
3855 ST1 = atan2(fpsrcop,fptemp);
3856 fpop();
3859 void helper_fxtract(void)
3861 CPU86_LDoubleU temp;
3862 unsigned int expdif;
3864 temp.d = ST0;
3865 expdif = EXPD(temp) - EXPBIAS;
3866 /*DP exponent bias*/
3867 ST0 = expdif;
3868 fpush();
3869 BIASEXPONENT(temp);
3870 ST0 = temp.d;
3873 void helper_fprem1(void)
3875 CPU86_LDouble dblq, fpsrcop, fptemp;
3876 CPU86_LDoubleU fpsrcop1, fptemp1;
3877 int expdif;
3878 signed long long int q;
3880 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3881 ST0 = 0.0 / 0.0; /* NaN */
3882 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3883 return;
3886 fpsrcop = ST0;
3887 fptemp = ST1;
3888 fpsrcop1.d = fpsrcop;
3889 fptemp1.d = fptemp;
3890 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3892 if (expdif < 0) {
3893 /* optimisation? taken from the AMD docs */
3894 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3895 /* ST0 is unchanged */
3896 return;
3899 if (expdif < 53) {
3900 dblq = fpsrcop / fptemp;
3901 /* round dblq towards nearest integer */
3902 dblq = rint(dblq);
3903 ST0 = fpsrcop - fptemp * dblq;
3905 /* convert dblq to q by truncating towards zero */
3906 if (dblq < 0.0)
3907 q = (signed long long int)(-dblq);
3908 else
3909 q = (signed long long int)dblq;
3911 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3912 /* (C0,C3,C1) <-- (q2,q1,q0) */
3913 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3914 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3915 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
3916 } else {
3917 env->fpus |= 0x400; /* C2 <-- 1 */
3918 fptemp = pow(2.0, expdif - 50);
3919 fpsrcop = (ST0 / ST1) / fptemp;
3920 /* fpsrcop = integer obtained by chopping */
3921 fpsrcop = (fpsrcop < 0.0) ?
3922 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3923 ST0 -= (ST1 * fpsrcop * fptemp);
3927 void helper_fprem(void)
3929 CPU86_LDouble dblq, fpsrcop, fptemp;
3930 CPU86_LDoubleU fpsrcop1, fptemp1;
3931 int expdif;
3932 signed long long int q;
3934 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3935 ST0 = 0.0 / 0.0; /* NaN */
3936 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3937 return;
3940 fpsrcop = (CPU86_LDouble)ST0;
3941 fptemp = (CPU86_LDouble)ST1;
3942 fpsrcop1.d = fpsrcop;
3943 fptemp1.d = fptemp;
3944 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3946 if (expdif < 0) {
3947 /* optimisation? taken from the AMD docs */
3948 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3949 /* ST0 is unchanged */
3950 return;
3953 if ( expdif < 53 ) {
3954 dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
3955 /* round dblq towards zero */
3956 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
3957 ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
3959 /* convert dblq to q by truncating towards zero */
3960 if (dblq < 0.0)
3961 q = (signed long long int)(-dblq);
3962 else
3963 q = (signed long long int)dblq;
3965 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3966 /* (C0,C3,C1) <-- (q2,q1,q0) */
3967 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3968 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3969 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
3970 } else {
3971 int N = 32 + (expdif % 32); /* as per AMD docs */
3972 env->fpus |= 0x400; /* C2 <-- 1 */
3973 fptemp = pow(2.0, (double)(expdif - N));
3974 fpsrcop = (ST0 / ST1) / fptemp;
3975 /* fpsrcop = integer obtained by chopping */
3976 fpsrcop = (fpsrcop < 0.0) ?
3977 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3978 ST0 -= (ST1 * fpsrcop * fptemp);
3982 void helper_fyl2xp1(void)
3984 CPU86_LDouble fptemp;
3986 fptemp = ST0;
3987 if ((fptemp+1.0)>0.0) {
3988 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
3989 ST1 *= fptemp;
3990 fpop();
3991 } else {
3992 env->fpus &= (~0x4700);
3993 env->fpus |= 0x400;
3997 void helper_fsqrt(void)
3999 CPU86_LDouble fptemp;
4001 fptemp = ST0;
4002 if (fptemp<0.0) {
4003 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4004 env->fpus |= 0x400;
4006 ST0 = sqrt(fptemp);
4009 void helper_fsincos(void)
4011 CPU86_LDouble fptemp;
4013 fptemp = ST0;
4014 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4015 env->fpus |= 0x400;
4016 } else {
4017 ST0 = sin(fptemp);
4018 fpush();
4019 ST0 = cos(fptemp);
4020 env->fpus &= (~0x400); /* C2 <-- 0 */
4021 /* the above code is for |arg| < 2**63 only */
4025 void helper_frndint(void)
4027 ST0 = floatx_round_to_int(ST0, &env->fp_status);
4030 void helper_fscale(void)
4032 ST0 = ldexp (ST0, (int)(ST1));
4035 void helper_fsin(void)
4037 CPU86_LDouble fptemp;
4039 fptemp = ST0;
4040 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4041 env->fpus |= 0x400;
4042 } else {
4043 ST0 = sin(fptemp);
4044 env->fpus &= (~0x400); /* C2 <-- 0 */
4045 /* the above code is for |arg| < 2**53 only */
4049 void helper_fcos(void)
4051 CPU86_LDouble fptemp;
4053 fptemp = ST0;
4054 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4055 env->fpus |= 0x400;
4056 } else {
4057 ST0 = cos(fptemp);
4058 env->fpus &= (~0x400); /* C2 <-- 0 */
4059 /* the above code is for |arg5 < 2**63 only */
4063 void helper_fxam_ST0(void)
4065 CPU86_LDoubleU temp;
4066 int expdif;
4068 temp.d = ST0;
4070 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4071 if (SIGND(temp))
4072 env->fpus |= 0x200; /* C1 <-- 1 */
4074 /* XXX: test fptags too */
4075 expdif = EXPD(temp);
4076 if (expdif == MAXEXPD) {
4077 #ifdef USE_X86LDOUBLE
4078 if (MANTD(temp) == 0x8000000000000000ULL)
4079 #else
4080 if (MANTD(temp) == 0)
4081 #endif
4082 env->fpus |= 0x500 /*Infinity*/;
4083 else
4084 env->fpus |= 0x100 /*NaN*/;
4085 } else if (expdif == 0) {
4086 if (MANTD(temp) == 0)
4087 env->fpus |= 0x4000 /*Zero*/;
4088 else
4089 env->fpus |= 0x4400 /*Denormal*/;
4090 } else {
4091 env->fpus |= 0x400;
4095 void helper_fstenv(target_ulong ptr, int data32)
4097 int fpus, fptag, exp, i;
4098 uint64_t mant;
4099 CPU86_LDoubleU tmp;
4101 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4102 fptag = 0;
4103 for (i=7; i>=0; i--) {
4104 fptag <<= 2;
4105 if (env->fptags[i]) {
4106 fptag |= 3;
4107 } else {
4108 tmp.d = env->fpregs[i].d;
4109 exp = EXPD(tmp);
4110 mant = MANTD(tmp);
4111 if (exp == 0 && mant == 0) {
4112 /* zero */
4113 fptag |= 1;
4114 } else if (exp == 0 || exp == MAXEXPD
4115 #ifdef USE_X86LDOUBLE
4116 || (mant & (1LL << 63)) == 0
4117 #endif
4119 /* NaNs, infinity, denormal */
4120 fptag |= 2;
4124 if (data32) {
4125 /* 32 bit */
4126 stl(ptr, env->fpuc);
4127 stl(ptr + 4, fpus);
4128 stl(ptr + 8, fptag);
4129 stl(ptr + 12, 0); /* fpip */
4130 stl(ptr + 16, 0); /* fpcs */
4131 stl(ptr + 20, 0); /* fpoo */
4132 stl(ptr + 24, 0); /* fpos */
4133 } else {
4134 /* 16 bit */
4135 stw(ptr, env->fpuc);
4136 stw(ptr + 2, fpus);
4137 stw(ptr + 4, fptag);
4138 stw(ptr + 6, 0);
4139 stw(ptr + 8, 0);
4140 stw(ptr + 10, 0);
4141 stw(ptr + 12, 0);
4145 void helper_fldenv(target_ulong ptr, int data32)
4147 int i, fpus, fptag;
4149 if (data32) {
4150 env->fpuc = lduw(ptr);
4151 fpus = lduw(ptr + 4);
4152 fptag = lduw(ptr + 8);
4154 else {
4155 env->fpuc = lduw(ptr);
4156 fpus = lduw(ptr + 2);
4157 fptag = lduw(ptr + 4);
4159 env->fpstt = (fpus >> 11) & 7;
4160 env->fpus = fpus & ~0x3800;
4161 for(i = 0;i < 8; i++) {
4162 env->fptags[i] = ((fptag & 3) == 3);
4163 fptag >>= 2;
4167 void helper_fsave(target_ulong ptr, int data32)
4169 CPU86_LDouble tmp;
4170 int i;
4172 helper_fstenv(ptr, data32);
4174 ptr += (14 << data32);
4175 for(i = 0;i < 8; i++) {
4176 tmp = ST(i);
4177 helper_fstt(tmp, ptr);
4178 ptr += 10;
4181 /* fninit */
4182 env->fpus = 0;
4183 env->fpstt = 0;
4184 env->fpuc = 0x37f;
4185 env->fptags[0] = 1;
4186 env->fptags[1] = 1;
4187 env->fptags[2] = 1;
4188 env->fptags[3] = 1;
4189 env->fptags[4] = 1;
4190 env->fptags[5] = 1;
4191 env->fptags[6] = 1;
4192 env->fptags[7] = 1;
4195 void helper_frstor(target_ulong ptr, int data32)
4197 CPU86_LDouble tmp;
4198 int i;
4200 helper_fldenv(ptr, data32);
4201 ptr += (14 << data32);
4203 for(i = 0;i < 8; i++) {
4204 tmp = helper_fldt(ptr);
4205 ST(i) = tmp;
4206 ptr += 10;
4210 void helper_fxsave(target_ulong ptr, int data64)
4212 int fpus, fptag, i, nb_xmm_regs;
4213 CPU86_LDouble tmp;
4214 target_ulong addr;
4216 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4217 fptag = 0;
4218 for(i = 0; i < 8; i++) {
4219 fptag |= (env->fptags[i] << i);
4221 stw(ptr, env->fpuc);
4222 stw(ptr + 2, fpus);
4223 stw(ptr + 4, fptag ^ 0xff);
4224 #ifdef TARGET_X86_64
4225 if (data64) {
4226 stq(ptr + 0x08, 0); /* rip */
4227 stq(ptr + 0x10, 0); /* rdp */
4228 } else
4229 #endif
4231 stl(ptr + 0x08, 0); /* eip */
4232 stl(ptr + 0x0c, 0); /* sel */
4233 stl(ptr + 0x10, 0); /* dp */
4234 stl(ptr + 0x14, 0); /* sel */
4237 addr = ptr + 0x20;
4238 for(i = 0;i < 8; i++) {
4239 tmp = ST(i);
4240 helper_fstt(tmp, addr);
4241 addr += 16;
4244 if (env->cr[4] & CR4_OSFXSR_MASK) {
4245 /* XXX: finish it */
4246 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4247 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4248 if (env->hflags & HF_CS64_MASK)
4249 nb_xmm_regs = 16;
4250 else
4251 nb_xmm_regs = 8;
4252 addr = ptr + 0xa0;
4253 for(i = 0; i < nb_xmm_regs; i++) {
4254 stq(addr, env->xmm_regs[i].XMM_Q(0));
4255 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4256 addr += 16;
4261 void helper_fxrstor(target_ulong ptr, int data64)
4263 int i, fpus, fptag, nb_xmm_regs;
4264 CPU86_LDouble tmp;
4265 target_ulong addr;
4267 env->fpuc = lduw(ptr);
4268 fpus = lduw(ptr + 2);
4269 fptag = lduw(ptr + 4);
4270 env->fpstt = (fpus >> 11) & 7;
4271 env->fpus = fpus & ~0x3800;
4272 fptag ^= 0xff;
4273 for(i = 0;i < 8; i++) {
4274 env->fptags[i] = ((fptag >> i) & 1);
4277 addr = ptr + 0x20;
4278 for(i = 0;i < 8; i++) {
4279 tmp = helper_fldt(addr);
4280 ST(i) = tmp;
4281 addr += 16;
4284 if (env->cr[4] & CR4_OSFXSR_MASK) {
4285 /* XXX: finish it */
4286 env->mxcsr = ldl(ptr + 0x18);
4287 //ldl(ptr + 0x1c);
4288 if (env->hflags & HF_CS64_MASK)
4289 nb_xmm_regs = 16;
4290 else
4291 nb_xmm_regs = 8;
4292 addr = ptr + 0xa0;
4293 for(i = 0; i < nb_xmm_regs; i++) {
4294 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4295 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4296 addr += 16;
4301 #ifndef USE_X86LDOUBLE
4303 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4305 CPU86_LDoubleU temp;
4306 int e;
4308 temp.d = f;
4309 /* mantissa */
4310 *pmant = (MANTD(temp) << 11) | (1LL << 63);
4311 /* exponent + sign */
4312 e = EXPD(temp) - EXPBIAS + 16383;
4313 e |= SIGND(temp) >> 16;
4314 *pexp = e;
4317 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4319 CPU86_LDoubleU temp;
4320 int e;
4321 uint64_t ll;
4323 /* XXX: handle overflow ? */
4324 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
4325 e |= (upper >> 4) & 0x800; /* sign */
4326 ll = (mant >> 11) & ((1LL << 52) - 1);
4327 #ifdef __arm__
4328 temp.l.upper = (e << 20) | (ll >> 32);
4329 temp.l.lower = ll;
4330 #else
4331 temp.ll = ll | ((uint64_t)e << 52);
4332 #endif
4333 return temp.d;
4336 #else
4338 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4340 CPU86_LDoubleU temp;
4342 temp.d = f;
4343 *pmant = temp.l.lower;
4344 *pexp = temp.l.upper;
4347 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4349 CPU86_LDoubleU temp;
4351 temp.l.upper = upper;
4352 temp.l.lower = mant;
4353 return temp.d;
4355 #endif
4357 #ifdef TARGET_X86_64
4359 //#define DEBUG_MULDIV
4361 static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4363 *plow += a;
4364 /* carry test */
4365 if (*plow < a)
4366 (*phigh)++;
4367 *phigh += b;
4370 static void neg128(uint64_t *plow, uint64_t *phigh)
4372 *plow = ~ *plow;
4373 *phigh = ~ *phigh;
4374 add128(plow, phigh, 1, 0);
4377 /* return TRUE if overflow */
4378 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4380 uint64_t q, r, a1, a0;
4381 int i, qb, ab;
4383 a0 = *plow;
4384 a1 = *phigh;
4385 if (a1 == 0) {
4386 q = a0 / b;
4387 r = a0 % b;
4388 *plow = q;
4389 *phigh = r;
4390 } else {
4391 if (a1 >= b)
4392 return 1;
4393 /* XXX: use a better algorithm */
4394 for(i = 0; i < 64; i++) {
4395 ab = a1 >> 63;
4396 a1 = (a1 << 1) | (a0 >> 63);
4397 if (ab || a1 >= b) {
4398 a1 -= b;
4399 qb = 1;
4400 } else {
4401 qb = 0;
4403 a0 = (a0 << 1) | qb;
4405 #if defined(DEBUG_MULDIV)
4406 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
4407 *phigh, *plow, b, a0, a1);
4408 #endif
4409 *plow = a0;
4410 *phigh = a1;
4412 return 0;
4415 /* return TRUE if overflow */
4416 static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
4418 int sa, sb;
4419 sa = ((int64_t)*phigh < 0);
4420 if (sa)
4421 neg128(plow, phigh);
4422 sb = (b < 0);
4423 if (sb)
4424 b = -b;
4425 if (div64(plow, phigh, b) != 0)
4426 return 1;
4427 if (sa ^ sb) {
4428 if (*plow > (1ULL << 63))
4429 return 1;
4430 *plow = - *plow;
4431 } else {
4432 if (*plow >= (1ULL << 63))
4433 return 1;
4435 if (sa)
4436 *phigh = - *phigh;
4437 return 0;
4440 void helper_mulq_EAX_T0(target_ulong t0)
4442 uint64_t r0, r1;
4444 mulu64(&r0, &r1, EAX, t0);
4445 EAX = r0;
4446 EDX = r1;
4447 CC_DST = r0;
4448 CC_SRC = r1;
4451 void helper_imulq_EAX_T0(target_ulong t0)
4453 uint64_t r0, r1;
4455 muls64(&r0, &r1, EAX, t0);
4456 EAX = r0;
4457 EDX = r1;
4458 CC_DST = r0;
4459 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4462 target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
4464 uint64_t r0, r1;
4466 muls64(&r0, &r1, t0, t1);
4467 CC_DST = r0;
4468 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4469 return r0;
4472 void helper_divq_EAX(target_ulong t0)
4474 uint64_t r0, r1;
4475 if (t0 == 0) {
4476 raise_exception(EXCP00_DIVZ);
4478 r0 = EAX;
4479 r1 = EDX;
4480 if (div64(&r0, &r1, t0))
4481 raise_exception(EXCP00_DIVZ);
4482 EAX = r0;
4483 EDX = r1;
4486 void helper_idivq_EAX(target_ulong t0)
4488 uint64_t r0, r1;
4489 if (t0 == 0) {
4490 raise_exception(EXCP00_DIVZ);
4492 r0 = EAX;
4493 r1 = EDX;
4494 if (idiv64(&r0, &r1, t0))
4495 raise_exception(EXCP00_DIVZ);
4496 EAX = r0;
4497 EDX = r1;
4499 #endif
4501 static void do_hlt(void)
4503 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
4504 env->halted = 1;
4505 env->exception_index = EXCP_HLT;
4506 cpu_loop_exit();
4509 void helper_hlt(int next_eip_addend)
4511 helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
4512 EIP += next_eip_addend;
4514 do_hlt();
4517 void helper_monitor(target_ulong ptr)
4519 if ((uint32_t)ECX != 0)
4520 raise_exception(EXCP0D_GPF);
4521 /* XXX: store address ? */
4522 helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
4525 void helper_mwait(int next_eip_addend)
4527 if ((uint32_t)ECX != 0)
4528 raise_exception(EXCP0D_GPF);
4529 helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
4530 EIP += next_eip_addend;
4532 /* XXX: not complete but not completely erroneous */
4533 if (env->cpu_index != 0 || env->next_cpu != NULL) {
4534 /* more than one CPU: do not sleep because another CPU may
4535 wake this one */
4536 } else {
4537 do_hlt();
4541 void helper_debug(void)
4543 env->exception_index = EXCP_DEBUG;
4544 cpu_loop_exit();
4547 void helper_raise_interrupt(int intno, int next_eip_addend)
4549 raise_interrupt(intno, 1, 0, next_eip_addend);
4552 void helper_raise_exception(int exception_index)
4554 raise_exception(exception_index);
4557 void helper_cli(void)
4559 env->eflags &= ~IF_MASK;
4562 void helper_sti(void)
4564 env->eflags |= IF_MASK;
4567 #if 0
4568 /* vm86plus instructions */
4569 void helper_cli_vm(void)
4571 env->eflags &= ~VIF_MASK;
4574 void helper_sti_vm(void)
4576 env->eflags |= VIF_MASK;
4577 if (env->eflags & VIP_MASK) {
4578 raise_exception(EXCP0D_GPF);
4581 #endif
4583 void helper_set_inhibit_irq(void)
4585 env->hflags |= HF_INHIBIT_IRQ_MASK;
4588 void helper_reset_inhibit_irq(void)
4590 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4593 void helper_boundw(target_ulong a0, int v)
4595 int low, high;
4596 low = ldsw(a0);
4597 high = ldsw(a0 + 2);
4598 v = (int16_t)v;
4599 if (v < low || v > high) {
4600 raise_exception(EXCP05_BOUND);
4602 FORCE_RET();
4605 void helper_boundl(target_ulong a0, int v)
4607 int low, high;
4608 low = ldl(a0);
4609 high = ldl(a0 + 4);
4610 if (v < low || v > high) {
4611 raise_exception(EXCP05_BOUND);
4613 FORCE_RET();
4616 static float approx_rsqrt(float a)
4618 return 1.0 / sqrt(a);
4621 static float approx_rcp(float a)
4623 return 1.0 / a;
4626 #if !defined(CONFIG_USER_ONLY)
4628 #define MMUSUFFIX _mmu
4630 #define SHIFT 0
4631 #include "softmmu_template.h"
4633 #define SHIFT 1
4634 #include "softmmu_template.h"
4636 #define SHIFT 2
4637 #include "softmmu_template.h"
4639 #define SHIFT 3
4640 #include "softmmu_template.h"
4642 #endif
4644 /* try to fill the TLB and return an exception if error. If retaddr is
4645 NULL, it means that the function was called in C code (i.e. not
4646 from generated code or from helper.c) */
4647 /* XXX: fix it to restore all registers */
4648 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
4650 TranslationBlock *tb;
4651 int ret;
4652 unsigned long pc;
4653 CPUX86State *saved_env;
4655 /* XXX: hack to restore env in all cases, even if not called from
4656 generated code */
4657 saved_env = env;
4658 env = cpu_single_env;
4660 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
4661 if (ret) {
4662 if (retaddr) {
4663 /* now we have a real cpu fault */
4664 pc = (unsigned long)retaddr;
4665 tb = tb_find_pc(pc);
4666 if (tb) {
4667 /* the PC is inside the translated code. It means that we have
4668 a virtual CPU fault */
4669 cpu_restore_state(tb, env, pc, NULL);
4672 raise_exception_err(env->exception_index, env->error_code);
4674 env = saved_env;
4678 /* Secure Virtual Machine helpers */
4680 #if defined(CONFIG_USER_ONLY)
4682 void helper_vmrun(int aflag, int next_eip_addend)
4685 void helper_vmmcall(void)
4688 void helper_vmload(int aflag)
4691 void helper_vmsave(int aflag)
4694 void helper_stgi(void)
4697 void helper_clgi(void)
4700 void helper_skinit(void)
4703 void helper_invlpga(int aflag)
4706 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
4709 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
4713 void helper_svm_check_io(uint32_t port, uint32_t param,
4714 uint32_t next_eip_addend)
4717 #else
4719 static inline void svm_save_seg(target_phys_addr_t addr,
4720 const SegmentCache *sc)
4722 stw_phys(addr + offsetof(struct vmcb_seg, selector),
4723 sc->selector);
4724 stq_phys(addr + offsetof(struct vmcb_seg, base),
4725 sc->base);
4726 stl_phys(addr + offsetof(struct vmcb_seg, limit),
4727 sc->limit);
4728 stw_phys(addr + offsetof(struct vmcb_seg, attrib),
4729 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
4732 static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
4734 unsigned int flags;
4736 sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
4737 sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
4738 sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
4739 flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
4740 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
4743 static inline void svm_load_seg_cache(target_phys_addr_t addr,
4744 CPUState *env, int seg_reg)
4746 SegmentCache sc1, *sc = &sc1;
4747 svm_load_seg(addr, sc);
4748 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
4749 sc->base, sc->limit, sc->flags);
4752 void helper_vmrun(int aflag, int next_eip_addend)
4754 target_ulong addr;
4755 uint32_t event_inj;
4756 uint32_t int_ctl;
4758 helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
4760 if (aflag == 2)
4761 addr = EAX;
4762 else
4763 addr = (uint32_t)EAX;
4765 if (loglevel & CPU_LOG_TB_IN_ASM)
4766 fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
4768 env->vm_vmcb = addr;
4770 /* save the current CPU state in the hsave page */
4771 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4772 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4774 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4775 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4777 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
4778 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
4779 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
4780 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
4781 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
4782 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
4784 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
4785 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
4787 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
4788 &env->segs[R_ES]);
4789 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
4790 &env->segs[R_CS]);
4791 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
4792 &env->segs[R_SS]);
4793 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
4794 &env->segs[R_DS]);
4796 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
4797 EIP + next_eip_addend);
4798 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4799 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4801 /* load the interception bitmaps so we do not need to access the
4802 vmcb in svm mode */
4803 env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
4804 env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4805 env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4806 env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4807 env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4808 env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4810 /* enable intercepts */
4811 env->hflags |= HF_SVMI_MASK;
4813 env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
4815 env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4816 env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4818 env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4819 env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4821 /* clear exit_info_2 so we behave like the real hardware */
4822 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4824 cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4825 cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4826 cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4827 env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4828 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
4829 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
4830 if (int_ctl & V_INTR_MASKING_MASK) {
4831 env->v_tpr = int_ctl & V_TPR_MASK;
4832 env->hflags2 |= HF2_VINTR_MASK;
4833 if (env->eflags & IF_MASK)
4834 env->hflags2 |= HF2_HIF_MASK;
4837 cpu_load_efer(env,
4838 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
4839 env->eflags = 0;
4840 load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
4841 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4842 CC_OP = CC_OP_EFLAGS;
4844 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
4845 env, R_ES);
4846 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
4847 env, R_CS);
4848 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
4849 env, R_SS);
4850 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
4851 env, R_DS);
4853 EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
4854 env->eip = EIP;
4855 ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
4856 EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
4857 env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
4858 env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
4859 cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
4861 /* FIXME: guest state consistency checks */
4863 switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
4864 case TLB_CONTROL_DO_NOTHING:
4865 break;
4866 case TLB_CONTROL_FLUSH_ALL_ASID:
4867 /* FIXME: this is not 100% correct but should work for now */
4868 tlb_flush(env, 1);
4869 break;
4872 env->hflags2 |= HF2_GIF_MASK;
4874 if (int_ctl & V_IRQ_MASK) {
4875 env->interrupt_request |= CPU_INTERRUPT_VIRQ;
4878 /* maybe we need to inject an event */
4879 event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
4880 if (event_inj & SVM_EVTINJ_VALID) {
4881 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4882 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
4883 uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
4884 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
4886 if (loglevel & CPU_LOG_TB_IN_ASM)
4887 fprintf(logfile, "Injecting(%#hx): ", valid_err);
4888 /* FIXME: need to implement valid_err */
4889 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4890 case SVM_EVTINJ_TYPE_INTR:
4891 env->exception_index = vector;
4892 env->error_code = event_inj_err;
4893 env->exception_is_int = 0;
4894 env->exception_next_eip = -1;
4895 if (loglevel & CPU_LOG_TB_IN_ASM)
4896 fprintf(logfile, "INTR");
4897 /* XXX: is it always correct ? */
4898 do_interrupt(vector, 0, 0, 0, 1);
4899 break;
4900 case SVM_EVTINJ_TYPE_NMI:
4901 env->exception_index = EXCP02_NMI;
4902 env->error_code = event_inj_err;
4903 env->exception_is_int = 0;
4904 env->exception_next_eip = EIP;
4905 if (loglevel & CPU_LOG_TB_IN_ASM)
4906 fprintf(logfile, "NMI");
4907 cpu_loop_exit();
4908 break;
4909 case SVM_EVTINJ_TYPE_EXEPT:
4910 env->exception_index = vector;
4911 env->error_code = event_inj_err;
4912 env->exception_is_int = 0;
4913 env->exception_next_eip = -1;
4914 if (loglevel & CPU_LOG_TB_IN_ASM)
4915 fprintf(logfile, "EXEPT");
4916 cpu_loop_exit();
4917 break;
4918 case SVM_EVTINJ_TYPE_SOFT:
4919 env->exception_index = vector;
4920 env->error_code = event_inj_err;
4921 env->exception_is_int = 1;
4922 env->exception_next_eip = EIP;
4923 if (loglevel & CPU_LOG_TB_IN_ASM)
4924 fprintf(logfile, "SOFT");
4925 cpu_loop_exit();
4926 break;
4928 if (loglevel & CPU_LOG_TB_IN_ASM)
4929 fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
4933 void helper_vmmcall(void)
4935 helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
4936 raise_exception(EXCP06_ILLOP);
4939 void helper_vmload(int aflag)
4941 target_ulong addr;
4942 helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
4944 if (aflag == 2)
4945 addr = EAX;
4946 else
4947 addr = (uint32_t)EAX;
4949 if (loglevel & CPU_LOG_TB_IN_ASM)
4950 fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4951 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4952 env->segs[R_FS].base);
4954 svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
4955 env, R_FS);
4956 svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
4957 env, R_GS);
4958 svm_load_seg(addr + offsetof(struct vmcb, save.tr),
4959 &env->tr);
4960 svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
4961 &env->ldt);
4963 #ifdef TARGET_X86_64
4964 env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
4965 env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
4966 env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
4967 env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
4968 #endif
4969 env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
4970 env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
4971 env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
4972 env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
4975 void helper_vmsave(int aflag)
4977 target_ulong addr;
4978 helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
4980 if (aflag == 2)
4981 addr = EAX;
4982 else
4983 addr = (uint32_t)EAX;
4985 if (loglevel & CPU_LOG_TB_IN_ASM)
4986 fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4987 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4988 env->segs[R_FS].base);
4990 svm_save_seg(addr + offsetof(struct vmcb, save.fs),
4991 &env->segs[R_FS]);
4992 svm_save_seg(addr + offsetof(struct vmcb, save.gs),
4993 &env->segs[R_GS]);
4994 svm_save_seg(addr + offsetof(struct vmcb, save.tr),
4995 &env->tr);
4996 svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
4997 &env->ldt);
4999 #ifdef TARGET_X86_64
5000 stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
5001 stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
5002 stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
5003 stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
5004 #endif
5005 stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5006 stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5007 stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5008 stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5011 void helper_stgi(void)
5013 helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
5014 env->hflags2 |= HF2_GIF_MASK;
5017 void helper_clgi(void)
5019 helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
5020 env->hflags2 &= ~HF2_GIF_MASK;
5023 void helper_skinit(void)
5025 helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
5026 /* XXX: not implemented */
5027 raise_exception(EXCP06_ILLOP);
5030 void helper_invlpga(int aflag)
5032 target_ulong addr;
5033 helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
5035 if (aflag == 2)
5036 addr = EAX;
5037 else
5038 addr = (uint32_t)EAX;
5040 /* XXX: could use the ASID to see if it is needed to do the
5041 flush */
5042 tlb_flush_page(env, addr);
5045 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5047 if (likely(!(env->hflags & HF_SVMI_MASK)))
5048 return;
5049 switch(type) {
5050 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
5051 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
5052 helper_vmexit(type, param);
5054 break;
5055 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5056 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
5057 helper_vmexit(type, param);
5059 break;
5060 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
5061 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
5062 helper_vmexit(type, param);
5064 break;
5065 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
5066 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
5067 helper_vmexit(type, param);
5069 break;
5070 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
5071 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
5072 helper_vmexit(type, param);
5074 break;
5075 case SVM_EXIT_MSR:
5076 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
5077 /* FIXME: this should be read in at vmrun (faster this way?) */
5078 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5079 uint32_t t0, t1;
5080 switch((uint32_t)ECX) {
5081 case 0 ... 0x1fff:
5082 t0 = (ECX * 2) % 8;
5083 t1 = ECX / 8;
5084 break;
5085 case 0xc0000000 ... 0xc0001fff:
5086 t0 = (8192 + ECX - 0xc0000000) * 2;
5087 t1 = (t0 / 8);
5088 t0 %= 8;
5089 break;
5090 case 0xc0010000 ... 0xc0011fff:
5091 t0 = (16384 + ECX - 0xc0010000) * 2;
5092 t1 = (t0 / 8);
5093 t0 %= 8;
5094 break;
5095 default:
5096 helper_vmexit(type, param);
5097 t0 = 0;
5098 t1 = 0;
5099 break;
5101 if (ldub_phys(addr + t1) & ((1 << param) << t0))
5102 helper_vmexit(type, param);
5104 break;
5105 default:
5106 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
5107 helper_vmexit(type, param);
5109 break;
5113 void helper_svm_check_io(uint32_t port, uint32_t param,
5114 uint32_t next_eip_addend)
5116 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
5117 /* FIXME: this should be read in at vmrun (faster this way?) */
5118 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5119 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5120 if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5121 /* next EIP */
5122 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
5123 env->eip + next_eip_addend);
5124 helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5129 /* Note: currently only 32 bits of exit_code are used */
5130 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5132 uint32_t int_ctl;
5134 if (loglevel & CPU_LOG_TB_IN_ASM)
5135 fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5136 exit_code, exit_info_1,
5137 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5138 EIP);
5140 if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5141 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5142 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5143 } else {
5144 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5147 /* Save the VM state in the vmcb */
5148 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
5149 &env->segs[R_ES]);
5150 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5151 &env->segs[R_CS]);
5152 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5153 &env->segs[R_SS]);
5154 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5155 &env->segs[R_DS]);
5157 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5158 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5160 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5161 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5163 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5164 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5165 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5166 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5167 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5169 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5170 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
5171 int_ctl |= env->v_tpr & V_TPR_MASK;
5172 if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
5173 int_ctl |= V_IRQ_MASK;
5174 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
5176 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5177 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5178 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5179 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5180 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5181 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5182 stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5184 /* Reload the host state from vm_hsave */
5185 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
5186 env->hflags &= ~HF_SVMI_MASK;
5187 env->intercept = 0;
5188 env->intercept_exceptions = 0;
5189 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
5190 env->tsc_offset = 0;
5192 env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5193 env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5195 env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5196 env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5198 cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5199 cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5200 cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5201 /* we need to set the efer after the crs so the hidden flags get
5202 set properly */
5203 cpu_load_efer(env,
5204 ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
5205 env->eflags = 0;
5206 load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5207 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5208 CC_OP = CC_OP_EFLAGS;
5210 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
5211 env, R_ES);
5212 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
5213 env, R_CS);
5214 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
5215 env, R_SS);
5216 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
5217 env, R_DS);
5219 EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5220 ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5221 EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5223 env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5224 env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5226 /* other setups */
5227 cpu_x86_set_cpl(env, 0);
5228 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5229 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5231 env->hflags2 &= ~HF2_GIF_MASK;
5232 /* FIXME: Resets the current ASID register to zero (host ASID). */
5234 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5236 /* Clears the TSC_OFFSET inside the processor. */
5238 /* If the host is in PAE mode, the processor reloads the host's PDPEs
5239 from the page table indicated the host's CR3. If the PDPEs contain
5240 illegal state, the processor causes a shutdown. */
5242 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5243 env->cr[0] |= CR0_PE_MASK;
5244 env->eflags &= ~VM_MASK;
5246 /* Disables all breakpoints in the host DR7 register. */
5248 /* Checks the reloaded host state for consistency. */
5250 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5251 host's code segment or non-canonical (in the case of long mode), a
5252 #GP fault is delivered inside the host.) */
5254 /* remove any pending exception */
5255 env->exception_index = -1;
5256 env->error_code = 0;
5257 env->old_exception = -1;
5259 cpu_loop_exit();
5262 #endif
5264 /* MMX/SSE */
5265 /* XXX: optimize by storing fptt and fptags in the static cpu state */
5266 void helper_enter_mmx(void)
5268 env->fpstt = 0;
5269 *(uint32_t *)(env->fptags) = 0;
5270 *(uint32_t *)(env->fptags + 4) = 0;
5273 void helper_emms(void)
5275 /* set to empty state */
5276 *(uint32_t *)(env->fptags) = 0x01010101;
5277 *(uint32_t *)(env->fptags + 4) = 0x01010101;
5280 /* XXX: suppress */
5281 void helper_movq(void *d, void *s)
5283 *(uint64_t *)d = *(uint64_t *)s;
5286 #define SHIFT 0
5287 #include "ops_sse.h"
5289 #define SHIFT 1
5290 #include "ops_sse.h"
5292 #define SHIFT 0
5293 #include "helper_template.h"
5294 #undef SHIFT
5296 #define SHIFT 1
5297 #include "helper_template.h"
5298 #undef SHIFT
5300 #define SHIFT 2
5301 #include "helper_template.h"
5302 #undef SHIFT
5304 #ifdef TARGET_X86_64
5306 #define SHIFT 3
5307 #include "helper_template.h"
5308 #undef SHIFT
5310 #endif
5312 /* bit operations */
5313 target_ulong helper_bsf(target_ulong t0)
5315 int count;
5316 target_ulong res;
5318 res = t0;
5319 count = 0;
5320 while ((res & 1) == 0) {
5321 count++;
5322 res >>= 1;
5324 return count;
5327 target_ulong helper_bsr(target_ulong t0)
5329 int count;
5330 target_ulong res, mask;
5332 res = t0;
5333 count = TARGET_LONG_BITS - 1;
5334 mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5335 while ((res & mask) == 0) {
5336 count--;
5337 res <<= 1;
5339 return count;
5343 static int compute_all_eflags(void)
5345 return CC_SRC;
5348 static int compute_c_eflags(void)
5350 return CC_SRC & CC_C;
5353 uint32_t helper_cc_compute_all(int op)
5355 switch (op) {
5356 default: /* should never happen */ return 0;
5358 case CC_OP_EFLAGS: return compute_all_eflags();
5360 case CC_OP_MULB: return compute_all_mulb();
5361 case CC_OP_MULW: return compute_all_mulw();
5362 case CC_OP_MULL: return compute_all_mull();
5364 case CC_OP_ADDB: return compute_all_addb();
5365 case CC_OP_ADDW: return compute_all_addw();
5366 case CC_OP_ADDL: return compute_all_addl();
5368 case CC_OP_ADCB: return compute_all_adcb();
5369 case CC_OP_ADCW: return compute_all_adcw();
5370 case CC_OP_ADCL: return compute_all_adcl();
5372 case CC_OP_SUBB: return compute_all_subb();
5373 case CC_OP_SUBW: return compute_all_subw();
5374 case CC_OP_SUBL: return compute_all_subl();
5376 case CC_OP_SBBB: return compute_all_sbbb();
5377 case CC_OP_SBBW: return compute_all_sbbw();
5378 case CC_OP_SBBL: return compute_all_sbbl();
5380 case CC_OP_LOGICB: return compute_all_logicb();
5381 case CC_OP_LOGICW: return compute_all_logicw();
5382 case CC_OP_LOGICL: return compute_all_logicl();
5384 case CC_OP_INCB: return compute_all_incb();
5385 case CC_OP_INCW: return compute_all_incw();
5386 case CC_OP_INCL: return compute_all_incl();
5388 case CC_OP_DECB: return compute_all_decb();
5389 case CC_OP_DECW: return compute_all_decw();
5390 case CC_OP_DECL: return compute_all_decl();
5392 case CC_OP_SHLB: return compute_all_shlb();
5393 case CC_OP_SHLW: return compute_all_shlw();
5394 case CC_OP_SHLL: return compute_all_shll();
5396 case CC_OP_SARB: return compute_all_sarb();
5397 case CC_OP_SARW: return compute_all_sarw();
5398 case CC_OP_SARL: return compute_all_sarl();
5400 #ifdef TARGET_X86_64
5401 case CC_OP_MULQ: return compute_all_mulq();
5403 case CC_OP_ADDQ: return compute_all_addq();
5405 case CC_OP_ADCQ: return compute_all_adcq();
5407 case CC_OP_SUBQ: return compute_all_subq();
5409 case CC_OP_SBBQ: return compute_all_sbbq();
5411 case CC_OP_LOGICQ: return compute_all_logicq();
5413 case CC_OP_INCQ: return compute_all_incq();
5415 case CC_OP_DECQ: return compute_all_decq();
5417 case CC_OP_SHLQ: return compute_all_shlq();
5419 case CC_OP_SARQ: return compute_all_sarq();
5420 #endif
5424 uint32_t helper_cc_compute_c(int op)
5426 switch (op) {
5427 default: /* should never happen */ return 0;
5429 case CC_OP_EFLAGS: return compute_c_eflags();
5431 case CC_OP_MULB: return compute_c_mull();
5432 case CC_OP_MULW: return compute_c_mull();
5433 case CC_OP_MULL: return compute_c_mull();
5435 case CC_OP_ADDB: return compute_c_addb();
5436 case CC_OP_ADDW: return compute_c_addw();
5437 case CC_OP_ADDL: return compute_c_addl();
5439 case CC_OP_ADCB: return compute_c_adcb();
5440 case CC_OP_ADCW: return compute_c_adcw();
5441 case CC_OP_ADCL: return compute_c_adcl();
5443 case CC_OP_SUBB: return compute_c_subb();
5444 case CC_OP_SUBW: return compute_c_subw();
5445 case CC_OP_SUBL: return compute_c_subl();
5447 case CC_OP_SBBB: return compute_c_sbbb();
5448 case CC_OP_SBBW: return compute_c_sbbw();
5449 case CC_OP_SBBL: return compute_c_sbbl();
5451 case CC_OP_LOGICB: return compute_c_logicb();
5452 case CC_OP_LOGICW: return compute_c_logicw();
5453 case CC_OP_LOGICL: return compute_c_logicl();
5455 case CC_OP_INCB: return compute_c_incl();
5456 case CC_OP_INCW: return compute_c_incl();
5457 case CC_OP_INCL: return compute_c_incl();
5459 case CC_OP_DECB: return compute_c_incl();
5460 case CC_OP_DECW: return compute_c_incl();
5461 case CC_OP_DECL: return compute_c_incl();
5463 case CC_OP_SHLB: return compute_c_shlb();
5464 case CC_OP_SHLW: return compute_c_shlw();
5465 case CC_OP_SHLL: return compute_c_shll();
5467 case CC_OP_SARB: return compute_c_sarl();
5468 case CC_OP_SARW: return compute_c_sarl();
5469 case CC_OP_SARL: return compute_c_sarl();
5471 #ifdef TARGET_X86_64
5472 case CC_OP_MULQ: return compute_c_mull();
5474 case CC_OP_ADDQ: return compute_c_addq();
5476 case CC_OP_ADCQ: return compute_c_adcq();
5478 case CC_OP_SUBQ: return compute_c_subq();
5480 case CC_OP_SBBQ: return compute_c_sbbq();
5482 case CC_OP_LOGICQ: return compute_c_logicq();
5484 case CC_OP_INCQ: return compute_c_incl();
5486 case CC_OP_DECQ: return compute_c_incl();
5488 case CC_OP_SHLQ: return compute_c_shlq();
5490 case CC_OP_SARQ: return compute_c_sarl();
5491 #endif