trace: Add trace-file command to open/close/flush trace file
[qemu/agraf.git] / target-i386 / op_helper.c
blobec6b3e938457cc591c7b3725732362deb0a5f796
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, see <http://www.gnu.org/licenses/>.
20 #include "exec.h"
21 #include "exec-all.h"
22 #include "host-utils.h"
23 #include "ioport.h"
25 //#define DEBUG_PCALL
28 #ifdef DEBUG_PCALL
29 # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
30 # define LOG_PCALL_STATE(env) \
31 log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
32 #else
33 # define LOG_PCALL(...) do { } while (0)
34 # define LOG_PCALL_STATE(env) do { } while (0)
35 #endif
38 #if 0
39 #define raise_exception_err(a, b)\
40 do {\
41 qemu_log("raise_exception line=%d\n", __LINE__);\
42 (raise_exception_err)(a, b);\
43 } while (0)
44 #endif
46 static const uint8_t parity_table[256] = {
47 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
48 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
51 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
55 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
57 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
58 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
59 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
60 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
61 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
62 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
63 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
64 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
65 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
66 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
67 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
68 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
69 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
70 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
71 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
72 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
73 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
74 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
75 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
76 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
77 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
78 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
81 /* modulo 17 table */
82 static const uint8_t rclw_table[32] = {
83 0, 1, 2, 3, 4, 5, 6, 7,
84 8, 9,10,11,12,13,14,15,
85 16, 0, 1, 2, 3, 4, 5, 6,
86 7, 8, 9,10,11,12,13,14,
89 /* modulo 9 table */
90 static const uint8_t rclb_table[32] = {
91 0, 1, 2, 3, 4, 5, 6, 7,
92 8, 0, 1, 2, 3, 4, 5, 6,
93 7, 8, 0, 1, 2, 3, 4, 5,
94 6, 7, 8, 0, 1, 2, 3, 4,
97 static const CPU86_LDouble f15rk[7] =
99 0.00000000000000000000L,
100 1.00000000000000000000L,
101 3.14159265358979323851L, /*pi*/
102 0.30102999566398119523L, /*lg2*/
103 0.69314718055994530943L, /*ln2*/
104 1.44269504088896340739L, /*l2e*/
105 3.32192809488736234781L, /*l2t*/
108 /* broken thread support */
110 static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
112 void helper_lock(void)
114 spin_lock(&global_cpu_lock);
117 void helper_unlock(void)
119 spin_unlock(&global_cpu_lock);
122 void helper_write_eflags(target_ulong t0, uint32_t update_mask)
124 load_eflags(t0, update_mask);
127 target_ulong helper_read_eflags(void)
129 uint32_t eflags;
130 eflags = helper_cc_compute_all(CC_OP);
131 eflags |= (DF & DF_MASK);
132 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
133 return eflags;
136 /* return non zero if error */
137 static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
138 int selector)
140 SegmentCache *dt;
141 int index;
142 target_ulong ptr;
144 if (selector & 0x4)
145 dt = &env->ldt;
146 else
147 dt = &env->gdt;
148 index = selector & ~7;
149 if ((index + 7) > dt->limit)
150 return -1;
151 ptr = dt->base + index;
152 *e1_ptr = ldl_kernel(ptr);
153 *e2_ptr = ldl_kernel(ptr + 4);
154 return 0;
157 static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
159 unsigned int limit;
160 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
161 if (e2 & DESC_G_MASK)
162 limit = (limit << 12) | 0xfff;
163 return limit;
166 static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
168 return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
171 static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
173 sc->base = get_seg_base(e1, e2);
174 sc->limit = get_seg_limit(e1, e2);
175 sc->flags = e2;
178 /* init the segment cache in vm86 mode. */
179 static inline void load_seg_vm(int seg, int selector)
181 selector &= 0xffff;
182 cpu_x86_load_seg_cache(env, seg, selector,
183 (selector << 4), 0xffff, 0);
186 static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
187 uint32_t *esp_ptr, int dpl)
189 int type, index, shift;
191 #if 0
193 int i;
194 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
195 for(i=0;i<env->tr.limit;i++) {
196 printf("%02x ", env->tr.base[i]);
197 if ((i & 7) == 7) printf("\n");
199 printf("\n");
201 #endif
203 if (!(env->tr.flags & DESC_P_MASK))
204 cpu_abort(env, "invalid tss");
205 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
206 if ((type & 7) != 1)
207 cpu_abort(env, "invalid tss type");
208 shift = type >> 3;
209 index = (dpl * 4 + 2) << shift;
210 if (index + (4 << shift) - 1 > env->tr.limit)
211 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
212 if (shift == 0) {
213 *esp_ptr = lduw_kernel(env->tr.base + index);
214 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
215 } else {
216 *esp_ptr = ldl_kernel(env->tr.base + index);
217 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
221 /* XXX: merge with load_seg() */
222 static void tss_load_seg(int seg_reg, int selector)
224 uint32_t e1, e2;
225 int rpl, dpl, cpl;
227 if ((selector & 0xfffc) != 0) {
228 if (load_segment(&e1, &e2, selector) != 0)
229 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230 if (!(e2 & DESC_S_MASK))
231 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
232 rpl = selector & 3;
233 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
234 cpl = env->hflags & HF_CPL_MASK;
235 if (seg_reg == R_CS) {
236 if (!(e2 & DESC_CS_MASK))
237 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
238 /* XXX: is it correct ? */
239 if (dpl != rpl)
240 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
241 if ((e2 & DESC_C_MASK) && dpl > rpl)
242 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
243 } else if (seg_reg == R_SS) {
244 /* SS must be writable data */
245 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
246 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
247 if (dpl != cpl || dpl != rpl)
248 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
249 } else {
250 /* not readable code */
251 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
252 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
253 /* if data or non conforming code, checks the rights */
254 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
255 if (dpl < cpl || dpl < rpl)
256 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
259 if (!(e2 & DESC_P_MASK))
260 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
261 cpu_x86_load_seg_cache(env, seg_reg, selector,
262 get_seg_base(e1, e2),
263 get_seg_limit(e1, e2),
264 e2);
265 } else {
266 if (seg_reg == R_SS || seg_reg == R_CS)
267 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
271 #define SWITCH_TSS_JMP 0
272 #define SWITCH_TSS_IRET 1
273 #define SWITCH_TSS_CALL 2
275 /* XXX: restore CPU state in registers (PowerPC case) */
276 static void switch_tss(int tss_selector,
277 uint32_t e1, uint32_t e2, int source,
278 uint32_t next_eip)
280 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
281 target_ulong tss_base;
282 uint32_t new_regs[8], new_segs[6];
283 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
284 uint32_t old_eflags, eflags_mask;
285 SegmentCache *dt;
286 int index;
287 target_ulong ptr;
289 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
290 LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
292 /* if task gate, we read the TSS segment and we load it */
293 if (type == 5) {
294 if (!(e2 & DESC_P_MASK))
295 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
296 tss_selector = e1 >> 16;
297 if (tss_selector & 4)
298 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
299 if (load_segment(&e1, &e2, tss_selector) != 0)
300 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
301 if (e2 & DESC_S_MASK)
302 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
303 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
304 if ((type & 7) != 1)
305 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
308 if (!(e2 & DESC_P_MASK))
309 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
311 if (type & 8)
312 tss_limit_max = 103;
313 else
314 tss_limit_max = 43;
315 tss_limit = get_seg_limit(e1, e2);
316 tss_base = get_seg_base(e1, e2);
317 if ((tss_selector & 4) != 0 ||
318 tss_limit < tss_limit_max)
319 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
320 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
321 if (old_type & 8)
322 old_tss_limit_max = 103;
323 else
324 old_tss_limit_max = 43;
326 /* read all the registers from the new TSS */
327 if (type & 8) {
328 /* 32 bit */
329 new_cr3 = ldl_kernel(tss_base + 0x1c);
330 new_eip = ldl_kernel(tss_base + 0x20);
331 new_eflags = ldl_kernel(tss_base + 0x24);
332 for(i = 0; i < 8; i++)
333 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
334 for(i = 0; i < 6; i++)
335 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
336 new_ldt = lduw_kernel(tss_base + 0x60);
337 new_trap = ldl_kernel(tss_base + 0x64);
338 } else {
339 /* 16 bit */
340 new_cr3 = 0;
341 new_eip = lduw_kernel(tss_base + 0x0e);
342 new_eflags = lduw_kernel(tss_base + 0x10);
343 for(i = 0; i < 8; i++)
344 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
345 for(i = 0; i < 4; i++)
346 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
347 new_ldt = lduw_kernel(tss_base + 0x2a);
348 new_segs[R_FS] = 0;
349 new_segs[R_GS] = 0;
350 new_trap = 0;
353 /* NOTE: we must avoid memory exceptions during the task switch,
354 so we make dummy accesses before */
355 /* XXX: it can still fail in some cases, so a bigger hack is
356 necessary to valid the TLB after having done the accesses */
358 v1 = ldub_kernel(env->tr.base);
359 v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
360 stb_kernel(env->tr.base, v1);
361 stb_kernel(env->tr.base + old_tss_limit_max, v2);
363 /* clear busy bit (it is restartable) */
364 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
365 target_ulong ptr;
366 uint32_t e2;
367 ptr = env->gdt.base + (env->tr.selector & ~7);
368 e2 = ldl_kernel(ptr + 4);
369 e2 &= ~DESC_TSS_BUSY_MASK;
370 stl_kernel(ptr + 4, e2);
372 old_eflags = compute_eflags();
373 if (source == SWITCH_TSS_IRET)
374 old_eflags &= ~NT_MASK;
376 /* save the current state in the old TSS */
377 if (type & 8) {
378 /* 32 bit */
379 stl_kernel(env->tr.base + 0x20, next_eip);
380 stl_kernel(env->tr.base + 0x24, old_eflags);
381 stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
382 stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
383 stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
384 stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
385 stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
386 stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
387 stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
388 stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
389 for(i = 0; i < 6; i++)
390 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
391 } else {
392 /* 16 bit */
393 stw_kernel(env->tr.base + 0x0e, next_eip);
394 stw_kernel(env->tr.base + 0x10, old_eflags);
395 stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
396 stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
397 stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
398 stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
399 stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
400 stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
401 stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
402 stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
403 for(i = 0; i < 4; i++)
404 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
407 /* now if an exception occurs, it will occurs in the next task
408 context */
410 if (source == SWITCH_TSS_CALL) {
411 stw_kernel(tss_base, env->tr.selector);
412 new_eflags |= NT_MASK;
415 /* set busy bit */
416 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
417 target_ulong ptr;
418 uint32_t e2;
419 ptr = env->gdt.base + (tss_selector & ~7);
420 e2 = ldl_kernel(ptr + 4);
421 e2 |= DESC_TSS_BUSY_MASK;
422 stl_kernel(ptr + 4, e2);
425 /* set the new CPU state */
426 /* from this point, any exception which occurs can give problems */
427 env->cr[0] |= CR0_TS_MASK;
428 env->hflags |= HF_TS_MASK;
429 env->tr.selector = tss_selector;
430 env->tr.base = tss_base;
431 env->tr.limit = tss_limit;
432 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
434 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
435 cpu_x86_update_cr3(env, new_cr3);
438 /* load all registers without an exception, then reload them with
439 possible exception */
440 env->eip = new_eip;
441 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
442 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
443 if (!(type & 8))
444 eflags_mask &= 0xffff;
445 load_eflags(new_eflags, eflags_mask);
446 /* XXX: what to do in 16 bit case ? */
447 EAX = new_regs[0];
448 ECX = new_regs[1];
449 EDX = new_regs[2];
450 EBX = new_regs[3];
451 ESP = new_regs[4];
452 EBP = new_regs[5];
453 ESI = new_regs[6];
454 EDI = new_regs[7];
455 if (new_eflags & VM_MASK) {
456 for(i = 0; i < 6; i++)
457 load_seg_vm(i, new_segs[i]);
458 /* in vm86, CPL is always 3 */
459 cpu_x86_set_cpl(env, 3);
460 } else {
461 /* CPL is set the RPL of CS */
462 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
463 /* first just selectors as the rest may trigger exceptions */
464 for(i = 0; i < 6; i++)
465 cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
468 env->ldt.selector = new_ldt & ~4;
469 env->ldt.base = 0;
470 env->ldt.limit = 0;
471 env->ldt.flags = 0;
473 /* load the LDT */
474 if (new_ldt & 4)
475 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
477 if ((new_ldt & 0xfffc) != 0) {
478 dt = &env->gdt;
479 index = new_ldt & ~7;
480 if ((index + 7) > dt->limit)
481 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
482 ptr = dt->base + index;
483 e1 = ldl_kernel(ptr);
484 e2 = ldl_kernel(ptr + 4);
485 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
486 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
487 if (!(e2 & DESC_P_MASK))
488 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
489 load_seg_cache_raw_dt(&env->ldt, e1, e2);
492 /* load the segments */
493 if (!(new_eflags & VM_MASK)) {
494 tss_load_seg(R_CS, new_segs[R_CS]);
495 tss_load_seg(R_SS, new_segs[R_SS]);
496 tss_load_seg(R_ES, new_segs[R_ES]);
497 tss_load_seg(R_DS, new_segs[R_DS]);
498 tss_load_seg(R_FS, new_segs[R_FS]);
499 tss_load_seg(R_GS, new_segs[R_GS]);
502 /* check that EIP is in the CS segment limits */
503 if (new_eip > env->segs[R_CS].limit) {
504 /* XXX: different exception if CALL ? */
505 raise_exception_err(EXCP0D_GPF, 0);
508 #ifndef CONFIG_USER_ONLY
509 /* reset local breakpoints */
510 if (env->dr[7] & 0x55) {
511 for (i = 0; i < 4; i++) {
512 if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
513 hw_breakpoint_remove(env, i);
515 env->dr[7] &= ~0x55;
517 #endif
520 /* check if Port I/O is allowed in TSS */
521 static inline void check_io(int addr, int size)
523 int io_offset, val, mask;
525 /* TSS must be a valid 32 bit one */
526 if (!(env->tr.flags & DESC_P_MASK) ||
527 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
528 env->tr.limit < 103)
529 goto fail;
530 io_offset = lduw_kernel(env->tr.base + 0x66);
531 io_offset += (addr >> 3);
532 /* Note: the check needs two bytes */
533 if ((io_offset + 1) > env->tr.limit)
534 goto fail;
535 val = lduw_kernel(env->tr.base + io_offset);
536 val >>= (addr & 7);
537 mask = (1 << size) - 1;
538 /* all bits must be zero to allow the I/O */
539 if ((val & mask) != 0) {
540 fail:
541 raise_exception_err(EXCP0D_GPF, 0);
545 void helper_check_iob(uint32_t t0)
547 check_io(t0, 1);
550 void helper_check_iow(uint32_t t0)
552 check_io(t0, 2);
555 void helper_check_iol(uint32_t t0)
557 check_io(t0, 4);
560 void helper_outb(uint32_t port, uint32_t data)
562 cpu_outb(port, data & 0xff);
565 target_ulong helper_inb(uint32_t port)
567 return cpu_inb(port);
570 void helper_outw(uint32_t port, uint32_t data)
572 cpu_outw(port, data & 0xffff);
575 target_ulong helper_inw(uint32_t port)
577 return cpu_inw(port);
580 void helper_outl(uint32_t port, uint32_t data)
582 cpu_outl(port, data);
585 target_ulong helper_inl(uint32_t port)
587 return cpu_inl(port);
590 static inline unsigned int get_sp_mask(unsigned int e2)
592 if (e2 & DESC_B_MASK)
593 return 0xffffffff;
594 else
595 return 0xffff;
598 static int exeption_has_error_code(int intno)
600 switch(intno) {
601 case 8:
602 case 10:
603 case 11:
604 case 12:
605 case 13:
606 case 14:
607 case 17:
608 return 1;
610 return 0;
613 #ifdef TARGET_X86_64
614 #define SET_ESP(val, sp_mask)\
615 do {\
616 if ((sp_mask) == 0xffff)\
617 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
618 else if ((sp_mask) == 0xffffffffLL)\
619 ESP = (uint32_t)(val);\
620 else\
621 ESP = (val);\
622 } while (0)
623 #else
624 #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
625 #endif
627 /* in 64-bit machines, this can overflow. So this segment addition macro
628 * can be used to trim the value to 32-bit whenever needed */
629 #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
631 /* XXX: add a is_user flag to have proper security support */
632 #define PUSHW(ssp, sp, sp_mask, val)\
634 sp -= 2;\
635 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
638 #define PUSHL(ssp, sp, sp_mask, val)\
640 sp -= 4;\
641 stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
644 #define POPW(ssp, sp, sp_mask, val)\
646 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
647 sp += 2;\
650 #define POPL(ssp, sp, sp_mask, val)\
652 val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
653 sp += 4;\
656 /* protected mode interrupt */
657 static void do_interrupt_protected(int intno, int is_int, int error_code,
658 unsigned int next_eip, int is_hw)
660 SegmentCache *dt;
661 target_ulong ptr, ssp;
662 int type, dpl, selector, ss_dpl, cpl;
663 int has_error_code, new_stack, shift;
664 uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
665 uint32_t old_eip, sp_mask;
667 has_error_code = 0;
668 if (!is_int && !is_hw)
669 has_error_code = exeption_has_error_code(intno);
670 if (is_int)
671 old_eip = next_eip;
672 else
673 old_eip = env->eip;
675 dt = &env->idt;
676 if (intno * 8 + 7 > dt->limit)
677 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
678 ptr = dt->base + intno * 8;
679 e1 = ldl_kernel(ptr);
680 e2 = ldl_kernel(ptr + 4);
681 /* check gate type */
682 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
683 switch(type) {
684 case 5: /* task gate */
685 /* must do that check here to return the correct error code */
686 if (!(e2 & DESC_P_MASK))
687 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
688 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
689 if (has_error_code) {
690 int type;
691 uint32_t mask;
692 /* push the error code */
693 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
694 shift = type >> 3;
695 if (env->segs[R_SS].flags & DESC_B_MASK)
696 mask = 0xffffffff;
697 else
698 mask = 0xffff;
699 esp = (ESP - (2 << shift)) & mask;
700 ssp = env->segs[R_SS].base + esp;
701 if (shift)
702 stl_kernel(ssp, error_code);
703 else
704 stw_kernel(ssp, error_code);
705 SET_ESP(esp, mask);
707 return;
708 case 6: /* 286 interrupt gate */
709 case 7: /* 286 trap gate */
710 case 14: /* 386 interrupt gate */
711 case 15: /* 386 trap gate */
712 break;
713 default:
714 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
715 break;
717 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
718 cpl = env->hflags & HF_CPL_MASK;
719 /* check privilege if software int */
720 if (is_int && dpl < cpl)
721 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
722 /* check valid bit */
723 if (!(e2 & DESC_P_MASK))
724 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
725 selector = e1 >> 16;
726 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
727 if ((selector & 0xfffc) == 0)
728 raise_exception_err(EXCP0D_GPF, 0);
730 if (load_segment(&e1, &e2, selector) != 0)
731 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
732 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
733 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
734 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
735 if (dpl > cpl)
736 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
737 if (!(e2 & DESC_P_MASK))
738 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
739 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
740 /* to inner privilege */
741 get_ss_esp_from_tss(&ss, &esp, dpl);
742 if ((ss & 0xfffc) == 0)
743 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
744 if ((ss & 3) != dpl)
745 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
746 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
747 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
748 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
749 if (ss_dpl != dpl)
750 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
751 if (!(ss_e2 & DESC_S_MASK) ||
752 (ss_e2 & DESC_CS_MASK) ||
753 !(ss_e2 & DESC_W_MASK))
754 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
755 if (!(ss_e2 & DESC_P_MASK))
756 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
757 new_stack = 1;
758 sp_mask = get_sp_mask(ss_e2);
759 ssp = get_seg_base(ss_e1, ss_e2);
760 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
761 /* to same privilege */
762 if (env->eflags & VM_MASK)
763 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
764 new_stack = 0;
765 sp_mask = get_sp_mask(env->segs[R_SS].flags);
766 ssp = env->segs[R_SS].base;
767 esp = ESP;
768 dpl = cpl;
769 } else {
770 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
771 new_stack = 0; /* avoid warning */
772 sp_mask = 0; /* avoid warning */
773 ssp = 0; /* avoid warning */
774 esp = 0; /* avoid warning */
777 shift = type >> 3;
779 #if 0
780 /* XXX: check that enough room is available */
781 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
782 if (env->eflags & VM_MASK)
783 push_size += 8;
784 push_size <<= shift;
785 #endif
786 if (shift == 1) {
787 if (new_stack) {
788 if (env->eflags & VM_MASK) {
789 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
790 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
791 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
792 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
794 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
795 PUSHL(ssp, esp, sp_mask, ESP);
797 PUSHL(ssp, esp, sp_mask, compute_eflags());
798 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
799 PUSHL(ssp, esp, sp_mask, old_eip);
800 if (has_error_code) {
801 PUSHL(ssp, esp, sp_mask, error_code);
803 } else {
804 if (new_stack) {
805 if (env->eflags & VM_MASK) {
806 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
807 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
808 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
809 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
811 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
812 PUSHW(ssp, esp, sp_mask, ESP);
814 PUSHW(ssp, esp, sp_mask, compute_eflags());
815 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
816 PUSHW(ssp, esp, sp_mask, old_eip);
817 if (has_error_code) {
818 PUSHW(ssp, esp, sp_mask, error_code);
822 if (new_stack) {
823 if (env->eflags & VM_MASK) {
824 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
825 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
826 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
827 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
829 ss = (ss & ~3) | dpl;
830 cpu_x86_load_seg_cache(env, R_SS, ss,
831 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
833 SET_ESP(esp, sp_mask);
835 selector = (selector & ~3) | dpl;
836 cpu_x86_load_seg_cache(env, R_CS, selector,
837 get_seg_base(e1, e2),
838 get_seg_limit(e1, e2),
839 e2);
840 cpu_x86_set_cpl(env, dpl);
841 env->eip = offset;
843 /* interrupt gate clear IF mask */
844 if ((type & 1) == 0) {
845 env->eflags &= ~IF_MASK;
847 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
850 #ifdef TARGET_X86_64
852 #define PUSHQ(sp, val)\
854 sp -= 8;\
855 stq_kernel(sp, (val));\
858 #define POPQ(sp, val)\
860 val = ldq_kernel(sp);\
861 sp += 8;\
864 static inline target_ulong get_rsp_from_tss(int level)
866 int index;
868 #if 0
869 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
870 env->tr.base, env->tr.limit);
871 #endif
873 if (!(env->tr.flags & DESC_P_MASK))
874 cpu_abort(env, "invalid tss");
875 index = 8 * level + 4;
876 if ((index + 7) > env->tr.limit)
877 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
878 return ldq_kernel(env->tr.base + index);
881 /* 64 bit interrupt */
882 static void do_interrupt64(int intno, int is_int, int error_code,
883 target_ulong next_eip, int is_hw)
885 SegmentCache *dt;
886 target_ulong ptr;
887 int type, dpl, selector, cpl, ist;
888 int has_error_code, new_stack;
889 uint32_t e1, e2, e3, ss;
890 target_ulong old_eip, esp, offset;
892 has_error_code = 0;
893 if (!is_int && !is_hw)
894 has_error_code = exeption_has_error_code(intno);
895 if (is_int)
896 old_eip = next_eip;
897 else
898 old_eip = env->eip;
900 dt = &env->idt;
901 if (intno * 16 + 15 > dt->limit)
902 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
903 ptr = dt->base + intno * 16;
904 e1 = ldl_kernel(ptr);
905 e2 = ldl_kernel(ptr + 4);
906 e3 = ldl_kernel(ptr + 8);
907 /* check gate type */
908 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
909 switch(type) {
910 case 14: /* 386 interrupt gate */
911 case 15: /* 386 trap gate */
912 break;
913 default:
914 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
915 break;
917 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
918 cpl = env->hflags & HF_CPL_MASK;
919 /* check privilege if software int */
920 if (is_int && dpl < cpl)
921 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
922 /* check valid bit */
923 if (!(e2 & DESC_P_MASK))
924 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
925 selector = e1 >> 16;
926 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
927 ist = e2 & 7;
928 if ((selector & 0xfffc) == 0)
929 raise_exception_err(EXCP0D_GPF, 0);
931 if (load_segment(&e1, &e2, selector) != 0)
932 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
933 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
934 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
935 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
936 if (dpl > cpl)
937 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
938 if (!(e2 & DESC_P_MASK))
939 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
940 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
941 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
942 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
943 /* to inner privilege */
944 if (ist != 0)
945 esp = get_rsp_from_tss(ist + 3);
946 else
947 esp = get_rsp_from_tss(dpl);
948 esp &= ~0xfLL; /* align stack */
949 ss = 0;
950 new_stack = 1;
951 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
952 /* to same privilege */
953 if (env->eflags & VM_MASK)
954 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
955 new_stack = 0;
956 if (ist != 0)
957 esp = get_rsp_from_tss(ist + 3);
958 else
959 esp = ESP;
960 esp &= ~0xfLL; /* align stack */
961 dpl = cpl;
962 } else {
963 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
964 new_stack = 0; /* avoid warning */
965 esp = 0; /* avoid warning */
968 PUSHQ(esp, env->segs[R_SS].selector);
969 PUSHQ(esp, ESP);
970 PUSHQ(esp, compute_eflags());
971 PUSHQ(esp, env->segs[R_CS].selector);
972 PUSHQ(esp, old_eip);
973 if (has_error_code) {
974 PUSHQ(esp, error_code);
977 if (new_stack) {
978 ss = 0 | dpl;
979 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
981 ESP = esp;
983 selector = (selector & ~3) | dpl;
984 cpu_x86_load_seg_cache(env, R_CS, selector,
985 get_seg_base(e1, e2),
986 get_seg_limit(e1, e2),
987 e2);
988 cpu_x86_set_cpl(env, dpl);
989 env->eip = offset;
991 /* interrupt gate clear IF mask */
992 if ((type & 1) == 0) {
993 env->eflags &= ~IF_MASK;
995 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
997 #endif
999 #ifdef TARGET_X86_64
1000 #if defined(CONFIG_USER_ONLY)
1001 void helper_syscall(int next_eip_addend)
1003 env->exception_index = EXCP_SYSCALL;
1004 env->exception_next_eip = env->eip + next_eip_addend;
1005 cpu_loop_exit();
1007 #else
1008 void helper_syscall(int next_eip_addend)
1010 int selector;
1012 if (!(env->efer & MSR_EFER_SCE)) {
1013 raise_exception_err(EXCP06_ILLOP, 0);
1015 selector = (env->star >> 32) & 0xffff;
1016 if (env->hflags & HF_LMA_MASK) {
1017 int code64;
1019 ECX = env->eip + next_eip_addend;
1020 env->regs[11] = compute_eflags();
1022 code64 = env->hflags & HF_CS64_MASK;
1024 cpu_x86_set_cpl(env, 0);
1025 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1026 0, 0xffffffff,
1027 DESC_G_MASK | DESC_P_MASK |
1028 DESC_S_MASK |
1029 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1030 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1031 0, 0xffffffff,
1032 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1033 DESC_S_MASK |
1034 DESC_W_MASK | DESC_A_MASK);
1035 env->eflags &= ~env->fmask;
1036 load_eflags(env->eflags, 0);
1037 if (code64)
1038 env->eip = env->lstar;
1039 else
1040 env->eip = env->cstar;
1041 } else {
1042 ECX = (uint32_t)(env->eip + next_eip_addend);
1044 cpu_x86_set_cpl(env, 0);
1045 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1046 0, 0xffffffff,
1047 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1048 DESC_S_MASK |
1049 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1050 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1051 0, 0xffffffff,
1052 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1053 DESC_S_MASK |
1054 DESC_W_MASK | DESC_A_MASK);
1055 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1056 env->eip = (uint32_t)env->star;
1059 #endif
1060 #endif
1062 #ifdef TARGET_X86_64
1063 void helper_sysret(int dflag)
1065 int cpl, selector;
1067 if (!(env->efer & MSR_EFER_SCE)) {
1068 raise_exception_err(EXCP06_ILLOP, 0);
1070 cpl = env->hflags & HF_CPL_MASK;
1071 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1072 raise_exception_err(EXCP0D_GPF, 0);
1074 selector = (env->star >> 48) & 0xffff;
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 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1102 0, 0xffffffff,
1103 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1104 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1105 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1106 env->eip = (uint32_t)ECX;
1107 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1108 0, 0xffffffff,
1109 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1110 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1111 DESC_W_MASK | DESC_A_MASK);
1112 env->eflags |= IF_MASK;
1113 cpu_x86_set_cpl(env, 3);
1116 #endif
1118 /* real mode interrupt */
1119 static void do_interrupt_real(int intno, int is_int, int error_code,
1120 unsigned int next_eip)
1122 SegmentCache *dt;
1123 target_ulong ptr, ssp;
1124 int selector;
1125 uint32_t offset, esp;
1126 uint32_t old_cs, old_eip;
1128 /* real mode (simpler !) */
1129 dt = &env->idt;
1130 if (intno * 4 + 3 > dt->limit)
1131 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1132 ptr = dt->base + intno * 4;
1133 offset = lduw_kernel(ptr);
1134 selector = lduw_kernel(ptr + 2);
1135 esp = ESP;
1136 ssp = env->segs[R_SS].base;
1137 if (is_int)
1138 old_eip = next_eip;
1139 else
1140 old_eip = env->eip;
1141 old_cs = env->segs[R_CS].selector;
1142 /* XXX: use SS segment size ? */
1143 PUSHW(ssp, esp, 0xffff, compute_eflags());
1144 PUSHW(ssp, esp, 0xffff, old_cs);
1145 PUSHW(ssp, esp, 0xffff, old_eip);
1147 /* update processor state */
1148 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1149 env->eip = offset;
1150 env->segs[R_CS].selector = selector;
1151 env->segs[R_CS].base = (selector << 4);
1152 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1155 /* fake user mode interrupt */
1156 void do_interrupt_user(int intno, int is_int, int error_code,
1157 target_ulong next_eip)
1159 SegmentCache *dt;
1160 target_ulong ptr;
1161 int dpl, cpl, shift;
1162 uint32_t e2;
1164 dt = &env->idt;
1165 if (env->hflags & HF_LMA_MASK) {
1166 shift = 4;
1167 } else {
1168 shift = 3;
1170 ptr = dt->base + (intno << shift);
1171 e2 = ldl_kernel(ptr + 4);
1173 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1174 cpl = env->hflags & HF_CPL_MASK;
1175 /* check privilege if software int */
1176 if (is_int && dpl < cpl)
1177 raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1179 /* Since we emulate only user space, we cannot do more than
1180 exiting the emulation with the suitable exception and error
1181 code */
1182 if (is_int)
1183 EIP = next_eip;
1186 #if !defined(CONFIG_USER_ONLY)
1187 static void handle_even_inj(int intno, int is_int, int error_code,
1188 int is_hw, int rm)
1190 uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1191 if (!(event_inj & SVM_EVTINJ_VALID)) {
1192 int type;
1193 if (is_int)
1194 type = SVM_EVTINJ_TYPE_SOFT;
1195 else
1196 type = SVM_EVTINJ_TYPE_EXEPT;
1197 event_inj = intno | type | SVM_EVTINJ_VALID;
1198 if (!rm && exeption_has_error_code(intno)) {
1199 event_inj |= SVM_EVTINJ_VALID_ERR;
1200 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
1202 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
1205 #endif
1208 * Begin execution of an interruption. is_int is TRUE if coming from
1209 * the int instruction. next_eip is the EIP value AFTER the interrupt
1210 * instruction. It is only relevant if is_int is TRUE.
1212 void do_interrupt(int intno, int is_int, int error_code,
1213 target_ulong next_eip, int is_hw)
1215 if (qemu_loglevel_mask(CPU_LOG_INT)) {
1216 if ((env->cr[0] & CR0_PE_MASK)) {
1217 static int count;
1218 qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1219 count, intno, error_code, is_int,
1220 env->hflags & HF_CPL_MASK,
1221 env->segs[R_CS].selector, EIP,
1222 (int)env->segs[R_CS].base + EIP,
1223 env->segs[R_SS].selector, ESP);
1224 if (intno == 0x0e) {
1225 qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
1226 } else {
1227 qemu_log(" EAX=" TARGET_FMT_lx, EAX);
1229 qemu_log("\n");
1230 log_cpu_state(env, X86_DUMP_CCOP);
1231 #if 0
1233 int i;
1234 target_ulong ptr;
1235 qemu_log(" code=");
1236 ptr = env->segs[R_CS].base + env->eip;
1237 for(i = 0; i < 16; i++) {
1238 qemu_log(" %02x", ldub(ptr + i));
1240 qemu_log("\n");
1242 #endif
1243 count++;
1246 if (env->cr[0] & CR0_PE_MASK) {
1247 #if !defined(CONFIG_USER_ONLY)
1248 if (env->hflags & HF_SVMI_MASK)
1249 handle_even_inj(intno, is_int, error_code, is_hw, 0);
1250 #endif
1251 #ifdef TARGET_X86_64
1252 if (env->hflags & HF_LMA_MASK) {
1253 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1254 } else
1255 #endif
1257 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1259 } else {
1260 #if !defined(CONFIG_USER_ONLY)
1261 if (env->hflags & HF_SVMI_MASK)
1262 handle_even_inj(intno, is_int, error_code, is_hw, 1);
1263 #endif
1264 do_interrupt_real(intno, is_int, error_code, next_eip);
1267 #if !defined(CONFIG_USER_ONLY)
1268 if (env->hflags & HF_SVMI_MASK) {
1269 uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1270 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
1272 #endif
1275 /* This should come from sysemu.h - if we could include it here... */
1276 void qemu_system_reset_request(void);
1279 * Check nested exceptions and change to double or triple fault if
1280 * needed. It should only be called, if this is not an interrupt.
1281 * Returns the new exception number.
1283 static int check_exception(int intno, int *error_code)
1285 int first_contributory = env->old_exception == 0 ||
1286 (env->old_exception >= 10 &&
1287 env->old_exception <= 13);
1288 int second_contributory = intno == 0 ||
1289 (intno >= 10 && intno <= 13);
1291 qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
1292 env->old_exception, intno);
1294 #if !defined(CONFIG_USER_ONLY)
1295 if (env->old_exception == EXCP08_DBLE) {
1296 if (env->hflags & HF_SVMI_MASK)
1297 helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
1299 qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
1301 qemu_system_reset_request();
1302 return EXCP_HLT;
1304 #endif
1306 if ((first_contributory && second_contributory)
1307 || (env->old_exception == EXCP0E_PAGE &&
1308 (second_contributory || (intno == EXCP0E_PAGE)))) {
1309 intno = EXCP08_DBLE;
1310 *error_code = 0;
1313 if (second_contributory || (intno == EXCP0E_PAGE) ||
1314 (intno == EXCP08_DBLE))
1315 env->old_exception = intno;
1317 return intno;
1321 * Signal an interruption. It is executed in the main CPU loop.
1322 * is_int is TRUE if coming from the int instruction. next_eip is the
1323 * EIP value AFTER the interrupt instruction. It is only relevant if
1324 * is_int is TRUE.
1326 static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
1327 int next_eip_addend)
1329 if (!is_int) {
1330 helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1331 intno = check_exception(intno, &error_code);
1332 } else {
1333 helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
1336 env->exception_index = intno;
1337 env->error_code = error_code;
1338 env->exception_is_int = is_int;
1339 env->exception_next_eip = env->eip + next_eip_addend;
1340 cpu_loop_exit();
1343 /* shortcuts to generate exceptions */
1345 void raise_exception_err(int exception_index, int error_code)
1347 raise_interrupt(exception_index, 0, error_code, 0);
1350 void raise_exception(int exception_index)
1352 raise_interrupt(exception_index, 0, 0, 0);
1355 void raise_exception_env(int exception_index, CPUState *nenv)
1357 env = nenv;
1358 raise_exception(exception_index);
1360 /* SMM support */
1362 #if defined(CONFIG_USER_ONLY)
1364 void do_smm_enter(void)
1368 void helper_rsm(void)
1372 #else
1374 #ifdef TARGET_X86_64
1375 #define SMM_REVISION_ID 0x00020064
1376 #else
1377 #define SMM_REVISION_ID 0x00020000
1378 #endif
1380 void do_smm_enter(void)
1382 target_ulong sm_state;
1383 SegmentCache *dt;
1384 int i, offset;
1386 qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
1387 log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
1389 env->hflags |= HF_SMM_MASK;
1390 cpu_smm_update(env);
1392 sm_state = env->smbase + 0x8000;
1394 #ifdef TARGET_X86_64
1395 for(i = 0; i < 6; i++) {
1396 dt = &env->segs[i];
1397 offset = 0x7e00 + i * 16;
1398 stw_phys(sm_state + offset, dt->selector);
1399 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1400 stl_phys(sm_state + offset + 4, dt->limit);
1401 stq_phys(sm_state + offset + 8, dt->base);
1404 stq_phys(sm_state + 0x7e68, env->gdt.base);
1405 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1407 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1408 stq_phys(sm_state + 0x7e78, env->ldt.base);
1409 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1410 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1412 stq_phys(sm_state + 0x7e88, env->idt.base);
1413 stl_phys(sm_state + 0x7e84, env->idt.limit);
1415 stw_phys(sm_state + 0x7e90, env->tr.selector);
1416 stq_phys(sm_state + 0x7e98, env->tr.base);
1417 stl_phys(sm_state + 0x7e94, env->tr.limit);
1418 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1420 stq_phys(sm_state + 0x7ed0, env->efer);
1422 stq_phys(sm_state + 0x7ff8, EAX);
1423 stq_phys(sm_state + 0x7ff0, ECX);
1424 stq_phys(sm_state + 0x7fe8, EDX);
1425 stq_phys(sm_state + 0x7fe0, EBX);
1426 stq_phys(sm_state + 0x7fd8, ESP);
1427 stq_phys(sm_state + 0x7fd0, EBP);
1428 stq_phys(sm_state + 0x7fc8, ESI);
1429 stq_phys(sm_state + 0x7fc0, EDI);
1430 for(i = 8; i < 16; i++)
1431 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1432 stq_phys(sm_state + 0x7f78, env->eip);
1433 stl_phys(sm_state + 0x7f70, compute_eflags());
1434 stl_phys(sm_state + 0x7f68, env->dr[6]);
1435 stl_phys(sm_state + 0x7f60, env->dr[7]);
1437 stl_phys(sm_state + 0x7f48, env->cr[4]);
1438 stl_phys(sm_state + 0x7f50, env->cr[3]);
1439 stl_phys(sm_state + 0x7f58, env->cr[0]);
1441 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1442 stl_phys(sm_state + 0x7f00, env->smbase);
1443 #else
1444 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1445 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1446 stl_phys(sm_state + 0x7ff4, compute_eflags());
1447 stl_phys(sm_state + 0x7ff0, env->eip);
1448 stl_phys(sm_state + 0x7fec, EDI);
1449 stl_phys(sm_state + 0x7fe8, ESI);
1450 stl_phys(sm_state + 0x7fe4, EBP);
1451 stl_phys(sm_state + 0x7fe0, ESP);
1452 stl_phys(sm_state + 0x7fdc, EBX);
1453 stl_phys(sm_state + 0x7fd8, EDX);
1454 stl_phys(sm_state + 0x7fd4, ECX);
1455 stl_phys(sm_state + 0x7fd0, EAX);
1456 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1457 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1459 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1460 stl_phys(sm_state + 0x7f64, env->tr.base);
1461 stl_phys(sm_state + 0x7f60, env->tr.limit);
1462 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1464 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1465 stl_phys(sm_state + 0x7f80, env->ldt.base);
1466 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1467 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1469 stl_phys(sm_state + 0x7f74, env->gdt.base);
1470 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1472 stl_phys(sm_state + 0x7f58, env->idt.base);
1473 stl_phys(sm_state + 0x7f54, env->idt.limit);
1475 for(i = 0; i < 6; i++) {
1476 dt = &env->segs[i];
1477 if (i < 3)
1478 offset = 0x7f84 + i * 12;
1479 else
1480 offset = 0x7f2c + (i - 3) * 12;
1481 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1482 stl_phys(sm_state + offset + 8, dt->base);
1483 stl_phys(sm_state + offset + 4, dt->limit);
1484 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1486 stl_phys(sm_state + 0x7f14, env->cr[4]);
1488 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1489 stl_phys(sm_state + 0x7ef8, env->smbase);
1490 #endif
1491 /* init SMM cpu state */
1493 #ifdef TARGET_X86_64
1494 cpu_load_efer(env, 0);
1495 #endif
1496 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1497 env->eip = 0x00008000;
1498 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1499 0xffffffff, 0);
1500 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1501 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1502 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1503 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1504 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1506 cpu_x86_update_cr0(env,
1507 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1508 cpu_x86_update_cr4(env, 0);
1509 env->dr[7] = 0x00000400;
1510 CC_OP = CC_OP_EFLAGS;
1513 void helper_rsm(void)
1515 target_ulong sm_state;
1516 int i, offset;
1517 uint32_t val;
1519 sm_state = env->smbase + 0x8000;
1520 #ifdef TARGET_X86_64
1521 cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
1523 for(i = 0; i < 6; i++) {
1524 offset = 0x7e00 + i * 16;
1525 cpu_x86_load_seg_cache(env, i,
1526 lduw_phys(sm_state + offset),
1527 ldq_phys(sm_state + offset + 8),
1528 ldl_phys(sm_state + offset + 4),
1529 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1532 env->gdt.base = ldq_phys(sm_state + 0x7e68);
1533 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1535 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1536 env->ldt.base = ldq_phys(sm_state + 0x7e78);
1537 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1538 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1540 env->idt.base = ldq_phys(sm_state + 0x7e88);
1541 env->idt.limit = ldl_phys(sm_state + 0x7e84);
1543 env->tr.selector = lduw_phys(sm_state + 0x7e90);
1544 env->tr.base = ldq_phys(sm_state + 0x7e98);
1545 env->tr.limit = ldl_phys(sm_state + 0x7e94);
1546 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1548 EAX = ldq_phys(sm_state + 0x7ff8);
1549 ECX = ldq_phys(sm_state + 0x7ff0);
1550 EDX = ldq_phys(sm_state + 0x7fe8);
1551 EBX = ldq_phys(sm_state + 0x7fe0);
1552 ESP = ldq_phys(sm_state + 0x7fd8);
1553 EBP = ldq_phys(sm_state + 0x7fd0);
1554 ESI = ldq_phys(sm_state + 0x7fc8);
1555 EDI = ldq_phys(sm_state + 0x7fc0);
1556 for(i = 8; i < 16; i++)
1557 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1558 env->eip = ldq_phys(sm_state + 0x7f78);
1559 load_eflags(ldl_phys(sm_state + 0x7f70),
1560 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1561 env->dr[6] = ldl_phys(sm_state + 0x7f68);
1562 env->dr[7] = ldl_phys(sm_state + 0x7f60);
1564 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1565 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1566 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1568 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1569 if (val & 0x20000) {
1570 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1572 #else
1573 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1574 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1575 load_eflags(ldl_phys(sm_state + 0x7ff4),
1576 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1577 env->eip = ldl_phys(sm_state + 0x7ff0);
1578 EDI = ldl_phys(sm_state + 0x7fec);
1579 ESI = ldl_phys(sm_state + 0x7fe8);
1580 EBP = ldl_phys(sm_state + 0x7fe4);
1581 ESP = ldl_phys(sm_state + 0x7fe0);
1582 EBX = ldl_phys(sm_state + 0x7fdc);
1583 EDX = ldl_phys(sm_state + 0x7fd8);
1584 ECX = ldl_phys(sm_state + 0x7fd4);
1585 EAX = ldl_phys(sm_state + 0x7fd0);
1586 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1587 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1589 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1590 env->tr.base = ldl_phys(sm_state + 0x7f64);
1591 env->tr.limit = ldl_phys(sm_state + 0x7f60);
1592 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1594 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1595 env->ldt.base = ldl_phys(sm_state + 0x7f80);
1596 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1597 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1599 env->gdt.base = ldl_phys(sm_state + 0x7f74);
1600 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1602 env->idt.base = ldl_phys(sm_state + 0x7f58);
1603 env->idt.limit = ldl_phys(sm_state + 0x7f54);
1605 for(i = 0; i < 6; i++) {
1606 if (i < 3)
1607 offset = 0x7f84 + i * 12;
1608 else
1609 offset = 0x7f2c + (i - 3) * 12;
1610 cpu_x86_load_seg_cache(env, i,
1611 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1612 ldl_phys(sm_state + offset + 8),
1613 ldl_phys(sm_state + offset + 4),
1614 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1616 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1618 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1619 if (val & 0x20000) {
1620 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1622 #endif
1623 CC_OP = CC_OP_EFLAGS;
1624 env->hflags &= ~HF_SMM_MASK;
1625 cpu_smm_update(env);
1627 qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
1628 log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
1631 #endif /* !CONFIG_USER_ONLY */
1634 /* division, flags are undefined */
1636 void helper_divb_AL(target_ulong t0)
1638 unsigned int num, den, q, r;
1640 num = (EAX & 0xffff);
1641 den = (t0 & 0xff);
1642 if (den == 0) {
1643 raise_exception(EXCP00_DIVZ);
1645 q = (num / den);
1646 if (q > 0xff)
1647 raise_exception(EXCP00_DIVZ);
1648 q &= 0xff;
1649 r = (num % den) & 0xff;
1650 EAX = (EAX & ~0xffff) | (r << 8) | q;
1653 void helper_idivb_AL(target_ulong t0)
1655 int num, den, q, r;
1657 num = (int16_t)EAX;
1658 den = (int8_t)t0;
1659 if (den == 0) {
1660 raise_exception(EXCP00_DIVZ);
1662 q = (num / den);
1663 if (q != (int8_t)q)
1664 raise_exception(EXCP00_DIVZ);
1665 q &= 0xff;
1666 r = (num % den) & 0xff;
1667 EAX = (EAX & ~0xffff) | (r << 8) | q;
1670 void helper_divw_AX(target_ulong t0)
1672 unsigned int num, den, q, r;
1674 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1675 den = (t0 & 0xffff);
1676 if (den == 0) {
1677 raise_exception(EXCP00_DIVZ);
1679 q = (num / den);
1680 if (q > 0xffff)
1681 raise_exception(EXCP00_DIVZ);
1682 q &= 0xffff;
1683 r = (num % den) & 0xffff;
1684 EAX = (EAX & ~0xffff) | q;
1685 EDX = (EDX & ~0xffff) | r;
1688 void helper_idivw_AX(target_ulong t0)
1690 int num, den, q, r;
1692 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1693 den = (int16_t)t0;
1694 if (den == 0) {
1695 raise_exception(EXCP00_DIVZ);
1697 q = (num / den);
1698 if (q != (int16_t)q)
1699 raise_exception(EXCP00_DIVZ);
1700 q &= 0xffff;
1701 r = (num % den) & 0xffff;
1702 EAX = (EAX & ~0xffff) | q;
1703 EDX = (EDX & ~0xffff) | r;
1706 void helper_divl_EAX(target_ulong t0)
1708 unsigned int den, r;
1709 uint64_t num, q;
1711 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1712 den = t0;
1713 if (den == 0) {
1714 raise_exception(EXCP00_DIVZ);
1716 q = (num / den);
1717 r = (num % den);
1718 if (q > 0xffffffff)
1719 raise_exception(EXCP00_DIVZ);
1720 EAX = (uint32_t)q;
1721 EDX = (uint32_t)r;
1724 void helper_idivl_EAX(target_ulong t0)
1726 int den, r;
1727 int64_t num, q;
1729 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1730 den = t0;
1731 if (den == 0) {
1732 raise_exception(EXCP00_DIVZ);
1734 q = (num / den);
1735 r = (num % den);
1736 if (q != (int32_t)q)
1737 raise_exception(EXCP00_DIVZ);
1738 EAX = (uint32_t)q;
1739 EDX = (uint32_t)r;
1742 /* bcd */
1744 /* XXX: exception */
1745 void helper_aam(int base)
1747 int al, ah;
1748 al = EAX & 0xff;
1749 ah = al / base;
1750 al = al % base;
1751 EAX = (EAX & ~0xffff) | al | (ah << 8);
1752 CC_DST = al;
1755 void helper_aad(int base)
1757 int al, ah;
1758 al = EAX & 0xff;
1759 ah = (EAX >> 8) & 0xff;
1760 al = ((ah * base) + al) & 0xff;
1761 EAX = (EAX & ~0xffff) | al;
1762 CC_DST = al;
1765 void helper_aaa(void)
1767 int icarry;
1768 int al, ah, af;
1769 int eflags;
1771 eflags = helper_cc_compute_all(CC_OP);
1772 af = eflags & CC_A;
1773 al = EAX & 0xff;
1774 ah = (EAX >> 8) & 0xff;
1776 icarry = (al > 0xf9);
1777 if (((al & 0x0f) > 9 ) || af) {
1778 al = (al + 6) & 0x0f;
1779 ah = (ah + 1 + icarry) & 0xff;
1780 eflags |= CC_C | CC_A;
1781 } else {
1782 eflags &= ~(CC_C | CC_A);
1783 al &= 0x0f;
1785 EAX = (EAX & ~0xffff) | al | (ah << 8);
1786 CC_SRC = eflags;
1789 void helper_aas(void)
1791 int icarry;
1792 int al, ah, af;
1793 int eflags;
1795 eflags = helper_cc_compute_all(CC_OP);
1796 af = eflags & CC_A;
1797 al = EAX & 0xff;
1798 ah = (EAX >> 8) & 0xff;
1800 icarry = (al < 6);
1801 if (((al & 0x0f) > 9 ) || af) {
1802 al = (al - 6) & 0x0f;
1803 ah = (ah - 1 - icarry) & 0xff;
1804 eflags |= CC_C | CC_A;
1805 } else {
1806 eflags &= ~(CC_C | CC_A);
1807 al &= 0x0f;
1809 EAX = (EAX & ~0xffff) | al | (ah << 8);
1810 CC_SRC = eflags;
1813 void helper_daa(void)
1815 int al, af, cf;
1816 int eflags;
1818 eflags = helper_cc_compute_all(CC_OP);
1819 cf = eflags & CC_C;
1820 af = eflags & CC_A;
1821 al = EAX & 0xff;
1823 eflags = 0;
1824 if (((al & 0x0f) > 9 ) || af) {
1825 al = (al + 6) & 0xff;
1826 eflags |= CC_A;
1828 if ((al > 0x9f) || cf) {
1829 al = (al + 0x60) & 0xff;
1830 eflags |= CC_C;
1832 EAX = (EAX & ~0xff) | al;
1833 /* well, speed is not an issue here, so we compute the flags by hand */
1834 eflags |= (al == 0) << 6; /* zf */
1835 eflags |= parity_table[al]; /* pf */
1836 eflags |= (al & 0x80); /* sf */
1837 CC_SRC = eflags;
1840 void helper_das(void)
1842 int al, al1, af, cf;
1843 int eflags;
1845 eflags = helper_cc_compute_all(CC_OP);
1846 cf = eflags & CC_C;
1847 af = eflags & CC_A;
1848 al = EAX & 0xff;
1850 eflags = 0;
1851 al1 = al;
1852 if (((al & 0x0f) > 9 ) || af) {
1853 eflags |= CC_A;
1854 if (al < 6 || cf)
1855 eflags |= CC_C;
1856 al = (al - 6) & 0xff;
1858 if ((al1 > 0x99) || cf) {
1859 al = (al - 0x60) & 0xff;
1860 eflags |= CC_C;
1862 EAX = (EAX & ~0xff) | al;
1863 /* well, speed is not an issue here, so we compute the flags by hand */
1864 eflags |= (al == 0) << 6; /* zf */
1865 eflags |= parity_table[al]; /* pf */
1866 eflags |= (al & 0x80); /* sf */
1867 CC_SRC = eflags;
1870 void helper_into(int next_eip_addend)
1872 int eflags;
1873 eflags = helper_cc_compute_all(CC_OP);
1874 if (eflags & CC_O) {
1875 raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
1879 void helper_cmpxchg8b(target_ulong a0)
1881 uint64_t d;
1882 int eflags;
1884 eflags = helper_cc_compute_all(CC_OP);
1885 d = ldq(a0);
1886 if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
1887 stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
1888 eflags |= CC_Z;
1889 } else {
1890 /* always do the store */
1891 stq(a0, d);
1892 EDX = (uint32_t)(d >> 32);
1893 EAX = (uint32_t)d;
1894 eflags &= ~CC_Z;
1896 CC_SRC = eflags;
1899 #ifdef TARGET_X86_64
1900 void helper_cmpxchg16b(target_ulong a0)
1902 uint64_t d0, d1;
1903 int eflags;
1905 if ((a0 & 0xf) != 0)
1906 raise_exception(EXCP0D_GPF);
1907 eflags = helper_cc_compute_all(CC_OP);
1908 d0 = ldq(a0);
1909 d1 = ldq(a0 + 8);
1910 if (d0 == EAX && d1 == EDX) {
1911 stq(a0, EBX);
1912 stq(a0 + 8, ECX);
1913 eflags |= CC_Z;
1914 } else {
1915 /* always do the store */
1916 stq(a0, d0);
1917 stq(a0 + 8, d1);
1918 EDX = d1;
1919 EAX = d0;
1920 eflags &= ~CC_Z;
1922 CC_SRC = eflags;
1924 #endif
1926 void helper_single_step(void)
1928 #ifndef CONFIG_USER_ONLY
1929 check_hw_breakpoints(env, 1);
1930 env->dr[6] |= DR6_BS;
1931 #endif
1932 raise_exception(EXCP01_DB);
1935 void helper_cpuid(void)
1937 uint32_t eax, ebx, ecx, edx;
1939 helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
1941 cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
1942 EAX = eax;
1943 EBX = ebx;
1944 ECX = ecx;
1945 EDX = edx;
1948 void helper_enter_level(int level, int data32, target_ulong t1)
1950 target_ulong ssp;
1951 uint32_t esp_mask, esp, ebp;
1953 esp_mask = get_sp_mask(env->segs[R_SS].flags);
1954 ssp = env->segs[R_SS].base;
1955 ebp = EBP;
1956 esp = ESP;
1957 if (data32) {
1958 /* 32 bit */
1959 esp -= 4;
1960 while (--level) {
1961 esp -= 4;
1962 ebp -= 4;
1963 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1965 esp -= 4;
1966 stl(ssp + (esp & esp_mask), t1);
1967 } else {
1968 /* 16 bit */
1969 esp -= 2;
1970 while (--level) {
1971 esp -= 2;
1972 ebp -= 2;
1973 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1975 esp -= 2;
1976 stw(ssp + (esp & esp_mask), t1);
1980 #ifdef TARGET_X86_64
1981 void helper_enter64_level(int level, int data64, target_ulong t1)
1983 target_ulong esp, ebp;
1984 ebp = EBP;
1985 esp = ESP;
1987 if (data64) {
1988 /* 64 bit */
1989 esp -= 8;
1990 while (--level) {
1991 esp -= 8;
1992 ebp -= 8;
1993 stq(esp, ldq(ebp));
1995 esp -= 8;
1996 stq(esp, t1);
1997 } else {
1998 /* 16 bit */
1999 esp -= 2;
2000 while (--level) {
2001 esp -= 2;
2002 ebp -= 2;
2003 stw(esp, lduw(ebp));
2005 esp -= 2;
2006 stw(esp, t1);
2009 #endif
2011 void helper_lldt(int selector)
2013 SegmentCache *dt;
2014 uint32_t e1, e2;
2015 int index, entry_limit;
2016 target_ulong ptr;
2018 selector &= 0xffff;
2019 if ((selector & 0xfffc) == 0) {
2020 /* XXX: NULL selector case: invalid LDT */
2021 env->ldt.base = 0;
2022 env->ldt.limit = 0;
2023 } else {
2024 if (selector & 0x4)
2025 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2026 dt = &env->gdt;
2027 index = selector & ~7;
2028 #ifdef TARGET_X86_64
2029 if (env->hflags & HF_LMA_MASK)
2030 entry_limit = 15;
2031 else
2032 #endif
2033 entry_limit = 7;
2034 if ((index + entry_limit) > dt->limit)
2035 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2036 ptr = dt->base + index;
2037 e1 = ldl_kernel(ptr);
2038 e2 = ldl_kernel(ptr + 4);
2039 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
2040 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2041 if (!(e2 & DESC_P_MASK))
2042 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2043 #ifdef TARGET_X86_64
2044 if (env->hflags & HF_LMA_MASK) {
2045 uint32_t e3;
2046 e3 = ldl_kernel(ptr + 8);
2047 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2048 env->ldt.base |= (target_ulong)e3 << 32;
2049 } else
2050 #endif
2052 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2055 env->ldt.selector = selector;
2058 void helper_ltr(int selector)
2060 SegmentCache *dt;
2061 uint32_t e1, e2;
2062 int index, type, entry_limit;
2063 target_ulong ptr;
2065 selector &= 0xffff;
2066 if ((selector & 0xfffc) == 0) {
2067 /* NULL selector case: invalid TR */
2068 env->tr.base = 0;
2069 env->tr.limit = 0;
2070 env->tr.flags = 0;
2071 } else {
2072 if (selector & 0x4)
2073 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2074 dt = &env->gdt;
2075 index = selector & ~7;
2076 #ifdef TARGET_X86_64
2077 if (env->hflags & HF_LMA_MASK)
2078 entry_limit = 15;
2079 else
2080 #endif
2081 entry_limit = 7;
2082 if ((index + entry_limit) > dt->limit)
2083 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2084 ptr = dt->base + index;
2085 e1 = ldl_kernel(ptr);
2086 e2 = ldl_kernel(ptr + 4);
2087 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2088 if ((e2 & DESC_S_MASK) ||
2089 (type != 1 && type != 9))
2090 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2091 if (!(e2 & DESC_P_MASK))
2092 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2093 #ifdef TARGET_X86_64
2094 if (env->hflags & HF_LMA_MASK) {
2095 uint32_t e3, e4;
2096 e3 = ldl_kernel(ptr + 8);
2097 e4 = ldl_kernel(ptr + 12);
2098 if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2099 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2100 load_seg_cache_raw_dt(&env->tr, e1, e2);
2101 env->tr.base |= (target_ulong)e3 << 32;
2102 } else
2103 #endif
2105 load_seg_cache_raw_dt(&env->tr, e1, e2);
2107 e2 |= DESC_TSS_BUSY_MASK;
2108 stl_kernel(ptr + 4, e2);
2110 env->tr.selector = selector;
2113 /* only works if protected mode and not VM86. seg_reg must be != R_CS */
2114 void helper_load_seg(int seg_reg, int selector)
2116 uint32_t e1, e2;
2117 int cpl, dpl, rpl;
2118 SegmentCache *dt;
2119 int index;
2120 target_ulong ptr;
2122 selector &= 0xffff;
2123 cpl = env->hflags & HF_CPL_MASK;
2124 if ((selector & 0xfffc) == 0) {
2125 /* null selector case */
2126 if (seg_reg == R_SS
2127 #ifdef TARGET_X86_64
2128 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2129 #endif
2131 raise_exception_err(EXCP0D_GPF, 0);
2132 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2133 } else {
2135 if (selector & 0x4)
2136 dt = &env->ldt;
2137 else
2138 dt = &env->gdt;
2139 index = selector & ~7;
2140 if ((index + 7) > dt->limit)
2141 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2142 ptr = dt->base + index;
2143 e1 = ldl_kernel(ptr);
2144 e2 = ldl_kernel(ptr + 4);
2146 if (!(e2 & DESC_S_MASK))
2147 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2148 rpl = selector & 3;
2149 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2150 if (seg_reg == R_SS) {
2151 /* must be writable segment */
2152 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2153 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2154 if (rpl != cpl || dpl != cpl)
2155 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2156 } else {
2157 /* must be readable segment */
2158 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2159 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2161 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2162 /* if not conforming code, test rights */
2163 if (dpl < cpl || dpl < rpl)
2164 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2168 if (!(e2 & DESC_P_MASK)) {
2169 if (seg_reg == R_SS)
2170 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2171 else
2172 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2175 /* set the access bit if not already set */
2176 if (!(e2 & DESC_A_MASK)) {
2177 e2 |= DESC_A_MASK;
2178 stl_kernel(ptr + 4, e2);
2181 cpu_x86_load_seg_cache(env, seg_reg, selector,
2182 get_seg_base(e1, e2),
2183 get_seg_limit(e1, e2),
2184 e2);
2185 #if 0
2186 qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2187 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2188 #endif
2192 /* protected mode jump */
2193 void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2194 int next_eip_addend)
2196 int gate_cs, type;
2197 uint32_t e1, e2, cpl, dpl, rpl, limit;
2198 target_ulong next_eip;
2200 if ((new_cs & 0xfffc) == 0)
2201 raise_exception_err(EXCP0D_GPF, 0);
2202 if (load_segment(&e1, &e2, new_cs) != 0)
2203 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2204 cpl = env->hflags & HF_CPL_MASK;
2205 if (e2 & DESC_S_MASK) {
2206 if (!(e2 & DESC_CS_MASK))
2207 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2208 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2209 if (e2 & DESC_C_MASK) {
2210 /* conforming code segment */
2211 if (dpl > cpl)
2212 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2213 } else {
2214 /* non conforming code segment */
2215 rpl = new_cs & 3;
2216 if (rpl > cpl)
2217 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2218 if (dpl != cpl)
2219 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2221 if (!(e2 & DESC_P_MASK))
2222 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2223 limit = get_seg_limit(e1, e2);
2224 if (new_eip > limit &&
2225 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2226 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2227 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2228 get_seg_base(e1, e2), limit, e2);
2229 EIP = new_eip;
2230 } else {
2231 /* jump to call or task gate */
2232 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2233 rpl = new_cs & 3;
2234 cpl = env->hflags & HF_CPL_MASK;
2235 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2236 switch(type) {
2237 case 1: /* 286 TSS */
2238 case 9: /* 386 TSS */
2239 case 5: /* task gate */
2240 if (dpl < cpl || dpl < rpl)
2241 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2242 next_eip = env->eip + next_eip_addend;
2243 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2244 CC_OP = CC_OP_EFLAGS;
2245 break;
2246 case 4: /* 286 call gate */
2247 case 12: /* 386 call gate */
2248 if ((dpl < cpl) || (dpl < rpl))
2249 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2250 if (!(e2 & DESC_P_MASK))
2251 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2252 gate_cs = e1 >> 16;
2253 new_eip = (e1 & 0xffff);
2254 if (type == 12)
2255 new_eip |= (e2 & 0xffff0000);
2256 if (load_segment(&e1, &e2, gate_cs) != 0)
2257 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2258 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2259 /* must be code segment */
2260 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2261 (DESC_S_MASK | DESC_CS_MASK)))
2262 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2263 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2264 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2265 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2266 if (!(e2 & DESC_P_MASK))
2267 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2268 limit = get_seg_limit(e1, e2);
2269 if (new_eip > limit)
2270 raise_exception_err(EXCP0D_GPF, 0);
2271 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2272 get_seg_base(e1, e2), limit, e2);
2273 EIP = new_eip;
2274 break;
2275 default:
2276 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2277 break;
2282 /* real mode call */
2283 void helper_lcall_real(int new_cs, target_ulong new_eip1,
2284 int shift, int next_eip)
2286 int new_eip;
2287 uint32_t esp, esp_mask;
2288 target_ulong ssp;
2290 new_eip = new_eip1;
2291 esp = ESP;
2292 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2293 ssp = env->segs[R_SS].base;
2294 if (shift) {
2295 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2296 PUSHL(ssp, esp, esp_mask, next_eip);
2297 } else {
2298 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2299 PUSHW(ssp, esp, esp_mask, next_eip);
2302 SET_ESP(esp, esp_mask);
2303 env->eip = new_eip;
2304 env->segs[R_CS].selector = new_cs;
2305 env->segs[R_CS].base = (new_cs << 4);
2308 /* protected mode call */
2309 void helper_lcall_protected(int new_cs, target_ulong new_eip,
2310 int shift, int next_eip_addend)
2312 int new_stack, i;
2313 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2314 uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
2315 uint32_t val, limit, old_sp_mask;
2316 target_ulong ssp, old_ssp, next_eip;
2318 next_eip = env->eip + next_eip_addend;
2319 LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
2320 LOG_PCALL_STATE(env);
2321 if ((new_cs & 0xfffc) == 0)
2322 raise_exception_err(EXCP0D_GPF, 0);
2323 if (load_segment(&e1, &e2, new_cs) != 0)
2324 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2325 cpl = env->hflags & HF_CPL_MASK;
2326 LOG_PCALL("desc=%08x:%08x\n", e1, e2);
2327 if (e2 & DESC_S_MASK) {
2328 if (!(e2 & DESC_CS_MASK))
2329 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2330 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2331 if (e2 & DESC_C_MASK) {
2332 /* conforming code segment */
2333 if (dpl > cpl)
2334 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2335 } else {
2336 /* non conforming code segment */
2337 rpl = new_cs & 3;
2338 if (rpl > cpl)
2339 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2340 if (dpl != cpl)
2341 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2343 if (!(e2 & DESC_P_MASK))
2344 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2346 #ifdef TARGET_X86_64
2347 /* XXX: check 16/32 bit cases in long mode */
2348 if (shift == 2) {
2349 target_ulong rsp;
2350 /* 64 bit case */
2351 rsp = ESP;
2352 PUSHQ(rsp, env->segs[R_CS].selector);
2353 PUSHQ(rsp, next_eip);
2354 /* from this point, not restartable */
2355 ESP = rsp;
2356 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2357 get_seg_base(e1, e2),
2358 get_seg_limit(e1, e2), e2);
2359 EIP = new_eip;
2360 } else
2361 #endif
2363 sp = ESP;
2364 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2365 ssp = env->segs[R_SS].base;
2366 if (shift) {
2367 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2368 PUSHL(ssp, sp, sp_mask, next_eip);
2369 } else {
2370 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2371 PUSHW(ssp, sp, sp_mask, next_eip);
2374 limit = get_seg_limit(e1, e2);
2375 if (new_eip > limit)
2376 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2377 /* from this point, not restartable */
2378 SET_ESP(sp, sp_mask);
2379 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2380 get_seg_base(e1, e2), limit, e2);
2381 EIP = new_eip;
2383 } else {
2384 /* check gate type */
2385 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2386 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2387 rpl = new_cs & 3;
2388 switch(type) {
2389 case 1: /* available 286 TSS */
2390 case 9: /* available 386 TSS */
2391 case 5: /* task gate */
2392 if (dpl < cpl || dpl < rpl)
2393 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2394 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2395 CC_OP = CC_OP_EFLAGS;
2396 return;
2397 case 4: /* 286 call gate */
2398 case 12: /* 386 call gate */
2399 break;
2400 default:
2401 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2402 break;
2404 shift = type >> 3;
2406 if (dpl < cpl || dpl < rpl)
2407 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2408 /* check valid bit */
2409 if (!(e2 & DESC_P_MASK))
2410 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2411 selector = e1 >> 16;
2412 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2413 param_count = e2 & 0x1f;
2414 if ((selector & 0xfffc) == 0)
2415 raise_exception_err(EXCP0D_GPF, 0);
2417 if (load_segment(&e1, &e2, selector) != 0)
2418 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2419 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2420 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2421 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2422 if (dpl > cpl)
2423 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2424 if (!(e2 & DESC_P_MASK))
2425 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2427 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2428 /* to inner privilege */
2429 get_ss_esp_from_tss(&ss, &sp, dpl);
2430 LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2431 ss, sp, param_count, ESP);
2432 if ((ss & 0xfffc) == 0)
2433 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2434 if ((ss & 3) != dpl)
2435 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2436 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2437 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2438 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2439 if (ss_dpl != dpl)
2440 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2441 if (!(ss_e2 & DESC_S_MASK) ||
2442 (ss_e2 & DESC_CS_MASK) ||
2443 !(ss_e2 & DESC_W_MASK))
2444 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2445 if (!(ss_e2 & DESC_P_MASK))
2446 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2448 // push_size = ((param_count * 2) + 8) << shift;
2450 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2451 old_ssp = env->segs[R_SS].base;
2453 sp_mask = get_sp_mask(ss_e2);
2454 ssp = get_seg_base(ss_e1, ss_e2);
2455 if (shift) {
2456 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2457 PUSHL(ssp, sp, sp_mask, ESP);
2458 for(i = param_count - 1; i >= 0; i--) {
2459 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2460 PUSHL(ssp, sp, sp_mask, val);
2462 } else {
2463 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2464 PUSHW(ssp, sp, sp_mask, ESP);
2465 for(i = param_count - 1; i >= 0; i--) {
2466 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2467 PUSHW(ssp, sp, sp_mask, val);
2470 new_stack = 1;
2471 } else {
2472 /* to same privilege */
2473 sp = ESP;
2474 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2475 ssp = env->segs[R_SS].base;
2476 // push_size = (4 << shift);
2477 new_stack = 0;
2480 if (shift) {
2481 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2482 PUSHL(ssp, sp, sp_mask, next_eip);
2483 } else {
2484 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2485 PUSHW(ssp, sp, sp_mask, next_eip);
2488 /* from this point, not restartable */
2490 if (new_stack) {
2491 ss = (ss & ~3) | dpl;
2492 cpu_x86_load_seg_cache(env, R_SS, ss,
2493 ssp,
2494 get_seg_limit(ss_e1, ss_e2),
2495 ss_e2);
2498 selector = (selector & ~3) | dpl;
2499 cpu_x86_load_seg_cache(env, R_CS, selector,
2500 get_seg_base(e1, e2),
2501 get_seg_limit(e1, e2),
2502 e2);
2503 cpu_x86_set_cpl(env, dpl);
2504 SET_ESP(sp, sp_mask);
2505 EIP = offset;
2509 /* real and vm86 mode iret */
2510 void helper_iret_real(int shift)
2512 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2513 target_ulong ssp;
2514 int eflags_mask;
2516 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2517 sp = ESP;
2518 ssp = env->segs[R_SS].base;
2519 if (shift == 1) {
2520 /* 32 bits */
2521 POPL(ssp, sp, sp_mask, new_eip);
2522 POPL(ssp, sp, sp_mask, new_cs);
2523 new_cs &= 0xffff;
2524 POPL(ssp, sp, sp_mask, new_eflags);
2525 } else {
2526 /* 16 bits */
2527 POPW(ssp, sp, sp_mask, new_eip);
2528 POPW(ssp, sp, sp_mask, new_cs);
2529 POPW(ssp, sp, sp_mask, new_eflags);
2531 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2532 env->segs[R_CS].selector = new_cs;
2533 env->segs[R_CS].base = (new_cs << 4);
2534 env->eip = new_eip;
2535 if (env->eflags & VM_MASK)
2536 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2537 else
2538 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2539 if (shift == 0)
2540 eflags_mask &= 0xffff;
2541 load_eflags(new_eflags, eflags_mask);
2542 env->hflags2 &= ~HF2_NMI_MASK;
2545 static inline void validate_seg(int seg_reg, int cpl)
2547 int dpl;
2548 uint32_t e2;
2550 /* XXX: on x86_64, we do not want to nullify FS and GS because
2551 they may still contain a valid base. I would be interested to
2552 know how a real x86_64 CPU behaves */
2553 if ((seg_reg == R_FS || seg_reg == R_GS) &&
2554 (env->segs[seg_reg].selector & 0xfffc) == 0)
2555 return;
2557 e2 = env->segs[seg_reg].flags;
2558 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2559 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2560 /* data or non conforming code segment */
2561 if (dpl < cpl) {
2562 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2567 /* protected mode iret */
2568 static inline void helper_ret_protected(int shift, int is_iret, int addend)
2570 uint32_t new_cs, new_eflags, new_ss;
2571 uint32_t new_es, new_ds, new_fs, new_gs;
2572 uint32_t e1, e2, ss_e1, ss_e2;
2573 int cpl, dpl, rpl, eflags_mask, iopl;
2574 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2576 #ifdef TARGET_X86_64
2577 if (shift == 2)
2578 sp_mask = -1;
2579 else
2580 #endif
2581 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2582 sp = ESP;
2583 ssp = env->segs[R_SS].base;
2584 new_eflags = 0; /* avoid warning */
2585 #ifdef TARGET_X86_64
2586 if (shift == 2) {
2587 POPQ(sp, new_eip);
2588 POPQ(sp, new_cs);
2589 new_cs &= 0xffff;
2590 if (is_iret) {
2591 POPQ(sp, new_eflags);
2593 } else
2594 #endif
2595 if (shift == 1) {
2596 /* 32 bits */
2597 POPL(ssp, sp, sp_mask, new_eip);
2598 POPL(ssp, sp, sp_mask, new_cs);
2599 new_cs &= 0xffff;
2600 if (is_iret) {
2601 POPL(ssp, sp, sp_mask, new_eflags);
2602 if (new_eflags & VM_MASK)
2603 goto return_to_vm86;
2605 } else {
2606 /* 16 bits */
2607 POPW(ssp, sp, sp_mask, new_eip);
2608 POPW(ssp, sp, sp_mask, new_cs);
2609 if (is_iret)
2610 POPW(ssp, sp, sp_mask, new_eflags);
2612 LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2613 new_cs, new_eip, shift, addend);
2614 LOG_PCALL_STATE(env);
2615 if ((new_cs & 0xfffc) == 0)
2616 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2617 if (load_segment(&e1, &e2, new_cs) != 0)
2618 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2619 if (!(e2 & DESC_S_MASK) ||
2620 !(e2 & DESC_CS_MASK))
2621 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2622 cpl = env->hflags & HF_CPL_MASK;
2623 rpl = new_cs & 3;
2624 if (rpl < cpl)
2625 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2626 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2627 if (e2 & DESC_C_MASK) {
2628 if (dpl > rpl)
2629 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2630 } else {
2631 if (dpl != rpl)
2632 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2634 if (!(e2 & DESC_P_MASK))
2635 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2637 sp += addend;
2638 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2639 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2640 /* return to same privilege level */
2641 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2642 get_seg_base(e1, e2),
2643 get_seg_limit(e1, e2),
2644 e2);
2645 } else {
2646 /* return to different privilege level */
2647 #ifdef TARGET_X86_64
2648 if (shift == 2) {
2649 POPQ(sp, new_esp);
2650 POPQ(sp, new_ss);
2651 new_ss &= 0xffff;
2652 } else
2653 #endif
2654 if (shift == 1) {
2655 /* 32 bits */
2656 POPL(ssp, sp, sp_mask, new_esp);
2657 POPL(ssp, sp, sp_mask, new_ss);
2658 new_ss &= 0xffff;
2659 } else {
2660 /* 16 bits */
2661 POPW(ssp, sp, sp_mask, new_esp);
2662 POPW(ssp, sp, sp_mask, new_ss);
2664 LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
2665 new_ss, new_esp);
2666 if ((new_ss & 0xfffc) == 0) {
2667 #ifdef TARGET_X86_64
2668 /* NULL ss is allowed in long mode if cpl != 3*/
2669 /* XXX: test CS64 ? */
2670 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2671 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2672 0, 0xffffffff,
2673 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2674 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2675 DESC_W_MASK | DESC_A_MASK);
2676 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2677 } else
2678 #endif
2680 raise_exception_err(EXCP0D_GPF, 0);
2682 } else {
2683 if ((new_ss & 3) != rpl)
2684 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2685 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2686 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2687 if (!(ss_e2 & DESC_S_MASK) ||
2688 (ss_e2 & DESC_CS_MASK) ||
2689 !(ss_e2 & DESC_W_MASK))
2690 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2691 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2692 if (dpl != rpl)
2693 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2694 if (!(ss_e2 & DESC_P_MASK))
2695 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2696 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2697 get_seg_base(ss_e1, ss_e2),
2698 get_seg_limit(ss_e1, ss_e2),
2699 ss_e2);
2702 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2703 get_seg_base(e1, e2),
2704 get_seg_limit(e1, e2),
2705 e2);
2706 cpu_x86_set_cpl(env, rpl);
2707 sp = new_esp;
2708 #ifdef TARGET_X86_64
2709 if (env->hflags & HF_CS64_MASK)
2710 sp_mask = -1;
2711 else
2712 #endif
2713 sp_mask = get_sp_mask(ss_e2);
2715 /* validate data segments */
2716 validate_seg(R_ES, rpl);
2717 validate_seg(R_DS, rpl);
2718 validate_seg(R_FS, rpl);
2719 validate_seg(R_GS, rpl);
2721 sp += addend;
2723 SET_ESP(sp, sp_mask);
2724 env->eip = new_eip;
2725 if (is_iret) {
2726 /* NOTE: 'cpl' is the _old_ CPL */
2727 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2728 if (cpl == 0)
2729 eflags_mask |= IOPL_MASK;
2730 iopl = (env->eflags >> IOPL_SHIFT) & 3;
2731 if (cpl <= iopl)
2732 eflags_mask |= IF_MASK;
2733 if (shift == 0)
2734 eflags_mask &= 0xffff;
2735 load_eflags(new_eflags, eflags_mask);
2737 return;
2739 return_to_vm86:
2740 POPL(ssp, sp, sp_mask, new_esp);
2741 POPL(ssp, sp, sp_mask, new_ss);
2742 POPL(ssp, sp, sp_mask, new_es);
2743 POPL(ssp, sp, sp_mask, new_ds);
2744 POPL(ssp, sp, sp_mask, new_fs);
2745 POPL(ssp, sp, sp_mask, new_gs);
2747 /* modify processor state */
2748 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2749 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2750 load_seg_vm(R_CS, new_cs & 0xffff);
2751 cpu_x86_set_cpl(env, 3);
2752 load_seg_vm(R_SS, new_ss & 0xffff);
2753 load_seg_vm(R_ES, new_es & 0xffff);
2754 load_seg_vm(R_DS, new_ds & 0xffff);
2755 load_seg_vm(R_FS, new_fs & 0xffff);
2756 load_seg_vm(R_GS, new_gs & 0xffff);
2758 env->eip = new_eip & 0xffff;
2759 ESP = new_esp;
2762 void helper_iret_protected(int shift, int next_eip)
2764 int tss_selector, type;
2765 uint32_t e1, e2;
2767 /* specific case for TSS */
2768 if (env->eflags & NT_MASK) {
2769 #ifdef TARGET_X86_64
2770 if (env->hflags & HF_LMA_MASK)
2771 raise_exception_err(EXCP0D_GPF, 0);
2772 #endif
2773 tss_selector = lduw_kernel(env->tr.base + 0);
2774 if (tss_selector & 4)
2775 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2776 if (load_segment(&e1, &e2, tss_selector) != 0)
2777 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2778 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2779 /* NOTE: we check both segment and busy TSS */
2780 if (type != 3)
2781 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2782 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2783 } else {
2784 helper_ret_protected(shift, 1, 0);
2786 env->hflags2 &= ~HF2_NMI_MASK;
2789 void helper_lret_protected(int shift, int addend)
2791 helper_ret_protected(shift, 0, addend);
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;
2866 #if defined(CONFIG_USER_ONLY)
2867 target_ulong helper_read_crN(int reg)
2869 return 0;
2872 void helper_write_crN(int reg, target_ulong t0)
2876 void helper_movl_drN_T0(int reg, target_ulong t0)
2879 #else
2880 target_ulong helper_read_crN(int reg)
2882 target_ulong val;
2884 helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
2885 switch(reg) {
2886 default:
2887 val = env->cr[reg];
2888 break;
2889 case 8:
2890 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2891 val = cpu_get_apic_tpr(env->apic_state);
2892 } else {
2893 val = env->v_tpr;
2895 break;
2897 return val;
2900 void helper_write_crN(int reg, target_ulong t0)
2902 helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
2903 switch(reg) {
2904 case 0:
2905 cpu_x86_update_cr0(env, t0);
2906 break;
2907 case 3:
2908 cpu_x86_update_cr3(env, t0);
2909 break;
2910 case 4:
2911 cpu_x86_update_cr4(env, t0);
2912 break;
2913 case 8:
2914 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2915 cpu_set_apic_tpr(env->apic_state, t0);
2917 env->v_tpr = t0 & 0x0f;
2918 break;
2919 default:
2920 env->cr[reg] = t0;
2921 break;
2925 void helper_movl_drN_T0(int reg, target_ulong t0)
2927 int i;
2929 if (reg < 4) {
2930 hw_breakpoint_remove(env, reg);
2931 env->dr[reg] = t0;
2932 hw_breakpoint_insert(env, reg);
2933 } else if (reg == 7) {
2934 for (i = 0; i < 4; i++)
2935 hw_breakpoint_remove(env, i);
2936 env->dr[7] = t0;
2937 for (i = 0; i < 4; i++)
2938 hw_breakpoint_insert(env, i);
2939 } else
2940 env->dr[reg] = t0;
2942 #endif
2944 void helper_lmsw(target_ulong t0)
2946 /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
2947 if already set to one. */
2948 t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
2949 helper_write_crN(0, t0);
2952 void helper_clts(void)
2954 env->cr[0] &= ~CR0_TS_MASK;
2955 env->hflags &= ~HF_TS_MASK;
2958 void helper_invlpg(target_ulong addr)
2960 helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
2961 tlb_flush_page(env, addr);
2964 void helper_rdtsc(void)
2966 uint64_t val;
2968 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2969 raise_exception(EXCP0D_GPF);
2971 helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
2973 val = cpu_get_tsc(env) + env->tsc_offset;
2974 EAX = (uint32_t)(val);
2975 EDX = (uint32_t)(val >> 32);
2978 void helper_rdtscp(void)
2980 helper_rdtsc();
2981 ECX = (uint32_t)(env->tsc_aux);
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->apic_state, 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 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3040 update_mask |= MSR_EFER_FFXSR;
3041 cpu_load_efer(env, (env->efer & ~update_mask) |
3042 (val & update_mask));
3044 break;
3045 case MSR_STAR:
3046 env->star = val;
3047 break;
3048 case MSR_PAT:
3049 env->pat = val;
3050 break;
3051 case MSR_VM_HSAVE_PA:
3052 env->vm_hsave = val;
3053 break;
3054 #ifdef TARGET_X86_64
3055 case MSR_LSTAR:
3056 env->lstar = val;
3057 break;
3058 case MSR_CSTAR:
3059 env->cstar = val;
3060 break;
3061 case MSR_FMASK:
3062 env->fmask = val;
3063 break;
3064 case MSR_FSBASE:
3065 env->segs[R_FS].base = val;
3066 break;
3067 case MSR_GSBASE:
3068 env->segs[R_GS].base = val;
3069 break;
3070 case MSR_KERNELGSBASE:
3071 env->kernelgsbase = val;
3072 break;
3073 #endif
3074 case MSR_MTRRphysBase(0):
3075 case MSR_MTRRphysBase(1):
3076 case MSR_MTRRphysBase(2):
3077 case MSR_MTRRphysBase(3):
3078 case MSR_MTRRphysBase(4):
3079 case MSR_MTRRphysBase(5):
3080 case MSR_MTRRphysBase(6):
3081 case MSR_MTRRphysBase(7):
3082 env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
3083 break;
3084 case MSR_MTRRphysMask(0):
3085 case MSR_MTRRphysMask(1):
3086 case MSR_MTRRphysMask(2):
3087 case MSR_MTRRphysMask(3):
3088 case MSR_MTRRphysMask(4):
3089 case MSR_MTRRphysMask(5):
3090 case MSR_MTRRphysMask(6):
3091 case MSR_MTRRphysMask(7):
3092 env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
3093 break;
3094 case MSR_MTRRfix64K_00000:
3095 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
3096 break;
3097 case MSR_MTRRfix16K_80000:
3098 case MSR_MTRRfix16K_A0000:
3099 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
3100 break;
3101 case MSR_MTRRfix4K_C0000:
3102 case MSR_MTRRfix4K_C8000:
3103 case MSR_MTRRfix4K_D0000:
3104 case MSR_MTRRfix4K_D8000:
3105 case MSR_MTRRfix4K_E0000:
3106 case MSR_MTRRfix4K_E8000:
3107 case MSR_MTRRfix4K_F0000:
3108 case MSR_MTRRfix4K_F8000:
3109 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
3110 break;
3111 case MSR_MTRRdefType:
3112 env->mtrr_deftype = val;
3113 break;
3114 case MSR_MCG_STATUS:
3115 env->mcg_status = val;
3116 break;
3117 case MSR_MCG_CTL:
3118 if ((env->mcg_cap & MCG_CTL_P)
3119 && (val == 0 || val == ~(uint64_t)0))
3120 env->mcg_ctl = val;
3121 break;
3122 case MSR_TSC_AUX:
3123 env->tsc_aux = val;
3124 break;
3125 default:
3126 if ((uint32_t)ECX >= MSR_MC0_CTL
3127 && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
3128 uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
3129 if ((offset & 0x3) != 0
3130 || (val == 0 || val == ~(uint64_t)0))
3131 env->mce_banks[offset] = val;
3132 break;
3134 /* XXX: exception ? */
3135 break;
3139 void helper_rdmsr(void)
3141 uint64_t val;
3143 helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3145 switch((uint32_t)ECX) {
3146 case MSR_IA32_SYSENTER_CS:
3147 val = env->sysenter_cs;
3148 break;
3149 case MSR_IA32_SYSENTER_ESP:
3150 val = env->sysenter_esp;
3151 break;
3152 case MSR_IA32_SYSENTER_EIP:
3153 val = env->sysenter_eip;
3154 break;
3155 case MSR_IA32_APICBASE:
3156 val = cpu_get_apic_base(env->apic_state);
3157 break;
3158 case MSR_EFER:
3159 val = env->efer;
3160 break;
3161 case MSR_STAR:
3162 val = env->star;
3163 break;
3164 case MSR_PAT:
3165 val = env->pat;
3166 break;
3167 case MSR_VM_HSAVE_PA:
3168 val = env->vm_hsave;
3169 break;
3170 case MSR_IA32_PERF_STATUS:
3171 /* tsc_increment_by_tick */
3172 val = 1000ULL;
3173 /* CPU multiplier */
3174 val |= (((uint64_t)4ULL) << 40);
3175 break;
3176 #ifdef TARGET_X86_64
3177 case MSR_LSTAR:
3178 val = env->lstar;
3179 break;
3180 case MSR_CSTAR:
3181 val = env->cstar;
3182 break;
3183 case MSR_FMASK:
3184 val = env->fmask;
3185 break;
3186 case MSR_FSBASE:
3187 val = env->segs[R_FS].base;
3188 break;
3189 case MSR_GSBASE:
3190 val = env->segs[R_GS].base;
3191 break;
3192 case MSR_KERNELGSBASE:
3193 val = env->kernelgsbase;
3194 break;
3195 case MSR_TSC_AUX:
3196 val = env->tsc_aux;
3197 break;
3198 #endif
3199 case MSR_MTRRphysBase(0):
3200 case MSR_MTRRphysBase(1):
3201 case MSR_MTRRphysBase(2):
3202 case MSR_MTRRphysBase(3):
3203 case MSR_MTRRphysBase(4):
3204 case MSR_MTRRphysBase(5):
3205 case MSR_MTRRphysBase(6):
3206 case MSR_MTRRphysBase(7):
3207 val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
3208 break;
3209 case MSR_MTRRphysMask(0):
3210 case MSR_MTRRphysMask(1):
3211 case MSR_MTRRphysMask(2):
3212 case MSR_MTRRphysMask(3):
3213 case MSR_MTRRphysMask(4):
3214 case MSR_MTRRphysMask(5):
3215 case MSR_MTRRphysMask(6):
3216 case MSR_MTRRphysMask(7):
3217 val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
3218 break;
3219 case MSR_MTRRfix64K_00000:
3220 val = env->mtrr_fixed[0];
3221 break;
3222 case MSR_MTRRfix16K_80000:
3223 case MSR_MTRRfix16K_A0000:
3224 val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
3225 break;
3226 case MSR_MTRRfix4K_C0000:
3227 case MSR_MTRRfix4K_C8000:
3228 case MSR_MTRRfix4K_D0000:
3229 case MSR_MTRRfix4K_D8000:
3230 case MSR_MTRRfix4K_E0000:
3231 case MSR_MTRRfix4K_E8000:
3232 case MSR_MTRRfix4K_F0000:
3233 case MSR_MTRRfix4K_F8000:
3234 val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
3235 break;
3236 case MSR_MTRRdefType:
3237 val = env->mtrr_deftype;
3238 break;
3239 case MSR_MTRRcap:
3240 if (env->cpuid_features & CPUID_MTRR)
3241 val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
3242 else
3243 /* XXX: exception ? */
3244 val = 0;
3245 break;
3246 case MSR_MCG_CAP:
3247 val = env->mcg_cap;
3248 break;
3249 case MSR_MCG_CTL:
3250 if (env->mcg_cap & MCG_CTL_P)
3251 val = env->mcg_ctl;
3252 else
3253 val = 0;
3254 break;
3255 case MSR_MCG_STATUS:
3256 val = env->mcg_status;
3257 break;
3258 default:
3259 if ((uint32_t)ECX >= MSR_MC0_CTL
3260 && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
3261 uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
3262 val = env->mce_banks[offset];
3263 break;
3265 /* XXX: exception ? */
3266 val = 0;
3267 break;
3269 EAX = (uint32_t)(val);
3270 EDX = (uint32_t)(val >> 32);
3272 #endif
3274 target_ulong helper_lsl(target_ulong selector1)
3276 unsigned int limit;
3277 uint32_t e1, e2, eflags, selector;
3278 int rpl, dpl, cpl, type;
3280 selector = selector1 & 0xffff;
3281 eflags = helper_cc_compute_all(CC_OP);
3282 if ((selector & 0xfffc) == 0)
3283 goto fail;
3284 if (load_segment(&e1, &e2, selector) != 0)
3285 goto fail;
3286 rpl = selector & 3;
3287 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3288 cpl = env->hflags & HF_CPL_MASK;
3289 if (e2 & DESC_S_MASK) {
3290 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3291 /* conforming */
3292 } else {
3293 if (dpl < cpl || dpl < rpl)
3294 goto fail;
3296 } else {
3297 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3298 switch(type) {
3299 case 1:
3300 case 2:
3301 case 3:
3302 case 9:
3303 case 11:
3304 break;
3305 default:
3306 goto fail;
3308 if (dpl < cpl || dpl < rpl) {
3309 fail:
3310 CC_SRC = eflags & ~CC_Z;
3311 return 0;
3314 limit = get_seg_limit(e1, e2);
3315 CC_SRC = eflags | CC_Z;
3316 return limit;
3319 target_ulong helper_lar(target_ulong selector1)
3321 uint32_t e1, e2, eflags, selector;
3322 int rpl, dpl, cpl, type;
3324 selector = selector1 & 0xffff;
3325 eflags = helper_cc_compute_all(CC_OP);
3326 if ((selector & 0xfffc) == 0)
3327 goto fail;
3328 if (load_segment(&e1, &e2, selector) != 0)
3329 goto fail;
3330 rpl = selector & 3;
3331 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3332 cpl = env->hflags & HF_CPL_MASK;
3333 if (e2 & DESC_S_MASK) {
3334 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3335 /* conforming */
3336 } else {
3337 if (dpl < cpl || dpl < rpl)
3338 goto fail;
3340 } else {
3341 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3342 switch(type) {
3343 case 1:
3344 case 2:
3345 case 3:
3346 case 4:
3347 case 5:
3348 case 9:
3349 case 11:
3350 case 12:
3351 break;
3352 default:
3353 goto fail;
3355 if (dpl < cpl || dpl < rpl) {
3356 fail:
3357 CC_SRC = eflags & ~CC_Z;
3358 return 0;
3361 CC_SRC = eflags | CC_Z;
3362 return e2 & 0x00f0ff00;
3365 void helper_verr(target_ulong selector1)
3367 uint32_t e1, e2, eflags, selector;
3368 int rpl, dpl, cpl;
3370 selector = selector1 & 0xffff;
3371 eflags = helper_cc_compute_all(CC_OP);
3372 if ((selector & 0xfffc) == 0)
3373 goto fail;
3374 if (load_segment(&e1, &e2, selector) != 0)
3375 goto fail;
3376 if (!(e2 & DESC_S_MASK))
3377 goto fail;
3378 rpl = selector & 3;
3379 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3380 cpl = env->hflags & HF_CPL_MASK;
3381 if (e2 & DESC_CS_MASK) {
3382 if (!(e2 & DESC_R_MASK))
3383 goto fail;
3384 if (!(e2 & DESC_C_MASK)) {
3385 if (dpl < cpl || dpl < rpl)
3386 goto fail;
3388 } else {
3389 if (dpl < cpl || dpl < rpl) {
3390 fail:
3391 CC_SRC = eflags & ~CC_Z;
3392 return;
3395 CC_SRC = eflags | CC_Z;
3398 void helper_verw(target_ulong selector1)
3400 uint32_t e1, e2, eflags, selector;
3401 int rpl, dpl, cpl;
3403 selector = selector1 & 0xffff;
3404 eflags = helper_cc_compute_all(CC_OP);
3405 if ((selector & 0xfffc) == 0)
3406 goto fail;
3407 if (load_segment(&e1, &e2, selector) != 0)
3408 goto fail;
3409 if (!(e2 & DESC_S_MASK))
3410 goto fail;
3411 rpl = selector & 3;
3412 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3413 cpl = env->hflags & HF_CPL_MASK;
3414 if (e2 & DESC_CS_MASK) {
3415 goto fail;
3416 } else {
3417 if (dpl < cpl || dpl < rpl)
3418 goto fail;
3419 if (!(e2 & DESC_W_MASK)) {
3420 fail:
3421 CC_SRC = eflags & ~CC_Z;
3422 return;
3425 CC_SRC = eflags | CC_Z;
3428 /* x87 FPU helpers */
3430 static void fpu_set_exception(int mask)
3432 env->fpus |= mask;
3433 if (env->fpus & (~env->fpuc & FPUC_EM))
3434 env->fpus |= FPUS_SE | FPUS_B;
3437 static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3439 if (b == 0.0)
3440 fpu_set_exception(FPUS_ZE);
3441 return a / b;
3444 static void fpu_raise_exception(void)
3446 if (env->cr[0] & CR0_NE_MASK) {
3447 raise_exception(EXCP10_COPR);
3449 #if !defined(CONFIG_USER_ONLY)
3450 else {
3451 cpu_set_ferr(env);
3453 #endif
3456 void helper_flds_FT0(uint32_t val)
3458 union {
3459 float32 f;
3460 uint32_t i;
3461 } u;
3462 u.i = val;
3463 FT0 = float32_to_floatx(u.f, &env->fp_status);
3466 void helper_fldl_FT0(uint64_t val)
3468 union {
3469 float64 f;
3470 uint64_t i;
3471 } u;
3472 u.i = val;
3473 FT0 = float64_to_floatx(u.f, &env->fp_status);
3476 void helper_fildl_FT0(int32_t val)
3478 FT0 = int32_to_floatx(val, &env->fp_status);
3481 void helper_flds_ST0(uint32_t val)
3483 int new_fpstt;
3484 union {
3485 float32 f;
3486 uint32_t i;
3487 } u;
3488 new_fpstt = (env->fpstt - 1) & 7;
3489 u.i = val;
3490 env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
3491 env->fpstt = new_fpstt;
3492 env->fptags[new_fpstt] = 0; /* validate stack entry */
3495 void helper_fldl_ST0(uint64_t val)
3497 int new_fpstt;
3498 union {
3499 float64 f;
3500 uint64_t i;
3501 } u;
3502 new_fpstt = (env->fpstt - 1) & 7;
3503 u.i = val;
3504 env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
3505 env->fpstt = new_fpstt;
3506 env->fptags[new_fpstt] = 0; /* validate stack entry */
3509 void helper_fildl_ST0(int32_t val)
3511 int new_fpstt;
3512 new_fpstt = (env->fpstt - 1) & 7;
3513 env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
3514 env->fpstt = new_fpstt;
3515 env->fptags[new_fpstt] = 0; /* validate stack entry */
3518 void helper_fildll_ST0(int64_t val)
3520 int new_fpstt;
3521 new_fpstt = (env->fpstt - 1) & 7;
3522 env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
3523 env->fpstt = new_fpstt;
3524 env->fptags[new_fpstt] = 0; /* validate stack entry */
3527 uint32_t helper_fsts_ST0(void)
3529 union {
3530 float32 f;
3531 uint32_t i;
3532 } u;
3533 u.f = floatx_to_float32(ST0, &env->fp_status);
3534 return u.i;
3537 uint64_t helper_fstl_ST0(void)
3539 union {
3540 float64 f;
3541 uint64_t i;
3542 } u;
3543 u.f = floatx_to_float64(ST0, &env->fp_status);
3544 return u.i;
3547 int32_t helper_fist_ST0(void)
3549 int32_t val;
3550 val = floatx_to_int32(ST0, &env->fp_status);
3551 if (val != (int16_t)val)
3552 val = -32768;
3553 return val;
3556 int32_t helper_fistl_ST0(void)
3558 int32_t val;
3559 val = floatx_to_int32(ST0, &env->fp_status);
3560 return val;
3563 int64_t helper_fistll_ST0(void)
3565 int64_t val;
3566 val = floatx_to_int64(ST0, &env->fp_status);
3567 return val;
3570 int32_t helper_fistt_ST0(void)
3572 int32_t val;
3573 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3574 if (val != (int16_t)val)
3575 val = -32768;
3576 return val;
3579 int32_t helper_fisttl_ST0(void)
3581 int32_t val;
3582 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3583 return val;
3586 int64_t helper_fisttll_ST0(void)
3588 int64_t val;
3589 val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
3590 return val;
3593 void helper_fldt_ST0(target_ulong ptr)
3595 int new_fpstt;
3596 new_fpstt = (env->fpstt - 1) & 7;
3597 env->fpregs[new_fpstt].d = helper_fldt(ptr);
3598 env->fpstt = new_fpstt;
3599 env->fptags[new_fpstt] = 0; /* validate stack entry */
3602 void helper_fstt_ST0(target_ulong ptr)
3604 helper_fstt(ST0, ptr);
3607 void helper_fpush(void)
3609 fpush();
3612 void helper_fpop(void)
3614 fpop();
3617 void helper_fdecstp(void)
3619 env->fpstt = (env->fpstt - 1) & 7;
3620 env->fpus &= (~0x4700);
3623 void helper_fincstp(void)
3625 env->fpstt = (env->fpstt + 1) & 7;
3626 env->fpus &= (~0x4700);
3629 /* FPU move */
3631 void helper_ffree_STN(int st_index)
3633 env->fptags[(env->fpstt + st_index) & 7] = 1;
3636 void helper_fmov_ST0_FT0(void)
3638 ST0 = FT0;
3641 void helper_fmov_FT0_STN(int st_index)
3643 FT0 = ST(st_index);
3646 void helper_fmov_ST0_STN(int st_index)
3648 ST0 = ST(st_index);
3651 void helper_fmov_STN_ST0(int st_index)
3653 ST(st_index) = ST0;
3656 void helper_fxchg_ST0_STN(int st_index)
3658 CPU86_LDouble tmp;
3659 tmp = ST(st_index);
3660 ST(st_index) = ST0;
3661 ST0 = tmp;
3664 /* FPU operations */
3666 static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
3668 void helper_fcom_ST0_FT0(void)
3670 int ret;
3672 ret = floatx_compare(ST0, FT0, &env->fp_status);
3673 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
3676 void helper_fucom_ST0_FT0(void)
3678 int ret;
3680 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3681 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
3684 static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
3686 void helper_fcomi_ST0_FT0(void)
3688 int eflags;
3689 int ret;
3691 ret = floatx_compare(ST0, FT0, &env->fp_status);
3692 eflags = helper_cc_compute_all(CC_OP);
3693 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3694 CC_SRC = eflags;
3697 void helper_fucomi_ST0_FT0(void)
3699 int eflags;
3700 int ret;
3702 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3703 eflags = helper_cc_compute_all(CC_OP);
3704 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3705 CC_SRC = eflags;
3708 void helper_fadd_ST0_FT0(void)
3710 ST0 += FT0;
3713 void helper_fmul_ST0_FT0(void)
3715 ST0 *= FT0;
3718 void helper_fsub_ST0_FT0(void)
3720 ST0 -= FT0;
3723 void helper_fsubr_ST0_FT0(void)
3725 ST0 = FT0 - ST0;
3728 void helper_fdiv_ST0_FT0(void)
3730 ST0 = helper_fdiv(ST0, FT0);
3733 void helper_fdivr_ST0_FT0(void)
3735 ST0 = helper_fdiv(FT0, ST0);
3738 /* fp operations between STN and ST0 */
3740 void helper_fadd_STN_ST0(int st_index)
3742 ST(st_index) += ST0;
3745 void helper_fmul_STN_ST0(int st_index)
3747 ST(st_index) *= ST0;
3750 void helper_fsub_STN_ST0(int st_index)
3752 ST(st_index) -= ST0;
3755 void helper_fsubr_STN_ST0(int st_index)
3757 CPU86_LDouble *p;
3758 p = &ST(st_index);
3759 *p = ST0 - *p;
3762 void helper_fdiv_STN_ST0(int st_index)
3764 CPU86_LDouble *p;
3765 p = &ST(st_index);
3766 *p = helper_fdiv(*p, ST0);
3769 void helper_fdivr_STN_ST0(int st_index)
3771 CPU86_LDouble *p;
3772 p = &ST(st_index);
3773 *p = helper_fdiv(ST0, *p);
3776 /* misc FPU operations */
3777 void helper_fchs_ST0(void)
3779 ST0 = floatx_chs(ST0);
3782 void helper_fabs_ST0(void)
3784 ST0 = floatx_abs(ST0);
3787 void helper_fld1_ST0(void)
3789 ST0 = f15rk[1];
3792 void helper_fldl2t_ST0(void)
3794 ST0 = f15rk[6];
3797 void helper_fldl2e_ST0(void)
3799 ST0 = f15rk[5];
3802 void helper_fldpi_ST0(void)
3804 ST0 = f15rk[2];
3807 void helper_fldlg2_ST0(void)
3809 ST0 = f15rk[3];
3812 void helper_fldln2_ST0(void)
3814 ST0 = f15rk[4];
3817 void helper_fldz_ST0(void)
3819 ST0 = f15rk[0];
3822 void helper_fldz_FT0(void)
3824 FT0 = f15rk[0];
3827 uint32_t helper_fnstsw(void)
3829 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3832 uint32_t helper_fnstcw(void)
3834 return env->fpuc;
3837 static void update_fp_status(void)
3839 int rnd_type;
3841 /* set rounding mode */
3842 switch(env->fpuc & RC_MASK) {
3843 default:
3844 case RC_NEAR:
3845 rnd_type = float_round_nearest_even;
3846 break;
3847 case RC_DOWN:
3848 rnd_type = float_round_down;
3849 break;
3850 case RC_UP:
3851 rnd_type = float_round_up;
3852 break;
3853 case RC_CHOP:
3854 rnd_type = float_round_to_zero;
3855 break;
3857 set_float_rounding_mode(rnd_type, &env->fp_status);
3858 #ifdef FLOATX80
3859 switch((env->fpuc >> 8) & 3) {
3860 case 0:
3861 rnd_type = 32;
3862 break;
3863 case 2:
3864 rnd_type = 64;
3865 break;
3866 case 3:
3867 default:
3868 rnd_type = 80;
3869 break;
3871 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3872 #endif
3875 void helper_fldcw(uint32_t val)
3877 env->fpuc = val;
3878 update_fp_status();
3881 void helper_fclex(void)
3883 env->fpus &= 0x7f00;
3886 void helper_fwait(void)
3888 if (env->fpus & FPUS_SE)
3889 fpu_raise_exception();
3892 void helper_fninit(void)
3894 env->fpus = 0;
3895 env->fpstt = 0;
3896 env->fpuc = 0x37f;
3897 env->fptags[0] = 1;
3898 env->fptags[1] = 1;
3899 env->fptags[2] = 1;
3900 env->fptags[3] = 1;
3901 env->fptags[4] = 1;
3902 env->fptags[5] = 1;
3903 env->fptags[6] = 1;
3904 env->fptags[7] = 1;
3907 /* BCD ops */
3909 void helper_fbld_ST0(target_ulong ptr)
3911 CPU86_LDouble tmp;
3912 uint64_t val;
3913 unsigned int v;
3914 int i;
3916 val = 0;
3917 for(i = 8; i >= 0; i--) {
3918 v = ldub(ptr + i);
3919 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3921 tmp = val;
3922 if (ldub(ptr + 9) & 0x80)
3923 tmp = -tmp;
3924 fpush();
3925 ST0 = tmp;
3928 void helper_fbst_ST0(target_ulong ptr)
3930 int v;
3931 target_ulong mem_ref, mem_end;
3932 int64_t val;
3934 val = floatx_to_int64(ST0, &env->fp_status);
3935 mem_ref = ptr;
3936 mem_end = mem_ref + 9;
3937 if (val < 0) {
3938 stb(mem_end, 0x80);
3939 val = -val;
3940 } else {
3941 stb(mem_end, 0x00);
3943 while (mem_ref < mem_end) {
3944 if (val == 0)
3945 break;
3946 v = val % 100;
3947 val = val / 100;
3948 v = ((v / 10) << 4) | (v % 10);
3949 stb(mem_ref++, v);
3951 while (mem_ref < mem_end) {
3952 stb(mem_ref++, 0);
3956 void helper_f2xm1(void)
3958 ST0 = pow(2.0,ST0) - 1.0;
3961 void helper_fyl2x(void)
3963 CPU86_LDouble fptemp;
3965 fptemp = ST0;
3966 if (fptemp>0.0){
3967 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
3968 ST1 *= fptemp;
3969 fpop();
3970 } else {
3971 env->fpus &= (~0x4700);
3972 env->fpus |= 0x400;
3976 void helper_fptan(void)
3978 CPU86_LDouble fptemp;
3980 fptemp = ST0;
3981 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3982 env->fpus |= 0x400;
3983 } else {
3984 ST0 = tan(fptemp);
3985 fpush();
3986 ST0 = 1.0;
3987 env->fpus &= (~0x400); /* C2 <-- 0 */
3988 /* the above code is for |arg| < 2**52 only */
3992 void helper_fpatan(void)
3994 CPU86_LDouble fptemp, fpsrcop;
3996 fpsrcop = ST1;
3997 fptemp = ST0;
3998 ST1 = atan2(fpsrcop,fptemp);
3999 fpop();
4002 void helper_fxtract(void)
4004 CPU86_LDoubleU temp;
4005 unsigned int expdif;
4007 temp.d = ST0;
4008 expdif = EXPD(temp) - EXPBIAS;
4009 /*DP exponent bias*/
4010 ST0 = expdif;
4011 fpush();
4012 BIASEXPONENT(temp);
4013 ST0 = temp.d;
4016 void helper_fprem1(void)
4018 CPU86_LDouble dblq, fpsrcop, fptemp;
4019 CPU86_LDoubleU fpsrcop1, fptemp1;
4020 int expdif;
4021 signed long long int q;
4023 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
4024 ST0 = 0.0 / 0.0; /* NaN */
4025 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4026 return;
4029 fpsrcop = ST0;
4030 fptemp = ST1;
4031 fpsrcop1.d = fpsrcop;
4032 fptemp1.d = fptemp;
4033 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4035 if (expdif < 0) {
4036 /* optimisation? taken from the AMD docs */
4037 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4038 /* ST0 is unchanged */
4039 return;
4042 if (expdif < 53) {
4043 dblq = fpsrcop / fptemp;
4044 /* round dblq towards nearest integer */
4045 dblq = rint(dblq);
4046 ST0 = fpsrcop - fptemp * dblq;
4048 /* convert dblq to q by truncating towards zero */
4049 if (dblq < 0.0)
4050 q = (signed long long int)(-dblq);
4051 else
4052 q = (signed long long int)dblq;
4054 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4055 /* (C0,C3,C1) <-- (q2,q1,q0) */
4056 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4057 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4058 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4059 } else {
4060 env->fpus |= 0x400; /* C2 <-- 1 */
4061 fptemp = pow(2.0, expdif - 50);
4062 fpsrcop = (ST0 / ST1) / fptemp;
4063 /* fpsrcop = integer obtained by chopping */
4064 fpsrcop = (fpsrcop < 0.0) ?
4065 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4066 ST0 -= (ST1 * fpsrcop * fptemp);
4070 void helper_fprem(void)
4072 CPU86_LDouble dblq, fpsrcop, fptemp;
4073 CPU86_LDoubleU fpsrcop1, fptemp1;
4074 int expdif;
4075 signed long long int q;
4077 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
4078 ST0 = 0.0 / 0.0; /* NaN */
4079 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4080 return;
4083 fpsrcop = (CPU86_LDouble)ST0;
4084 fptemp = (CPU86_LDouble)ST1;
4085 fpsrcop1.d = fpsrcop;
4086 fptemp1.d = fptemp;
4087 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4089 if (expdif < 0) {
4090 /* optimisation? taken from the AMD docs */
4091 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4092 /* ST0 is unchanged */
4093 return;
4096 if ( expdif < 53 ) {
4097 dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
4098 /* round dblq towards zero */
4099 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
4100 ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
4102 /* convert dblq to q by truncating towards zero */
4103 if (dblq < 0.0)
4104 q = (signed long long int)(-dblq);
4105 else
4106 q = (signed long long int)dblq;
4108 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4109 /* (C0,C3,C1) <-- (q2,q1,q0) */
4110 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4111 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4112 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4113 } else {
4114 int N = 32 + (expdif % 32); /* as per AMD docs */
4115 env->fpus |= 0x400; /* C2 <-- 1 */
4116 fptemp = pow(2.0, (double)(expdif - N));
4117 fpsrcop = (ST0 / ST1) / fptemp;
4118 /* fpsrcop = integer obtained by chopping */
4119 fpsrcop = (fpsrcop < 0.0) ?
4120 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4121 ST0 -= (ST1 * fpsrcop * fptemp);
4125 void helper_fyl2xp1(void)
4127 CPU86_LDouble fptemp;
4129 fptemp = ST0;
4130 if ((fptemp+1.0)>0.0) {
4131 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
4132 ST1 *= fptemp;
4133 fpop();
4134 } else {
4135 env->fpus &= (~0x4700);
4136 env->fpus |= 0x400;
4140 void helper_fsqrt(void)
4142 CPU86_LDouble fptemp;
4144 fptemp = ST0;
4145 if (fptemp<0.0) {
4146 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4147 env->fpus |= 0x400;
4149 ST0 = sqrt(fptemp);
4152 void helper_fsincos(void)
4154 CPU86_LDouble fptemp;
4156 fptemp = ST0;
4157 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4158 env->fpus |= 0x400;
4159 } else {
4160 ST0 = sin(fptemp);
4161 fpush();
4162 ST0 = cos(fptemp);
4163 env->fpus &= (~0x400); /* C2 <-- 0 */
4164 /* the above code is for |arg| < 2**63 only */
4168 void helper_frndint(void)
4170 ST0 = floatx_round_to_int(ST0, &env->fp_status);
4173 void helper_fscale(void)
4175 ST0 = ldexp (ST0, (int)(ST1));
4178 void helper_fsin(void)
4180 CPU86_LDouble fptemp;
4182 fptemp = ST0;
4183 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4184 env->fpus |= 0x400;
4185 } else {
4186 ST0 = sin(fptemp);
4187 env->fpus &= (~0x400); /* C2 <-- 0 */
4188 /* the above code is for |arg| < 2**53 only */
4192 void helper_fcos(void)
4194 CPU86_LDouble fptemp;
4196 fptemp = ST0;
4197 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4198 env->fpus |= 0x400;
4199 } else {
4200 ST0 = cos(fptemp);
4201 env->fpus &= (~0x400); /* C2 <-- 0 */
4202 /* the above code is for |arg5 < 2**63 only */
4206 void helper_fxam_ST0(void)
4208 CPU86_LDoubleU temp;
4209 int expdif;
4211 temp.d = ST0;
4213 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4214 if (SIGND(temp))
4215 env->fpus |= 0x200; /* C1 <-- 1 */
4217 /* XXX: test fptags too */
4218 expdif = EXPD(temp);
4219 if (expdif == MAXEXPD) {
4220 #ifdef USE_X86LDOUBLE
4221 if (MANTD(temp) == 0x8000000000000000ULL)
4222 #else
4223 if (MANTD(temp) == 0)
4224 #endif
4225 env->fpus |= 0x500 /*Infinity*/;
4226 else
4227 env->fpus |= 0x100 /*NaN*/;
4228 } else if (expdif == 0) {
4229 if (MANTD(temp) == 0)
4230 env->fpus |= 0x4000 /*Zero*/;
4231 else
4232 env->fpus |= 0x4400 /*Denormal*/;
4233 } else {
4234 env->fpus |= 0x400;
4238 void helper_fstenv(target_ulong ptr, int data32)
4240 int fpus, fptag, exp, i;
4241 uint64_t mant;
4242 CPU86_LDoubleU tmp;
4244 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4245 fptag = 0;
4246 for (i=7; i>=0; i--) {
4247 fptag <<= 2;
4248 if (env->fptags[i]) {
4249 fptag |= 3;
4250 } else {
4251 tmp.d = env->fpregs[i].d;
4252 exp = EXPD(tmp);
4253 mant = MANTD(tmp);
4254 if (exp == 0 && mant == 0) {
4255 /* zero */
4256 fptag |= 1;
4257 } else if (exp == 0 || exp == MAXEXPD
4258 #ifdef USE_X86LDOUBLE
4259 || (mant & (1LL << 63)) == 0
4260 #endif
4262 /* NaNs, infinity, denormal */
4263 fptag |= 2;
4267 if (data32) {
4268 /* 32 bit */
4269 stl(ptr, env->fpuc);
4270 stl(ptr + 4, fpus);
4271 stl(ptr + 8, fptag);
4272 stl(ptr + 12, 0); /* fpip */
4273 stl(ptr + 16, 0); /* fpcs */
4274 stl(ptr + 20, 0); /* fpoo */
4275 stl(ptr + 24, 0); /* fpos */
4276 } else {
4277 /* 16 bit */
4278 stw(ptr, env->fpuc);
4279 stw(ptr + 2, fpus);
4280 stw(ptr + 4, fptag);
4281 stw(ptr + 6, 0);
4282 stw(ptr + 8, 0);
4283 stw(ptr + 10, 0);
4284 stw(ptr + 12, 0);
4288 void helper_fldenv(target_ulong ptr, int data32)
4290 int i, fpus, fptag;
4292 if (data32) {
4293 env->fpuc = lduw(ptr);
4294 fpus = lduw(ptr + 4);
4295 fptag = lduw(ptr + 8);
4297 else {
4298 env->fpuc = lduw(ptr);
4299 fpus = lduw(ptr + 2);
4300 fptag = lduw(ptr + 4);
4302 env->fpstt = (fpus >> 11) & 7;
4303 env->fpus = fpus & ~0x3800;
4304 for(i = 0;i < 8; i++) {
4305 env->fptags[i] = ((fptag & 3) == 3);
4306 fptag >>= 2;
4310 void helper_fsave(target_ulong ptr, int data32)
4312 CPU86_LDouble tmp;
4313 int i;
4315 helper_fstenv(ptr, data32);
4317 ptr += (14 << data32);
4318 for(i = 0;i < 8; i++) {
4319 tmp = ST(i);
4320 helper_fstt(tmp, ptr);
4321 ptr += 10;
4324 /* fninit */
4325 env->fpus = 0;
4326 env->fpstt = 0;
4327 env->fpuc = 0x37f;
4328 env->fptags[0] = 1;
4329 env->fptags[1] = 1;
4330 env->fptags[2] = 1;
4331 env->fptags[3] = 1;
4332 env->fptags[4] = 1;
4333 env->fptags[5] = 1;
4334 env->fptags[6] = 1;
4335 env->fptags[7] = 1;
4338 void helper_frstor(target_ulong ptr, int data32)
4340 CPU86_LDouble tmp;
4341 int i;
4343 helper_fldenv(ptr, data32);
4344 ptr += (14 << data32);
4346 for(i = 0;i < 8; i++) {
4347 tmp = helper_fldt(ptr);
4348 ST(i) = tmp;
4349 ptr += 10;
4353 void helper_fxsave(target_ulong ptr, int data64)
4355 int fpus, fptag, i, nb_xmm_regs;
4356 CPU86_LDouble tmp;
4357 target_ulong addr;
4359 /* The operand must be 16 byte aligned */
4360 if (ptr & 0xf) {
4361 raise_exception(EXCP0D_GPF);
4364 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4365 fptag = 0;
4366 for(i = 0; i < 8; i++) {
4367 fptag |= (env->fptags[i] << i);
4369 stw(ptr, env->fpuc);
4370 stw(ptr + 2, fpus);
4371 stw(ptr + 4, fptag ^ 0xff);
4372 #ifdef TARGET_X86_64
4373 if (data64) {
4374 stq(ptr + 0x08, 0); /* rip */
4375 stq(ptr + 0x10, 0); /* rdp */
4376 } else
4377 #endif
4379 stl(ptr + 0x08, 0); /* eip */
4380 stl(ptr + 0x0c, 0); /* sel */
4381 stl(ptr + 0x10, 0); /* dp */
4382 stl(ptr + 0x14, 0); /* sel */
4385 addr = ptr + 0x20;
4386 for(i = 0;i < 8; i++) {
4387 tmp = ST(i);
4388 helper_fstt(tmp, addr);
4389 addr += 16;
4392 if (env->cr[4] & CR4_OSFXSR_MASK) {
4393 /* XXX: finish it */
4394 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4395 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4396 if (env->hflags & HF_CS64_MASK)
4397 nb_xmm_regs = 16;
4398 else
4399 nb_xmm_regs = 8;
4400 addr = ptr + 0xa0;
4401 /* Fast FXSAVE leaves out the XMM registers */
4402 if (!(env->efer & MSR_EFER_FFXSR)
4403 || (env->hflags & HF_CPL_MASK)
4404 || !(env->hflags & HF_LMA_MASK)) {
4405 for(i = 0; i < nb_xmm_regs; i++) {
4406 stq(addr, env->xmm_regs[i].XMM_Q(0));
4407 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4408 addr += 16;
4414 void helper_fxrstor(target_ulong ptr, int data64)
4416 int i, fpus, fptag, nb_xmm_regs;
4417 CPU86_LDouble tmp;
4418 target_ulong addr;
4420 /* The operand must be 16 byte aligned */
4421 if (ptr & 0xf) {
4422 raise_exception(EXCP0D_GPF);
4425 env->fpuc = lduw(ptr);
4426 fpus = lduw(ptr + 2);
4427 fptag = lduw(ptr + 4);
4428 env->fpstt = (fpus >> 11) & 7;
4429 env->fpus = fpus & ~0x3800;
4430 fptag ^= 0xff;
4431 for(i = 0;i < 8; i++) {
4432 env->fptags[i] = ((fptag >> i) & 1);
4435 addr = ptr + 0x20;
4436 for(i = 0;i < 8; i++) {
4437 tmp = helper_fldt(addr);
4438 ST(i) = tmp;
4439 addr += 16;
4442 if (env->cr[4] & CR4_OSFXSR_MASK) {
4443 /* XXX: finish it */
4444 env->mxcsr = ldl(ptr + 0x18);
4445 //ldl(ptr + 0x1c);
4446 if (env->hflags & HF_CS64_MASK)
4447 nb_xmm_regs = 16;
4448 else
4449 nb_xmm_regs = 8;
4450 addr = ptr + 0xa0;
4451 /* Fast FXRESTORE leaves out the XMM registers */
4452 if (!(env->efer & MSR_EFER_FFXSR)
4453 || (env->hflags & HF_CPL_MASK)
4454 || !(env->hflags & HF_LMA_MASK)) {
4455 for(i = 0; i < nb_xmm_regs; i++) {
4456 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4457 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4458 addr += 16;
4464 #ifndef USE_X86LDOUBLE
4466 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4468 CPU86_LDoubleU temp;
4469 int e;
4471 temp.d = f;
4472 /* mantissa */
4473 *pmant = (MANTD(temp) << 11) | (1LL << 63);
4474 /* exponent + sign */
4475 e = EXPD(temp) - EXPBIAS + 16383;
4476 e |= SIGND(temp) >> 16;
4477 *pexp = e;
4480 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4482 CPU86_LDoubleU temp;
4483 int e;
4484 uint64_t ll;
4486 /* XXX: handle overflow ? */
4487 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
4488 e |= (upper >> 4) & 0x800; /* sign */
4489 ll = (mant >> 11) & ((1LL << 52) - 1);
4490 #ifdef __arm__
4491 temp.l.upper = (e << 20) | (ll >> 32);
4492 temp.l.lower = ll;
4493 #else
4494 temp.ll = ll | ((uint64_t)e << 52);
4495 #endif
4496 return temp.d;
4499 #else
4501 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4503 CPU86_LDoubleU temp;
4505 temp.d = f;
4506 *pmant = temp.l.lower;
4507 *pexp = temp.l.upper;
4510 CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4512 CPU86_LDoubleU temp;
4514 temp.l.upper = upper;
4515 temp.l.lower = mant;
4516 return temp.d;
4518 #endif
4520 #ifdef TARGET_X86_64
4522 //#define DEBUG_MULDIV
4524 static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4526 *plow += a;
4527 /* carry test */
4528 if (*plow < a)
4529 (*phigh)++;
4530 *phigh += b;
4533 static void neg128(uint64_t *plow, uint64_t *phigh)
4535 *plow = ~ *plow;
4536 *phigh = ~ *phigh;
4537 add128(plow, phigh, 1, 0);
4540 /* return TRUE if overflow */
4541 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4543 uint64_t q, r, a1, a0;
4544 int i, qb, ab;
4546 a0 = *plow;
4547 a1 = *phigh;
4548 if (a1 == 0) {
4549 q = a0 / b;
4550 r = a0 % b;
4551 *plow = q;
4552 *phigh = r;
4553 } else {
4554 if (a1 >= b)
4555 return 1;
4556 /* XXX: use a better algorithm */
4557 for(i = 0; i < 64; i++) {
4558 ab = a1 >> 63;
4559 a1 = (a1 << 1) | (a0 >> 63);
4560 if (ab || a1 >= b) {
4561 a1 -= b;
4562 qb = 1;
4563 } else {
4564 qb = 0;
4566 a0 = (a0 << 1) | qb;
4568 #if defined(DEBUG_MULDIV)
4569 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
4570 *phigh, *plow, b, a0, a1);
4571 #endif
4572 *plow = a0;
4573 *phigh = a1;
4575 return 0;
4578 /* return TRUE if overflow */
4579 static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
4581 int sa, sb;
4582 sa = ((int64_t)*phigh < 0);
4583 if (sa)
4584 neg128(plow, phigh);
4585 sb = (b < 0);
4586 if (sb)
4587 b = -b;
4588 if (div64(plow, phigh, b) != 0)
4589 return 1;
4590 if (sa ^ sb) {
4591 if (*plow > (1ULL << 63))
4592 return 1;
4593 *plow = - *plow;
4594 } else {
4595 if (*plow >= (1ULL << 63))
4596 return 1;
4598 if (sa)
4599 *phigh = - *phigh;
4600 return 0;
4603 void helper_mulq_EAX_T0(target_ulong t0)
4605 uint64_t r0, r1;
4607 mulu64(&r0, &r1, EAX, t0);
4608 EAX = r0;
4609 EDX = r1;
4610 CC_DST = r0;
4611 CC_SRC = r1;
4614 void helper_imulq_EAX_T0(target_ulong t0)
4616 uint64_t r0, r1;
4618 muls64(&r0, &r1, EAX, t0);
4619 EAX = r0;
4620 EDX = r1;
4621 CC_DST = r0;
4622 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4625 target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
4627 uint64_t r0, r1;
4629 muls64(&r0, &r1, t0, t1);
4630 CC_DST = r0;
4631 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4632 return r0;
4635 void helper_divq_EAX(target_ulong t0)
4637 uint64_t r0, r1;
4638 if (t0 == 0) {
4639 raise_exception(EXCP00_DIVZ);
4641 r0 = EAX;
4642 r1 = EDX;
4643 if (div64(&r0, &r1, t0))
4644 raise_exception(EXCP00_DIVZ);
4645 EAX = r0;
4646 EDX = r1;
4649 void helper_idivq_EAX(target_ulong t0)
4651 uint64_t r0, r1;
4652 if (t0 == 0) {
4653 raise_exception(EXCP00_DIVZ);
4655 r0 = EAX;
4656 r1 = EDX;
4657 if (idiv64(&r0, &r1, t0))
4658 raise_exception(EXCP00_DIVZ);
4659 EAX = r0;
4660 EDX = r1;
4662 #endif
4664 static void do_hlt(void)
4666 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
4667 env->halted = 1;
4668 env->exception_index = EXCP_HLT;
4669 cpu_loop_exit();
4672 void helper_hlt(int next_eip_addend)
4674 helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
4675 EIP += next_eip_addend;
4677 do_hlt();
4680 void helper_monitor(target_ulong ptr)
4682 if ((uint32_t)ECX != 0)
4683 raise_exception(EXCP0D_GPF);
4684 /* XXX: store address ? */
4685 helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
4688 void helper_mwait(int next_eip_addend)
4690 if ((uint32_t)ECX != 0)
4691 raise_exception(EXCP0D_GPF);
4692 helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
4693 EIP += next_eip_addend;
4695 /* XXX: not complete but not completely erroneous */
4696 if (env->cpu_index != 0 || env->next_cpu != NULL) {
4697 /* more than one CPU: do not sleep because another CPU may
4698 wake this one */
4699 } else {
4700 do_hlt();
4704 void helper_debug(void)
4706 env->exception_index = EXCP_DEBUG;
4707 cpu_loop_exit();
4710 void helper_reset_rf(void)
4712 env->eflags &= ~RF_MASK;
4715 void helper_raise_interrupt(int intno, int next_eip_addend)
4717 raise_interrupt(intno, 1, 0, next_eip_addend);
4720 void helper_raise_exception(int exception_index)
4722 raise_exception(exception_index);
4725 void helper_cli(void)
4727 env->eflags &= ~IF_MASK;
4730 void helper_sti(void)
4732 env->eflags |= IF_MASK;
4735 #if 0
4736 /* vm86plus instructions */
4737 void helper_cli_vm(void)
4739 env->eflags &= ~VIF_MASK;
4742 void helper_sti_vm(void)
4744 env->eflags |= VIF_MASK;
4745 if (env->eflags & VIP_MASK) {
4746 raise_exception(EXCP0D_GPF);
4749 #endif
4751 void helper_set_inhibit_irq(void)
4753 env->hflags |= HF_INHIBIT_IRQ_MASK;
4756 void helper_reset_inhibit_irq(void)
4758 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4761 void helper_boundw(target_ulong a0, int v)
4763 int low, high;
4764 low = ldsw(a0);
4765 high = ldsw(a0 + 2);
4766 v = (int16_t)v;
4767 if (v < low || v > high) {
4768 raise_exception(EXCP05_BOUND);
4772 void helper_boundl(target_ulong a0, int v)
4774 int low, high;
4775 low = ldl(a0);
4776 high = ldl(a0 + 4);
4777 if (v < low || v > high) {
4778 raise_exception(EXCP05_BOUND);
4782 static float approx_rsqrt(float a)
4784 return 1.0 / sqrt(a);
4787 static float approx_rcp(float a)
4789 return 1.0 / a;
4792 #if !defined(CONFIG_USER_ONLY)
4794 #define MMUSUFFIX _mmu
4796 #define SHIFT 0
4797 #include "softmmu_template.h"
4799 #define SHIFT 1
4800 #include "softmmu_template.h"
4802 #define SHIFT 2
4803 #include "softmmu_template.h"
4805 #define SHIFT 3
4806 #include "softmmu_template.h"
4808 #endif
4810 #if !defined(CONFIG_USER_ONLY)
4811 /* try to fill the TLB and return an exception if error. If retaddr is
4812 NULL, it means that the function was called in C code (i.e. not
4813 from generated code or from helper.c) */
4814 /* XXX: fix it to restore all registers */
4815 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
4817 TranslationBlock *tb;
4818 int ret;
4819 unsigned long pc;
4820 CPUX86State *saved_env;
4822 /* XXX: hack to restore env in all cases, even if not called from
4823 generated code */
4824 saved_env = env;
4825 env = cpu_single_env;
4827 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
4828 if (ret) {
4829 if (retaddr) {
4830 /* now we have a real cpu fault */
4831 pc = (unsigned long)retaddr;
4832 tb = tb_find_pc(pc);
4833 if (tb) {
4834 /* the PC is inside the translated code. It means that we have
4835 a virtual CPU fault */
4836 cpu_restore_state(tb, env, pc, NULL);
4839 raise_exception_err(env->exception_index, env->error_code);
4841 env = saved_env;
4843 #endif
4845 /* Secure Virtual Machine helpers */
4847 #if defined(CONFIG_USER_ONLY)
4849 void helper_vmrun(int aflag, int next_eip_addend)
4852 void helper_vmmcall(void)
4855 void helper_vmload(int aflag)
4858 void helper_vmsave(int aflag)
4861 void helper_stgi(void)
4864 void helper_clgi(void)
4867 void helper_skinit(void)
4870 void helper_invlpga(int aflag)
4873 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
4876 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
4880 void helper_svm_check_io(uint32_t port, uint32_t param,
4881 uint32_t next_eip_addend)
4884 #else
4886 static inline void svm_save_seg(target_phys_addr_t addr,
4887 const SegmentCache *sc)
4889 stw_phys(addr + offsetof(struct vmcb_seg, selector),
4890 sc->selector);
4891 stq_phys(addr + offsetof(struct vmcb_seg, base),
4892 sc->base);
4893 stl_phys(addr + offsetof(struct vmcb_seg, limit),
4894 sc->limit);
4895 stw_phys(addr + offsetof(struct vmcb_seg, attrib),
4896 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
4899 static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
4901 unsigned int flags;
4903 sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
4904 sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
4905 sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
4906 flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
4907 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
4910 static inline void svm_load_seg_cache(target_phys_addr_t addr,
4911 CPUState *env, int seg_reg)
4913 SegmentCache sc1, *sc = &sc1;
4914 svm_load_seg(addr, sc);
4915 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
4916 sc->base, sc->limit, sc->flags);
4919 void helper_vmrun(int aflag, int next_eip_addend)
4921 target_ulong addr;
4922 uint32_t event_inj;
4923 uint32_t int_ctl;
4925 helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
4927 if (aflag == 2)
4928 addr = EAX;
4929 else
4930 addr = (uint32_t)EAX;
4932 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
4934 env->vm_vmcb = addr;
4936 /* save the current CPU state in the hsave page */
4937 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4938 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4940 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4941 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4943 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
4944 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
4945 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
4946 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
4947 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
4948 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
4950 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
4951 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
4953 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
4954 &env->segs[R_ES]);
4955 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
4956 &env->segs[R_CS]);
4957 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
4958 &env->segs[R_SS]);
4959 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
4960 &env->segs[R_DS]);
4962 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
4963 EIP + next_eip_addend);
4964 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4965 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4967 /* load the interception bitmaps so we do not need to access the
4968 vmcb in svm mode */
4969 env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
4970 env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4971 env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4972 env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4973 env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4974 env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4976 /* enable intercepts */
4977 env->hflags |= HF_SVMI_MASK;
4979 env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
4981 env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4982 env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4984 env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4985 env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4987 /* clear exit_info_2 so we behave like the real hardware */
4988 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4990 cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4991 cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4992 cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4993 env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4994 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
4995 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
4996 if (int_ctl & V_INTR_MASKING_MASK) {
4997 env->v_tpr = int_ctl & V_TPR_MASK;
4998 env->hflags2 |= HF2_VINTR_MASK;
4999 if (env->eflags & IF_MASK)
5000 env->hflags2 |= HF2_HIF_MASK;
5003 cpu_load_efer(env,
5004 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
5005 env->eflags = 0;
5006 load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
5007 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5008 CC_OP = CC_OP_EFLAGS;
5010 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
5011 env, R_ES);
5012 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5013 env, R_CS);
5014 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5015 env, R_SS);
5016 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5017 env, R_DS);
5019 EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
5020 env->eip = EIP;
5021 ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
5022 EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
5023 env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
5024 env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
5025 cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
5027 /* FIXME: guest state consistency checks */
5029 switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
5030 case TLB_CONTROL_DO_NOTHING:
5031 break;
5032 case TLB_CONTROL_FLUSH_ALL_ASID:
5033 /* FIXME: this is not 100% correct but should work for now */
5034 tlb_flush(env, 1);
5035 break;
5038 env->hflags2 |= HF2_GIF_MASK;
5040 if (int_ctl & V_IRQ_MASK) {
5041 env->interrupt_request |= CPU_INTERRUPT_VIRQ;
5044 /* maybe we need to inject an event */
5045 event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
5046 if (event_inj & SVM_EVTINJ_VALID) {
5047 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
5048 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
5049 uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
5051 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
5052 /* FIXME: need to implement valid_err */
5053 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
5054 case SVM_EVTINJ_TYPE_INTR:
5055 env->exception_index = vector;
5056 env->error_code = event_inj_err;
5057 env->exception_is_int = 0;
5058 env->exception_next_eip = -1;
5059 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
5060 /* XXX: is it always correct ? */
5061 do_interrupt(vector, 0, 0, 0, 1);
5062 break;
5063 case SVM_EVTINJ_TYPE_NMI:
5064 env->exception_index = EXCP02_NMI;
5065 env->error_code = event_inj_err;
5066 env->exception_is_int = 0;
5067 env->exception_next_eip = EIP;
5068 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
5069 cpu_loop_exit();
5070 break;
5071 case SVM_EVTINJ_TYPE_EXEPT:
5072 env->exception_index = vector;
5073 env->error_code = event_inj_err;
5074 env->exception_is_int = 0;
5075 env->exception_next_eip = -1;
5076 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
5077 cpu_loop_exit();
5078 break;
5079 case SVM_EVTINJ_TYPE_SOFT:
5080 env->exception_index = vector;
5081 env->error_code = event_inj_err;
5082 env->exception_is_int = 1;
5083 env->exception_next_eip = EIP;
5084 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
5085 cpu_loop_exit();
5086 break;
5088 qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
5092 void helper_vmmcall(void)
5094 helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
5095 raise_exception(EXCP06_ILLOP);
5098 void helper_vmload(int aflag)
5100 target_ulong addr;
5101 helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
5103 if (aflag == 2)
5104 addr = EAX;
5105 else
5106 addr = (uint32_t)EAX;
5108 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5109 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5110 env->segs[R_FS].base);
5112 svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
5113 env, R_FS);
5114 svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
5115 env, R_GS);
5116 svm_load_seg(addr + offsetof(struct vmcb, save.tr),
5117 &env->tr);
5118 svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
5119 &env->ldt);
5121 #ifdef TARGET_X86_64
5122 env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
5123 env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
5124 env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
5125 env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
5126 #endif
5127 env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
5128 env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
5129 env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
5130 env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
5133 void helper_vmsave(int aflag)
5135 target_ulong addr;
5136 helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
5138 if (aflag == 2)
5139 addr = EAX;
5140 else
5141 addr = (uint32_t)EAX;
5143 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5144 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5145 env->segs[R_FS].base);
5147 svm_save_seg(addr + offsetof(struct vmcb, save.fs),
5148 &env->segs[R_FS]);
5149 svm_save_seg(addr + offsetof(struct vmcb, save.gs),
5150 &env->segs[R_GS]);
5151 svm_save_seg(addr + offsetof(struct vmcb, save.tr),
5152 &env->tr);
5153 svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
5154 &env->ldt);
5156 #ifdef TARGET_X86_64
5157 stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
5158 stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
5159 stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
5160 stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
5161 #endif
5162 stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5163 stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5164 stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5165 stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5168 void helper_stgi(void)
5170 helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
5171 env->hflags2 |= HF2_GIF_MASK;
5174 void helper_clgi(void)
5176 helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
5177 env->hflags2 &= ~HF2_GIF_MASK;
5180 void helper_skinit(void)
5182 helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
5183 /* XXX: not implemented */
5184 raise_exception(EXCP06_ILLOP);
5187 void helper_invlpga(int aflag)
5189 target_ulong addr;
5190 helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
5192 if (aflag == 2)
5193 addr = EAX;
5194 else
5195 addr = (uint32_t)EAX;
5197 /* XXX: could use the ASID to see if it is needed to do the
5198 flush */
5199 tlb_flush_page(env, addr);
5202 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5204 if (likely(!(env->hflags & HF_SVMI_MASK)))
5205 return;
5206 switch(type) {
5207 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
5208 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
5209 helper_vmexit(type, param);
5211 break;
5212 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5213 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
5214 helper_vmexit(type, param);
5216 break;
5217 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
5218 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
5219 helper_vmexit(type, param);
5221 break;
5222 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
5223 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
5224 helper_vmexit(type, param);
5226 break;
5227 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
5228 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
5229 helper_vmexit(type, param);
5231 break;
5232 case SVM_EXIT_MSR:
5233 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
5234 /* FIXME: this should be read in at vmrun (faster this way?) */
5235 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5236 uint32_t t0, t1;
5237 switch((uint32_t)ECX) {
5238 case 0 ... 0x1fff:
5239 t0 = (ECX * 2) % 8;
5240 t1 = (ECX * 2) / 8;
5241 break;
5242 case 0xc0000000 ... 0xc0001fff:
5243 t0 = (8192 + ECX - 0xc0000000) * 2;
5244 t1 = (t0 / 8);
5245 t0 %= 8;
5246 break;
5247 case 0xc0010000 ... 0xc0011fff:
5248 t0 = (16384 + ECX - 0xc0010000) * 2;
5249 t1 = (t0 / 8);
5250 t0 %= 8;
5251 break;
5252 default:
5253 helper_vmexit(type, param);
5254 t0 = 0;
5255 t1 = 0;
5256 break;
5258 if (ldub_phys(addr + t1) & ((1 << param) << t0))
5259 helper_vmexit(type, param);
5261 break;
5262 default:
5263 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
5264 helper_vmexit(type, param);
5266 break;
5270 void helper_svm_check_io(uint32_t port, uint32_t param,
5271 uint32_t next_eip_addend)
5273 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
5274 /* FIXME: this should be read in at vmrun (faster this way?) */
5275 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5276 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5277 if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5278 /* next EIP */
5279 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
5280 env->eip + next_eip_addend);
5281 helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5286 /* Note: currently only 32 bits of exit_code are used */
5287 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5289 uint32_t int_ctl;
5291 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5292 exit_code, exit_info_1,
5293 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5294 EIP);
5296 if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5297 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5298 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5299 } else {
5300 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5303 /* Save the VM state in the vmcb */
5304 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
5305 &env->segs[R_ES]);
5306 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5307 &env->segs[R_CS]);
5308 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5309 &env->segs[R_SS]);
5310 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5311 &env->segs[R_DS]);
5313 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5314 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5316 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5317 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5319 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5320 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5321 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5322 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5323 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5325 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5326 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
5327 int_ctl |= env->v_tpr & V_TPR_MASK;
5328 if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
5329 int_ctl |= V_IRQ_MASK;
5330 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
5332 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5333 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5334 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5335 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5336 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5337 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5338 stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5340 /* Reload the host state from vm_hsave */
5341 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
5342 env->hflags &= ~HF_SVMI_MASK;
5343 env->intercept = 0;
5344 env->intercept_exceptions = 0;
5345 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
5346 env->tsc_offset = 0;
5348 env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5349 env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5351 env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5352 env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5354 cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5355 cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5356 cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5357 /* we need to set the efer after the crs so the hidden flags get
5358 set properly */
5359 cpu_load_efer(env,
5360 ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
5361 env->eflags = 0;
5362 load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5363 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5364 CC_OP = CC_OP_EFLAGS;
5366 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
5367 env, R_ES);
5368 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
5369 env, R_CS);
5370 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
5371 env, R_SS);
5372 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
5373 env, R_DS);
5375 EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5376 ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5377 EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5379 env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5380 env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5382 /* other setups */
5383 cpu_x86_set_cpl(env, 0);
5384 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5385 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5387 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
5388 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
5389 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
5390 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
5391 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
5393 env->hflags2 &= ~HF2_GIF_MASK;
5394 /* FIXME: Resets the current ASID register to zero (host ASID). */
5396 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5398 /* Clears the TSC_OFFSET inside the processor. */
5400 /* If the host is in PAE mode, the processor reloads the host's PDPEs
5401 from the page table indicated the host's CR3. If the PDPEs contain
5402 illegal state, the processor causes a shutdown. */
5404 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5405 env->cr[0] |= CR0_PE_MASK;
5406 env->eflags &= ~VM_MASK;
5408 /* Disables all breakpoints in the host DR7 register. */
5410 /* Checks the reloaded host state for consistency. */
5412 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5413 host's code segment or non-canonical (in the case of long mode), a
5414 #GP fault is delivered inside the host.) */
5416 /* remove any pending exception */
5417 env->exception_index = -1;
5418 env->error_code = 0;
5419 env->old_exception = -1;
5421 cpu_loop_exit();
5424 #endif
5426 /* MMX/SSE */
5427 /* XXX: optimize by storing fptt and fptags in the static cpu state */
5428 void helper_enter_mmx(void)
5430 env->fpstt = 0;
5431 *(uint32_t *)(env->fptags) = 0;
5432 *(uint32_t *)(env->fptags + 4) = 0;
5435 void helper_emms(void)
5437 /* set to empty state */
5438 *(uint32_t *)(env->fptags) = 0x01010101;
5439 *(uint32_t *)(env->fptags + 4) = 0x01010101;
5442 /* XXX: suppress */
5443 void helper_movq(void *d, void *s)
5445 *(uint64_t *)d = *(uint64_t *)s;
5448 #define SHIFT 0
5449 #include "ops_sse.h"
5451 #define SHIFT 1
5452 #include "ops_sse.h"
5454 #define SHIFT 0
5455 #include "helper_template.h"
5456 #undef SHIFT
5458 #define SHIFT 1
5459 #include "helper_template.h"
5460 #undef SHIFT
5462 #define SHIFT 2
5463 #include "helper_template.h"
5464 #undef SHIFT
5466 #ifdef TARGET_X86_64
5468 #define SHIFT 3
5469 #include "helper_template.h"
5470 #undef SHIFT
5472 #endif
5474 /* bit operations */
5475 target_ulong helper_bsf(target_ulong t0)
5477 int count;
5478 target_ulong res;
5480 res = t0;
5481 count = 0;
5482 while ((res & 1) == 0) {
5483 count++;
5484 res >>= 1;
5486 return count;
5489 target_ulong helper_lzcnt(target_ulong t0, int wordsize)
5491 int count;
5492 target_ulong res, mask;
5494 if (wordsize > 0 && t0 == 0) {
5495 return wordsize;
5497 res = t0;
5498 count = TARGET_LONG_BITS - 1;
5499 mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5500 while ((res & mask) == 0) {
5501 count--;
5502 res <<= 1;
5504 if (wordsize > 0) {
5505 return wordsize - 1 - count;
5507 return count;
5510 target_ulong helper_bsr(target_ulong t0)
5512 return helper_lzcnt(t0, 0);
5515 static int compute_all_eflags(void)
5517 return CC_SRC;
5520 static int compute_c_eflags(void)
5522 return CC_SRC & CC_C;
5525 uint32_t helper_cc_compute_all(int op)
5527 switch (op) {
5528 default: /* should never happen */ return 0;
5530 case CC_OP_EFLAGS: return compute_all_eflags();
5532 case CC_OP_MULB: return compute_all_mulb();
5533 case CC_OP_MULW: return compute_all_mulw();
5534 case CC_OP_MULL: return compute_all_mull();
5536 case CC_OP_ADDB: return compute_all_addb();
5537 case CC_OP_ADDW: return compute_all_addw();
5538 case CC_OP_ADDL: return compute_all_addl();
5540 case CC_OP_ADCB: return compute_all_adcb();
5541 case CC_OP_ADCW: return compute_all_adcw();
5542 case CC_OP_ADCL: return compute_all_adcl();
5544 case CC_OP_SUBB: return compute_all_subb();
5545 case CC_OP_SUBW: return compute_all_subw();
5546 case CC_OP_SUBL: return compute_all_subl();
5548 case CC_OP_SBBB: return compute_all_sbbb();
5549 case CC_OP_SBBW: return compute_all_sbbw();
5550 case CC_OP_SBBL: return compute_all_sbbl();
5552 case CC_OP_LOGICB: return compute_all_logicb();
5553 case CC_OP_LOGICW: return compute_all_logicw();
5554 case CC_OP_LOGICL: return compute_all_logicl();
5556 case CC_OP_INCB: return compute_all_incb();
5557 case CC_OP_INCW: return compute_all_incw();
5558 case CC_OP_INCL: return compute_all_incl();
5560 case CC_OP_DECB: return compute_all_decb();
5561 case CC_OP_DECW: return compute_all_decw();
5562 case CC_OP_DECL: return compute_all_decl();
5564 case CC_OP_SHLB: return compute_all_shlb();
5565 case CC_OP_SHLW: return compute_all_shlw();
5566 case CC_OP_SHLL: return compute_all_shll();
5568 case CC_OP_SARB: return compute_all_sarb();
5569 case CC_OP_SARW: return compute_all_sarw();
5570 case CC_OP_SARL: return compute_all_sarl();
5572 #ifdef TARGET_X86_64
5573 case CC_OP_MULQ: return compute_all_mulq();
5575 case CC_OP_ADDQ: return compute_all_addq();
5577 case CC_OP_ADCQ: return compute_all_adcq();
5579 case CC_OP_SUBQ: return compute_all_subq();
5581 case CC_OP_SBBQ: return compute_all_sbbq();
5583 case CC_OP_LOGICQ: return compute_all_logicq();
5585 case CC_OP_INCQ: return compute_all_incq();
5587 case CC_OP_DECQ: return compute_all_decq();
5589 case CC_OP_SHLQ: return compute_all_shlq();
5591 case CC_OP_SARQ: return compute_all_sarq();
5592 #endif
5596 uint32_t helper_cc_compute_c(int op)
5598 switch (op) {
5599 default: /* should never happen */ return 0;
5601 case CC_OP_EFLAGS: return compute_c_eflags();
5603 case CC_OP_MULB: return compute_c_mull();
5604 case CC_OP_MULW: return compute_c_mull();
5605 case CC_OP_MULL: return compute_c_mull();
5607 case CC_OP_ADDB: return compute_c_addb();
5608 case CC_OP_ADDW: return compute_c_addw();
5609 case CC_OP_ADDL: return compute_c_addl();
5611 case CC_OP_ADCB: return compute_c_adcb();
5612 case CC_OP_ADCW: return compute_c_adcw();
5613 case CC_OP_ADCL: return compute_c_adcl();
5615 case CC_OP_SUBB: return compute_c_subb();
5616 case CC_OP_SUBW: return compute_c_subw();
5617 case CC_OP_SUBL: return compute_c_subl();
5619 case CC_OP_SBBB: return compute_c_sbbb();
5620 case CC_OP_SBBW: return compute_c_sbbw();
5621 case CC_OP_SBBL: return compute_c_sbbl();
5623 case CC_OP_LOGICB: return compute_c_logicb();
5624 case CC_OP_LOGICW: return compute_c_logicw();
5625 case CC_OP_LOGICL: return compute_c_logicl();
5627 case CC_OP_INCB: return compute_c_incl();
5628 case CC_OP_INCW: return compute_c_incl();
5629 case CC_OP_INCL: return compute_c_incl();
5631 case CC_OP_DECB: return compute_c_incl();
5632 case CC_OP_DECW: return compute_c_incl();
5633 case CC_OP_DECL: return compute_c_incl();
5635 case CC_OP_SHLB: return compute_c_shlb();
5636 case CC_OP_SHLW: return compute_c_shlw();
5637 case CC_OP_SHLL: return compute_c_shll();
5639 case CC_OP_SARB: return compute_c_sarl();
5640 case CC_OP_SARW: return compute_c_sarl();
5641 case CC_OP_SARL: return compute_c_sarl();
5643 #ifdef TARGET_X86_64
5644 case CC_OP_MULQ: return compute_c_mull();
5646 case CC_OP_ADDQ: return compute_c_addq();
5648 case CC_OP_ADCQ: return compute_c_adcq();
5650 case CC_OP_SUBQ: return compute_c_subq();
5652 case CC_OP_SBBQ: return compute_c_sbbq();
5654 case CC_OP_LOGICQ: return compute_c_logicq();
5656 case CC_OP_INCQ: return compute_c_incl();
5658 case CC_OP_DECQ: return compute_c_incl();
5660 case CC_OP_SHLQ: return compute_c_shlq();
5662 case CC_OP_SARQ: return compute_c_sarl();
5663 #endif