VirtualBox

source: vbox/trunk/src/recompiler/target-i386/helper.c@ 6475

Last change on this file since 6475 was 6475, checked in by vboxsync, 17 years ago

Added the NoDmik() macro.

  • Property svn:eol-style set to native
File size: 134.4 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#ifdef VBOX
21# include <VBox/err.h>
22#endif
23#include "exec.h"
24
25//#define DEBUG_PCALL
26
27#if 0
28#define raise_exception_err(a, b)\
29do {\
30 if (logfile)\
31 fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
32 (raise_exception_err)(a, b);\
33} while (0)
34#endif
35
36const uint8_t parity_table[256] = {
37 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
40 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
43 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
48 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
56 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
58 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
59 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
60 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
61 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
62 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
64 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
65 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
66 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
67 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
68 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
69};
70
71/* modulo 17 table */
72const uint8_t rclw_table[32] = {
73 0, 1, 2, 3, 4, 5, 6, 7,
74 8, 9,10,11,12,13,14,15,
75 16, 0, 1, 2, 3, 4, 5, 6,
76 7, 8, 9,10,11,12,13,14,
77};
78
79/* modulo 9 table */
80const uint8_t rclb_table[32] = {
81 0, 1, 2, 3, 4, 5, 6, 7,
82 8, 0, 1, 2, 3, 4, 5, 6,
83 7, 8, 0, 1, 2, 3, 4, 5,
84 6, 7, 8, 0, 1, 2, 3, 4,
85};
86
87const CPU86_LDouble f15rk[7] =
88{
89 0.00000000000000000000L,
90 1.00000000000000000000L,
91 3.14159265358979323851L, /*pi*/
92 0.30102999566398119523L, /*lg2*/
93 0.69314718055994530943L, /*ln2*/
94 1.44269504088896340739L, /*l2e*/
95 3.32192809488736234781L, /*l2t*/
96};
97
98/* thread support */
99
100spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
101
102void cpu_lock(void)
103{
104 spin_lock(&global_cpu_lock);
105}
106
107void cpu_unlock(void)
108{
109 spin_unlock(&global_cpu_lock);
110}
111
112void cpu_loop_exit(void)
113{
114 /* NOTE: the register at this point must be saved by hand because
115 longjmp restore them */
116 regs_to_env();
117 longjmp(env->jmp_env, 1);
118}
119
120/* return non zero if error */
121static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
122 int selector)
123{
124 SegmentCache *dt;
125 int index;
126 target_ulong ptr;
127
128 if (selector & 0x4)
129 dt = &env->ldt;
130 else
131 dt = &env->gdt;
132 index = selector & ~7;
133 if ((index + 7) > dt->limit)
134 return -1;
135 ptr = dt->base + index;
136 *e1_ptr = ldl_kernel(ptr);
137 *e2_ptr = ldl_kernel(ptr + 4);
138 return 0;
139}
140
141static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
142{
143 unsigned int limit;
144 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
145 if (e2 & DESC_G_MASK)
146 limit = (limit << 12) | 0xfff;
147 return limit;
148}
149
150static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
151{
152 return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
153}
154
155static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
156{
157 sc->base = get_seg_base(e1, e2);
158 sc->limit = get_seg_limit(e1, e2);
159 sc->flags = e2;
160}
161
162/* init the segment cache in vm86 mode. */
163static inline void load_seg_vm(int seg, int selector)
164{
165 selector &= 0xffff;
166 cpu_x86_load_seg_cache(env, seg, selector,
167 (selector << 4), 0xffff, 0);
168}
169
170static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
171 uint32_t *esp_ptr, int dpl)
172{
173 int type, index, shift;
174
175#if 0
176 {
177 int i;
178 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
179 for(i=0;i<env->tr.limit;i++) {
180 printf("%02x ", env->tr.base[i]);
181 if ((i & 7) == 7) printf("\n");
182 }
183 printf("\n");
184 }
185#endif
186
187 if (!(env->tr.flags & DESC_P_MASK))
188 cpu_abort(env, "invalid tss");
189 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
190 if ((type & 7) != 1)
191 cpu_abort(env, "invalid tss type %d", type);
192 shift = type >> 3;
193 index = (dpl * 4 + 2) << shift;
194 if (index + (4 << shift) - 1 > env->tr.limit)
195 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
196 if (shift == 0) {
197 *esp_ptr = lduw_kernel(env->tr.base + index);
198 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
199 } else {
200 *esp_ptr = ldl_kernel(env->tr.base + index);
201 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
202 }
203}
204
205/* XXX: merge with load_seg() */
206static void tss_load_seg(int seg_reg, int selector)
207{
208 uint32_t e1, e2;
209 int rpl, dpl, cpl;
210
211 if ((selector & 0xfffc) != 0) {
212 if (load_segment(&e1, &e2, selector) != 0)
213 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
214 if (!(e2 & DESC_S_MASK))
215 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
216 rpl = selector & 3;
217 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
218 cpl = env->hflags & HF_CPL_MASK;
219 if (seg_reg == R_CS) {
220 if (!(e2 & DESC_CS_MASK))
221 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
222 /* XXX: is it correct ? */
223 if (dpl != rpl)
224 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
225 if ((e2 & DESC_C_MASK) && dpl > rpl)
226 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
227 } else if (seg_reg == R_SS) {
228 /* SS must be writable data */
229 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
230 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
231 if (dpl != cpl || dpl != rpl)
232 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
233 } else {
234 /* not readable code */
235 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
236 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
237 /* if data or non conforming code, checks the rights */
238 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
239 if (dpl < cpl || dpl < rpl)
240 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
241 }
242 }
243 if (!(e2 & DESC_P_MASK))
244 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
245 cpu_x86_load_seg_cache(env, seg_reg, selector,
246 get_seg_base(e1, e2),
247 get_seg_limit(e1, e2),
248 e2);
249 } else {
250 if (seg_reg == R_SS || seg_reg == R_CS)
251 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
252 }
253}
254
255#define SWITCH_TSS_JMP 0
256#define SWITCH_TSS_IRET 1
257#define SWITCH_TSS_CALL 2
258
259/* XXX: restore CPU state in registers (PowerPC case) */
260static void switch_tss(int tss_selector,
261 uint32_t e1, uint32_t e2, int source,
262 uint32_t next_eip)
263{
264 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
265 target_ulong tss_base;
266 uint32_t new_regs[8], new_segs[6];
267 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
268 uint32_t old_eflags, eflags_mask;
269 SegmentCache *dt;
270 int index;
271 target_ulong ptr;
272
273 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
274#ifdef DEBUG_PCALL
275 if (loglevel & CPU_LOG_PCALL)
276 fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
277#endif
278
279#if defined(VBOX) && defined(DEBUG)
280 printf("switch_tss %x %x %x %d %08x\n", tss_selector, e1, e2, source, next_eip);
281#endif
282
283 /* if task gate, we read the TSS segment and we load it */
284 if (type == 5) {
285 if (!(e2 & DESC_P_MASK))
286 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
287 tss_selector = e1 >> 16;
288 if (tss_selector & 4)
289 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
290 if (load_segment(&e1, &e2, tss_selector) != 0)
291 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
292 if (e2 & DESC_S_MASK)
293 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
294 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
295 if ((type & 7) != 1)
296 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
297 }
298
299 if (!(e2 & DESC_P_MASK))
300 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
301
302 if (type & 8)
303 tss_limit_max = 103;
304 else
305 tss_limit_max = 43;
306 tss_limit = get_seg_limit(e1, e2);
307 tss_base = get_seg_base(e1, e2);
308 if ((tss_selector & 4) != 0 ||
309 tss_limit < tss_limit_max)
310 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
311 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
312 if (old_type & 8)
313 old_tss_limit_max = 103;
314 else
315 old_tss_limit_max = 43;
316
317 /* read all the registers from the new TSS */
318 if (type & 8) {
319 /* 32 bit */
320 new_cr3 = ldl_kernel(tss_base + 0x1c);
321 new_eip = ldl_kernel(tss_base + 0x20);
322 new_eflags = ldl_kernel(tss_base + 0x24);
323 for(i = 0; i < 8; i++)
324 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
325 for(i = 0; i < 6; i++)
326 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
327 new_ldt = lduw_kernel(tss_base + 0x60);
328 new_trap = ldl_kernel(tss_base + 0x64);
329 } else {
330 /* 16 bit */
331 new_cr3 = 0;
332 new_eip = lduw_kernel(tss_base + 0x0e);
333 new_eflags = lduw_kernel(tss_base + 0x10);
334 for(i = 0; i < 8; i++)
335 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
336 for(i = 0; i < 4; i++)
337 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
338 new_ldt = lduw_kernel(tss_base + 0x2a);
339 new_segs[R_FS] = 0;
340 new_segs[R_GS] = 0;
341 new_trap = 0;
342 }
343
344 /* NOTE: we must avoid memory exceptions during the task switch,
345 so we make dummy accesses before */
346 /* XXX: it can still fail in some cases, so a bigger hack is
347 necessary to valid the TLB after having done the accesses */
348
349 v1 = ldub_kernel(env->tr.base);
350 v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
351 stb_kernel(env->tr.base, v1);
352 stb_kernel(env->tr.base + old_tss_limit_max, v2);
353
354 /* clear busy bit (it is restartable) */
355 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
356 target_ulong ptr;
357 uint32_t e2;
358 ptr = env->gdt.base + (env->tr.selector & ~7);
359 e2 = ldl_kernel(ptr + 4);
360 e2 &= ~DESC_TSS_BUSY_MASK;
361 stl_kernel(ptr + 4, e2);
362 }
363 old_eflags = compute_eflags();
364 if (source == SWITCH_TSS_IRET)
365 old_eflags &= ~NT_MASK;
366
367 /* save the current state in the old TSS */
368 if (type & 8) {
369 /* 32 bit */
370 stl_kernel(env->tr.base + 0x20, next_eip);
371 stl_kernel(env->tr.base + 0x24, old_eflags);
372 stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
373 stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
374 stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
375 stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
376 stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
377 stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
378 stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
379 stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
380 for(i = 0; i < 6; i++)
381 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
382#if defined(VBOX) && defined(DEBUG)
383 printf("TSS 32 bits switch\n");
384 printf("Saving CS=%08X\n", env->segs[R_CS].selector);
385#endif
386 } else {
387 /* 16 bit */
388 stw_kernel(env->tr.base + 0x0e, next_eip);
389 stw_kernel(env->tr.base + 0x10, old_eflags);
390 stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
391 stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
392 stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
393 stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
394 stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
395 stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
396 stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
397 stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
398 for(i = 0; i < 4; i++)
399 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
400 }
401
402 /* now if an exception occurs, it will occurs in the next task
403 context */
404
405 if (source == SWITCH_TSS_CALL) {
406 stw_kernel(tss_base, env->tr.selector);
407 new_eflags |= NT_MASK;
408 }
409
410 /* set busy bit */
411 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
412 target_ulong ptr;
413 uint32_t e2;
414 ptr = env->gdt.base + (tss_selector & ~7);
415 e2 = ldl_kernel(ptr + 4);
416 e2 |= DESC_TSS_BUSY_MASK;
417 stl_kernel(ptr + 4, e2);
418 }
419
420 /* set the new CPU state */
421 /* from this point, any exception which occurs can give problems */
422 env->cr[0] |= CR0_TS_MASK;
423 env->hflags |= HF_TS_MASK;
424 env->tr.selector = tss_selector;
425 env->tr.base = tss_base;
426 env->tr.limit = tss_limit;
427 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
428
429 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
430 cpu_x86_update_cr3(env, new_cr3);
431 }
432
433 /* load all registers without an exception, then reload them with
434 possible exception */
435 env->eip = new_eip;
436 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
437 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
438 if (!(type & 8))
439 eflags_mask &= 0xffff;
440 load_eflags(new_eflags, eflags_mask);
441 /* XXX: what to do in 16 bit case ? */
442 EAX = new_regs[0];
443 ECX = new_regs[1];
444 EDX = new_regs[2];
445 EBX = new_regs[3];
446 ESP = new_regs[4];
447 EBP = new_regs[5];
448 ESI = new_regs[6];
449 EDI = new_regs[7];
450 if (new_eflags & VM_MASK) {
451 for(i = 0; i < 6; i++)
452 load_seg_vm(i, new_segs[i]);
453 /* in vm86, CPL is always 3 */
454 cpu_x86_set_cpl(env, 3);
455 } else {
456 /* CPL is set the RPL of CS */
457 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
458 /* first just selectors as the rest may trigger exceptions */
459 for(i = 0; i < 6; i++)
460 cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
461 }
462
463 env->ldt.selector = new_ldt & ~4;
464 env->ldt.base = 0;
465 env->ldt.limit = 0;
466 env->ldt.flags = 0;
467
468 /* load the LDT */
469 if (new_ldt & 4)
470 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
471
472 if ((new_ldt & 0xfffc) != 0) {
473 dt = &env->gdt;
474 index = new_ldt & ~7;
475 if ((index + 7) > dt->limit)
476 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
477 ptr = dt->base + index;
478 e1 = ldl_kernel(ptr);
479 e2 = ldl_kernel(ptr + 4);
480 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
481 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
482 if (!(e2 & DESC_P_MASK))
483 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
484 load_seg_cache_raw_dt(&env->ldt, e1, e2);
485 }
486
487 /* load the segments */
488 if (!(new_eflags & VM_MASK)) {
489 tss_load_seg(R_CS, new_segs[R_CS]);
490 tss_load_seg(R_SS, new_segs[R_SS]);
491 tss_load_seg(R_ES, new_segs[R_ES]);
492 tss_load_seg(R_DS, new_segs[R_DS]);
493 tss_load_seg(R_FS, new_segs[R_FS]);
494 tss_load_seg(R_GS, new_segs[R_GS]);
495 }
496
497 /* check that EIP is in the CS segment limits */
498 if (new_eip > env->segs[R_CS].limit) {
499 /* XXX: different exception if CALL ? */
500 raise_exception_err(EXCP0D_GPF, 0);
501 }
502}
503
504/* check if Port I/O is allowed in TSS */
505static inline void check_io(int addr, int size)
506{
507 int io_offset, val, mask;
508
509 /* TSS must be a valid 32 bit one */
510 if (!(env->tr.flags & DESC_P_MASK) ||
511 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
512 env->tr.limit < 103)
513 goto fail;
514 io_offset = lduw_kernel(env->tr.base + 0x66);
515 io_offset += (addr >> 3);
516 /* Note: the check needs two bytes */
517 if ((io_offset + 1) > env->tr.limit)
518 goto fail;
519 val = lduw_kernel(env->tr.base + io_offset);
520 val >>= (addr & 7);
521 mask = (1 << size) - 1;
522 /* all bits must be zero to allow the I/O */
523 if ((val & mask) != 0) {
524 fail:
525 raise_exception_err(EXCP0D_GPF, 0);
526 }
527}
528
529void check_iob_T0(void)
530{
531 check_io(T0, 1);
532}
533
534void check_iow_T0(void)
535{
536 check_io(T0, 2);
537}
538
539void check_iol_T0(void)
540{
541 check_io(T0, 4);
542}
543
544void check_iob_DX(void)
545{
546 check_io(EDX & 0xffff, 1);
547}
548
549void check_iow_DX(void)
550{
551 check_io(EDX & 0xffff, 2);
552}
553
554void check_iol_DX(void)
555{
556 check_io(EDX & 0xffff, 4);
557}
558
559static inline unsigned int get_sp_mask(unsigned int e2)
560{
561 if (e2 & DESC_B_MASK)
562 return 0xffffffff;
563 else
564 return 0xffff;
565}
566
567#ifdef TARGET_X86_64
568#define SET_ESP(val, sp_mask)\
569do {\
570 if ((sp_mask) == 0xffff)\
571 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
572 else if ((sp_mask) == 0xffffffffLL)\
573 ESP = (uint32_t)(val);\
574 else\
575 ESP = (val);\
576} while (0)
577#else
578#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
579#endif
580
581/* XXX: add a is_user flag to have proper security support */
582#define PUSHW(ssp, sp, sp_mask, val)\
583{\
584 sp -= 2;\
585 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
586}
587
588#define PUSHL(ssp, sp, sp_mask, val)\
589{\
590 sp -= 4;\
591 stl_kernel((ssp) + (sp & (sp_mask)), (val));\
592}
593
594#define POPW(ssp, sp, sp_mask, val)\
595{\
596 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
597 sp += 2;\
598}
599
600#define POPL(ssp, sp, sp_mask, val)\
601{\
602 val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
603 sp += 4;\
604}
605
606/* protected mode interrupt */
607static void do_interrupt_protected(int intno, int is_int, int error_code,
608 unsigned int next_eip, int is_hw)
609{
610 SegmentCache *dt;
611 target_ulong ptr, ssp;
612 int type, dpl, selector, ss_dpl, cpl;
613 int has_error_code, new_stack, shift;
614 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
615 uint32_t old_eip, sp_mask;
616
617#ifdef VBOX
618 if (remR3NotifyTrap(env, intno, error_code, next_eip) != VINF_SUCCESS)
619 cpu_loop_exit();
620#endif
621
622 has_error_code = 0;
623 if (!is_int && !is_hw) {
624 switch(intno) {
625 case 8:
626 case 10:
627 case 11:
628 case 12:
629 case 13:
630 case 14:
631 case 17:
632 has_error_code = 1;
633 break;
634 }
635 }
636 if (is_int)
637 old_eip = next_eip;
638 else
639 old_eip = env->eip;
640
641 dt = &env->idt;
642 if (intno * 8 + 7 > dt->limit)
643 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
644 ptr = dt->base + intno * 8;
645 e1 = ldl_kernel(ptr);
646 e2 = ldl_kernel(ptr + 4);
647 /* check gate type */
648 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
649 switch(type) {
650 case 5: /* task gate */
651 /* must do that check here to return the correct error code */
652 if (!(e2 & DESC_P_MASK))
653 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
654 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
655 if (has_error_code) {
656 int type;
657 uint32_t mask;
658 /* push the error code */
659 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
660 shift = type >> 3;
661 if (env->segs[R_SS].flags & DESC_B_MASK)
662 mask = 0xffffffff;
663 else
664 mask = 0xffff;
665 esp = (ESP - (2 << shift)) & mask;
666 ssp = env->segs[R_SS].base + esp;
667 if (shift)
668 stl_kernel(ssp, error_code);
669 else
670 stw_kernel(ssp, error_code);
671 SET_ESP(esp, mask);
672 }
673 return;
674 case 6: /* 286 interrupt gate */
675 case 7: /* 286 trap gate */
676 case 14: /* 386 interrupt gate */
677 case 15: /* 386 trap gate */
678 break;
679 default:
680 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
681 break;
682 }
683 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
684 cpl = env->hflags & HF_CPL_MASK;
685 /* check privledge if software int */
686 if (is_int && dpl < cpl)
687 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
688 /* check valid bit */
689 if (!(e2 & DESC_P_MASK))
690 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
691 selector = e1 >> 16;
692 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
693 if ((selector & 0xfffc) == 0)
694 raise_exception_err(EXCP0D_GPF, 0);
695
696 if (load_segment(&e1, &e2, selector) != 0)
697 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
698 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
699 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
700 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
701 if (dpl > cpl)
702 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
703 if (!(e2 & DESC_P_MASK))
704 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
705 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
706 /* to inner priviledge */
707 get_ss_esp_from_tss(&ss, &esp, dpl);
708 if ((ss & 0xfffc) == 0)
709 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
710 if ((ss & 3) != dpl)
711 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
712 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
713 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
714 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
715 if (ss_dpl != dpl)
716 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
717 if (!(ss_e2 & DESC_S_MASK) ||
718 (ss_e2 & DESC_CS_MASK) ||
719 !(ss_e2 & DESC_W_MASK))
720 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
721 if (!(ss_e2 & DESC_P_MASK))
722#ifdef VBOX /* See page 3-477 of 253666.pdf */
723 raise_exception_err(EXCP0C_STACK, ss & 0xfffc);
724#else
725 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
726#endif
727 new_stack = 1;
728 sp_mask = get_sp_mask(ss_e2);
729 ssp = get_seg_base(ss_e1, ss_e2);
730#if defined(VBOX) && defined(DEBUG)
731 printf("new stack %04X:%08X gate dpl=%d\n", ss, esp, dpl);
732#endif
733 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
734 /* to same priviledge */
735 if (env->eflags & VM_MASK)
736 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
737 new_stack = 0;
738 sp_mask = get_sp_mask(env->segs[R_SS].flags);
739 ssp = env->segs[R_SS].base;
740 esp = ESP;
741 dpl = cpl;
742 } else {
743 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
744 new_stack = 0; /* avoid warning */
745 sp_mask = 0; /* avoid warning */
746 ssp = 0; /* avoid warning */
747 esp = 0; /* avoid warning */
748 }
749
750 shift = type >> 3;
751
752#if 0
753 /* XXX: check that enough room is available */
754 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
755 if (env->eflags & VM_MASK)
756 push_size += 8;
757 push_size <<= shift;
758#endif
759 if (shift == 1) {
760 if (new_stack) {
761 if (env->eflags & VM_MASK) {
762 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
763 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
764 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
765 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
766 }
767 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
768 PUSHL(ssp, esp, sp_mask, ESP);
769 }
770 PUSHL(ssp, esp, sp_mask, compute_eflags());
771 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
772 PUSHL(ssp, esp, sp_mask, old_eip);
773 if (has_error_code) {
774 PUSHL(ssp, esp, sp_mask, error_code);
775 }
776 } else {
777 if (new_stack) {
778 if (env->eflags & VM_MASK) {
779 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
780 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
781 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
782 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
783 }
784 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
785 PUSHW(ssp, esp, sp_mask, ESP);
786 }
787 PUSHW(ssp, esp, sp_mask, compute_eflags());
788 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
789 PUSHW(ssp, esp, sp_mask, old_eip);
790 if (has_error_code) {
791 PUSHW(ssp, esp, sp_mask, error_code);
792 }
793 }
794
795 if (new_stack) {
796 if (env->eflags & VM_MASK) {
797 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
798 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
799 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
800 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
801 }
802 ss = (ss & ~3) | dpl;
803 cpu_x86_load_seg_cache(env, R_SS, ss,
804 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
805 }
806 SET_ESP(esp, sp_mask);
807
808 selector = (selector & ~3) | dpl;
809 cpu_x86_load_seg_cache(env, R_CS, selector,
810 get_seg_base(e1, e2),
811 get_seg_limit(e1, e2),
812 e2);
813 cpu_x86_set_cpl(env, dpl);
814 env->eip = offset;
815
816 /* interrupt gate clear IF mask */
817 if ((type & 1) == 0) {
818 env->eflags &= ~IF_MASK;
819 }
820 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
821}
822
823#ifdef VBOX
824
825/* check if VME interrupt redirection is enabled in TSS */
826static inline bool is_vme_irq_redirected(int intno)
827{
828 int io_offset, intredir_offset;
829 unsigned char val, mask;
830
831 /* TSS must be a valid 32 bit one */
832 if (!(env->tr.flags & DESC_P_MASK) ||
833 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
834 env->tr.limit < 103)
835 goto fail;
836 io_offset = lduw_kernel(env->tr.base + 0x66);
837 /* the virtual interrupt redirection bitmap is located below the io bitmap */
838 intredir_offset = io_offset - 0x20;
839
840 intredir_offset += (intno >> 3);
841 if ((intredir_offset) > env->tr.limit)
842 goto fail;
843
844 val = ldub_kernel(env->tr.base + intredir_offset);
845 mask = 1 << (unsigned char)(intno & 7);
846
847 /* bit set means no redirection. */
848 if ((val & mask) != 0) {
849 return false;
850 }
851 return true;
852
853fail:
854 raise_exception_err(EXCP0D_GPF, 0);
855 return true;
856}
857
858/* V86 mode software interrupt with CR4.VME=1 */
859static void do_soft_interrupt_vme(int intno, int error_code, unsigned int next_eip)
860{
861 target_ulong ptr, ssp;
862 int selector;
863 uint32_t offset, esp;
864 uint32_t old_cs, old_eflags;
865 uint32_t iopl;
866
867 iopl = ((env->eflags >> IOPL_SHIFT) & 3);
868
869 if (!is_vme_irq_redirected(intno))
870 {
871 if (iopl == 3)
872 /* normal protected mode handler call */
873 return do_interrupt_protected(intno, 1, error_code, next_eip, 0);
874 else
875 raise_exception_err(EXCP0D_GPF, 0);
876 }
877
878 /* virtual mode idt is at linear address 0 */
879 ptr = 0 + intno * 4;
880 offset = lduw_kernel(ptr);
881 selector = lduw_kernel(ptr + 2);
882 esp = ESP;
883 ssp = env->segs[R_SS].base;
884 old_cs = env->segs[R_CS].selector;
885
886 old_eflags = compute_eflags();
887 if (iopl < 3)
888 {
889 /* copy VIF into IF and set IOPL to 3 */
890 if (env->eflags & VIF_MASK)
891 old_eflags |= IF_MASK;
892 else
893 old_eflags &= ~IF_MASK;
894
895 old_eflags |= (3 << IOPL_SHIFT);
896 }
897
898 /* XXX: use SS segment size ? */
899 PUSHW(ssp, esp, 0xffff, old_eflags);
900 PUSHW(ssp, esp, 0xffff, old_cs);
901 PUSHW(ssp, esp, 0xffff, next_eip);
902
903 /* update processor state */
904 ESP = (ESP & ~0xffff) | (esp & 0xffff);
905 env->eip = offset;
906 env->segs[R_CS].selector = selector;
907 env->segs[R_CS].base = (selector << 4);
908 env->eflags &= ~(TF_MASK | RF_MASK);
909
910 if (iopl < 3)
911 env->eflags &= ~VIF_MASK;
912 else
913 env->eflags &= ~IF_MASK;
914}
915#endif /* VBOX */
916
917#ifdef TARGET_X86_64
918
919#define PUSHQ(sp, val)\
920{\
921 sp -= 8;\
922 stq_kernel(sp, (val));\
923}
924
925#define POPQ(sp, val)\
926{\
927 val = ldq_kernel(sp);\
928 sp += 8;\
929}
930
931static inline target_ulong get_rsp_from_tss(int level)
932{
933 int index;
934
935#if 0
936 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
937 env->tr.base, env->tr.limit);
938#endif
939
940 if (!(env->tr.flags & DESC_P_MASK))
941 cpu_abort(env, "invalid tss");
942 index = 8 * level + 4;
943 if ((index + 7) > env->tr.limit)
944 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
945 return ldq_kernel(env->tr.base + index);
946}
947
948/* 64 bit interrupt */
949static void do_interrupt64(int intno, int is_int, int error_code,
950 target_ulong next_eip, int is_hw)
951{
952 SegmentCache *dt;
953 target_ulong ptr;
954 int type, dpl, selector, cpl, ist;
955 int has_error_code, new_stack;
956 uint32_t e1, e2, e3, ss;
957 target_ulong old_eip, esp, offset;
958
959 has_error_code = 0;
960 if (!is_int && !is_hw) {
961 switch(intno) {
962 case 8:
963 case 10:
964 case 11:
965 case 12:
966 case 13:
967 case 14:
968 case 17:
969 has_error_code = 1;
970 break;
971 }
972 }
973 if (is_int)
974 old_eip = next_eip;
975 else
976 old_eip = env->eip;
977
978 dt = &env->idt;
979 if (intno * 16 + 15 > dt->limit)
980 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
981 ptr = dt->base + intno * 16;
982 e1 = ldl_kernel(ptr);
983 e2 = ldl_kernel(ptr + 4);
984 e3 = ldl_kernel(ptr + 8);
985 /* check gate type */
986 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
987 switch(type) {
988 case 14: /* 386 interrupt gate */
989 case 15: /* 386 trap gate */
990 break;
991 default:
992 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
993 break;
994 }
995 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
996 cpl = env->hflags & HF_CPL_MASK;
997 /* check privledge if software int */
998 if (is_int && dpl < cpl)
999 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
1000 /* check valid bit */
1001 if (!(e2 & DESC_P_MASK))
1002 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
1003 selector = e1 >> 16;
1004 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1005 ist = e2 & 7;
1006 if ((selector & 0xfffc) == 0)
1007 raise_exception_err(EXCP0D_GPF, 0);
1008
1009 if (load_segment(&e1, &e2, selector) != 0)
1010 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1011 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1012 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1013 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1014 if (dpl > cpl)
1015 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1016 if (!(e2 & DESC_P_MASK))
1017 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1018 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
1019 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1020 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
1021 /* to inner priviledge */
1022 if (ist != 0)
1023 esp = get_rsp_from_tss(ist + 3);
1024 else
1025 esp = get_rsp_from_tss(dpl);
1026 esp &= ~0xfLL; /* align stack */
1027 ss = 0;
1028 new_stack = 1;
1029 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
1030 /* to same priviledge */
1031 if (env->eflags & VM_MASK)
1032 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1033 new_stack = 0;
1034 if (ist != 0)
1035 esp = get_rsp_from_tss(ist + 3);
1036 else
1037 esp = ESP;
1038 esp &= ~0xfLL; /* align stack */
1039 dpl = cpl;
1040 } else {
1041 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1042 new_stack = 0; /* avoid warning */
1043 esp = 0; /* avoid warning */
1044 }
1045
1046 PUSHQ(esp, env->segs[R_SS].selector);
1047 PUSHQ(esp, ESP);
1048 PUSHQ(esp, compute_eflags());
1049 PUSHQ(esp, env->segs[R_CS].selector);
1050 PUSHQ(esp, old_eip);
1051 if (has_error_code) {
1052 PUSHQ(esp, error_code);
1053 }
1054
1055 if (new_stack) {
1056 ss = 0 | dpl;
1057 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
1058 }
1059 ESP = esp;
1060
1061 selector = (selector & ~3) | dpl;
1062 cpu_x86_load_seg_cache(env, R_CS, selector,
1063 get_seg_base(e1, e2),
1064 get_seg_limit(e1, e2),
1065 e2);
1066 cpu_x86_set_cpl(env, dpl);
1067 env->eip = offset;
1068
1069 /* interrupt gate clear IF mask */
1070 if ((type & 1) == 0) {
1071 env->eflags &= ~IF_MASK;
1072 }
1073 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
1074}
1075#endif
1076
1077void helper_syscall(int next_eip_addend)
1078{
1079 int selector;
1080
1081 if (!(env->efer & MSR_EFER_SCE)) {
1082 raise_exception_err(EXCP06_ILLOP, 0);
1083 }
1084 selector = (env->star >> 32) & 0xffff;
1085#ifdef TARGET_X86_64
1086 if (env->hflags & HF_LMA_MASK) {
1087 int code64;
1088
1089 ECX = env->eip + next_eip_addend;
1090 env->regs[11] = compute_eflags();
1091
1092 code64 = env->hflags & HF_CS64_MASK;
1093
1094 cpu_x86_set_cpl(env, 0);
1095 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1096 0, 0xffffffff,
1097 DESC_G_MASK | DESC_P_MASK |
1098 DESC_S_MASK |
1099 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1100 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1101 0, 0xffffffff,
1102 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1103 DESC_S_MASK |
1104 DESC_W_MASK | DESC_A_MASK);
1105 env->eflags &= ~env->fmask;
1106 if (code64)
1107 env->eip = env->lstar;
1108 else
1109 env->eip = env->cstar;
1110 } else
1111#endif
1112 {
1113 ECX = (uint32_t)(env->eip + next_eip_addend);
1114
1115 cpu_x86_set_cpl(env, 0);
1116 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1117 0, 0xffffffff,
1118 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1119 DESC_S_MASK |
1120 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1121 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1122 0, 0xffffffff,
1123 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1124 DESC_S_MASK |
1125 DESC_W_MASK | DESC_A_MASK);
1126 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1127 env->eip = (uint32_t)env->star;
1128 }
1129}
1130
1131void helper_sysret(int dflag)
1132{
1133 int cpl, selector;
1134
1135 if (!(env->efer & MSR_EFER_SCE)) {
1136 raise_exception_err(EXCP06_ILLOP, 0);
1137 }
1138 cpl = env->hflags & HF_CPL_MASK;
1139 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1140 raise_exception_err(EXCP0D_GPF, 0);
1141 }
1142 selector = (env->star >> 48) & 0xffff;
1143#ifdef TARGET_X86_64
1144 if (env->hflags & HF_LMA_MASK) {
1145 if (dflag == 2) {
1146 cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1147 0, 0xffffffff,
1148 DESC_G_MASK | DESC_P_MASK |
1149 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1150 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1151 DESC_L_MASK);
1152 env->eip = ECX;
1153 } else {
1154 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1155 0, 0xffffffff,
1156 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1157 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1158 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1159 env->eip = (uint32_t)ECX;
1160 }
1161 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1162 0, 0xffffffff,
1163 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1164 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1165 DESC_W_MASK | DESC_A_MASK);
1166 load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1167 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1168 cpu_x86_set_cpl(env, 3);
1169 } else
1170#endif
1171 {
1172 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1173 0, 0xffffffff,
1174 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1175 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1176 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1177 env->eip = (uint32_t)ECX;
1178 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1179 0, 0xffffffff,
1180 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1181 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1182 DESC_W_MASK | DESC_A_MASK);
1183 env->eflags |= IF_MASK;
1184 cpu_x86_set_cpl(env, 3);
1185 }
1186#ifdef USE_KQEMU
1187 if (kqemu_is_ok(env)) {
1188 if (env->hflags & HF_LMA_MASK)
1189 CC_OP = CC_OP_EFLAGS;
1190 env->exception_index = -1;
1191 cpu_loop_exit();
1192 }
1193#endif
1194}
1195
1196#ifdef VBOX
1197/**
1198 * Checks and processes external VMM events.
1199 * Called by op_check_external_event() when any of the flags is set and can be serviced.
1200 */
1201void helper_external_event(void)
1202{
1203#if defined(RT_OS_DARWIN) && defined(VBOX_STRICT)
1204 uintptr_t uESP;
1205 __asm__ __volatile__("movl %%esp, %0" : "=r" (uESP));
1206 AssertMsg(!(uESP & 15), ("esp=%#p\n", uESP));
1207#endif
1208 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_HARD)
1209 {
1210 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXTERNAL_HARD);
1211 cpu_interrupt(env, CPU_INTERRUPT_HARD);
1212 }
1213 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_EXIT)
1214 {
1215 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXTERNAL_EXIT);
1216 cpu_interrupt(env, CPU_INTERRUPT_EXIT);
1217 }
1218 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_DMA)
1219 {
1220 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXTERNAL_DMA);
1221 remR3DmaRun(env);
1222 }
1223 if (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_TIMER)
1224 {
1225 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXTERNAL_TIMER);
1226 remR3TimersRun(env);
1227 }
1228}
1229/* helper for recording call instruction addresses for later scanning */
1230void helper_record_call()
1231{
1232 if ( !(env->state & CPU_RAW_RING0)
1233 && (env->cr[0] & CR0_PG_MASK)
1234 && !(env->eflags & X86_EFL_IF))
1235 remR3RecordCall(env);
1236}
1237#endif /* VBOX */
1238
1239/* real mode interrupt */
1240static void do_interrupt_real(int intno, int is_int, int error_code,
1241 unsigned int next_eip)
1242{
1243 SegmentCache *dt;
1244 target_ulong ptr, ssp;
1245 int selector;
1246 uint32_t offset, esp;
1247 uint32_t old_cs, old_eip;
1248
1249 /* real mode (simpler !) */
1250 dt = &env->idt;
1251 if (intno * 4 + 3 > dt->limit)
1252 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1253 ptr = dt->base + intno * 4;
1254 offset = lduw_kernel(ptr);
1255 selector = lduw_kernel(ptr + 2);
1256 esp = ESP;
1257 ssp = env->segs[R_SS].base;
1258 if (is_int)
1259 old_eip = next_eip;
1260 else
1261 old_eip = env->eip;
1262 old_cs = env->segs[R_CS].selector;
1263 /* XXX: use SS segment size ? */
1264 PUSHW(ssp, esp, 0xffff, compute_eflags());
1265 PUSHW(ssp, esp, 0xffff, old_cs);
1266 PUSHW(ssp, esp, 0xffff, old_eip);
1267
1268 /* update processor state */
1269 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1270 env->eip = offset;
1271 env->segs[R_CS].selector = selector;
1272 env->segs[R_CS].base = (selector << 4);
1273 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1274}
1275
1276/* fake user mode interrupt */
1277void do_interrupt_user(int intno, int is_int, int error_code,
1278 target_ulong next_eip)
1279{
1280 SegmentCache *dt;
1281 target_ulong ptr;
1282 int dpl, cpl;
1283 uint32_t e2;
1284
1285 dt = &env->idt;
1286 ptr = dt->base + (intno * 8);
1287 e2 = ldl_kernel(ptr + 4);
1288
1289 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1290 cpl = env->hflags & HF_CPL_MASK;
1291 /* check privledge if software int */
1292 if (is_int && dpl < cpl)
1293 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1294
1295 /* Since we emulate only user space, we cannot do more than
1296 exiting the emulation with the suitable exception and error
1297 code */
1298 if (is_int)
1299 EIP = next_eip;
1300}
1301
1302/*
1303 * Begin execution of an interruption. is_int is TRUE if coming from
1304 * the int instruction. next_eip is the EIP value AFTER the interrupt
1305 * instruction. It is only relevant if is_int is TRUE.
1306 */
1307void do_interrupt(int intno, int is_int, int error_code,
1308 target_ulong next_eip, int is_hw)
1309{
1310 if (loglevel & CPU_LOG_INT) {
1311 if ((env->cr[0] & CR0_PE_MASK)) {
1312 static int count;
1313 fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1314 count, intno, error_code, is_int,
1315 env->hflags & HF_CPL_MASK,
1316 env->segs[R_CS].selector, EIP,
1317 (int)env->segs[R_CS].base + EIP,
1318 env->segs[R_SS].selector, ESP);
1319 if (intno == 0x0e) {
1320 fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1321 } else {
1322 fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1323 }
1324 fprintf(logfile, "\n");
1325 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1326#if 0
1327 {
1328 int i;
1329 uint8_t *ptr;
1330 fprintf(logfile, " code=");
1331 ptr = env->segs[R_CS].base + env->eip;
1332 for(i = 0; i < 16; i++) {
1333 fprintf(logfile, " %02x", ldub(ptr + i));
1334 }
1335 fprintf(logfile, "\n");
1336 }
1337#endif
1338 count++;
1339 }
1340 }
1341 if (env->cr[0] & CR0_PE_MASK) {
1342#if TARGET_X86_64
1343 if (env->hflags & HF_LMA_MASK) {
1344 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1345 } else
1346#endif
1347 {
1348#ifdef VBOX
1349 /* int xx *, v86 code and VME enabled? */
1350 if ( (env->eflags & VM_MASK)
1351 && (env->cr[4] & CR4_VME_MASK)
1352 && is_int
1353 && !is_hw
1354 && env->eip + 1 != next_eip /* single byte int 3 goes straight to the protected mode handler */
1355 )
1356 do_soft_interrupt_vme(intno, error_code, next_eip);
1357 else
1358#endif /* VBOX */
1359 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1360 }
1361 } else {
1362 do_interrupt_real(intno, is_int, error_code, next_eip);
1363 }
1364}
1365
1366/*
1367 * Signal an interruption. It is executed in the main CPU loop.
1368 * is_int is TRUE if coming from the int instruction. next_eip is the
1369 * EIP value AFTER the interrupt instruction. It is only relevant if
1370 * is_int is TRUE.
1371 */
1372void raise_interrupt(int intno, int is_int, int error_code,
1373 int next_eip_addend)
1374{
1375#if defined(VBOX) && defined(DEBUG)
1376 NoDmik(Log2(("raise_interrupt: %x %x %x %08x\n", intno, is_int, error_code, env->eip + next_eip_addend)));
1377#endif
1378 env->exception_index = intno;
1379 env->error_code = error_code;
1380 env->exception_is_int = is_int;
1381 env->exception_next_eip = env->eip + next_eip_addend;
1382 cpu_loop_exit();
1383}
1384
1385/* same as raise_exception_err, but do not restore global registers */
1386static void raise_exception_err_norestore(int exception_index, int error_code)
1387{
1388 env->exception_index = exception_index;
1389 env->error_code = error_code;
1390 env->exception_is_int = 0;
1391 env->exception_next_eip = 0;
1392 longjmp(env->jmp_env, 1);
1393}
1394
1395/* shortcuts to generate exceptions */
1396
1397void (raise_exception_err)(int exception_index, int error_code)
1398{
1399 raise_interrupt(exception_index, 0, error_code, 0);
1400}
1401
1402void raise_exception(int exception_index)
1403{
1404 raise_interrupt(exception_index, 0, 0, 0);
1405}
1406
1407/* SMM support */
1408
1409#if defined(CONFIG_USER_ONLY)
1410
1411void do_smm_enter(void)
1412{
1413}
1414
1415void helper_rsm(void)
1416{
1417}
1418
1419#else
1420
1421#ifdef TARGET_X86_64
1422#define SMM_REVISION_ID 0x00020064
1423#else
1424#define SMM_REVISION_ID 0x00020000
1425#endif
1426
1427void do_smm_enter(void)
1428{
1429#ifdef VBOX
1430 cpu_abort(env, "do_ssm_enter");
1431#else /* !VBOX */
1432 target_ulong sm_state;
1433 SegmentCache *dt;
1434 int i, offset;
1435
1436 if (loglevel & CPU_LOG_INT) {
1437 fprintf(logfile, "SMM: enter\n");
1438 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1439 }
1440
1441 env->hflags |= HF_SMM_MASK;
1442 cpu_smm_update(env);
1443
1444 sm_state = env->smbase + 0x8000;
1445
1446#ifdef TARGET_X86_64
1447 for(i = 0; i < 6; i++) {
1448 dt = &env->segs[i];
1449 offset = 0x7e00 + i * 16;
1450 stw_phys(sm_state + offset, dt->selector);
1451 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1452 stl_phys(sm_state + offset + 4, dt->limit);
1453 stq_phys(sm_state + offset + 8, dt->base);
1454 }
1455
1456 stq_phys(sm_state + 0x7e68, env->gdt.base);
1457 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1458
1459 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1460 stq_phys(sm_state + 0x7e78, env->ldt.base);
1461 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1462 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1463
1464 stq_phys(sm_state + 0x7e88, env->idt.base);
1465 stl_phys(sm_state + 0x7e84, env->idt.limit);
1466
1467 stw_phys(sm_state + 0x7e90, env->tr.selector);
1468 stq_phys(sm_state + 0x7e98, env->tr.base);
1469 stl_phys(sm_state + 0x7e94, env->tr.limit);
1470 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1471
1472 stq_phys(sm_state + 0x7ed0, env->efer);
1473
1474 stq_phys(sm_state + 0x7ff8, EAX);
1475 stq_phys(sm_state + 0x7ff0, ECX);
1476 stq_phys(sm_state + 0x7fe8, EDX);
1477 stq_phys(sm_state + 0x7fe0, EBX);
1478 stq_phys(sm_state + 0x7fd8, ESP);
1479 stq_phys(sm_state + 0x7fd0, EBP);
1480 stq_phys(sm_state + 0x7fc8, ESI);
1481 stq_phys(sm_state + 0x7fc0, EDI);
1482 for(i = 8; i < 16; i++)
1483 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1484 stq_phys(sm_state + 0x7f78, env->eip);
1485 stl_phys(sm_state + 0x7f70, compute_eflags());
1486 stl_phys(sm_state + 0x7f68, env->dr[6]);
1487 stl_phys(sm_state + 0x7f60, env->dr[7]);
1488
1489 stl_phys(sm_state + 0x7f48, env->cr[4]);
1490 stl_phys(sm_state + 0x7f50, env->cr[3]);
1491 stl_phys(sm_state + 0x7f58, env->cr[0]);
1492
1493 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1494 stl_phys(sm_state + 0x7f00, env->smbase);
1495#else
1496 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1497 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1498 stl_phys(sm_state + 0x7ff4, compute_eflags());
1499 stl_phys(sm_state + 0x7ff0, env->eip);
1500 stl_phys(sm_state + 0x7fec, EDI);
1501 stl_phys(sm_state + 0x7fe8, ESI);
1502 stl_phys(sm_state + 0x7fe4, EBP);
1503 stl_phys(sm_state + 0x7fe0, ESP);
1504 stl_phys(sm_state + 0x7fdc, EBX);
1505 stl_phys(sm_state + 0x7fd8, EDX);
1506 stl_phys(sm_state + 0x7fd4, ECX);
1507 stl_phys(sm_state + 0x7fd0, EAX);
1508 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1509 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1510
1511 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1512 stl_phys(sm_state + 0x7f64, env->tr.base);
1513 stl_phys(sm_state + 0x7f60, env->tr.limit);
1514 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1515
1516 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1517 stl_phys(sm_state + 0x7f80, env->ldt.base);
1518 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1519 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1520
1521 stl_phys(sm_state + 0x7f74, env->gdt.base);
1522 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1523
1524 stl_phys(sm_state + 0x7f58, env->idt.base);
1525 stl_phys(sm_state + 0x7f54, env->idt.limit);
1526
1527 for(i = 0; i < 6; i++) {
1528 dt = &env->segs[i];
1529 if (i < 3)
1530 offset = 0x7f84 + i * 12;
1531 else
1532 offset = 0x7f2c + (i - 3) * 12;
1533 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1534 stl_phys(sm_state + offset + 8, dt->base);
1535 stl_phys(sm_state + offset + 4, dt->limit);
1536 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1537 }
1538 stl_phys(sm_state + 0x7f14, env->cr[4]);
1539
1540 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1541 stl_phys(sm_state + 0x7ef8, env->smbase);
1542#endif
1543 /* init SMM cpu state */
1544
1545#ifdef TARGET_X86_64
1546 env->efer = 0;
1547 env->hflags &= ~HF_LMA_MASK;
1548#endif
1549 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1550 env->eip = 0x00008000;
1551 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1552 0xffffffff, 0);
1553 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1554 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1555 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1556 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1557 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1558
1559 cpu_x86_update_cr0(env,
1560 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1561 cpu_x86_update_cr4(env, 0);
1562 env->dr[7] = 0x00000400;
1563 CC_OP = CC_OP_EFLAGS;
1564#endif /* VBOX */
1565}
1566
1567void helper_rsm(void)
1568{
1569#ifdef VBOX
1570 cpu_abort(env, "helper_rsm");
1571#else /* !VBOX */
1572 target_ulong sm_state;
1573 int i, offset;
1574 uint32_t val;
1575
1576 sm_state = env->smbase + 0x8000;
1577#ifdef TARGET_X86_64
1578 env->efer = ldq_phys(sm_state + 0x7ed0);
1579 if (env->efer & MSR_EFER_LMA)
1580 env->hflags |= HF_LMA_MASK;
1581 else
1582 env->hflags &= ~HF_LMA_MASK;
1583
1584 for(i = 0; i < 6; i++) {
1585 offset = 0x7e00 + i * 16;
1586 cpu_x86_load_seg_cache(env, i,
1587 lduw_phys(sm_state + offset),
1588 ldq_phys(sm_state + offset + 8),
1589 ldl_phys(sm_state + offset + 4),
1590 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1591 }
1592
1593 env->gdt.base = ldq_phys(sm_state + 0x7e68);
1594 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1595
1596 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1597 env->ldt.base = ldq_phys(sm_state + 0x7e78);
1598 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1599 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1600
1601 env->idt.base = ldq_phys(sm_state + 0x7e88);
1602 env->idt.limit = ldl_phys(sm_state + 0x7e84);
1603
1604 env->tr.selector = lduw_phys(sm_state + 0x7e90);
1605 env->tr.base = ldq_phys(sm_state + 0x7e98);
1606 env->tr.limit = ldl_phys(sm_state + 0x7e94);
1607 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1608
1609 EAX = ldq_phys(sm_state + 0x7ff8);
1610 ECX = ldq_phys(sm_state + 0x7ff0);
1611 EDX = ldq_phys(sm_state + 0x7fe8);
1612 EBX = ldq_phys(sm_state + 0x7fe0);
1613 ESP = ldq_phys(sm_state + 0x7fd8);
1614 EBP = ldq_phys(sm_state + 0x7fd0);
1615 ESI = ldq_phys(sm_state + 0x7fc8);
1616 EDI = ldq_phys(sm_state + 0x7fc0);
1617 for(i = 8; i < 16; i++)
1618 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1619 env->eip = ldq_phys(sm_state + 0x7f78);
1620 load_eflags(ldl_phys(sm_state + 0x7f70),
1621 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1622 env->dr[6] = ldl_phys(sm_state + 0x7f68);
1623 env->dr[7] = ldl_phys(sm_state + 0x7f60);
1624
1625 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1626 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1627 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1628
1629 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1630 if (val & 0x20000) {
1631 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1632 }
1633#else
1634 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1635 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1636 load_eflags(ldl_phys(sm_state + 0x7ff4),
1637 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1638 env->eip = ldl_phys(sm_state + 0x7ff0);
1639 EDI = ldl_phys(sm_state + 0x7fec);
1640 ESI = ldl_phys(sm_state + 0x7fe8);
1641 EBP = ldl_phys(sm_state + 0x7fe4);
1642 ESP = ldl_phys(sm_state + 0x7fe0);
1643 EBX = ldl_phys(sm_state + 0x7fdc);
1644 EDX = ldl_phys(sm_state + 0x7fd8);
1645 ECX = ldl_phys(sm_state + 0x7fd4);
1646 EAX = ldl_phys(sm_state + 0x7fd0);
1647 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1648 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1649
1650 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1651 env->tr.base = ldl_phys(sm_state + 0x7f64);
1652 env->tr.limit = ldl_phys(sm_state + 0x7f60);
1653 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1654
1655 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1656 env->ldt.base = ldl_phys(sm_state + 0x7f80);
1657 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1658 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1659
1660 env->gdt.base = ldl_phys(sm_state + 0x7f74);
1661 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1662
1663 env->idt.base = ldl_phys(sm_state + 0x7f58);
1664 env->idt.limit = ldl_phys(sm_state + 0x7f54);
1665
1666 for(i = 0; i < 6; i++) {
1667 if (i < 3)
1668 offset = 0x7f84 + i * 12;
1669 else
1670 offset = 0x7f2c + (i - 3) * 12;
1671 cpu_x86_load_seg_cache(env, i,
1672 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1673 ldl_phys(sm_state + offset + 8),
1674 ldl_phys(sm_state + offset + 4),
1675 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1676 }
1677 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1678
1679 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1680 if (val & 0x20000) {
1681 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1682 }
1683#endif
1684 CC_OP = CC_OP_EFLAGS;
1685 env->hflags &= ~HF_SMM_MASK;
1686 cpu_smm_update(env);
1687
1688 if (loglevel & CPU_LOG_INT) {
1689 fprintf(logfile, "SMM: after RSM\n");
1690 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1691 }
1692#endif /* !VBOX */
1693}
1694
1695#endif /* !CONFIG_USER_ONLY */
1696
1697
1698#ifdef BUGGY_GCC_DIV64
1699/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1700 call it from another function */
1701uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1702{
1703 *q_ptr = num / den;
1704 return num % den;
1705}
1706
1707int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1708{
1709 *q_ptr = num / den;
1710 return num % den;
1711}
1712#endif
1713
1714void helper_divl_EAX_T0(void)
1715{
1716 unsigned int den, r;
1717 uint64_t num, q;
1718
1719 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1720 den = T0;
1721 if (den == 0) {
1722 raise_exception(EXCP00_DIVZ);
1723 }
1724#ifdef BUGGY_GCC_DIV64
1725 r = div32(&q, num, den);
1726#else
1727 q = (num / den);
1728 r = (num % den);
1729#endif
1730 if (q > 0xffffffff)
1731 raise_exception(EXCP00_DIVZ);
1732 EAX = (uint32_t)q;
1733 EDX = (uint32_t)r;
1734}
1735
1736void helper_idivl_EAX_T0(void)
1737{
1738 int den, r;
1739 int64_t num, q;
1740
1741 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1742 den = T0;
1743 if (den == 0) {
1744 raise_exception(EXCP00_DIVZ);
1745 }
1746#ifdef BUGGY_GCC_DIV64
1747 r = idiv32(&q, num, den);
1748#else
1749 q = (num / den);
1750 r = (num % den);
1751#endif
1752 if (q != (int32_t)q)
1753 raise_exception(EXCP00_DIVZ);
1754 EAX = (uint32_t)q;
1755 EDX = (uint32_t)r;
1756}
1757
1758void helper_cmpxchg8b(void)
1759{
1760 uint64_t d;
1761 int eflags;
1762
1763 eflags = cc_table[CC_OP].compute_all();
1764 d = ldq(A0);
1765 if (d == (((uint64_t)EDX << 32) | EAX)) {
1766 stq(A0, ((uint64_t)ECX << 32) | EBX);
1767 eflags |= CC_Z;
1768 } else {
1769 EDX = d >> 32;
1770 EAX = d;
1771 eflags &= ~CC_Z;
1772 }
1773 CC_SRC = eflags;
1774}
1775
1776void helper_cpuid(void)
1777{
1778#ifndef VBOX
1779 uint32_t index;
1780 index = (uint32_t)EAX;
1781
1782 /* test if maximum index reached */
1783 if (index & 0x80000000) {
1784 if (index > env->cpuid_xlevel)
1785 index = env->cpuid_level;
1786 } else {
1787 if (index > env->cpuid_level)
1788 index = env->cpuid_level;
1789 }
1790
1791 switch(index) {
1792 case 0:
1793 EAX = env->cpuid_level;
1794 EBX = env->cpuid_vendor1;
1795 EDX = env->cpuid_vendor2;
1796 ECX = env->cpuid_vendor3;
1797 break;
1798 case 1:
1799 EAX = env->cpuid_version;
1800 EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
1801 ECX = env->cpuid_ext_features;
1802 EDX = env->cpuid_features;
1803 break;
1804 case 2:
1805 /* cache info: needed for Pentium Pro compatibility */
1806 EAX = 0x410601;
1807 EBX = 0;
1808 ECX = 0;
1809 EDX = 0;
1810 break;
1811 case 0x80000000:
1812 EAX = env->cpuid_xlevel;
1813 EBX = env->cpuid_vendor1;
1814 EDX = env->cpuid_vendor2;
1815 ECX = env->cpuid_vendor3;
1816 break;
1817 case 0x80000001:
1818 EAX = env->cpuid_features;
1819 EBX = 0;
1820 ECX = 0;
1821 EDX = env->cpuid_ext2_features;
1822 break;
1823 case 0x80000002:
1824 case 0x80000003:
1825 case 0x80000004:
1826 EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
1827 EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
1828 ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
1829 EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
1830 break;
1831 case 0x80000005:
1832 /* cache info (L1 cache) */
1833 EAX = 0x01ff01ff;
1834 EBX = 0x01ff01ff;
1835 ECX = 0x40020140;
1836 EDX = 0x40020140;
1837 break;
1838 case 0x80000006:
1839 /* cache info (L2 cache) */
1840 EAX = 0;
1841 EBX = 0x42004200;
1842 ECX = 0x02008140;
1843 EDX = 0;
1844 break;
1845 case 0x80000008:
1846 /* virtual & phys address size in low 2 bytes. */
1847 EAX = 0x00003028;
1848 EBX = 0;
1849 ECX = 0;
1850 EDX = 0;
1851 break;
1852 default:
1853 /* reserved values: zero */
1854 EAX = 0;
1855 EBX = 0;
1856 ECX = 0;
1857 EDX = 0;
1858 break;
1859 }
1860#else /* VBOX */
1861 remR3CpuId(env, EAX, &EAX, &EBX, &ECX, &EDX);
1862#endif /* VBOX */
1863}
1864
1865void helper_enter_level(int level, int data32)
1866{
1867 target_ulong ssp;
1868 uint32_t esp_mask, esp, ebp;
1869
1870 esp_mask = get_sp_mask(env->segs[R_SS].flags);
1871 ssp = env->segs[R_SS].base;
1872 ebp = EBP;
1873 esp = ESP;
1874 if (data32) {
1875 /* 32 bit */
1876 esp -= 4;
1877 while (--level) {
1878 esp -= 4;
1879 ebp -= 4;
1880 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1881 }
1882 esp -= 4;
1883 stl(ssp + (esp & esp_mask), T1);
1884 } else {
1885 /* 16 bit */
1886 esp -= 2;
1887 while (--level) {
1888 esp -= 2;
1889 ebp -= 2;
1890 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1891 }
1892 esp -= 2;
1893 stw(ssp + (esp & esp_mask), T1);
1894 }
1895}
1896
1897#ifdef TARGET_X86_64
1898void helper_enter64_level(int level, int data64)
1899{
1900 target_ulong esp, ebp;
1901 ebp = EBP;
1902 esp = ESP;
1903
1904 if (data64) {
1905 /* 64 bit */
1906 esp -= 8;
1907 while (--level) {
1908 esp -= 8;
1909 ebp -= 8;
1910 stq(esp, ldq(ebp));
1911 }
1912 esp -= 8;
1913 stq(esp, T1);
1914 } else {
1915 /* 16 bit */
1916 esp -= 2;
1917 while (--level) {
1918 esp -= 2;
1919 ebp -= 2;
1920 stw(esp, lduw(ebp));
1921 }
1922 esp -= 2;
1923 stw(esp, T1);
1924 }
1925}
1926#endif
1927
1928void helper_lldt_T0(void)
1929{
1930 int selector;
1931 SegmentCache *dt;
1932 uint32_t e1, e2;
1933 int index, entry_limit;
1934 target_ulong ptr;
1935#ifdef VBOX
1936 Log(("helper_lldt_T0: old ldtr=%RTsel {.base=%VGv, .limit=%VGv} new=%RTsel\n",
1937 (RTSEL)env->ldt.selector, (RTGCPTR)env->ldt.base, (RTGCPTR)env->ldt.limit, (RTSEL)(T0 & 0xffff)));
1938#endif
1939
1940 selector = T0 & 0xffff;
1941 if ((selector & 0xfffc) == 0) {
1942 /* XXX: NULL selector case: invalid LDT */
1943 env->ldt.base = 0;
1944 env->ldt.limit = 0;
1945 } else {
1946 if (selector & 0x4)
1947 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1948 dt = &env->gdt;
1949 index = selector & ~7;
1950#ifdef TARGET_X86_64
1951 if (env->hflags & HF_LMA_MASK)
1952 entry_limit = 15;
1953 else
1954#endif
1955 entry_limit = 7;
1956 if ((index + entry_limit) > dt->limit)
1957 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1958 ptr = dt->base + index;
1959 e1 = ldl_kernel(ptr);
1960 e2 = ldl_kernel(ptr + 4);
1961 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1962 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1963 if (!(e2 & DESC_P_MASK))
1964 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1965#ifdef TARGET_X86_64
1966 if (env->hflags & HF_LMA_MASK) {
1967 uint32_t e3;
1968 e3 = ldl_kernel(ptr + 8);
1969 load_seg_cache_raw_dt(&env->ldt, e1, e2);
1970 env->ldt.base |= (target_ulong)e3 << 32;
1971 } else
1972#endif
1973 {
1974 load_seg_cache_raw_dt(&env->ldt, e1, e2);
1975 }
1976 }
1977 env->ldt.selector = selector;
1978#ifdef VBOX
1979 Log(("helper_lldt_T0: new ldtr=%RTsel {.base=%VGv, .limit=%VGv}\n",
1980 (RTSEL)env->ldt.selector, (RTGCPTR)env->ldt.base, (RTGCPTR)env->ldt.limit));
1981#endif
1982}
1983
1984void helper_ltr_T0(void)
1985{
1986 int selector;
1987 SegmentCache *dt;
1988 uint32_t e1, e2;
1989 int index, type, entry_limit;
1990 target_ulong ptr;
1991
1992#ifdef VBOX
1993 Log(("helper_ltr_T0: old tr=%RTsel {.base=%VGv, .limit=%VGv, .flags=%RX32} new=%RTsel\n",
1994 (RTSEL)env->tr.selector, (RTGCPTR)env->tr.base, (RTGCPTR)env->tr.limit,
1995 env->tr.flags, (RTSEL)(T0 & 0xffff)));
1996#endif
1997
1998 selector = T0 & 0xffff;
1999 if ((selector & 0xfffc) == 0) {
2000 /* NULL selector case: invalid TR */
2001 env->tr.base = 0;
2002 env->tr.limit = 0;
2003 env->tr.flags = 0;
2004 } else {
2005 if (selector & 0x4)
2006 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2007 dt = &env->gdt;
2008 index = selector & ~7;
2009#ifdef TARGET_X86_64
2010 if (env->hflags & HF_LMA_MASK)
2011 entry_limit = 15;
2012 else
2013#endif
2014 entry_limit = 7;
2015 if ((index + entry_limit) > dt->limit)
2016 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2017 ptr = dt->base + index;
2018 e1 = ldl_kernel(ptr);
2019 e2 = ldl_kernel(ptr + 4);
2020 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2021 if ((e2 & DESC_S_MASK) ||
2022 (type != 1 && type != 9))
2023 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2024 if (!(e2 & DESC_P_MASK))
2025 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2026#ifdef TARGET_X86_64
2027 if (env->hflags & HF_LMA_MASK) {
2028 uint32_t e3;
2029 e3 = ldl_kernel(ptr + 8);
2030 load_seg_cache_raw_dt(&env->tr, e1, e2);
2031 env->tr.base |= (target_ulong)e3 << 32;
2032 } else
2033#endif
2034 {
2035 load_seg_cache_raw_dt(&env->tr, e1, e2);
2036 }
2037 e2 |= DESC_TSS_BUSY_MASK;
2038 stl_kernel(ptr + 4, e2);
2039 }
2040 env->tr.selector = selector;
2041#ifdef VBOX
2042 Log(("helper_ltr_T0: new tr=%RTsel {.base=%VGv, .limit=%VGv, .flags=%RX32} new=%RTsel\n",
2043 (RTSEL)env->tr.selector, (RTGCPTR)env->tr.base, (RTGCPTR)env->tr.limit,
2044 env->tr.flags, (RTSEL)(T0 & 0xffff)));
2045#endif
2046}
2047
2048/* only works if protected mode and not VM86. seg_reg must be != R_CS */
2049void load_seg(int seg_reg, int selector)
2050{
2051 uint32_t e1, e2;
2052 int cpl, dpl, rpl;
2053 SegmentCache *dt;
2054 int index;
2055 target_ulong ptr;
2056
2057 selector &= 0xffff;
2058 cpl = env->hflags & HF_CPL_MASK;
2059
2060#ifdef VBOX
2061 /* Trying to load a selector with CPL=1? */
2062 if (cpl == 0 && (selector & 3) == 1 && (env->state & CPU_RAW_RING0))
2063 {
2064 Log(("RPL 1 -> sel %04X -> %04X\n", selector, selector & 0xfffc));
2065 selector = selector & 0xfffc;
2066 }
2067#endif
2068
2069 if ((selector & 0xfffc) == 0) {
2070 /* null selector case */
2071 if (seg_reg == R_SS
2072#ifdef TARGET_X86_64
2073 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2074#endif
2075 )
2076 raise_exception_err(EXCP0D_GPF, 0);
2077 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2078 } else {
2079
2080 if (selector & 0x4)
2081 dt = &env->ldt;
2082 else
2083 dt = &env->gdt;
2084 index = selector & ~7;
2085 if ((index + 7) > dt->limit)
2086 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2087 ptr = dt->base + index;
2088 e1 = ldl_kernel(ptr);
2089 e2 = ldl_kernel(ptr + 4);
2090
2091 if (!(e2 & DESC_S_MASK))
2092 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2093 rpl = selector & 3;
2094 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2095 if (seg_reg == R_SS) {
2096 /* must be writable segment */
2097 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2098 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2099 if (rpl != cpl || dpl != cpl)
2100 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2101 } else {
2102 /* must be readable segment */
2103 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2104 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2105
2106 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2107 /* if not conforming code, test rights */
2108 if (dpl < cpl || dpl < rpl)
2109 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2110 }
2111 }
2112
2113 if (!(e2 & DESC_P_MASK)) {
2114 if (seg_reg == R_SS)
2115 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2116 else
2117 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2118 }
2119
2120 /* set the access bit if not already set */
2121 if (!(e2 & DESC_A_MASK)) {
2122 e2 |= DESC_A_MASK;
2123 stl_kernel(ptr + 4, e2);
2124 }
2125
2126 cpu_x86_load_seg_cache(env, seg_reg, selector,
2127 get_seg_base(e1, e2),
2128 get_seg_limit(e1, e2),
2129 e2);
2130#if 0
2131 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2132 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2133#endif
2134 }
2135}
2136
2137/* protected mode jump */
2138void helper_ljmp_protected_T0_T1(int next_eip_addend)
2139{
2140 int new_cs, gate_cs, type;
2141 uint32_t e1, e2, cpl, dpl, rpl, limit;
2142 target_ulong new_eip, next_eip;
2143
2144 new_cs = T0;
2145 new_eip = T1;
2146 if ((new_cs & 0xfffc) == 0)
2147 raise_exception_err(EXCP0D_GPF, 0);
2148 if (load_segment(&e1, &e2, new_cs) != 0)
2149 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2150 cpl = env->hflags & HF_CPL_MASK;
2151 if (e2 & DESC_S_MASK) {
2152 if (!(e2 & DESC_CS_MASK))
2153 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2154 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2155 if (e2 & DESC_C_MASK) {
2156 /* conforming code segment */
2157 if (dpl > cpl)
2158 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2159 } else {
2160 /* non conforming code segment */
2161 rpl = new_cs & 3;
2162 if (rpl > cpl)
2163 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2164 if (dpl != cpl)
2165 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2166 }
2167 if (!(e2 & DESC_P_MASK))
2168 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2169 limit = get_seg_limit(e1, e2);
2170 if (new_eip > limit &&
2171 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2172 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2173 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2174 get_seg_base(e1, e2), limit, e2);
2175 EIP = new_eip;
2176 } else {
2177 /* jump to call or task gate */
2178 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2179 rpl = new_cs & 3;
2180 cpl = env->hflags & HF_CPL_MASK;
2181 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2182 switch(type) {
2183 case 1: /* 286 TSS */
2184 case 9: /* 386 TSS */
2185 case 5: /* task gate */
2186 if (dpl < cpl || dpl < rpl)
2187 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2188 next_eip = env->eip + next_eip_addend;
2189 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2190 CC_OP = CC_OP_EFLAGS;
2191 break;
2192 case 4: /* 286 call gate */
2193 case 12: /* 386 call gate */
2194 if ((dpl < cpl) || (dpl < rpl))
2195 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2196 if (!(e2 & DESC_P_MASK))
2197 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2198 gate_cs = e1 >> 16;
2199 new_eip = (e1 & 0xffff);
2200 if (type == 12)
2201 new_eip |= (e2 & 0xffff0000);
2202 if (load_segment(&e1, &e2, gate_cs) != 0)
2203 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2204 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2205 /* must be code segment */
2206 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2207 (DESC_S_MASK | DESC_CS_MASK)))
2208 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2209 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2210 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2211 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2212 if (!(e2 & DESC_P_MASK))
2213#ifdef VBOX /* See page 3-514 of 253666.pdf */
2214 raise_exception_err(EXCP0B_NOSEG, gate_cs & 0xfffc);
2215#else
2216 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2217#endif
2218 limit = get_seg_limit(e1, e2);
2219 if (new_eip > limit)
2220 raise_exception_err(EXCP0D_GPF, 0);
2221 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2222 get_seg_base(e1, e2), limit, e2);
2223 EIP = new_eip;
2224 break;
2225 default:
2226 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2227 break;
2228 }
2229 }
2230}
2231
2232/* real mode call */
2233void helper_lcall_real_T0_T1(int shift, int next_eip)
2234{
2235 int new_cs, new_eip;
2236 uint32_t esp, esp_mask;
2237 target_ulong ssp;
2238
2239 new_cs = T0;
2240 new_eip = T1;
2241 esp = ESP;
2242 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2243 ssp = env->segs[R_SS].base;
2244 if (shift) {
2245 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2246 PUSHL(ssp, esp, esp_mask, next_eip);
2247 } else {
2248 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2249 PUSHW(ssp, esp, esp_mask, next_eip);
2250 }
2251
2252 SET_ESP(esp, esp_mask);
2253 env->eip = new_eip;
2254 env->segs[R_CS].selector = new_cs;
2255 env->segs[R_CS].base = (new_cs << 4);
2256}
2257
2258/* protected mode call */
2259void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
2260{
2261 int new_cs, new_stack, i;
2262 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2263 uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2264 uint32_t val, limit, old_sp_mask;
2265 target_ulong ssp, old_ssp, next_eip, new_eip;
2266
2267 new_cs = T0;
2268 new_eip = T1;
2269 next_eip = env->eip + next_eip_addend;
2270#ifdef DEBUG_PCALL
2271 if (loglevel & CPU_LOG_PCALL) {
2272 fprintf(logfile, "lcall %04x:%08x s=%d\n",
2273 new_cs, (uint32_t)new_eip, shift);
2274 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2275 }
2276#endif
2277 if ((new_cs & 0xfffc) == 0)
2278 raise_exception_err(EXCP0D_GPF, 0);
2279 if (load_segment(&e1, &e2, new_cs) != 0)
2280 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2281 cpl = env->hflags & HF_CPL_MASK;
2282#ifdef DEBUG_PCALL
2283 if (loglevel & CPU_LOG_PCALL) {
2284 fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2285 }
2286#endif
2287 if (e2 & DESC_S_MASK) {
2288 if (!(e2 & DESC_CS_MASK))
2289 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2290 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2291 if (e2 & DESC_C_MASK) {
2292 /* conforming code segment */
2293 if (dpl > cpl)
2294 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2295 } else {
2296 /* non conforming code segment */
2297 rpl = new_cs & 3;
2298 if (rpl > cpl)
2299 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2300 if (dpl != cpl)
2301 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2302 }
2303 if (!(e2 & DESC_P_MASK))
2304 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2305
2306#ifdef TARGET_X86_64
2307 /* XXX: check 16/32 bit cases in long mode */
2308 if (shift == 2) {
2309 target_ulong rsp;
2310 /* 64 bit case */
2311 rsp = ESP;
2312 PUSHQ(rsp, env->segs[R_CS].selector);
2313 PUSHQ(rsp, next_eip);
2314 /* from this point, not restartable */
2315 ESP = rsp;
2316 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2317 get_seg_base(e1, e2),
2318 get_seg_limit(e1, e2), e2);
2319 EIP = new_eip;
2320 } else
2321#endif
2322 {
2323 sp = ESP;
2324 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2325 ssp = env->segs[R_SS].base;
2326 if (shift) {
2327 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2328 PUSHL(ssp, sp, sp_mask, next_eip);
2329 } else {
2330 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2331 PUSHW(ssp, sp, sp_mask, next_eip);
2332 }
2333
2334 limit = get_seg_limit(e1, e2);
2335 if (new_eip > limit)
2336 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2337 /* from this point, not restartable */
2338 SET_ESP(sp, sp_mask);
2339 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2340 get_seg_base(e1, e2), limit, e2);
2341 EIP = new_eip;
2342 }
2343 } else {
2344 /* check gate type */
2345 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2346 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2347 rpl = new_cs & 3;
2348 switch(type) {
2349 case 1: /* available 286 TSS */
2350 case 9: /* available 386 TSS */
2351 case 5: /* task gate */
2352 if (dpl < cpl || dpl < rpl)
2353 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2354 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2355 CC_OP = CC_OP_EFLAGS;
2356 return;
2357 case 4: /* 286 call gate */
2358 case 12: /* 386 call gate */
2359 break;
2360 default:
2361 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2362 break;
2363 }
2364 shift = type >> 3;
2365
2366 if (dpl < cpl || dpl < rpl)
2367 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2368 /* check valid bit */
2369 if (!(e2 & DESC_P_MASK))
2370 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2371 selector = e1 >> 16;
2372 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2373 param_count = e2 & 0x1f;
2374 if ((selector & 0xfffc) == 0)
2375 raise_exception_err(EXCP0D_GPF, 0);
2376
2377 if (load_segment(&e1, &e2, selector) != 0)
2378 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2379 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2380 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2381 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2382 if (dpl > cpl)
2383 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2384 if (!(e2 & DESC_P_MASK))
2385 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2386
2387 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2388 /* to inner priviledge */
2389 get_ss_esp_from_tss(&ss, &sp, dpl);
2390#ifdef DEBUG_PCALL
2391 if (loglevel & CPU_LOG_PCALL)
2392 fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2393 ss, sp, param_count, ESP);
2394#endif
2395 if ((ss & 0xfffc) == 0)
2396 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2397 if ((ss & 3) != dpl)
2398 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2399 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2400 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2401 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2402 if (ss_dpl != dpl)
2403 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2404 if (!(ss_e2 & DESC_S_MASK) ||
2405 (ss_e2 & DESC_CS_MASK) ||
2406 !(ss_e2 & DESC_W_MASK))
2407 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2408 if (!(ss_e2 & DESC_P_MASK))
2409#ifdef VBOX /* See page 3-99 of 253666.pdf */
2410 raise_exception_err(EXCP0C_STACK, ss & 0xfffc);
2411#else
2412 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2413#endif
2414
2415 // push_size = ((param_count * 2) + 8) << shift;
2416
2417 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2418 old_ssp = env->segs[R_SS].base;
2419
2420 sp_mask = get_sp_mask(ss_e2);
2421 ssp = get_seg_base(ss_e1, ss_e2);
2422 if (shift) {
2423 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2424 PUSHL(ssp, sp, sp_mask, ESP);
2425 for(i = param_count - 1; i >= 0; i--) {
2426 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2427 PUSHL(ssp, sp, sp_mask, val);
2428 }
2429 } else {
2430 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2431 PUSHW(ssp, sp, sp_mask, ESP);
2432 for(i = param_count - 1; i >= 0; i--) {
2433 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2434 PUSHW(ssp, sp, sp_mask, val);
2435 }
2436 }
2437 new_stack = 1;
2438 } else {
2439 /* to same priviledge */
2440 sp = ESP;
2441 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2442 ssp = env->segs[R_SS].base;
2443 // push_size = (4 << shift);
2444 new_stack = 0;
2445 }
2446
2447 if (shift) {
2448 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2449 PUSHL(ssp, sp, sp_mask, next_eip);
2450 } else {
2451 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2452 PUSHW(ssp, sp, sp_mask, next_eip);
2453 }
2454
2455 /* from this point, not restartable */
2456
2457 if (new_stack) {
2458 ss = (ss & ~3) | dpl;
2459 cpu_x86_load_seg_cache(env, R_SS, ss,
2460 ssp,
2461 get_seg_limit(ss_e1, ss_e2),
2462 ss_e2);
2463 }
2464
2465 selector = (selector & ~3) | dpl;
2466 cpu_x86_load_seg_cache(env, R_CS, selector,
2467 get_seg_base(e1, e2),
2468 get_seg_limit(e1, e2),
2469 e2);
2470 cpu_x86_set_cpl(env, dpl);
2471 SET_ESP(sp, sp_mask);
2472 EIP = offset;
2473 }
2474#ifdef USE_KQEMU
2475 if (kqemu_is_ok(env)) {
2476 env->exception_index = -1;
2477 cpu_loop_exit();
2478 }
2479#endif
2480}
2481
2482/* real and vm86 mode iret */
2483void helper_iret_real(int shift)
2484{
2485 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2486 target_ulong ssp;
2487 int eflags_mask;
2488#ifdef VBOX
2489 bool fVME = false;
2490
2491 remR3TrapClear(env->pVM);
2492#endif /* VBOX */
2493
2494 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2495 sp = ESP;
2496 ssp = env->segs[R_SS].base;
2497 if (shift == 1) {
2498 /* 32 bits */
2499 POPL(ssp, sp, sp_mask, new_eip);
2500 POPL(ssp, sp, sp_mask, new_cs);
2501 new_cs &= 0xffff;
2502 POPL(ssp, sp, sp_mask, new_eflags);
2503 } else {
2504 /* 16 bits */
2505 POPW(ssp, sp, sp_mask, new_eip);
2506 POPW(ssp, sp, sp_mask, new_cs);
2507 POPW(ssp, sp, sp_mask, new_eflags);
2508 }
2509#ifdef VBOX
2510 if ( (env->eflags & VM_MASK)
2511 && ((env->eflags >> IOPL_SHIFT) & 3) != 3
2512 && (env->cr[4] & CR4_VME_MASK)) /* implied or else we would fault earlier */
2513 {
2514 fVME = true;
2515 /* if virtual interrupt pending and (virtual) interrupts will be enabled -> #GP */
2516 /* if TF will be set -> #GP */
2517 if ( ((new_eflags & IF_MASK) && (env->eflags & VIP_MASK))
2518 || (new_eflags & TF_MASK))
2519 raise_exception(EXCP0D_GPF);
2520 }
2521#endif /* VBOX */
2522
2523 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2524 load_seg_vm(R_CS, new_cs);
2525 env->eip = new_eip;
2526#ifdef VBOX
2527 if (fVME)
2528 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2529 else
2530#endif
2531 if (env->eflags & VM_MASK)
2532 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2533 else
2534 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2535 if (shift == 0)
2536 eflags_mask &= 0xffff;
2537 load_eflags(new_eflags, eflags_mask);
2538
2539#ifdef VBOX
2540 if (fVME)
2541 {
2542 if (new_eflags & IF_MASK)
2543 env->eflags |= VIF_MASK;
2544 else
2545 env->eflags &= ~VIF_MASK;
2546 }
2547#endif /* VBOX */
2548}
2549
2550static inline void validate_seg(int seg_reg, int cpl)
2551{
2552 int dpl;
2553 uint32_t e2;
2554
2555 /* XXX: on x86_64, we do not want to nullify FS and GS because
2556 they may still contain a valid base. I would be interested to
2557 know how a real x86_64 CPU behaves */
2558 if ((seg_reg == R_FS || seg_reg == R_GS) &&
2559 (env->segs[seg_reg].selector & 0xfffc) == 0)
2560 return;
2561
2562 e2 = env->segs[seg_reg].flags;
2563 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2564 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2565 /* data or non conforming code segment */
2566 if (dpl < cpl) {
2567 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2568 }
2569 }
2570}
2571
2572/* protected mode iret */
2573static inline void helper_ret_protected(int shift, int is_iret, int addend)
2574{
2575 uint32_t new_cs, new_eflags, new_ss;
2576 uint32_t new_es, new_ds, new_fs, new_gs;
2577 uint32_t e1, e2, ss_e1, ss_e2;
2578 int cpl, dpl, rpl, eflags_mask, iopl;
2579 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2580
2581#ifdef TARGET_X86_64
2582 if (shift == 2)
2583 sp_mask = -1;
2584 else
2585#endif
2586 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2587 sp = ESP;
2588 ssp = env->segs[R_SS].base;
2589 new_eflags = 0; /* avoid warning */
2590#ifdef TARGET_X86_64
2591 if (shift == 2) {
2592 POPQ(sp, new_eip);
2593 POPQ(sp, new_cs);
2594 new_cs &= 0xffff;
2595 if (is_iret) {
2596 POPQ(sp, new_eflags);
2597 }
2598 } else
2599#endif
2600 if (shift == 1) {
2601 /* 32 bits */
2602 POPL(ssp, sp, sp_mask, new_eip);
2603 POPL(ssp, sp, sp_mask, new_cs);
2604 new_cs &= 0xffff;
2605 if (is_iret) {
2606 POPL(ssp, sp, sp_mask, new_eflags);
2607#if defined(VBOX) && defined(DEBUG)
2608 printf("iret: new CS %04X\n", new_cs);
2609 printf("iret: new EIP %08X\n", new_eip);
2610 printf("iret: new EFLAGS %08X\n", new_eflags);
2611 printf("iret: EAX=%08x\n", EAX);
2612#endif
2613
2614 if (new_eflags & VM_MASK)
2615 goto return_to_vm86;
2616 }
2617#ifdef VBOX
2618 if ((new_cs & 0x3) == 1 && (env->state & CPU_RAW_RING0))
2619 {
2620#ifdef DEBUG
2621 printf("RPL 1 -> new_cs %04X -> %04X\n", new_cs, new_cs & 0xfffc);
2622#endif
2623 new_cs = new_cs & 0xfffc;
2624 }
2625#endif
2626 } else {
2627 /* 16 bits */
2628 POPW(ssp, sp, sp_mask, new_eip);
2629 POPW(ssp, sp, sp_mask, new_cs);
2630 if (is_iret)
2631 POPW(ssp, sp, sp_mask, new_eflags);
2632 }
2633#ifdef DEBUG_PCALL
2634 if (loglevel & CPU_LOG_PCALL) {
2635 fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2636 new_cs, new_eip, shift, addend);
2637 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2638 }
2639#endif
2640 if ((new_cs & 0xfffc) == 0)
2641 {
2642#if defined(VBOX) && defined(DEBUG)
2643 printf("new_cs & 0xfffc) == 0\n");
2644#endif
2645 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2646 }
2647 if (load_segment(&e1, &e2, new_cs) != 0)
2648 {
2649#if defined(VBOX) && defined(DEBUG)
2650 printf("load_segment failed\n");
2651#endif
2652 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2653 }
2654 if (!(e2 & DESC_S_MASK) ||
2655 !(e2 & DESC_CS_MASK))
2656 {
2657#if defined(VBOX) && defined(DEBUG)
2658 printf("e2 mask %08x\n", e2);
2659#endif
2660 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2661 }
2662 cpl = env->hflags & HF_CPL_MASK;
2663 rpl = new_cs & 3;
2664 if (rpl < cpl)
2665 {
2666#if defined(VBOX) && defined(DEBUG)
2667 printf("rpl < cpl (%d vs %d)\n", rpl, cpl);
2668#endif
2669 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2670 }
2671 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2672 if (e2 & DESC_C_MASK) {
2673 if (dpl > rpl)
2674 {
2675#if defined(VBOX) && defined(DEBUG)
2676 printf("dpl > rpl (%d vs %d)\n", dpl, rpl);
2677#endif
2678 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2679 }
2680 } else {
2681 if (dpl != rpl)
2682 {
2683#if defined(VBOX) && defined(DEBUG)
2684 printf("dpl != rpl (%d vs %d) e1=%x e2=%x\n", dpl, rpl, e1, e2);
2685#endif
2686 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2687 }
2688 }
2689 if (!(e2 & DESC_P_MASK))
2690 {
2691#if defined(VBOX) && defined(DEBUG)
2692 printf("DESC_P_MASK e2=%08x\n", e2);
2693#endif
2694 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2695 }
2696 sp += addend;
2697 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2698 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2699 /* return to same priledge level */
2700 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2701 get_seg_base(e1, e2),
2702 get_seg_limit(e1, e2),
2703 e2);
2704 } else {
2705 /* return to different priviledge level */
2706#ifdef TARGET_X86_64
2707 if (shift == 2) {
2708 POPQ(sp, new_esp);
2709 POPQ(sp, new_ss);
2710 new_ss &= 0xffff;
2711 } else
2712#endif
2713 if (shift == 1) {
2714 /* 32 bits */
2715 POPL(ssp, sp, sp_mask, new_esp);
2716 POPL(ssp, sp, sp_mask, new_ss);
2717 new_ss &= 0xffff;
2718 } else {
2719 /* 16 bits */
2720 POPW(ssp, sp, sp_mask, new_esp);
2721 POPW(ssp, sp, sp_mask, new_ss);
2722 }
2723#ifdef DEBUG_PCALL
2724 if (loglevel & CPU_LOG_PCALL) {
2725 fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2726 new_ss, new_esp);
2727 }
2728#endif
2729 if ((new_ss & 0xfffc) == 0) {
2730#ifdef TARGET_X86_64
2731 /* NULL ss is allowed in long mode if cpl != 3*/
2732 /* XXX: test CS64 ? */
2733 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2734 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2735 0, 0xffffffff,
2736 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2737 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2738 DESC_W_MASK | DESC_A_MASK);
2739 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2740 } else
2741#endif
2742 {
2743 raise_exception_err(EXCP0D_GPF, 0);
2744 }
2745 } else {
2746 if ((new_ss & 3) != rpl)
2747 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2748 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2749 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2750 if (!(ss_e2 & DESC_S_MASK) ||
2751 (ss_e2 & DESC_CS_MASK) ||
2752 !(ss_e2 & DESC_W_MASK))
2753 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2754 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2755 if (dpl != rpl)
2756 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2757 if (!(ss_e2 & DESC_P_MASK))
2758 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2759 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2760 get_seg_base(ss_e1, ss_e2),
2761 get_seg_limit(ss_e1, ss_e2),
2762 ss_e2);
2763 }
2764
2765 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2766 get_seg_base(e1, e2),
2767 get_seg_limit(e1, e2),
2768 e2);
2769 cpu_x86_set_cpl(env, rpl);
2770 sp = new_esp;
2771#ifdef TARGET_X86_64
2772 if (env->hflags & HF_CS64_MASK)
2773 sp_mask = -1;
2774 else
2775#endif
2776 sp_mask = get_sp_mask(ss_e2);
2777
2778 /* validate data segments */
2779 validate_seg(R_ES, rpl);
2780 validate_seg(R_DS, rpl);
2781 validate_seg(R_FS, rpl);
2782 validate_seg(R_GS, rpl);
2783
2784 sp += addend;
2785 }
2786 SET_ESP(sp, sp_mask);
2787 env->eip = new_eip;
2788 if (is_iret) {
2789 /* NOTE: 'cpl' is the _old_ CPL */
2790 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2791 if (cpl == 0)
2792#ifdef VBOX
2793 eflags_mask |= IOPL_MASK | VIF_MASK | VIP_MASK;
2794#else
2795 eflags_mask |= IOPL_MASK;
2796#endif
2797 iopl = (env->eflags >> IOPL_SHIFT) & 3;
2798 if (cpl <= iopl)
2799 eflags_mask |= IF_MASK;
2800 if (shift == 0)
2801 eflags_mask &= 0xffff;
2802 load_eflags(new_eflags, eflags_mask);
2803 }
2804 return;
2805
2806 return_to_vm86:
2807
2808#if 0 // defined(VBOX) && defined(DEBUG)
2809 printf("V86: new CS %04X\n", new_cs);
2810 printf("V86: Descriptor %08X:%08X\n", e2, e1);
2811 printf("V86: new EIP %08X\n", new_eip);
2812 printf("V86: new EFLAGS %08X\n", new_eflags);
2813#endif
2814
2815 POPL(ssp, sp, sp_mask, new_esp);
2816 POPL(ssp, sp, sp_mask, new_ss);
2817 POPL(ssp, sp, sp_mask, new_es);
2818 POPL(ssp, sp, sp_mask, new_ds);
2819 POPL(ssp, sp, sp_mask, new_fs);
2820 POPL(ssp, sp, sp_mask, new_gs);
2821
2822 /* modify processor state */
2823 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2824 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2825 load_seg_vm(R_CS, new_cs & 0xffff);
2826 cpu_x86_set_cpl(env, 3);
2827 load_seg_vm(R_SS, new_ss & 0xffff);
2828 load_seg_vm(R_ES, new_es & 0xffff);
2829 load_seg_vm(R_DS, new_ds & 0xffff);
2830 load_seg_vm(R_FS, new_fs & 0xffff);
2831 load_seg_vm(R_GS, new_gs & 0xffff);
2832
2833 env->eip = new_eip & 0xffff;
2834 ESP = new_esp;
2835}
2836
2837void helper_iret_protected(int shift, int next_eip)
2838{
2839 int tss_selector, type;
2840 uint32_t e1, e2;
2841
2842#ifdef VBOX
2843 remR3TrapClear(env->pVM);
2844#endif
2845
2846 /* specific case for TSS */
2847 if (env->eflags & NT_MASK) {
2848#ifdef TARGET_X86_64
2849 if (env->hflags & HF_LMA_MASK)
2850 raise_exception_err(EXCP0D_GPF, 0);
2851#endif
2852 tss_selector = lduw_kernel(env->tr.base + 0);
2853 if (tss_selector & 4)
2854 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2855 if (load_segment(&e1, &e2, tss_selector) != 0)
2856 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2857 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2858 /* NOTE: we check both segment and busy TSS */
2859 if (type != 3)
2860 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2861 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2862 } else {
2863 helper_ret_protected(shift, 1, 0);
2864 }
2865#ifdef USE_KQEMU
2866 if (kqemu_is_ok(env)) {
2867 CC_OP = CC_OP_EFLAGS;
2868 env->exception_index = -1;
2869 cpu_loop_exit();
2870 }
2871#endif
2872}
2873
2874void helper_lret_protected(int shift, int addend)
2875{
2876 helper_ret_protected(shift, 0, addend);
2877#ifdef USE_KQEMU
2878 if (kqemu_is_ok(env)) {
2879 env->exception_index = -1;
2880 cpu_loop_exit();
2881 }
2882#endif
2883}
2884
2885void helper_sysenter(void)
2886{
2887 if (env->sysenter_cs == 0) {
2888 raise_exception_err(EXCP0D_GPF, 0);
2889 }
2890 env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2891 cpu_x86_set_cpl(env, 0);
2892 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2893 0, 0xffffffff,
2894 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2895 DESC_S_MASK |
2896 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2897 cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2898 0, 0xffffffff,
2899 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2900 DESC_S_MASK |
2901 DESC_W_MASK | DESC_A_MASK);
2902 ESP = env->sysenter_esp;
2903 EIP = env->sysenter_eip;
2904}
2905
2906void helper_sysexit(void)
2907{
2908 int cpl;
2909
2910 cpl = env->hflags & HF_CPL_MASK;
2911 if (env->sysenter_cs == 0 || cpl != 0) {
2912 raise_exception_err(EXCP0D_GPF, 0);
2913 }
2914 cpu_x86_set_cpl(env, 3);
2915 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2916 0, 0xffffffff,
2917 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2918 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2919 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2920 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2921 0, 0xffffffff,
2922 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2923 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2924 DESC_W_MASK | DESC_A_MASK);
2925 ESP = ECX;
2926 EIP = EDX;
2927#ifdef USE_KQEMU
2928 if (kqemu_is_ok(env)) {
2929 env->exception_index = -1;
2930 cpu_loop_exit();
2931 }
2932#endif
2933}
2934
2935void helper_movl_crN_T0(int reg)
2936{
2937#if !defined(CONFIG_USER_ONLY)
2938 switch(reg) {
2939 case 0:
2940 cpu_x86_update_cr0(env, T0);
2941 break;
2942 case 3:
2943 cpu_x86_update_cr3(env, T0);
2944 break;
2945 case 4:
2946 cpu_x86_update_cr4(env, T0);
2947 break;
2948 case 8:
2949 cpu_set_apic_tpr(env, T0);
2950 break;
2951 default:
2952 env->cr[reg] = T0;
2953 break;
2954 }
2955#endif
2956}
2957
2958/* XXX: do more */
2959void helper_movl_drN_T0(int reg)
2960{
2961 env->dr[reg] = T0;
2962}
2963
2964void helper_invlpg(target_ulong addr)
2965{
2966 cpu_x86_flush_tlb(env, addr);
2967}
2968
2969void helper_rdtsc(void)
2970{
2971 uint64_t val;
2972
2973 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2974 raise_exception(EXCP0D_GPF);
2975 }
2976 val = cpu_get_tsc(env);
2977 EAX = (uint32_t)(val);
2978 EDX = (uint32_t)(val >> 32);
2979}
2980
2981#if defined(CONFIG_USER_ONLY)
2982void helper_wrmsr(void)
2983{
2984}
2985
2986void helper_rdmsr(void)
2987{
2988}
2989#else
2990void helper_wrmsr(void)
2991{
2992 uint64_t val;
2993
2994 val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2995
2996 switch((uint32_t)ECX) {
2997 case MSR_IA32_SYSENTER_CS:
2998 env->sysenter_cs = val & 0xffff;
2999 break;
3000 case MSR_IA32_SYSENTER_ESP:
3001 env->sysenter_esp = val;
3002 break;
3003 case MSR_IA32_SYSENTER_EIP:
3004 env->sysenter_eip = val;
3005 break;
3006 case MSR_IA32_APICBASE:
3007 cpu_set_apic_base(env, val);
3008 break;
3009 case MSR_EFER:
3010 {
3011 uint64_t update_mask;
3012 update_mask = 0;
3013 if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3014 update_mask |= MSR_EFER_SCE;
3015 if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3016 update_mask |= MSR_EFER_LME;
3017 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3018 update_mask |= MSR_EFER_FFXSR;
3019 if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3020 update_mask |= MSR_EFER_NXE;
3021 env->efer = (env->efer & ~update_mask) |
3022 (val & update_mask);
3023 }
3024 break;
3025 case MSR_STAR:
3026 env->star = val;
3027 break;
3028 case MSR_PAT:
3029 env->pat = val;
3030 break;
3031#ifdef TARGET_X86_64
3032 case MSR_LSTAR:
3033 env->lstar = val;
3034 break;
3035 case MSR_CSTAR:
3036 env->cstar = val;
3037 break;
3038 case MSR_FMASK:
3039 env->fmask = val;
3040 break;
3041 case MSR_FSBASE:
3042 env->segs[R_FS].base = val;
3043 break;
3044 case MSR_GSBASE:
3045 env->segs[R_GS].base = val;
3046 break;
3047 case MSR_KERNELGSBASE:
3048 env->kernelgsbase = val;
3049 break;
3050#endif
3051 default:
3052 /* XXX: exception ? */
3053 break;
3054 }
3055}
3056
3057void helper_rdmsr(void)
3058{
3059 uint64_t val;
3060 switch((uint32_t)ECX) {
3061 case MSR_IA32_SYSENTER_CS:
3062 val = env->sysenter_cs;
3063 break;
3064 case MSR_IA32_SYSENTER_ESP:
3065 val = env->sysenter_esp;
3066 break;
3067 case MSR_IA32_SYSENTER_EIP:
3068 val = env->sysenter_eip;
3069 break;
3070 case MSR_IA32_APICBASE:
3071 val = cpu_get_apic_base(env);
3072 break;
3073 case MSR_EFER:
3074 val = env->efer;
3075 break;
3076 case MSR_STAR:
3077 val = env->star;
3078 break;
3079 case MSR_PAT:
3080 val = env->pat;
3081 break;
3082#ifdef TARGET_X86_64
3083 case MSR_LSTAR:
3084 val = env->lstar;
3085 break;
3086 case MSR_CSTAR:
3087 val = env->cstar;
3088 break;
3089 case MSR_FMASK:
3090 val = env->fmask;
3091 break;
3092 case MSR_FSBASE:
3093 val = env->segs[R_FS].base;
3094 break;
3095 case MSR_GSBASE:
3096 val = env->segs[R_GS].base;
3097 break;
3098 case MSR_KERNELGSBASE:
3099 val = env->kernelgsbase;
3100 break;
3101#endif
3102 default:
3103 /* XXX: exception ? */
3104 val = 0;
3105 break;
3106 }
3107 EAX = (uint32_t)(val);
3108 EDX = (uint32_t)(val >> 32);
3109}
3110#endif
3111
3112void helper_lsl(void)
3113{
3114 unsigned int selector, limit;
3115 uint32_t e1, e2, eflags;
3116 int rpl, dpl, cpl, type;
3117
3118 eflags = cc_table[CC_OP].compute_all();
3119 selector = T0 & 0xffff;
3120 if (load_segment(&e1, &e2, selector) != 0)
3121 goto fail;
3122 rpl = selector & 3;
3123 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3124 cpl = env->hflags & HF_CPL_MASK;
3125 if (e2 & DESC_S_MASK) {
3126 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3127 /* conforming */
3128 } else {
3129 if (dpl < cpl || dpl < rpl)
3130 goto fail;
3131 }
3132 } else {
3133 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3134 switch(type) {
3135 case 1:
3136 case 2:
3137 case 3:
3138 case 9:
3139 case 11:
3140 break;
3141 default:
3142 goto fail;
3143 }
3144 if (dpl < cpl || dpl < rpl) {
3145 fail:
3146 CC_SRC = eflags & ~CC_Z;
3147 return;
3148 }
3149 }
3150 limit = get_seg_limit(e1, e2);
3151 T1 = limit;
3152 CC_SRC = eflags | CC_Z;
3153}
3154
3155void helper_lar(void)
3156{
3157 unsigned int selector;
3158 uint32_t e1, e2, eflags;
3159 int rpl, dpl, cpl, type;
3160
3161 eflags = cc_table[CC_OP].compute_all();
3162 selector = T0 & 0xffff;
3163 if ((selector & 0xfffc) == 0)
3164 goto fail;
3165 if (load_segment(&e1, &e2, selector) != 0)
3166 goto fail;
3167 rpl = selector & 3;
3168 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3169 cpl = env->hflags & HF_CPL_MASK;
3170 if (e2 & DESC_S_MASK) {
3171 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3172 /* conforming */
3173 } else {
3174 if (dpl < cpl || dpl < rpl)
3175 goto fail;
3176 }
3177 } else {
3178 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3179 switch(type) {
3180 case 1:
3181 case 2:
3182 case 3:
3183 case 4:
3184 case 5:
3185 case 9:
3186 case 11:
3187 case 12:
3188 break;
3189 default:
3190 goto fail;
3191 }
3192 if (dpl < cpl || dpl < rpl) {
3193 fail:
3194 CC_SRC = eflags & ~CC_Z;
3195 return;
3196 }
3197 }
3198 T1 = e2 & 0x00f0ff00;
3199 CC_SRC = eflags | CC_Z;
3200}
3201
3202void helper_verr(void)
3203{
3204 unsigned int selector;
3205 uint32_t e1, e2, eflags;
3206 int rpl, dpl, cpl;
3207
3208 eflags = cc_table[CC_OP].compute_all();
3209 selector = T0 & 0xffff;
3210 if ((selector & 0xfffc) == 0)
3211 goto fail;
3212 if (load_segment(&e1, &e2, selector) != 0)
3213 goto fail;
3214 if (!(e2 & DESC_S_MASK))
3215 goto fail;
3216 rpl = selector & 3;
3217 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3218 cpl = env->hflags & HF_CPL_MASK;
3219 if (e2 & DESC_CS_MASK) {
3220 if (!(e2 & DESC_R_MASK))
3221 goto fail;
3222 if (!(e2 & DESC_C_MASK)) {
3223 if (dpl < cpl || dpl < rpl)
3224 goto fail;
3225 }
3226 } else {
3227 if (dpl < cpl || dpl < rpl) {
3228 fail:
3229 CC_SRC = eflags & ~CC_Z;
3230 return;
3231 }
3232 }
3233 CC_SRC = eflags | CC_Z;
3234}
3235
3236void helper_verw(void)
3237{
3238 unsigned int selector;
3239 uint32_t e1, e2, eflags;
3240 int rpl, dpl, cpl;
3241
3242 eflags = cc_table[CC_OP].compute_all();
3243 selector = T0 & 0xffff;
3244 if ((selector & 0xfffc) == 0)
3245 goto fail;
3246 if (load_segment(&e1, &e2, selector) != 0)
3247 goto fail;
3248 if (!(e2 & DESC_S_MASK))
3249 goto fail;
3250 rpl = selector & 3;
3251 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3252 cpl = env->hflags & HF_CPL_MASK;
3253 if (e2 & DESC_CS_MASK) {
3254 goto fail;
3255 } else {
3256 if (dpl < cpl || dpl < rpl)
3257 goto fail;
3258 if (!(e2 & DESC_W_MASK)) {
3259 fail:
3260 CC_SRC = eflags & ~CC_Z;
3261 return;
3262 }
3263 }
3264 CC_SRC = eflags | CC_Z;
3265}
3266
3267/* FPU helpers */
3268
3269void helper_fldt_ST0_A0(void)
3270{
3271 int new_fpstt;
3272 new_fpstt = (env->fpstt - 1) & 7;
3273 env->fpregs[new_fpstt].d = helper_fldt(A0);
3274 env->fpstt = new_fpstt;
3275 env->fptags[new_fpstt] = 0; /* validate stack entry */
3276}
3277
3278void helper_fstt_ST0_A0(void)
3279{
3280 helper_fstt(ST0, A0);
3281}
3282
3283void fpu_set_exception(int mask)
3284{
3285 env->fpus |= mask;
3286 if (env->fpus & (~env->fpuc & FPUC_EM))
3287 env->fpus |= FPUS_SE | FPUS_B;
3288}
3289
3290CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3291{
3292 if (b == 0.0)
3293 fpu_set_exception(FPUS_ZE);
3294 return a / b;
3295}
3296
3297void fpu_raise_exception(void)
3298{
3299 if (env->cr[0] & CR0_NE_MASK) {
3300 raise_exception(EXCP10_COPR);
3301 }
3302#if !defined(CONFIG_USER_ONLY)
3303 else {
3304 cpu_set_ferr(env);
3305 }
3306#endif
3307}
3308
3309/* BCD ops */
3310
3311void helper_fbld_ST0_A0(void)
3312{
3313 CPU86_LDouble tmp;
3314 uint64_t val;
3315 unsigned int v;
3316 int i;
3317
3318 val = 0;
3319 for(i = 8; i >= 0; i--) {
3320 v = ldub(A0 + i);
3321 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3322 }
3323 tmp = val;
3324 if (ldub(A0 + 9) & 0x80)
3325 tmp = -tmp;
3326 fpush();
3327 ST0 = tmp;
3328}
3329
3330void helper_fbst_ST0_A0(void)
3331{
3332 int v;
3333 target_ulong mem_ref, mem_end;
3334 int64_t val;
3335
3336 val = floatx_to_int64(ST0, &env->fp_status);
3337 mem_ref = A0;
3338 mem_end = mem_ref + 9;
3339 if (val < 0) {
3340 stb(mem_end, 0x80);
3341 val = -val;
3342 } else {
3343 stb(mem_end, 0x00);
3344 }
3345 while (mem_ref < mem_end) {
3346 if (val == 0)
3347 break;
3348 v = val % 100;
3349 val = val / 100;
3350 v = ((v / 10) << 4) | (v % 10);
3351 stb(mem_ref++, v);
3352 }
3353 while (mem_ref < mem_end) {
3354 stb(mem_ref++, 0);
3355 }
3356}
3357
3358void helper_f2xm1(void)
3359{
3360 ST0 = pow(2.0,ST0) - 1.0;
3361}
3362
3363void helper_fyl2x(void)
3364{
3365 CPU86_LDouble fptemp;
3366
3367 fptemp = ST0;
3368 if (fptemp>0.0){
3369 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
3370 ST1 *= fptemp;
3371 fpop();
3372 } else {
3373 env->fpus &= (~0x4700);
3374 env->fpus |= 0x400;
3375 }
3376}
3377
3378void helper_fptan(void)
3379{
3380 CPU86_LDouble fptemp;
3381
3382 fptemp = ST0;
3383 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3384 env->fpus |= 0x400;
3385 } else {
3386 ST0 = tan(fptemp);
3387 fpush();
3388 ST0 = 1.0;
3389 env->fpus &= (~0x400); /* C2 <-- 0 */
3390 /* the above code is for |arg| < 2**52 only */
3391 }
3392}
3393
3394void helper_fpatan(void)
3395{
3396 CPU86_LDouble fptemp, fpsrcop;
3397
3398 fpsrcop = ST1;
3399 fptemp = ST0;
3400 ST1 = atan2(fpsrcop,fptemp);
3401 fpop();
3402}
3403
3404void helper_fxtract(void)
3405{
3406 CPU86_LDoubleU temp;
3407 unsigned int expdif;
3408
3409 temp.d = ST0;
3410 expdif = EXPD(temp) - EXPBIAS;
3411 /*DP exponent bias*/
3412 ST0 = expdif;
3413 fpush();
3414 BIASEXPONENT(temp);
3415 ST0 = temp.d;
3416}
3417
3418void helper_fprem1(void)
3419{
3420 CPU86_LDouble dblq, fpsrcop, fptemp;
3421 CPU86_LDoubleU fpsrcop1, fptemp1;
3422 int expdif;
3423 int q;
3424
3425 fpsrcop = ST0;
3426 fptemp = ST1;
3427 fpsrcop1.d = fpsrcop;
3428 fptemp1.d = fptemp;
3429 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3430 if (expdif < 53) {
3431 dblq = fpsrcop / fptemp;
3432 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
3433 ST0 = fpsrcop - fptemp*dblq;
3434 q = (int)dblq; /* cutting off top bits is assumed here */
3435 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3436 /* (C0,C1,C3) <-- (q2,q1,q0) */
3437 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
3438 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
3439 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
3440 } else {
3441 env->fpus |= 0x400; /* C2 <-- 1 */
3442 fptemp = pow(2.0, expdif-50);
3443 fpsrcop = (ST0 / ST1) / fptemp;
3444 /* fpsrcop = integer obtained by rounding to the nearest */
3445 fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
3446 floor(fpsrcop): ceil(fpsrcop);
3447 ST0 -= (ST1 * fpsrcop * fptemp);
3448 }
3449}
3450
3451void helper_fprem(void)
3452{
3453 CPU86_LDouble dblq, fpsrcop, fptemp;
3454 CPU86_LDoubleU fpsrcop1, fptemp1;
3455 int expdif;
3456 int q;
3457
3458 fpsrcop = ST0;
3459 fptemp = ST1;
3460 fpsrcop1.d = fpsrcop;
3461 fptemp1.d = fptemp;
3462 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3463 if ( expdif < 53 ) {
3464 dblq = fpsrcop / fptemp;
3465 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
3466 ST0 = fpsrcop - fptemp*dblq;
3467 q = (int)dblq; /* cutting off top bits is assumed here */
3468 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3469 /* (C0,C1,C3) <-- (q2,q1,q0) */
3470 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
3471 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
3472 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
3473 } else {
3474 env->fpus |= 0x400; /* C2 <-- 1 */
3475 fptemp = pow(2.0, expdif-50);
3476 fpsrcop = (ST0 / ST1) / fptemp;
3477 /* fpsrcop = integer obtained by chopping */
3478 fpsrcop = (fpsrcop < 0.0)?
3479 -(floor(fabs(fpsrcop))): floor(fpsrcop);
3480 ST0 -= (ST1 * fpsrcop * fptemp);
3481 }
3482}
3483
3484void helper_fyl2xp1(void)
3485{
3486 CPU86_LDouble fptemp;
3487
3488 fptemp = ST0;
3489 if ((fptemp+1.0)>0.0) {
3490 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
3491 ST1 *= fptemp;
3492 fpop();
3493 } else {
3494 env->fpus &= (~0x4700);
3495 env->fpus |= 0x400;
3496 }
3497}
3498
3499void helper_fsqrt(void)
3500{
3501 CPU86_LDouble fptemp;
3502
3503 fptemp = ST0;
3504 if (fptemp<0.0) {
3505 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3506 env->fpus |= 0x400;
3507 }
3508 ST0 = sqrt(fptemp);
3509}
3510
3511void helper_fsincos(void)
3512{
3513 CPU86_LDouble fptemp;
3514
3515 fptemp = ST0;
3516 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3517 env->fpus |= 0x400;
3518 } else {
3519 ST0 = sin(fptemp);
3520 fpush();
3521 ST0 = cos(fptemp);
3522 env->fpus &= (~0x400); /* C2 <-- 0 */
3523 /* the above code is for |arg| < 2**63 only */
3524 }
3525}
3526
3527void helper_frndint(void)
3528{
3529 ST0 = floatx_round_to_int(ST0, &env->fp_status);
3530}
3531
3532void helper_fscale(void)
3533{
3534 ST0 = ldexp (ST0, (int)(ST1));
3535}
3536
3537void helper_fsin(void)
3538{
3539 CPU86_LDouble fptemp;
3540
3541 fptemp = ST0;
3542 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3543 env->fpus |= 0x400;
3544 } else {
3545 ST0 = sin(fptemp);
3546 env->fpus &= (~0x400); /* C2 <-- 0 */
3547 /* the above code is for |arg| < 2**53 only */
3548 }
3549}
3550
3551void helper_fcos(void)
3552{
3553 CPU86_LDouble fptemp;
3554
3555 fptemp = ST0;
3556 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3557 env->fpus |= 0x400;
3558 } else {
3559 ST0 = cos(fptemp);
3560 env->fpus &= (~0x400); /* C2 <-- 0 */
3561 /* the above code is for |arg5 < 2**63 only */
3562 }
3563}
3564
3565void helper_fxam_ST0(void)
3566{
3567 CPU86_LDoubleU temp;
3568 int expdif;
3569
3570 temp.d = ST0;
3571
3572 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3573 if (SIGND(temp))
3574 env->fpus |= 0x200; /* C1 <-- 1 */
3575
3576 /* XXX: test fptags too */
3577 expdif = EXPD(temp);
3578 if (expdif == MAXEXPD) {
3579#ifdef USE_X86LDOUBLE
3580 if (MANTD(temp) == 0x8000000000000000ULL)
3581#else
3582 if (MANTD(temp) == 0)
3583#endif
3584 env->fpus |= 0x500 /*Infinity*/;
3585 else
3586 env->fpus |= 0x100 /*NaN*/;
3587 } else if (expdif == 0) {
3588 if (MANTD(temp) == 0)
3589 env->fpus |= 0x4000 /*Zero*/;
3590 else
3591 env->fpus |= 0x4400 /*Denormal*/;
3592 } else {
3593 env->fpus |= 0x400;
3594 }
3595}
3596
3597void helper_fstenv(target_ulong ptr, int data32)
3598{
3599 int fpus, fptag, exp, i;
3600 uint64_t mant;
3601 CPU86_LDoubleU tmp;
3602
3603 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3604 fptag = 0;
3605 for (i=7; i>=0; i--) {
3606 fptag <<= 2;
3607 if (env->fptags[i]) {
3608 fptag |= 3;
3609 } else {
3610 tmp.d = env->fpregs[i].d;
3611 exp = EXPD(tmp);
3612 mant = MANTD(tmp);
3613 if (exp == 0 && mant == 0) {
3614 /* zero */
3615 fptag |= 1;
3616 } else if (exp == 0 || exp == MAXEXPD
3617#ifdef USE_X86LDOUBLE
3618 || (mant & (1LL << 63)) == 0
3619#endif
3620 ) {
3621 /* NaNs, infinity, denormal */
3622 fptag |= 2;
3623 }
3624 }
3625 }
3626 if (data32) {
3627 /* 32 bit */
3628 stl(ptr, env->fpuc);
3629 stl(ptr + 4, fpus);
3630 stl(ptr + 8, fptag);
3631 stl(ptr + 12, 0); /* fpip */
3632 stl(ptr + 16, 0); /* fpcs */
3633 stl(ptr + 20, 0); /* fpoo */
3634 stl(ptr + 24, 0); /* fpos */
3635 } else {
3636 /* 16 bit */
3637 stw(ptr, env->fpuc);
3638 stw(ptr + 2, fpus);
3639 stw(ptr + 4, fptag);
3640 stw(ptr + 6, 0);
3641 stw(ptr + 8, 0);
3642 stw(ptr + 10, 0);
3643 stw(ptr + 12, 0);
3644 }
3645}
3646
3647void helper_fldenv(target_ulong ptr, int data32)
3648{
3649 int i, fpus, fptag;
3650
3651 if (data32) {
3652 env->fpuc = lduw(ptr);
3653 fpus = lduw(ptr + 4);
3654 fptag = lduw(ptr + 8);
3655 }
3656 else {
3657 env->fpuc = lduw(ptr);
3658 fpus = lduw(ptr + 2);
3659 fptag = lduw(ptr + 4);
3660 }
3661 env->fpstt = (fpus >> 11) & 7;
3662 env->fpus = fpus & ~0x3800;
3663 for(i = 0;i < 8; i++) {
3664 env->fptags[i] = ((fptag & 3) == 3);
3665 fptag >>= 2;
3666 }
3667}
3668
3669void helper_fsave(target_ulong ptr, int data32)
3670{
3671 CPU86_LDouble tmp;
3672 int i;
3673
3674 helper_fstenv(ptr, data32);
3675
3676 ptr += (14 << data32);
3677 for(i = 0;i < 8; i++) {
3678 tmp = ST(i);
3679 helper_fstt(tmp, ptr);
3680 ptr += 10;
3681 }
3682
3683 /* fninit */
3684 env->fpus = 0;
3685 env->fpstt = 0;
3686 env->fpuc = 0x37f;
3687 env->fptags[0] = 1;
3688 env->fptags[1] = 1;
3689 env->fptags[2] = 1;
3690 env->fptags[3] = 1;
3691 env->fptags[4] = 1;
3692 env->fptags[5] = 1;
3693 env->fptags[6] = 1;
3694 env->fptags[7] = 1;
3695}
3696
3697void helper_frstor(target_ulong ptr, int data32)
3698{
3699 CPU86_LDouble tmp;
3700 int i;
3701
3702 helper_fldenv(ptr, data32);
3703 ptr += (14 << data32);
3704
3705 for(i = 0;i < 8; i++) {
3706 tmp = helper_fldt(ptr);
3707 ST(i) = tmp;
3708 ptr += 10;
3709 }
3710}
3711
3712void helper_fxsave(target_ulong ptr, int data64)
3713{
3714 int fpus, fptag, i, nb_xmm_regs;
3715 CPU86_LDouble tmp;
3716 target_ulong addr;
3717
3718 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3719 fptag = 0;
3720 for(i = 0; i < 8; i++) {
3721 fptag |= (env->fptags[i] << i);
3722 }
3723 stw(ptr, env->fpuc);
3724 stw(ptr + 2, fpus);
3725 stw(ptr + 4, fptag ^ 0xff);
3726
3727 addr = ptr + 0x20;
3728 for(i = 0;i < 8; i++) {
3729 tmp = ST(i);
3730 helper_fstt(tmp, addr);
3731 addr += 16;
3732 }
3733
3734 if (env->cr[4] & CR4_OSFXSR_MASK) {
3735 /* XXX: finish it */
3736 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3737 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3738 nb_xmm_regs = 8 << data64;
3739 addr = ptr + 0xa0;
3740 for(i = 0; i < nb_xmm_regs; i++) {
3741 stq(addr, env->xmm_regs[i].XMM_Q(0));
3742 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3743 addr += 16;
3744 }
3745 }
3746}
3747
3748void helper_fxrstor(target_ulong ptr, int data64)
3749{
3750 int i, fpus, fptag, nb_xmm_regs;
3751 CPU86_LDouble tmp;
3752 target_ulong addr;
3753
3754 env->fpuc = lduw(ptr);
3755 fpus = lduw(ptr + 2);
3756 fptag = lduw(ptr + 4);
3757 env->fpstt = (fpus >> 11) & 7;
3758 env->fpus = fpus & ~0x3800;
3759 fptag ^= 0xff;
3760 for(i = 0;i < 8; i++) {
3761 env->fptags[i] = ((fptag >> i) & 1);
3762 }
3763
3764 addr = ptr + 0x20;
3765 for(i = 0;i < 8; i++) {
3766 tmp = helper_fldt(addr);
3767 ST(i) = tmp;
3768 addr += 16;
3769 }
3770
3771 if (env->cr[4] & CR4_OSFXSR_MASK) {
3772 /* XXX: finish it */
3773 env->mxcsr = ldl(ptr + 0x18);
3774 //ldl(ptr + 0x1c);
3775 nb_xmm_regs = 8 << data64;
3776 addr = ptr + 0xa0;
3777 for(i = 0; i < nb_xmm_regs; i++) {
3778#if !defined(VBOX) || __GNUC__ < 4
3779 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3780 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3781#else /* VBOX + __GNUC__ >= 4: gcc 4.x compiler bug - it runs out of registers for the 64-bit value. */
3782# if 1
3783 env->xmm_regs[i].XMM_L(0) = ldl(addr);
3784 env->xmm_regs[i].XMM_L(1) = ldl(addr + 4);
3785 env->xmm_regs[i].XMM_L(2) = ldl(addr + 8);
3786 env->xmm_regs[i].XMM_L(3) = ldl(addr + 12);
3787# else
3788 /* this works fine on Mac OS X, gcc 4.0.1 */
3789 uint64_t u64 = ldq(addr);
3790 env->xmm_regs[i].XMM_Q(0);
3791 u64 = ldq(addr + 4);
3792 env->xmm_regs[i].XMM_Q(1) = u64;
3793# endif
3794#endif
3795 addr += 16;
3796 }
3797 }
3798}
3799
3800#ifndef USE_X86LDOUBLE
3801
3802void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3803{
3804 CPU86_LDoubleU temp;
3805 int e;
3806
3807 temp.d = f;
3808 /* mantissa */
3809 *pmant = (MANTD(temp) << 11) | (1LL << 63);
3810 /* exponent + sign */
3811 e = EXPD(temp) - EXPBIAS + 16383;
3812 e |= SIGND(temp) >> 16;
3813 *pexp = e;
3814}
3815
3816CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3817{
3818 CPU86_LDoubleU temp;
3819 int e;
3820 uint64_t ll;
3821
3822 /* XXX: handle overflow ? */
3823 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3824 e |= (upper >> 4) & 0x800; /* sign */
3825 ll = (mant >> 11) & ((1LL << 52) - 1);
3826#ifdef __arm__
3827 temp.l.upper = (e << 20) | (ll >> 32);
3828 temp.l.lower = ll;
3829#else
3830 temp.ll = ll | ((uint64_t)e << 52);
3831#endif
3832 return temp.d;
3833}
3834
3835#else
3836
3837void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3838{
3839 CPU86_LDoubleU temp;
3840
3841 temp.d = f;
3842 *pmant = temp.l.lower;
3843 *pexp = temp.l.upper;
3844}
3845
3846CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3847{
3848 CPU86_LDoubleU temp;
3849
3850 temp.l.upper = upper;
3851 temp.l.lower = mant;
3852 return temp.d;
3853}
3854#endif
3855
3856#ifdef TARGET_X86_64
3857
3858//#define DEBUG_MULDIV
3859
3860static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3861{
3862 *plow += a;
3863 /* carry test */
3864 if (*plow < a)
3865 (*phigh)++;
3866 *phigh += b;
3867}
3868
3869static void neg128(uint64_t *plow, uint64_t *phigh)
3870{
3871 *plow = ~ *plow;
3872 *phigh = ~ *phigh;
3873 add128(plow, phigh, 1, 0);
3874}
3875
3876static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3877{
3878 uint32_t a0, a1, b0, b1;
3879 uint64_t v;
3880
3881 a0 = a;
3882 a1 = a >> 32;
3883
3884 b0 = b;
3885 b1 = b >> 32;
3886
3887 v = (uint64_t)a0 * (uint64_t)b0;
3888 *plow = v;
3889 *phigh = 0;
3890
3891 v = (uint64_t)a0 * (uint64_t)b1;
3892 add128(plow, phigh, v << 32, v >> 32);
3893
3894 v = (uint64_t)a1 * (uint64_t)b0;
3895 add128(plow, phigh, v << 32, v >> 32);
3896
3897 v = (uint64_t)a1 * (uint64_t)b1;
3898 *phigh += v;
3899#ifdef DEBUG_MULDIV
3900 printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
3901 a, b, *phigh, *plow);
3902#endif
3903}
3904
3905static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
3906{
3907 int sa, sb;
3908 sa = (a < 0);
3909 if (sa)
3910 a = -a;
3911 sb = (b < 0);
3912 if (sb)
3913 b = -b;
3914 mul64(plow, phigh, a, b);
3915 if (sa ^ sb) {
3916 neg128(plow, phigh);
3917 }
3918}
3919
3920/* return TRUE if overflow */
3921static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3922{
3923 uint64_t q, r, a1, a0;
3924 int i, qb, ab;
3925
3926 a0 = *plow;
3927 a1 = *phigh;
3928 if (a1 == 0) {
3929 q = a0 / b;
3930 r = a0 % b;
3931 *plow = q;
3932 *phigh = r;
3933 } else {
3934 if (a1 >= b)
3935 return 1;
3936 /* XXX: use a better algorithm */
3937 for(i = 0; i < 64; i++) {
3938 ab = a1 >> 63;
3939 a1 = (a1 << 1) | (a0 >> 63);
3940 if (ab || a1 >= b) {
3941 a1 -= b;
3942 qb = 1;
3943 } else {
3944 qb = 0;
3945 }
3946 a0 = (a0 << 1) | qb;
3947 }
3948#if defined(DEBUG_MULDIV)
3949 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
3950 *phigh, *plow, b, a0, a1);
3951#endif
3952 *plow = a0;
3953 *phigh = a1;
3954 }
3955 return 0;
3956}
3957
3958/* return TRUE if overflow */
3959static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3960{
3961 int sa, sb;
3962 sa = ((int64_t)*phigh < 0);
3963 if (sa)
3964 neg128(plow, phigh);
3965 sb = (b < 0);
3966 if (sb)
3967 b = -b;
3968 if (div64(plow, phigh, b) != 0)
3969 return 1;
3970 if (sa ^ sb) {
3971 if (*plow > (1ULL << 63))
3972 return 1;
3973 *plow = - *plow;
3974 } else {
3975 if (*plow >= (1ULL << 63))
3976 return 1;
3977 }
3978 if (sa)
3979 *phigh = - *phigh;
3980 return 0;
3981}
3982
3983void helper_mulq_EAX_T0(void)
3984{
3985 uint64_t r0, r1;
3986
3987 mul64(&r0, &r1, EAX, T0);
3988 EAX = r0;
3989 EDX = r1;
3990 CC_DST = r0;
3991 CC_SRC = r1;
3992}
3993
3994void helper_imulq_EAX_T0(void)
3995{
3996 uint64_t r0, r1;
3997
3998 imul64(&r0, &r1, EAX, T0);
3999 EAX = r0;
4000 EDX = r1;
4001 CC_DST = r0;
4002 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4003}
4004
4005void helper_imulq_T0_T1(void)
4006{
4007 uint64_t r0, r1;
4008
4009 imul64(&r0, &r1, T0, T1);
4010 T0 = r0;
4011 CC_DST = r0;
4012 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4013}
4014
4015void helper_divq_EAX_T0(void)
4016{
4017 uint64_t r0, r1;
4018 if (T0 == 0) {
4019 raise_exception(EXCP00_DIVZ);
4020 }
4021 r0 = EAX;
4022 r1 = EDX;
4023 if (div64(&r0, &r1, T0))
4024 raise_exception(EXCP00_DIVZ);
4025 EAX = r0;
4026 EDX = r1;
4027}
4028
4029void helper_idivq_EAX_T0(void)
4030{
4031 uint64_t r0, r1;
4032 if (T0 == 0) {
4033 raise_exception(EXCP00_DIVZ);
4034 }
4035 r0 = EAX;
4036 r1 = EDX;
4037 if (idiv64(&r0, &r1, T0))
4038 raise_exception(EXCP00_DIVZ);
4039 EAX = r0;
4040 EDX = r1;
4041}
4042
4043void helper_bswapq_T0(void)
4044{
4045 T0 = bswap64(T0);
4046}
4047#endif
4048
4049void helper_hlt(void)
4050{
4051 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
4052 env->hflags |= HF_HALTED_MASK;
4053 env->exception_index = EXCP_HLT;
4054 cpu_loop_exit();
4055}
4056
4057void helper_monitor(void)
4058{
4059 if ((uint32_t)ECX != 0)
4060 raise_exception(EXCP0D_GPF);
4061 /* XXX: store address ? */
4062}
4063
4064void helper_mwait(void)
4065{
4066 if ((uint32_t)ECX != 0)
4067 raise_exception(EXCP0D_GPF);
4068#ifdef VBOX
4069 helper_hlt();
4070#else
4071 /* XXX: not complete but not completely erroneous */
4072 if (env->cpu_index != 0 || env->next_cpu != NULL) {
4073 /* more than one CPU: do not sleep because another CPU may
4074 wake this one */
4075 } else {
4076 helper_hlt();
4077 }
4078#endif
4079}
4080
4081float approx_rsqrt(float a)
4082{
4083 return 1.0 / sqrt(a);
4084}
4085
4086float approx_rcp(float a)
4087{
4088 return 1.0 / a;
4089}
4090
4091void update_fp_status(void)
4092{
4093 int rnd_type;
4094
4095 /* set rounding mode */
4096 switch(env->fpuc & RC_MASK) {
4097 default:
4098 case RC_NEAR:
4099 rnd_type = float_round_nearest_even;
4100 break;
4101 case RC_DOWN:
4102 rnd_type = float_round_down;
4103 break;
4104 case RC_UP:
4105 rnd_type = float_round_up;
4106 break;
4107 case RC_CHOP:
4108 rnd_type = float_round_to_zero;
4109 break;
4110 }
4111 set_float_rounding_mode(rnd_type, &env->fp_status);
4112#ifdef FLOATX80
4113 switch((env->fpuc >> 8) & 3) {
4114 case 0:
4115 rnd_type = 32;
4116 break;
4117 case 2:
4118 rnd_type = 64;
4119 break;
4120 case 3:
4121 default:
4122 rnd_type = 80;
4123 break;
4124 }
4125 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
4126#endif
4127}
4128
4129#if !defined(CONFIG_USER_ONLY)
4130
4131#define MMUSUFFIX _mmu
4132#define GETPC() (__builtin_return_address(0))
4133
4134#define SHIFT 0
4135#include "softmmu_template.h"
4136
4137#define SHIFT 1
4138#include "softmmu_template.h"
4139
4140#define SHIFT 2
4141#include "softmmu_template.h"
4142
4143#define SHIFT 3
4144#include "softmmu_template.h"
4145
4146#endif
4147
4148/* try to fill the TLB and return an exception if error. If retaddr is
4149 NULL, it means that the function was called in C code (i.e. not
4150 from generated code or from helper.c) */
4151/* XXX: fix it to restore all registers */
4152void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
4153{
4154 TranslationBlock *tb;
4155 int ret;
4156 unsigned long pc;
4157 CPUX86State *saved_env;
4158
4159 /* XXX: hack to restore env in all cases, even if not called from
4160 generated code */
4161 saved_env = env;
4162 env = cpu_single_env;
4163
4164 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
4165 if (ret) {
4166 if (retaddr) {
4167 /* now we have a real cpu fault */
4168 pc = (unsigned long)retaddr;
4169 tb = tb_find_pc(pc);
4170 if (tb) {
4171 /* the PC is inside the translated code. It means that we have
4172 a virtual CPU fault */
4173 cpu_restore_state(tb, env, pc, NULL);
4174 }
4175 }
4176 if (retaddr)
4177 raise_exception_err(env->exception_index, env->error_code);
4178 else
4179 raise_exception_err_norestore(env->exception_index, env->error_code);
4180 }
4181 env = saved_env;
4182}
4183
4184#ifdef VBOX
4185
4186/**
4187 * Correctly computes the eflags.
4188 * @returns eflags.
4189 * @param env1 CPU environment.
4190 */
4191uint32_t raw_compute_eflags(CPUX86State *env1)
4192{
4193 CPUX86State *savedenv = env;
4194 env = env1;
4195 uint32_t efl = compute_eflags();
4196 env = savedenv;
4197 return efl;
4198}
4199
4200/**
4201 * Reads byte from virtual address in guest memory area.
4202 * XXX: is it working for any addresses? swapped out pages?
4203 * @returns readed data byte.
4204 * @param env1 CPU environment.
4205 * @param pvAddr GC Virtual address.
4206 */
4207uint8_t read_byte(CPUX86State *env1, target_ulong addr)
4208{
4209 CPUX86State *savedenv = env;
4210 env = env1;
4211 uint8_t u8 = ldub_kernel(addr);
4212 env = savedenv;
4213 return u8;
4214}
4215
4216/**
4217 * Reads byte from virtual address in guest memory area.
4218 * XXX: is it working for any addresses? swapped out pages?
4219 * @returns readed data byte.
4220 * @param env1 CPU environment.
4221 * @param pvAddr GC Virtual address.
4222 */
4223uint16_t read_word(CPUX86State *env1, target_ulong addr)
4224{
4225 CPUX86State *savedenv = env;
4226 env = env1;
4227 uint16_t u16 = lduw_kernel(addr);
4228 env = savedenv;
4229 return u16;
4230}
4231
4232/**
4233 * Reads byte from virtual address in guest memory area.
4234 * XXX: is it working for any addresses? swapped out pages?
4235 * @returns readed data byte.
4236 * @param env1 CPU environment.
4237 * @param pvAddr GC Virtual address.
4238 */
4239uint32_t read_dword(CPUX86State *env1, target_ulong addr)
4240{
4241 CPUX86State *savedenv = env;
4242 env = env1;
4243 uint32_t u32 = ldl_kernel(addr);
4244 env = savedenv;
4245 return u32;
4246}
4247
4248/**
4249 * Writes byte to virtual address in guest memory area.
4250 * XXX: is it working for any addresses? swapped out pages?
4251 * @returns readed data byte.
4252 * @param env1 CPU environment.
4253 * @param pvAddr GC Virtual address.
4254 * @param val byte value
4255 */
4256void write_byte(CPUX86State *env1, target_ulong addr, uint8_t val)
4257{
4258 CPUX86State *savedenv = env;
4259 env = env1;
4260 stb(addr, val);
4261 env = savedenv;
4262}
4263
4264void write_word(CPUX86State *env1, target_ulong addr, uint16_t val)
4265{
4266 CPUX86State *savedenv = env;
4267 env = env1;
4268 stw(addr, val);
4269 env = savedenv;
4270}
4271
4272void write_dword(CPUX86State *env1, target_ulong addr, uint32_t val)
4273{
4274 CPUX86State *savedenv = env;
4275 env = env1;
4276 stl(addr, val);
4277 env = savedenv;
4278}
4279
4280/**
4281 * Correctly loads selector into segment register with updating internal
4282 * qemu data/caches.
4283 * @param env1 CPU environment.
4284 * @param seg_reg Segment register.
4285 * @param selector Selector to load.
4286 */
4287void sync_seg(CPUX86State *env1, int seg_reg, int selector)
4288{
4289 CPUX86State *savedenv = env;
4290 env = env1;
4291
4292 if ( env->eflags & X86_EFL_VM
4293 || !(env->cr[0] & X86_CR0_PE))
4294 {
4295 load_seg_vm(seg_reg, selector);
4296
4297 env = savedenv;
4298
4299 /* Successful sync. */
4300 env1->segs[seg_reg].newselector = 0;
4301 }
4302 else
4303 {
4304 if (setjmp(env1->jmp_env) == 0)
4305 {
4306 if (seg_reg == R_CS)
4307 {
4308 uint32_t e1, e2;
4309 load_segment(&e1, &e2, selector);
4310 cpu_x86_load_seg_cache(env, R_CS, selector,
4311 get_seg_base(e1, e2),
4312 get_seg_limit(e1, e2),
4313 e2);
4314 }
4315 else
4316 load_seg(seg_reg, selector);
4317 env = savedenv;
4318
4319 /* Successful sync. */
4320 env1->segs[seg_reg].newselector = 0;
4321 }
4322 else
4323 {
4324 env = savedenv;
4325
4326 /* Postpone sync until the guest uses the selector. */
4327 env1->segs[seg_reg].selector = selector; /* hidden values are now incorrect, but will be resynced when this register is accessed. */
4328 env1->segs[seg_reg].newselector = selector;
4329 Log(("sync_seg: out of sync seg_reg=%d selector=%#x\n", seg_reg, selector));
4330 }
4331 }
4332
4333}
4334
4335
4336/**
4337 * Correctly loads a new ldtr selector.
4338 *
4339 * @param env1 CPU environment.
4340 * @param selector Selector to load.
4341 */
4342void sync_ldtr(CPUX86State *env1, int selector)
4343{
4344 CPUX86State *saved_env = env;
4345 target_ulong saved_T0 = T0;
4346 if (setjmp(env1->jmp_env) == 0)
4347 {
4348 env = env1;
4349 T0 = selector;
4350 helper_lldt_T0();
4351 T0 = saved_T0;
4352 env = saved_env;
4353 }
4354 else
4355 {
4356 T0 = saved_T0;
4357 env = saved_env;
4358#ifdef VBOX_STRICT
4359 cpu_abort(env1, "sync_ldtr: selector=%#x\n", selector);
4360#endif
4361 }
4362}
4363
4364/**
4365 * Correctly loads a new tr selector.
4366 *
4367 * @param env1 CPU environment.
4368 * @param selector Selector to load.
4369 */
4370int sync_tr(CPUX86State *env1, int selector)
4371{
4372 /* ARG! this was going to call helper_ltr_T0 but that won't work because of busy flag. */
4373 SegmentCache *dt;
4374 uint32_t e1, e2;
4375 int index, type, entry_limit;
4376 target_ulong ptr;
4377 CPUX86State *saved_env = env;
4378 env = env1;
4379
4380 selector &= 0xffff;
4381 if ((selector & 0xfffc) == 0) {
4382 /* NULL selector case: invalid TR */
4383 env->tr.base = 0;
4384 env->tr.limit = 0;
4385 env->tr.flags = 0;
4386 } else {
4387 if (selector & 0x4)
4388 goto l_failure;
4389 dt = &env->gdt;
4390 index = selector & ~7;
4391#ifdef TARGET_X86_64
4392 if (env->hflags & HF_LMA_MASK)
4393 entry_limit = 15;
4394 else
4395#endif
4396 entry_limit = 7;
4397 if ((index + entry_limit) > dt->limit)
4398 goto l_failure;
4399 ptr = dt->base + index;
4400 e1 = ldl_kernel(ptr);
4401 e2 = ldl_kernel(ptr + 4);
4402 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
4403 if ((e2 & DESC_S_MASK) /*||
4404 (type != 1 && type != 9)*/)
4405 goto l_failure;
4406 if (!(e2 & DESC_P_MASK))
4407 goto l_failure;
4408#ifdef TARGET_X86_64
4409 if (env->hflags & HF_LMA_MASK) {
4410 uint32_t e3;
4411 e3 = ldl_kernel(ptr + 8);
4412 load_seg_cache_raw_dt(&env->tr, e1, e2);
4413 env->tr.base |= (target_ulong)e3 << 32;
4414 } else
4415#endif
4416 {
4417 load_seg_cache_raw_dt(&env->tr, e1, e2);
4418 }
4419 e2 |= DESC_TSS_BUSY_MASK;
4420 stl_kernel(ptr + 4, e2);
4421 }
4422 env->tr.selector = selector;
4423
4424 env = saved_env;
4425 return 0;
4426l_failure:
4427 AssertMsgFailed(("selector=%d\n", selector));
4428 return -1;
4429}
4430
4431int emulate_single_instr(CPUX86State *env1)
4432{
4433#if 1 /* single stepping is broken when using a static tb... feel free to figure out why. :-) */
4434 /* This has to be static because it needs to be addressible
4435 using 32-bit immediate addresses on 64-bit machines. This
4436 is dictated by the gcc code model used when building this
4437 module / op.o. Using a static here pushes the problem
4438 onto the module loader. */
4439 static TranslationBlock tb_temp;
4440#endif
4441 TranslationBlock *tb;
4442 TranslationBlock *current;
4443 int csize;
4444 void (*gen_func)(void);
4445 uint8_t *tc_ptr;
4446 uint32_t old_eip;
4447
4448 /* ensures env is loaded in ebp! */
4449 CPUX86State *savedenv = env;
4450 env = env1;
4451
4452 RAWEx_ProfileStart(env, STATS_EMULATE_SINGLE_INSTR);
4453
4454#if 1 /* see above */
4455 tc_ptr = env->pvCodeBuffer;
4456#else
4457 tc_ptr = code_gen_ptr;
4458#endif
4459
4460 /*
4461 * Setup temporary translation block.
4462 */
4463 /* tb_alloc: */
4464#if 1 /* see above */
4465 tb = &tb_temp;
4466 tb->pc = env->segs[R_CS].base + env->eip;
4467 tb->cflags = 0;
4468#else
4469 tb = tb_alloc(env->segs[R_CS].base + env->eip);
4470 if (!tb)
4471 {
4472 tb_flush(env);
4473 tb = tb_alloc(env->segs[R_CS].base + env->eip);
4474 }
4475#endif
4476
4477 /* tb_find_slow: */
4478 tb->tc_ptr = tc_ptr;
4479 tb->cs_base = env->segs[R_CS].base;
4480 tb->flags = env->hflags | (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
4481
4482 /* Initialize the rest with sensible values. */
4483 tb->size = 0;
4484 tb->phys_hash_next = NULL;
4485 tb->page_next[0] = NULL;
4486 tb->page_next[1] = NULL;
4487 tb->page_addr[0] = 0;
4488 tb->page_addr[1] = 0;
4489 tb->tb_next_offset[0] = 0xffff;
4490 tb->tb_next_offset[1] = 0xffff;
4491 tb->tb_next[0] = 0xffff;
4492 tb->tb_next[1] = 0xffff;
4493 tb->jmp_next[0] = NULL;
4494 tb->jmp_next[1] = NULL;
4495 tb->jmp_first = NULL;
4496
4497 current = env->current_tb;
4498 env->current_tb = NULL;
4499
4500 /*
4501 * Translate only one instruction.
4502 */
4503 ASMAtomicOrU32(&env->state, CPU_EMULATE_SINGLE_INSTR);
4504 if (cpu_gen_code(env, tb, env->cbCodeBuffer, &csize) < 0)
4505 {
4506 AssertFailed();
4507 RAWEx_ProfileStop(env, STATS_EMULATE_SINGLE_INSTR);
4508 ASMAtomicAndU32(&env->state, ~CPU_EMULATE_SINGLE_INSTR);
4509 env = savedenv;
4510 return -1;
4511 }
4512#ifdef DEBUG
4513 if(csize > env->cbCodeBuffer)
4514 {
4515 RAWEx_ProfileStop(env, STATS_EMULATE_SINGLE_INSTR);
4516 AssertFailed();
4517 ASMAtomicAndU32(&env->state, ~CPU_EMULATE_SINGLE_INSTR);
4518 env = savedenv;
4519 return -1;
4520 }
4521 if (tb->tc_ptr != tc_ptr)
4522 {
4523 RAWEx_ProfileStop(env, STATS_EMULATE_SINGLE_INSTR);
4524 AssertFailed();
4525 ASMAtomicAndU32(&env->state, ~CPU_EMULATE_SINGLE_INSTR);
4526 env = savedenv;
4527 return -1;
4528 }
4529#endif
4530 ASMAtomicAndU32(&env->state, ~CPU_EMULATE_SINGLE_INSTR);
4531
4532 /* tb_link_phys: */
4533 tb->jmp_first = (TranslationBlock *)((intptr_t)tb | 2);
4534 Assert(tb->jmp_next[0] == NULL); Assert(tb->jmp_next[1] == NULL);
4535 if (tb->tb_next_offset[0] != 0xffff)
4536 tb_set_jmp_target(tb, 0, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[0]));
4537 if (tb->tb_next_offset[1] != 0xffff)
4538 tb_set_jmp_target(tb, 1, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[1]));
4539
4540 /*
4541 * Execute it using emulation
4542 */
4543 old_eip = env->eip;
4544 gen_func = (void *)tb->tc_ptr;
4545 env->current_tb = tb;
4546
4547 // eip remains the same for repeated instructions; no idea why qemu doesn't do a jump inside the generated code
4548 // perhaps not a very safe hack
4549 while(old_eip == env->eip)
4550 {
4551 gen_func();
4552 /*
4553 * Exit once we detect an external interrupt and interrupts are enabled
4554 */
4555 if( (env->interrupt_request & (CPU_INTERRUPT_EXTERNAL_EXIT|CPU_INTERRUPT_EXTERNAL_TIMER)) ||
4556 ( (env->eflags & IF_MASK) &&
4557 !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
4558 (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_HARD) ) )
4559 {
4560 break;
4561 }
4562 }
4563 env->current_tb = current;
4564
4565 Assert(tb->phys_hash_next == NULL);
4566 Assert(tb->page_next[0] == NULL);
4567 Assert(tb->page_next[1] == NULL);
4568 Assert(tb->page_addr[0] == 0);
4569 Assert(tb->page_addr[1] == 0);
4570/*
4571 Assert(tb->tb_next_offset[0] == 0xffff);
4572 Assert(tb->tb_next_offset[1] == 0xffff);
4573 Assert(tb->tb_next[0] == 0xffff);
4574 Assert(tb->tb_next[1] == 0xffff);
4575 Assert(tb->jmp_next[0] == NULL);
4576 Assert(tb->jmp_next[1] == NULL);
4577 Assert(tb->jmp_first == NULL); */
4578
4579 RAWEx_ProfileStop(env, STATS_EMULATE_SINGLE_INSTR);
4580
4581 /*
4582 * Execute the next instruction when we encounter instruction fusing.
4583 */
4584 if (env->hflags & HF_INHIBIT_IRQ_MASK)
4585 {
4586 Log(("REM: Emulating next instruction due to instruction fusing (HF_INHIBIT_IRQ_MASK)\n"));
4587 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4588 emulate_single_instr(env);
4589 }
4590
4591 env = savedenv;
4592 return 0;
4593}
4594
4595int get_ss_esp_from_tss_raw(CPUX86State *env1, uint32_t *ss_ptr,
4596 uint32_t *esp_ptr, int dpl)
4597{
4598 int type, index, shift;
4599
4600 CPUX86State *savedenv = env;
4601 env = env1;
4602
4603 if (!(env->tr.flags & DESC_P_MASK))
4604 cpu_abort(env, "invalid tss");
4605 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
4606 if ((type & 7) != 1)
4607 cpu_abort(env, "invalid tss type %d", type);
4608 shift = type >> 3;
4609 index = (dpl * 4 + 2) << shift;
4610 if (index + (4 << shift) - 1 > env->tr.limit)
4611 {
4612 env = savedenv;
4613 return 0;
4614 }
4615 //raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
4616
4617 if (shift == 0) {
4618 *esp_ptr = lduw_kernel(env->tr.base + index);
4619 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
4620 } else {
4621 *esp_ptr = ldl_kernel(env->tr.base + index);
4622 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
4623 }
4624
4625 env = savedenv;
4626 return 1;
4627}
4628
4629//*****************************************************************************
4630// Needs to be at the bottom of the file (overriding macros)
4631
4632static inline CPU86_LDouble helper_fldt_raw(uint8_t *ptr)
4633{
4634 return *(CPU86_LDouble *)ptr;
4635}
4636
4637static inline void helper_fstt_raw(CPU86_LDouble f, uint8_t *ptr)
4638{
4639 *(CPU86_LDouble *)ptr = f;
4640}
4641
4642#undef stw
4643#undef stl
4644#undef stq
4645#define stw(a,b) *(uint16_t *)(a) = (uint16_t)(b)
4646#define stl(a,b) *(uint32_t *)(a) = (uint32_t)(b)
4647#define stq(a,b) *(uint64_t *)(a) = (uint64_t)(b)
4648#define data64 0
4649
4650//*****************************************************************************
4651void restore_raw_fp_state(CPUX86State *env, uint8_t *ptr)
4652{
4653 int fpus, fptag, i, nb_xmm_regs;
4654 CPU86_LDouble tmp;
4655 uint8_t *addr;
4656
4657 if (env->cpuid_features & CPUID_FXSR)
4658 {
4659 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4660 fptag = 0;
4661 for(i = 0; i < 8; i++) {
4662 fptag |= (env->fptags[i] << i);
4663 }
4664 stw(ptr, env->fpuc);
4665 stw(ptr + 2, fpus);
4666 stw(ptr + 4, fptag ^ 0xff);
4667
4668 addr = ptr + 0x20;
4669 for(i = 0;i < 8; i++) {
4670 tmp = ST(i);
4671 helper_fstt_raw(tmp, addr);
4672 addr += 16;
4673 }
4674
4675 if (env->cr[4] & CR4_OSFXSR_MASK) {
4676 /* XXX: finish it */
4677 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4678 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4679 nb_xmm_regs = 8 << data64;
4680 addr = ptr + 0xa0;
4681 for(i = 0; i < nb_xmm_regs; i++) {
4682#if __GNUC__ < 4
4683 stq(addr, env->xmm_regs[i].XMM_Q(0));
4684 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4685#else /* VBOX + __GNUC__ >= 4: gcc 4.x compiler bug - it runs out of registers for the 64-bit value. */
4686 stl(addr, env->xmm_regs[i].XMM_L(0));
4687 stl(addr + 4, env->xmm_regs[i].XMM_L(1));
4688 stl(addr + 8, env->xmm_regs[i].XMM_L(2));
4689 stl(addr + 12, env->xmm_regs[i].XMM_L(3));
4690#endif
4691 addr += 16;
4692 }
4693 }
4694 }
4695 else
4696 {
4697 PX86FPUSTATE fp = (PX86FPUSTATE)ptr;
4698 int fptag;
4699
4700 fp->FCW = env->fpuc;
4701 fp->FSW = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4702 fptag = 0;
4703 for (i=7; i>=0; i--) {
4704 fptag <<= 2;
4705 if (env->fptags[i]) {
4706 fptag |= 3;
4707 } else {
4708 /* the FPU automatically computes it */
4709 }
4710 }
4711 fp->FTW = fptag;
4712
4713 for(i = 0;i < 8; i++) {
4714 tmp = ST(i);
4715 helper_fstt_raw(tmp, &fp->regs[i].reg[0]);
4716 }
4717 }
4718}
4719
4720//*****************************************************************************
4721#undef lduw
4722#undef ldl
4723#undef ldq
4724#define lduw(a) *(uint16_t *)(a)
4725#define ldl(a) *(uint32_t *)(a)
4726#define ldq(a) *(uint64_t *)(a)
4727//*****************************************************************************
4728void save_raw_fp_state(CPUX86State *env, uint8_t *ptr)
4729{
4730 int i, fpus, fptag, nb_xmm_regs;
4731 CPU86_LDouble tmp;
4732 uint8_t *addr;
4733
4734 if (env->cpuid_features & CPUID_FXSR)
4735 {
4736 env->fpuc = lduw(ptr);
4737 fpus = lduw(ptr + 2);
4738 fptag = lduw(ptr + 4);
4739 env->fpstt = (fpus >> 11) & 7;
4740 env->fpus = fpus & ~0x3800;
4741 fptag ^= 0xff;
4742 for(i = 0;i < 8; i++) {
4743 env->fptags[i] = ((fptag >> i) & 1);
4744 }
4745
4746 addr = ptr + 0x20;
4747 for(i = 0;i < 8; i++) {
4748 tmp = helper_fldt_raw(addr);
4749 ST(i) = tmp;
4750 addr += 16;
4751 }
4752
4753 if (env->cr[4] & CR4_OSFXSR_MASK) {
4754 /* XXX: finish it, endianness */
4755 env->mxcsr = ldl(ptr + 0x18);
4756 //ldl(ptr + 0x1c);
4757 nb_xmm_regs = 8 << data64;
4758 addr = ptr + 0xa0;
4759 for(i = 0; i < nb_xmm_regs; i++) {
4760 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4761 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4762 addr += 16;
4763 }
4764 }
4765 }
4766 else
4767 {
4768 PX86FPUSTATE fp = (PX86FPUSTATE)ptr;
4769 int fptag, j;
4770
4771 env->fpuc = fp->FCW;
4772 env->fpstt = (fp->FSW >> 11) & 7;
4773 env->fpus = fp->FSW & ~0x3800;
4774 fptag = fp->FTW;
4775 for(i = 0;i < 8; i++) {
4776 env->fptags[i] = ((fptag & 3) == 3);
4777 fptag >>= 2;
4778 }
4779 j = env->fpstt;
4780 for(i = 0;i < 8; i++) {
4781 tmp = helper_fldt_raw(&fp->regs[i].reg[0]);
4782 ST(i) = tmp;
4783 }
4784 }
4785}
4786//*****************************************************************************
4787//*****************************************************************************
4788
4789#endif /* VBOX */
4790
Note: See TracBrowser for help on using the repository browser.

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