sh4/r2d: update pci, usb and kernel management
[qemu/sh4.git] / target-i386 / op_helper.c
blobd32a6a3d97069bbbbd2cf97a53134efb3cf52129
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);
500 #ifndef CONFIG_USER_ONLY
501 /* reset local breakpoints */
502 if (env->dr[7] & 0x55) {
503 for (i = 0; i < 4; i++) {
504 if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
505 hw_breakpoint_remove(env, i);
507 env->dr[7] &= ~0x55;
509 #endif
512 /* check if Port I/O is allowed in TSS */
513 static inline void check_io(int addr, int size)
515 int io_offset, val, mask;
517 /* TSS must be a valid 32 bit one */
518 if (!(env->tr.flags & DESC_P_MASK) ||
519 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
520 env->tr.limit < 103)
521 goto fail;
522 io_offset = lduw_kernel(env->tr.base + 0x66);
523 io_offset += (addr >> 3);
524 /* Note: the check needs two bytes */
525 if ((io_offset + 1) > env->tr.limit)
526 goto fail;
527 val = lduw_kernel(env->tr.base + io_offset);
528 val >>= (addr & 7);
529 mask = (1 << size) - 1;
530 /* all bits must be zero to allow the I/O */
531 if ((val & mask) != 0) {
532 fail:
533 raise_exception_err(EXCP0D_GPF, 0);
537 void helper_check_iob(uint32_t t0)
539 check_io(t0, 1);
542 void helper_check_iow(uint32_t t0)
544 check_io(t0, 2);
547 void helper_check_iol(uint32_t t0)
549 check_io(t0, 4);
552 void helper_outb(uint32_t port, uint32_t data)
554 cpu_outb(env, port, data & 0xff);
557 target_ulong helper_inb(uint32_t port)
559 return cpu_inb(env, port);
562 void helper_outw(uint32_t port, uint32_t data)
564 cpu_outw(env, port, data & 0xffff);
567 target_ulong helper_inw(uint32_t port)
569 return cpu_inw(env, port);
572 void helper_outl(uint32_t port, uint32_t data)
574 cpu_outl(env, port, data);
577 target_ulong helper_inl(uint32_t port)
579 return cpu_inl(env, port);
582 static inline unsigned int get_sp_mask(unsigned int e2)
584 if (e2 & DESC_B_MASK)
585 return 0xffffffff;
586 else
587 return 0xffff;
590 #ifdef TARGET_X86_64
591 #define SET_ESP(val, sp_mask)\
592 do {\
593 if ((sp_mask) == 0xffff)\
594 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
595 else if ((sp_mask) == 0xffffffffLL)\
596 ESP = (uint32_t)(val);\
597 else\
598 ESP = (val);\
599 } while (0)
600 #else
601 #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
602 #endif
604 /* in 64-bit machines, this can overflow. So this segment addition macro
605 * can be used to trim the value to 32-bit whenever needed */
606 #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
608 /* XXX: add a is_user flag to have proper security support */
609 #define PUSHW(ssp, sp, sp_mask, val)\
611 sp -= 2;\
612 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
615 #define PUSHL(ssp, sp, sp_mask, val)\
617 sp -= 4;\
618 stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
621 #define POPW(ssp, sp, sp_mask, val)\
623 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
624 sp += 2;\
627 #define POPL(ssp, sp, sp_mask, val)\
629 val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
630 sp += 4;\
633 /* protected mode interrupt */
634 static void do_interrupt_protected(int intno, int is_int, int error_code,
635 unsigned int next_eip, int is_hw)
637 SegmentCache *dt;
638 target_ulong ptr, ssp;
639 int type, dpl, selector, ss_dpl, cpl;
640 int has_error_code, new_stack, shift;
641 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
642 uint32_t old_eip, sp_mask;
644 has_error_code = 0;
645 if (!is_int && !is_hw) {
646 switch(intno) {
647 case 8:
648 case 10:
649 case 11:
650 case 12:
651 case 13:
652 case 14:
653 case 17:
654 has_error_code = 1;
655 break;
658 if (is_int)
659 old_eip = next_eip;
660 else
661 old_eip = env->eip;
663 dt = &env->idt;
664 if (intno * 8 + 7 > dt->limit)
665 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
666 ptr = dt->base + intno * 8;
667 e1 = ldl_kernel(ptr);
668 e2 = ldl_kernel(ptr + 4);
669 /* check gate type */
670 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
671 switch(type) {
672 case 5: /* task gate */
673 /* must do that check here to return the correct error code */
674 if (!(e2 & DESC_P_MASK))
675 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
676 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
677 if (has_error_code) {
678 int type;
679 uint32_t mask;
680 /* push the error code */
681 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
682 shift = type >> 3;
683 if (env->segs[R_SS].flags & DESC_B_MASK)
684 mask = 0xffffffff;
685 else
686 mask = 0xffff;
687 esp = (ESP - (2 << shift)) & mask;
688 ssp = env->segs[R_SS].base + esp;
689 if (shift)
690 stl_kernel(ssp, error_code);
691 else
692 stw_kernel(ssp, error_code);
693 SET_ESP(esp, mask);
695 return;
696 case 6: /* 286 interrupt gate */
697 case 7: /* 286 trap gate */
698 case 14: /* 386 interrupt gate */
699 case 15: /* 386 trap gate */
700 break;
701 default:
702 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
703 break;
705 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
706 cpl = env->hflags & HF_CPL_MASK;
707 /* check privilege if software int */
708 if (is_int && dpl < cpl)
709 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
710 /* check valid bit */
711 if (!(e2 & DESC_P_MASK))
712 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
713 selector = e1 >> 16;
714 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
715 if ((selector & 0xfffc) == 0)
716 raise_exception_err(EXCP0D_GPF, 0);
718 if (load_segment(&e1, &e2, selector) != 0)
719 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
720 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
721 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
722 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
723 if (dpl > cpl)
724 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
725 if (!(e2 & DESC_P_MASK))
726 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
727 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
728 /* to inner privilege */
729 get_ss_esp_from_tss(&ss, &esp, dpl);
730 if ((ss & 0xfffc) == 0)
731 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
732 if ((ss & 3) != dpl)
733 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
734 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
735 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
736 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
737 if (ss_dpl != dpl)
738 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
739 if (!(ss_e2 & DESC_S_MASK) ||
740 (ss_e2 & DESC_CS_MASK) ||
741 !(ss_e2 & DESC_W_MASK))
742 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
743 if (!(ss_e2 & DESC_P_MASK))
744 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
745 new_stack = 1;
746 sp_mask = get_sp_mask(ss_e2);
747 ssp = get_seg_base(ss_e1, ss_e2);
748 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
749 /* to same privilege */
750 if (env->eflags & VM_MASK)
751 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
752 new_stack = 0;
753 sp_mask = get_sp_mask(env->segs[R_SS].flags);
754 ssp = env->segs[R_SS].base;
755 esp = ESP;
756 dpl = cpl;
757 } else {
758 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
759 new_stack = 0; /* avoid warning */
760 sp_mask = 0; /* avoid warning */
761 ssp = 0; /* avoid warning */
762 esp = 0; /* avoid warning */
765 shift = type >> 3;
767 #if 0
768 /* XXX: check that enough room is available */
769 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
770 if (env->eflags & VM_MASK)
771 push_size += 8;
772 push_size <<= shift;
773 #endif
774 if (shift == 1) {
775 if (new_stack) {
776 if (env->eflags & VM_MASK) {
777 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
778 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
779 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
780 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
782 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
783 PUSHL(ssp, esp, sp_mask, ESP);
785 PUSHL(ssp, esp, sp_mask, compute_eflags());
786 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
787 PUSHL(ssp, esp, sp_mask, old_eip);
788 if (has_error_code) {
789 PUSHL(ssp, esp, sp_mask, error_code);
791 } else {
792 if (new_stack) {
793 if (env->eflags & VM_MASK) {
794 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
795 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
796 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
797 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
799 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
800 PUSHW(ssp, esp, sp_mask, ESP);
802 PUSHW(ssp, esp, sp_mask, compute_eflags());
803 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
804 PUSHW(ssp, esp, sp_mask, old_eip);
805 if (has_error_code) {
806 PUSHW(ssp, esp, sp_mask, error_code);
810 if (new_stack) {
811 if (env->eflags & VM_MASK) {
812 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
813 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
814 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
815 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
817 ss = (ss & ~3) | dpl;
818 cpu_x86_load_seg_cache(env, R_SS, ss,
819 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
821 SET_ESP(esp, sp_mask);
823 selector = (selector & ~3) | dpl;
824 cpu_x86_load_seg_cache(env, R_CS, selector,
825 get_seg_base(e1, e2),
826 get_seg_limit(e1, e2),
827 e2);
828 cpu_x86_set_cpl(env, dpl);
829 env->eip = offset;
831 /* interrupt gate clear IF mask */
832 if ((type & 1) == 0) {
833 env->eflags &= ~IF_MASK;
835 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
838 #ifdef TARGET_X86_64
840 #define PUSHQ(sp, val)\
842 sp -= 8;\
843 stq_kernel(sp, (val));\
846 #define POPQ(sp, val)\
848 val = ldq_kernel(sp);\
849 sp += 8;\
852 static inline target_ulong get_rsp_from_tss(int level)
854 int index;
856 #if 0
857 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
858 env->tr.base, env->tr.limit);
859 #endif
861 if (!(env->tr.flags & DESC_P_MASK))
862 cpu_abort(env, "invalid tss");
863 index = 8 * level + 4;
864 if ((index + 7) > env->tr.limit)
865 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
866 return ldq_kernel(env->tr.base + index);
869 /* 64 bit interrupt */
870 static void do_interrupt64(int intno, int is_int, int error_code,
871 target_ulong next_eip, int is_hw)
873 SegmentCache *dt;
874 target_ulong ptr;
875 int type, dpl, selector, cpl, ist;
876 int has_error_code, new_stack;
877 uint32_t e1, e2, e3, ss;
878 target_ulong old_eip, esp, offset;
880 has_error_code = 0;
881 if (!is_int && !is_hw) {
882 switch(intno) {
883 case 8:
884 case 10:
885 case 11:
886 case 12:
887 case 13:
888 case 14:
889 case 17:
890 has_error_code = 1;
891 break;
894 if (is_int)
895 old_eip = next_eip;
896 else
897 old_eip = env->eip;
899 dt = &env->idt;
900 if (intno * 16 + 15 > dt->limit)
901 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
902 ptr = dt->base + intno * 16;
903 e1 = ldl_kernel(ptr);
904 e2 = ldl_kernel(ptr + 4);
905 e3 = ldl_kernel(ptr + 8);
906 /* check gate type */
907 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
908 switch(type) {
909 case 14: /* 386 interrupt gate */
910 case 15: /* 386 trap gate */
911 break;
912 default:
913 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
914 break;
916 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
917 cpl = env->hflags & HF_CPL_MASK;
918 /* check privilege if software int */
919 if (is_int && dpl < cpl)
920 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
921 /* check valid bit */
922 if (!(e2 & DESC_P_MASK))
923 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
924 selector = e1 >> 16;
925 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
926 ist = e2 & 7;
927 if ((selector & 0xfffc) == 0)
928 raise_exception_err(EXCP0D_GPF, 0);
930 if (load_segment(&e1, &e2, selector) != 0)
931 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
932 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
933 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
934 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
935 if (dpl > cpl)
936 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
937 if (!(e2 & DESC_P_MASK))
938 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
939 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
940 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
941 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
942 /* to inner privilege */
943 if (ist != 0)
944 esp = get_rsp_from_tss(ist + 3);
945 else
946 esp = get_rsp_from_tss(dpl);
947 esp &= ~0xfLL; /* align stack */
948 ss = 0;
949 new_stack = 1;
950 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
951 /* to same privilege */
952 if (env->eflags & VM_MASK)
953 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
954 new_stack = 0;
955 if (ist != 0)
956 esp = get_rsp_from_tss(ist + 3);
957 else
958 esp = ESP;
959 esp &= ~0xfLL; /* align stack */
960 dpl = cpl;
961 } else {
962 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
963 new_stack = 0; /* avoid warning */
964 esp = 0; /* avoid warning */
967 PUSHQ(esp, env->segs[R_SS].selector);
968 PUSHQ(esp, ESP);
969 PUSHQ(esp, compute_eflags());
970 PUSHQ(esp, env->segs[R_CS].selector);
971 PUSHQ(esp, old_eip);
972 if (has_error_code) {
973 PUSHQ(esp, error_code);
976 if (new_stack) {
977 ss = 0 | dpl;
978 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
980 ESP = esp;
982 selector = (selector & ~3) | dpl;
983 cpu_x86_load_seg_cache(env, R_CS, selector,
984 get_seg_base(e1, e2),
985 get_seg_limit(e1, e2),
986 e2);
987 cpu_x86_set_cpl(env, dpl);
988 env->eip = offset;
990 /* interrupt gate clear IF mask */
991 if ((type & 1) == 0) {
992 env->eflags &= ~IF_MASK;
994 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
996 #endif
998 #if defined(CONFIG_USER_ONLY)
999 void helper_syscall(int next_eip_addend)
1001 env->exception_index = EXCP_SYSCALL;
1002 env->exception_next_eip = env->eip + next_eip_addend;
1003 cpu_loop_exit();
1005 #else
1006 void helper_syscall(int next_eip_addend)
1008 int selector;
1010 if (!(env->efer & MSR_EFER_SCE)) {
1011 raise_exception_err(EXCP06_ILLOP, 0);
1013 selector = (env->star >> 32) & 0xffff;
1014 #ifdef TARGET_X86_64
1015 if (env->hflags & HF_LMA_MASK) {
1016 int code64;
1018 ECX = env->eip + next_eip_addend;
1019 env->regs[11] = compute_eflags();
1021 code64 = env->hflags & HF_CS64_MASK;
1023 cpu_x86_set_cpl(env, 0);
1024 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1025 0, 0xffffffff,
1026 DESC_G_MASK | DESC_P_MASK |
1027 DESC_S_MASK |
1028 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1029 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1030 0, 0xffffffff,
1031 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1032 DESC_S_MASK |
1033 DESC_W_MASK | DESC_A_MASK);
1034 env->eflags &= ~env->fmask;
1035 load_eflags(env->eflags, 0);
1036 if (code64)
1037 env->eip = env->lstar;
1038 else
1039 env->eip = env->cstar;
1040 } else
1041 #endif
1043 ECX = (uint32_t)(env->eip + next_eip_addend);
1045 cpu_x86_set_cpl(env, 0);
1046 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1047 0, 0xffffffff,
1048 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1049 DESC_S_MASK |
1050 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1051 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1052 0, 0xffffffff,
1053 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1054 DESC_S_MASK |
1055 DESC_W_MASK | DESC_A_MASK);
1056 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1057 env->eip = (uint32_t)env->star;
1060 #endif
1062 void helper_sysret(int dflag)
1064 int cpl, selector;
1066 if (!(env->efer & MSR_EFER_SCE)) {
1067 raise_exception_err(EXCP06_ILLOP, 0);
1069 cpl = env->hflags & HF_CPL_MASK;
1070 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1071 raise_exception_err(EXCP0D_GPF, 0);
1073 selector = (env->star >> 48) & 0xffff;
1074 #ifdef TARGET_X86_64
1075 if (env->hflags & HF_LMA_MASK) {
1076 if (dflag == 2) {
1077 cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1078 0, 0xffffffff,
1079 DESC_G_MASK | DESC_P_MASK |
1080 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1081 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1082 DESC_L_MASK);
1083 env->eip = ECX;
1084 } else {
1085 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1086 0, 0xffffffff,
1087 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1088 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1089 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1090 env->eip = (uint32_t)ECX;
1092 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1093 0, 0xffffffff,
1094 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1095 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1096 DESC_W_MASK | DESC_A_MASK);
1097 load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1098 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1099 cpu_x86_set_cpl(env, 3);
1100 } else
1101 #endif
1103 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1104 0, 0xffffffff,
1105 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1106 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1107 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1108 env->eip = (uint32_t)ECX;
1109 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1110 0, 0xffffffff,
1111 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1112 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1113 DESC_W_MASK | DESC_A_MASK);
1114 env->eflags |= IF_MASK;
1115 cpu_x86_set_cpl(env, 3);
1117 #ifdef USE_KQEMU
1118 if (kqemu_is_ok(env)) {
1119 if (env->hflags & HF_LMA_MASK)
1120 CC_OP = CC_OP_EFLAGS;
1121 env->exception_index = -1;
1122 cpu_loop_exit();
1124 #endif
1127 /* real mode interrupt */
1128 static void do_interrupt_real(int intno, int is_int, int error_code,
1129 unsigned int next_eip)
1131 SegmentCache *dt;
1132 target_ulong ptr, ssp;
1133 int selector;
1134 uint32_t offset, esp;
1135 uint32_t old_cs, old_eip;
1137 /* real mode (simpler !) */
1138 dt = &env->idt;
1139 if (intno * 4 + 3 > dt->limit)
1140 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1141 ptr = dt->base + intno * 4;
1142 offset = lduw_kernel(ptr);
1143 selector = lduw_kernel(ptr + 2);
1144 esp = ESP;
1145 ssp = env->segs[R_SS].base;
1146 if (is_int)
1147 old_eip = next_eip;
1148 else
1149 old_eip = env->eip;
1150 old_cs = env->segs[R_CS].selector;
1151 /* XXX: use SS segment size ? */
1152 PUSHW(ssp, esp, 0xffff, compute_eflags());
1153 PUSHW(ssp, esp, 0xffff, old_cs);
1154 PUSHW(ssp, esp, 0xffff, old_eip);
1156 /* update processor state */
1157 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1158 env->eip = offset;
1159 env->segs[R_CS].selector = selector;
1160 env->segs[R_CS].base = (selector << 4);
1161 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1164 /* fake user mode interrupt */
1165 void do_interrupt_user(int intno, int is_int, int error_code,
1166 target_ulong next_eip)
1168 SegmentCache *dt;
1169 target_ulong ptr;
1170 int dpl, cpl, shift;
1171 uint32_t e2;
1173 dt = &env->idt;
1174 if (env->hflags & HF_LMA_MASK) {
1175 shift = 4;
1176 } else {
1177 shift = 3;
1179 ptr = dt->base + (intno << shift);
1180 e2 = ldl_kernel(ptr + 4);
1182 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1183 cpl = env->hflags & HF_CPL_MASK;
1184 /* check privilege if software int */
1185 if (is_int && dpl < cpl)
1186 raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1188 /* Since we emulate only user space, we cannot do more than
1189 exiting the emulation with the suitable exception and error
1190 code */
1191 if (is_int)
1192 EIP = next_eip;
1196 * Begin execution of an interruption. is_int is TRUE if coming from
1197 * the int instruction. next_eip is the EIP value AFTER the interrupt
1198 * instruction. It is only relevant if is_int is TRUE.
1200 void do_interrupt(int intno, int is_int, int error_code,
1201 target_ulong next_eip, int is_hw)
1203 if (loglevel & CPU_LOG_INT) {
1204 if ((env->cr[0] & CR0_PE_MASK)) {
1205 static int count;
1206 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,
1207 count, intno, error_code, is_int,
1208 env->hflags & HF_CPL_MASK,
1209 env->segs[R_CS].selector, EIP,
1210 (int)env->segs[R_CS].base + EIP,
1211 env->segs[R_SS].selector, ESP);
1212 if (intno == 0x0e) {
1213 fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1214 } else {
1215 fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1217 fprintf(logfile, "\n");
1218 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1219 #if 0
1221 int i;
1222 uint8_t *ptr;
1223 fprintf(logfile, " code=");
1224 ptr = env->segs[R_CS].base + env->eip;
1225 for(i = 0; i < 16; i++) {
1226 fprintf(logfile, " %02x", ldub(ptr + i));
1228 fprintf(logfile, "\n");
1230 #endif
1231 count++;
1234 if (env->cr[0] & CR0_PE_MASK) {
1235 #ifdef TARGET_X86_64
1236 if (env->hflags & HF_LMA_MASK) {
1237 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1238 } else
1239 #endif
1241 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1243 } else {
1244 do_interrupt_real(intno, is_int, error_code, next_eip);
1249 * Check nested exceptions and change to double or triple fault if
1250 * needed. It should only be called, if this is not an interrupt.
1251 * Returns the new exception number.
1253 static int check_exception(int intno, int *error_code)
1255 int first_contributory = env->old_exception == 0 ||
1256 (env->old_exception >= 10 &&
1257 env->old_exception <= 13);
1258 int second_contributory = intno == 0 ||
1259 (intno >= 10 && intno <= 13);
1261 if (loglevel & CPU_LOG_INT)
1262 fprintf(logfile, "check_exception old: 0x%x new 0x%x\n",
1263 env->old_exception, intno);
1265 if (env->old_exception == EXCP08_DBLE)
1266 cpu_abort(env, "triple fault");
1268 if ((first_contributory && second_contributory)
1269 || (env->old_exception == EXCP0E_PAGE &&
1270 (second_contributory || (intno == EXCP0E_PAGE)))) {
1271 intno = EXCP08_DBLE;
1272 *error_code = 0;
1275 if (second_contributory || (intno == EXCP0E_PAGE) ||
1276 (intno == EXCP08_DBLE))
1277 env->old_exception = intno;
1279 return intno;
1283 * Signal an interruption. It is executed in the main CPU loop.
1284 * is_int is TRUE if coming from the int instruction. next_eip is the
1285 * EIP value AFTER the interrupt instruction. It is only relevant if
1286 * is_int is TRUE.
1288 void raise_interrupt(int intno, int is_int, int error_code,
1289 int next_eip_addend)
1291 if (!is_int) {
1292 helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1293 intno = check_exception(intno, &error_code);
1294 } else {
1295 helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
1298 env->exception_index = intno;
1299 env->error_code = error_code;
1300 env->exception_is_int = is_int;
1301 env->exception_next_eip = env->eip + next_eip_addend;
1302 cpu_loop_exit();
1305 /* shortcuts to generate exceptions */
1307 void (raise_exception_err)(int exception_index, int error_code)
1309 raise_interrupt(exception_index, 0, error_code, 0);
1312 void raise_exception(int exception_index)
1314 raise_interrupt(exception_index, 0, 0, 0);
1317 /* SMM support */
1319 #if defined(CONFIG_USER_ONLY)
1321 void do_smm_enter(void)
1325 void helper_rsm(void)
1329 #else
1331 #ifdef TARGET_X86_64
1332 #define SMM_REVISION_ID 0x00020064
1333 #else
1334 #define SMM_REVISION_ID 0x00020000
1335 #endif
1337 void do_smm_enter(void)
1339 target_ulong sm_state;
1340 SegmentCache *dt;
1341 int i, offset;
1343 if (loglevel & CPU_LOG_INT) {
1344 fprintf(logfile, "SMM: enter\n");
1345 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1348 env->hflags |= HF_SMM_MASK;
1349 cpu_smm_update(env);
1351 sm_state = env->smbase + 0x8000;
1353 #ifdef TARGET_X86_64
1354 for(i = 0; i < 6; i++) {
1355 dt = &env->segs[i];
1356 offset = 0x7e00 + i * 16;
1357 stw_phys(sm_state + offset, dt->selector);
1358 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1359 stl_phys(sm_state + offset + 4, dt->limit);
1360 stq_phys(sm_state + offset + 8, dt->base);
1363 stq_phys(sm_state + 0x7e68, env->gdt.base);
1364 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1366 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1367 stq_phys(sm_state + 0x7e78, env->ldt.base);
1368 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1369 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1371 stq_phys(sm_state + 0x7e88, env->idt.base);
1372 stl_phys(sm_state + 0x7e84, env->idt.limit);
1374 stw_phys(sm_state + 0x7e90, env->tr.selector);
1375 stq_phys(sm_state + 0x7e98, env->tr.base);
1376 stl_phys(sm_state + 0x7e94, env->tr.limit);
1377 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1379 stq_phys(sm_state + 0x7ed0, env->efer);
1381 stq_phys(sm_state + 0x7ff8, EAX);
1382 stq_phys(sm_state + 0x7ff0, ECX);
1383 stq_phys(sm_state + 0x7fe8, EDX);
1384 stq_phys(sm_state + 0x7fe0, EBX);
1385 stq_phys(sm_state + 0x7fd8, ESP);
1386 stq_phys(sm_state + 0x7fd0, EBP);
1387 stq_phys(sm_state + 0x7fc8, ESI);
1388 stq_phys(sm_state + 0x7fc0, EDI);
1389 for(i = 8; i < 16; i++)
1390 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1391 stq_phys(sm_state + 0x7f78, env->eip);
1392 stl_phys(sm_state + 0x7f70, compute_eflags());
1393 stl_phys(sm_state + 0x7f68, env->dr[6]);
1394 stl_phys(sm_state + 0x7f60, env->dr[7]);
1396 stl_phys(sm_state + 0x7f48, env->cr[4]);
1397 stl_phys(sm_state + 0x7f50, env->cr[3]);
1398 stl_phys(sm_state + 0x7f58, env->cr[0]);
1400 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1401 stl_phys(sm_state + 0x7f00, env->smbase);
1402 #else
1403 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1404 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1405 stl_phys(sm_state + 0x7ff4, compute_eflags());
1406 stl_phys(sm_state + 0x7ff0, env->eip);
1407 stl_phys(sm_state + 0x7fec, EDI);
1408 stl_phys(sm_state + 0x7fe8, ESI);
1409 stl_phys(sm_state + 0x7fe4, EBP);
1410 stl_phys(sm_state + 0x7fe0, ESP);
1411 stl_phys(sm_state + 0x7fdc, EBX);
1412 stl_phys(sm_state + 0x7fd8, EDX);
1413 stl_phys(sm_state + 0x7fd4, ECX);
1414 stl_phys(sm_state + 0x7fd0, EAX);
1415 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1416 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1418 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1419 stl_phys(sm_state + 0x7f64, env->tr.base);
1420 stl_phys(sm_state + 0x7f60, env->tr.limit);
1421 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1423 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1424 stl_phys(sm_state + 0x7f80, env->ldt.base);
1425 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1426 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1428 stl_phys(sm_state + 0x7f74, env->gdt.base);
1429 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1431 stl_phys(sm_state + 0x7f58, env->idt.base);
1432 stl_phys(sm_state + 0x7f54, env->idt.limit);
1434 for(i = 0; i < 6; i++) {
1435 dt = &env->segs[i];
1436 if (i < 3)
1437 offset = 0x7f84 + i * 12;
1438 else
1439 offset = 0x7f2c + (i - 3) * 12;
1440 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1441 stl_phys(sm_state + offset + 8, dt->base);
1442 stl_phys(sm_state + offset + 4, dt->limit);
1443 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1445 stl_phys(sm_state + 0x7f14, env->cr[4]);
1447 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1448 stl_phys(sm_state + 0x7ef8, env->smbase);
1449 #endif
1450 /* init SMM cpu state */
1452 #ifdef TARGET_X86_64
1453 cpu_load_efer(env, 0);
1454 #endif
1455 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1456 env->eip = 0x00008000;
1457 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1458 0xffffffff, 0);
1459 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1460 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1461 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1462 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1463 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1465 cpu_x86_update_cr0(env,
1466 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1467 cpu_x86_update_cr4(env, 0);
1468 env->dr[7] = 0x00000400;
1469 CC_OP = CC_OP_EFLAGS;
1472 void helper_rsm(void)
1474 target_ulong sm_state;
1475 int i, offset;
1476 uint32_t val;
1478 sm_state = env->smbase + 0x8000;
1479 #ifdef TARGET_X86_64
1480 cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
1482 for(i = 0; i < 6; i++) {
1483 offset = 0x7e00 + i * 16;
1484 cpu_x86_load_seg_cache(env, i,
1485 lduw_phys(sm_state + offset),
1486 ldq_phys(sm_state + offset + 8),
1487 ldl_phys(sm_state + offset + 4),
1488 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1491 env->gdt.base = ldq_phys(sm_state + 0x7e68);
1492 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1494 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1495 env->ldt.base = ldq_phys(sm_state + 0x7e78);
1496 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1497 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1499 env->idt.base = ldq_phys(sm_state + 0x7e88);
1500 env->idt.limit = ldl_phys(sm_state + 0x7e84);
1502 env->tr.selector = lduw_phys(sm_state + 0x7e90);
1503 env->tr.base = ldq_phys(sm_state + 0x7e98);
1504 env->tr.limit = ldl_phys(sm_state + 0x7e94);
1505 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1507 EAX = ldq_phys(sm_state + 0x7ff8);
1508 ECX = ldq_phys(sm_state + 0x7ff0);
1509 EDX = ldq_phys(sm_state + 0x7fe8);
1510 EBX = ldq_phys(sm_state + 0x7fe0);
1511 ESP = ldq_phys(sm_state + 0x7fd8);
1512 EBP = ldq_phys(sm_state + 0x7fd0);
1513 ESI = ldq_phys(sm_state + 0x7fc8);
1514 EDI = ldq_phys(sm_state + 0x7fc0);
1515 for(i = 8; i < 16; i++)
1516 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1517 env->eip = ldq_phys(sm_state + 0x7f78);
1518 load_eflags(ldl_phys(sm_state + 0x7f70),
1519 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1520 env->dr[6] = ldl_phys(sm_state + 0x7f68);
1521 env->dr[7] = ldl_phys(sm_state + 0x7f60);
1523 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1524 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1525 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1527 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1528 if (val & 0x20000) {
1529 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1531 #else
1532 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1533 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1534 load_eflags(ldl_phys(sm_state + 0x7ff4),
1535 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1536 env->eip = ldl_phys(sm_state + 0x7ff0);
1537 EDI = ldl_phys(sm_state + 0x7fec);
1538 ESI = ldl_phys(sm_state + 0x7fe8);
1539 EBP = ldl_phys(sm_state + 0x7fe4);
1540 ESP = ldl_phys(sm_state + 0x7fe0);
1541 EBX = ldl_phys(sm_state + 0x7fdc);
1542 EDX = ldl_phys(sm_state + 0x7fd8);
1543 ECX = ldl_phys(sm_state + 0x7fd4);
1544 EAX = ldl_phys(sm_state + 0x7fd0);
1545 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1546 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1548 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1549 env->tr.base = ldl_phys(sm_state + 0x7f64);
1550 env->tr.limit = ldl_phys(sm_state + 0x7f60);
1551 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1553 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1554 env->ldt.base = ldl_phys(sm_state + 0x7f80);
1555 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1556 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1558 env->gdt.base = ldl_phys(sm_state + 0x7f74);
1559 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1561 env->idt.base = ldl_phys(sm_state + 0x7f58);
1562 env->idt.limit = ldl_phys(sm_state + 0x7f54);
1564 for(i = 0; i < 6; i++) {
1565 if (i < 3)
1566 offset = 0x7f84 + i * 12;
1567 else
1568 offset = 0x7f2c + (i - 3) * 12;
1569 cpu_x86_load_seg_cache(env, i,
1570 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1571 ldl_phys(sm_state + offset + 8),
1572 ldl_phys(sm_state + offset + 4),
1573 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1575 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1577 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1578 if (val & 0x20000) {
1579 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1581 #endif
1582 CC_OP = CC_OP_EFLAGS;
1583 env->hflags &= ~HF_SMM_MASK;
1584 cpu_smm_update(env);
1586 if (loglevel & CPU_LOG_INT) {
1587 fprintf(logfile, "SMM: after RSM\n");
1588 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1592 #endif /* !CONFIG_USER_ONLY */
1595 /* division, flags are undefined */
1597 void helper_divb_AL(target_ulong t0)
1599 unsigned int num, den, q, r;
1601 num = (EAX & 0xffff);
1602 den = (t0 & 0xff);
1603 if (den == 0) {
1604 raise_exception(EXCP00_DIVZ);
1606 q = (num / den);
1607 if (q > 0xff)
1608 raise_exception(EXCP00_DIVZ);
1609 q &= 0xff;
1610 r = (num % den) & 0xff;
1611 EAX = (EAX & ~0xffff) | (r << 8) | q;
1614 void helper_idivb_AL(target_ulong t0)
1616 int num, den, q, r;
1618 num = (int16_t)EAX;
1619 den = (int8_t)t0;
1620 if (den == 0) {
1621 raise_exception(EXCP00_DIVZ);
1623 q = (num / den);
1624 if (q != (int8_t)q)
1625 raise_exception(EXCP00_DIVZ);
1626 q &= 0xff;
1627 r = (num % den) & 0xff;
1628 EAX = (EAX & ~0xffff) | (r << 8) | q;
1631 void helper_divw_AX(target_ulong t0)
1633 unsigned int num, den, q, r;
1635 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1636 den = (t0 & 0xffff);
1637 if (den == 0) {
1638 raise_exception(EXCP00_DIVZ);
1640 q = (num / den);
1641 if (q > 0xffff)
1642 raise_exception(EXCP00_DIVZ);
1643 q &= 0xffff;
1644 r = (num % den) & 0xffff;
1645 EAX = (EAX & ~0xffff) | q;
1646 EDX = (EDX & ~0xffff) | r;
1649 void helper_idivw_AX(target_ulong t0)
1651 int num, den, q, r;
1653 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1654 den = (int16_t)t0;
1655 if (den == 0) {
1656 raise_exception(EXCP00_DIVZ);
1658 q = (num / den);
1659 if (q != (int16_t)q)
1660 raise_exception(EXCP00_DIVZ);
1661 q &= 0xffff;
1662 r = (num % den) & 0xffff;
1663 EAX = (EAX & ~0xffff) | q;
1664 EDX = (EDX & ~0xffff) | r;
1667 void helper_divl_EAX(target_ulong t0)
1669 unsigned int den, r;
1670 uint64_t num, q;
1672 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1673 den = t0;
1674 if (den == 0) {
1675 raise_exception(EXCP00_DIVZ);
1677 q = (num / den);
1678 r = (num % den);
1679 if (q > 0xffffffff)
1680 raise_exception(EXCP00_DIVZ);
1681 EAX = (uint32_t)q;
1682 EDX = (uint32_t)r;
1685 void helper_idivl_EAX(target_ulong t0)
1687 int den, r;
1688 int64_t num, q;
1690 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1691 den = t0;
1692 if (den == 0) {
1693 raise_exception(EXCP00_DIVZ);
1695 q = (num / den);
1696 r = (num % den);
1697 if (q != (int32_t)q)
1698 raise_exception(EXCP00_DIVZ);
1699 EAX = (uint32_t)q;
1700 EDX = (uint32_t)r;
1703 /* bcd */
1705 /* XXX: exception */
1706 void helper_aam(int base)
1708 int al, ah;
1709 al = EAX & 0xff;
1710 ah = al / base;
1711 al = al % base;
1712 EAX = (EAX & ~0xffff) | al | (ah << 8);
1713 CC_DST = al;
1716 void helper_aad(int base)
1718 int al, ah;
1719 al = EAX & 0xff;
1720 ah = (EAX >> 8) & 0xff;
1721 al = ((ah * base) + al) & 0xff;
1722 EAX = (EAX & ~0xffff) | al;
1723 CC_DST = al;
1726 void helper_aaa(void)
1728 int icarry;
1729 int al, ah, af;
1730 int eflags;
1732 eflags = helper_cc_compute_all(CC_OP);
1733 af = eflags & CC_A;
1734 al = EAX & 0xff;
1735 ah = (EAX >> 8) & 0xff;
1737 icarry = (al > 0xf9);
1738 if (((al & 0x0f) > 9 ) || af) {
1739 al = (al + 6) & 0x0f;
1740 ah = (ah + 1 + icarry) & 0xff;
1741 eflags |= CC_C | CC_A;
1742 } else {
1743 eflags &= ~(CC_C | CC_A);
1744 al &= 0x0f;
1746 EAX = (EAX & ~0xffff) | al | (ah << 8);
1747 CC_SRC = eflags;
1750 void helper_aas(void)
1752 int icarry;
1753 int al, ah, af;
1754 int eflags;
1756 eflags = helper_cc_compute_all(CC_OP);
1757 af = eflags & CC_A;
1758 al = EAX & 0xff;
1759 ah = (EAX >> 8) & 0xff;
1761 icarry = (al < 6);
1762 if (((al & 0x0f) > 9 ) || af) {
1763 al = (al - 6) & 0x0f;
1764 ah = (ah - 1 - icarry) & 0xff;
1765 eflags |= CC_C | CC_A;
1766 } else {
1767 eflags &= ~(CC_C | CC_A);
1768 al &= 0x0f;
1770 EAX = (EAX & ~0xffff) | al | (ah << 8);
1771 CC_SRC = eflags;
1774 void helper_daa(void)
1776 int al, af, cf;
1777 int eflags;
1779 eflags = helper_cc_compute_all(CC_OP);
1780 cf = eflags & CC_C;
1781 af = eflags & CC_A;
1782 al = EAX & 0xff;
1784 eflags = 0;
1785 if (((al & 0x0f) > 9 ) || af) {
1786 al = (al + 6) & 0xff;
1787 eflags |= CC_A;
1789 if ((al > 0x9f) || cf) {
1790 al = (al + 0x60) & 0xff;
1791 eflags |= CC_C;
1793 EAX = (EAX & ~0xff) | al;
1794 /* well, speed is not an issue here, so we compute the flags by hand */
1795 eflags |= (al == 0) << 6; /* zf */
1796 eflags |= parity_table[al]; /* pf */
1797 eflags |= (al & 0x80); /* sf */
1798 CC_SRC = eflags;
1801 void helper_das(void)
1803 int al, al1, af, cf;
1804 int eflags;
1806 eflags = helper_cc_compute_all(CC_OP);
1807 cf = eflags & CC_C;
1808 af = eflags & CC_A;
1809 al = EAX & 0xff;
1811 eflags = 0;
1812 al1 = al;
1813 if (((al & 0x0f) > 9 ) || af) {
1814 eflags |= CC_A;
1815 if (al < 6 || cf)
1816 eflags |= CC_C;
1817 al = (al - 6) & 0xff;
1819 if ((al1 > 0x99) || cf) {
1820 al = (al - 0x60) & 0xff;
1821 eflags |= CC_C;
1823 EAX = (EAX & ~0xff) | al;
1824 /* well, speed is not an issue here, so we compute the flags by hand */
1825 eflags |= (al == 0) << 6; /* zf */
1826 eflags |= parity_table[al]; /* pf */
1827 eflags |= (al & 0x80); /* sf */
1828 CC_SRC = eflags;
1831 void helper_into(int next_eip_addend)
1833 int eflags;
1834 eflags = helper_cc_compute_all(CC_OP);
1835 if (eflags & CC_O) {
1836 raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
1840 void helper_cmpxchg8b(target_ulong a0)
1842 uint64_t d;
1843 int eflags;
1845 eflags = helper_cc_compute_all(CC_OP);
1846 d = ldq(a0);
1847 if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
1848 stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
1849 eflags |= CC_Z;
1850 } else {
1851 /* always do the store */
1852 stq(a0, d);
1853 EDX = (uint32_t)(d >> 32);
1854 EAX = (uint32_t)d;
1855 eflags &= ~CC_Z;
1857 CC_SRC = eflags;
1860 #ifdef TARGET_X86_64
1861 void helper_cmpxchg16b(target_ulong a0)
1863 uint64_t d0, d1;
1864 int eflags;
1866 if ((a0 & 0xf) != 0)
1867 raise_exception(EXCP0D_GPF);
1868 eflags = helper_cc_compute_all(CC_OP);
1869 d0 = ldq(a0);
1870 d1 = ldq(a0 + 8);
1871 if (d0 == EAX && d1 == EDX) {
1872 stq(a0, EBX);
1873 stq(a0 + 8, ECX);
1874 eflags |= CC_Z;
1875 } else {
1876 /* always do the store */
1877 stq(a0, d0);
1878 stq(a0 + 8, d1);
1879 EDX = d1;
1880 EAX = d0;
1881 eflags &= ~CC_Z;
1883 CC_SRC = eflags;
1885 #endif
1887 void helper_single_step(void)
1889 #ifndef CONFIG_USER_ONLY
1890 check_hw_breakpoints(env, 1);
1891 env->dr[6] |= DR6_BS;
1892 #endif
1893 raise_exception(EXCP01_DB);
1896 void helper_cpuid(void)
1898 uint32_t eax, ebx, ecx, edx;
1900 helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
1902 cpu_x86_cpuid(env, (uint32_t)EAX, &eax, &ebx, &ecx, &edx);
1903 EAX = eax;
1904 EBX = ebx;
1905 ECX = ecx;
1906 EDX = edx;
1909 void helper_enter_level(int level, int data32, target_ulong t1)
1911 target_ulong ssp;
1912 uint32_t esp_mask, esp, ebp;
1914 esp_mask = get_sp_mask(env->segs[R_SS].flags);
1915 ssp = env->segs[R_SS].base;
1916 ebp = EBP;
1917 esp = ESP;
1918 if (data32) {
1919 /* 32 bit */
1920 esp -= 4;
1921 while (--level) {
1922 esp -= 4;
1923 ebp -= 4;
1924 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1926 esp -= 4;
1927 stl(ssp + (esp & esp_mask), t1);
1928 } else {
1929 /* 16 bit */
1930 esp -= 2;
1931 while (--level) {
1932 esp -= 2;
1933 ebp -= 2;
1934 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1936 esp -= 2;
1937 stw(ssp + (esp & esp_mask), t1);
1941 #ifdef TARGET_X86_64
1942 void helper_enter64_level(int level, int data64, target_ulong t1)
1944 target_ulong esp, ebp;
1945 ebp = EBP;
1946 esp = ESP;
1948 if (data64) {
1949 /* 64 bit */
1950 esp -= 8;
1951 while (--level) {
1952 esp -= 8;
1953 ebp -= 8;
1954 stq(esp, ldq(ebp));
1956 esp -= 8;
1957 stq(esp, t1);
1958 } else {
1959 /* 16 bit */
1960 esp -= 2;
1961 while (--level) {
1962 esp -= 2;
1963 ebp -= 2;
1964 stw(esp, lduw(ebp));
1966 esp -= 2;
1967 stw(esp, t1);
1970 #endif
1972 void helper_lldt(int selector)
1974 SegmentCache *dt;
1975 uint32_t e1, e2;
1976 int index, entry_limit;
1977 target_ulong ptr;
1979 selector &= 0xffff;
1980 if ((selector & 0xfffc) == 0) {
1981 /* XXX: NULL selector case: invalid LDT */
1982 env->ldt.base = 0;
1983 env->ldt.limit = 0;
1984 } else {
1985 if (selector & 0x4)
1986 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1987 dt = &env->gdt;
1988 index = selector & ~7;
1989 #ifdef TARGET_X86_64
1990 if (env->hflags & HF_LMA_MASK)
1991 entry_limit = 15;
1992 else
1993 #endif
1994 entry_limit = 7;
1995 if ((index + entry_limit) > dt->limit)
1996 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1997 ptr = dt->base + index;
1998 e1 = ldl_kernel(ptr);
1999 e2 = ldl_kernel(ptr + 4);
2000 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
2001 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2002 if (!(e2 & DESC_P_MASK))
2003 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2004 #ifdef TARGET_X86_64
2005 if (env->hflags & HF_LMA_MASK) {
2006 uint32_t e3;
2007 e3 = ldl_kernel(ptr + 8);
2008 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2009 env->ldt.base |= (target_ulong)e3 << 32;
2010 } else
2011 #endif
2013 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2016 env->ldt.selector = selector;
2019 void helper_ltr(int selector)
2021 SegmentCache *dt;
2022 uint32_t e1, e2;
2023 int index, type, entry_limit;
2024 target_ulong ptr;
2026 selector &= 0xffff;
2027 if ((selector & 0xfffc) == 0) {
2028 /* NULL selector case: invalid TR */
2029 env->tr.base = 0;
2030 env->tr.limit = 0;
2031 env->tr.flags = 0;
2032 } else {
2033 if (selector & 0x4)
2034 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2035 dt = &env->gdt;
2036 index = selector & ~7;
2037 #ifdef TARGET_X86_64
2038 if (env->hflags & HF_LMA_MASK)
2039 entry_limit = 15;
2040 else
2041 #endif
2042 entry_limit = 7;
2043 if ((index + entry_limit) > dt->limit)
2044 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2045 ptr = dt->base + index;
2046 e1 = ldl_kernel(ptr);
2047 e2 = ldl_kernel(ptr + 4);
2048 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2049 if ((e2 & DESC_S_MASK) ||
2050 (type != 1 && type != 9))
2051 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2052 if (!(e2 & DESC_P_MASK))
2053 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2054 #ifdef TARGET_X86_64
2055 if (env->hflags & HF_LMA_MASK) {
2056 uint32_t e3, e4;
2057 e3 = ldl_kernel(ptr + 8);
2058 e4 = ldl_kernel(ptr + 12);
2059 if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2060 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2061 load_seg_cache_raw_dt(&env->tr, e1, e2);
2062 env->tr.base |= (target_ulong)e3 << 32;
2063 } else
2064 #endif
2066 load_seg_cache_raw_dt(&env->tr, e1, e2);
2068 e2 |= DESC_TSS_BUSY_MASK;
2069 stl_kernel(ptr + 4, e2);
2071 env->tr.selector = selector;
2074 /* only works if protected mode and not VM86. seg_reg must be != R_CS */
2075 void helper_load_seg(int seg_reg, int selector)
2077 uint32_t e1, e2;
2078 int cpl, dpl, rpl;
2079 SegmentCache *dt;
2080 int index;
2081 target_ulong ptr;
2083 selector &= 0xffff;
2084 cpl = env->hflags & HF_CPL_MASK;
2085 if ((selector & 0xfffc) == 0) {
2086 /* null selector case */
2087 if (seg_reg == R_SS
2088 #ifdef TARGET_X86_64
2089 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2090 #endif
2092 raise_exception_err(EXCP0D_GPF, 0);
2093 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2094 } else {
2096 if (selector & 0x4)
2097 dt = &env->ldt;
2098 else
2099 dt = &env->gdt;
2100 index = selector & ~7;
2101 if ((index + 7) > dt->limit)
2102 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2103 ptr = dt->base + index;
2104 e1 = ldl_kernel(ptr);
2105 e2 = ldl_kernel(ptr + 4);
2107 if (!(e2 & DESC_S_MASK))
2108 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2109 rpl = selector & 3;
2110 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2111 if (seg_reg == R_SS) {
2112 /* must be writable segment */
2113 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2114 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2115 if (rpl != cpl || dpl != cpl)
2116 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2117 } else {
2118 /* must be readable segment */
2119 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2120 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2122 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2123 /* if not conforming code, test rights */
2124 if (dpl < cpl || dpl < rpl)
2125 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2129 if (!(e2 & DESC_P_MASK)) {
2130 if (seg_reg == R_SS)
2131 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2132 else
2133 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2136 /* set the access bit if not already set */
2137 if (!(e2 & DESC_A_MASK)) {
2138 e2 |= DESC_A_MASK;
2139 stl_kernel(ptr + 4, e2);
2142 cpu_x86_load_seg_cache(env, seg_reg, selector,
2143 get_seg_base(e1, e2),
2144 get_seg_limit(e1, e2),
2145 e2);
2146 #if 0
2147 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2148 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2149 #endif
2153 /* protected mode jump */
2154 void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2155 int next_eip_addend)
2157 int gate_cs, type;
2158 uint32_t e1, e2, cpl, dpl, rpl, limit;
2159 target_ulong next_eip;
2161 if ((new_cs & 0xfffc) == 0)
2162 raise_exception_err(EXCP0D_GPF, 0);
2163 if (load_segment(&e1, &e2, new_cs) != 0)
2164 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2165 cpl = env->hflags & HF_CPL_MASK;
2166 if (e2 & DESC_S_MASK) {
2167 if (!(e2 & DESC_CS_MASK))
2168 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2169 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2170 if (e2 & DESC_C_MASK) {
2171 /* conforming code segment */
2172 if (dpl > cpl)
2173 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2174 } else {
2175 /* non conforming code segment */
2176 rpl = new_cs & 3;
2177 if (rpl > cpl)
2178 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2179 if (dpl != cpl)
2180 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2182 if (!(e2 & DESC_P_MASK))
2183 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2184 limit = get_seg_limit(e1, e2);
2185 if (new_eip > limit &&
2186 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2187 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2188 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2189 get_seg_base(e1, e2), limit, e2);
2190 EIP = new_eip;
2191 } else {
2192 /* jump to call or task gate */
2193 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2194 rpl = new_cs & 3;
2195 cpl = env->hflags & HF_CPL_MASK;
2196 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2197 switch(type) {
2198 case 1: /* 286 TSS */
2199 case 9: /* 386 TSS */
2200 case 5: /* task gate */
2201 if (dpl < cpl || dpl < rpl)
2202 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2203 next_eip = env->eip + next_eip_addend;
2204 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2205 CC_OP = CC_OP_EFLAGS;
2206 break;
2207 case 4: /* 286 call gate */
2208 case 12: /* 386 call gate */
2209 if ((dpl < cpl) || (dpl < rpl))
2210 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2211 if (!(e2 & DESC_P_MASK))
2212 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2213 gate_cs = e1 >> 16;
2214 new_eip = (e1 & 0xffff);
2215 if (type == 12)
2216 new_eip |= (e2 & 0xffff0000);
2217 if (load_segment(&e1, &e2, gate_cs) != 0)
2218 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2219 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2220 /* must be code segment */
2221 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2222 (DESC_S_MASK | DESC_CS_MASK)))
2223 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2224 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2225 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2226 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2227 if (!(e2 & DESC_P_MASK))
2228 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2229 limit = get_seg_limit(e1, e2);
2230 if (new_eip > limit)
2231 raise_exception_err(EXCP0D_GPF, 0);
2232 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2233 get_seg_base(e1, e2), limit, e2);
2234 EIP = new_eip;
2235 break;
2236 default:
2237 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2238 break;
2243 /* real mode call */
2244 void helper_lcall_real(int new_cs, target_ulong new_eip1,
2245 int shift, int next_eip)
2247 int new_eip;
2248 uint32_t esp, esp_mask;
2249 target_ulong ssp;
2251 new_eip = new_eip1;
2252 esp = ESP;
2253 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2254 ssp = env->segs[R_SS].base;
2255 if (shift) {
2256 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2257 PUSHL(ssp, esp, esp_mask, next_eip);
2258 } else {
2259 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2260 PUSHW(ssp, esp, esp_mask, next_eip);
2263 SET_ESP(esp, esp_mask);
2264 env->eip = new_eip;
2265 env->segs[R_CS].selector = new_cs;
2266 env->segs[R_CS].base = (new_cs << 4);
2269 /* protected mode call */
2270 void helper_lcall_protected(int new_cs, target_ulong new_eip,
2271 int shift, int next_eip_addend)
2273 int new_stack, i;
2274 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2275 uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2276 uint32_t val, limit, old_sp_mask;
2277 target_ulong ssp, old_ssp, next_eip;
2279 next_eip = env->eip + next_eip_addend;
2280 #ifdef DEBUG_PCALL
2281 if (loglevel & CPU_LOG_PCALL) {
2282 fprintf(logfile, "lcall %04x:%08x s=%d\n",
2283 new_cs, (uint32_t)new_eip, shift);
2284 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2286 #endif
2287 if ((new_cs & 0xfffc) == 0)
2288 raise_exception_err(EXCP0D_GPF, 0);
2289 if (load_segment(&e1, &e2, new_cs) != 0)
2290 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2291 cpl = env->hflags & HF_CPL_MASK;
2292 #ifdef DEBUG_PCALL
2293 if (loglevel & CPU_LOG_PCALL) {
2294 fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2296 #endif
2297 if (e2 & DESC_S_MASK) {
2298 if (!(e2 & DESC_CS_MASK))
2299 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2300 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2301 if (e2 & DESC_C_MASK) {
2302 /* conforming code segment */
2303 if (dpl > cpl)
2304 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2305 } else {
2306 /* non conforming code segment */
2307 rpl = new_cs & 3;
2308 if (rpl > cpl)
2309 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2310 if (dpl != cpl)
2311 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2313 if (!(e2 & DESC_P_MASK))
2314 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2316 #ifdef TARGET_X86_64
2317 /* XXX: check 16/32 bit cases in long mode */
2318 if (shift == 2) {
2319 target_ulong rsp;
2320 /* 64 bit case */
2321 rsp = ESP;
2322 PUSHQ(rsp, env->segs[R_CS].selector);
2323 PUSHQ(rsp, next_eip);
2324 /* from this point, not restartable */
2325 ESP = rsp;
2326 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2327 get_seg_base(e1, e2),
2328 get_seg_limit(e1, e2), e2);
2329 EIP = new_eip;
2330 } else
2331 #endif
2333 sp = ESP;
2334 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2335 ssp = env->segs[R_SS].base;
2336 if (shift) {
2337 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2338 PUSHL(ssp, sp, sp_mask, next_eip);
2339 } else {
2340 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2341 PUSHW(ssp, sp, sp_mask, next_eip);
2344 limit = get_seg_limit(e1, e2);
2345 if (new_eip > limit)
2346 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2347 /* from this point, not restartable */
2348 SET_ESP(sp, sp_mask);
2349 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2350 get_seg_base(e1, e2), limit, e2);
2351 EIP = new_eip;
2353 } else {
2354 /* check gate type */
2355 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2356 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2357 rpl = new_cs & 3;
2358 switch(type) {
2359 case 1: /* available 286 TSS */
2360 case 9: /* available 386 TSS */
2361 case 5: /* task gate */
2362 if (dpl < cpl || dpl < rpl)
2363 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2364 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2365 CC_OP = CC_OP_EFLAGS;
2366 return;
2367 case 4: /* 286 call gate */
2368 case 12: /* 386 call gate */
2369 break;
2370 default:
2371 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2372 break;
2374 shift = type >> 3;
2376 if (dpl < cpl || dpl < rpl)
2377 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2378 /* check valid bit */
2379 if (!(e2 & DESC_P_MASK))
2380 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2381 selector = e1 >> 16;
2382 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2383 param_count = e2 & 0x1f;
2384 if ((selector & 0xfffc) == 0)
2385 raise_exception_err(EXCP0D_GPF, 0);
2387 if (load_segment(&e1, &e2, selector) != 0)
2388 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2389 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2390 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2391 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2392 if (dpl > cpl)
2393 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2394 if (!(e2 & DESC_P_MASK))
2395 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2397 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2398 /* to inner privilege */
2399 get_ss_esp_from_tss(&ss, &sp, dpl);
2400 #ifdef DEBUG_PCALL
2401 if (loglevel & CPU_LOG_PCALL)
2402 fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2403 ss, sp, param_count, ESP);
2404 #endif
2405 if ((ss & 0xfffc) == 0)
2406 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2407 if ((ss & 3) != dpl)
2408 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2409 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2410 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2411 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2412 if (ss_dpl != dpl)
2413 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2414 if (!(ss_e2 & DESC_S_MASK) ||
2415 (ss_e2 & DESC_CS_MASK) ||
2416 !(ss_e2 & DESC_W_MASK))
2417 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2418 if (!(ss_e2 & DESC_P_MASK))
2419 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2421 // push_size = ((param_count * 2) + 8) << shift;
2423 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2424 old_ssp = env->segs[R_SS].base;
2426 sp_mask = get_sp_mask(ss_e2);
2427 ssp = get_seg_base(ss_e1, ss_e2);
2428 if (shift) {
2429 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2430 PUSHL(ssp, sp, sp_mask, ESP);
2431 for(i = param_count - 1; i >= 0; i--) {
2432 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2433 PUSHL(ssp, sp, sp_mask, val);
2435 } else {
2436 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2437 PUSHW(ssp, sp, sp_mask, ESP);
2438 for(i = param_count - 1; i >= 0; i--) {
2439 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2440 PUSHW(ssp, sp, sp_mask, val);
2443 new_stack = 1;
2444 } else {
2445 /* to same privilege */
2446 sp = ESP;
2447 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2448 ssp = env->segs[R_SS].base;
2449 // push_size = (4 << shift);
2450 new_stack = 0;
2453 if (shift) {
2454 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2455 PUSHL(ssp, sp, sp_mask, next_eip);
2456 } else {
2457 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2458 PUSHW(ssp, sp, sp_mask, next_eip);
2461 /* from this point, not restartable */
2463 if (new_stack) {
2464 ss = (ss & ~3) | dpl;
2465 cpu_x86_load_seg_cache(env, R_SS, ss,
2466 ssp,
2467 get_seg_limit(ss_e1, ss_e2),
2468 ss_e2);
2471 selector = (selector & ~3) | dpl;
2472 cpu_x86_load_seg_cache(env, R_CS, selector,
2473 get_seg_base(e1, e2),
2474 get_seg_limit(e1, e2),
2475 e2);
2476 cpu_x86_set_cpl(env, dpl);
2477 SET_ESP(sp, sp_mask);
2478 EIP = offset;
2480 #ifdef USE_KQEMU
2481 if (kqemu_is_ok(env)) {
2482 env->exception_index = -1;
2483 cpu_loop_exit();
2485 #endif
2488 /* real and vm86 mode iret */
2489 void helper_iret_real(int shift)
2491 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2492 target_ulong ssp;
2493 int eflags_mask;
2495 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2496 sp = ESP;
2497 ssp = env->segs[R_SS].base;
2498 if (shift == 1) {
2499 /* 32 bits */
2500 POPL(ssp, sp, sp_mask, new_eip);
2501 POPL(ssp, sp, sp_mask, new_cs);
2502 new_cs &= 0xffff;
2503 POPL(ssp, sp, sp_mask, new_eflags);
2504 } else {
2505 /* 16 bits */
2506 POPW(ssp, sp, sp_mask, new_eip);
2507 POPW(ssp, sp, sp_mask, new_cs);
2508 POPW(ssp, sp, sp_mask, new_eflags);
2510 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2511 env->segs[R_CS].selector = new_cs;
2512 env->segs[R_CS].base = (new_cs << 4);
2513 env->eip = new_eip;
2514 if (env->eflags & VM_MASK)
2515 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2516 else
2517 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2518 if (shift == 0)
2519 eflags_mask &= 0xffff;
2520 load_eflags(new_eflags, eflags_mask);
2521 env->hflags2 &= ~HF2_NMI_MASK;
2524 static inline void validate_seg(int seg_reg, int cpl)
2526 int dpl;
2527 uint32_t e2;
2529 /* XXX: on x86_64, we do not want to nullify FS and GS because
2530 they may still contain a valid base. I would be interested to
2531 know how a real x86_64 CPU behaves */
2532 if ((seg_reg == R_FS || seg_reg == R_GS) &&
2533 (env->segs[seg_reg].selector & 0xfffc) == 0)
2534 return;
2536 e2 = env->segs[seg_reg].flags;
2537 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2538 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2539 /* data or non conforming code segment */
2540 if (dpl < cpl) {
2541 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2546 /* protected mode iret */
2547 static inline void helper_ret_protected(int shift, int is_iret, int addend)
2549 uint32_t new_cs, new_eflags, new_ss;
2550 uint32_t new_es, new_ds, new_fs, new_gs;
2551 uint32_t e1, e2, ss_e1, ss_e2;
2552 int cpl, dpl, rpl, eflags_mask, iopl;
2553 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2555 #ifdef TARGET_X86_64
2556 if (shift == 2)
2557 sp_mask = -1;
2558 else
2559 #endif
2560 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2561 sp = ESP;
2562 ssp = env->segs[R_SS].base;
2563 new_eflags = 0; /* avoid warning */
2564 #ifdef TARGET_X86_64
2565 if (shift == 2) {
2566 POPQ(sp, new_eip);
2567 POPQ(sp, new_cs);
2568 new_cs &= 0xffff;
2569 if (is_iret) {
2570 POPQ(sp, new_eflags);
2572 } else
2573 #endif
2574 if (shift == 1) {
2575 /* 32 bits */
2576 POPL(ssp, sp, sp_mask, new_eip);
2577 POPL(ssp, sp, sp_mask, new_cs);
2578 new_cs &= 0xffff;
2579 if (is_iret) {
2580 POPL(ssp, sp, sp_mask, new_eflags);
2581 if (new_eflags & VM_MASK)
2582 goto return_to_vm86;
2584 } else {
2585 /* 16 bits */
2586 POPW(ssp, sp, sp_mask, new_eip);
2587 POPW(ssp, sp, sp_mask, new_cs);
2588 if (is_iret)
2589 POPW(ssp, sp, sp_mask, new_eflags);
2591 #ifdef DEBUG_PCALL
2592 if (loglevel & CPU_LOG_PCALL) {
2593 fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2594 new_cs, new_eip, shift, addend);
2595 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2597 #endif
2598 if ((new_cs & 0xfffc) == 0)
2599 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2600 if (load_segment(&e1, &e2, new_cs) != 0)
2601 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2602 if (!(e2 & DESC_S_MASK) ||
2603 !(e2 & DESC_CS_MASK))
2604 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2605 cpl = env->hflags & HF_CPL_MASK;
2606 rpl = new_cs & 3;
2607 if (rpl < cpl)
2608 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2609 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2610 if (e2 & DESC_C_MASK) {
2611 if (dpl > rpl)
2612 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2613 } else {
2614 if (dpl != rpl)
2615 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2617 if (!(e2 & DESC_P_MASK))
2618 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2620 sp += addend;
2621 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2622 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2623 /* return to same privilege level */
2624 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2625 get_seg_base(e1, e2),
2626 get_seg_limit(e1, e2),
2627 e2);
2628 } else {
2629 /* return to different privilege level */
2630 #ifdef TARGET_X86_64
2631 if (shift == 2) {
2632 POPQ(sp, new_esp);
2633 POPQ(sp, new_ss);
2634 new_ss &= 0xffff;
2635 } else
2636 #endif
2637 if (shift == 1) {
2638 /* 32 bits */
2639 POPL(ssp, sp, sp_mask, new_esp);
2640 POPL(ssp, sp, sp_mask, new_ss);
2641 new_ss &= 0xffff;
2642 } else {
2643 /* 16 bits */
2644 POPW(ssp, sp, sp_mask, new_esp);
2645 POPW(ssp, sp, sp_mask, new_ss);
2647 #ifdef DEBUG_PCALL
2648 if (loglevel & CPU_LOG_PCALL) {
2649 fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2650 new_ss, new_esp);
2652 #endif
2653 if ((new_ss & 0xfffc) == 0) {
2654 #ifdef TARGET_X86_64
2655 /* NULL ss is allowed in long mode if cpl != 3*/
2656 /* XXX: test CS64 ? */
2657 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2658 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2659 0, 0xffffffff,
2660 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2661 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2662 DESC_W_MASK | DESC_A_MASK);
2663 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2664 } else
2665 #endif
2667 raise_exception_err(EXCP0D_GPF, 0);
2669 } else {
2670 if ((new_ss & 3) != rpl)
2671 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2672 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2673 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2674 if (!(ss_e2 & DESC_S_MASK) ||
2675 (ss_e2 & DESC_CS_MASK) ||
2676 !(ss_e2 & DESC_W_MASK))
2677 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2678 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2679 if (dpl != rpl)
2680 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2681 if (!(ss_e2 & DESC_P_MASK))
2682 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2683 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2684 get_seg_base(ss_e1, ss_e2),
2685 get_seg_limit(ss_e1, ss_e2),
2686 ss_e2);
2689 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2690 get_seg_base(e1, e2),
2691 get_seg_limit(e1, e2),
2692 e2);
2693 cpu_x86_set_cpl(env, rpl);
2694 sp = new_esp;
2695 #ifdef TARGET_X86_64
2696 if (env->hflags & HF_CS64_MASK)
2697 sp_mask = -1;
2698 else
2699 #endif
2700 sp_mask = get_sp_mask(ss_e2);
2702 /* validate data segments */
2703 validate_seg(R_ES, rpl);
2704 validate_seg(R_DS, rpl);
2705 validate_seg(R_FS, rpl);
2706 validate_seg(R_GS, rpl);
2708 sp += addend;
2710 SET_ESP(sp, sp_mask);
2711 env->eip = new_eip;
2712 if (is_iret) {
2713 /* NOTE: 'cpl' is the _old_ CPL */
2714 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2715 if (cpl == 0)
2716 eflags_mask |= IOPL_MASK;
2717 iopl = (env->eflags >> IOPL_SHIFT) & 3;
2718 if (cpl <= iopl)
2719 eflags_mask |= IF_MASK;
2720 if (shift == 0)
2721 eflags_mask &= 0xffff;
2722 load_eflags(new_eflags, eflags_mask);
2724 return;
2726 return_to_vm86:
2727 POPL(ssp, sp, sp_mask, new_esp);
2728 POPL(ssp, sp, sp_mask, new_ss);
2729 POPL(ssp, sp, sp_mask, new_es);
2730 POPL(ssp, sp, sp_mask, new_ds);
2731 POPL(ssp, sp, sp_mask, new_fs);
2732 POPL(ssp, sp, sp_mask, new_gs);
2734 /* modify processor state */
2735 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2736 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2737 load_seg_vm(R_CS, new_cs & 0xffff);
2738 cpu_x86_set_cpl(env, 3);
2739 load_seg_vm(R_SS, new_ss & 0xffff);
2740 load_seg_vm(R_ES, new_es & 0xffff);
2741 load_seg_vm(R_DS, new_ds & 0xffff);
2742 load_seg_vm(R_FS, new_fs & 0xffff);
2743 load_seg_vm(R_GS, new_gs & 0xffff);
2745 env->eip = new_eip & 0xffff;
2746 ESP = new_esp;
2749 void helper_iret_protected(int shift, int next_eip)
2751 int tss_selector, type;
2752 uint32_t e1, e2;
2754 /* specific case for TSS */
2755 if (env->eflags & NT_MASK) {
2756 #ifdef TARGET_X86_64
2757 if (env->hflags & HF_LMA_MASK)
2758 raise_exception_err(EXCP0D_GPF, 0);
2759 #endif
2760 tss_selector = lduw_kernel(env->tr.base + 0);
2761 if (tss_selector & 4)
2762 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2763 if (load_segment(&e1, &e2, tss_selector) != 0)
2764 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2765 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2766 /* NOTE: we check both segment and busy TSS */
2767 if (type != 3)
2768 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2769 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2770 } else {
2771 helper_ret_protected(shift, 1, 0);
2773 env->hflags2 &= ~HF2_NMI_MASK;
2774 #ifdef USE_KQEMU
2775 if (kqemu_is_ok(env)) {
2776 CC_OP = CC_OP_EFLAGS;
2777 env->exception_index = -1;
2778 cpu_loop_exit();
2780 #endif
2783 void helper_lret_protected(int shift, int addend)
2785 helper_ret_protected(shift, 0, addend);
2786 #ifdef USE_KQEMU
2787 if (kqemu_is_ok(env)) {
2788 env->exception_index = -1;
2789 cpu_loop_exit();
2791 #endif
2794 void helper_sysenter(void)
2796 if (env->sysenter_cs == 0) {
2797 raise_exception_err(EXCP0D_GPF, 0);
2799 env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2800 cpu_x86_set_cpl(env, 0);
2802 #ifdef TARGET_X86_64
2803 if (env->hflags & HF_LMA_MASK) {
2804 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2805 0, 0xffffffff,
2806 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2807 DESC_S_MASK |
2808 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2809 } else
2810 #endif
2812 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2813 0, 0xffffffff,
2814 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2815 DESC_S_MASK |
2816 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2818 cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2819 0, 0xffffffff,
2820 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2821 DESC_S_MASK |
2822 DESC_W_MASK | DESC_A_MASK);
2823 ESP = env->sysenter_esp;
2824 EIP = env->sysenter_eip;
2827 void helper_sysexit(int dflag)
2829 int cpl;
2831 cpl = env->hflags & HF_CPL_MASK;
2832 if (env->sysenter_cs == 0 || cpl != 0) {
2833 raise_exception_err(EXCP0D_GPF, 0);
2835 cpu_x86_set_cpl(env, 3);
2836 #ifdef TARGET_X86_64
2837 if (dflag == 2) {
2838 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
2839 0, 0xffffffff,
2840 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2841 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2842 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2843 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
2844 0, 0xffffffff,
2845 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2846 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2847 DESC_W_MASK | DESC_A_MASK);
2848 } else
2849 #endif
2851 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2852 0, 0xffffffff,
2853 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2854 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2855 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2856 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2857 0, 0xffffffff,
2858 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2859 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2860 DESC_W_MASK | DESC_A_MASK);
2862 ESP = ECX;
2863 EIP = EDX;
2864 #ifdef USE_KQEMU
2865 if (kqemu_is_ok(env)) {
2866 env->exception_index = -1;
2867 cpu_loop_exit();
2869 #endif
2872 #if defined(CONFIG_USER_ONLY)
2873 target_ulong helper_read_crN(int reg)
2875 return 0;
2878 void helper_write_crN(int reg, target_ulong t0)
2882 void helper_movl_drN_T0(int reg, target_ulong t0)
2885 #else
2886 target_ulong helper_read_crN(int reg)
2888 target_ulong val;
2890 helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
2891 switch(reg) {
2892 default:
2893 val = env->cr[reg];
2894 break;
2895 case 8:
2896 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2897 val = cpu_get_apic_tpr(env);
2898 } else {
2899 val = env->v_tpr;
2901 break;
2903 return val;
2906 void helper_write_crN(int reg, target_ulong t0)
2908 helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
2909 switch(reg) {
2910 case 0:
2911 cpu_x86_update_cr0(env, t0);
2912 break;
2913 case 3:
2914 cpu_x86_update_cr3(env, t0);
2915 break;
2916 case 4:
2917 cpu_x86_update_cr4(env, t0);
2918 break;
2919 case 8:
2920 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2921 cpu_set_apic_tpr(env, t0);
2923 env->v_tpr = t0 & 0x0f;
2924 break;
2925 default:
2926 env->cr[reg] = t0;
2927 break;
2931 void helper_movl_drN_T0(int reg, target_ulong t0)
2933 int i;
2935 if (reg < 4) {
2936 hw_breakpoint_remove(env, reg);
2937 env->dr[reg] = t0;
2938 hw_breakpoint_insert(env, reg);
2939 } else if (reg == 7) {
2940 for (i = 0; i < 4; i++)
2941 hw_breakpoint_remove(env, i);
2942 env->dr[7] = t0;
2943 for (i = 0; i < 4; i++)
2944 hw_breakpoint_insert(env, i);
2945 } else
2946 env->dr[reg] = t0;
2948 #endif
2950 void helper_lmsw(target_ulong t0)
2952 /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
2953 if already set to one. */
2954 t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
2955 helper_write_crN(0, t0);
2958 void helper_clts(void)
2960 env->cr[0] &= ~CR0_TS_MASK;
2961 env->hflags &= ~HF_TS_MASK;
2964 void helper_invlpg(target_ulong addr)
2966 helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
2967 tlb_flush_page(env, addr);
2970 void helper_rdtsc(void)
2972 uint64_t val;
2974 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2975 raise_exception(EXCP0D_GPF);
2977 helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
2979 val = cpu_get_tsc(env) + env->tsc_offset;
2980 EAX = (uint32_t)(val);
2981 EDX = (uint32_t)(val >> 32);
2984 void helper_rdpmc(void)
2986 if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2987 raise_exception(EXCP0D_GPF);
2989 helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
2991 /* currently unimplemented */
2992 raise_exception_err(EXCP06_ILLOP, 0);
2995 #if defined(CONFIG_USER_ONLY)
2996 void helper_wrmsr(void)
3000 void helper_rdmsr(void)
3003 #else
3004 void helper_wrmsr(void)
3006 uint64_t val;
3008 helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
3010 val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
3012 switch((uint32_t)ECX) {
3013 case MSR_IA32_SYSENTER_CS:
3014 env->sysenter_cs = val & 0xffff;
3015 break;
3016 case MSR_IA32_SYSENTER_ESP:
3017 env->sysenter_esp = val;
3018 break;
3019 case MSR_IA32_SYSENTER_EIP:
3020 env->sysenter_eip = val;
3021 break;
3022 case MSR_IA32_APICBASE:
3023 cpu_set_apic_base(env, val);
3024 break;
3025 case MSR_EFER:
3027 uint64_t update_mask;
3028 update_mask = 0;
3029 if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3030 update_mask |= MSR_EFER_SCE;
3031 if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3032 update_mask |= MSR_EFER_LME;
3033 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3034 update_mask |= MSR_EFER_FFXSR;
3035 if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3036 update_mask |= MSR_EFER_NXE;
3037 if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
3038 update_mask |= MSR_EFER_SVME;
3039 cpu_load_efer(env, (env->efer & ~update_mask) |
3040 (val & update_mask));
3042 break;
3043 case MSR_STAR:
3044 env->star = val;
3045 break;
3046 case MSR_PAT:
3047 env->pat = val;
3048 break;
3049 case MSR_VM_HSAVE_PA:
3050 env->vm_hsave = val;
3051 break;
3052 #ifdef TARGET_X86_64
3053 case MSR_LSTAR:
3054 env->lstar = val;
3055 break;
3056 case MSR_CSTAR:
3057 env->cstar = val;
3058 break;
3059 case MSR_FMASK:
3060 env->fmask = val;
3061 break;
3062 case MSR_FSBASE:
3063 env->segs[R_FS].base = val;
3064 break;
3065 case MSR_GSBASE:
3066 env->segs[R_GS].base = val;
3067 break;
3068 case MSR_KERNELGSBASE:
3069 env->kernelgsbase = val;
3070 break;
3071 #endif
3072 default:
3073 /* XXX: exception ? */
3074 break;
3078 void helper_rdmsr(void)
3080 uint64_t val;
3082 helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3084 switch((uint32_t)ECX) {
3085 case MSR_IA32_SYSENTER_CS:
3086 val = env->sysenter_cs;
3087 break;
3088 case MSR_IA32_SYSENTER_ESP:
3089 val = env->sysenter_esp;
3090 break;
3091 case MSR_IA32_SYSENTER_EIP:
3092 val = env->sysenter_eip;
3093 break;
3094 case MSR_IA32_APICBASE:
3095 val = cpu_get_apic_base(env);
3096 break;
3097 case MSR_EFER:
3098 val = env->efer;
3099 break;
3100 case MSR_STAR:
3101 val = env->star;
3102 break;
3103 case MSR_PAT:
3104 val = env->pat;
3105 break;
3106 case MSR_VM_HSAVE_PA:
3107 val = env->vm_hsave;
3108 break;
3109 case MSR_IA32_PERF_STATUS:
3110 /* tsc_increment_by_tick */
3111 val = 1000ULL;
3112 /* CPU multiplier */
3113 val |= (((uint64_t)4ULL) << 40);
3114 break;
3115 #ifdef TARGET_X86_64
3116 case MSR_LSTAR:
3117 val = env->lstar;
3118 break;
3119 case MSR_CSTAR:
3120 val = env->cstar;
3121 break;
3122 case MSR_FMASK:
3123 val = env->fmask;
3124 break;
3125 case MSR_FSBASE:
3126 val = env->segs[R_FS].base;
3127 break;
3128 case MSR_GSBASE:
3129 val = env->segs[R_GS].base;
3130 break;
3131 case MSR_KERNELGSBASE:
3132 val = env->kernelgsbase;
3133 break;
3134 #endif
3135 #ifdef USE_KQEMU
3136 case MSR_QPI_COMMBASE:
3137 if (env->kqemu_enabled) {
3138 val = kqemu_comm_base;
3139 } else {
3140 val = 0;
3142 break;
3143 #endif
3144 default:
3145 /* XXX: exception ? */
3146 val = 0;
3147 break;
3149 EAX = (uint32_t)(val);
3150 EDX = (uint32_t)(val >> 32);
3152 #endif
3154 target_ulong helper_lsl(target_ulong selector1)
3156 unsigned int limit;
3157 uint32_t e1, e2, eflags, selector;
3158 int rpl, dpl, cpl, type;
3160 selector = selector1 & 0xffff;
3161 eflags = helper_cc_compute_all(CC_OP);
3162 if (load_segment(&e1, &e2, selector) != 0)
3163 goto fail;
3164 rpl = selector & 3;
3165 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3166 cpl = env->hflags & HF_CPL_MASK;
3167 if (e2 & DESC_S_MASK) {
3168 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3169 /* conforming */
3170 } else {
3171 if (dpl < cpl || dpl < rpl)
3172 goto fail;
3174 } else {
3175 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3176 switch(type) {
3177 case 1:
3178 case 2:
3179 case 3:
3180 case 9:
3181 case 11:
3182 break;
3183 default:
3184 goto fail;
3186 if (dpl < cpl || dpl < rpl) {
3187 fail:
3188 CC_SRC = eflags & ~CC_Z;
3189 return 0;
3192 limit = get_seg_limit(e1, e2);
3193 CC_SRC = eflags | CC_Z;
3194 return limit;
3197 target_ulong helper_lar(target_ulong selector1)
3199 uint32_t e1, e2, eflags, selector;
3200 int rpl, dpl, cpl, type;
3202 selector = selector1 & 0xffff;
3203 eflags = helper_cc_compute_all(CC_OP);
3204 if ((selector & 0xfffc) == 0)
3205 goto fail;
3206 if (load_segment(&e1, &e2, selector) != 0)
3207 goto fail;
3208 rpl = selector & 3;
3209 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3210 cpl = env->hflags & HF_CPL_MASK;
3211 if (e2 & DESC_S_MASK) {
3212 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3213 /* conforming */
3214 } else {
3215 if (dpl < cpl || dpl < rpl)
3216 goto fail;
3218 } else {
3219 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3220 switch(type) {
3221 case 1:
3222 case 2:
3223 case 3:
3224 case 4:
3225 case 5:
3226 case 9:
3227 case 11:
3228 case 12:
3229 break;
3230 default:
3231 goto fail;
3233 if (dpl < cpl || dpl < rpl) {
3234 fail:
3235 CC_SRC = eflags & ~CC_Z;
3236 return 0;
3239 CC_SRC = eflags | CC_Z;
3240 return e2 & 0x00f0ff00;
3243 void helper_verr(target_ulong selector1)
3245 uint32_t e1, e2, eflags, selector;
3246 int rpl, dpl, cpl;
3248 selector = selector1 & 0xffff;
3249 eflags = helper_cc_compute_all(CC_OP);
3250 if ((selector & 0xfffc) == 0)
3251 goto fail;
3252 if (load_segment(&e1, &e2, selector) != 0)
3253 goto fail;
3254 if (!(e2 & DESC_S_MASK))
3255 goto fail;
3256 rpl = selector & 3;
3257 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3258 cpl = env->hflags & HF_CPL_MASK;
3259 if (e2 & DESC_CS_MASK) {
3260 if (!(e2 & DESC_R_MASK))
3261 goto fail;
3262 if (!(e2 & DESC_C_MASK)) {
3263 if (dpl < cpl || dpl < rpl)
3264 goto fail;
3266 } else {
3267 if (dpl < cpl || dpl < rpl) {
3268 fail:
3269 CC_SRC = eflags & ~CC_Z;
3270 return;
3273 CC_SRC = eflags | CC_Z;
3276 void helper_verw(target_ulong selector1)
3278 uint32_t e1, e2, eflags, selector;
3279 int rpl, dpl, cpl;
3281 selector = selector1 & 0xffff;
3282 eflags = helper_cc_compute_all(CC_OP);
3283 if ((selector & 0xfffc) == 0)
3284 goto fail;
3285 if (load_segment(&e1, &e2, selector) != 0)
3286 goto fail;
3287 if (!(e2 & DESC_S_MASK))
3288 goto fail;
3289 rpl = selector & 3;
3290 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3291 cpl = env->hflags & HF_CPL_MASK;
3292 if (e2 & DESC_CS_MASK) {
3293 goto fail;
3294 } else {
3295 if (dpl < cpl || dpl < rpl)
3296 goto fail;
3297 if (!(e2 & DESC_W_MASK)) {
3298 fail:
3299 CC_SRC = eflags & ~CC_Z;
3300 return;
3303 CC_SRC = eflags | CC_Z;
3306 /* x87 FPU helpers */
3308 static void fpu_set_exception(int mask)
3310 env->fpus |= mask;
3311 if (env->fpus & (~env->fpuc & FPUC_EM))
3312 env->fpus |= FPUS_SE | FPUS_B;
3315 static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3317 if (b == 0.0)
3318 fpu_set_exception(FPUS_ZE);
3319 return a / b;
3322 void fpu_raise_exception(void)
3324 if (env->cr[0] & CR0_NE_MASK) {
3325 raise_exception(EXCP10_COPR);
3327 #if !defined(CONFIG_USER_ONLY)
3328 else {
3329 cpu_set_ferr(env);
3331 #endif
3334 void helper_flds_FT0(uint32_t val)
3336 union {
3337 float32 f;
3338 uint32_t i;
3339 } u;
3340 u.i = val;
3341 FT0 = float32_to_floatx(u.f, &env->fp_status);
3344 void helper_fldl_FT0(uint64_t val)
3346 union {
3347 float64 f;
3348 uint64_t i;
3349 } u;
3350 u.i = val;
3351 FT0 = float64_to_floatx(u.f, &env->fp_status);
3354 void helper_fildl_FT0(int32_t val)
3356 FT0 = int32_to_floatx(val, &env->fp_status);
3359 void helper_flds_ST0(uint32_t val)
3361 int new_fpstt;
3362 union {
3363 float32 f;
3364 uint32_t i;
3365 } u;
3366 new_fpstt = (env->fpstt - 1) & 7;
3367 u.i = val;
3368 env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
3369 env->fpstt = new_fpstt;
3370 env->fptags[new_fpstt] = 0; /* validate stack entry */
3373 void helper_fldl_ST0(uint64_t val)
3375 int new_fpstt;
3376 union {
3377 float64 f;
3378 uint64_t i;
3379 } u;
3380 new_fpstt = (env->fpstt - 1) & 7;
3381 u.i = val;
3382 env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
3383 env->fpstt = new_fpstt;
3384 env->fptags[new_fpstt] = 0; /* validate stack entry */
3387 void helper_fildl_ST0(int32_t val)
3389 int new_fpstt;
3390 new_fpstt = (env->fpstt - 1) & 7;
3391 env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
3392 env->fpstt = new_fpstt;
3393 env->fptags[new_fpstt] = 0; /* validate stack entry */
3396 void helper_fildll_ST0(int64_t val)
3398 int new_fpstt;
3399 new_fpstt = (env->fpstt - 1) & 7;
3400 env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
3401 env->fpstt = new_fpstt;
3402 env->fptags[new_fpstt] = 0; /* validate stack entry */
3405 uint32_t helper_fsts_ST0(void)
3407 union {
3408 float32 f;
3409 uint32_t i;
3410 } u;
3411 u.f = floatx_to_float32(ST0, &env->fp_status);
3412 return u.i;
3415 uint64_t helper_fstl_ST0(void)
3417 union {
3418 float64 f;
3419 uint64_t i;
3420 } u;
3421 u.f = floatx_to_float64(ST0, &env->fp_status);
3422 return u.i;
3425 int32_t helper_fist_ST0(void)
3427 int32_t val;
3428 val = floatx_to_int32(ST0, &env->fp_status);
3429 if (val != (int16_t)val)
3430 val = -32768;
3431 return val;
3434 int32_t helper_fistl_ST0(void)
3436 int32_t val;
3437 val = floatx_to_int32(ST0, &env->fp_status);
3438 return val;
3441 int64_t helper_fistll_ST0(void)
3443 int64_t val;
3444 val = floatx_to_int64(ST0, &env->fp_status);
3445 return val;
3448 int32_t helper_fistt_ST0(void)
3450 int32_t val;
3451 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3452 if (val != (int16_t)val)
3453 val = -32768;
3454 return val;
3457 int32_t helper_fisttl_ST0(void)
3459 int32_t val;
3460 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3461 return val;
3464 int64_t helper_fisttll_ST0(void)
3466 int64_t val;
3467 val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
3468 return val;
3471 void helper_fldt_ST0(target_ulong ptr)
3473 int new_fpstt;
3474 new_fpstt = (env->fpstt - 1) & 7;
3475 env->fpregs[new_fpstt].d = helper_fldt(ptr);
3476 env->fpstt = new_fpstt;
3477 env->fptags[new_fpstt] = 0; /* validate stack entry */
3480 void helper_fstt_ST0(target_ulong ptr)
3482 helper_fstt(ST0, ptr);
3485 void helper_fpush(void)
3487 fpush();
3490 void helper_fpop(void)
3492 fpop();
3495 void helper_fdecstp(void)
3497 env->fpstt = (env->fpstt - 1) & 7;
3498 env->fpus &= (~0x4700);
3501 void helper_fincstp(void)
3503 env->fpstt = (env->fpstt + 1) & 7;
3504 env->fpus &= (~0x4700);
3507 /* FPU move */
3509 void helper_ffree_STN(int st_index)
3511 env->fptags[(env->fpstt + st_index) & 7] = 1;
3514 void helper_fmov_ST0_FT0(void)
3516 ST0 = FT0;
3519 void helper_fmov_FT0_STN(int st_index)
3521 FT0 = ST(st_index);
3524 void helper_fmov_ST0_STN(int st_index)
3526 ST0 = ST(st_index);
3529 void helper_fmov_STN_ST0(int st_index)
3531 ST(st_index) = ST0;
3534 void helper_fxchg_ST0_STN(int st_index)
3536 CPU86_LDouble tmp;
3537 tmp = ST(st_index);
3538 ST(st_index) = ST0;
3539 ST0 = tmp;
3542 /* FPU operations */
3544 static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
3546 void helper_fcom_ST0_FT0(void)
3548 int ret;
3550 ret = floatx_compare(ST0, FT0, &env->fp_status);
3551 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
3554 void helper_fucom_ST0_FT0(void)
3556 int ret;
3558 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3559 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
3562 static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
3564 void helper_fcomi_ST0_FT0(void)
3566 int eflags;
3567 int ret;
3569 ret = floatx_compare(ST0, FT0, &env->fp_status);
3570 eflags = helper_cc_compute_all(CC_OP);
3571 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3572 CC_SRC = eflags;
3575 void helper_fucomi_ST0_FT0(void)
3577 int eflags;
3578 int ret;
3580 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3581 eflags = helper_cc_compute_all(CC_OP);
3582 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3583 CC_SRC = eflags;
3586 void helper_fadd_ST0_FT0(void)
3588 ST0 += FT0;
3591 void helper_fmul_ST0_FT0(void)
3593 ST0 *= FT0;
3596 void helper_fsub_ST0_FT0(void)
3598 ST0 -= FT0;
3601 void helper_fsubr_ST0_FT0(void)
3603 ST0 = FT0 - ST0;
3606 void helper_fdiv_ST0_FT0(void)
3608 ST0 = helper_fdiv(ST0, FT0);
3611 void helper_fdivr_ST0_FT0(void)
3613 ST0 = helper_fdiv(FT0, ST0);
3616 /* fp operations between STN and ST0 */
3618 void helper_fadd_STN_ST0(int st_index)
3620 ST(st_index) += ST0;
3623 void helper_fmul_STN_ST0(int st_index)
3625 ST(st_index) *= ST0;
3628 void helper_fsub_STN_ST0(int st_index)
3630 ST(st_index) -= ST0;
3633 void helper_fsubr_STN_ST0(int st_index)
3635 CPU86_LDouble *p;
3636 p = &ST(st_index);
3637 *p = ST0 - *p;
3640 void helper_fdiv_STN_ST0(int st_index)
3642 CPU86_LDouble *p;
3643 p = &ST(st_index);
3644 *p = helper_fdiv(*p, ST0);
3647 void helper_fdivr_STN_ST0(int st_index)
3649 CPU86_LDouble *p;
3650 p = &ST(st_index);
3651 *p = helper_fdiv(ST0, *p);
3654 /* misc FPU operations */
3655 void helper_fchs_ST0(void)
3657 ST0 = floatx_chs(ST0);
3660 void helper_fabs_ST0(void)
3662 ST0 = floatx_abs(ST0);
3665 void helper_fld1_ST0(void)
3667 ST0 = f15rk[1];
3670 void helper_fldl2t_ST0(void)
3672 ST0 = f15rk[6];
3675 void helper_fldl2e_ST0(void)
3677 ST0 = f15rk[5];
3680 void helper_fldpi_ST0(void)
3682 ST0 = f15rk[2];
3685 void helper_fldlg2_ST0(void)
3687 ST0 = f15rk[3];
3690 void helper_fldln2_ST0(void)
3692 ST0 = f15rk[4];
3695 void helper_fldz_ST0(void)
3697 ST0 = f15rk[0];
3700 void helper_fldz_FT0(void)
3702 FT0 = f15rk[0];
3705 uint32_t helper_fnstsw(void)
3707 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3710 uint32_t helper_fnstcw(void)
3712 return env->fpuc;
3715 static void update_fp_status(void)
3717 int rnd_type;
3719 /* set rounding mode */
3720 switch(env->fpuc & RC_MASK) {
3721 default:
3722 case RC_NEAR:
3723 rnd_type = float_round_nearest_even;
3724 break;
3725 case RC_DOWN:
3726 rnd_type = float_round_down;
3727 break;
3728 case RC_UP:
3729 rnd_type = float_round_up;
3730 break;
3731 case RC_CHOP:
3732 rnd_type = float_round_to_zero;
3733 break;
3735 set_float_rounding_mode(rnd_type, &env->fp_status);
3736 #ifdef FLOATX80
3737 switch((env->fpuc >> 8) & 3) {
3738 case 0:
3739 rnd_type = 32;
3740 break;
3741 case 2:
3742 rnd_type = 64;
3743 break;
3744 case 3:
3745 default:
3746 rnd_type = 80;
3747 break;
3749 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3750 #endif
3753 void helper_fldcw(uint32_t val)
3755 env->fpuc = val;
3756 update_fp_status();
3759 void helper_fclex(void)
3761 env->fpus &= 0x7f00;
3764 void helper_fwait(void)
3766 if (env->fpus & FPUS_SE)
3767 fpu_raise_exception();
3770 void helper_fninit(void)
3772 env->fpus = 0;
3773 env->fpstt = 0;
3774 env->fpuc = 0x37f;
3775 env->fptags[0] = 1;
3776 env->fptags[1] = 1;
3777 env->fptags[2] = 1;
3778 env->fptags[3] = 1;
3779 env->fptags[4] = 1;
3780 env->fptags[5] = 1;
3781 env->fptags[6] = 1;
3782 env->fptags[7] = 1;
3785 /* BCD ops */
3787 void helper_fbld_ST0(target_ulong ptr)
3789 CPU86_LDouble tmp;
3790 uint64_t val;
3791 unsigned int v;
3792 int i;
3794 val = 0;
3795 for(i = 8; i >= 0; i--) {
3796 v = ldub(ptr + i);
3797 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3799 tmp = val;
3800 if (ldub(ptr + 9) & 0x80)
3801 tmp = -tmp;
3802 fpush();
3803 ST0 = tmp;
3806 void helper_fbst_ST0(target_ulong ptr)
3808 int v;
3809 target_ulong mem_ref, mem_end;
3810 int64_t val;
3812 val = floatx_to_int64(ST0, &env->fp_status);
3813 mem_ref = ptr;
3814 mem_end = mem_ref + 9;
3815 if (val < 0) {
3816 stb(mem_end, 0x80);
3817 val = -val;
3818 } else {
3819 stb(mem_end, 0x00);
3821 while (mem_ref < mem_end) {
3822 if (val == 0)
3823 break;
3824 v = val % 100;
3825 val = val / 100;
3826 v = ((v / 10) << 4) | (v % 10);
3827 stb(mem_ref++, v);
3829 while (mem_ref < mem_end) {
3830 stb(mem_ref++, 0);
3834 void helper_f2xm1(void)
3836 ST0 = pow(2.0,ST0) - 1.0;
3839 void helper_fyl2x(void)
3841 CPU86_LDouble fptemp;
3843 fptemp = ST0;
3844 if (fptemp>0.0){
3845 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
3846 ST1 *= fptemp;
3847 fpop();
3848 } else {
3849 env->fpus &= (~0x4700);
3850 env->fpus |= 0x400;
3854 void helper_fptan(void)
3856 CPU86_LDouble fptemp;
3858 fptemp = ST0;
3859 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3860 env->fpus |= 0x400;
3861 } else {
3862 ST0 = tan(fptemp);
3863 fpush();
3864 ST0 = 1.0;
3865 env->fpus &= (~0x400); /* C2 <-- 0 */
3866 /* the above code is for |arg| < 2**52 only */
3870 void helper_fpatan(void)
3872 CPU86_LDouble fptemp, fpsrcop;
3874 fpsrcop = ST1;
3875 fptemp = ST0;
3876 ST1 = atan2(fpsrcop,fptemp);
3877 fpop();
3880 void helper_fxtract(void)
3882 CPU86_LDoubleU temp;
3883 unsigned int expdif;
3885 temp.d = ST0;
3886 expdif = EXPD(temp) - EXPBIAS;
3887 /*DP exponent bias*/
3888 ST0 = expdif;
3889 fpush();
3890 BIASEXPONENT(temp);
3891 ST0 = temp.d;
3894 void helper_fprem1(void)
3896 CPU86_LDouble dblq, fpsrcop, fptemp;
3897 CPU86_LDoubleU fpsrcop1, fptemp1;
3898 int expdif;
3899 signed long long int q;
3901 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3902 ST0 = 0.0 / 0.0; /* NaN */
3903 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3904 return;
3907 fpsrcop = ST0;
3908 fptemp = ST1;
3909 fpsrcop1.d = fpsrcop;
3910 fptemp1.d = fptemp;
3911 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3913 if (expdif < 0) {
3914 /* optimisation? taken from the AMD docs */
3915 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3916 /* ST0 is unchanged */
3917 return;
3920 if (expdif < 53) {
3921 dblq = fpsrcop / fptemp;
3922 /* round dblq towards nearest integer */
3923 dblq = rint(dblq);
3924 ST0 = fpsrcop - fptemp * dblq;
3926 /* convert dblq to q by truncating towards zero */
3927 if (dblq < 0.0)
3928 q = (signed long long int)(-dblq);
3929 else
3930 q = (signed long long int)dblq;
3932 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3933 /* (C0,C3,C1) <-- (q2,q1,q0) */
3934 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3935 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3936 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
3937 } else {
3938 env->fpus |= 0x400; /* C2 <-- 1 */
3939 fptemp = pow(2.0, expdif - 50);
3940 fpsrcop = (ST0 / ST1) / fptemp;
3941 /* fpsrcop = integer obtained by chopping */
3942 fpsrcop = (fpsrcop < 0.0) ?
3943 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3944 ST0 -= (ST1 * fpsrcop * fptemp);
3948 void helper_fprem(void)
3950 CPU86_LDouble dblq, fpsrcop, fptemp;
3951 CPU86_LDoubleU fpsrcop1, fptemp1;
3952 int expdif;
3953 signed long long int q;
3955 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3956 ST0 = 0.0 / 0.0; /* NaN */
3957 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3958 return;
3961 fpsrcop = (CPU86_LDouble)ST0;
3962 fptemp = (CPU86_LDouble)ST1;
3963 fpsrcop1.d = fpsrcop;
3964 fptemp1.d = fptemp;
3965 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3967 if (expdif < 0) {
3968 /* optimisation? taken from the AMD docs */
3969 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3970 /* ST0 is unchanged */
3971 return;
3974 if ( expdif < 53 ) {
3975 dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
3976 /* round dblq towards zero */
3977 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
3978 ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
3980 /* convert dblq to q by truncating towards zero */
3981 if (dblq < 0.0)
3982 q = (signed long long int)(-dblq);
3983 else
3984 q = (signed long long int)dblq;
3986 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3987 /* (C0,C3,C1) <-- (q2,q1,q0) */
3988 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3989 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3990 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
3991 } else {
3992 int N = 32 + (expdif % 32); /* as per AMD docs */
3993 env->fpus |= 0x400; /* C2 <-- 1 */
3994 fptemp = pow(2.0, (double)(expdif - N));
3995 fpsrcop = (ST0 / ST1) / fptemp;
3996 /* fpsrcop = integer obtained by chopping */
3997 fpsrcop = (fpsrcop < 0.0) ?
3998 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3999 ST0 -= (ST1 * fpsrcop * fptemp);
4003 void helper_fyl2xp1(void)
4005 CPU86_LDouble fptemp;
4007 fptemp = ST0;
4008 if ((fptemp+1.0)>0.0) {
4009 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
4010 ST1 *= fptemp;
4011 fpop();
4012 } else {
4013 env->fpus &= (~0x4700);
4014 env->fpus |= 0x400;
4018 void helper_fsqrt(void)
4020 CPU86_LDouble fptemp;
4022 fptemp = ST0;
4023 if (fptemp<0.0) {
4024 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4025 env->fpus |= 0x400;
4027 ST0 = sqrt(fptemp);
4030 void helper_fsincos(void)
4032 CPU86_LDouble fptemp;
4034 fptemp = ST0;
4035 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4036 env->fpus |= 0x400;
4037 } else {
4038 ST0 = sin(fptemp);
4039 fpush();
4040 ST0 = cos(fptemp);
4041 env->fpus &= (~0x400); /* C2 <-- 0 */
4042 /* the above code is for |arg| < 2**63 only */
4046 void helper_frndint(void)
4048 ST0 = floatx_round_to_int(ST0, &env->fp_status);
4051 void helper_fscale(void)
4053 ST0 = ldexp (ST0, (int)(ST1));
4056 void helper_fsin(void)
4058 CPU86_LDouble fptemp;
4060 fptemp = ST0;
4061 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4062 env->fpus |= 0x400;
4063 } else {
4064 ST0 = sin(fptemp);
4065 env->fpus &= (~0x400); /* C2 <-- 0 */
4066 /* the above code is for |arg| < 2**53 only */
4070 void helper_fcos(void)
4072 CPU86_LDouble fptemp;
4074 fptemp = ST0;
4075 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4076 env->fpus |= 0x400;
4077 } else {
4078 ST0 = cos(fptemp);
4079 env->fpus &= (~0x400); /* C2 <-- 0 */
4080 /* the above code is for |arg5 < 2**63 only */
4084 void helper_fxam_ST0(void)
4086 CPU86_LDoubleU temp;
4087 int expdif;
4089 temp.d = ST0;
4091 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4092 if (SIGND(temp))
4093 env->fpus |= 0x200; /* C1 <-- 1 */
4095 /* XXX: test fptags too */
4096 expdif = EXPD(temp);
4097 if (expdif == MAXEXPD) {
4098 #ifdef USE_X86LDOUBLE
4099 if (MANTD(temp) == 0x8000000000000000ULL)
4100 #else
4101 if (MANTD(temp) == 0)
4102 #endif
4103 env->fpus |= 0x500 /*Infinity*/;
4104 else
4105 env->fpus |= 0x100 /*NaN*/;
4106 } else if (expdif == 0) {
4107 if (MANTD(temp) == 0)
4108 env->fpus |= 0x4000 /*Zero*/;
4109 else
4110 env->fpus |= 0x4400 /*Denormal*/;
4111 } else {
4112 env->fpus |= 0x400;
4116 void helper_fstenv(target_ulong ptr, int data32)
4118 int fpus, fptag, exp, i;
4119 uint64_t mant;
4120 CPU86_LDoubleU tmp;
4122 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4123 fptag = 0;
4124 for (i=7; i>=0; i--) {
4125 fptag <<= 2;
4126 if (env->fptags[i]) {
4127 fptag |= 3;
4128 } else {
4129 tmp.d = env->fpregs[i].d;
4130 exp = EXPD(tmp);
4131 mant = MANTD(tmp);
4132 if (exp == 0 && mant == 0) {
4133 /* zero */
4134 fptag |= 1;
4135 } else if (exp == 0 || exp == MAXEXPD
4136 #ifdef USE_X86LDOUBLE
4137 || (mant & (1LL << 63)) == 0
4138 #endif
4140 /* NaNs, infinity, denormal */
4141 fptag |= 2;
4145 if (data32) {
4146 /* 32 bit */
4147 stl(ptr, env->fpuc);
4148 stl(ptr + 4, fpus);
4149 stl(ptr + 8, fptag);
4150 stl(ptr + 12, 0); /* fpip */
4151 stl(ptr + 16, 0); /* fpcs */
4152 stl(ptr + 20, 0); /* fpoo */
4153 stl(ptr + 24, 0); /* fpos */
4154 } else {
4155 /* 16 bit */
4156 stw(ptr, env->fpuc);
4157 stw(ptr + 2, fpus);
4158 stw(ptr + 4, fptag);
4159 stw(ptr + 6, 0);
4160 stw(ptr + 8, 0);
4161 stw(ptr + 10, 0);
4162 stw(ptr + 12, 0);
4166 void helper_fldenv(target_ulong ptr, int data32)
4168 int i, fpus, fptag;
4170 if (data32) {
4171 env->fpuc = lduw(ptr);
4172 fpus = lduw(ptr + 4);
4173 fptag = lduw(ptr + 8);
4175 else {
4176 env->fpuc = lduw(ptr);
4177 fpus = lduw(ptr + 2);
4178 fptag = lduw(ptr + 4);
4180 env->fpstt = (fpus >> 11) & 7;
4181 env->fpus = fpus & ~0x3800;
4182 for(i = 0;i < 8; i++) {
4183 env->fptags[i] = ((fptag & 3) == 3);
4184 fptag >>= 2;
4188 void helper_fsave(target_ulong ptr, int data32)
4190 CPU86_LDouble tmp;
4191 int i;
4193 helper_fstenv(ptr, data32);
4195 ptr += (14 << data32);
4196 for(i = 0;i < 8; i++) {
4197 tmp = ST(i);
4198 helper_fstt(tmp, ptr);
4199 ptr += 10;
4202 /* fninit */
4203 env->fpus = 0;
4204 env->fpstt = 0;
4205 env->fpuc = 0x37f;
4206 env->fptags[0] = 1;
4207 env->fptags[1] = 1;
4208 env->fptags[2] = 1;
4209 env->fptags[3] = 1;
4210 env->fptags[4] = 1;
4211 env->fptags[5] = 1;
4212 env->fptags[6] = 1;
4213 env->fptags[7] = 1;
4216 void helper_frstor(target_ulong ptr, int data32)
4218 CPU86_LDouble tmp;
4219 int i;
4221 helper_fldenv(ptr, data32);
4222 ptr += (14 << data32);
4224 for(i = 0;i < 8; i++) {
4225 tmp = helper_fldt(ptr);
4226 ST(i) = tmp;
4227 ptr += 10;
4231 void helper_fxsave(target_ulong ptr, int data64)
4233 int fpus, fptag, i, nb_xmm_regs;
4234 CPU86_LDouble tmp;
4235 target_ulong addr;
4237 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4238 fptag = 0;
4239 for(i = 0; i < 8; i++) {
4240 fptag |= (env->fptags[i] << i);
4242 stw(ptr, env->fpuc);
4243 stw(ptr + 2, fpus);
4244 stw(ptr + 4, fptag ^ 0xff);
4245 #ifdef TARGET_X86_64
4246 if (data64) {
4247 stq(ptr + 0x08, 0); /* rip */
4248 stq(ptr + 0x10, 0); /* rdp */
4249 } else
4250 #endif
4252 stl(ptr + 0x08, 0); /* eip */
4253 stl(ptr + 0x0c, 0); /* sel */
4254 stl(ptr + 0x10, 0); /* dp */
4255 stl(ptr + 0x14, 0); /* sel */
4258 addr = ptr + 0x20;
4259 for(i = 0;i < 8; i++) {
4260 tmp = ST(i);
4261 helper_fstt(tmp, addr);
4262 addr += 16;
4265 if (env->cr[4] & CR4_OSFXSR_MASK) {
4266 /* XXX: finish it */
4267 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4268 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4269 if (env->hflags & HF_CS64_MASK)
4270 nb_xmm_regs = 16;
4271 else
4272 nb_xmm_regs = 8;
4273 addr = ptr + 0xa0;
4274 for(i = 0; i < nb_xmm_regs; i++) {
4275 stq(addr, env->xmm_regs[i].XMM_Q(0));
4276 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4277 addr += 16;
4282 void helper_fxrstor(target_ulong ptr, int data64)
4284 int i, fpus, fptag, nb_xmm_regs;
4285 CPU86_LDouble tmp;
4286 target_ulong addr;
4288 env->fpuc = lduw(ptr);
4289 fpus = lduw(ptr + 2);
4290 fptag = lduw(ptr + 4);
4291 env->fpstt = (fpus >> 11) & 7;
4292 env->fpus = fpus & ~0x3800;
4293 fptag ^= 0xff;
4294 for(i = 0;i < 8; i++) {
4295 env->fptags[i] = ((fptag >> i) & 1);
4298 addr = ptr + 0x20;
4299 for(i = 0;i < 8; i++) {
4300 tmp = helper_fldt(addr);
4301 ST(i) = tmp;
4302 addr += 16;
4305 if (env->cr[4] & CR4_OSFXSR_MASK) {
4306 /* XXX: finish it */
4307 env->mxcsr = ldl(ptr + 0x18);
4308 //ldl(ptr + 0x1c);
4309 if (env->hflags & HF_CS64_MASK)
4310 nb_xmm_regs = 16;
4311 else
4312 nb_xmm_regs = 8;
4313 addr = ptr + 0xa0;
4314 for(i = 0; i < nb_xmm_regs; i++) {
4315 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4316 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4317 addr += 16;
4322 #ifndef USE_X86LDOUBLE
4324 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4326 CPU86_LDoubleU temp;
4327 int e;
4329 temp.d = f;
4330 /* mantissa */
4331 *pmant = (MANTD(temp) << 11) | (1LL << 63);
4332 /* exponent + sign */
4333 e = EXPD(temp) - EXPBIAS + 16383;
4334 e |= SIGND(temp) >> 16;
4335 *pexp = e;
4338 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4340 CPU86_LDoubleU temp;
4341 int e;
4342 uint64_t ll;
4344 /* XXX: handle overflow ? */
4345 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
4346 e |= (upper >> 4) & 0x800; /* sign */
4347 ll = (mant >> 11) & ((1LL << 52) - 1);
4348 #ifdef __arm__
4349 temp.l.upper = (e << 20) | (ll >> 32);
4350 temp.l.lower = ll;
4351 #else
4352 temp.ll = ll | ((uint64_t)e << 52);
4353 #endif
4354 return temp.d;
4357 #else
4359 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4361 CPU86_LDoubleU temp;
4363 temp.d = f;
4364 *pmant = temp.l.lower;
4365 *pexp = temp.l.upper;
4368 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4370 CPU86_LDoubleU temp;
4372 temp.l.upper = upper;
4373 temp.l.lower = mant;
4374 return temp.d;
4376 #endif
4378 #ifdef TARGET_X86_64
4380 //#define DEBUG_MULDIV
4382 static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4384 *plow += a;
4385 /* carry test */
4386 if (*plow < a)
4387 (*phigh)++;
4388 *phigh += b;
4391 static void neg128(uint64_t *plow, uint64_t *phigh)
4393 *plow = ~ *plow;
4394 *phigh = ~ *phigh;
4395 add128(plow, phigh, 1, 0);
4398 /* return TRUE if overflow */
4399 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4401 uint64_t q, r, a1, a0;
4402 int i, qb, ab;
4404 a0 = *plow;
4405 a1 = *phigh;
4406 if (a1 == 0) {
4407 q = a0 / b;
4408 r = a0 % b;
4409 *plow = q;
4410 *phigh = r;
4411 } else {
4412 if (a1 >= b)
4413 return 1;
4414 /* XXX: use a better algorithm */
4415 for(i = 0; i < 64; i++) {
4416 ab = a1 >> 63;
4417 a1 = (a1 << 1) | (a0 >> 63);
4418 if (ab || a1 >= b) {
4419 a1 -= b;
4420 qb = 1;
4421 } else {
4422 qb = 0;
4424 a0 = (a0 << 1) | qb;
4426 #if defined(DEBUG_MULDIV)
4427 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
4428 *phigh, *plow, b, a0, a1);
4429 #endif
4430 *plow = a0;
4431 *phigh = a1;
4433 return 0;
4436 /* return TRUE if overflow */
4437 static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
4439 int sa, sb;
4440 sa = ((int64_t)*phigh < 0);
4441 if (sa)
4442 neg128(plow, phigh);
4443 sb = (b < 0);
4444 if (sb)
4445 b = -b;
4446 if (div64(plow, phigh, b) != 0)
4447 return 1;
4448 if (sa ^ sb) {
4449 if (*plow > (1ULL << 63))
4450 return 1;
4451 *plow = - *plow;
4452 } else {
4453 if (*plow >= (1ULL << 63))
4454 return 1;
4456 if (sa)
4457 *phigh = - *phigh;
4458 return 0;
4461 void helper_mulq_EAX_T0(target_ulong t0)
4463 uint64_t r0, r1;
4465 mulu64(&r0, &r1, EAX, t0);
4466 EAX = r0;
4467 EDX = r1;
4468 CC_DST = r0;
4469 CC_SRC = r1;
4472 void helper_imulq_EAX_T0(target_ulong t0)
4474 uint64_t r0, r1;
4476 muls64(&r0, &r1, EAX, t0);
4477 EAX = r0;
4478 EDX = r1;
4479 CC_DST = r0;
4480 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4483 target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
4485 uint64_t r0, r1;
4487 muls64(&r0, &r1, t0, t1);
4488 CC_DST = r0;
4489 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4490 return r0;
4493 void helper_divq_EAX(target_ulong t0)
4495 uint64_t r0, r1;
4496 if (t0 == 0) {
4497 raise_exception(EXCP00_DIVZ);
4499 r0 = EAX;
4500 r1 = EDX;
4501 if (div64(&r0, &r1, t0))
4502 raise_exception(EXCP00_DIVZ);
4503 EAX = r0;
4504 EDX = r1;
4507 void helper_idivq_EAX(target_ulong t0)
4509 uint64_t r0, r1;
4510 if (t0 == 0) {
4511 raise_exception(EXCP00_DIVZ);
4513 r0 = EAX;
4514 r1 = EDX;
4515 if (idiv64(&r0, &r1, t0))
4516 raise_exception(EXCP00_DIVZ);
4517 EAX = r0;
4518 EDX = r1;
4520 #endif
4522 static void do_hlt(void)
4524 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
4525 env->halted = 1;
4526 env->exception_index = EXCP_HLT;
4527 cpu_loop_exit();
4530 void helper_hlt(int next_eip_addend)
4532 helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
4533 EIP += next_eip_addend;
4535 do_hlt();
4538 void helper_monitor(target_ulong ptr)
4540 if ((uint32_t)ECX != 0)
4541 raise_exception(EXCP0D_GPF);
4542 /* XXX: store address ? */
4543 helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
4546 void helper_mwait(int next_eip_addend)
4548 if ((uint32_t)ECX != 0)
4549 raise_exception(EXCP0D_GPF);
4550 helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
4551 EIP += next_eip_addend;
4553 /* XXX: not complete but not completely erroneous */
4554 if (env->cpu_index != 0 || env->next_cpu != NULL) {
4555 /* more than one CPU: do not sleep because another CPU may
4556 wake this one */
4557 } else {
4558 do_hlt();
4562 void helper_debug(void)
4564 env->exception_index = EXCP_DEBUG;
4565 cpu_loop_exit();
4568 void helper_raise_interrupt(int intno, int next_eip_addend)
4570 raise_interrupt(intno, 1, 0, next_eip_addend);
4573 void helper_raise_exception(int exception_index)
4575 raise_exception(exception_index);
4578 void helper_cli(void)
4580 env->eflags &= ~IF_MASK;
4583 void helper_sti(void)
4585 env->eflags |= IF_MASK;
4588 #if 0
4589 /* vm86plus instructions */
4590 void helper_cli_vm(void)
4592 env->eflags &= ~VIF_MASK;
4595 void helper_sti_vm(void)
4597 env->eflags |= VIF_MASK;
4598 if (env->eflags & VIP_MASK) {
4599 raise_exception(EXCP0D_GPF);
4602 #endif
4604 void helper_set_inhibit_irq(void)
4606 env->hflags |= HF_INHIBIT_IRQ_MASK;
4609 void helper_reset_inhibit_irq(void)
4611 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4614 void helper_boundw(target_ulong a0, int v)
4616 int low, high;
4617 low = ldsw(a0);
4618 high = ldsw(a0 + 2);
4619 v = (int16_t)v;
4620 if (v < low || v > high) {
4621 raise_exception(EXCP05_BOUND);
4625 void helper_boundl(target_ulong a0, int v)
4627 int low, high;
4628 low = ldl(a0);
4629 high = ldl(a0 + 4);
4630 if (v < low || v > high) {
4631 raise_exception(EXCP05_BOUND);
4635 static float approx_rsqrt(float a)
4637 return 1.0 / sqrt(a);
4640 static float approx_rcp(float a)
4642 return 1.0 / a;
4645 #if !defined(CONFIG_USER_ONLY)
4647 #define MMUSUFFIX _mmu
4649 #define SHIFT 0
4650 #include "softmmu_template.h"
4652 #define SHIFT 1
4653 #include "softmmu_template.h"
4655 #define SHIFT 2
4656 #include "softmmu_template.h"
4658 #define SHIFT 3
4659 #include "softmmu_template.h"
4661 #endif
4663 /* try to fill the TLB and return an exception if error. If retaddr is
4664 NULL, it means that the function was called in C code (i.e. not
4665 from generated code or from helper.c) */
4666 /* XXX: fix it to restore all registers */
4667 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
4669 TranslationBlock *tb;
4670 int ret;
4671 unsigned long pc;
4672 CPUX86State *saved_env;
4674 /* XXX: hack to restore env in all cases, even if not called from
4675 generated code */
4676 saved_env = env;
4677 env = cpu_single_env;
4679 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
4680 if (ret) {
4681 if (retaddr) {
4682 /* now we have a real cpu fault */
4683 pc = (unsigned long)retaddr;
4684 tb = tb_find_pc(pc);
4685 if (tb) {
4686 /* the PC is inside the translated code. It means that we have
4687 a virtual CPU fault */
4688 cpu_restore_state(tb, env, pc, NULL);
4691 raise_exception_err(env->exception_index, env->error_code);
4693 env = saved_env;
4697 /* Secure Virtual Machine helpers */
4699 #if defined(CONFIG_USER_ONLY)
4701 void helper_vmrun(int aflag, int next_eip_addend)
4704 void helper_vmmcall(void)
4707 void helper_vmload(int aflag)
4710 void helper_vmsave(int aflag)
4713 void helper_stgi(void)
4716 void helper_clgi(void)
4719 void helper_skinit(void)
4722 void helper_invlpga(int aflag)
4725 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
4728 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
4732 void helper_svm_check_io(uint32_t port, uint32_t param,
4733 uint32_t next_eip_addend)
4736 #else
4738 static inline void svm_save_seg(target_phys_addr_t addr,
4739 const SegmentCache *sc)
4741 stw_phys(addr + offsetof(struct vmcb_seg, selector),
4742 sc->selector);
4743 stq_phys(addr + offsetof(struct vmcb_seg, base),
4744 sc->base);
4745 stl_phys(addr + offsetof(struct vmcb_seg, limit),
4746 sc->limit);
4747 stw_phys(addr + offsetof(struct vmcb_seg, attrib),
4748 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
4751 static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
4753 unsigned int flags;
4755 sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
4756 sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
4757 sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
4758 flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
4759 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
4762 static inline void svm_load_seg_cache(target_phys_addr_t addr,
4763 CPUState *env, int seg_reg)
4765 SegmentCache sc1, *sc = &sc1;
4766 svm_load_seg(addr, sc);
4767 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
4768 sc->base, sc->limit, sc->flags);
4771 void helper_vmrun(int aflag, int next_eip_addend)
4773 target_ulong addr;
4774 uint32_t event_inj;
4775 uint32_t int_ctl;
4777 helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
4779 if (aflag == 2)
4780 addr = EAX;
4781 else
4782 addr = (uint32_t)EAX;
4784 if (loglevel & CPU_LOG_TB_IN_ASM)
4785 fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
4787 env->vm_vmcb = addr;
4789 /* save the current CPU state in the hsave page */
4790 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4791 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4793 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4794 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4796 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
4797 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
4798 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
4799 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
4800 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
4801 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
4803 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
4804 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
4806 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
4807 &env->segs[R_ES]);
4808 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
4809 &env->segs[R_CS]);
4810 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
4811 &env->segs[R_SS]);
4812 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
4813 &env->segs[R_DS]);
4815 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
4816 EIP + next_eip_addend);
4817 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4818 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4820 /* load the interception bitmaps so we do not need to access the
4821 vmcb in svm mode */
4822 env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
4823 env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4824 env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4825 env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4826 env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4827 env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4829 /* enable intercepts */
4830 env->hflags |= HF_SVMI_MASK;
4832 env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
4834 env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4835 env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4837 env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4838 env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4840 /* clear exit_info_2 so we behave like the real hardware */
4841 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4843 cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4844 cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4845 cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4846 env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4847 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
4848 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
4849 if (int_ctl & V_INTR_MASKING_MASK) {
4850 env->v_tpr = int_ctl & V_TPR_MASK;
4851 env->hflags2 |= HF2_VINTR_MASK;
4852 if (env->eflags & IF_MASK)
4853 env->hflags2 |= HF2_HIF_MASK;
4856 cpu_load_efer(env,
4857 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
4858 env->eflags = 0;
4859 load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
4860 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4861 CC_OP = CC_OP_EFLAGS;
4863 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
4864 env, R_ES);
4865 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
4866 env, R_CS);
4867 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
4868 env, R_SS);
4869 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
4870 env, R_DS);
4872 EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
4873 env->eip = EIP;
4874 ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
4875 EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
4876 env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
4877 env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
4878 cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
4880 /* FIXME: guest state consistency checks */
4882 switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
4883 case TLB_CONTROL_DO_NOTHING:
4884 break;
4885 case TLB_CONTROL_FLUSH_ALL_ASID:
4886 /* FIXME: this is not 100% correct but should work for now */
4887 tlb_flush(env, 1);
4888 break;
4891 env->hflags2 |= HF2_GIF_MASK;
4893 if (int_ctl & V_IRQ_MASK) {
4894 env->interrupt_request |= CPU_INTERRUPT_VIRQ;
4897 /* maybe we need to inject an event */
4898 event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
4899 if (event_inj & SVM_EVTINJ_VALID) {
4900 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4901 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
4902 uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
4903 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
4905 if (loglevel & CPU_LOG_TB_IN_ASM)
4906 fprintf(logfile, "Injecting(%#hx): ", valid_err);
4907 /* FIXME: need to implement valid_err */
4908 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4909 case SVM_EVTINJ_TYPE_INTR:
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, "INTR");
4916 /* XXX: is it always correct ? */
4917 do_interrupt(vector, 0, 0, 0, 1);
4918 break;
4919 case SVM_EVTINJ_TYPE_NMI:
4920 env->exception_index = EXCP02_NMI;
4921 env->error_code = event_inj_err;
4922 env->exception_is_int = 0;
4923 env->exception_next_eip = EIP;
4924 if (loglevel & CPU_LOG_TB_IN_ASM)
4925 fprintf(logfile, "NMI");
4926 cpu_loop_exit();
4927 break;
4928 case SVM_EVTINJ_TYPE_EXEPT:
4929 env->exception_index = vector;
4930 env->error_code = event_inj_err;
4931 env->exception_is_int = 0;
4932 env->exception_next_eip = -1;
4933 if (loglevel & CPU_LOG_TB_IN_ASM)
4934 fprintf(logfile, "EXEPT");
4935 cpu_loop_exit();
4936 break;
4937 case SVM_EVTINJ_TYPE_SOFT:
4938 env->exception_index = vector;
4939 env->error_code = event_inj_err;
4940 env->exception_is_int = 1;
4941 env->exception_next_eip = EIP;
4942 if (loglevel & CPU_LOG_TB_IN_ASM)
4943 fprintf(logfile, "SOFT");
4944 cpu_loop_exit();
4945 break;
4947 if (loglevel & CPU_LOG_TB_IN_ASM)
4948 fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
4952 void helper_vmmcall(void)
4954 helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
4955 raise_exception(EXCP06_ILLOP);
4958 void helper_vmload(int aflag)
4960 target_ulong addr;
4961 helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
4963 if (aflag == 2)
4964 addr = EAX;
4965 else
4966 addr = (uint32_t)EAX;
4968 if (loglevel & CPU_LOG_TB_IN_ASM)
4969 fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4970 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4971 env->segs[R_FS].base);
4973 svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
4974 env, R_FS);
4975 svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
4976 env, R_GS);
4977 svm_load_seg(addr + offsetof(struct vmcb, save.tr),
4978 &env->tr);
4979 svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
4980 &env->ldt);
4982 #ifdef TARGET_X86_64
4983 env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
4984 env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
4985 env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
4986 env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
4987 #endif
4988 env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
4989 env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
4990 env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
4991 env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
4994 void helper_vmsave(int aflag)
4996 target_ulong addr;
4997 helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
4999 if (aflag == 2)
5000 addr = EAX;
5001 else
5002 addr = (uint32_t)EAX;
5004 if (loglevel & CPU_LOG_TB_IN_ASM)
5005 fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5006 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5007 env->segs[R_FS].base);
5009 svm_save_seg(addr + offsetof(struct vmcb, save.fs),
5010 &env->segs[R_FS]);
5011 svm_save_seg(addr + offsetof(struct vmcb, save.gs),
5012 &env->segs[R_GS]);
5013 svm_save_seg(addr + offsetof(struct vmcb, save.tr),
5014 &env->tr);
5015 svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
5016 &env->ldt);
5018 #ifdef TARGET_X86_64
5019 stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
5020 stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
5021 stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
5022 stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
5023 #endif
5024 stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5025 stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5026 stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5027 stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5030 void helper_stgi(void)
5032 helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
5033 env->hflags2 |= HF2_GIF_MASK;
5036 void helper_clgi(void)
5038 helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
5039 env->hflags2 &= ~HF2_GIF_MASK;
5042 void helper_skinit(void)
5044 helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
5045 /* XXX: not implemented */
5046 raise_exception(EXCP06_ILLOP);
5049 void helper_invlpga(int aflag)
5051 target_ulong addr;
5052 helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
5054 if (aflag == 2)
5055 addr = EAX;
5056 else
5057 addr = (uint32_t)EAX;
5059 /* XXX: could use the ASID to see if it is needed to do the
5060 flush */
5061 tlb_flush_page(env, addr);
5064 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5066 if (likely(!(env->hflags & HF_SVMI_MASK)))
5067 return;
5068 switch(type) {
5069 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
5070 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
5071 helper_vmexit(type, param);
5073 break;
5074 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5075 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
5076 helper_vmexit(type, param);
5078 break;
5079 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
5080 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
5081 helper_vmexit(type, param);
5083 break;
5084 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
5085 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
5086 helper_vmexit(type, param);
5088 break;
5089 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
5090 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
5091 helper_vmexit(type, param);
5093 break;
5094 case SVM_EXIT_MSR:
5095 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
5096 /* FIXME: this should be read in at vmrun (faster this way?) */
5097 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5098 uint32_t t0, t1;
5099 switch((uint32_t)ECX) {
5100 case 0 ... 0x1fff:
5101 t0 = (ECX * 2) % 8;
5102 t1 = ECX / 8;
5103 break;
5104 case 0xc0000000 ... 0xc0001fff:
5105 t0 = (8192 + ECX - 0xc0000000) * 2;
5106 t1 = (t0 / 8);
5107 t0 %= 8;
5108 break;
5109 case 0xc0010000 ... 0xc0011fff:
5110 t0 = (16384 + ECX - 0xc0010000) * 2;
5111 t1 = (t0 / 8);
5112 t0 %= 8;
5113 break;
5114 default:
5115 helper_vmexit(type, param);
5116 t0 = 0;
5117 t1 = 0;
5118 break;
5120 if (ldub_phys(addr + t1) & ((1 << param) << t0))
5121 helper_vmexit(type, param);
5123 break;
5124 default:
5125 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
5126 helper_vmexit(type, param);
5128 break;
5132 void helper_svm_check_io(uint32_t port, uint32_t param,
5133 uint32_t next_eip_addend)
5135 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
5136 /* FIXME: this should be read in at vmrun (faster this way?) */
5137 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5138 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5139 if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5140 /* next EIP */
5141 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
5142 env->eip + next_eip_addend);
5143 helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5148 /* Note: currently only 32 bits of exit_code are used */
5149 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5151 uint32_t int_ctl;
5153 if (loglevel & CPU_LOG_TB_IN_ASM)
5154 fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5155 exit_code, exit_info_1,
5156 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5157 EIP);
5159 if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5160 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5161 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5162 } else {
5163 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5166 /* Save the VM state in the vmcb */
5167 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
5168 &env->segs[R_ES]);
5169 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5170 &env->segs[R_CS]);
5171 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5172 &env->segs[R_SS]);
5173 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5174 &env->segs[R_DS]);
5176 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5177 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5179 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5180 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5182 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5183 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5184 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5185 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5186 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5188 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5189 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
5190 int_ctl |= env->v_tpr & V_TPR_MASK;
5191 if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
5192 int_ctl |= V_IRQ_MASK;
5193 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
5195 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5196 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5197 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5198 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5199 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5200 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5201 stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5203 /* Reload the host state from vm_hsave */
5204 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
5205 env->hflags &= ~HF_SVMI_MASK;
5206 env->intercept = 0;
5207 env->intercept_exceptions = 0;
5208 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
5209 env->tsc_offset = 0;
5211 env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5212 env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5214 env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5215 env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5217 cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5218 cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5219 cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5220 /* we need to set the efer after the crs so the hidden flags get
5221 set properly */
5222 cpu_load_efer(env,
5223 ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
5224 env->eflags = 0;
5225 load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5226 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5227 CC_OP = CC_OP_EFLAGS;
5229 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
5230 env, R_ES);
5231 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
5232 env, R_CS);
5233 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
5234 env, R_SS);
5235 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
5236 env, R_DS);
5238 EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5239 ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5240 EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5242 env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5243 env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5245 /* other setups */
5246 cpu_x86_set_cpl(env, 0);
5247 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5248 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5250 env->hflags2 &= ~HF2_GIF_MASK;
5251 /* FIXME: Resets the current ASID register to zero (host ASID). */
5253 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5255 /* Clears the TSC_OFFSET inside the processor. */
5257 /* If the host is in PAE mode, the processor reloads the host's PDPEs
5258 from the page table indicated the host's CR3. If the PDPEs contain
5259 illegal state, the processor causes a shutdown. */
5261 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5262 env->cr[0] |= CR0_PE_MASK;
5263 env->eflags &= ~VM_MASK;
5265 /* Disables all breakpoints in the host DR7 register. */
5267 /* Checks the reloaded host state for consistency. */
5269 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5270 host's code segment or non-canonical (in the case of long mode), a
5271 #GP fault is delivered inside the host.) */
5273 /* remove any pending exception */
5274 env->exception_index = -1;
5275 env->error_code = 0;
5276 env->old_exception = -1;
5278 cpu_loop_exit();
5281 #endif
5283 /* MMX/SSE */
5284 /* XXX: optimize by storing fptt and fptags in the static cpu state */
5285 void helper_enter_mmx(void)
5287 env->fpstt = 0;
5288 *(uint32_t *)(env->fptags) = 0;
5289 *(uint32_t *)(env->fptags + 4) = 0;
5292 void helper_emms(void)
5294 /* set to empty state */
5295 *(uint32_t *)(env->fptags) = 0x01010101;
5296 *(uint32_t *)(env->fptags + 4) = 0x01010101;
5299 /* XXX: suppress */
5300 void helper_movq(void *d, void *s)
5302 *(uint64_t *)d = *(uint64_t *)s;
5305 #define SHIFT 0
5306 #include "ops_sse.h"
5308 #define SHIFT 1
5309 #include "ops_sse.h"
5311 #define SHIFT 0
5312 #include "helper_template.h"
5313 #undef SHIFT
5315 #define SHIFT 1
5316 #include "helper_template.h"
5317 #undef SHIFT
5319 #define SHIFT 2
5320 #include "helper_template.h"
5321 #undef SHIFT
5323 #ifdef TARGET_X86_64
5325 #define SHIFT 3
5326 #include "helper_template.h"
5327 #undef SHIFT
5329 #endif
5331 /* bit operations */
5332 target_ulong helper_bsf(target_ulong t0)
5334 int count;
5335 target_ulong res;
5337 res = t0;
5338 count = 0;
5339 while ((res & 1) == 0) {
5340 count++;
5341 res >>= 1;
5343 return count;
5346 target_ulong helper_bsr(target_ulong t0)
5348 int count;
5349 target_ulong res, mask;
5351 res = t0;
5352 count = TARGET_LONG_BITS - 1;
5353 mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5354 while ((res & mask) == 0) {
5355 count--;
5356 res <<= 1;
5358 return count;
5362 static int compute_all_eflags(void)
5364 return CC_SRC;
5367 static int compute_c_eflags(void)
5369 return CC_SRC & CC_C;
5372 uint32_t helper_cc_compute_all(int op)
5374 switch (op) {
5375 default: /* should never happen */ return 0;
5377 case CC_OP_EFLAGS: return compute_all_eflags();
5379 case CC_OP_MULB: return compute_all_mulb();
5380 case CC_OP_MULW: return compute_all_mulw();
5381 case CC_OP_MULL: return compute_all_mull();
5383 case CC_OP_ADDB: return compute_all_addb();
5384 case CC_OP_ADDW: return compute_all_addw();
5385 case CC_OP_ADDL: return compute_all_addl();
5387 case CC_OP_ADCB: return compute_all_adcb();
5388 case CC_OP_ADCW: return compute_all_adcw();
5389 case CC_OP_ADCL: return compute_all_adcl();
5391 case CC_OP_SUBB: return compute_all_subb();
5392 case CC_OP_SUBW: return compute_all_subw();
5393 case CC_OP_SUBL: return compute_all_subl();
5395 case CC_OP_SBBB: return compute_all_sbbb();
5396 case CC_OP_SBBW: return compute_all_sbbw();
5397 case CC_OP_SBBL: return compute_all_sbbl();
5399 case CC_OP_LOGICB: return compute_all_logicb();
5400 case CC_OP_LOGICW: return compute_all_logicw();
5401 case CC_OP_LOGICL: return compute_all_logicl();
5403 case CC_OP_INCB: return compute_all_incb();
5404 case CC_OP_INCW: return compute_all_incw();
5405 case CC_OP_INCL: return compute_all_incl();
5407 case CC_OP_DECB: return compute_all_decb();
5408 case CC_OP_DECW: return compute_all_decw();
5409 case CC_OP_DECL: return compute_all_decl();
5411 case CC_OP_SHLB: return compute_all_shlb();
5412 case CC_OP_SHLW: return compute_all_shlw();
5413 case CC_OP_SHLL: return compute_all_shll();
5415 case CC_OP_SARB: return compute_all_sarb();
5416 case CC_OP_SARW: return compute_all_sarw();
5417 case CC_OP_SARL: return compute_all_sarl();
5419 #ifdef TARGET_X86_64
5420 case CC_OP_MULQ: return compute_all_mulq();
5422 case CC_OP_ADDQ: return compute_all_addq();
5424 case CC_OP_ADCQ: return compute_all_adcq();
5426 case CC_OP_SUBQ: return compute_all_subq();
5428 case CC_OP_SBBQ: return compute_all_sbbq();
5430 case CC_OP_LOGICQ: return compute_all_logicq();
5432 case CC_OP_INCQ: return compute_all_incq();
5434 case CC_OP_DECQ: return compute_all_decq();
5436 case CC_OP_SHLQ: return compute_all_shlq();
5438 case CC_OP_SARQ: return compute_all_sarq();
5439 #endif
5443 uint32_t helper_cc_compute_c(int op)
5445 switch (op) {
5446 default: /* should never happen */ return 0;
5448 case CC_OP_EFLAGS: return compute_c_eflags();
5450 case CC_OP_MULB: return compute_c_mull();
5451 case CC_OP_MULW: return compute_c_mull();
5452 case CC_OP_MULL: return compute_c_mull();
5454 case CC_OP_ADDB: return compute_c_addb();
5455 case CC_OP_ADDW: return compute_c_addw();
5456 case CC_OP_ADDL: return compute_c_addl();
5458 case CC_OP_ADCB: return compute_c_adcb();
5459 case CC_OP_ADCW: return compute_c_adcw();
5460 case CC_OP_ADCL: return compute_c_adcl();
5462 case CC_OP_SUBB: return compute_c_subb();
5463 case CC_OP_SUBW: return compute_c_subw();
5464 case CC_OP_SUBL: return compute_c_subl();
5466 case CC_OP_SBBB: return compute_c_sbbb();
5467 case CC_OP_SBBW: return compute_c_sbbw();
5468 case CC_OP_SBBL: return compute_c_sbbl();
5470 case CC_OP_LOGICB: return compute_c_logicb();
5471 case CC_OP_LOGICW: return compute_c_logicw();
5472 case CC_OP_LOGICL: return compute_c_logicl();
5474 case CC_OP_INCB: return compute_c_incl();
5475 case CC_OP_INCW: return compute_c_incl();
5476 case CC_OP_INCL: return compute_c_incl();
5478 case CC_OP_DECB: return compute_c_incl();
5479 case CC_OP_DECW: return compute_c_incl();
5480 case CC_OP_DECL: return compute_c_incl();
5482 case CC_OP_SHLB: return compute_c_shlb();
5483 case CC_OP_SHLW: return compute_c_shlw();
5484 case CC_OP_SHLL: return compute_c_shll();
5486 case CC_OP_SARB: return compute_c_sarl();
5487 case CC_OP_SARW: return compute_c_sarl();
5488 case CC_OP_SARL: return compute_c_sarl();
5490 #ifdef TARGET_X86_64
5491 case CC_OP_MULQ: return compute_c_mull();
5493 case CC_OP_ADDQ: return compute_c_addq();
5495 case CC_OP_ADCQ: return compute_c_adcq();
5497 case CC_OP_SUBQ: return compute_c_subq();
5499 case CC_OP_SBBQ: return compute_c_sbbq();
5501 case CC_OP_LOGICQ: return compute_c_logicq();
5503 case CC_OP_INCQ: return compute_c_incl();
5505 case CC_OP_DECQ: return compute_c_incl();
5507 case CC_OP_SHLQ: return compute_c_shlq();
5509 case CC_OP_SARQ: return compute_c_sarl();
5510 #endif