VirtualBox

source: vbox/trunk/src/recompiler/target-i386/op_helper.c@ 47660

Last change on this file since 47660 was 47549, checked in by vboxsync, 11 years ago

REM: Set more access bits on selectors, clear/set the unusable flag more.

  • Property svn:eol-style set to native
File size: 200.5 KB
Line 
1/*
2 * i386 helpers
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
22 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
23 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
24 * a choice of LGPL license versions is made available with the language indicating
25 * that LGPLv2 or any later version may be used, or where a choice of which version
26 * of the LGPL is applied is otherwise unspecified.
27 */
28
29#include "exec.h"
30#include "exec-all.h"
31#include "host-utils.h"
32#include "ioport.h"
33
34#ifdef VBOX
35# include "qemu-common.h"
36# include <math.h>
37# include "tcg.h"
38#endif /* VBOX */
39
40//#define DEBUG_PCALL
41
42
43#ifdef DEBUG_PCALL
44# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
45# define LOG_PCALL_STATE(env) \
46 log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
47#else
48# define LOG_PCALL(...) do { } while (0)
49# define LOG_PCALL_STATE(env) do { } while (0)
50#endif
51
52
53#if 0
54#define raise_exception_err(a, b)\
55do {\
56 qemu_log("raise_exception line=%d\n", __LINE__);\
57 (raise_exception_err)(a, b);\
58} while (0)
59#endif
60
61static const uint8_t parity_table[256] = {
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 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
65 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
66 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 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
69 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
70 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
71 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
72 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
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 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
77 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
78 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
79 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
80 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
81 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
82 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
83 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
84 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
85 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
86 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
87 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
88 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
89 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
90 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
91 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
92 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
93 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
94};
95
96/* modulo 17 table */
97static const uint8_t rclw_table[32] = {
98 0, 1, 2, 3, 4, 5, 6, 7,
99 8, 9,10,11,12,13,14,15,
100 16, 0, 1, 2, 3, 4, 5, 6,
101 7, 8, 9,10,11,12,13,14,
102};
103
104/* modulo 9 table */
105static const uint8_t rclb_table[32] = {
106 0, 1, 2, 3, 4, 5, 6, 7,
107 8, 0, 1, 2, 3, 4, 5, 6,
108 7, 8, 0, 1, 2, 3, 4, 5,
109 6, 7, 8, 0, 1, 2, 3, 4,
110};
111
112static const CPU86_LDouble f15rk[7] =
113{
114 0.00000000000000000000L,
115 1.00000000000000000000L,
116 3.14159265358979323851L, /*pi*/
117 0.30102999566398119523L, /*lg2*/
118 0.69314718055994530943L, /*ln2*/
119 1.44269504088896340739L, /*l2e*/
120 3.32192809488736234781L, /*l2t*/
121};
122
123/* broken thread support */
124
125static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
126
127void helper_lock(void)
128{
129 spin_lock(&global_cpu_lock);
130}
131
132void helper_unlock(void)
133{
134 spin_unlock(&global_cpu_lock);
135}
136
137void helper_write_eflags(target_ulong t0, uint32_t update_mask)
138{
139 load_eflags(t0, update_mask);
140}
141
142target_ulong helper_read_eflags(void)
143{
144 uint32_t eflags;
145 eflags = helper_cc_compute_all(CC_OP);
146 eflags |= (DF & DF_MASK);
147 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
148 return eflags;
149}
150
151#ifdef VBOX
152
153void helper_write_eflags_vme(target_ulong t0)
154{
155 unsigned int new_eflags = t0;
156
157 assert(env->eflags & (1<<VM_SHIFT));
158
159 /* if virtual interrupt pending and (virtual) interrupts will be enabled -> #GP */
160 /* if TF will be set -> #GP */
161 if ( ((new_eflags & IF_MASK) && (env->eflags & VIP_MASK))
162 || (new_eflags & TF_MASK)) {
163 raise_exception(EXCP0D_GPF);
164 } else {
165 load_eflags(new_eflags,
166 (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff);
167
168 if (new_eflags & IF_MASK) {
169 env->eflags |= VIF_MASK;
170 } else {
171 env->eflags &= ~VIF_MASK;
172 }
173 }
174}
175
176target_ulong helper_read_eflags_vme(void)
177{
178 uint32_t eflags;
179 eflags = helper_cc_compute_all(CC_OP);
180 eflags |= (DF & DF_MASK);
181 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
182 if (env->eflags & VIF_MASK)
183 eflags |= IF_MASK;
184 else
185 eflags &= ~IF_MASK;
186
187 /* According to AMD manual, should be read with IOPL == 3 */
188 eflags |= (3 << IOPL_SHIFT);
189
190 /* We only use helper_read_eflags_vme() in 16-bits mode */
191 return eflags & 0xffff;
192}
193
194void helper_dump_state()
195{
196 LogRel(("CS:EIP=%08x:%08x, FLAGS=%08x\n", env->segs[R_CS].base, env->eip, env->eflags));
197 LogRel(("EAX=%08x\tECX=%08x\tEDX=%08x\tEBX=%08x\n",
198 (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
199 (uint32_t)env->regs[R_EDX], (uint32_t)env->regs[R_EBX]));
200 LogRel(("ESP=%08x\tEBP=%08x\tESI=%08x\tEDI=%08x\n",
201 (uint32_t)env->regs[R_ESP], (uint32_t)env->regs[R_EBP],
202 (uint32_t)env->regs[R_ESI], (uint32_t)env->regs[R_EDI]));
203}
204
205/**
206 * Updates e2 with the DESC_A_MASK, writes it to the descriptor table, and
207 * returns the updated e2.
208 *
209 * @returns e2 with A set.
210 * @param e2 The 2nd selector DWORD.
211 */
212static uint32_t set_segment_accessed(int selector, uint32_t e2)
213{
214 SegmentCache *dt = selector & X86_SEL_LDT ? &env->ldt : &env->gdt;
215 target_ulong ptr = dt->base + (selector & X86_SEL_MASK);
216
217 e2 |= DESC_A_MASK;
218 stl_kernel(ptr + 4, e2);
219 return e2;
220}
221
222#endif /* VBOX */
223
224/* return non zero if error */
225static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
226 int selector)
227{
228 SegmentCache *dt;
229 int index;
230 target_ulong ptr;
231
232#ifdef VBOX
233 /* Trying to load a selector with CPL=1? */
234 /** @todo this is a hack to correct the incorrect checking order for pending interrupts in the patm iret replacement code (corrected in the ring-1 version) */
235 /** @todo in theory the iret could fault and we'd still need this. */
236 if ((env->hflags & HF_CPL_MASK) == 0 && (selector & 3) == 1 && (env->state & CPU_RAW_RING0) && !EMIsRawRing1Enabled(env->pVM))
237 {
238 Log(("RPL 1 -> sel %04X -> %04X\n", selector, selector & 0xfffc));
239 selector = selector & 0xfffc;
240 }
241#endif /* VBOX */
242
243 if (selector & 0x4)
244 dt = &env->ldt;
245 else
246 dt = &env->gdt;
247 index = selector & ~7;
248 if ((index + 7) > dt->limit)
249 return -1;
250 ptr = dt->base + index;
251 *e1_ptr = ldl_kernel(ptr);
252 *e2_ptr = ldl_kernel(ptr + 4);
253 return 0;
254}
255
256static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
257{
258 unsigned int limit;
259 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
260 if (e2 & DESC_G_MASK)
261 limit = (limit << 12) | 0xfff;
262 return limit;
263}
264
265static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
266{
267 return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
268}
269
270static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
271{
272 sc->base = get_seg_base(e1, e2);
273 sc->limit = get_seg_limit(e1, e2);
274 sc->flags = e2;
275#ifdef VBOX
276 sc->flags &= ~DESC_INTEL_UNUSABLE;
277 sc->newselector = 0;
278 sc->fVBoxFlags = CPUMSELREG_FLAGS_VALID;
279#endif
280}
281
282/* init the segment cache in vm86 mode. */
283static inline void load_seg_vm(int seg, int selector)
284{
285 selector &= 0xffff;
286#ifdef VBOX
287 /* flags must be 0xf3; expand-up read/write accessed data segment with DPL=3. (VT-x) */
288 unsigned flags = DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK;
289 flags |= (3 << DESC_DPL_SHIFT);
290
291 cpu_x86_load_seg_cache(env, seg, selector,
292 (selector << 4), 0xffff, flags);
293#else /* VBOX */
294 cpu_x86_load_seg_cache(env, seg, selector,
295 (selector << 4), 0xffff, 0);
296#endif /* VBOX */
297}
298
299static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
300 uint32_t *esp_ptr, int dpl)
301{
302#ifndef VBOX
303 int type, index, shift;
304#else
305 unsigned int type, index, shift;
306#endif
307
308#if 0
309 {
310 int i;
311 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
312 for(i=0;i<env->tr.limit;i++) {
313 printf("%02x ", env->tr.base[i]);
314 if ((i & 7) == 7) printf("\n");
315 }
316 printf("\n");
317 }
318#endif
319
320 if (!(env->tr.flags & DESC_P_MASK))
321 cpu_abort(env, "invalid tss");
322 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
323 if ((type & 7) != 1)
324 cpu_abort(env, "invalid tss type");
325 shift = type >> 3;
326 index = (dpl * 4 + 2) << shift;
327 if (index + (4 << shift) - 1 > env->tr.limit)
328 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
329 if (shift == 0) {
330 *esp_ptr = lduw_kernel(env->tr.base + index);
331 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
332 } else {
333 *esp_ptr = ldl_kernel(env->tr.base + index);
334 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
335 }
336}
337
338/* XXX: merge with load_seg() */
339static void tss_load_seg(int seg_reg, int selector)
340{
341 uint32_t e1, e2;
342 int rpl, dpl, cpl;
343
344#ifdef VBOX
345 e1 = e2 = 0; /* gcc warning? */
346 cpl = env->hflags & HF_CPL_MASK;
347 /* Trying to load a selector with CPL=1? */
348 if (cpl == 0 && (selector & 3) == 1 && (env->state & CPU_RAW_RING0))
349 {
350 Log(("RPL 1 -> sel %04X -> %04X (tss_load_seg)\n", selector, selector & 0xfffc));
351 selector = selector & 0xfffc;
352 }
353#endif /* VBOX */
354
355 if ((selector & 0xfffc) != 0) {
356 if (load_segment(&e1, &e2, selector) != 0)
357 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
358 if (!(e2 & DESC_S_MASK))
359 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
360 rpl = selector & 3;
361 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
362 cpl = env->hflags & HF_CPL_MASK;
363 if (seg_reg == R_CS) {
364 if (!(e2 & DESC_CS_MASK))
365 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
366 /* XXX: is it correct ? */
367 if (dpl != rpl)
368 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
369 if ((e2 & DESC_C_MASK) && dpl > rpl)
370 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
371 } else if (seg_reg == R_SS) {
372 /* SS must be writable data */
373 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
374 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
375 if (dpl != cpl || dpl != rpl)
376 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
377 } else {
378 /* not readable code */
379 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
380 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
381 /* if data or non conforming code, checks the rights */
382 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
383 if (dpl < cpl || dpl < rpl)
384 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
385 }
386 }
387 if (!(e2 & DESC_P_MASK))
388 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
389 cpu_x86_load_seg_cache(env, seg_reg, selector,
390 get_seg_base(e1, e2),
391 get_seg_limit(e1, e2),
392 e2);
393 } else {
394 if (seg_reg == R_SS || seg_reg == R_CS)
395 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
396#ifdef VBOX
397# if 0 /** @todo now we ignore loading 0 selectors, need to check what is correct once */
398 cpu_x86_load_seg_cache(env, seg_reg, selector,
399 0, 0, 0);
400# endif
401#endif /* VBOX */
402 }
403}
404
405#define SWITCH_TSS_JMP 0
406#define SWITCH_TSS_IRET 1
407#define SWITCH_TSS_CALL 2
408
409/* XXX: restore CPU state in registers (PowerPC case) */
410static void switch_tss(int tss_selector,
411 uint32_t e1, uint32_t e2, int source,
412 uint32_t next_eip)
413{
414 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
415 target_ulong tss_base;
416 uint32_t new_regs[8], new_segs[6];
417 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
418 uint32_t old_eflags, eflags_mask;
419 SegmentCache *dt;
420#ifndef VBOX
421 int index;
422#else
423 unsigned int index;
424#endif
425 target_ulong ptr;
426
427 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
428 LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
429
430 /* if task gate, we read the TSS segment and we load it */
431 if (type == 5) {
432 if (!(e2 & DESC_P_MASK))
433 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
434 tss_selector = e1 >> 16;
435 if (tss_selector & 4)
436 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
437 if (load_segment(&e1, &e2, tss_selector) != 0)
438 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
439 if (e2 & DESC_S_MASK)
440 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
441 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
442 if ((type & 7) != 1)
443 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
444 }
445
446 if (!(e2 & DESC_P_MASK))
447 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
448
449 if (type & 8)
450 tss_limit_max = 103;
451 else
452 tss_limit_max = 43;
453 tss_limit = get_seg_limit(e1, e2);
454 tss_base = get_seg_base(e1, e2);
455 if ((tss_selector & 4) != 0 ||
456 tss_limit < tss_limit_max)
457 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
458 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
459 if (old_type & 8)
460 old_tss_limit_max = 103;
461 else
462 old_tss_limit_max = 43;
463
464 /* read all the registers from the new TSS */
465 if (type & 8) {
466 /* 32 bit */
467 new_cr3 = ldl_kernel(tss_base + 0x1c);
468 new_eip = ldl_kernel(tss_base + 0x20);
469 new_eflags = ldl_kernel(tss_base + 0x24);
470 for(i = 0; i < 8; i++)
471 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
472 for(i = 0; i < 6; i++)
473 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
474 new_ldt = lduw_kernel(tss_base + 0x60);
475 new_trap = ldl_kernel(tss_base + 0x64);
476 } else {
477 /* 16 bit */
478 new_cr3 = 0;
479 new_eip = lduw_kernel(tss_base + 0x0e);
480 new_eflags = lduw_kernel(tss_base + 0x10);
481 for(i = 0; i < 8; i++)
482 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
483 for(i = 0; i < 4; i++)
484 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
485 new_ldt = lduw_kernel(tss_base + 0x2a);
486 new_segs[R_FS] = 0;
487 new_segs[R_GS] = 0;
488 new_trap = 0;
489 }
490
491 /* NOTE: we must avoid memory exceptions during the task switch,
492 so we make dummy accesses before */
493 /* XXX: it can still fail in some cases, so a bigger hack is
494 necessary to valid the TLB after having done the accesses */
495
496 v1 = ldub_kernel(env->tr.base);
497 v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
498 stb_kernel(env->tr.base, v1);
499 stb_kernel(env->tr.base + old_tss_limit_max, v2);
500
501 /* clear busy bit (it is restartable) */
502 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
503 target_ulong ptr;
504 uint32_t e2;
505 ptr = env->gdt.base + (env->tr.selector & ~7);
506 e2 = ldl_kernel(ptr + 4);
507 e2 &= ~DESC_TSS_BUSY_MASK;
508 stl_kernel(ptr + 4, e2);
509 }
510 old_eflags = compute_eflags();
511 if (source == SWITCH_TSS_IRET)
512 old_eflags &= ~NT_MASK;
513
514 /* save the current state in the old TSS */
515 if (type & 8) {
516 /* 32 bit */
517 stl_kernel(env->tr.base + 0x20, next_eip);
518 stl_kernel(env->tr.base + 0x24, old_eflags);
519 stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
520 stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
521 stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
522 stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
523 stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
524 stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
525 stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
526 stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
527 for(i = 0; i < 6; i++)
528 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
529#ifdef VBOX
530 /* Must store the ldt as it gets reloaded and might have been changed. */
531 stw_kernel(env->tr.base + 0x60, env->ldt.selector);
532#endif
533#if defined(VBOX) && defined(DEBUG)
534 printf("TSS 32 bits switch\n");
535 printf("Saving CS=%08X\n", env->segs[R_CS].selector);
536#endif
537 } else {
538 /* 16 bit */
539 stw_kernel(env->tr.base + 0x0e, next_eip);
540 stw_kernel(env->tr.base + 0x10, old_eflags);
541 stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
542 stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
543 stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
544 stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
545 stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
546 stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
547 stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
548 stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
549 for(i = 0; i < 4; i++)
550 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
551#ifdef VBOX
552 /* Must store the ldt as it gets reloaded and might have been changed. */
553 stw_kernel(env->tr.base + 0x2a, env->ldt.selector);
554#endif
555 }
556
557 /* now if an exception occurs, it will occurs in the next task
558 context */
559
560 if (source == SWITCH_TSS_CALL) {
561 stw_kernel(tss_base, env->tr.selector);
562 new_eflags |= NT_MASK;
563 }
564
565 /* set busy bit */
566 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
567 target_ulong ptr;
568 uint32_t e2;
569 ptr = env->gdt.base + (tss_selector & ~7);
570 e2 = ldl_kernel(ptr + 4);
571 e2 |= DESC_TSS_BUSY_MASK;
572 stl_kernel(ptr + 4, e2);
573 }
574
575 /* set the new CPU state */
576 /* from this point, any exception which occurs can give problems */
577 env->cr[0] |= CR0_TS_MASK;
578 env->hflags |= HF_TS_MASK;
579 env->tr.selector = tss_selector;
580 env->tr.base = tss_base;
581 env->tr.limit = tss_limit;
582 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
583#ifdef VBOX
584 env->tr.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
585 env->tr.newselector = 0;
586#endif
587
588 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
589 cpu_x86_update_cr3(env, new_cr3);
590 }
591
592 /* load all registers without an exception, then reload them with
593 possible exception */
594 env->eip = new_eip;
595 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
596 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
597 if (!(type & 8))
598 eflags_mask &= 0xffff;
599 load_eflags(new_eflags, eflags_mask);
600 /* XXX: what to do in 16 bit case ? */
601 EAX = new_regs[0];
602 ECX = new_regs[1];
603 EDX = new_regs[2];
604 EBX = new_regs[3];
605 ESP = new_regs[4];
606 EBP = new_regs[5];
607 ESI = new_regs[6];
608 EDI = new_regs[7];
609 if (new_eflags & VM_MASK) {
610 for(i = 0; i < 6; i++)
611 load_seg_vm(i, new_segs[i]);
612 /* in vm86, CPL is always 3 */
613 cpu_x86_set_cpl(env, 3);
614 } else {
615 /* CPL is set the RPL of CS */
616 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
617 /* first just selectors as the rest may trigger exceptions */
618 for(i = 0; i < 6; i++)
619 cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
620 }
621
622 env->ldt.selector = new_ldt & ~4;
623 env->ldt.base = 0;
624 env->ldt.limit = 0;
625 env->ldt.flags = 0;
626#ifdef VBOX
627 env->ldt.flags = DESC_INTEL_UNUSABLE;
628 env->ldt.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
629 env->ldt.newselector = 0;
630#endif
631
632 /* load the LDT */
633 if (new_ldt & 4)
634 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
635
636 if ((new_ldt & 0xfffc) != 0) {
637 dt = &env->gdt;
638 index = new_ldt & ~7;
639 if ((index + 7) > dt->limit)
640 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
641 ptr = dt->base + index;
642 e1 = ldl_kernel(ptr);
643 e2 = ldl_kernel(ptr + 4);
644 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
645 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
646 if (!(e2 & DESC_P_MASK))
647 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
648 load_seg_cache_raw_dt(&env->ldt, e1, e2);
649 }
650
651 /* load the segments */
652 if (!(new_eflags & VM_MASK)) {
653 tss_load_seg(R_CS, new_segs[R_CS]);
654 tss_load_seg(R_SS, new_segs[R_SS]);
655 tss_load_seg(R_ES, new_segs[R_ES]);
656 tss_load_seg(R_DS, new_segs[R_DS]);
657 tss_load_seg(R_FS, new_segs[R_FS]);
658 tss_load_seg(R_GS, new_segs[R_GS]);
659 }
660
661 /* check that EIP is in the CS segment limits */
662 if (new_eip > env->segs[R_CS].limit) {
663 /* XXX: different exception if CALL ? */
664 raise_exception_err(EXCP0D_GPF, 0);
665 }
666
667#ifndef CONFIG_USER_ONLY
668 /* reset local breakpoints */
669 if (env->dr[7] & 0x55) {
670 for (i = 0; i < 4; i++) {
671 if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
672 hw_breakpoint_remove(env, i);
673 }
674 env->dr[7] &= ~0x55;
675 }
676#endif
677}
678
679/* check if Port I/O is allowed in TSS */
680static inline void check_io(int addr, int size)
681{
682#ifndef VBOX
683 int io_offset, val, mask;
684#else
685 int val, mask;
686 unsigned int io_offset;
687#endif /* VBOX */
688
689 /* TSS must be a valid 32 bit one */
690 if (!(env->tr.flags & DESC_P_MASK) ||
691 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
692 env->tr.limit < 103)
693 goto fail;
694 io_offset = lduw_kernel(env->tr.base + 0x66);
695 io_offset += (addr >> 3);
696 /* Note: the check needs two bytes */
697 if ((io_offset + 1) > env->tr.limit)
698 goto fail;
699 val = lduw_kernel(env->tr.base + io_offset);
700 val >>= (addr & 7);
701 mask = (1 << size) - 1;
702 /* all bits must be zero to allow the I/O */
703 if ((val & mask) != 0) {
704 fail:
705 raise_exception_err(EXCP0D_GPF, 0);
706 }
707}
708
709#ifdef VBOX
710
711/* Keep in sync with gen_check_external_event() */
712void helper_check_external_event()
713{
714 if ( (env->interrupt_request & ( CPU_INTERRUPT_EXTERNAL_FLUSH_TLB
715 | CPU_INTERRUPT_EXTERNAL_EXIT
716 | CPU_INTERRUPT_EXTERNAL_TIMER
717 | CPU_INTERRUPT_EXTERNAL_DMA))
718 || ( (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_HARD)
719 && (env->eflags & IF_MASK)
720 && !(env->hflags & HF_INHIBIT_IRQ_MASK) ) )
721 {
722 helper_external_event();
723 }
724
725}
726
727void helper_sync_seg(uint32_t reg)
728{
729 if (env->segs[reg].newselector)
730 sync_seg(env, reg, env->segs[reg].newselector);
731}
732
733#endif /* VBOX */
734
735void helper_check_iob(uint32_t t0)
736{
737 check_io(t0, 1);
738}
739
740void helper_check_iow(uint32_t t0)
741{
742 check_io(t0, 2);
743}
744
745void helper_check_iol(uint32_t t0)
746{
747 check_io(t0, 4);
748}
749
750void helper_outb(uint32_t port, uint32_t data)
751{
752#ifndef VBOX
753 cpu_outb(port, data & 0xff);
754#else
755 cpu_outb(env, port, data & 0xff);
756#endif
757}
758
759target_ulong helper_inb(uint32_t port)
760{
761#ifndef VBOX
762 return cpu_inb(port);
763#else
764 return cpu_inb(env, port);
765#endif
766}
767
768void helper_outw(uint32_t port, uint32_t data)
769{
770#ifndef VBOX
771 cpu_outw(port, data & 0xffff);
772#else
773 cpu_outw(env, port, data & 0xffff);
774#endif
775}
776
777target_ulong helper_inw(uint32_t port)
778{
779#ifndef VBOX
780 return cpu_inw(port);
781#else
782 return cpu_inw(env, port);
783#endif
784}
785
786void helper_outl(uint32_t port, uint32_t data)
787{
788#ifndef VBOX
789 cpu_outl(port, data);
790#else
791 cpu_outl(env, port, data);
792#endif
793}
794
795target_ulong helper_inl(uint32_t port)
796{
797#ifndef VBOX
798 return cpu_inl(port);
799#else
800 return cpu_inl(env, port);
801#endif
802}
803
804static inline unsigned int get_sp_mask(unsigned int e2)
805{
806 if (e2 & DESC_B_MASK)
807 return 0xffffffff;
808 else
809 return 0xffff;
810}
811
812static int exeption_has_error_code(int intno)
813{
814 switch(intno) {
815 case 8:
816 case 10:
817 case 11:
818 case 12:
819 case 13:
820 case 14:
821 case 17:
822 return 1;
823 }
824 return 0;
825}
826
827#ifdef TARGET_X86_64
828#define SET_ESP(val, sp_mask)\
829do {\
830 if ((sp_mask) == 0xffff)\
831 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
832 else if ((sp_mask) == 0xffffffffLL)\
833 ESP = (uint32_t)(val);\
834 else\
835 ESP = (val);\
836} while (0)
837#else
838#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
839#endif
840
841/* in 64-bit machines, this can overflow. So this segment addition macro
842 * can be used to trim the value to 32-bit whenever needed */
843#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
844
845/* XXX: add a is_user flag to have proper security support */
846#define PUSHW(ssp, sp, sp_mask, val)\
847{\
848 sp -= 2;\
849 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
850}
851
852#define PUSHL(ssp, sp, sp_mask, val)\
853{\
854 sp -= 4;\
855 stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
856}
857
858#define POPW(ssp, sp, sp_mask, val)\
859{\
860 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
861 sp += 2;\
862}
863
864#define POPL(ssp, sp, sp_mask, val)\
865{\
866 val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
867 sp += 4;\
868}
869
870/* protected mode interrupt */
871static void do_interrupt_protected(int intno, int is_int, int error_code,
872 unsigned int next_eip, int is_hw)
873{
874 SegmentCache *dt;
875 target_ulong ptr, ssp;
876 int type, dpl, selector, ss_dpl, cpl;
877 int has_error_code, new_stack, shift;
878 uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
879 uint32_t old_eip, sp_mask;
880
881#ifdef VBOX
882 if (remR3NotifyTrap(env, intno, error_code, next_eip) != VINF_SUCCESS)
883 cpu_loop_exit();
884#endif
885
886 has_error_code = 0;
887 if (!is_int && !is_hw)
888 has_error_code = exeption_has_error_code(intno);
889 if (is_int)
890 old_eip = next_eip;
891 else
892 old_eip = env->eip;
893
894 dt = &env->idt;
895#ifndef VBOX
896 if (intno * 8 + 7 > dt->limit)
897#else
898 if ((unsigned)intno * 8 + 7 > dt->limit)
899#endif
900 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
901 ptr = dt->base + intno * 8;
902 e1 = ldl_kernel(ptr);
903 e2 = ldl_kernel(ptr + 4);
904 /* check gate type */
905 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
906 switch(type) {
907 case 5: /* task gate */
908#ifdef VBOX
909 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
910 cpl = env->hflags & HF_CPL_MASK;
911 /* check privilege if software int */
912 if (is_int && dpl < cpl)
913 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
914#endif
915 /* must do that check here to return the correct error code */
916 if (!(e2 & DESC_P_MASK))
917 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
918 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
919 if (has_error_code) {
920 int type;
921 uint32_t mask;
922 /* push the error code */
923 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
924 shift = type >> 3;
925 if (env->segs[R_SS].flags & DESC_B_MASK)
926 mask = 0xffffffff;
927 else
928 mask = 0xffff;
929 esp = (ESP - (2 << shift)) & mask;
930 ssp = env->segs[R_SS].base + esp;
931 if (shift)
932 stl_kernel(ssp, error_code);
933 else
934 stw_kernel(ssp, error_code);
935 SET_ESP(esp, mask);
936 }
937 return;
938 case 6: /* 286 interrupt gate */
939 case 7: /* 286 trap gate */
940 case 14: /* 386 interrupt gate */
941 case 15: /* 386 trap gate */
942 break;
943 default:
944 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
945 break;
946 }
947 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
948 cpl = env->hflags & HF_CPL_MASK;
949 /* check privilege if software int */
950 if (is_int && dpl < cpl)
951 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
952 /* check valid bit */
953 if (!(e2 & DESC_P_MASK))
954 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
955 selector = e1 >> 16;
956 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
957 if ((selector & 0xfffc) == 0)
958 raise_exception_err(EXCP0D_GPF, 0);
959
960 if (load_segment(&e1, &e2, selector) != 0)
961 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
962#ifdef VBOX /** @todo figure out when this is done one day... */
963 if (!(e2 & DESC_A_MASK))
964 e2 = set_segment_accessed(selector, e2);
965#endif
966 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
967 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
968 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
969 if (dpl > cpl)
970 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
971 if (!(e2 & DESC_P_MASK))
972 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
973 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
974 /* to inner privilege */
975 get_ss_esp_from_tss(&ss, &esp, dpl);
976 if ((ss & 0xfffc) == 0)
977 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
978 if ((ss & 3) != dpl)
979 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
980 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
981 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
982#ifdef VBOX /** @todo figure out when this is done one day... */
983 if (!(ss_e2 & DESC_A_MASK))
984 ss_e2 = set_segment_accessed(ss, ss_e2);
985#endif
986 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
987 if (ss_dpl != dpl)
988 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
989 if (!(ss_e2 & DESC_S_MASK) ||
990 (ss_e2 & DESC_CS_MASK) ||
991 !(ss_e2 & DESC_W_MASK))
992 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
993 if (!(ss_e2 & DESC_P_MASK))
994#ifdef VBOX /* See page 3-477 of 253666.pdf */
995 raise_exception_err(EXCP0C_STACK, ss & 0xfffc);
996#else
997 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
998#endif
999 new_stack = 1;
1000 sp_mask = get_sp_mask(ss_e2);
1001 ssp = get_seg_base(ss_e1, ss_e2);
1002#if defined(VBOX) && defined(DEBUG)
1003 printf("new stack %04X:%08X gate dpl=%d\n", ss, esp, dpl);
1004#endif
1005 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
1006 /* to same privilege */
1007 if (env->eflags & VM_MASK)
1008 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1009 new_stack = 0;
1010 sp_mask = get_sp_mask(env->segs[R_SS].flags);
1011 ssp = env->segs[R_SS].base;
1012 esp = ESP;
1013 dpl = cpl;
1014 } else {
1015 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1016 new_stack = 0; /* avoid warning */
1017 sp_mask = 0; /* avoid warning */
1018 ssp = 0; /* avoid warning */
1019 esp = 0; /* avoid warning */
1020 }
1021
1022 shift = type >> 3;
1023
1024#if 0
1025 /* XXX: check that enough room is available */
1026 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
1027 if (env->eflags & VM_MASK)
1028 push_size += 8;
1029 push_size <<= shift;
1030#endif
1031 if (shift == 1) {
1032 if (new_stack) {
1033 if (env->eflags & VM_MASK) {
1034 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
1035 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
1036 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
1037 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
1038 }
1039 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
1040 PUSHL(ssp, esp, sp_mask, ESP);
1041 }
1042 PUSHL(ssp, esp, sp_mask, compute_eflags());
1043 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
1044 PUSHL(ssp, esp, sp_mask, old_eip);
1045 if (has_error_code) {
1046 PUSHL(ssp, esp, sp_mask, error_code);
1047 }
1048 } else {
1049 if (new_stack) {
1050 if (env->eflags & VM_MASK) {
1051 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
1052 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
1053 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
1054 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
1055 }
1056 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
1057 PUSHW(ssp, esp, sp_mask, ESP);
1058 }
1059 PUSHW(ssp, esp, sp_mask, compute_eflags());
1060 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
1061 PUSHW(ssp, esp, sp_mask, old_eip);
1062 if (has_error_code) {
1063 PUSHW(ssp, esp, sp_mask, error_code);
1064 }
1065 }
1066
1067 if (new_stack) {
1068 if (env->eflags & VM_MASK) {
1069 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
1070 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
1071 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
1072 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
1073 }
1074 ss = (ss & ~3) | dpl;
1075 cpu_x86_load_seg_cache(env, R_SS, ss,
1076 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
1077 }
1078 SET_ESP(esp, sp_mask);
1079
1080 selector = (selector & ~3) | dpl;
1081 cpu_x86_load_seg_cache(env, R_CS, selector,
1082 get_seg_base(e1, e2),
1083 get_seg_limit(e1, e2),
1084 e2);
1085 cpu_x86_set_cpl(env, dpl);
1086 env->eip = offset;
1087
1088 /* interrupt gate clear IF mask */
1089 if ((type & 1) == 0) {
1090 env->eflags &= ~IF_MASK;
1091 }
1092#ifndef VBOX
1093 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
1094#else
1095 /*
1096 * We must clear VIP/VIF too on interrupt entry, as otherwise FreeBSD
1097 * gets confused by seemingly changed EFLAGS. See #3491 and
1098 * public bug #2341.
1099 */
1100 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK | VIF_MASK | VIP_MASK);
1101#endif
1102}
1103
1104#ifdef VBOX
1105
1106/* check if VME interrupt redirection is enabled in TSS */
1107DECLINLINE(bool) is_vme_irq_redirected(int intno)
1108{
1109 unsigned int io_offset, intredir_offset;
1110 unsigned char val, mask;
1111
1112 /* TSS must be a valid 32 bit one */
1113 if (!(env->tr.flags & DESC_P_MASK) ||
1114 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
1115 env->tr.limit < 103)
1116 goto fail;
1117 io_offset = lduw_kernel(env->tr.base + 0x66);
1118 /* Make sure the io bitmap offset is valid; anything less than sizeof(VBOXTSS) means there's none. */
1119 if (io_offset < 0x68 + 0x20)
1120 io_offset = 0x68 + 0x20;
1121 /* the virtual interrupt redirection bitmap is located below the io bitmap */
1122 intredir_offset = io_offset - 0x20;
1123
1124 intredir_offset += (intno >> 3);
1125 if ((intredir_offset) > env->tr.limit)
1126 goto fail;
1127
1128 val = ldub_kernel(env->tr.base + intredir_offset);
1129 mask = 1 << (unsigned char)(intno & 7);
1130
1131 /* bit set means no redirection. */
1132 if ((val & mask) != 0) {
1133 return false;
1134 }
1135 return true;
1136
1137fail:
1138 raise_exception_err(EXCP0D_GPF, 0);
1139 return true;
1140}
1141
1142/* V86 mode software interrupt with CR4.VME=1 */
1143static void do_soft_interrupt_vme(int intno, int error_code, unsigned int next_eip)
1144{
1145 target_ulong ptr, ssp;
1146 int selector;
1147 uint32_t offset, esp;
1148 uint32_t old_cs, old_eflags;
1149 uint32_t iopl;
1150
1151 iopl = ((env->eflags >> IOPL_SHIFT) & 3);
1152
1153 if (!is_vme_irq_redirected(intno))
1154 {
1155 if (iopl == 3)
1156 {
1157 do_interrupt_protected(intno, 1, error_code, next_eip, 0);
1158 return;
1159 }
1160 else
1161 raise_exception_err(EXCP0D_GPF, 0);
1162 }
1163
1164 /* virtual mode idt is at linear address 0 */
1165 ptr = 0 + intno * 4;
1166 offset = lduw_kernel(ptr);
1167 selector = lduw_kernel(ptr + 2);
1168 esp = ESP;
1169 ssp = env->segs[R_SS].base;
1170 old_cs = env->segs[R_CS].selector;
1171
1172 old_eflags = compute_eflags();
1173 if (iopl < 3)
1174 {
1175 /* copy VIF into IF and set IOPL to 3 */
1176 if (env->eflags & VIF_MASK)
1177 old_eflags |= IF_MASK;
1178 else
1179 old_eflags &= ~IF_MASK;
1180
1181 old_eflags |= (3 << IOPL_SHIFT);
1182 }
1183
1184 /* XXX: use SS segment size ? */
1185 PUSHW(ssp, esp, 0xffff, old_eflags);
1186 PUSHW(ssp, esp, 0xffff, old_cs);
1187 PUSHW(ssp, esp, 0xffff, next_eip);
1188
1189 /* update processor state */
1190 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1191 env->eip = offset;
1192 env->segs[R_CS].selector = selector;
1193 env->segs[R_CS].base = (selector << 4);
1194 env->eflags &= ~(TF_MASK | RF_MASK);
1195
1196 if (iopl < 3)
1197 env->eflags &= ~VIF_MASK;
1198 else
1199 env->eflags &= ~IF_MASK;
1200}
1201
1202#endif /* VBOX */
1203
1204#ifdef TARGET_X86_64
1205
1206#define PUSHQ(sp, val)\
1207{\
1208 sp -= 8;\
1209 stq_kernel(sp, (val));\
1210}
1211
1212#define POPQ(sp, val)\
1213{\
1214 val = ldq_kernel(sp);\
1215 sp += 8;\
1216}
1217
1218static inline target_ulong get_rsp_from_tss(int level)
1219{
1220 int index;
1221
1222#if 0
1223 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
1224 env->tr.base, env->tr.limit);
1225#endif
1226
1227 if (!(env->tr.flags & DESC_P_MASK))
1228 cpu_abort(env, "invalid tss");
1229 index = 8 * level + 4;
1230 if ((index + 7) > env->tr.limit)
1231 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
1232 return ldq_kernel(env->tr.base + index);
1233}
1234
1235/* 64 bit interrupt */
1236static void do_interrupt64(int intno, int is_int, int error_code,
1237 target_ulong next_eip, int is_hw)
1238{
1239 SegmentCache *dt;
1240 target_ulong ptr;
1241 int type, dpl, selector, cpl, ist;
1242 int has_error_code, new_stack;
1243 uint32_t e1, e2, e3, ss;
1244 target_ulong old_eip, esp, offset;
1245
1246#ifdef VBOX
1247 if (remR3NotifyTrap(env, intno, error_code, next_eip) != VINF_SUCCESS)
1248 cpu_loop_exit();
1249#endif
1250
1251 has_error_code = 0;
1252 if (!is_int && !is_hw)
1253 has_error_code = exeption_has_error_code(intno);
1254 if (is_int)
1255 old_eip = next_eip;
1256 else
1257 old_eip = env->eip;
1258
1259 dt = &env->idt;
1260 if (intno * 16 + 15 > dt->limit)
1261 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1262 ptr = dt->base + intno * 16;
1263 e1 = ldl_kernel(ptr);
1264 e2 = ldl_kernel(ptr + 4);
1265 e3 = ldl_kernel(ptr + 8);
1266 /* check gate type */
1267 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1268 switch(type) {
1269 case 14: /* 386 interrupt gate */
1270 case 15: /* 386 trap gate */
1271 break;
1272 default:
1273 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1274 break;
1275 }
1276 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1277 cpl = env->hflags & HF_CPL_MASK;
1278 /* check privilege if software int */
1279 if (is_int && dpl < cpl)
1280 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1281 /* check valid bit */
1282 if (!(e2 & DESC_P_MASK))
1283 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
1284 selector = e1 >> 16;
1285 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1286 ist = e2 & 7;
1287 if ((selector & 0xfffc) == 0)
1288 raise_exception_err(EXCP0D_GPF, 0);
1289
1290 if (load_segment(&e1, &e2, selector) != 0)
1291 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1292 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1293 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1294 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1295 if (dpl > cpl)
1296 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1297 if (!(e2 & DESC_P_MASK))
1298 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1299 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
1300 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1301 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
1302 /* to inner privilege */
1303 if (ist != 0)
1304 esp = get_rsp_from_tss(ist + 3);
1305 else
1306 esp = get_rsp_from_tss(dpl);
1307 esp &= ~0xfLL; /* align stack */
1308 ss = 0;
1309 new_stack = 1;
1310 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
1311 /* to same privilege */
1312 if (env->eflags & VM_MASK)
1313 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1314 new_stack = 0;
1315 if (ist != 0)
1316 esp = get_rsp_from_tss(ist + 3);
1317 else
1318 esp = ESP;
1319 esp &= ~0xfLL; /* align stack */
1320 dpl = cpl;
1321 } else {
1322 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1323 new_stack = 0; /* avoid warning */
1324 esp = 0; /* avoid warning */
1325 }
1326
1327 PUSHQ(esp, env->segs[R_SS].selector);
1328 PUSHQ(esp, ESP);
1329 PUSHQ(esp, compute_eflags());
1330 PUSHQ(esp, env->segs[R_CS].selector);
1331 PUSHQ(esp, old_eip);
1332 if (has_error_code) {
1333 PUSHQ(esp, error_code);
1334 }
1335
1336 if (new_stack) {
1337 ss = 0 | dpl;
1338#ifndef VBOX
1339 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
1340#else
1341 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, dpl << DESC_DPL_SHIFT);
1342#endif
1343 }
1344 ESP = esp;
1345
1346 selector = (selector & ~3) | dpl;
1347 cpu_x86_load_seg_cache(env, R_CS, selector,
1348 get_seg_base(e1, e2),
1349 get_seg_limit(e1, e2),
1350 e2);
1351 cpu_x86_set_cpl(env, dpl);
1352 env->eip = offset;
1353
1354 /* interrupt gate clear IF mask */
1355 if ((type & 1) == 0) {
1356 env->eflags &= ~IF_MASK;
1357 }
1358#ifndef VBOX
1359 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
1360#else /* VBOX */
1361 /*
1362 * We must clear VIP/VIF too on interrupt entry, as otherwise FreeBSD
1363 * gets confused by seemingly changed EFLAGS. See #3491 and
1364 * public bug #2341.
1365 */
1366 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK | VIF_MASK | VIP_MASK);
1367#endif /* VBOX */
1368}
1369#endif
1370
1371#ifdef TARGET_X86_64
1372#if defined(CONFIG_USER_ONLY)
1373void helper_syscall(int next_eip_addend)
1374{
1375 env->exception_index = EXCP_SYSCALL;
1376 env->exception_next_eip = env->eip + next_eip_addend;
1377 cpu_loop_exit();
1378}
1379#else
1380void helper_syscall(int next_eip_addend)
1381{
1382 int selector;
1383
1384 if (!(env->efer & MSR_EFER_SCE)) {
1385 raise_exception_err(EXCP06_ILLOP, 0);
1386 }
1387 selector = (env->star >> 32) & 0xffff;
1388 if (env->hflags & HF_LMA_MASK) {
1389 int code64;
1390
1391 ECX = env->eip + next_eip_addend;
1392 env->regs[11] = compute_eflags();
1393
1394 code64 = env->hflags & HF_CS64_MASK;
1395
1396 cpu_x86_set_cpl(env, 0);
1397 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1398 0, 0xffffffff,
1399 DESC_G_MASK | DESC_P_MASK |
1400 DESC_S_MASK |
1401 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1402 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1403 0, 0xffffffff,
1404 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1405 DESC_S_MASK |
1406 DESC_W_MASK | DESC_A_MASK);
1407 env->eflags &= ~env->fmask;
1408 load_eflags(env->eflags, 0);
1409 if (code64)
1410 env->eip = env->lstar;
1411 else
1412 env->eip = env->cstar;
1413 } else {
1414 ECX = (uint32_t)(env->eip + next_eip_addend);
1415
1416 cpu_x86_set_cpl(env, 0);
1417 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1418 0, 0xffffffff,
1419 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1420 DESC_S_MASK |
1421 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1422 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1423 0, 0xffffffff,
1424 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1425 DESC_S_MASK |
1426 DESC_W_MASK | DESC_A_MASK);
1427 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1428 env->eip = (uint32_t)env->star;
1429 }
1430}
1431#endif
1432#endif
1433
1434#ifdef TARGET_X86_64
1435void helper_sysret(int dflag)
1436{
1437 int cpl, selector;
1438
1439 if (!(env->efer & MSR_EFER_SCE)) {
1440 raise_exception_err(EXCP06_ILLOP, 0);
1441 }
1442 cpl = env->hflags & HF_CPL_MASK;
1443 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1444 raise_exception_err(EXCP0D_GPF, 0);
1445 }
1446 selector = (env->star >> 48) & 0xffff;
1447 if (env->hflags & HF_LMA_MASK) {
1448 if (dflag == 2) {
1449 cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1450 0, 0xffffffff,
1451 DESC_G_MASK | DESC_P_MASK |
1452 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1453 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1454 DESC_L_MASK);
1455 env->eip = ECX;
1456 } else {
1457 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1458 0, 0xffffffff,
1459 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1460 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1461 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1462 env->eip = (uint32_t)ECX;
1463 }
1464 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1465 0, 0xffffffff,
1466 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1467 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1468 DESC_W_MASK | DESC_A_MASK);
1469 load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1470 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1471 cpu_x86_set_cpl(env, 3);
1472 } else {
1473 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1474 0, 0xffffffff,
1475 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1476 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1477 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1478 env->eip = (uint32_t)ECX;
1479 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1480 0, 0xffffffff,
1481 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1482 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1483 DESC_W_MASK | DESC_A_MASK);
1484 env->eflags |= IF_MASK;
1485 cpu_x86_set_cpl(env, 3);
1486 }
1487}
1488#endif
1489
1490#ifdef VBOX
1491
1492/**
1493 * Checks and processes external VMM events.
1494 * Called by op_check_external_event() when any of the flags is set and can be serviced.
1495 */
1496void helper_external_event(void)
1497{
1498# if defined(RT_OS_DARWIN) && defined(VBOX_STRICT)
1499 uintptr_t uSP;
1500# ifdef RT_ARCH_AMD64
1501 __asm__ __volatile__("movq %%rsp, %0" : "=r" (uSP));
1502# else
1503 __asm__ __volatile__("movl %%esp, %0" : "=r" (uSP));
1504# endif
1505 AssertMsg(!(uSP & 15), ("xSP=%#p\n", uSP));
1506# endif
1507 /* Keep in sync with flags checked by gen_check_external_event() */
1508 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_HARD)
1509 {
1510 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request,
1511 ~CPU_INTERRUPT_EXTERNAL_HARD);
1512 cpu_interrupt(env, CPU_INTERRUPT_HARD);
1513 }
1514 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_EXIT)
1515 {
1516 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request,
1517 ~CPU_INTERRUPT_EXTERNAL_EXIT);
1518 cpu_exit(env);
1519 }
1520 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_DMA)
1521 {
1522 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request,
1523 ~CPU_INTERRUPT_EXTERNAL_DMA);
1524 remR3DmaRun(env);
1525 }
1526 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_TIMER)
1527 {
1528 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request,
1529 ~CPU_INTERRUPT_EXTERNAL_TIMER);
1530 remR3TimersRun(env);
1531 }
1532 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_FLUSH_TLB)
1533 {
1534 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request,
1535 ~CPU_INTERRUPT_EXTERNAL_HARD);
1536 cpu_interrupt(env, CPU_INTERRUPT_HARD);
1537 }
1538}
1539
1540/* helper for recording call instruction addresses for later scanning */
1541void helper_record_call()
1542{
1543 if ( !(env->state & CPU_RAW_RING0)
1544 && (env->cr[0] & CR0_PG_MASK)
1545 && !(env->eflags & X86_EFL_IF))
1546 remR3RecordCall(env);
1547}
1548
1549#endif /* VBOX */
1550
1551/* real mode interrupt */
1552static void do_interrupt_real(int intno, int is_int, int error_code,
1553 unsigned int next_eip)
1554{
1555 SegmentCache *dt;
1556 target_ulong ptr, ssp;
1557 int selector;
1558 uint32_t offset, esp;
1559 uint32_t old_cs, old_eip;
1560
1561 /* real mode (simpler !) */
1562 dt = &env->idt;
1563#ifndef VBOX
1564 if (intno * 4 + 3 > dt->limit)
1565#else
1566 if ((unsigned)intno * 4 + 3 > dt->limit)
1567#endif
1568 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1569 ptr = dt->base + intno * 4;
1570 offset = lduw_kernel(ptr);
1571 selector = lduw_kernel(ptr + 2);
1572 esp = ESP;
1573 ssp = env->segs[R_SS].base;
1574 if (is_int)
1575 old_eip = next_eip;
1576 else
1577 old_eip = env->eip;
1578 old_cs = env->segs[R_CS].selector;
1579 /* XXX: use SS segment size ? */
1580 PUSHW(ssp, esp, 0xffff, compute_eflags());
1581 PUSHW(ssp, esp, 0xffff, old_cs);
1582 PUSHW(ssp, esp, 0xffff, old_eip);
1583
1584 /* update processor state */
1585 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1586 env->eip = offset;
1587 env->segs[R_CS].selector = selector;
1588 env->segs[R_CS].base = (selector << 4);
1589 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1590}
1591
1592/* fake user mode interrupt */
1593void do_interrupt_user(int intno, int is_int, int error_code,
1594 target_ulong next_eip)
1595{
1596 SegmentCache *dt;
1597 target_ulong ptr;
1598 int dpl, cpl, shift;
1599 uint32_t e2;
1600
1601 dt = &env->idt;
1602 if (env->hflags & HF_LMA_MASK) {
1603 shift = 4;
1604 } else {
1605 shift = 3;
1606 }
1607 ptr = dt->base + (intno << shift);
1608 e2 = ldl_kernel(ptr + 4);
1609
1610 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1611 cpl = env->hflags & HF_CPL_MASK;
1612 /* check privilege if software int */
1613 if (is_int && dpl < cpl)
1614 raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1615
1616 /* Since we emulate only user space, we cannot do more than
1617 exiting the emulation with the suitable exception and error
1618 code */
1619 if (is_int)
1620 EIP = next_eip;
1621}
1622
1623#if !defined(CONFIG_USER_ONLY)
1624static void handle_even_inj(int intno, int is_int, int error_code,
1625 int is_hw, int rm)
1626{
1627 uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1628 if (!(event_inj & SVM_EVTINJ_VALID)) {
1629 int type;
1630 if (is_int)
1631 type = SVM_EVTINJ_TYPE_SOFT;
1632 else
1633 type = SVM_EVTINJ_TYPE_EXEPT;
1634 event_inj = intno | type | SVM_EVTINJ_VALID;
1635 if (!rm && exeption_has_error_code(intno)) {
1636 event_inj |= SVM_EVTINJ_VALID_ERR;
1637 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
1638 }
1639 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
1640 }
1641}
1642#endif
1643
1644/*
1645 * Begin execution of an interruption. is_int is TRUE if coming from
1646 * the int instruction. next_eip is the EIP value AFTER the interrupt
1647 * instruction. It is only relevant if is_int is TRUE.
1648 */
1649void do_interrupt(int intno, int is_int, int error_code,
1650 target_ulong next_eip, int is_hw)
1651{
1652 if (qemu_loglevel_mask(CPU_LOG_INT)) {
1653 if ((env->cr[0] & CR0_PE_MASK)) {
1654 static int count;
1655 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,
1656 count, intno, error_code, is_int,
1657 env->hflags & HF_CPL_MASK,
1658 env->segs[R_CS].selector, EIP,
1659 (int)env->segs[R_CS].base + EIP,
1660 env->segs[R_SS].selector, ESP);
1661 if (intno == 0x0e) {
1662 qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
1663 } else {
1664 qemu_log(" EAX=" TARGET_FMT_lx, EAX);
1665 }
1666 qemu_log("\n");
1667 log_cpu_state(env, X86_DUMP_CCOP);
1668#if 0
1669 {
1670 int i;
1671 uint8_t *ptr;
1672 qemu_log(" code=");
1673 ptr = env->segs[R_CS].base + env->eip;
1674 for(i = 0; i < 16; i++) {
1675 qemu_log(" %02x", ldub(ptr + i));
1676 }
1677 qemu_log("\n");
1678 }
1679#endif
1680 count++;
1681 }
1682 }
1683#ifdef VBOX
1684 if (RT_UNLIKELY(env->state & CPU_EMULATE_SINGLE_STEP)) {
1685 if (is_int) {
1686 RTLogPrintf("do_interrupt: %#04x err=%#x pc=%#RGv%s\n",
1687 intno, error_code, (RTGCPTR)env->eip, is_hw ? " hw" : "");
1688 } else {
1689 RTLogPrintf("do_interrupt: %#04x err=%#x pc=%#RGv next=%#RGv%s\n",
1690 intno, error_code, (RTGCPTR)env->eip, (RTGCPTR)next_eip, is_hw ? " hw" : "");
1691 }
1692 }
1693#endif
1694 if (env->cr[0] & CR0_PE_MASK) {
1695#if !defined(CONFIG_USER_ONLY)
1696 if (env->hflags & HF_SVMI_MASK)
1697 handle_even_inj(intno, is_int, error_code, is_hw, 0);
1698#endif
1699#ifdef TARGET_X86_64
1700 if (env->hflags & HF_LMA_MASK) {
1701 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1702 } else
1703#endif
1704 {
1705#ifdef VBOX
1706 /* int xx *, v86 code and VME enabled? */
1707 if ( (env->eflags & VM_MASK)
1708 && (env->cr[4] & CR4_VME_MASK)
1709 && is_int
1710 && !is_hw
1711 && env->eip + 1 != next_eip /* single byte int 3 goes straight to the protected mode handler */
1712 )
1713 do_soft_interrupt_vme(intno, error_code, next_eip);
1714 else
1715#endif /* VBOX */
1716 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1717 }
1718 } else {
1719#if !defined(CONFIG_USER_ONLY)
1720 if (env->hflags & HF_SVMI_MASK)
1721 handle_even_inj(intno, is_int, error_code, is_hw, 1);
1722#endif
1723 do_interrupt_real(intno, is_int, error_code, next_eip);
1724 }
1725
1726#if !defined(CONFIG_USER_ONLY)
1727 if (env->hflags & HF_SVMI_MASK) {
1728 uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
1729 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
1730 }
1731#endif
1732}
1733
1734/* This should come from sysemu.h - if we could include it here... */
1735void qemu_system_reset_request(void);
1736
1737/*
1738 * Check nested exceptions and change to double or triple fault if
1739 * needed. It should only be called, if this is not an interrupt.
1740 * Returns the new exception number.
1741 */
1742static int check_exception(int intno, int *error_code)
1743{
1744 int first_contributory = env->old_exception == 0 ||
1745 (env->old_exception >= 10 &&
1746 env->old_exception <= 13);
1747 int second_contributory = intno == 0 ||
1748 (intno >= 10 && intno <= 13);
1749
1750 qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
1751 env->old_exception, intno);
1752
1753#if !defined(CONFIG_USER_ONLY)
1754 if (env->old_exception == EXCP08_DBLE) {
1755 if (env->hflags & HF_SVMI_MASK)
1756 helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
1757
1758 qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
1759
1760# ifndef VBOX
1761 qemu_system_reset_request();
1762# else
1763 remR3RaiseRC(env->pVM, VINF_EM_RESET); /** @todo test + improve tripple fault handling. */
1764# endif
1765 return EXCP_HLT;
1766 }
1767#endif
1768
1769 if ((first_contributory && second_contributory)
1770 || (env->old_exception == EXCP0E_PAGE &&
1771 (second_contributory || (intno == EXCP0E_PAGE)))) {
1772 intno = EXCP08_DBLE;
1773 *error_code = 0;
1774 }
1775
1776 if (second_contributory || (intno == EXCP0E_PAGE) ||
1777 (intno == EXCP08_DBLE))
1778 env->old_exception = intno;
1779
1780 return intno;
1781}
1782
1783/*
1784 * Signal an interruption. It is executed in the main CPU loop.
1785 * is_int is TRUE if coming from the int instruction. next_eip is the
1786 * EIP value AFTER the interrupt instruction. It is only relevant if
1787 * is_int is TRUE.
1788 */
1789static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
1790 int next_eip_addend)
1791{
1792#if defined(VBOX) && defined(DEBUG)
1793 Log2(("raise_interrupt: %x %x %x %RGv\n", intno, is_int, error_code, (RTGCPTR)env->eip + next_eip_addend));
1794#endif
1795 if (!is_int) {
1796 helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1797 intno = check_exception(intno, &error_code);
1798 } else {
1799 helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
1800 }
1801
1802 env->exception_index = intno;
1803 env->error_code = error_code;
1804 env->exception_is_int = is_int;
1805 env->exception_next_eip = env->eip + next_eip_addend;
1806 cpu_loop_exit();
1807}
1808
1809/* shortcuts to generate exceptions */
1810
1811void raise_exception_err(int exception_index, int error_code)
1812{
1813 raise_interrupt(exception_index, 0, error_code, 0);
1814}
1815
1816void raise_exception(int exception_index)
1817{
1818 raise_interrupt(exception_index, 0, 0, 0);
1819}
1820
1821void raise_exception_env(int exception_index, CPUState *nenv)
1822{
1823 env = nenv;
1824 raise_exception(exception_index);
1825}
1826/* SMM support */
1827
1828#if defined(CONFIG_USER_ONLY)
1829
1830void do_smm_enter(void)
1831{
1832}
1833
1834void helper_rsm(void)
1835{
1836}
1837
1838#else
1839
1840#ifdef TARGET_X86_64
1841#define SMM_REVISION_ID 0x00020064
1842#else
1843#define SMM_REVISION_ID 0x00020000
1844#endif
1845
1846void do_smm_enter(void)
1847{
1848 target_ulong sm_state;
1849 SegmentCache *dt;
1850 int i, offset;
1851
1852 qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
1853 log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
1854
1855 env->hflags |= HF_SMM_MASK;
1856 cpu_smm_update(env);
1857
1858 sm_state = env->smbase + 0x8000;
1859
1860#ifdef TARGET_X86_64
1861 for(i = 0; i < 6; i++) {
1862 dt = &env->segs[i];
1863 offset = 0x7e00 + i * 16;
1864 stw_phys(sm_state + offset, dt->selector);
1865 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1866 stl_phys(sm_state + offset + 4, dt->limit);
1867 stq_phys(sm_state + offset + 8, dt->base);
1868 }
1869
1870 stq_phys(sm_state + 0x7e68, env->gdt.base);
1871 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1872
1873 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1874 stq_phys(sm_state + 0x7e78, env->ldt.base);
1875 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1876 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1877
1878 stq_phys(sm_state + 0x7e88, env->idt.base);
1879 stl_phys(sm_state + 0x7e84, env->idt.limit);
1880
1881 stw_phys(sm_state + 0x7e90, env->tr.selector);
1882 stq_phys(sm_state + 0x7e98, env->tr.base);
1883 stl_phys(sm_state + 0x7e94, env->tr.limit);
1884 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1885
1886 stq_phys(sm_state + 0x7ed0, env->efer);
1887
1888 stq_phys(sm_state + 0x7ff8, EAX);
1889 stq_phys(sm_state + 0x7ff0, ECX);
1890 stq_phys(sm_state + 0x7fe8, EDX);
1891 stq_phys(sm_state + 0x7fe0, EBX);
1892 stq_phys(sm_state + 0x7fd8, ESP);
1893 stq_phys(sm_state + 0x7fd0, EBP);
1894 stq_phys(sm_state + 0x7fc8, ESI);
1895 stq_phys(sm_state + 0x7fc0, EDI);
1896 for(i = 8; i < 16; i++)
1897 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1898 stq_phys(sm_state + 0x7f78, env->eip);
1899 stl_phys(sm_state + 0x7f70, compute_eflags());
1900 stl_phys(sm_state + 0x7f68, env->dr[6]);
1901 stl_phys(sm_state + 0x7f60, env->dr[7]);
1902
1903 stl_phys(sm_state + 0x7f48, env->cr[4]);
1904 stl_phys(sm_state + 0x7f50, env->cr[3]);
1905 stl_phys(sm_state + 0x7f58, env->cr[0]);
1906
1907 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1908 stl_phys(sm_state + 0x7f00, env->smbase);
1909#else
1910 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1911 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1912 stl_phys(sm_state + 0x7ff4, compute_eflags());
1913 stl_phys(sm_state + 0x7ff0, env->eip);
1914 stl_phys(sm_state + 0x7fec, EDI);
1915 stl_phys(sm_state + 0x7fe8, ESI);
1916 stl_phys(sm_state + 0x7fe4, EBP);
1917 stl_phys(sm_state + 0x7fe0, ESP);
1918 stl_phys(sm_state + 0x7fdc, EBX);
1919 stl_phys(sm_state + 0x7fd8, EDX);
1920 stl_phys(sm_state + 0x7fd4, ECX);
1921 stl_phys(sm_state + 0x7fd0, EAX);
1922 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1923 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1924
1925 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1926 stl_phys(sm_state + 0x7f64, env->tr.base);
1927 stl_phys(sm_state + 0x7f60, env->tr.limit);
1928 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1929
1930 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1931 stl_phys(sm_state + 0x7f80, env->ldt.base);
1932 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1933 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1934
1935 stl_phys(sm_state + 0x7f74, env->gdt.base);
1936 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1937
1938 stl_phys(sm_state + 0x7f58, env->idt.base);
1939 stl_phys(sm_state + 0x7f54, env->idt.limit);
1940
1941 for(i = 0; i < 6; i++) {
1942 dt = &env->segs[i];
1943 if (i < 3)
1944 offset = 0x7f84 + i * 12;
1945 else
1946 offset = 0x7f2c + (i - 3) * 12;
1947 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1948 stl_phys(sm_state + offset + 8, dt->base);
1949 stl_phys(sm_state + offset + 4, dt->limit);
1950 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1951 }
1952 stl_phys(sm_state + 0x7f14, env->cr[4]);
1953
1954 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1955 stl_phys(sm_state + 0x7ef8, env->smbase);
1956#endif
1957 /* init SMM cpu state */
1958
1959#ifdef TARGET_X86_64
1960 cpu_load_efer(env, 0);
1961#endif
1962 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1963 env->eip = 0x00008000;
1964 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1965 0xffffffff, 0);
1966 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1967 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1968 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1969 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1970 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1971
1972 cpu_x86_update_cr0(env,
1973 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1974 cpu_x86_update_cr4(env, 0);
1975 env->dr[7] = 0x00000400;
1976 CC_OP = CC_OP_EFLAGS;
1977}
1978
1979void helper_rsm(void)
1980{
1981#ifdef VBOX
1982 cpu_abort(env, "helper_rsm");
1983#else /* !VBOX */
1984 target_ulong sm_state;
1985 int i, offset;
1986 uint32_t val;
1987
1988 sm_state = env->smbase + 0x8000;
1989#ifdef TARGET_X86_64
1990 cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
1991
1992 for(i = 0; i < 6; i++) {
1993 offset = 0x7e00 + i * 16;
1994 cpu_x86_load_seg_cache(env, i,
1995 lduw_phys(sm_state + offset),
1996 ldq_phys(sm_state + offset + 8),
1997 ldl_phys(sm_state + offset + 4),
1998 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1999 }
2000
2001 env->gdt.base = ldq_phys(sm_state + 0x7e68);
2002 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
2003
2004 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
2005 env->ldt.base = ldq_phys(sm_state + 0x7e78);
2006 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
2007 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
2008#ifdef VBOX
2009 env->ldt.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2010 env->ldt.newselector = 0;
2011#endif
2012
2013 env->idt.base = ldq_phys(sm_state + 0x7e88);
2014 env->idt.limit = ldl_phys(sm_state + 0x7e84);
2015
2016 env->tr.selector = lduw_phys(sm_state + 0x7e90);
2017 env->tr.base = ldq_phys(sm_state + 0x7e98);
2018 env->tr.limit = ldl_phys(sm_state + 0x7e94);
2019 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
2020#ifdef VBOX
2021 env->tr.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2022 env->tr.newselector = 0;
2023#endif
2024
2025 EAX = ldq_phys(sm_state + 0x7ff8);
2026 ECX = ldq_phys(sm_state + 0x7ff0);
2027 EDX = ldq_phys(sm_state + 0x7fe8);
2028 EBX = ldq_phys(sm_state + 0x7fe0);
2029 ESP = ldq_phys(sm_state + 0x7fd8);
2030 EBP = ldq_phys(sm_state + 0x7fd0);
2031 ESI = ldq_phys(sm_state + 0x7fc8);
2032 EDI = ldq_phys(sm_state + 0x7fc0);
2033 for(i = 8; i < 16; i++)
2034 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
2035 env->eip = ldq_phys(sm_state + 0x7f78);
2036 load_eflags(ldl_phys(sm_state + 0x7f70),
2037 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
2038 env->dr[6] = ldl_phys(sm_state + 0x7f68);
2039 env->dr[7] = ldl_phys(sm_state + 0x7f60);
2040
2041 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
2042 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
2043 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
2044
2045 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
2046 if (val & 0x20000) {
2047 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
2048 }
2049#else
2050 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
2051 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
2052 load_eflags(ldl_phys(sm_state + 0x7ff4),
2053 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
2054 env->eip = ldl_phys(sm_state + 0x7ff0);
2055 EDI = ldl_phys(sm_state + 0x7fec);
2056 ESI = ldl_phys(sm_state + 0x7fe8);
2057 EBP = ldl_phys(sm_state + 0x7fe4);
2058 ESP = ldl_phys(sm_state + 0x7fe0);
2059 EBX = ldl_phys(sm_state + 0x7fdc);
2060 EDX = ldl_phys(sm_state + 0x7fd8);
2061 ECX = ldl_phys(sm_state + 0x7fd4);
2062 EAX = ldl_phys(sm_state + 0x7fd0);
2063 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
2064 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
2065
2066 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
2067 env->tr.base = ldl_phys(sm_state + 0x7f64);
2068 env->tr.limit = ldl_phys(sm_state + 0x7f60);
2069 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
2070#ifdef VBOX
2071 env->tr.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2072 env->tr.newselector = 0;
2073#endif
2074
2075 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
2076 env->ldt.base = ldl_phys(sm_state + 0x7f80);
2077 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
2078 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
2079#ifdef VBOX
2080 env->ldt.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2081 env->ldt.newselector = 0;
2082#endif
2083
2084 env->gdt.base = ldl_phys(sm_state + 0x7f74);
2085 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
2086
2087 env->idt.base = ldl_phys(sm_state + 0x7f58);
2088 env->idt.limit = ldl_phys(sm_state + 0x7f54);
2089
2090 for(i = 0; i < 6; i++) {
2091 if (i < 3)
2092 offset = 0x7f84 + i * 12;
2093 else
2094 offset = 0x7f2c + (i - 3) * 12;
2095 cpu_x86_load_seg_cache(env, i,
2096 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
2097 ldl_phys(sm_state + offset + 8),
2098 ldl_phys(sm_state + offset + 4),
2099 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
2100 }
2101 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
2102
2103 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
2104 if (val & 0x20000) {
2105 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
2106 }
2107#endif
2108 CC_OP = CC_OP_EFLAGS;
2109 env->hflags &= ~HF_SMM_MASK;
2110 cpu_smm_update(env);
2111
2112 qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
2113 log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
2114#endif /* !VBOX */
2115}
2116
2117#endif /* !CONFIG_USER_ONLY */
2118
2119
2120/* division, flags are undefined */
2121
2122void helper_divb_AL(target_ulong t0)
2123{
2124 unsigned int num, den, q, r;
2125
2126 num = (EAX & 0xffff);
2127 den = (t0 & 0xff);
2128 if (den == 0) {
2129 raise_exception(EXCP00_DIVZ);
2130 }
2131 q = (num / den);
2132 if (q > 0xff)
2133 raise_exception(EXCP00_DIVZ);
2134 q &= 0xff;
2135 r = (num % den) & 0xff;
2136 EAX = (EAX & ~0xffff) | (r << 8) | q;
2137}
2138
2139void helper_idivb_AL(target_ulong t0)
2140{
2141 int num, den, q, r;
2142
2143 num = (int16_t)EAX;
2144 den = (int8_t)t0;
2145 if (den == 0) {
2146 raise_exception(EXCP00_DIVZ);
2147 }
2148 q = (num / den);
2149 if (q != (int8_t)q)
2150 raise_exception(EXCP00_DIVZ);
2151 q &= 0xff;
2152 r = (num % den) & 0xff;
2153 EAX = (EAX & ~0xffff) | (r << 8) | q;
2154}
2155
2156void helper_divw_AX(target_ulong t0)
2157{
2158 unsigned int num, den, q, r;
2159
2160 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
2161 den = (t0 & 0xffff);
2162 if (den == 0) {
2163 raise_exception(EXCP00_DIVZ);
2164 }
2165 q = (num / den);
2166 if (q > 0xffff)
2167 raise_exception(EXCP00_DIVZ);
2168 q &= 0xffff;
2169 r = (num % den) & 0xffff;
2170 EAX = (EAX & ~0xffff) | q;
2171 EDX = (EDX & ~0xffff) | r;
2172}
2173
2174void helper_idivw_AX(target_ulong t0)
2175{
2176 int num, den, q, r;
2177
2178 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
2179 den = (int16_t)t0;
2180 if (den == 0) {
2181 raise_exception(EXCP00_DIVZ);
2182 }
2183 q = (num / den);
2184 if (q != (int16_t)q)
2185 raise_exception(EXCP00_DIVZ);
2186 q &= 0xffff;
2187 r = (num % den) & 0xffff;
2188 EAX = (EAX & ~0xffff) | q;
2189 EDX = (EDX & ~0xffff) | r;
2190}
2191
2192void helper_divl_EAX(target_ulong t0)
2193{
2194 unsigned int den, r;
2195 uint64_t num, q;
2196
2197 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2198 den = t0;
2199 if (den == 0) {
2200 raise_exception(EXCP00_DIVZ);
2201 }
2202 q = (num / den);
2203 r = (num % den);
2204 if (q > 0xffffffff)
2205 raise_exception(EXCP00_DIVZ);
2206 EAX = (uint32_t)q;
2207 EDX = (uint32_t)r;
2208}
2209
2210void helper_idivl_EAX(target_ulong t0)
2211{
2212 int den, r;
2213 int64_t num, q;
2214
2215 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2216 den = t0;
2217 if (den == 0) {
2218 raise_exception(EXCP00_DIVZ);
2219 }
2220 q = (num / den);
2221 r = (num % den);
2222 if (q != (int32_t)q)
2223 raise_exception(EXCP00_DIVZ);
2224 EAX = (uint32_t)q;
2225 EDX = (uint32_t)r;
2226}
2227
2228/* bcd */
2229
2230/* XXX: exception */
2231void helper_aam(int base)
2232{
2233 int al, ah;
2234 al = EAX & 0xff;
2235 ah = al / base;
2236 al = al % base;
2237 EAX = (EAX & ~0xffff) | al | (ah << 8);
2238 CC_DST = al;
2239}
2240
2241void helper_aad(int base)
2242{
2243 int al, ah;
2244 al = EAX & 0xff;
2245 ah = (EAX >> 8) & 0xff;
2246 al = ((ah * base) + al) & 0xff;
2247 EAX = (EAX & ~0xffff) | al;
2248 CC_DST = al;
2249}
2250
2251void helper_aaa(void)
2252{
2253 int icarry;
2254 int al, ah, af;
2255 int eflags;
2256
2257 eflags = helper_cc_compute_all(CC_OP);
2258 af = eflags & CC_A;
2259 al = EAX & 0xff;
2260 ah = (EAX >> 8) & 0xff;
2261
2262 icarry = (al > 0xf9);
2263 if (((al & 0x0f) > 9 ) || af) {
2264 al = (al + 6) & 0x0f;
2265 ah = (ah + 1 + icarry) & 0xff;
2266 eflags |= CC_C | CC_A;
2267 } else {
2268 eflags &= ~(CC_C | CC_A);
2269 al &= 0x0f;
2270 }
2271 EAX = (EAX & ~0xffff) | al | (ah << 8);
2272 CC_SRC = eflags;
2273}
2274
2275void helper_aas(void)
2276{
2277 int icarry;
2278 int al, ah, af;
2279 int eflags;
2280
2281 eflags = helper_cc_compute_all(CC_OP);
2282 af = eflags & CC_A;
2283 al = EAX & 0xff;
2284 ah = (EAX >> 8) & 0xff;
2285
2286 icarry = (al < 6);
2287 if (((al & 0x0f) > 9 ) || af) {
2288 al = (al - 6) & 0x0f;
2289 ah = (ah - 1 - icarry) & 0xff;
2290 eflags |= CC_C | CC_A;
2291 } else {
2292 eflags &= ~(CC_C | CC_A);
2293 al &= 0x0f;
2294 }
2295 EAX = (EAX & ~0xffff) | al | (ah << 8);
2296 CC_SRC = eflags;
2297}
2298
2299void helper_daa(void)
2300{
2301 int al, af, cf;
2302 int eflags;
2303
2304 eflags = helper_cc_compute_all(CC_OP);
2305 cf = eflags & CC_C;
2306 af = eflags & CC_A;
2307 al = EAX & 0xff;
2308
2309 eflags = 0;
2310 if (((al & 0x0f) > 9 ) || af) {
2311 al = (al + 6) & 0xff;
2312 eflags |= CC_A;
2313 }
2314 if ((al > 0x9f) || cf) {
2315 al = (al + 0x60) & 0xff;
2316 eflags |= CC_C;
2317 }
2318 EAX = (EAX & ~0xff) | al;
2319 /* well, speed is not an issue here, so we compute the flags by hand */
2320 eflags |= (al == 0) << 6; /* zf */
2321 eflags |= parity_table[al]; /* pf */
2322 eflags |= (al & 0x80); /* sf */
2323 CC_SRC = eflags;
2324}
2325
2326void helper_das(void)
2327{
2328 int al, al1, af, cf;
2329 int eflags;
2330
2331 eflags = helper_cc_compute_all(CC_OP);
2332 cf = eflags & CC_C;
2333 af = eflags & CC_A;
2334 al = EAX & 0xff;
2335
2336 eflags = 0;
2337 al1 = al;
2338 if (((al & 0x0f) > 9 ) || af) {
2339 eflags |= CC_A;
2340 if (al < 6 || cf)
2341 eflags |= CC_C;
2342 al = (al - 6) & 0xff;
2343 }
2344 if ((al1 > 0x99) || cf) {
2345 al = (al - 0x60) & 0xff;
2346 eflags |= CC_C;
2347 }
2348 EAX = (EAX & ~0xff) | al;
2349 /* well, speed is not an issue here, so we compute the flags by hand */
2350 eflags |= (al == 0) << 6; /* zf */
2351 eflags |= parity_table[al]; /* pf */
2352 eflags |= (al & 0x80); /* sf */
2353 CC_SRC = eflags;
2354}
2355
2356void helper_into(int next_eip_addend)
2357{
2358 int eflags;
2359 eflags = helper_cc_compute_all(CC_OP);
2360 if (eflags & CC_O) {
2361 raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
2362 }
2363}
2364
2365void helper_cmpxchg8b(target_ulong a0)
2366{
2367 uint64_t d;
2368 int eflags;
2369
2370 eflags = helper_cc_compute_all(CC_OP);
2371 d = ldq(a0);
2372 if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
2373 stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
2374 eflags |= CC_Z;
2375 } else {
2376 /* always do the store */
2377 stq(a0, d);
2378 EDX = (uint32_t)(d >> 32);
2379 EAX = (uint32_t)d;
2380 eflags &= ~CC_Z;
2381 }
2382 CC_SRC = eflags;
2383}
2384
2385#ifdef TARGET_X86_64
2386void helper_cmpxchg16b(target_ulong a0)
2387{
2388 uint64_t d0, d1;
2389 int eflags;
2390
2391 if ((a0 & 0xf) != 0)
2392 raise_exception(EXCP0D_GPF);
2393 eflags = helper_cc_compute_all(CC_OP);
2394 d0 = ldq(a0);
2395 d1 = ldq(a0 + 8);
2396 if (d0 == EAX && d1 == EDX) {
2397 stq(a0, EBX);
2398 stq(a0 + 8, ECX);
2399 eflags |= CC_Z;
2400 } else {
2401 /* always do the store */
2402 stq(a0, d0);
2403 stq(a0 + 8, d1);
2404 EDX = d1;
2405 EAX = d0;
2406 eflags &= ~CC_Z;
2407 }
2408 CC_SRC = eflags;
2409}
2410#endif
2411
2412void helper_single_step(void)
2413{
2414#ifndef CONFIG_USER_ONLY
2415 check_hw_breakpoints(env, 1);
2416 env->dr[6] |= DR6_BS;
2417#endif
2418 raise_exception(EXCP01_DB);
2419}
2420
2421void helper_cpuid(void)
2422{
2423 uint32_t eax, ebx, ecx, edx;
2424
2425 helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
2426
2427 cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
2428 EAX = eax;
2429 EBX = ebx;
2430 ECX = ecx;
2431 EDX = edx;
2432}
2433
2434void helper_enter_level(int level, int data32, target_ulong t1)
2435{
2436 target_ulong ssp;
2437 uint32_t esp_mask, esp, ebp;
2438
2439 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2440 ssp = env->segs[R_SS].base;
2441 ebp = EBP;
2442 esp = ESP;
2443 if (data32) {
2444 /* 32 bit */
2445 esp -= 4;
2446 while (--level) {
2447 esp -= 4;
2448 ebp -= 4;
2449 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
2450 }
2451 esp -= 4;
2452 stl(ssp + (esp & esp_mask), t1);
2453 } else {
2454 /* 16 bit */
2455 esp -= 2;
2456 while (--level) {
2457 esp -= 2;
2458 ebp -= 2;
2459 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
2460 }
2461 esp -= 2;
2462 stw(ssp + (esp & esp_mask), t1);
2463 }
2464}
2465
2466#ifdef TARGET_X86_64
2467void helper_enter64_level(int level, int data64, target_ulong t1)
2468{
2469 target_ulong esp, ebp;
2470 ebp = EBP;
2471 esp = ESP;
2472
2473 if (data64) {
2474 /* 64 bit */
2475 esp -= 8;
2476 while (--level) {
2477 esp -= 8;
2478 ebp -= 8;
2479 stq(esp, ldq(ebp));
2480 }
2481 esp -= 8;
2482 stq(esp, t1);
2483 } else {
2484 /* 16 bit */
2485 esp -= 2;
2486 while (--level) {
2487 esp -= 2;
2488 ebp -= 2;
2489 stw(esp, lduw(ebp));
2490 }
2491 esp -= 2;
2492 stw(esp, t1);
2493 }
2494}
2495#endif
2496
2497void helper_lldt(int selector)
2498{
2499 SegmentCache *dt;
2500 uint32_t e1, e2;
2501#ifndef VBOX
2502 int index, entry_limit;
2503#else
2504 unsigned int index, entry_limit;
2505#endif
2506 target_ulong ptr;
2507
2508#ifdef VBOX
2509 Log(("helper_lldt_T0: old ldtr=%RTsel {.base=%RGv, .limit=%RGv} new=%RTsel\n",
2510 (RTSEL)env->ldt.selector, (RTGCPTR)env->ldt.base, (RTGCPTR)env->ldt.limit, (RTSEL)(selector & 0xffff)));
2511#endif
2512
2513 selector &= 0xffff;
2514 if ((selector & 0xfffc) == 0) {
2515 /* XXX: NULL selector case: invalid LDT */
2516 env->ldt.base = 0;
2517 env->ldt.limit = 0;
2518#ifdef VBOX
2519 env->ldt.flags = DESC_INTEL_UNUSABLE;
2520 env->ldt.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2521 env->ldt.newselector = 0;
2522#endif
2523 } else {
2524 if (selector & 0x4)
2525 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2526 dt = &env->gdt;
2527 index = selector & ~7;
2528#ifdef TARGET_X86_64
2529 if (env->hflags & HF_LMA_MASK)
2530 entry_limit = 15;
2531 else
2532#endif
2533 entry_limit = 7;
2534 if ((index + entry_limit) > dt->limit)
2535 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2536 ptr = dt->base + index;
2537 e1 = ldl_kernel(ptr);
2538 e2 = ldl_kernel(ptr + 4);
2539 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
2540 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2541 if (!(e2 & DESC_P_MASK))
2542 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2543#ifdef TARGET_X86_64
2544 if (env->hflags & HF_LMA_MASK) {
2545 uint32_t e3;
2546 e3 = ldl_kernel(ptr + 8);
2547 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2548 env->ldt.base |= (target_ulong)e3 << 32;
2549 } else
2550#endif
2551 {
2552 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2553 }
2554 }
2555 env->ldt.selector = selector;
2556#ifdef VBOX
2557 Log(("helper_lldt_T0: new ldtr=%RTsel {.base=%RGv, .limit=%RGv}\n",
2558 (RTSEL)env->ldt.selector, (RTGCPTR)env->ldt.base, (RTGCPTR)env->ldt.limit));
2559#endif
2560}
2561
2562void helper_ltr(int selector)
2563{
2564 SegmentCache *dt;
2565 uint32_t e1, e2;
2566#ifndef VBOX
2567 int index, type, entry_limit;
2568#else
2569 unsigned int index;
2570 int type, entry_limit;
2571#endif
2572 target_ulong ptr;
2573
2574#ifdef VBOX
2575 Log(("helper_ltr: pc=%RGv old tr=%RTsel {.base=%RGv, .limit=%RGv, .flags=%RX32} new=%RTsel\n",
2576 (RTGCPTR)env->eip, (RTSEL)env->tr.selector, (RTGCPTR)env->tr.base, (RTGCPTR)env->tr.limit,
2577 env->tr.flags, (RTSEL)(selector & 0xffff)));
2578#endif
2579 selector &= 0xffff;
2580 if ((selector & 0xfffc) == 0) {
2581 /* NULL selector case: invalid TR */
2582 env->tr.base = 0;
2583 env->tr.limit = 0;
2584 env->tr.flags = 0;
2585#ifdef VBOX
2586 env->tr.flags = DESC_INTEL_UNUSABLE;
2587 env->tr.fVBoxFlags = CPUMSELREG_FLAGS_VALID;
2588 env->tr.newselector = 0;
2589#endif
2590 } else {
2591 if (selector & 0x4)
2592 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2593 dt = &env->gdt;
2594 index = selector & ~7;
2595#ifdef TARGET_X86_64
2596 if (env->hflags & HF_LMA_MASK)
2597 entry_limit = 15;
2598 else
2599#endif
2600 entry_limit = 7;
2601 if ((index + entry_limit) > dt->limit)
2602 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2603 ptr = dt->base + index;
2604 e1 = ldl_kernel(ptr);
2605 e2 = ldl_kernel(ptr + 4);
2606 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2607 if ((e2 & DESC_S_MASK) ||
2608 (type != 1 && type != 9))
2609 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2610 if (!(e2 & DESC_P_MASK))
2611 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2612#ifdef TARGET_X86_64
2613 if (env->hflags & HF_LMA_MASK) {
2614 uint32_t e3, e4;
2615 e3 = ldl_kernel(ptr + 8);
2616 e4 = ldl_kernel(ptr + 12);
2617 if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2618 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2619 load_seg_cache_raw_dt(&env->tr, e1, e2);
2620 env->tr.base |= (target_ulong)e3 << 32;
2621 } else
2622#endif
2623 {
2624 load_seg_cache_raw_dt(&env->tr, e1, e2);
2625 }
2626 e2 |= DESC_TSS_BUSY_MASK;
2627 stl_kernel(ptr + 4, e2);
2628 }
2629 env->tr.selector = selector;
2630#ifdef VBOX
2631 Log(("helper_ltr: new tr=%RTsel {.base=%RGv, .limit=%RGv, .flags=%RX32} new=%RTsel\n",
2632 (RTSEL)env->tr.selector, (RTGCPTR)env->tr.base, (RTGCPTR)env->tr.limit,
2633 env->tr.flags, (RTSEL)(selector & 0xffff)));
2634#endif
2635}
2636
2637/* only works if protected mode and not VM86. seg_reg must be != R_CS */
2638void helper_load_seg(int seg_reg, int selector)
2639{
2640 uint32_t e1, e2;
2641 int cpl, dpl, rpl;
2642 SegmentCache *dt;
2643#ifndef VBOX
2644 int index;
2645#else
2646 unsigned int index;
2647#endif
2648 target_ulong ptr;
2649
2650 selector &= 0xffff;
2651 cpl = env->hflags & HF_CPL_MASK;
2652#ifdef VBOX
2653
2654 /* Trying to load a selector with CPL=1? */
2655 if (cpl == 0 && (selector & 3) == 1 && (env->state & CPU_RAW_RING0))
2656 {
2657 Log(("RPL 1 -> sel %04X -> %04X (helper_load_seg)\n", selector, selector & 0xfffc));
2658 selector = selector & 0xfffc;
2659 }
2660#endif /* VBOX */
2661 if ((selector & 0xfffc) == 0) {
2662 /* null selector case */
2663#ifndef VBOX
2664 if (seg_reg == R_SS
2665#ifdef TARGET_X86_64
2666 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2667#endif
2668 )
2669 raise_exception_err(EXCP0D_GPF, 0);
2670 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2671#else
2672 if (seg_reg == R_SS) {
2673 if (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2674 raise_exception_err(EXCP0D_GPF, 0);
2675 e2 = (cpl << DESC_DPL_SHIFT) | DESC_INTEL_UNUSABLE;
2676 } else {
2677 e2 = DESC_INTEL_UNUSABLE;
2678 }
2679 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, e2);
2680#endif
2681 } else {
2682
2683 if (selector & 0x4)
2684 dt = &env->ldt;
2685 else
2686 dt = &env->gdt;
2687 index = selector & ~7;
2688 if ((index + 7) > dt->limit)
2689 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2690 ptr = dt->base + index;
2691 e1 = ldl_kernel(ptr);
2692 e2 = ldl_kernel(ptr + 4);
2693
2694 if (!(e2 & DESC_S_MASK))
2695 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2696 rpl = selector & 3;
2697 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2698 if (seg_reg == R_SS) {
2699 /* must be writable segment */
2700 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2701 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2702 if (rpl != cpl || dpl != cpl)
2703 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2704 } else {
2705 /* must be readable segment */
2706 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2707 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2708
2709 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2710 /* if not conforming code, test rights */
2711 if (dpl < cpl || dpl < rpl)
2712 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2713 }
2714 }
2715
2716 if (!(e2 & DESC_P_MASK)) {
2717 if (seg_reg == R_SS)
2718 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2719 else
2720 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2721 }
2722
2723 /* set the access bit if not already set */
2724 if (!(e2 & DESC_A_MASK)) {
2725 e2 |= DESC_A_MASK;
2726 stl_kernel(ptr + 4, e2);
2727 }
2728
2729 cpu_x86_load_seg_cache(env, seg_reg, selector,
2730 get_seg_base(e1, e2),
2731 get_seg_limit(e1, e2),
2732 e2);
2733#if 0
2734 qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2735 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2736#endif
2737 }
2738}
2739
2740/* protected mode jump */
2741void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2742 int next_eip_addend)
2743{
2744 int gate_cs, type;
2745 uint32_t e1, e2, cpl, dpl, rpl, limit;
2746 target_ulong next_eip;
2747
2748#ifdef VBOX /** @todo Why do we do this? */
2749 e1 = e2 = 0;
2750#endif
2751 if ((new_cs & 0xfffc) == 0)
2752 raise_exception_err(EXCP0D_GPF, 0);
2753 if (load_segment(&e1, &e2, new_cs) != 0)
2754 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2755 cpl = env->hflags & HF_CPL_MASK;
2756 if (e2 & DESC_S_MASK) {
2757 if (!(e2 & DESC_CS_MASK))
2758 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2759 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2760 if (e2 & DESC_C_MASK) {
2761 /* conforming code segment */
2762 if (dpl > cpl)
2763 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2764 } else {
2765 /* non conforming code segment */
2766 rpl = new_cs & 3;
2767 if (rpl > cpl)
2768 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2769 if (dpl != cpl)
2770 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2771 }
2772 if (!(e2 & DESC_P_MASK))
2773 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2774 limit = get_seg_limit(e1, e2);
2775 if (new_eip > limit &&
2776 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2777 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2778#ifdef VBOX
2779 if (!(e2 & DESC_A_MASK))
2780 e2 = set_segment_accessed(new_cs, e2);
2781#endif
2782 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2783 get_seg_base(e1, e2), limit, e2);
2784 EIP = new_eip;
2785 } else {
2786 /* jump to call or task gate */
2787 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2788 rpl = new_cs & 3;
2789 cpl = env->hflags & HF_CPL_MASK;
2790 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2791 switch(type) {
2792 case 1: /* 286 TSS */
2793 case 9: /* 386 TSS */
2794 case 5: /* task gate */
2795 if (dpl < cpl || dpl < rpl)
2796 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2797 next_eip = env->eip + next_eip_addend;
2798 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2799 CC_OP = CC_OP_EFLAGS;
2800 break;
2801 case 4: /* 286 call gate */
2802 case 12: /* 386 call gate */
2803 if ((dpl < cpl) || (dpl < rpl))
2804 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2805 if (!(e2 & DESC_P_MASK))
2806 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2807 gate_cs = e1 >> 16;
2808 new_eip = (e1 & 0xffff);
2809 if (type == 12)
2810 new_eip |= (e2 & 0xffff0000);
2811 if (load_segment(&e1, &e2, gate_cs) != 0)
2812 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2813 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2814 /* must be code segment */
2815 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2816 (DESC_S_MASK | DESC_CS_MASK)))
2817 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2818 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2819 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2820 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2821 if (!(e2 & DESC_P_MASK))
2822#ifdef VBOX /* See page 3-514 of 253666.pdf */
2823 raise_exception_err(EXCP0B_NOSEG, gate_cs & 0xfffc);
2824#else
2825 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2826#endif
2827 limit = get_seg_limit(e1, e2);
2828 if (new_eip > limit)
2829 raise_exception_err(EXCP0D_GPF, 0);
2830 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2831 get_seg_base(e1, e2), limit, e2);
2832 EIP = new_eip;
2833 break;
2834 default:
2835 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2836 break;
2837 }
2838 }
2839}
2840
2841/* real mode call */
2842void helper_lcall_real(int new_cs, target_ulong new_eip1,
2843 int shift, int next_eip)
2844{
2845 int new_eip;
2846 uint32_t esp, esp_mask;
2847 target_ulong ssp;
2848
2849 new_eip = new_eip1;
2850 esp = ESP;
2851 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2852 ssp = env->segs[R_SS].base;
2853 if (shift) {
2854 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2855 PUSHL(ssp, esp, esp_mask, next_eip);
2856 } else {
2857 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2858 PUSHW(ssp, esp, esp_mask, next_eip);
2859 }
2860
2861 SET_ESP(esp, esp_mask);
2862 env->eip = new_eip;
2863 env->segs[R_CS].selector = new_cs;
2864 env->segs[R_CS].base = (new_cs << 4);
2865}
2866
2867/* protected mode call */
2868void helper_lcall_protected(int new_cs, target_ulong new_eip,
2869 int shift, int next_eip_addend)
2870{
2871 int new_stack, i;
2872 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2873 uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
2874 uint32_t val, limit, old_sp_mask;
2875 target_ulong ssp, old_ssp, next_eip;
2876
2877#ifdef VBOX /** @todo Why do we do this? */
2878 e1 = e2 = 0;
2879#endif
2880 next_eip = env->eip + next_eip_addend;
2881 LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
2882 LOG_PCALL_STATE(env);
2883 if ((new_cs & 0xfffc) == 0)
2884 raise_exception_err(EXCP0D_GPF, 0);
2885 if (load_segment(&e1, &e2, new_cs) != 0)
2886 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2887 cpl = env->hflags & HF_CPL_MASK;
2888 LOG_PCALL("desc=%08x:%08x\n", e1, e2);
2889 if (e2 & DESC_S_MASK) {
2890 if (!(e2 & DESC_CS_MASK))
2891 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2892 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2893 if (e2 & DESC_C_MASK) {
2894 /* conforming code segment */
2895 if (dpl > cpl)
2896 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2897 } else {
2898 /* non conforming code segment */
2899 rpl = new_cs & 3;
2900 if (rpl > cpl)
2901 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2902 if (dpl != cpl)
2903 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2904 }
2905 if (!(e2 & DESC_P_MASK))
2906 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2907#ifdef VBOX
2908 if (!(e2 & DESC_A_MASK))
2909 e2 = set_segment_accessed(new_cs, e2);
2910#endif
2911
2912#ifdef TARGET_X86_64
2913 /* XXX: check 16/32 bit cases in long mode */
2914 if (shift == 2) {
2915 target_ulong rsp;
2916 /* 64 bit case */
2917 rsp = ESP;
2918 PUSHQ(rsp, env->segs[R_CS].selector);
2919 PUSHQ(rsp, next_eip);
2920 /* from this point, not restartable */
2921 ESP = rsp;
2922 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2923 get_seg_base(e1, e2),
2924 get_seg_limit(e1, e2), e2);
2925 EIP = new_eip;
2926 } else
2927#endif
2928 {
2929 sp = ESP;
2930 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2931 ssp = env->segs[R_SS].base;
2932 if (shift) {
2933 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2934 PUSHL(ssp, sp, sp_mask, next_eip);
2935 } else {
2936 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2937 PUSHW(ssp, sp, sp_mask, next_eip);
2938 }
2939
2940 limit = get_seg_limit(e1, e2);
2941 if (new_eip > limit)
2942 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2943 /* from this point, not restartable */
2944 SET_ESP(sp, sp_mask);
2945 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2946 get_seg_base(e1, e2), limit, e2);
2947 EIP = new_eip;
2948 }
2949 } else {
2950 /* check gate type */
2951 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2952 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2953 rpl = new_cs & 3;
2954 switch(type) {
2955 case 1: /* available 286 TSS */
2956 case 9: /* available 386 TSS */
2957 case 5: /* task gate */
2958 if (dpl < cpl || dpl < rpl)
2959 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2960 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2961 CC_OP = CC_OP_EFLAGS;
2962 return;
2963 case 4: /* 286 call gate */
2964 case 12: /* 386 call gate */
2965 break;
2966 default:
2967 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2968 break;
2969 }
2970 shift = type >> 3;
2971
2972 if (dpl < cpl || dpl < rpl)
2973 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2974 /* check valid bit */
2975 if (!(e2 & DESC_P_MASK))
2976 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2977 selector = e1 >> 16;
2978 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2979 param_count = e2 & 0x1f;
2980 if ((selector & 0xfffc) == 0)
2981 raise_exception_err(EXCP0D_GPF, 0);
2982
2983 if (load_segment(&e1, &e2, selector) != 0)
2984 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2985 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2986 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2987 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2988 if (dpl > cpl)
2989 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2990 if (!(e2 & DESC_P_MASK))
2991 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2992
2993 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2994 /* to inner privilege */
2995 get_ss_esp_from_tss(&ss, &sp, dpl);
2996 LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2997 ss, sp, param_count, ESP);
2998 if ((ss & 0xfffc) == 0)
2999 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3000 if ((ss & 3) != dpl)
3001 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3002 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
3003 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3004 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
3005 if (ss_dpl != dpl)
3006 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3007 if (!(ss_e2 & DESC_S_MASK) ||
3008 (ss_e2 & DESC_CS_MASK) ||
3009 !(ss_e2 & DESC_W_MASK))
3010 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3011 if (!(ss_e2 & DESC_P_MASK))
3012#ifdef VBOX /* See page 3-99 of 253666.pdf */
3013 raise_exception_err(EXCP0C_STACK, ss & 0xfffc);
3014#else
3015 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
3016#endif
3017
3018 // push_size = ((param_count * 2) + 8) << shift;
3019
3020 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
3021 old_ssp = env->segs[R_SS].base;
3022
3023 sp_mask = get_sp_mask(ss_e2);
3024 ssp = get_seg_base(ss_e1, ss_e2);
3025 if (shift) {
3026 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
3027 PUSHL(ssp, sp, sp_mask, ESP);
3028 for(i = param_count - 1; i >= 0; i--) {
3029 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
3030 PUSHL(ssp, sp, sp_mask, val);
3031 }
3032 } else {
3033 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
3034 PUSHW(ssp, sp, sp_mask, ESP);
3035 for(i = param_count - 1; i >= 0; i--) {
3036 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
3037 PUSHW(ssp, sp, sp_mask, val);
3038 }
3039 }
3040 new_stack = 1;
3041 } else {
3042 /* to same privilege */
3043 sp = ESP;
3044 sp_mask = get_sp_mask(env->segs[R_SS].flags);
3045 ssp = env->segs[R_SS].base;
3046 // push_size = (4 << shift);
3047 new_stack = 0;
3048 }
3049
3050 if (shift) {
3051 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
3052 PUSHL(ssp, sp, sp_mask, next_eip);
3053 } else {
3054 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
3055 PUSHW(ssp, sp, sp_mask, next_eip);
3056 }
3057
3058 /* from this point, not restartable */
3059
3060 if (new_stack) {
3061 ss = (ss & ~3) | dpl;
3062 cpu_x86_load_seg_cache(env, R_SS, ss,
3063 ssp,
3064 get_seg_limit(ss_e1, ss_e2),
3065 ss_e2);
3066 }
3067
3068 selector = (selector & ~3) | dpl;
3069 cpu_x86_load_seg_cache(env, R_CS, selector,
3070 get_seg_base(e1, e2),
3071 get_seg_limit(e1, e2),
3072 e2);
3073 cpu_x86_set_cpl(env, dpl);
3074 SET_ESP(sp, sp_mask);
3075 EIP = offset;
3076 }
3077}
3078
3079/* real and vm86 mode iret */
3080void helper_iret_real(int shift)
3081{
3082 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
3083 target_ulong ssp;
3084 int eflags_mask;
3085#ifdef VBOX
3086 bool fVME = false;
3087
3088 remR3TrapClear(env->pVM);
3089#endif /* VBOX */
3090
3091 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
3092 sp = ESP;
3093 ssp = env->segs[R_SS].base;
3094 if (shift == 1) {
3095 /* 32 bits */
3096 POPL(ssp, sp, sp_mask, new_eip);
3097 POPL(ssp, sp, sp_mask, new_cs);
3098 new_cs &= 0xffff;
3099 POPL(ssp, sp, sp_mask, new_eflags);
3100 } else {
3101 /* 16 bits */
3102 POPW(ssp, sp, sp_mask, new_eip);
3103 POPW(ssp, sp, sp_mask, new_cs);
3104 POPW(ssp, sp, sp_mask, new_eflags);
3105 }
3106#ifdef VBOX
3107 if ( (env->eflags & VM_MASK)
3108 && ((env->eflags >> IOPL_SHIFT) & 3) != 3
3109 && (env->cr[4] & CR4_VME_MASK)) /* implied or else we would fault earlier */
3110 {
3111 fVME = true;
3112 /* if virtual interrupt pending and (virtual) interrupts will be enabled -> #GP */
3113 /* if TF will be set -> #GP */
3114 if ( ((new_eflags & IF_MASK) && (env->eflags & VIP_MASK))
3115 || (new_eflags & TF_MASK))
3116 raise_exception(EXCP0D_GPF);
3117 }
3118#endif /* VBOX */
3119 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
3120 env->segs[R_CS].selector = new_cs;
3121 env->segs[R_CS].base = (new_cs << 4);
3122 env->eip = new_eip;
3123#ifdef VBOX
3124 if (fVME)
3125 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
3126 else
3127#endif
3128 if (env->eflags & VM_MASK)
3129 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
3130 else
3131 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
3132 if (shift == 0)
3133 eflags_mask &= 0xffff;
3134 load_eflags(new_eflags, eflags_mask);
3135 env->hflags2 &= ~HF2_NMI_MASK;
3136#ifdef VBOX
3137 if (fVME)
3138 {
3139 if (new_eflags & IF_MASK)
3140 env->eflags |= VIF_MASK;
3141 else
3142 env->eflags &= ~VIF_MASK;
3143 }
3144#endif /* VBOX */
3145}
3146
3147static inline void validate_seg(int seg_reg, int cpl)
3148{
3149 int dpl;
3150 uint32_t e2;
3151
3152 /* XXX: on x86_64, we do not want to nullify FS and GS because
3153 they may still contain a valid base. I would be interested to
3154 know how a real x86_64 CPU behaves */
3155 if ((seg_reg == R_FS || seg_reg == R_GS) &&
3156 (env->segs[seg_reg].selector & 0xfffc) == 0)
3157 return;
3158
3159 e2 = env->segs[seg_reg].flags;
3160 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3161 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
3162 /* data or non conforming code segment */
3163 if (dpl < cpl) {
3164 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
3165 }
3166 }
3167}
3168
3169/* protected mode iret */
3170static inline void helper_ret_protected(int shift, int is_iret, int addend)
3171{
3172 uint32_t new_cs, new_eflags, new_ss;
3173 uint32_t new_es, new_ds, new_fs, new_gs;
3174 uint32_t e1, e2, ss_e1, ss_e2;
3175 int cpl, dpl, rpl, eflags_mask, iopl;
3176 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
3177
3178#ifdef VBOX /** @todo Why do we do this? */
3179 ss_e1 = ss_e2 = e1 = e2 = 0;
3180#endif
3181
3182#ifdef TARGET_X86_64
3183 if (shift == 2)
3184 sp_mask = -1;
3185 else
3186#endif
3187 sp_mask = get_sp_mask(env->segs[R_SS].flags);
3188 sp = ESP;
3189 ssp = env->segs[R_SS].base;
3190 new_eflags = 0; /* avoid warning */
3191#ifdef TARGET_X86_64
3192 if (shift == 2) {
3193 POPQ(sp, new_eip);
3194 POPQ(sp, new_cs);
3195 new_cs &= 0xffff;
3196 if (is_iret) {
3197 POPQ(sp, new_eflags);
3198 }
3199 } else
3200#endif
3201 if (shift == 1) {
3202 /* 32 bits */
3203 POPL(ssp, sp, sp_mask, new_eip);
3204 POPL(ssp, sp, sp_mask, new_cs);
3205 new_cs &= 0xffff;
3206 if (is_iret) {
3207 POPL(ssp, sp, sp_mask, new_eflags);
3208#define LOG_GROUP LOG_GROUP_REM
3209#if defined(VBOX) && defined(DEBUG)
3210 Log(("iret: new CS %04X (old=%x)\n", new_cs, env->segs[R_CS].selector));
3211 Log(("iret: new EIP %08X\n", (uint32_t)new_eip));
3212 Log(("iret: new EFLAGS %08X\n", new_eflags));
3213 Log(("iret: EAX=%08x\n", (uint32_t)EAX));
3214#endif
3215 if (new_eflags & VM_MASK)
3216 goto return_to_vm86;
3217 }
3218#ifdef VBOX
3219 if ((new_cs & 0x3) == 1 && (env->state & CPU_RAW_RING0))
3220 {
3221 if ( !EMIsRawRing1Enabled(env->pVM)
3222 || env->segs[R_CS].selector == (new_cs & 0xfffc))
3223 {
3224 Log(("RPL 1 -> new_cs %04X -> %04X\n", new_cs, new_cs & 0xfffc));
3225 new_cs = new_cs & 0xfffc;
3226 }
3227 else
3228 {
3229 /* Ugly assumption: assume a genuine switch to ring-1. */
3230 Log(("Genuine switch to ring-1 (iret)\n"));
3231 }
3232 }
3233 else if ((new_cs & 0x3) == 2 && (env->state & CPU_RAW_RING0) && EMIsRawRing1Enabled(env->pVM))
3234 {
3235 Log(("RPL 2 -> new_cs %04X -> %04X\n", new_cs, (new_cs & 0xfffc) | 1));
3236 new_cs = (new_cs & 0xfffc) | 1;
3237 }
3238#endif
3239 } else {
3240 /* 16 bits */
3241 POPW(ssp, sp, sp_mask, new_eip);
3242 POPW(ssp, sp, sp_mask, new_cs);
3243 if (is_iret)
3244 POPW(ssp, sp, sp_mask, new_eflags);
3245 }
3246 LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
3247 new_cs, new_eip, shift, addend);
3248 LOG_PCALL_STATE(env);
3249 if ((new_cs & 0xfffc) == 0)
3250 {
3251#if defined(VBOX) && defined(DEBUG)
3252 Log(("new_cs & 0xfffc) == 0\n"));
3253#endif
3254 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3255 }
3256 if (load_segment(&e1, &e2, new_cs) != 0)
3257 {
3258#if defined(VBOX) && defined(DEBUG)
3259 Log(("load_segment failed\n"));
3260#endif
3261 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3262 }
3263 if (!(e2 & DESC_S_MASK) ||
3264 !(e2 & DESC_CS_MASK))
3265 {
3266#if defined(VBOX) && defined(DEBUG)
3267 Log(("e2 mask %08x\n", e2));
3268#endif
3269 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3270 }
3271 cpl = env->hflags & HF_CPL_MASK;
3272 rpl = new_cs & 3;
3273 if (rpl < cpl)
3274 {
3275#if defined(VBOX) && defined(DEBUG)
3276 Log(("rpl < cpl (%d vs %d)\n", rpl, cpl));
3277#endif
3278 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3279 }
3280 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3281
3282 if (e2 & DESC_C_MASK) {
3283 if (dpl > rpl)
3284 {
3285#if defined(VBOX) && defined(DEBUG)
3286 Log(("dpl > rpl (%d vs %d)\n", dpl, rpl));
3287#endif
3288 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3289 }
3290 } else {
3291 if (dpl != rpl)
3292 {
3293#if defined(VBOX) && defined(DEBUG)
3294 Log(("dpl != rpl (%d vs %d) e1=%x e2=%x\n", dpl, rpl, e1, e2));
3295#endif
3296 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
3297 }
3298 }
3299 if (!(e2 & DESC_P_MASK))
3300 {
3301#if defined(VBOX) && defined(DEBUG)
3302 Log(("DESC_P_MASK e2=%08x\n", e2));
3303#endif
3304 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
3305 }
3306
3307 sp += addend;
3308 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
3309 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
3310 /* return to same privilege level */
3311#ifdef VBOX
3312 if (!(e2 & DESC_A_MASK))
3313 e2 = set_segment_accessed(new_cs, e2);
3314#endif
3315 cpu_x86_load_seg_cache(env, R_CS, new_cs,
3316 get_seg_base(e1, e2),
3317 get_seg_limit(e1, e2),
3318 e2);
3319 } else {
3320 /* return to different privilege level */
3321#ifdef TARGET_X86_64
3322 if (shift == 2) {
3323 POPQ(sp, new_esp);
3324 POPQ(sp, new_ss);
3325 new_ss &= 0xffff;
3326 } else
3327#endif
3328 if (shift == 1) {
3329 /* 32 bits */
3330 POPL(ssp, sp, sp_mask, new_esp);
3331 POPL(ssp, sp, sp_mask, new_ss);
3332 new_ss &= 0xffff;
3333 } else {
3334 /* 16 bits */
3335 POPW(ssp, sp, sp_mask, new_esp);
3336 POPW(ssp, sp, sp_mask, new_ss);
3337 }
3338 LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
3339 new_ss, new_esp);
3340 if ((new_ss & 0xfffc) == 0) {
3341#ifdef TARGET_X86_64
3342 /* NULL ss is allowed in long mode if cpl != 3*/
3343# ifndef VBOX
3344 /* XXX: test CS64 ? */
3345 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
3346 cpu_x86_load_seg_cache(env, R_SS, new_ss,
3347 0, 0xffffffff,
3348 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3349 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
3350 DESC_W_MASK | DESC_A_MASK);
3351 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
3352 } else
3353# else /* VBOX */
3354 if ((env->hflags & HF_LMA_MASK) && rpl != 3 && (e2 & DESC_L_MASK)) {
3355 if (!(e2 & DESC_A_MASK))
3356 e2 = set_segment_accessed(new_cs, e2);
3357 cpu_x86_load_seg_cache(env, R_SS, new_ss,
3358 0, 0xffffffff,
3359 DESC_INTEL_UNUSABLE | (rpl << DESC_DPL_SHIFT) );
3360 ss_e2 = DESC_B_MASK; /* not really used */
3361 } else
3362# endif
3363#endif
3364 {
3365#if defined(VBOX) && defined(DEBUG)
3366 Log(("NULL ss, rpl=%d\n", rpl));
3367#endif
3368 raise_exception_err(EXCP0D_GPF, 0);
3369 }
3370 } else {
3371 if ((new_ss & 3) != rpl)
3372 {
3373#if defined(VBOX) && defined(DEBUG)
3374 Log(("new_ss=%x != rpl=%d\n", new_ss, rpl));
3375#endif
3376 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
3377 }
3378 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
3379 {
3380#if defined(VBOX) && defined(DEBUG)
3381 Log(("new_ss=%x load error\n", new_ss));
3382#endif
3383 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
3384 }
3385 if (!(ss_e2 & DESC_S_MASK) ||
3386 (ss_e2 & DESC_CS_MASK) ||
3387 !(ss_e2 & DESC_W_MASK))
3388 {
3389#if defined(VBOX) && defined(DEBUG)
3390 Log(("new_ss=%x ss_e2=%#x bad type\n", new_ss, ss_e2));
3391#endif
3392 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
3393 }
3394 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
3395 if (dpl != rpl)
3396 {
3397#if defined(VBOX) && defined(DEBUG)
3398 Log(("SS.dpl=%u != rpl=%u\n", dpl, rpl));
3399#endif
3400 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
3401 }
3402 if (!(ss_e2 & DESC_P_MASK))
3403 {
3404#if defined(VBOX) && defined(DEBUG)
3405 Log(("new_ss=%#x #NP\n", new_ss));
3406#endif
3407 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
3408 }
3409#ifdef VBOX
3410 if (!(e2 & DESC_A_MASK))
3411 e2 = set_segment_accessed(new_cs, e2);
3412 if (!(ss_e2 & DESC_A_MASK))
3413 ss_e2 = set_segment_accessed(new_ss, ss_e2);
3414#endif
3415 cpu_x86_load_seg_cache(env, R_SS, new_ss,
3416 get_seg_base(ss_e1, ss_e2),
3417 get_seg_limit(ss_e1, ss_e2),
3418 ss_e2);
3419 }
3420
3421 cpu_x86_load_seg_cache(env, R_CS, new_cs,
3422 get_seg_base(e1, e2),
3423 get_seg_limit(e1, e2),
3424 e2);
3425 cpu_x86_set_cpl(env, rpl);
3426 sp = new_esp;
3427#ifdef TARGET_X86_64
3428 if (env->hflags & HF_CS64_MASK)
3429 sp_mask = -1;
3430 else
3431#endif
3432 sp_mask = get_sp_mask(ss_e2);
3433
3434 /* validate data segments */
3435 validate_seg(R_ES, rpl);
3436 validate_seg(R_DS, rpl);
3437 validate_seg(R_FS, rpl);
3438 validate_seg(R_GS, rpl);
3439
3440 sp += addend;
3441 }
3442 SET_ESP(sp, sp_mask);
3443 env->eip = new_eip;
3444 if (is_iret) {
3445 /* NOTE: 'cpl' is the _old_ CPL */
3446 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
3447 if (cpl == 0)
3448#ifdef VBOX
3449 eflags_mask |= IOPL_MASK | VIF_MASK | VIP_MASK;
3450#else
3451 eflags_mask |= IOPL_MASK;
3452#endif
3453 iopl = (env->eflags >> IOPL_SHIFT) & 3;
3454 if (cpl <= iopl)
3455 eflags_mask |= IF_MASK;
3456 if (shift == 0)
3457 eflags_mask &= 0xffff;
3458 load_eflags(new_eflags, eflags_mask);
3459 }
3460 return;
3461
3462 return_to_vm86:
3463 POPL(ssp, sp, sp_mask, new_esp);
3464 POPL(ssp, sp, sp_mask, new_ss);
3465 POPL(ssp, sp, sp_mask, new_es);
3466 POPL(ssp, sp, sp_mask, new_ds);
3467 POPL(ssp, sp, sp_mask, new_fs);
3468 POPL(ssp, sp, sp_mask, new_gs);
3469
3470 /* modify processor state */
3471 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
3472 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
3473 load_seg_vm(R_CS, new_cs & 0xffff);
3474 cpu_x86_set_cpl(env, 3);
3475 load_seg_vm(R_SS, new_ss & 0xffff);
3476 load_seg_vm(R_ES, new_es & 0xffff);
3477 load_seg_vm(R_DS, new_ds & 0xffff);
3478 load_seg_vm(R_FS, new_fs & 0xffff);
3479 load_seg_vm(R_GS, new_gs & 0xffff);
3480
3481 env->eip = new_eip & 0xffff;
3482 ESP = new_esp;
3483}
3484
3485void helper_iret_protected(int shift, int next_eip)
3486{
3487 int tss_selector, type;
3488 uint32_t e1, e2;
3489
3490#ifdef VBOX
3491 Log(("iret (shift=%d new_eip=%#x)\n", shift, next_eip));
3492 e1 = e2 = 0; /** @todo Why do we do this? */
3493 remR3TrapClear(env->pVM);
3494#endif
3495
3496 /* specific case for TSS */
3497 if (env->eflags & NT_MASK) {
3498#ifdef TARGET_X86_64
3499 if (env->hflags & HF_LMA_MASK)
3500 {
3501#if defined(VBOX) && defined(DEBUG)
3502 Log(("eflags.NT=1 on iret in long mode\n"));
3503#endif
3504 raise_exception_err(EXCP0D_GPF, 0);
3505 }
3506#endif
3507 tss_selector = lduw_kernel(env->tr.base + 0);
3508 if (tss_selector & 4)
3509 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
3510 if (load_segment(&e1, &e2, tss_selector) != 0)
3511 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
3512 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
3513 /* NOTE: we check both segment and busy TSS */
3514 if (type != 3)
3515 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
3516 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
3517 } else {
3518 helper_ret_protected(shift, 1, 0);
3519 }
3520 env->hflags2 &= ~HF2_NMI_MASK;
3521}
3522
3523void helper_lret_protected(int shift, int addend)
3524{
3525 helper_ret_protected(shift, 0, addend);
3526}
3527
3528void helper_sysenter(void)
3529{
3530 if (env->sysenter_cs == 0) {
3531 raise_exception_err(EXCP0D_GPF, 0);
3532 }
3533 env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
3534 cpu_x86_set_cpl(env, 0);
3535
3536#ifdef TARGET_X86_64
3537 if (env->hflags & HF_LMA_MASK) {
3538 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
3539 0, 0xffffffff,
3540 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3541 DESC_S_MASK |
3542 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
3543 } else
3544#endif
3545 {
3546 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
3547 0, 0xffffffff,
3548 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3549 DESC_S_MASK |
3550 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
3551 }
3552 cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
3553 0, 0xffffffff,
3554 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3555 DESC_S_MASK |
3556 DESC_W_MASK | DESC_A_MASK);
3557 ESP = env->sysenter_esp;
3558 EIP = env->sysenter_eip;
3559}
3560
3561void helper_sysexit(int dflag)
3562{
3563 int cpl;
3564
3565 cpl = env->hflags & HF_CPL_MASK;
3566 if (env->sysenter_cs == 0 || cpl != 0) {
3567 raise_exception_err(EXCP0D_GPF, 0);
3568 }
3569 cpu_x86_set_cpl(env, 3);
3570#ifdef TARGET_X86_64
3571 if (dflag == 2) {
3572 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
3573 0, 0xffffffff,
3574 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3575 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3576 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
3577 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
3578 0, 0xffffffff,
3579 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3580 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3581 DESC_W_MASK | DESC_A_MASK);
3582 } else
3583#endif
3584 {
3585 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
3586 0, 0xffffffff,
3587 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3588 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3589 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
3590 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
3591 0, 0xffffffff,
3592 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
3593 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
3594 DESC_W_MASK | DESC_A_MASK);
3595 }
3596 ESP = ECX;
3597 EIP = EDX;
3598}
3599
3600#if defined(CONFIG_USER_ONLY)
3601target_ulong helper_read_crN(int reg)
3602{
3603 return 0;
3604}
3605
3606void helper_write_crN(int reg, target_ulong t0)
3607{
3608}
3609
3610void helper_movl_drN_T0(int reg, target_ulong t0)
3611{
3612}
3613#else
3614target_ulong helper_read_crN(int reg)
3615{
3616 target_ulong val;
3617
3618 helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
3619 switch(reg) {
3620 default:
3621 val = env->cr[reg];
3622 break;
3623 case 8:
3624 if (!(env->hflags2 & HF2_VINTR_MASK)) {
3625#ifndef VBOX
3626 val = cpu_get_apic_tpr(env->apic_state);
3627#else /* VBOX */
3628 val = cpu_get_apic_tpr(env);
3629#endif /* VBOX */
3630 } else {
3631 val = env->v_tpr;
3632 }
3633 break;
3634 }
3635 return val;
3636}
3637
3638void helper_write_crN(int reg, target_ulong t0)
3639{
3640 helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
3641 switch(reg) {
3642 case 0:
3643 cpu_x86_update_cr0(env, t0);
3644 break;
3645 case 3:
3646 cpu_x86_update_cr3(env, t0);
3647 break;
3648 case 4:
3649 cpu_x86_update_cr4(env, t0);
3650 break;
3651 case 8:
3652 if (!(env->hflags2 & HF2_VINTR_MASK)) {
3653#ifndef VBOX
3654 cpu_set_apic_tpr(env->apic_state, t0);
3655#else /* VBOX */
3656 cpu_set_apic_tpr(env, t0);
3657#endif /* VBOX */
3658 }
3659 env->v_tpr = t0 & 0x0f;
3660 break;
3661 default:
3662 env->cr[reg] = t0;
3663 break;
3664 }
3665}
3666
3667void helper_movl_drN_T0(int reg, target_ulong t0)
3668{
3669 int i;
3670
3671 if (reg < 4) {
3672 hw_breakpoint_remove(env, reg);
3673 env->dr[reg] = t0;
3674 hw_breakpoint_insert(env, reg);
3675# ifndef VBOX
3676 } else if (reg == 7) {
3677# else
3678 } else if (reg == 7 || reg == 5) { /* (DR5 is an alias for DR7.) */
3679 if (t0 & X86_DR7_MBZ_MASK)
3680 raise_exception_err(EXCP0D_GPF, 0);
3681 t0 |= X86_DR7_RA1_MASK;
3682 t0 &= ~X86_DR7_RAZ_MASK;
3683# endif
3684 for (i = 0; i < 4; i++)
3685 hw_breakpoint_remove(env, i);
3686 env->dr[7] = t0;
3687 for (i = 0; i < 4; i++)
3688 hw_breakpoint_insert(env, i);
3689 } else {
3690# ifndef VBOX
3691 env->dr[reg] = t0;
3692# else
3693 if (t0 & X86_DR6_MBZ_MASK)
3694 raise_exception_err(EXCP0D_GPF, 0);
3695 t0 |= X86_DR6_RA1_MASK;
3696 t0 &= ~X86_DR6_RAZ_MASK;
3697 env->dr[6] = t0; /* (DR4 is an alias for DR6.) */
3698# endif
3699 }
3700}
3701#endif
3702
3703void helper_lmsw(target_ulong t0)
3704{
3705 /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
3706 if already set to one. */
3707 t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
3708 helper_write_crN(0, t0);
3709}
3710
3711void helper_clts(void)
3712{
3713 env->cr[0] &= ~CR0_TS_MASK;
3714 env->hflags &= ~HF_TS_MASK;
3715}
3716
3717void helper_invlpg(target_ulong addr)
3718{
3719 helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
3720 tlb_flush_page(env, addr);
3721}
3722
3723void helper_rdtsc(void)
3724{
3725 uint64_t val;
3726
3727 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
3728 raise_exception(EXCP0D_GPF);
3729 }
3730 helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
3731
3732 val = cpu_get_tsc(env) + env->tsc_offset;
3733 EAX = (uint32_t)(val);
3734 EDX = (uint32_t)(val >> 32);
3735}
3736
3737void helper_rdtscp(void)
3738{
3739 helper_rdtsc();
3740#ifndef VBOX
3741 ECX = (uint32_t)(env->tsc_aux);
3742#else /* VBOX */
3743 uint64_t val;
3744 if (cpu_rdmsr(env, MSR_K8_TSC_AUX, &val) == 0)
3745 ECX = (uint32_t)(val);
3746 else
3747 ECX = 0;
3748#endif /* VBOX */
3749}
3750
3751void helper_rdpmc(void)
3752{
3753#ifdef VBOX
3754 /* If X86_CR4_PCE is *not* set, then CPL must be zero. */
3755 if (!(env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
3756 raise_exception(EXCP0D_GPF);
3757 }
3758 /* Just return zero here; rather tricky to properly emulate this, especially as the specs are a mess. */
3759 EAX = 0;
3760 EDX = 0;
3761#else /* !VBOX */
3762 if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
3763 raise_exception(EXCP0D_GPF);
3764 }
3765 helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
3766
3767 /* currently unimplemented */
3768 raise_exception_err(EXCP06_ILLOP, 0);
3769#endif /* !VBOX */
3770}
3771
3772#if defined(CONFIG_USER_ONLY)
3773void helper_wrmsr(void)
3774{
3775}
3776
3777void helper_rdmsr(void)
3778{
3779}
3780#else
3781void helper_wrmsr(void)
3782{
3783 uint64_t val;
3784
3785 helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
3786
3787 val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
3788
3789 switch((uint32_t)ECX) {
3790 case MSR_IA32_SYSENTER_CS:
3791 env->sysenter_cs = val & 0xffff;
3792 break;
3793 case MSR_IA32_SYSENTER_ESP:
3794 env->sysenter_esp = val;
3795 break;
3796 case MSR_IA32_SYSENTER_EIP:
3797 env->sysenter_eip = val;
3798 break;
3799 case MSR_IA32_APICBASE:
3800# ifndef VBOX /* The CPUMSetGuestMsr call below does this now. */
3801 cpu_set_apic_base(env->apic_state, val);
3802# endif
3803 break;
3804 case MSR_EFER:
3805 {
3806 uint64_t update_mask;
3807 update_mask = 0;
3808 if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3809 update_mask |= MSR_EFER_SCE;
3810 if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3811 update_mask |= MSR_EFER_LME;
3812 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3813 update_mask |= MSR_EFER_FFXSR;
3814 if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3815 update_mask |= MSR_EFER_NXE;
3816 if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
3817 update_mask |= MSR_EFER_SVME;
3818 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3819 update_mask |= MSR_EFER_FFXSR;
3820 cpu_load_efer(env, (env->efer & ~update_mask) |
3821 (val & update_mask));
3822 }
3823 break;
3824 case MSR_STAR:
3825 env->star = val;
3826 break;
3827 case MSR_PAT:
3828 env->pat = val;
3829 break;
3830 case MSR_VM_HSAVE_PA:
3831 env->vm_hsave = val;
3832 break;
3833#ifdef TARGET_X86_64
3834 case MSR_LSTAR:
3835 env->lstar = val;
3836 break;
3837 case MSR_CSTAR:
3838 env->cstar = val;
3839 break;
3840 case MSR_FMASK:
3841 env->fmask = val;
3842 break;
3843 case MSR_FSBASE:
3844 env->segs[R_FS].base = val;
3845 break;
3846 case MSR_GSBASE:
3847 env->segs[R_GS].base = val;
3848 break;
3849 case MSR_KERNELGSBASE:
3850 env->kernelgsbase = val;
3851 break;
3852#endif
3853# ifndef VBOX
3854 case MSR_MTRRphysBase(0):
3855 case MSR_MTRRphysBase(1):
3856 case MSR_MTRRphysBase(2):
3857 case MSR_MTRRphysBase(3):
3858 case MSR_MTRRphysBase(4):
3859 case MSR_MTRRphysBase(5):
3860 case MSR_MTRRphysBase(6):
3861 case MSR_MTRRphysBase(7):
3862 env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
3863 break;
3864 case MSR_MTRRphysMask(0):
3865 case MSR_MTRRphysMask(1):
3866 case MSR_MTRRphysMask(2):
3867 case MSR_MTRRphysMask(3):
3868 case MSR_MTRRphysMask(4):
3869 case MSR_MTRRphysMask(5):
3870 case MSR_MTRRphysMask(6):
3871 case MSR_MTRRphysMask(7):
3872 env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
3873 break;
3874 case MSR_MTRRfix64K_00000:
3875 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
3876 break;
3877 case MSR_MTRRfix16K_80000:
3878 case MSR_MTRRfix16K_A0000:
3879 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
3880 break;
3881 case MSR_MTRRfix4K_C0000:
3882 case MSR_MTRRfix4K_C8000:
3883 case MSR_MTRRfix4K_D0000:
3884 case MSR_MTRRfix4K_D8000:
3885 case MSR_MTRRfix4K_E0000:
3886 case MSR_MTRRfix4K_E8000:
3887 case MSR_MTRRfix4K_F0000:
3888 case MSR_MTRRfix4K_F8000:
3889 env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
3890 break;
3891 case MSR_MTRRdefType:
3892 env->mtrr_deftype = val;
3893 break;
3894 case MSR_MCG_STATUS:
3895 env->mcg_status = val;
3896 break;
3897 case MSR_MCG_CTL:
3898 if ((env->mcg_cap & MCG_CTL_P)
3899 && (val == 0 || val == ~(uint64_t)0))
3900 env->mcg_ctl = val;
3901 break;
3902 case MSR_TSC_AUX:
3903 env->tsc_aux = val;
3904 break;
3905# endif /* !VBOX */
3906 default:
3907# ifndef VBOX
3908 if ((uint32_t)ECX >= MSR_MC0_CTL
3909 && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
3910 uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
3911 if ((offset & 0x3) != 0
3912 || (val == 0 || val == ~(uint64_t)0))
3913 env->mce_banks[offset] = val;
3914 break;
3915 }
3916 /* XXX: exception ? */
3917# endif
3918 break;
3919 }
3920
3921# ifdef VBOX
3922 /* call CPUM. */
3923 if (cpu_wrmsr(env, (uint32_t)ECX, val) != 0)
3924 {
3925 /** @todo be a brave man and raise a \#GP(0) here as we should... */
3926 }
3927# endif
3928}
3929
3930void helper_rdmsr(void)
3931{
3932 uint64_t val;
3933
3934 helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3935
3936 switch((uint32_t)ECX) {
3937 case MSR_IA32_SYSENTER_CS:
3938 val = env->sysenter_cs;
3939 break;
3940 case MSR_IA32_SYSENTER_ESP:
3941 val = env->sysenter_esp;
3942 break;
3943 case MSR_IA32_SYSENTER_EIP:
3944 val = env->sysenter_eip;
3945 break;
3946 case MSR_IA32_APICBASE:
3947#ifndef VBOX
3948 val = cpu_get_apic_base(env->apic_state);
3949#else /* VBOX */
3950 val = cpu_get_apic_base(env);
3951#endif /* VBOX */
3952 break;
3953 case MSR_EFER:
3954 val = env->efer;
3955 break;
3956 case MSR_STAR:
3957 val = env->star;
3958 break;
3959 case MSR_PAT:
3960 val = env->pat;
3961 break;
3962 case MSR_VM_HSAVE_PA:
3963 val = env->vm_hsave;
3964 break;
3965# ifndef VBOX /* forward to CPUMQueryGuestMsr. */
3966 case MSR_IA32_PERF_STATUS:
3967 /* tsc_increment_by_tick */
3968 val = 1000ULL;
3969 /* CPU multiplier */
3970 val |= (((uint64_t)4ULL) << 40);
3971 break;
3972# endif /* !VBOX */
3973#ifdef TARGET_X86_64
3974 case MSR_LSTAR:
3975 val = env->lstar;
3976 break;
3977 case MSR_CSTAR:
3978 val = env->cstar;
3979 break;
3980 case MSR_FMASK:
3981 val = env->fmask;
3982 break;
3983 case MSR_FSBASE:
3984 val = env->segs[R_FS].base;
3985 break;
3986 case MSR_GSBASE:
3987 val = env->segs[R_GS].base;
3988 break;
3989 case MSR_KERNELGSBASE:
3990 val = env->kernelgsbase;
3991 break;
3992# ifndef VBOX
3993 case MSR_TSC_AUX:
3994 val = env->tsc_aux;
3995 break;
3996# endif /*!VBOX*/
3997#endif
3998# ifndef VBOX
3999 case MSR_MTRRphysBase(0):
4000 case MSR_MTRRphysBase(1):
4001 case MSR_MTRRphysBase(2):
4002 case MSR_MTRRphysBase(3):
4003 case MSR_MTRRphysBase(4):
4004 case MSR_MTRRphysBase(5):
4005 case MSR_MTRRphysBase(6):
4006 case MSR_MTRRphysBase(7):
4007 val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
4008 break;
4009 case MSR_MTRRphysMask(0):
4010 case MSR_MTRRphysMask(1):
4011 case MSR_MTRRphysMask(2):
4012 case MSR_MTRRphysMask(3):
4013 case MSR_MTRRphysMask(4):
4014 case MSR_MTRRphysMask(5):
4015 case MSR_MTRRphysMask(6):
4016 case MSR_MTRRphysMask(7):
4017 val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
4018 break;
4019 case MSR_MTRRfix64K_00000:
4020 val = env->mtrr_fixed[0];
4021 break;
4022 case MSR_MTRRfix16K_80000:
4023 case MSR_MTRRfix16K_A0000:
4024 val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
4025 break;
4026 case MSR_MTRRfix4K_C0000:
4027 case MSR_MTRRfix4K_C8000:
4028 case MSR_MTRRfix4K_D0000:
4029 case MSR_MTRRfix4K_D8000:
4030 case MSR_MTRRfix4K_E0000:
4031 case MSR_MTRRfix4K_E8000:
4032 case MSR_MTRRfix4K_F0000:
4033 case MSR_MTRRfix4K_F8000:
4034 val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
4035 break;
4036 case MSR_MTRRdefType:
4037 val = env->mtrr_deftype;
4038 break;
4039 case MSR_MTRRcap:
4040 if (env->cpuid_features & CPUID_MTRR)
4041 val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
4042 else
4043 /* XXX: exception ? */
4044 val = 0;
4045 break;
4046 case MSR_MCG_CAP:
4047 val = env->mcg_cap;
4048 break;
4049 case MSR_MCG_CTL:
4050 if (env->mcg_cap & MCG_CTL_P)
4051 val = env->mcg_ctl;
4052 else
4053 val = 0;
4054 break;
4055 case MSR_MCG_STATUS:
4056 val = env->mcg_status;
4057 break;
4058# endif /* !VBOX */
4059 default:
4060# ifndef VBOX
4061 if ((uint32_t)ECX >= MSR_MC0_CTL
4062 && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
4063 uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
4064 val = env->mce_banks[offset];
4065 break;
4066 }
4067 /* XXX: exception ? */
4068 val = 0;
4069# else /* VBOX */
4070 if (cpu_rdmsr(env, (uint32_t)ECX, &val) != 0)
4071 {
4072 /** @todo be a brave man and raise a \#GP(0) here as we should... */
4073 val = 0;
4074 }
4075# endif /* VBOX */
4076 break;
4077 }
4078 EAX = (uint32_t)(val);
4079 EDX = (uint32_t)(val >> 32);
4080
4081# ifdef VBOX_STRICT
4082 if ((uint32_t)ECX != MSR_IA32_TSC) {
4083 if (cpu_rdmsr(env, (uint32_t)ECX, &val) != 0)
4084 val = 0;
4085 AssertMsg(val == RT_MAKE_U64(EAX, EDX), ("idMsr=%#x val=%#llx eax:edx=%#llx\n", (uint32_t)ECX, val, RT_MAKE_U64(EAX, EDX)));
4086 }
4087# endif
4088}
4089#endif
4090
4091target_ulong helper_lsl(target_ulong selector1)
4092{
4093 unsigned int limit;
4094 uint32_t e1, e2, eflags, selector;
4095 int rpl, dpl, cpl, type;
4096
4097 selector = selector1 & 0xffff;
4098 eflags = helper_cc_compute_all(CC_OP);
4099 if ((selector & 0xfffc) == 0)
4100 goto fail;
4101 if (load_segment(&e1, &e2, selector) != 0)
4102 goto fail;
4103 rpl = selector & 3;
4104 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
4105 cpl = env->hflags & HF_CPL_MASK;
4106 if (e2 & DESC_S_MASK) {
4107 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
4108 /* conforming */
4109 } else {
4110 if (dpl < cpl || dpl < rpl)
4111 goto fail;
4112 }
4113 } else {
4114 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
4115 switch(type) {
4116 case 1:
4117 case 2:
4118 case 3:
4119 case 9:
4120 case 11:
4121 break;
4122 default:
4123 goto fail;
4124 }
4125 if (dpl < cpl || dpl < rpl) {
4126 fail:
4127 CC_SRC = eflags & ~CC_Z;
4128 return 0;
4129 }
4130 }
4131 limit = get_seg_limit(e1, e2);
4132 CC_SRC = eflags | CC_Z;
4133 return limit;
4134}
4135
4136target_ulong helper_lar(target_ulong selector1)
4137{
4138 uint32_t e1, e2, eflags, selector;
4139 int rpl, dpl, cpl, type;
4140
4141 selector = selector1 & 0xffff;
4142 eflags = helper_cc_compute_all(CC_OP);
4143 if ((selector & 0xfffc) == 0)
4144 goto fail;
4145 if (load_segment(&e1, &e2, selector) != 0)
4146 goto fail;
4147 rpl = selector & 3;
4148 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
4149 cpl = env->hflags & HF_CPL_MASK;
4150 if (e2 & DESC_S_MASK) {
4151 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
4152 /* conforming */
4153 } else {
4154 if (dpl < cpl || dpl < rpl)
4155 goto fail;
4156 }
4157 } else {
4158 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
4159 switch(type) {
4160 case 1:
4161 case 2:
4162 case 3:
4163 case 4:
4164 case 5:
4165 case 9:
4166 case 11:
4167 case 12:
4168 break;
4169 default:
4170 goto fail;
4171 }
4172 if (dpl < cpl || dpl < rpl) {
4173 fail:
4174 CC_SRC = eflags & ~CC_Z;
4175 return 0;
4176 }
4177 }
4178 CC_SRC = eflags | CC_Z;
4179 return e2 & 0x00f0ff00;
4180}
4181
4182void helper_verr(target_ulong selector1)
4183{
4184 uint32_t e1, e2, eflags, selector;
4185 int rpl, dpl, cpl;
4186
4187 selector = selector1 & 0xffff;
4188 eflags = helper_cc_compute_all(CC_OP);
4189 if ((selector & 0xfffc) == 0)
4190 goto fail;
4191 if (load_segment(&e1, &e2, selector) != 0)
4192 goto fail;
4193 if (!(e2 & DESC_S_MASK))
4194 goto fail;
4195 rpl = selector & 3;
4196 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
4197 cpl = env->hflags & HF_CPL_MASK;
4198 if (e2 & DESC_CS_MASK) {
4199 if (!(e2 & DESC_R_MASK))
4200 goto fail;
4201 if (!(e2 & DESC_C_MASK)) {
4202 if (dpl < cpl || dpl < rpl)
4203 goto fail;
4204 }
4205 } else {
4206 if (dpl < cpl || dpl < rpl) {
4207 fail:
4208 CC_SRC = eflags & ~CC_Z;
4209 return;
4210 }
4211 }
4212 CC_SRC = eflags | CC_Z;
4213}
4214
4215void helper_verw(target_ulong selector1)
4216{
4217 uint32_t e1, e2, eflags, selector;
4218 int rpl, dpl, cpl;
4219
4220 selector = selector1 & 0xffff;
4221 eflags = helper_cc_compute_all(CC_OP);
4222 if ((selector & 0xfffc) == 0)
4223 goto fail;
4224 if (load_segment(&e1, &e2, selector) != 0)
4225 goto fail;
4226 if (!(e2 & DESC_S_MASK))
4227 goto fail;
4228 rpl = selector & 3;
4229 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
4230 cpl = env->hflags & HF_CPL_MASK;
4231 if (e2 & DESC_CS_MASK) {
4232 goto fail;
4233 } else {
4234 if (dpl < cpl || dpl < rpl)
4235 goto fail;
4236 if (!(e2 & DESC_W_MASK)) {
4237 fail:
4238 CC_SRC = eflags & ~CC_Z;
4239 return;
4240 }
4241 }
4242 CC_SRC = eflags | CC_Z;
4243}
4244
4245/* x87 FPU helpers */
4246
4247static void fpu_set_exception(int mask)
4248{
4249 env->fpus |= mask;
4250 if (env->fpus & (~env->fpuc & FPUC_EM))
4251 env->fpus |= FPUS_SE | FPUS_B;
4252}
4253
4254static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
4255{
4256 if (b == 0.0)
4257 fpu_set_exception(FPUS_ZE);
4258 return a / b;
4259}
4260
4261static void fpu_raise_exception(void)
4262{
4263 if (env->cr[0] & CR0_NE_MASK) {
4264 raise_exception(EXCP10_COPR);
4265 }
4266#if !defined(CONFIG_USER_ONLY)
4267 else {
4268 cpu_set_ferr(env);
4269 }
4270#endif
4271}
4272
4273void helper_flds_FT0(uint32_t val)
4274{
4275 union {
4276 float32 f;
4277 uint32_t i;
4278 } u;
4279 u.i = val;
4280 FT0 = float32_to_floatx(u.f, &env->fp_status);
4281}
4282
4283void helper_fldl_FT0(uint64_t val)
4284{
4285 union {
4286 float64 f;
4287 uint64_t i;
4288 } u;
4289 u.i = val;
4290 FT0 = float64_to_floatx(u.f, &env->fp_status);
4291}
4292
4293void helper_fildl_FT0(int32_t val)
4294{
4295 FT0 = int32_to_floatx(val, &env->fp_status);
4296}
4297
4298void helper_flds_ST0(uint32_t val)
4299{
4300 int new_fpstt;
4301 union {
4302 float32 f;
4303 uint32_t i;
4304 } u;
4305 new_fpstt = (env->fpstt - 1) & 7;
4306 u.i = val;
4307 env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
4308 env->fpstt = new_fpstt;
4309 env->fptags[new_fpstt] = 0; /* validate stack entry */
4310}
4311
4312void helper_fldl_ST0(uint64_t val)
4313{
4314 int new_fpstt;
4315 union {
4316 float64 f;
4317 uint64_t i;
4318 } u;
4319 new_fpstt = (env->fpstt - 1) & 7;
4320 u.i = val;
4321 env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
4322 env->fpstt = new_fpstt;
4323 env->fptags[new_fpstt] = 0; /* validate stack entry */
4324}
4325
4326void helper_fildl_ST0(int32_t val)
4327{
4328 int new_fpstt;
4329 new_fpstt = (env->fpstt - 1) & 7;
4330 env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
4331 env->fpstt = new_fpstt;
4332 env->fptags[new_fpstt] = 0; /* validate stack entry */
4333}
4334
4335void helper_fildll_ST0(int64_t val)
4336{
4337 int new_fpstt;
4338 new_fpstt = (env->fpstt - 1) & 7;
4339 env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
4340 env->fpstt = new_fpstt;
4341 env->fptags[new_fpstt] = 0; /* validate stack entry */
4342}
4343
4344#ifndef VBOX
4345uint32_t helper_fsts_ST0(void)
4346#else
4347RTCCUINTREG helper_fsts_ST0(void)
4348#endif
4349{
4350 union {
4351 float32 f;
4352 uint32_t i;
4353 } u;
4354 u.f = floatx_to_float32(ST0, &env->fp_status);
4355 return u.i;
4356}
4357
4358uint64_t helper_fstl_ST0(void)
4359{
4360 union {
4361 float64 f;
4362 uint64_t i;
4363 } u;
4364 u.f = floatx_to_float64(ST0, &env->fp_status);
4365 return u.i;
4366}
4367
4368#ifndef VBOX
4369int32_t helper_fist_ST0(void)
4370#else
4371RTCCINTREG helper_fist_ST0(void)
4372#endif
4373{
4374 int32_t val;
4375 val = floatx_to_int32(ST0, &env->fp_status);
4376 if (val != (int16_t)val)
4377 val = -32768;
4378 return val;
4379}
4380
4381#ifndef VBOX
4382int32_t helper_fistl_ST0(void)
4383#else
4384RTCCINTREG helper_fistl_ST0(void)
4385#endif
4386{
4387 int32_t val;
4388 val = floatx_to_int32(ST0, &env->fp_status);
4389 return val;
4390}
4391
4392int64_t helper_fistll_ST0(void)
4393{
4394 int64_t val;
4395 val = floatx_to_int64(ST0, &env->fp_status);
4396 return val;
4397}
4398
4399#ifndef VBOX
4400int32_t helper_fistt_ST0(void)
4401#else
4402RTCCINTREG helper_fistt_ST0(void)
4403#endif
4404{
4405 int32_t val;
4406 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
4407 if (val != (int16_t)val)
4408 val = -32768;
4409 return val;
4410}
4411
4412#ifndef VBOX
4413int32_t helper_fisttl_ST0(void)
4414#else
4415RTCCINTREG helper_fisttl_ST0(void)
4416#endif
4417{
4418 int32_t val;
4419 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
4420 return val;
4421}
4422
4423int64_t helper_fisttll_ST0(void)
4424{
4425 int64_t val;
4426 val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
4427 return val;
4428}
4429
4430void helper_fldt_ST0(target_ulong ptr)
4431{
4432 int new_fpstt;
4433 new_fpstt = (env->fpstt - 1) & 7;
4434 env->fpregs[new_fpstt].d = helper_fldt(ptr);
4435 env->fpstt = new_fpstt;
4436 env->fptags[new_fpstt] = 0; /* validate stack entry */
4437}
4438
4439void helper_fstt_ST0(target_ulong ptr)
4440{
4441 helper_fstt(ST0, ptr);
4442}
4443
4444void helper_fpush(void)
4445{
4446 fpush();
4447}
4448
4449void helper_fpop(void)
4450{
4451 fpop();
4452}
4453
4454void helper_fdecstp(void)
4455{
4456 env->fpstt = (env->fpstt - 1) & 7;
4457 env->fpus &= (~0x4700);
4458}
4459
4460void helper_fincstp(void)
4461{
4462 env->fpstt = (env->fpstt + 1) & 7;
4463 env->fpus &= (~0x4700);
4464}
4465
4466/* FPU move */
4467
4468void helper_ffree_STN(int st_index)
4469{
4470 env->fptags[(env->fpstt + st_index) & 7] = 1;
4471}
4472
4473void helper_fmov_ST0_FT0(void)
4474{
4475 ST0 = FT0;
4476}
4477
4478void helper_fmov_FT0_STN(int st_index)
4479{
4480 FT0 = ST(st_index);
4481}
4482
4483void helper_fmov_ST0_STN(int st_index)
4484{
4485 ST0 = ST(st_index);
4486}
4487
4488void helper_fmov_STN_ST0(int st_index)
4489{
4490 ST(st_index) = ST0;
4491}
4492
4493void helper_fxchg_ST0_STN(int st_index)
4494{
4495 CPU86_LDouble tmp;
4496 tmp = ST(st_index);
4497 ST(st_index) = ST0;
4498 ST0 = tmp;
4499}
4500
4501/* FPU operations */
4502
4503static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
4504
4505void helper_fcom_ST0_FT0(void)
4506{
4507 int ret;
4508
4509 ret = floatx_compare(ST0, FT0, &env->fp_status);
4510 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
4511}
4512
4513void helper_fucom_ST0_FT0(void)
4514{
4515 int ret;
4516
4517 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
4518 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
4519}
4520
4521static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
4522
4523void helper_fcomi_ST0_FT0(void)
4524{
4525 int eflags;
4526 int ret;
4527
4528 ret = floatx_compare(ST0, FT0, &env->fp_status);
4529 eflags = helper_cc_compute_all(CC_OP);
4530 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
4531 CC_SRC = eflags;
4532}
4533
4534void helper_fucomi_ST0_FT0(void)
4535{
4536 int eflags;
4537 int ret;
4538
4539 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
4540 eflags = helper_cc_compute_all(CC_OP);
4541 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
4542 CC_SRC = eflags;
4543}
4544
4545void helper_fadd_ST0_FT0(void)
4546{
4547 ST0 += FT0;
4548}
4549
4550void helper_fmul_ST0_FT0(void)
4551{
4552 ST0 *= FT0;
4553}
4554
4555void helper_fsub_ST0_FT0(void)
4556{
4557 ST0 -= FT0;
4558}
4559
4560void helper_fsubr_ST0_FT0(void)
4561{
4562 ST0 = FT0 - ST0;
4563}
4564
4565void helper_fdiv_ST0_FT0(void)
4566{
4567 ST0 = helper_fdiv(ST0, FT0);
4568}
4569
4570void helper_fdivr_ST0_FT0(void)
4571{
4572 ST0 = helper_fdiv(FT0, ST0);
4573}
4574
4575/* fp operations between STN and ST0 */
4576
4577void helper_fadd_STN_ST0(int st_index)
4578{
4579 ST(st_index) += ST0;
4580}
4581
4582void helper_fmul_STN_ST0(int st_index)
4583{
4584 ST(st_index) *= ST0;
4585}
4586
4587void helper_fsub_STN_ST0(int st_index)
4588{
4589 ST(st_index) -= ST0;
4590}
4591
4592void helper_fsubr_STN_ST0(int st_index)
4593{
4594 CPU86_LDouble *p;
4595 p = &ST(st_index);
4596 *p = ST0 - *p;
4597}
4598
4599void helper_fdiv_STN_ST0(int st_index)
4600{
4601 CPU86_LDouble *p;
4602 p = &ST(st_index);
4603 *p = helper_fdiv(*p, ST0);
4604}
4605
4606void helper_fdivr_STN_ST0(int st_index)
4607{
4608 CPU86_LDouble *p;
4609 p = &ST(st_index);
4610 *p = helper_fdiv(ST0, *p);
4611}
4612
4613/* misc FPU operations */
4614void helper_fchs_ST0(void)
4615{
4616 ST0 = floatx_chs(ST0);
4617}
4618
4619void helper_fabs_ST0(void)
4620{
4621 ST0 = floatx_abs(ST0);
4622}
4623
4624void helper_fld1_ST0(void)
4625{
4626 ST0 = f15rk[1];
4627}
4628
4629void helper_fldl2t_ST0(void)
4630{
4631 ST0 = f15rk[6];
4632}
4633
4634void helper_fldl2e_ST0(void)
4635{
4636 ST0 = f15rk[5];
4637}
4638
4639void helper_fldpi_ST0(void)
4640{
4641 ST0 = f15rk[2];
4642}
4643
4644void helper_fldlg2_ST0(void)
4645{
4646 ST0 = f15rk[3];
4647}
4648
4649void helper_fldln2_ST0(void)
4650{
4651 ST0 = f15rk[4];
4652}
4653
4654void helper_fldz_ST0(void)
4655{
4656 ST0 = f15rk[0];
4657}
4658
4659void helper_fldz_FT0(void)
4660{
4661 FT0 = f15rk[0];
4662}
4663
4664#ifndef VBOX
4665uint32_t helper_fnstsw(void)
4666#else
4667RTCCUINTREG helper_fnstsw(void)
4668#endif
4669{
4670 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4671}
4672
4673#ifndef VBOX
4674uint32_t helper_fnstcw(void)
4675#else
4676RTCCUINTREG helper_fnstcw(void)
4677#endif
4678{
4679 return env->fpuc;
4680}
4681
4682static void update_fp_status(void)
4683{
4684 int rnd_type;
4685
4686 /* set rounding mode */
4687 switch(env->fpuc & RC_MASK) {
4688 default:
4689 case RC_NEAR:
4690 rnd_type = float_round_nearest_even;
4691 break;
4692 case RC_DOWN:
4693 rnd_type = float_round_down;
4694 break;
4695 case RC_UP:
4696 rnd_type = float_round_up;
4697 break;
4698 case RC_CHOP:
4699 rnd_type = float_round_to_zero;
4700 break;
4701 }
4702 set_float_rounding_mode(rnd_type, &env->fp_status);
4703#ifdef FLOATX80
4704 switch((env->fpuc >> 8) & 3) {
4705 case 0:
4706 rnd_type = 32;
4707 break;
4708 case 2:
4709 rnd_type = 64;
4710 break;
4711 case 3:
4712 default:
4713 rnd_type = 80;
4714 break;
4715 }
4716 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
4717#endif
4718}
4719
4720void helper_fldcw(uint32_t val)
4721{
4722 env->fpuc = val;
4723 update_fp_status();
4724}
4725
4726void helper_fclex(void)
4727{
4728 env->fpus &= 0x7f00;
4729}
4730
4731void helper_fwait(void)
4732{
4733 if (env->fpus & FPUS_SE)
4734 fpu_raise_exception();
4735}
4736
4737void helper_fninit(void)
4738{
4739 env->fpus = 0;
4740 env->fpstt = 0;
4741 env->fpuc = 0x37f;
4742 env->fptags[0] = 1;
4743 env->fptags[1] = 1;
4744 env->fptags[2] = 1;
4745 env->fptags[3] = 1;
4746 env->fptags[4] = 1;
4747 env->fptags[5] = 1;
4748 env->fptags[6] = 1;
4749 env->fptags[7] = 1;
4750}
4751
4752/* BCD ops */
4753
4754void helper_fbld_ST0(target_ulong ptr)
4755{
4756 CPU86_LDouble tmp;
4757 uint64_t val;
4758 unsigned int v;
4759 int i;
4760
4761 val = 0;
4762 for(i = 8; i >= 0; i--) {
4763 v = ldub(ptr + i);
4764 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
4765 }
4766 tmp = val;
4767 if (ldub(ptr + 9) & 0x80)
4768 tmp = -tmp;
4769 fpush();
4770 ST0 = tmp;
4771}
4772
4773void helper_fbst_ST0(target_ulong ptr)
4774{
4775 int v;
4776 target_ulong mem_ref, mem_end;
4777 int64_t val;
4778
4779 val = floatx_to_int64(ST0, &env->fp_status);
4780 mem_ref = ptr;
4781 mem_end = mem_ref + 9;
4782 if (val < 0) {
4783 stb(mem_end, 0x80);
4784 val = -val;
4785 } else {
4786 stb(mem_end, 0x00);
4787 }
4788 while (mem_ref < mem_end) {
4789 if (val == 0)
4790 break;
4791 v = val % 100;
4792 val = val / 100;
4793 v = ((v / 10) << 4) | (v % 10);
4794 stb(mem_ref++, v);
4795 }
4796 while (mem_ref < mem_end) {
4797 stb(mem_ref++, 0);
4798 }
4799}
4800
4801void helper_f2xm1(void)
4802{
4803 ST0 = pow(2.0,ST0) - 1.0;
4804}
4805
4806void helper_fyl2x(void)
4807{
4808 CPU86_LDouble fptemp;
4809
4810 fptemp = ST0;
4811 if (fptemp>0.0){
4812 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
4813 ST1 *= fptemp;
4814 fpop();
4815 } else {
4816 env->fpus &= (~0x4700);
4817 env->fpus |= 0x400;
4818 }
4819}
4820
4821void helper_fptan(void)
4822{
4823 CPU86_LDouble fptemp;
4824
4825 fptemp = ST0;
4826 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4827 env->fpus |= 0x400;
4828 } else {
4829 ST0 = tan(fptemp);
4830 fpush();
4831 ST0 = 1.0;
4832 env->fpus &= (~0x400); /* C2 <-- 0 */
4833 /* the above code is for |arg| < 2**52 only */
4834 }
4835}
4836
4837void helper_fpatan(void)
4838{
4839 CPU86_LDouble fptemp, fpsrcop;
4840
4841 fpsrcop = ST1;
4842 fptemp = ST0;
4843 ST1 = atan2(fpsrcop,fptemp);
4844 fpop();
4845}
4846
4847void helper_fxtract(void)
4848{
4849 CPU86_LDoubleU temp;
4850 unsigned int expdif;
4851
4852 temp.d = ST0;
4853 expdif = EXPD(temp) - EXPBIAS;
4854 /*DP exponent bias*/
4855 ST0 = expdif;
4856 fpush();
4857 BIASEXPONENT(temp);
4858 ST0 = temp.d;
4859}
4860
4861void helper_fprem1(void)
4862{
4863 CPU86_LDouble dblq, fpsrcop, fptemp;
4864 CPU86_LDoubleU fpsrcop1, fptemp1;
4865 int expdif;
4866 signed long long int q;
4867
4868#ifndef VBOX /* Unfortunately, we cannot handle isinf/isnan easily in wrapper */
4869 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
4870#else
4871 if ((ST0 != ST0) || (ST1 != ST1) || (ST1 == 0.0)) {
4872#endif
4873 ST0 = 0.0 / 0.0; /* NaN */
4874 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4875 return;
4876 }
4877
4878 fpsrcop = ST0;
4879 fptemp = ST1;
4880 fpsrcop1.d = fpsrcop;
4881 fptemp1.d = fptemp;
4882 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4883
4884 if (expdif < 0) {
4885 /* optimisation? taken from the AMD docs */
4886 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4887 /* ST0 is unchanged */
4888 return;
4889 }
4890
4891 if (expdif < 53) {
4892 dblq = fpsrcop / fptemp;
4893 /* round dblq towards nearest integer */
4894 dblq = rint(dblq);
4895 ST0 = fpsrcop - fptemp * dblq;
4896
4897 /* convert dblq to q by truncating towards zero */
4898 if (dblq < 0.0)
4899 q = (signed long long int)(-dblq);
4900 else
4901 q = (signed long long int)dblq;
4902
4903 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4904 /* (C0,C3,C1) <-- (q2,q1,q0) */
4905 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4906 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4907 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4908 } else {
4909 env->fpus |= 0x400; /* C2 <-- 1 */
4910 fptemp = pow(2.0, expdif - 50);
4911 fpsrcop = (ST0 / ST1) / fptemp;
4912 /* fpsrcop = integer obtained by chopping */
4913 fpsrcop = (fpsrcop < 0.0) ?
4914 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4915 ST0 -= (ST1 * fpsrcop * fptemp);
4916 }
4917}
4918
4919void helper_fprem(void)
4920{
4921 CPU86_LDouble dblq, fpsrcop, fptemp;
4922 CPU86_LDoubleU fpsrcop1, fptemp1;
4923 int expdif;
4924 signed long long int q;
4925
4926#ifndef VBOX /* Unfortunately, we cannot easily handle isinf/isnan in wrapper */
4927 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
4928#else
4929 if ((ST0 != ST0) || (ST1 != ST1) || (ST1 == 0.0)) {
4930#endif
4931 ST0 = 0.0 / 0.0; /* NaN */
4932 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4933 return;
4934 }
4935
4936 fpsrcop = (CPU86_LDouble)ST0;
4937 fptemp = (CPU86_LDouble)ST1;
4938 fpsrcop1.d = fpsrcop;
4939 fptemp1.d = fptemp;
4940 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4941
4942 if (expdif < 0) {
4943 /* optimisation? taken from the AMD docs */
4944 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4945 /* ST0 is unchanged */
4946 return;
4947 }
4948
4949 if ( expdif < 53 ) {
4950 dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
4951 /* round dblq towards zero */
4952 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
4953 ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
4954
4955 /* convert dblq to q by truncating towards zero */
4956 if (dblq < 0.0)
4957 q = (signed long long int)(-dblq);
4958 else
4959 q = (signed long long int)dblq;
4960
4961 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4962 /* (C0,C3,C1) <-- (q2,q1,q0) */
4963 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
4964 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4965 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4966 } else {
4967 int N = 32 + (expdif % 32); /* as per AMD docs */
4968 env->fpus |= 0x400; /* C2 <-- 1 */
4969 fptemp = pow(2.0, (double)(expdif - N));
4970 fpsrcop = (ST0 / ST1) / fptemp;
4971 /* fpsrcop = integer obtained by chopping */
4972 fpsrcop = (fpsrcop < 0.0) ?
4973 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4974 ST0 -= (ST1 * fpsrcop * fptemp);
4975 }
4976}
4977
4978void helper_fyl2xp1(void)
4979{
4980 CPU86_LDouble fptemp;
4981
4982 fptemp = ST0;
4983 if ((fptemp+1.0)>0.0) {
4984 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
4985 ST1 *= fptemp;
4986 fpop();
4987 } else {
4988 env->fpus &= (~0x4700);
4989 env->fpus |= 0x400;
4990 }
4991}
4992
4993void helper_fsqrt(void)
4994{
4995 CPU86_LDouble fptemp;
4996
4997 fptemp = ST0;
4998 if (fptemp<0.0) {
4999 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
5000 env->fpus |= 0x400;
5001 }
5002 ST0 = sqrt(fptemp);
5003}
5004
5005void helper_fsincos(void)
5006{
5007 CPU86_LDouble fptemp;
5008
5009 fptemp = ST0;
5010 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
5011 env->fpus |= 0x400;
5012 } else {
5013 ST0 = sin(fptemp);
5014 fpush();
5015 ST0 = cos(fptemp);
5016 env->fpus &= (~0x400); /* C2 <-- 0 */
5017 /* the above code is for |arg| < 2**63 only */
5018 }
5019}
5020
5021void helper_frndint(void)
5022{
5023 ST0 = floatx_round_to_int(ST0, &env->fp_status);
5024}
5025
5026void helper_fscale(void)
5027{
5028 ST0 = ldexp (ST0, (int)(ST1));
5029}
5030
5031void helper_fsin(void)
5032{
5033 CPU86_LDouble fptemp;
5034
5035 fptemp = ST0;
5036 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
5037 env->fpus |= 0x400;
5038 } else {
5039 ST0 = sin(fptemp);
5040 env->fpus &= (~0x400); /* C2 <-- 0 */
5041 /* the above code is for |arg| < 2**53 only */
5042 }
5043}
5044
5045void helper_fcos(void)
5046{
5047 CPU86_LDouble fptemp;
5048
5049 fptemp = ST0;
5050 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
5051 env->fpus |= 0x400;
5052 } else {
5053 ST0 = cos(fptemp);
5054 env->fpus &= (~0x400); /* C2 <-- 0 */
5055 /* the above code is for |arg5 < 2**63 only */
5056 }
5057}
5058
5059void helper_fxam_ST0(void)
5060{
5061 CPU86_LDoubleU temp;
5062 int expdif;
5063
5064 temp.d = ST0;
5065
5066 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
5067 if (SIGND(temp))
5068 env->fpus |= 0x200; /* C1 <-- 1 */
5069
5070 /* XXX: test fptags too */
5071 expdif = EXPD(temp);
5072 if (expdif == MAXEXPD) {
5073#ifdef USE_X86LDOUBLE
5074 if (MANTD(temp) == 0x8000000000000000ULL)
5075#else
5076 if (MANTD(temp) == 0)
5077#endif
5078 env->fpus |= 0x500 /*Infinity*/;
5079 else
5080 env->fpus |= 0x100 /*NaN*/;
5081 } else if (expdif == 0) {
5082 if (MANTD(temp) == 0)
5083 env->fpus |= 0x4000 /*Zero*/;
5084 else
5085 env->fpus |= 0x4400 /*Denormal*/;
5086 } else {
5087 env->fpus |= 0x400;
5088 }
5089}
5090
5091void helper_fstenv(target_ulong ptr, int data32)
5092{
5093 int fpus, fptag, exp, i;
5094 uint64_t mant;
5095 CPU86_LDoubleU tmp;
5096
5097 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
5098 fptag = 0;
5099 for (i=7; i>=0; i--) {
5100 fptag <<= 2;
5101 if (env->fptags[i]) {
5102 fptag |= 3;
5103 } else {
5104 tmp.d = env->fpregs[i].d;
5105 exp = EXPD(tmp);
5106 mant = MANTD(tmp);
5107 if (exp == 0 && mant == 0) {
5108 /* zero */
5109 fptag |= 1;
5110 } else if (exp == 0 || exp == MAXEXPD
5111#ifdef USE_X86LDOUBLE
5112 || (mant & (1LL << 63)) == 0
5113#endif
5114 ) {
5115 /* NaNs, infinity, denormal */
5116 fptag |= 2;
5117 }
5118 }
5119 }
5120 if (data32) {
5121 /* 32 bit */
5122 stl(ptr, env->fpuc);
5123 stl(ptr + 4, fpus);
5124 stl(ptr + 8, fptag);
5125 stl(ptr + 12, 0); /* fpip */
5126 stl(ptr + 16, 0); /* fpcs */
5127 stl(ptr + 20, 0); /* fpoo */
5128 stl(ptr + 24, 0); /* fpos */
5129 } else {
5130 /* 16 bit */
5131 stw(ptr, env->fpuc);
5132 stw(ptr + 2, fpus);
5133 stw(ptr + 4, fptag);
5134 stw(ptr + 6, 0);
5135 stw(ptr + 8, 0);
5136 stw(ptr + 10, 0);
5137 stw(ptr + 12, 0);
5138 }
5139}
5140
5141void helper_fldenv(target_ulong ptr, int data32)
5142{
5143 int i, fpus, fptag;
5144
5145 if (data32) {
5146 env->fpuc = lduw(ptr);
5147 fpus = lduw(ptr + 4);
5148 fptag = lduw(ptr + 8);
5149 }
5150 else {
5151 env->fpuc = lduw(ptr);
5152 fpus = lduw(ptr + 2);
5153 fptag = lduw(ptr + 4);
5154 }
5155 env->fpstt = (fpus >> 11) & 7;
5156 env->fpus = fpus & ~0x3800;
5157 for(i = 0;i < 8; i++) {
5158 env->fptags[i] = ((fptag & 3) == 3);
5159 fptag >>= 2;
5160 }
5161}
5162
5163void helper_fsave(target_ulong ptr, int data32)
5164{
5165 CPU86_LDouble tmp;
5166 int i;
5167
5168 helper_fstenv(ptr, data32);
5169
5170 ptr += (14 << data32);
5171 for(i = 0;i < 8; i++) {
5172 tmp = ST(i);
5173 helper_fstt(tmp, ptr);
5174 ptr += 10;
5175 }
5176
5177 /* fninit */
5178 env->fpus = 0;
5179 env->fpstt = 0;
5180 env->fpuc = 0x37f;
5181 env->fptags[0] = 1;
5182 env->fptags[1] = 1;
5183 env->fptags[2] = 1;
5184 env->fptags[3] = 1;
5185 env->fptags[4] = 1;
5186 env->fptags[5] = 1;
5187 env->fptags[6] = 1;
5188 env->fptags[7] = 1;
5189}
5190
5191void helper_frstor(target_ulong ptr, int data32)
5192{
5193 CPU86_LDouble tmp;
5194 int i;
5195
5196 helper_fldenv(ptr, data32);
5197 ptr += (14 << data32);
5198
5199 for(i = 0;i < 8; i++) {
5200 tmp = helper_fldt(ptr);
5201 ST(i) = tmp;
5202 ptr += 10;
5203 }
5204}
5205
5206void helper_fxsave(target_ulong ptr, int data64)
5207{
5208 int fpus, fptag, i, nb_xmm_regs;
5209 CPU86_LDouble tmp;
5210 target_ulong addr;
5211
5212 /* The operand must be 16 byte aligned */
5213 if (ptr & 0xf) {
5214 raise_exception(EXCP0D_GPF);
5215 }
5216
5217 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
5218 fptag = 0;
5219 for(i = 0; i < 8; i++) {
5220 fptag |= (env->fptags[i] << i);
5221 }
5222 stw(ptr, env->fpuc);
5223 stw(ptr + 2, fpus);
5224 stw(ptr + 4, fptag ^ 0xff);
5225#ifdef TARGET_X86_64
5226 if (data64) {
5227 stq(ptr + 0x08, 0); /* rip */
5228 stq(ptr + 0x10, 0); /* rdp */
5229 } else
5230#endif
5231 {
5232 stl(ptr + 0x08, 0); /* eip */
5233 stl(ptr + 0x0c, 0); /* sel */
5234 stl(ptr + 0x10, 0); /* dp */
5235 stl(ptr + 0x14, 0); /* sel */
5236 }
5237
5238 addr = ptr + 0x20;
5239 for(i = 0;i < 8; i++) {
5240 tmp = ST(i);
5241 helper_fstt(tmp, addr);
5242 addr += 16;
5243 }
5244
5245 if (env->cr[4] & CR4_OSFXSR_MASK) {
5246 /* XXX: finish it */
5247 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
5248 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
5249 if (env->hflags & HF_CS64_MASK)
5250 nb_xmm_regs = 16;
5251 else
5252 nb_xmm_regs = 8;
5253 addr = ptr + 0xa0;
5254 /* Fast FXSAVE leaves out the XMM registers */
5255 if (!(env->efer & MSR_EFER_FFXSR)
5256 || (env->hflags & HF_CPL_MASK)
5257 || !(env->hflags & HF_LMA_MASK)) {
5258 for(i = 0; i < nb_xmm_regs; i++) {
5259 stq(addr, env->xmm_regs[i].XMM_Q(0));
5260 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
5261 addr += 16;
5262 }
5263 }
5264 }
5265}
5266
5267void helper_fxrstor(target_ulong ptr, int data64)
5268{
5269 int i, fpus, fptag, nb_xmm_regs;
5270 CPU86_LDouble tmp;
5271 target_ulong addr;
5272
5273 /* The operand must be 16 byte aligned */
5274 if (ptr & 0xf) {
5275 raise_exception(EXCP0D_GPF);
5276 }
5277
5278 env->fpuc = lduw(ptr);
5279 fpus = lduw(ptr + 2);
5280 fptag = lduw(ptr + 4);
5281 env->fpstt = (fpus >> 11) & 7;
5282 env->fpus = fpus & ~0x3800;
5283 fptag ^= 0xff;
5284 for(i = 0;i < 8; i++) {
5285 env->fptags[i] = ((fptag >> i) & 1);
5286 }
5287
5288 addr = ptr + 0x20;
5289 for(i = 0;i < 8; i++) {
5290 tmp = helper_fldt(addr);
5291 ST(i) = tmp;
5292 addr += 16;
5293 }
5294
5295 if (env->cr[4] & CR4_OSFXSR_MASK) {
5296 /* XXX: finish it */
5297 env->mxcsr = ldl(ptr + 0x18);
5298 //ldl(ptr + 0x1c);
5299 if (env->hflags & HF_CS64_MASK)
5300 nb_xmm_regs = 16;
5301 else
5302 nb_xmm_regs = 8;
5303 addr = ptr + 0xa0;
5304 /* Fast FXRESTORE leaves out the XMM registers */
5305 if (!(env->efer & MSR_EFER_FFXSR)
5306 || (env->hflags & HF_CPL_MASK)
5307 || !(env->hflags & HF_LMA_MASK)) {
5308 for(i = 0; i < nb_xmm_regs; i++) {
5309#if !defined(VBOX) || __GNUC__ < 4
5310 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
5311 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
5312#else /* VBOX + __GNUC__ >= 4: gcc 4.x compiler bug - it runs out of registers for the 64-bit value. */
5313# if 1
5314 env->xmm_regs[i].XMM_L(0) = ldl(addr);
5315 env->xmm_regs[i].XMM_L(1) = ldl(addr + 4);
5316 env->xmm_regs[i].XMM_L(2) = ldl(addr + 8);
5317 env->xmm_regs[i].XMM_L(3) = ldl(addr + 12);
5318# else
5319 /* this works fine on Mac OS X, gcc 4.0.1 */
5320 uint64_t u64 = ldq(addr);
5321 env->xmm_regs[i].XMM_Q(0);
5322 u64 = ldq(addr + 4);
5323 env->xmm_regs[i].XMM_Q(1) = u64;
5324# endif
5325#endif
5326 addr += 16;
5327 }
5328 }
5329 }
5330}
5331
5332#ifndef USE_X86LDOUBLE
5333
5334void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
5335{
5336 CPU86_LDoubleU temp;
5337 int e;
5338
5339 temp.d = f;
5340 /* mantissa */
5341 *pmant = (MANTD(temp) << 11) | (1LL << 63);
5342 /* exponent + sign */
5343 e = EXPD(temp) - EXPBIAS + 16383;
5344 e |= SIGND(temp) >> 16;
5345 *pexp = e;
5346}
5347
5348CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
5349{
5350 CPU86_LDoubleU temp;
5351 int e;
5352 uint64_t ll;
5353
5354 /* XXX: handle overflow ? */
5355 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
5356 e |= (upper >> 4) & 0x800; /* sign */
5357 ll = (mant >> 11) & ((1LL << 52) - 1);
5358#ifdef __arm__
5359 temp.l.upper = (e << 20) | (ll >> 32);
5360 temp.l.lower = ll;
5361#else
5362 temp.ll = ll | ((uint64_t)e << 52);
5363#endif
5364 return temp.d;
5365}
5366
5367#else
5368
5369void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
5370{
5371 CPU86_LDoubleU temp;
5372
5373 temp.d = f;
5374 *pmant = temp.l.lower;
5375 *pexp = temp.l.upper;
5376}
5377
5378CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
5379{
5380 CPU86_LDoubleU temp;
5381
5382 temp.l.upper = upper;
5383 temp.l.lower = mant;
5384 return temp.d;
5385}
5386#endif
5387
5388#ifdef TARGET_X86_64
5389
5390//#define DEBUG_MULDIV
5391
5392static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
5393{
5394 *plow += a;
5395 /* carry test */
5396 if (*plow < a)
5397 (*phigh)++;
5398 *phigh += b;
5399}
5400
5401static void neg128(uint64_t *plow, uint64_t *phigh)
5402{
5403 *plow = ~ *plow;
5404 *phigh = ~ *phigh;
5405 add128(plow, phigh, 1, 0);
5406}
5407
5408/* return TRUE if overflow */
5409static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
5410{
5411 uint64_t q, r, a1, a0;
5412 int i, qb, ab;
5413
5414 a0 = *plow;
5415 a1 = *phigh;
5416 if (a1 == 0) {
5417 q = a0 / b;
5418 r = a0 % b;
5419 *plow = q;
5420 *phigh = r;
5421 } else {
5422 if (a1 >= b)
5423 return 1;
5424 /* XXX: use a better algorithm */
5425 for(i = 0; i < 64; i++) {
5426 ab = a1 >> 63;
5427 a1 = (a1 << 1) | (a0 >> 63);
5428 if (ab || a1 >= b) {
5429 a1 -= b;
5430 qb = 1;
5431 } else {
5432 qb = 0;
5433 }
5434 a0 = (a0 << 1) | qb;
5435 }
5436#if defined(DEBUG_MULDIV)
5437 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
5438 *phigh, *plow, b, a0, a1);
5439#endif
5440 *plow = a0;
5441 *phigh = a1;
5442 }
5443 return 0;
5444}
5445
5446/* return TRUE if overflow */
5447static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
5448{
5449 int sa, sb;
5450 sa = ((int64_t)*phigh < 0);
5451 if (sa)
5452 neg128(plow, phigh);
5453 sb = (b < 0);
5454 if (sb)
5455 b = -b;
5456 if (div64(plow, phigh, b) != 0)
5457 return 1;
5458 if (sa ^ sb) {
5459 if (*plow > (1ULL << 63))
5460 return 1;
5461 *plow = - *plow;
5462 } else {
5463 if (*plow >= (1ULL << 63))
5464 return 1;
5465 }
5466 if (sa)
5467 *phigh = - *phigh;
5468 return 0;
5469}
5470
5471void helper_mulq_EAX_T0(target_ulong t0)
5472{
5473 uint64_t r0, r1;
5474
5475 mulu64(&r0, &r1, EAX, t0);
5476 EAX = r0;
5477 EDX = r1;
5478 CC_DST = r0;
5479 CC_SRC = r1;
5480}
5481
5482void helper_imulq_EAX_T0(target_ulong t0)
5483{
5484 uint64_t r0, r1;
5485
5486 muls64(&r0, &r1, EAX, t0);
5487 EAX = r0;
5488 EDX = r1;
5489 CC_DST = r0;
5490 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
5491}
5492
5493target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
5494{
5495 uint64_t r0, r1;
5496
5497 muls64(&r0, &r1, t0, t1);
5498 CC_DST = r0;
5499 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
5500 return r0;
5501}
5502
5503void helper_divq_EAX(target_ulong t0)
5504{
5505 uint64_t r0, r1;
5506 if (t0 == 0) {
5507 raise_exception(EXCP00_DIVZ);
5508 }
5509 r0 = EAX;
5510 r1 = EDX;
5511 if (div64(&r0, &r1, t0))
5512 raise_exception(EXCP00_DIVZ);
5513 EAX = r0;
5514 EDX = r1;
5515}
5516
5517void helper_idivq_EAX(target_ulong t0)
5518{
5519 uint64_t r0, r1;
5520 if (t0 == 0) {
5521 raise_exception(EXCP00_DIVZ);
5522 }
5523 r0 = EAX;
5524 r1 = EDX;
5525 if (idiv64(&r0, &r1, t0))
5526 raise_exception(EXCP00_DIVZ);
5527 EAX = r0;
5528 EDX = r1;
5529}
5530#endif
5531
5532static void do_hlt(void)
5533{
5534 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
5535 env->halted = 1;
5536 env->exception_index = EXCP_HLT;
5537 cpu_loop_exit();
5538}
5539
5540void helper_hlt(int next_eip_addend)
5541{
5542 helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
5543 EIP += next_eip_addend;
5544
5545 do_hlt();
5546}
5547
5548void helper_monitor(target_ulong ptr)
5549{
5550#ifdef VBOX
5551 if ((uint32_t)ECX > 1)
5552 raise_exception(EXCP0D_GPF);
5553#else /* !VBOX */
5554 if ((uint32_t)ECX != 0)
5555 raise_exception(EXCP0D_GPF);
5556#endif /* !VBOX */
5557 /* XXX: store address ? */
5558 helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
5559}
5560
5561void helper_mwait(int next_eip_addend)
5562{
5563 if ((uint32_t)ECX != 0)
5564 raise_exception(EXCP0D_GPF);
5565#ifdef VBOX
5566 helper_hlt(next_eip_addend);
5567#else /* !VBOX */
5568 helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
5569 EIP += next_eip_addend;
5570
5571 /* XXX: not complete but not completely erroneous */
5572 if (env->cpu_index != 0 || env->next_cpu != NULL) {
5573 /* more than one CPU: do not sleep because another CPU may
5574 wake this one */
5575 } else {
5576 do_hlt();
5577 }
5578#endif /* !VBOX */
5579}
5580
5581void helper_debug(void)
5582{
5583 env->exception_index = EXCP_DEBUG;
5584 cpu_loop_exit();
5585}
5586
5587void helper_reset_rf(void)
5588{
5589 env->eflags &= ~RF_MASK;
5590}
5591
5592void helper_raise_interrupt(int intno, int next_eip_addend)
5593{
5594 raise_interrupt(intno, 1, 0, next_eip_addend);
5595}
5596
5597void helper_raise_exception(int exception_index)
5598{
5599 raise_exception(exception_index);
5600}
5601
5602void helper_cli(void)
5603{
5604 env->eflags &= ~IF_MASK;
5605}
5606
5607void helper_sti(void)
5608{
5609 env->eflags |= IF_MASK;
5610}
5611
5612#ifdef VBOX
5613void helper_cli_vme(void)
5614{
5615 env->eflags &= ~VIF_MASK;
5616}
5617
5618void helper_sti_vme(void)
5619{
5620 /* First check, then change eflags according to the AMD manual */
5621 if (env->eflags & VIP_MASK) {
5622 raise_exception(EXCP0D_GPF);
5623 }
5624 env->eflags |= VIF_MASK;
5625}
5626#endif /* VBOX */
5627
5628#if 0
5629/* vm86plus instructions */
5630void helper_cli_vm(void)
5631{
5632 env->eflags &= ~VIF_MASK;
5633}
5634
5635void helper_sti_vm(void)
5636{
5637 env->eflags |= VIF_MASK;
5638 if (env->eflags & VIP_MASK) {
5639 raise_exception(EXCP0D_GPF);
5640 }
5641}
5642#endif
5643
5644void helper_set_inhibit_irq(void)
5645{
5646 env->hflags |= HF_INHIBIT_IRQ_MASK;
5647}
5648
5649void helper_reset_inhibit_irq(void)
5650{
5651 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5652}
5653
5654void helper_boundw(target_ulong a0, int v)
5655{
5656 int low, high;
5657 low = ldsw(a0);
5658 high = ldsw(a0 + 2);
5659 v = (int16_t)v;
5660 if (v < low || v > high) {
5661 raise_exception(EXCP05_BOUND);
5662 }
5663}
5664
5665void helper_boundl(target_ulong a0, int v)
5666{
5667 int low, high;
5668 low = ldl(a0);
5669 high = ldl(a0 + 4);
5670 if (v < low || v > high) {
5671 raise_exception(EXCP05_BOUND);
5672 }
5673}
5674
5675static float approx_rsqrt(float a)
5676{
5677 return 1.0 / sqrt(a);
5678}
5679
5680static float approx_rcp(float a)
5681{
5682 return 1.0 / a;
5683}
5684
5685#if !defined(CONFIG_USER_ONLY)
5686
5687#define MMUSUFFIX _mmu
5688
5689#define SHIFT 0
5690#include "softmmu_template.h"
5691
5692#define SHIFT 1
5693#include "softmmu_template.h"
5694
5695#define SHIFT 2
5696#include "softmmu_template.h"
5697
5698#define SHIFT 3
5699#include "softmmu_template.h"
5700
5701#endif
5702
5703#if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
5704/* This code assumes real physical address always fit into host CPU reg,
5705 which is wrong in general, but true for our current use cases. */
5706RTCCUINTREG REGPARM __ldb_vbox_phys(RTCCUINTREG addr)
5707{
5708 return remR3PhysReadS8(addr);
5709}
5710RTCCUINTREG REGPARM __ldub_vbox_phys(RTCCUINTREG addr)
5711{
5712 return remR3PhysReadU8(addr);
5713}
5714void REGPARM __stb_vbox_phys(RTCCUINTREG addr, RTCCUINTREG val)
5715{
5716 remR3PhysWriteU8(addr, val);
5717}
5718RTCCUINTREG REGPARM __ldw_vbox_phys(RTCCUINTREG addr)
5719{
5720 return remR3PhysReadS16(addr);
5721}
5722RTCCUINTREG REGPARM __lduw_vbox_phys(RTCCUINTREG addr)
5723{
5724 return remR3PhysReadU16(addr);
5725}
5726void REGPARM __stw_vbox_phys(RTCCUINTREG addr, RTCCUINTREG val)
5727{
5728 remR3PhysWriteU16(addr, val);
5729}
5730RTCCUINTREG REGPARM __ldl_vbox_phys(RTCCUINTREG addr)
5731{
5732 return remR3PhysReadS32(addr);
5733}
5734RTCCUINTREG REGPARM __ldul_vbox_phys(RTCCUINTREG addr)
5735{
5736 return remR3PhysReadU32(addr);
5737}
5738void REGPARM __stl_vbox_phys(RTCCUINTREG addr, RTCCUINTREG val)
5739{
5740 remR3PhysWriteU32(addr, val);
5741}
5742uint64_t REGPARM __ldq_vbox_phys(RTCCUINTREG addr)
5743{
5744 return remR3PhysReadU64(addr);
5745}
5746void REGPARM __stq_vbox_phys(RTCCUINTREG addr, uint64_t val)
5747{
5748 remR3PhysWriteU64(addr, val);
5749}
5750#endif /* VBOX */
5751
5752#if !defined(CONFIG_USER_ONLY)
5753/* try to fill the TLB and return an exception if error. If retaddr is
5754 NULL, it means that the function was called in C code (i.e. not
5755 from generated code or from helper.c) */
5756/* XXX: fix it to restore all registers */
5757void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
5758{
5759 TranslationBlock *tb;
5760 int ret;
5761 uintptr_t pc;
5762 CPUX86State *saved_env;
5763
5764 /* XXX: hack to restore env in all cases, even if not called from
5765 generated code */
5766 saved_env = env;
5767 env = cpu_single_env;
5768
5769 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
5770 if (ret) {
5771 if (retaddr) {
5772 /* now we have a real cpu fault */
5773 pc = (uintptr_t)retaddr;
5774 tb = tb_find_pc(pc);
5775 if (tb) {
5776 /* the PC is inside the translated code. It means that we have
5777 a virtual CPU fault */
5778 cpu_restore_state(tb, env, pc, NULL);
5779 }
5780 }
5781 raise_exception_err(env->exception_index, env->error_code);
5782 }
5783 env = saved_env;
5784}
5785#endif
5786
5787#ifdef VBOX
5788
5789/**
5790 * Correctly computes the eflags.
5791 * @returns eflags.
5792 * @param env1 CPU environment.
5793 */
5794uint32_t raw_compute_eflags(CPUX86State *env1)
5795{
5796 CPUX86State *savedenv = env;
5797 uint32_t efl;
5798 env = env1;
5799 efl = compute_eflags();
5800 env = savedenv;
5801 return efl;
5802}
5803
5804/**
5805 * Reads byte from virtual address in guest memory area.
5806 * XXX: is it working for any addresses? swapped out pages?
5807 * @returns read data byte.
5808 * @param env1 CPU environment.
5809 * @param pvAddr GC Virtual address.
5810 */
5811uint8_t read_byte(CPUX86State *env1, target_ulong addr)
5812{
5813 CPUX86State *savedenv = env;
5814 uint8_t u8;
5815 env = env1;
5816 u8 = ldub_kernel(addr);
5817 env = savedenv;
5818 return u8;
5819}
5820
5821/**
5822 * Reads byte from virtual address in guest memory area.
5823 * XXX: is it working for any addresses? swapped out pages?
5824 * @returns read data byte.
5825 * @param env1 CPU environment.
5826 * @param pvAddr GC Virtual address.
5827 */
5828uint16_t read_word(CPUX86State *env1, target_ulong addr)
5829{
5830 CPUX86State *savedenv = env;
5831 uint16_t u16;
5832 env = env1;
5833 u16 = lduw_kernel(addr);
5834 env = savedenv;
5835 return u16;
5836}
5837
5838/**
5839 * Reads byte from virtual address in guest memory area.
5840 * XXX: is it working for any addresses? swapped out pages?
5841 * @returns read data byte.
5842 * @param env1 CPU environment.
5843 * @param pvAddr GC Virtual address.
5844 */
5845uint32_t read_dword(CPUX86State *env1, target_ulong addr)
5846{
5847 CPUX86State *savedenv = env;
5848 uint32_t u32;
5849 env = env1;
5850 u32 = ldl_kernel(addr);
5851 env = savedenv;
5852 return u32;
5853}
5854
5855/**
5856 * Writes byte to virtual address in guest memory area.
5857 * XXX: is it working for any addresses? swapped out pages?
5858 * @returns read data byte.
5859 * @param env1 CPU environment.
5860 * @param pvAddr GC Virtual address.
5861 * @param val byte value
5862 */
5863void write_byte(CPUX86State *env1, target_ulong addr, uint8_t val)
5864{
5865 CPUX86State *savedenv = env;
5866 env = env1;
5867 stb(addr, val);
5868 env = savedenv;
5869}
5870
5871void write_word(CPUX86State *env1, target_ulong addr, uint16_t val)
5872{
5873 CPUX86State *savedenv = env;
5874 env = env1;
5875 stw(addr, val);
5876 env = savedenv;
5877}
5878
5879void write_dword(CPUX86State *env1, target_ulong addr, uint32_t val)
5880{
5881 CPUX86State *savedenv = env;
5882 env = env1;
5883 stl(addr, val);
5884 env = savedenv;
5885}
5886
5887/**
5888 * Correctly loads selector into segment register with updating internal
5889 * qemu data/caches.
5890 * @param env1 CPU environment.
5891 * @param seg_reg Segment register.
5892 * @param selector Selector to load.
5893 */
5894void sync_seg(CPUX86State *env1, int seg_reg, int selector)
5895{
5896 CPUX86State *savedenv = env;
5897#ifdef FORCE_SEGMENT_SYNC
5898 jmp_buf old_buf;
5899#endif
5900
5901 env = env1;
5902
5903 if ( env->eflags & X86_EFL_VM
5904 || !(env->cr[0] & X86_CR0_PE))
5905 {
5906 load_seg_vm(seg_reg, selector);
5907
5908 env = savedenv;
5909
5910 /* Successful sync. */
5911 Assert(env1->segs[seg_reg].newselector == 0);
5912 }
5913 else
5914 {
5915 /* For some reasons, it works even w/o save/restore of the jump buffer, so as code is
5916 time critical - let's not do that */
5917#ifdef FORCE_SEGMENT_SYNC
5918 memcpy(&old_buf, &env1->jmp_env, sizeof(old_buf));
5919#endif
5920 if (setjmp(env1->jmp_env) == 0)
5921 {
5922 if (seg_reg == R_CS)
5923 {
5924 uint32_t e1, e2;
5925 e1 = e2 = 0;
5926 load_segment(&e1, &e2, selector);
5927 cpu_x86_load_seg_cache(env, R_CS, selector,
5928 get_seg_base(e1, e2),
5929 get_seg_limit(e1, e2),
5930 e2);
5931 }
5932 else
5933 helper_load_seg(seg_reg, selector);
5934 /* We used to use tss_load_seg(seg_reg, selector); which, for some reasons ignored
5935 loading 0 selectors, what, in order, lead to subtle problems like #3588 */
5936
5937 env = savedenv;
5938
5939 /* Successful sync. */
5940 Assert(env1->segs[seg_reg].newselector == 0);
5941 }
5942 else
5943 {
5944 env = savedenv;
5945
5946 /* Postpone sync until the guest uses the selector. */
5947 env1->segs[seg_reg].selector = selector; /* hidden values are now incorrect, but will be resynced when this register is accessed. */
5948 env1->segs[seg_reg].newselector = selector;
5949 Log(("sync_seg: out of sync seg_reg=%d selector=%#x\n", seg_reg, selector));
5950 env1->exception_index = -1;
5951 env1->error_code = 0;
5952 env1->old_exception = -1;
5953 }
5954#ifdef FORCE_SEGMENT_SYNC
5955 memcpy(&env1->jmp_env, &old_buf, sizeof(old_buf));
5956#endif
5957 }
5958
5959}
5960
5961DECLINLINE(void) tb_reset_jump(TranslationBlock *tb, int n)
5962{
5963 tb_set_jmp_target(tb, n, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[n]));
5964}
5965
5966
5967int emulate_single_instr(CPUX86State *env1)
5968{
5969 TranslationBlock *tb;
5970 TranslationBlock *current;
5971 int flags;
5972 uint8_t *tc_ptr;
5973 target_ulong old_eip;
5974
5975 /* ensures env is loaded! */
5976 CPUX86State *savedenv = env;
5977 env = env1;
5978
5979 RAWEx_ProfileStart(env, STATS_EMULATE_SINGLE_INSTR);
5980
5981 current = env->current_tb;
5982 env->current_tb = NULL;
5983 flags = env->hflags | (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
5984
5985 /*
5986 * Translate only one instruction.
5987 */
5988 ASMAtomicOrU32(&env->state, CPU_EMULATE_SINGLE_INSTR);
5989 tb = tb_gen_code(env, env->eip + env->segs[R_CS].base,
5990 env->segs[R_CS].base, flags, 0);
5991
5992 ASMAtomicAndU32(&env->state, ~CPU_EMULATE_SINGLE_INSTR);
5993
5994
5995 /* tb_link_phys: */
5996 tb->jmp_first = (TranslationBlock *)((intptr_t)tb | 2);
5997 tb->jmp_next[0] = NULL;
5998 tb->jmp_next[1] = NULL;
5999 Assert(tb->jmp_next[0] == NULL);
6000 Assert(tb->jmp_next[1] == NULL);
6001 if (tb->tb_next_offset[0] != 0xffff)
6002 tb_reset_jump(tb, 0);
6003 if (tb->tb_next_offset[1] != 0xffff)
6004 tb_reset_jump(tb, 1);
6005
6006 /*
6007 * Execute it using emulation
6008 */
6009 old_eip = env->eip;
6010 env->current_tb = tb;
6011
6012 /*
6013 * eip remains the same for repeated instructions; no idea why qemu doesn't do a jump inside the generated code
6014 * perhaps not a very safe hack
6015 */
6016 while (old_eip == env->eip)
6017 {
6018 tc_ptr = tb->tc_ptr;
6019
6020#if defined(VBOX) && defined(GCC_WITH_BUGGY_REGPARM)
6021 int fake_ret;
6022 tcg_qemu_tb_exec(tc_ptr, fake_ret);
6023#else
6024 tcg_qemu_tb_exec(tc_ptr);
6025#endif
6026
6027 /*
6028 * Exit once we detect an external interrupt and interrupts are enabled
6029 */
6030 if ( (env->interrupt_request & (CPU_INTERRUPT_EXTERNAL_EXIT | CPU_INTERRUPT_EXTERNAL_TIMER))
6031 || ( (env->eflags & IF_MASK)
6032 && !(env->hflags & HF_INHIBIT_IRQ_MASK)
6033 && (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_HARD) )
6034 )
6035 {
6036 break;
6037 }
6038 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_FLUSH_TLB) {
6039 tlb_flush(env, true);
6040 }
6041 }
6042 env->current_tb = current;
6043
6044 tb_phys_invalidate(tb, -1);
6045 tb_free(tb);
6046/*
6047 Assert(tb->tb_next_offset[0] == 0xffff);
6048 Assert(tb->tb_next_offset[1] == 0xffff);
6049 Assert(tb->tb_next[0] == 0xffff);
6050 Assert(tb->tb_next[1] == 0xffff);
6051 Assert(tb->jmp_next[0] == NULL);
6052 Assert(tb->jmp_next[1] == NULL);
6053 Assert(tb->jmp_first == NULL); */
6054
6055 RAWEx_ProfileStop(env, STATS_EMULATE_SINGLE_INSTR);
6056
6057 /*
6058 * Execute the next instruction when we encounter instruction fusing.
6059 */
6060 if (env->hflags & HF_INHIBIT_IRQ_MASK)
6061 {
6062 Log(("REM: Emulating next instruction due to instruction fusing (HF_INHIBIT_IRQ_MASK) at %RGv\n", env->eip));
6063 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
6064 emulate_single_instr(env);
6065 }
6066
6067 env = savedenv;
6068 return 0;
6069}
6070
6071/**
6072 * Correctly loads a new ldtr selector.
6073 *
6074 * @param env1 CPU environment.
6075 * @param selector Selector to load.
6076 */
6077void sync_ldtr(CPUX86State *env1, int selector)
6078{
6079 CPUX86State *saved_env = env;
6080 if (setjmp(env1->jmp_env) == 0)
6081 {
6082 env = env1;
6083 helper_lldt(selector);
6084 env = saved_env;
6085 }
6086 else
6087 {
6088 env = saved_env;
6089#ifdef VBOX_STRICT
6090 cpu_abort(env1, "sync_ldtr: selector=%#x\n", selector);
6091#endif
6092 }
6093}
6094
6095int get_ss_esp_from_tss_raw(CPUX86State *env1, uint32_t *ss_ptr,
6096 uint32_t *esp_ptr, int dpl)
6097{
6098 int type, index, shift;
6099
6100 CPUX86State *savedenv = env;
6101 env = env1;
6102
6103 if (!(env->tr.flags & DESC_P_MASK))
6104 cpu_abort(env, "invalid tss");
6105 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
6106 if ((type & 7) != 1)
6107 cpu_abort(env, "invalid tss type %d", type);
6108 shift = type >> 3;
6109 index = (dpl * 4 + 2) << shift;
6110 if (index + (4 << shift) - 1 > env->tr.limit)
6111 {
6112 env = savedenv;
6113 return 0;
6114 }
6115 //raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
6116
6117 if (shift == 0) {
6118 *esp_ptr = lduw_kernel(env->tr.base + index);
6119 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
6120 } else {
6121 *esp_ptr = ldl_kernel(env->tr.base + index);
6122 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
6123 }
6124
6125 env = savedenv;
6126 return 1;
6127}
6128
6129//*****************************************************************************
6130// Needs to be at the bottom of the file (overriding macros)
6131
6132static inline CPU86_LDouble helper_fldt_raw(uint8_t *ptr)
6133{
6134#ifdef USE_X86LDOUBLE
6135 CPU86_LDoubleU tmp;
6136 tmp.l.lower = *(uint64_t const *)ptr;
6137 tmp.l.upper = *(uint16_t const *)(ptr + 8);
6138 return tmp.d;
6139#else
6140# error "Busted FPU saving/restoring!"
6141 return *(CPU86_LDouble *)ptr;
6142#endif
6143}
6144
6145static inline void helper_fstt_raw(CPU86_LDouble f, uint8_t *ptr)
6146{
6147#ifdef USE_X86LDOUBLE
6148 CPU86_LDoubleU tmp;
6149 tmp.d = f;
6150 *(uint64_t *)(ptr + 0) = tmp.l.lower;
6151 *(uint16_t *)(ptr + 8) = tmp.l.upper;
6152 *(uint16_t *)(ptr + 10) = 0;
6153 *(uint32_t *)(ptr + 12) = 0;
6154 AssertCompile(sizeof(long double) > 8);
6155#else
6156# error "Busted FPU saving/restoring!"
6157 *(CPU86_LDouble *)ptr = f;
6158#endif
6159}
6160
6161#undef stw
6162#undef stl
6163#undef stq
6164#define stw(a,b) *(uint16_t *)(a) = (uint16_t)(b)
6165#define stl(a,b) *(uint32_t *)(a) = (uint32_t)(b)
6166#define stq(a,b) *(uint64_t *)(a) = (uint64_t)(b)
6167
6168//*****************************************************************************
6169void restore_raw_fp_state(CPUX86State *env, uint8_t *ptr)
6170{
6171 int fpus, fptag, i, nb_xmm_regs;
6172 CPU86_LDouble tmp;
6173 uint8_t *addr;
6174 int data64 = !!(env->hflags & HF_LMA_MASK);
6175
6176 if (env->cpuid_features & CPUID_FXSR)
6177 {
6178 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
6179 fptag = 0;
6180 for(i = 0; i < 8; i++) {
6181 fptag |= (env->fptags[i] << i);
6182 }
6183 stw(ptr, env->fpuc);
6184 stw(ptr + 2, fpus);
6185 stw(ptr + 4, fptag ^ 0xff);
6186
6187 addr = ptr + 0x20;
6188 for(i = 0;i < 8; i++) {
6189 tmp = ST(i);
6190 helper_fstt_raw(tmp, addr);
6191 addr += 16;
6192 }
6193
6194 if (env->cr[4] & CR4_OSFXSR_MASK) {
6195 /* XXX: finish it */
6196 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
6197 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
6198 nb_xmm_regs = 8 << data64;
6199 addr = ptr + 0xa0;
6200 for(i = 0; i < nb_xmm_regs; i++) {
6201#if __GNUC__ < 4
6202 stq(addr, env->xmm_regs[i].XMM_Q(0));
6203 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
6204#else /* VBOX + __GNUC__ >= 4: gcc 4.x compiler bug - it runs out of registers for the 64-bit value. */
6205 stl(addr, env->xmm_regs[i].XMM_L(0));
6206 stl(addr + 4, env->xmm_regs[i].XMM_L(1));
6207 stl(addr + 8, env->xmm_regs[i].XMM_L(2));
6208 stl(addr + 12, env->xmm_regs[i].XMM_L(3));
6209#endif
6210 addr += 16;
6211 }
6212 }
6213 }
6214 else
6215 {
6216 PX86FPUSTATE fp = (PX86FPUSTATE)ptr;
6217 int fptag;
6218
6219 fp->FCW = env->fpuc;
6220 fp->FSW = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
6221 fptag = 0;
6222 for (i=7; i>=0; i--) {
6223 fptag <<= 2;
6224 if (env->fptags[i]) {
6225 fptag |= 3;
6226 } else {
6227 /* the FPU automatically computes it */
6228 }
6229 }
6230 fp->FTW = fptag;
6231
6232 for(i = 0;i < 8; i++) {
6233 tmp = ST(i);
6234 helper_fstt_raw(tmp, &fp->regs[i].au8[0]);
6235 }
6236 }
6237}
6238
6239//*****************************************************************************
6240#undef lduw
6241#undef ldl
6242#undef ldq
6243#define lduw(a) *(uint16_t *)(a)
6244#define ldl(a) *(uint32_t *)(a)
6245#define ldq(a) *(uint64_t *)(a)
6246//*****************************************************************************
6247void save_raw_fp_state(CPUX86State *env, uint8_t *ptr)
6248{
6249 int i, fpus, fptag, nb_xmm_regs;
6250 CPU86_LDouble tmp;
6251 uint8_t *addr;
6252 int data64 = !!(env->hflags & HF_LMA_MASK); /* don't use HF_CS64_MASK here as cs hasn't been synced when this function is called. */
6253
6254 if (env->cpuid_features & CPUID_FXSR)
6255 {
6256 env->fpuc = lduw(ptr);
6257 fpus = lduw(ptr + 2);
6258 fptag = lduw(ptr + 4);
6259 env->fpstt = (fpus >> 11) & 7;
6260 env->fpus = fpus & ~0x3800;
6261 fptag ^= 0xff;
6262 for(i = 0;i < 8; i++) {
6263 env->fptags[i] = ((fptag >> i) & 1);
6264 }
6265
6266 addr = ptr + 0x20;
6267 for(i = 0;i < 8; i++) {
6268 tmp = helper_fldt_raw(addr);
6269 ST(i) = tmp;
6270 addr += 16;
6271 }
6272
6273 if (env->cr[4] & CR4_OSFXSR_MASK) {
6274 /* XXX: finish it, endianness */
6275 env->mxcsr = ldl(ptr + 0x18);
6276 //ldl(ptr + 0x1c);
6277 nb_xmm_regs = 8 << data64;
6278 addr = ptr + 0xa0;
6279 for(i = 0; i < nb_xmm_regs; i++) {
6280#if HC_ARCH_BITS == 32
6281 /* this is a workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35135 */
6282 env->xmm_regs[i].XMM_L(0) = ldl(addr);
6283 env->xmm_regs[i].XMM_L(1) = ldl(addr + 4);
6284 env->xmm_regs[i].XMM_L(2) = ldl(addr + 8);
6285 env->xmm_regs[i].XMM_L(3) = ldl(addr + 12);
6286#else
6287 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
6288 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
6289#endif
6290 addr += 16;
6291 }
6292 }
6293 }
6294 else
6295 {
6296 PX86FPUSTATE fp = (PX86FPUSTATE)ptr;
6297 int fptag, j;
6298
6299 env->fpuc = fp->FCW;
6300 env->fpstt = (fp->FSW >> 11) & 7;
6301 env->fpus = fp->FSW & ~0x3800;
6302 fptag = fp->FTW;
6303 for(i = 0;i < 8; i++) {
6304 env->fptags[i] = ((fptag & 3) == 3);
6305 fptag >>= 2;
6306 }
6307 j = env->fpstt;
6308 for(i = 0;i < 8; i++) {
6309 tmp = helper_fldt_raw(&fp->regs[i].au8[0]);
6310 ST(i) = tmp;
6311 }
6312 }
6313}
6314//*****************************************************************************
6315//*****************************************************************************
6316
6317#endif /* VBOX */
6318
6319/* Secure Virtual Machine helpers */
6320
6321#if defined(CONFIG_USER_ONLY)
6322
6323void helper_vmrun(int aflag, int next_eip_addend)
6324{
6325}
6326void helper_vmmcall(void)
6327{
6328}
6329void helper_vmload(int aflag)
6330{
6331}
6332void helper_vmsave(int aflag)
6333{
6334}
6335void helper_stgi(void)
6336{
6337}
6338void helper_clgi(void)
6339{
6340}
6341void helper_skinit(void)
6342{
6343}
6344void helper_invlpga(int aflag)
6345{
6346}
6347void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
6348{
6349}
6350void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
6351{
6352}
6353
6354void helper_svm_check_io(uint32_t port, uint32_t param,
6355 uint32_t next_eip_addend)
6356{
6357}
6358#else
6359
6360static inline void svm_save_seg(target_phys_addr_t addr,
6361 const SegmentCache *sc)
6362{
6363 stw_phys(addr + offsetof(struct vmcb_seg, selector),
6364 sc->selector);
6365 stq_phys(addr + offsetof(struct vmcb_seg, base),
6366 sc->base);
6367 stl_phys(addr + offsetof(struct vmcb_seg, limit),
6368 sc->limit);
6369 stw_phys(addr + offsetof(struct vmcb_seg, attrib),
6370 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
6371}
6372
6373static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
6374{
6375 unsigned int flags;
6376
6377 sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
6378 sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
6379 sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
6380 flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
6381 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
6382}
6383
6384static inline void svm_load_seg_cache(target_phys_addr_t addr,
6385 CPUState *env, int seg_reg)
6386{
6387 SegmentCache sc1, *sc = &sc1;
6388 svm_load_seg(addr, sc);
6389 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
6390 sc->base, sc->limit, sc->flags);
6391}
6392
6393void helper_vmrun(int aflag, int next_eip_addend)
6394{
6395 target_ulong addr;
6396 uint32_t event_inj;
6397 uint32_t int_ctl;
6398
6399 helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
6400
6401 if (aflag == 2)
6402 addr = EAX;
6403 else
6404 addr = (uint32_t)EAX;
6405
6406 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
6407
6408 env->vm_vmcb = addr;
6409
6410 /* save the current CPU state in the hsave page */
6411 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
6412 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
6413
6414 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
6415 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
6416
6417 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
6418 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
6419 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
6420 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
6421 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
6422 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
6423
6424 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
6425 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
6426
6427 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
6428 &env->segs[R_ES]);
6429 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
6430 &env->segs[R_CS]);
6431 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
6432 &env->segs[R_SS]);
6433 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
6434 &env->segs[R_DS]);
6435
6436 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
6437 EIP + next_eip_addend);
6438 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
6439 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
6440
6441 /* load the interception bitmaps so we do not need to access the
6442 vmcb in svm mode */
6443 env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
6444 env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
6445 env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
6446 env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
6447 env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
6448 env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
6449
6450 /* enable intercepts */
6451 env->hflags |= HF_SVMI_MASK;
6452
6453 env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
6454
6455 env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
6456 env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
6457
6458 env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
6459 env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
6460
6461 /* clear exit_info_2 so we behave like the real hardware */
6462 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
6463
6464 cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
6465 cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
6466 cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
6467 env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
6468 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
6469 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
6470 if (int_ctl & V_INTR_MASKING_MASK) {
6471 env->v_tpr = int_ctl & V_TPR_MASK;
6472 env->hflags2 |= HF2_VINTR_MASK;
6473 if (env->eflags & IF_MASK)
6474 env->hflags2 |= HF2_HIF_MASK;
6475 }
6476
6477 cpu_load_efer(env,
6478 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
6479 env->eflags = 0;
6480 load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
6481 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
6482 CC_OP = CC_OP_EFLAGS;
6483
6484 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
6485 env, R_ES);
6486 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
6487 env, R_CS);
6488 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
6489 env, R_SS);
6490 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
6491 env, R_DS);
6492
6493 EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
6494 env->eip = EIP;
6495 ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
6496 EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
6497 env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
6498 env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
6499 cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
6500
6501 /* FIXME: guest state consistency checks */
6502
6503 switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
6504 case TLB_CONTROL_DO_NOTHING:
6505 break;
6506 case TLB_CONTROL_FLUSH_ALL_ASID:
6507 /* FIXME: this is not 100% correct but should work for now */
6508 tlb_flush(env, 1);
6509 break;
6510 }
6511
6512 env->hflags2 |= HF2_GIF_MASK;
6513
6514 if (int_ctl & V_IRQ_MASK) {
6515 env->interrupt_request |= CPU_INTERRUPT_VIRQ;
6516 }
6517
6518 /* maybe we need to inject an event */
6519 event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
6520 if (event_inj & SVM_EVTINJ_VALID) {
6521 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
6522 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
6523 uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
6524
6525 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
6526 /* FIXME: need to implement valid_err */
6527 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
6528 case SVM_EVTINJ_TYPE_INTR:
6529 env->exception_index = vector;
6530 env->error_code = event_inj_err;
6531 env->exception_is_int = 0;
6532 env->exception_next_eip = -1;
6533 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
6534 /* XXX: is it always correct ? */
6535 do_interrupt(vector, 0, 0, 0, 1);
6536 break;
6537 case SVM_EVTINJ_TYPE_NMI:
6538 env->exception_index = EXCP02_NMI;
6539 env->error_code = event_inj_err;
6540 env->exception_is_int = 0;
6541 env->exception_next_eip = EIP;
6542 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
6543 cpu_loop_exit();
6544 break;
6545 case SVM_EVTINJ_TYPE_EXEPT:
6546 env->exception_index = vector;
6547 env->error_code = event_inj_err;
6548 env->exception_is_int = 0;
6549 env->exception_next_eip = -1;
6550 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
6551 cpu_loop_exit();
6552 break;
6553 case SVM_EVTINJ_TYPE_SOFT:
6554 env->exception_index = vector;
6555 env->error_code = event_inj_err;
6556 env->exception_is_int = 1;
6557 env->exception_next_eip = EIP;
6558 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
6559 cpu_loop_exit();
6560 break;
6561 }
6562 qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
6563 }
6564}
6565
6566void helper_vmmcall(void)
6567{
6568 helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
6569 raise_exception(EXCP06_ILLOP);
6570}
6571
6572void helper_vmload(int aflag)
6573{
6574 target_ulong addr;
6575 helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
6576
6577 if (aflag == 2)
6578 addr = EAX;
6579 else
6580 addr = (uint32_t)EAX;
6581
6582 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
6583 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
6584 env->segs[R_FS].base);
6585
6586 svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
6587 env, R_FS);
6588 svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
6589 env, R_GS);
6590 svm_load_seg(addr + offsetof(struct vmcb, save.tr),
6591 &env->tr);
6592 svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
6593 &env->ldt);
6594
6595#ifdef TARGET_X86_64
6596 env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
6597 env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
6598 env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
6599 env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
6600#endif
6601 env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
6602 env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
6603 env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
6604 env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
6605}
6606
6607void helper_vmsave(int aflag)
6608{
6609 target_ulong addr;
6610 helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
6611
6612 if (aflag == 2)
6613 addr = EAX;
6614 else
6615 addr = (uint32_t)EAX;
6616
6617 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
6618 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
6619 env->segs[R_FS].base);
6620
6621 svm_save_seg(addr + offsetof(struct vmcb, save.fs),
6622 &env->segs[R_FS]);
6623 svm_save_seg(addr + offsetof(struct vmcb, save.gs),
6624 &env->segs[R_GS]);
6625 svm_save_seg(addr + offsetof(struct vmcb, save.tr),
6626 &env->tr);
6627 svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
6628 &env->ldt);
6629
6630#ifdef TARGET_X86_64
6631 stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
6632 stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
6633 stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
6634 stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
6635#endif
6636 stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
6637 stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
6638 stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
6639 stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
6640}
6641
6642void helper_stgi(void)
6643{
6644 helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
6645 env->hflags2 |= HF2_GIF_MASK;
6646}
6647
6648void helper_clgi(void)
6649{
6650 helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
6651 env->hflags2 &= ~HF2_GIF_MASK;
6652}
6653
6654void helper_skinit(void)
6655{
6656 helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
6657 /* XXX: not implemented */
6658 raise_exception(EXCP06_ILLOP);
6659}
6660
6661void helper_invlpga(int aflag)
6662{
6663 target_ulong addr;
6664 helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
6665
6666 if (aflag == 2)
6667 addr = EAX;
6668 else
6669 addr = (uint32_t)EAX;
6670
6671 /* XXX: could use the ASID to see if it is needed to do the
6672 flush */
6673 tlb_flush_page(env, addr);
6674}
6675
6676void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
6677{
6678 if (likely(!(env->hflags & HF_SVMI_MASK)))
6679 return;
6680#ifndef VBOX
6681 switch(type) {
6682 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
6683 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
6684 helper_vmexit(type, param);
6685 }
6686 break;
6687 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
6688 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
6689 helper_vmexit(type, param);
6690 }
6691 break;
6692 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
6693 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
6694 helper_vmexit(type, param);
6695 }
6696 break;
6697 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
6698 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
6699 helper_vmexit(type, param);
6700 }
6701 break;
6702 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
6703 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
6704 helper_vmexit(type, param);
6705 }
6706 break;
6707 case SVM_EXIT_MSR:
6708 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
6709 /* FIXME: this should be read in at vmrun (faster this way?) */
6710 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
6711 uint32_t t0, t1;
6712 switch((uint32_t)ECX) {
6713 case 0 ... 0x1fff:
6714 t0 = (ECX * 2) % 8;
6715 t1 = ECX / 8;
6716 break;
6717 case 0xc0000000 ... 0xc0001fff:
6718 t0 = (8192 + ECX - 0xc0000000) * 2;
6719 t1 = (t0 / 8);
6720 t0 %= 8;
6721 break;
6722 case 0xc0010000 ... 0xc0011fff:
6723 t0 = (16384 + ECX - 0xc0010000) * 2;
6724 t1 = (t0 / 8);
6725 t0 %= 8;
6726 break;
6727 default:
6728 helper_vmexit(type, param);
6729 t0 = 0;
6730 t1 = 0;
6731 break;
6732 }
6733 if (ldub_phys(addr + t1) & ((1 << param) << t0))
6734 helper_vmexit(type, param);
6735 }
6736 break;
6737 default:
6738 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
6739 helper_vmexit(type, param);
6740 }
6741 break;
6742 }
6743#else /* VBOX */
6744 AssertMsgFailed(("We shouldn't be here, HM supported differently!"));
6745#endif /* VBOX */
6746}
6747
6748void helper_svm_check_io(uint32_t port, uint32_t param,
6749 uint32_t next_eip_addend)
6750{
6751 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
6752 /* FIXME: this should be read in at vmrun (faster this way?) */
6753 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
6754 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
6755 if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
6756 /* next EIP */
6757 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
6758 env->eip + next_eip_addend);
6759 helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
6760 }
6761 }
6762}
6763
6764/* Note: currently only 32 bits of exit_code are used */
6765void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
6766{
6767 uint32_t int_ctl;
6768
6769 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
6770 exit_code, exit_info_1,
6771 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
6772 EIP);
6773
6774 if(env->hflags & HF_INHIBIT_IRQ_MASK) {
6775 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
6776 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
6777 } else {
6778 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
6779 }
6780
6781 /* Save the VM state in the vmcb */
6782 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
6783 &env->segs[R_ES]);
6784 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
6785 &env->segs[R_CS]);
6786 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
6787 &env->segs[R_SS]);
6788 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
6789 &env->segs[R_DS]);
6790
6791 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
6792 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
6793
6794 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
6795 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
6796
6797 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
6798 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
6799 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
6800 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
6801 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
6802
6803 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
6804 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
6805 int_ctl |= env->v_tpr & V_TPR_MASK;
6806 if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
6807 int_ctl |= V_IRQ_MASK;
6808 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
6809
6810 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
6811 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
6812 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
6813 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
6814 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
6815 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
6816 stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
6817
6818 /* Reload the host state from vm_hsave */
6819 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
6820 env->hflags &= ~HF_SVMI_MASK;
6821 env->intercept = 0;
6822 env->intercept_exceptions = 0;
6823 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
6824 env->tsc_offset = 0;
6825
6826 env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
6827 env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
6828
6829 env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
6830 env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
6831
6832 cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
6833 cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
6834 cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
6835 /* we need to set the efer after the crs so the hidden flags get
6836 set properly */
6837 cpu_load_efer(env,
6838 ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
6839 env->eflags = 0;
6840 load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
6841 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
6842 CC_OP = CC_OP_EFLAGS;
6843
6844 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
6845 env, R_ES);
6846 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
6847 env, R_CS);
6848 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
6849 env, R_SS);
6850 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
6851 env, R_DS);
6852
6853 EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
6854 ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
6855 EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
6856
6857 env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
6858 env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
6859
6860 /* other setups */
6861 cpu_x86_set_cpl(env, 0);
6862 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
6863 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
6864
6865 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
6866 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
6867 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
6868 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
6869 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
6870
6871 env->hflags2 &= ~HF2_GIF_MASK;
6872 /* FIXME: Resets the current ASID register to zero (host ASID). */
6873
6874 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
6875
6876 /* Clears the TSC_OFFSET inside the processor. */
6877
6878 /* If the host is in PAE mode, the processor reloads the host's PDPEs
6879 from the page table indicated the host's CR3. If the PDPEs contain
6880 illegal state, the processor causes a shutdown. */
6881
6882 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
6883 env->cr[0] |= CR0_PE_MASK;
6884 env->eflags &= ~VM_MASK;
6885
6886 /* Disables all breakpoints in the host DR7 register. */
6887
6888 /* Checks the reloaded host state for consistency. */
6889
6890 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
6891 host's code segment or non-canonical (in the case of long mode), a
6892 #GP fault is delivered inside the host.) */
6893
6894 /* remove any pending exception */
6895 env->exception_index = -1;
6896 env->error_code = 0;
6897 env->old_exception = -1;
6898
6899 cpu_loop_exit();
6900}
6901
6902#endif
6903
6904/* MMX/SSE */
6905/* XXX: optimize by storing fptt and fptags in the static cpu state */
6906void helper_enter_mmx(void)
6907{
6908 env->fpstt = 0;
6909 *(uint32_t *)(env->fptags) = 0;
6910 *(uint32_t *)(env->fptags + 4) = 0;
6911}
6912
6913void helper_emms(void)
6914{
6915 /* set to empty state */
6916 *(uint32_t *)(env->fptags) = 0x01010101;
6917 *(uint32_t *)(env->fptags + 4) = 0x01010101;
6918}
6919
6920/* XXX: suppress */
6921void helper_movq(void *d, void *s)
6922{
6923 *(uint64_t *)d = *(uint64_t *)s;
6924}
6925
6926#define SHIFT 0
6927#include "ops_sse.h"
6928
6929#define SHIFT 1
6930#include "ops_sse.h"
6931
6932#define SHIFT 0
6933#include "helper_template.h"
6934#undef SHIFT
6935
6936#define SHIFT 1
6937#include "helper_template.h"
6938#undef SHIFT
6939
6940#define SHIFT 2
6941#include "helper_template.h"
6942#undef SHIFT
6943
6944#ifdef TARGET_X86_64
6945
6946#define SHIFT 3
6947#include "helper_template.h"
6948#undef SHIFT
6949
6950#endif
6951
6952/* bit operations */
6953target_ulong helper_bsf(target_ulong t0)
6954{
6955 int count;
6956 target_ulong res;
6957
6958 res = t0;
6959 count = 0;
6960 while ((res & 1) == 0) {
6961 count++;
6962 res >>= 1;
6963 }
6964 return count;
6965}
6966
6967target_ulong helper_lzcnt(target_ulong t0, int wordsize)
6968{
6969 int count;
6970 target_ulong res, mask;
6971
6972 if (wordsize > 0 && t0 == 0) {
6973 return wordsize;
6974 }
6975 res = t0;
6976 count = TARGET_LONG_BITS - 1;
6977 mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
6978 while ((res & mask) == 0) {
6979 count--;
6980 res <<= 1;
6981 }
6982 if (wordsize > 0) {
6983 return wordsize - 1 - count;
6984 }
6985 return count;
6986}
6987
6988target_ulong helper_bsr(target_ulong t0)
6989{
6990 return helper_lzcnt(t0, 0);
6991}
6992
6993static int compute_all_eflags(void)
6994{
6995 return CC_SRC;
6996}
6997
6998static int compute_c_eflags(void)
6999{
7000 return CC_SRC & CC_C;
7001}
7002
7003uint32_t helper_cc_compute_all(int op)
7004{
7005 switch (op) {
7006 default: /* should never happen */ return 0;
7007
7008 case CC_OP_EFLAGS: return compute_all_eflags();
7009
7010 case CC_OP_MULB: return compute_all_mulb();
7011 case CC_OP_MULW: return compute_all_mulw();
7012 case CC_OP_MULL: return compute_all_mull();
7013
7014 case CC_OP_ADDB: return compute_all_addb();
7015 case CC_OP_ADDW: return compute_all_addw();
7016 case CC_OP_ADDL: return compute_all_addl();
7017
7018 case CC_OP_ADCB: return compute_all_adcb();
7019 case CC_OP_ADCW: return compute_all_adcw();
7020 case CC_OP_ADCL: return compute_all_adcl();
7021
7022 case CC_OP_SUBB: return compute_all_subb();
7023 case CC_OP_SUBW: return compute_all_subw();
7024 case CC_OP_SUBL: return compute_all_subl();
7025
7026 case CC_OP_SBBB: return compute_all_sbbb();
7027 case CC_OP_SBBW: return compute_all_sbbw();
7028 case CC_OP_SBBL: return compute_all_sbbl();
7029
7030 case CC_OP_LOGICB: return compute_all_logicb();
7031 case CC_OP_LOGICW: return compute_all_logicw();
7032 case CC_OP_LOGICL: return compute_all_logicl();
7033
7034 case CC_OP_INCB: return compute_all_incb();
7035 case CC_OP_INCW: return compute_all_incw();
7036 case CC_OP_INCL: return compute_all_incl();
7037
7038 case CC_OP_DECB: return compute_all_decb();
7039 case CC_OP_DECW: return compute_all_decw();
7040 case CC_OP_DECL: return compute_all_decl();
7041
7042 case CC_OP_SHLB: return compute_all_shlb();
7043 case CC_OP_SHLW: return compute_all_shlw();
7044 case CC_OP_SHLL: return compute_all_shll();
7045
7046 case CC_OP_SARB: return compute_all_sarb();
7047 case CC_OP_SARW: return compute_all_sarw();
7048 case CC_OP_SARL: return compute_all_sarl();
7049
7050#ifdef TARGET_X86_64
7051 case CC_OP_MULQ: return compute_all_mulq();
7052
7053 case CC_OP_ADDQ: return compute_all_addq();
7054
7055 case CC_OP_ADCQ: return compute_all_adcq();
7056
7057 case CC_OP_SUBQ: return compute_all_subq();
7058
7059 case CC_OP_SBBQ: return compute_all_sbbq();
7060
7061 case CC_OP_LOGICQ: return compute_all_logicq();
7062
7063 case CC_OP_INCQ: return compute_all_incq();
7064
7065 case CC_OP_DECQ: return compute_all_decq();
7066
7067 case CC_OP_SHLQ: return compute_all_shlq();
7068
7069 case CC_OP_SARQ: return compute_all_sarq();
7070#endif
7071 }
7072}
7073
7074uint32_t helper_cc_compute_c(int op)
7075{
7076 switch (op) {
7077 default: /* should never happen */ return 0;
7078
7079 case CC_OP_EFLAGS: return compute_c_eflags();
7080
7081 case CC_OP_MULB: return compute_c_mull();
7082 case CC_OP_MULW: return compute_c_mull();
7083 case CC_OP_MULL: return compute_c_mull();
7084
7085 case CC_OP_ADDB: return compute_c_addb();
7086 case CC_OP_ADDW: return compute_c_addw();
7087 case CC_OP_ADDL: return compute_c_addl();
7088
7089 case CC_OP_ADCB: return compute_c_adcb();
7090 case CC_OP_ADCW: return compute_c_adcw();
7091 case CC_OP_ADCL: return compute_c_adcl();
7092
7093 case CC_OP_SUBB: return compute_c_subb();
7094 case CC_OP_SUBW: return compute_c_subw();
7095 case CC_OP_SUBL: return compute_c_subl();
7096
7097 case CC_OP_SBBB: return compute_c_sbbb();
7098 case CC_OP_SBBW: return compute_c_sbbw();
7099 case CC_OP_SBBL: return compute_c_sbbl();
7100
7101 case CC_OP_LOGICB: return compute_c_logicb();
7102 case CC_OP_LOGICW: return compute_c_logicw();
7103 case CC_OP_LOGICL: return compute_c_logicl();
7104
7105 case CC_OP_INCB: return compute_c_incl();
7106 case CC_OP_INCW: return compute_c_incl();
7107 case CC_OP_INCL: return compute_c_incl();
7108
7109 case CC_OP_DECB: return compute_c_incl();
7110 case CC_OP_DECW: return compute_c_incl();
7111 case CC_OP_DECL: return compute_c_incl();
7112
7113 case CC_OP_SHLB: return compute_c_shlb();
7114 case CC_OP_SHLW: return compute_c_shlw();
7115 case CC_OP_SHLL: return compute_c_shll();
7116
7117 case CC_OP_SARB: return compute_c_sarl();
7118 case CC_OP_SARW: return compute_c_sarl();
7119 case CC_OP_SARL: return compute_c_sarl();
7120
7121#ifdef TARGET_X86_64
7122 case CC_OP_MULQ: return compute_c_mull();
7123
7124 case CC_OP_ADDQ: return compute_c_addq();
7125
7126 case CC_OP_ADCQ: return compute_c_adcq();
7127
7128 case CC_OP_SUBQ: return compute_c_subq();
7129
7130 case CC_OP_SBBQ: return compute_c_sbbq();
7131
7132 case CC_OP_LOGICQ: return compute_c_logicq();
7133
7134 case CC_OP_INCQ: return compute_c_incl();
7135
7136 case CC_OP_DECQ: return compute_c_incl();
7137
7138 case CC_OP_SHLQ: return compute_c_shlq();
7139
7140 case CC_OP_SARQ: return compute_c_sarl();
7141#endif
7142 }
7143}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette