]> git.proxmox.com Git - qemu.git/blame - target-i386/op_helper.c
target-i386: fix CVE-2007-1322
[qemu.git] / target-i386 / op_helper.c
CommitLineData
eaa728ee
FB
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#define CPU_NO_GLOBAL_REGS
21#include "exec.h"
22#include "host-utils.h"
23
24//#define DEBUG_PCALL
25
26#if 0
27#define raise_exception_err(a, b)\
28do {\
29 if (logfile)\
30 fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
31 (raise_exception_err)(a, b);\
32} while (0)
33#endif
34
35const uint8_t parity_table[256] = {
36 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
37 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
38 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
40 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
41 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
42 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
43 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
44 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
46 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
49 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
52 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
53 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
57 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
58 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
59 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
60 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
61 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
62 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
64 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
65 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
66 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
67 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
68};
69
70/* modulo 17 table */
71const uint8_t rclw_table[32] = {
72 0, 1, 2, 3, 4, 5, 6, 7,
73 8, 9,10,11,12,13,14,15,
74 16, 0, 1, 2, 3, 4, 5, 6,
75 7, 8, 9,10,11,12,13,14,
76};
77
78/* modulo 9 table */
79const uint8_t rclb_table[32] = {
80 0, 1, 2, 3, 4, 5, 6, 7,
81 8, 0, 1, 2, 3, 4, 5, 6,
82 7, 8, 0, 1, 2, 3, 4, 5,
83 6, 7, 8, 0, 1, 2, 3, 4,
84};
85
86const CPU86_LDouble f15rk[7] =
87{
88 0.00000000000000000000L,
89 1.00000000000000000000L,
90 3.14159265358979323851L, /*pi*/
91 0.30102999566398119523L, /*lg2*/
92 0.69314718055994530943L, /*ln2*/
93 1.44269504088896340739L, /*l2e*/
94 3.32192809488736234781L, /*l2t*/
95};
96
97/* broken thread support */
98
b1d8e52e 99static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
eaa728ee
FB
100
101void helper_lock(void)
102{
103 spin_lock(&global_cpu_lock);
104}
105
106void helper_unlock(void)
107{
108 spin_unlock(&global_cpu_lock);
109}
110
111void helper_write_eflags(target_ulong t0, uint32_t update_mask)
112{
113 load_eflags(t0, update_mask);
114}
115
116target_ulong helper_read_eflags(void)
117{
118 uint32_t eflags;
a7812ae4 119 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
120 eflags |= (DF & DF_MASK);
121 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
122 return eflags;
123}
124
125/* return non zero if error */
126static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
127 int selector)
128{
129 SegmentCache *dt;
130 int index;
131 target_ulong ptr;
132
133 if (selector & 0x4)
134 dt = &env->ldt;
135 else
136 dt = &env->gdt;
137 index = selector & ~7;
138 if ((index + 7) > dt->limit)
139 return -1;
140 ptr = dt->base + index;
141 *e1_ptr = ldl_kernel(ptr);
142 *e2_ptr = ldl_kernel(ptr + 4);
143 return 0;
144}
145
146static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
147{
148 unsigned int limit;
149 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
150 if (e2 & DESC_G_MASK)
151 limit = (limit << 12) | 0xfff;
152 return limit;
153}
154
155static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
156{
157 return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
158}
159
160static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
161{
162 sc->base = get_seg_base(e1, e2);
163 sc->limit = get_seg_limit(e1, e2);
164 sc->flags = e2;
165}
166
167/* init the segment cache in vm86 mode. */
168static inline void load_seg_vm(int seg, int selector)
169{
170 selector &= 0xffff;
171 cpu_x86_load_seg_cache(env, seg, selector,
172 (selector << 4), 0xffff, 0);
173}
174
175static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
176 uint32_t *esp_ptr, int dpl)
177{
178 int type, index, shift;
179
180#if 0
181 {
182 int i;
183 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
184 for(i=0;i<env->tr.limit;i++) {
185 printf("%02x ", env->tr.base[i]);
186 if ((i & 7) == 7) printf("\n");
187 }
188 printf("\n");
189 }
190#endif
191
192 if (!(env->tr.flags & DESC_P_MASK))
193 cpu_abort(env, "invalid tss");
194 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
195 if ((type & 7) != 1)
196 cpu_abort(env, "invalid tss type");
197 shift = type >> 3;
198 index = (dpl * 4 + 2) << shift;
199 if (index + (4 << shift) - 1 > env->tr.limit)
200 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
201 if (shift == 0) {
202 *esp_ptr = lduw_kernel(env->tr.base + index);
203 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
204 } else {
205 *esp_ptr = ldl_kernel(env->tr.base + index);
206 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
207 }
208}
209
210/* XXX: merge with load_seg() */
211static void tss_load_seg(int seg_reg, int selector)
212{
213 uint32_t e1, e2;
214 int rpl, dpl, cpl;
215
216 if ((selector & 0xfffc) != 0) {
217 if (load_segment(&e1, &e2, selector) != 0)
218 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
219 if (!(e2 & DESC_S_MASK))
220 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
221 rpl = selector & 3;
222 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
223 cpl = env->hflags & HF_CPL_MASK;
224 if (seg_reg == R_CS) {
225 if (!(e2 & DESC_CS_MASK))
226 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
227 /* XXX: is it correct ? */
228 if (dpl != rpl)
229 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230 if ((e2 & DESC_C_MASK) && dpl > rpl)
231 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
232 } else if (seg_reg == R_SS) {
233 /* SS must be writable data */
234 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
235 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
236 if (dpl != cpl || dpl != rpl)
237 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
238 } else {
239 /* not readable code */
240 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
241 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
242 /* if data or non conforming code, checks the rights */
243 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
244 if (dpl < cpl || dpl < rpl)
245 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
246 }
247 }
248 if (!(e2 & DESC_P_MASK))
249 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
250 cpu_x86_load_seg_cache(env, seg_reg, selector,
251 get_seg_base(e1, e2),
252 get_seg_limit(e1, e2),
253 e2);
254 } else {
255 if (seg_reg == R_SS || seg_reg == R_CS)
256 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
257 }
258}
259
260#define SWITCH_TSS_JMP 0
261#define SWITCH_TSS_IRET 1
262#define SWITCH_TSS_CALL 2
263
264/* XXX: restore CPU state in registers (PowerPC case) */
265static void switch_tss(int tss_selector,
266 uint32_t e1, uint32_t e2, int source,
267 uint32_t next_eip)
268{
269 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
270 target_ulong tss_base;
271 uint32_t new_regs[8], new_segs[6];
272 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
273 uint32_t old_eflags, eflags_mask;
274 SegmentCache *dt;
275 int index;
276 target_ulong ptr;
277
278 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
279#ifdef DEBUG_PCALL
280 if (loglevel & CPU_LOG_PCALL)
281 fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
282#endif
283
284 /* if task gate, we read the TSS segment and we load it */
285 if (type == 5) {
286 if (!(e2 & DESC_P_MASK))
287 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
288 tss_selector = e1 >> 16;
289 if (tss_selector & 4)
290 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
291 if (load_segment(&e1, &e2, tss_selector) != 0)
292 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
293 if (e2 & DESC_S_MASK)
294 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
295 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
296 if ((type & 7) != 1)
297 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
298 }
299
300 if (!(e2 & DESC_P_MASK))
301 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
302
303 if (type & 8)
304 tss_limit_max = 103;
305 else
306 tss_limit_max = 43;
307 tss_limit = get_seg_limit(e1, e2);
308 tss_base = get_seg_base(e1, e2);
309 if ((tss_selector & 4) != 0 ||
310 tss_limit < tss_limit_max)
311 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
312 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
313 if (old_type & 8)
314 old_tss_limit_max = 103;
315 else
316 old_tss_limit_max = 43;
317
318 /* read all the registers from the new TSS */
319 if (type & 8) {
320 /* 32 bit */
321 new_cr3 = ldl_kernel(tss_base + 0x1c);
322 new_eip = ldl_kernel(tss_base + 0x20);
323 new_eflags = ldl_kernel(tss_base + 0x24);
324 for(i = 0; i < 8; i++)
325 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
326 for(i = 0; i < 6; i++)
327 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
328 new_ldt = lduw_kernel(tss_base + 0x60);
329 new_trap = ldl_kernel(tss_base + 0x64);
330 } else {
331 /* 16 bit */
332 new_cr3 = 0;
333 new_eip = lduw_kernel(tss_base + 0x0e);
334 new_eflags = lduw_kernel(tss_base + 0x10);
335 for(i = 0; i < 8; i++)
336 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
337 for(i = 0; i < 4; i++)
338 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
339 new_ldt = lduw_kernel(tss_base + 0x2a);
340 new_segs[R_FS] = 0;
341 new_segs[R_GS] = 0;
342 new_trap = 0;
343 }
344
345 /* NOTE: we must avoid memory exceptions during the task switch,
346 so we make dummy accesses before */
347 /* XXX: it can still fail in some cases, so a bigger hack is
348 necessary to valid the TLB after having done the accesses */
349
350 v1 = ldub_kernel(env->tr.base);
351 v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
352 stb_kernel(env->tr.base, v1);
353 stb_kernel(env->tr.base + old_tss_limit_max, v2);
354
355 /* clear busy bit (it is restartable) */
356 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
357 target_ulong ptr;
358 uint32_t e2;
359 ptr = env->gdt.base + (env->tr.selector & ~7);
360 e2 = ldl_kernel(ptr + 4);
361 e2 &= ~DESC_TSS_BUSY_MASK;
362 stl_kernel(ptr + 4, e2);
363 }
364 old_eflags = compute_eflags();
365 if (source == SWITCH_TSS_IRET)
366 old_eflags &= ~NT_MASK;
367
368 /* save the current state in the old TSS */
369 if (type & 8) {
370 /* 32 bit */
371 stl_kernel(env->tr.base + 0x20, next_eip);
372 stl_kernel(env->tr.base + 0x24, old_eflags);
373 stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
374 stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
375 stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
376 stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
377 stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
378 stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
379 stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
380 stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
381 for(i = 0; i < 6; i++)
382 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
383 } else {
384 /* 16 bit */
385 stw_kernel(env->tr.base + 0x0e, next_eip);
386 stw_kernel(env->tr.base + 0x10, old_eflags);
387 stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
388 stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
389 stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
390 stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
391 stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
392 stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
393 stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
394 stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
395 for(i = 0; i < 4; i++)
396 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
397 }
398
399 /* now if an exception occurs, it will occurs in the next task
400 context */
401
402 if (source == SWITCH_TSS_CALL) {
403 stw_kernel(tss_base, env->tr.selector);
404 new_eflags |= NT_MASK;
405 }
406
407 /* set busy bit */
408 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
409 target_ulong ptr;
410 uint32_t e2;
411 ptr = env->gdt.base + (tss_selector & ~7);
412 e2 = ldl_kernel(ptr + 4);
413 e2 |= DESC_TSS_BUSY_MASK;
414 stl_kernel(ptr + 4, e2);
415 }
416
417 /* set the new CPU state */
418 /* from this point, any exception which occurs can give problems */
419 env->cr[0] |= CR0_TS_MASK;
420 env->hflags |= HF_TS_MASK;
421 env->tr.selector = tss_selector;
422 env->tr.base = tss_base;
423 env->tr.limit = tss_limit;
424 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
425
426 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
427 cpu_x86_update_cr3(env, new_cr3);
428 }
429
430 /* load all registers without an exception, then reload them with
431 possible exception */
432 env->eip = new_eip;
433 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
434 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
435 if (!(type & 8))
436 eflags_mask &= 0xffff;
437 load_eflags(new_eflags, eflags_mask);
438 /* XXX: what to do in 16 bit case ? */
439 EAX = new_regs[0];
440 ECX = new_regs[1];
441 EDX = new_regs[2];
442 EBX = new_regs[3];
443 ESP = new_regs[4];
444 EBP = new_regs[5];
445 ESI = new_regs[6];
446 EDI = new_regs[7];
447 if (new_eflags & VM_MASK) {
448 for(i = 0; i < 6; i++)
449 load_seg_vm(i, new_segs[i]);
450 /* in vm86, CPL is always 3 */
451 cpu_x86_set_cpl(env, 3);
452 } else {
453 /* CPL is set the RPL of CS */
454 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
455 /* first just selectors as the rest may trigger exceptions */
456 for(i = 0; i < 6; i++)
457 cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
458 }
459
460 env->ldt.selector = new_ldt & ~4;
461 env->ldt.base = 0;
462 env->ldt.limit = 0;
463 env->ldt.flags = 0;
464
465 /* load the LDT */
466 if (new_ldt & 4)
467 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
468
469 if ((new_ldt & 0xfffc) != 0) {
470 dt = &env->gdt;
471 index = new_ldt & ~7;
472 if ((index + 7) > dt->limit)
473 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
474 ptr = dt->base + index;
475 e1 = ldl_kernel(ptr);
476 e2 = ldl_kernel(ptr + 4);
477 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
478 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
479 if (!(e2 & DESC_P_MASK))
480 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
481 load_seg_cache_raw_dt(&env->ldt, e1, e2);
482 }
483
484 /* load the segments */
485 if (!(new_eflags & VM_MASK)) {
486 tss_load_seg(R_CS, new_segs[R_CS]);
487 tss_load_seg(R_SS, new_segs[R_SS]);
488 tss_load_seg(R_ES, new_segs[R_ES]);
489 tss_load_seg(R_DS, new_segs[R_DS]);
490 tss_load_seg(R_FS, new_segs[R_FS]);
491 tss_load_seg(R_GS, new_segs[R_GS]);
492 }
493
494 /* check that EIP is in the CS segment limits */
495 if (new_eip > env->segs[R_CS].limit) {
496 /* XXX: different exception if CALL ? */
497 raise_exception_err(EXCP0D_GPF, 0);
498 }
01df040b
AL
499
500#ifndef CONFIG_USER_ONLY
501 /* reset local breakpoints */
502 if (env->dr[7] & 0x55) {
503 for (i = 0; i < 4; i++) {
504 if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
505 hw_breakpoint_remove(env, i);
506 }
507 env->dr[7] &= ~0x55;
508 }
509#endif
eaa728ee
FB
510}
511
512/* check if Port I/O is allowed in TSS */
513static inline void check_io(int addr, int size)
514{
515 int io_offset, val, mask;
516
517 /* TSS must be a valid 32 bit one */
518 if (!(env->tr.flags & DESC_P_MASK) ||
519 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
520 env->tr.limit < 103)
521 goto fail;
522 io_offset = lduw_kernel(env->tr.base + 0x66);
523 io_offset += (addr >> 3);
524 /* Note: the check needs two bytes */
525 if ((io_offset + 1) > env->tr.limit)
526 goto fail;
527 val = lduw_kernel(env->tr.base + io_offset);
528 val >>= (addr & 7);
529 mask = (1 << size) - 1;
530 /* all bits must be zero to allow the I/O */
531 if ((val & mask) != 0) {
532 fail:
533 raise_exception_err(EXCP0D_GPF, 0);
534 }
535}
536
537void helper_check_iob(uint32_t t0)
538{
539 check_io(t0, 1);
540}
541
542void helper_check_iow(uint32_t t0)
543{
544 check_io(t0, 2);
545}
546
547void helper_check_iol(uint32_t t0)
548{
549 check_io(t0, 4);
550}
551
552void helper_outb(uint32_t port, uint32_t data)
553{
554 cpu_outb(env, port, data & 0xff);
555}
556
557target_ulong helper_inb(uint32_t port)
558{
559 return cpu_inb(env, port);
560}
561
562void helper_outw(uint32_t port, uint32_t data)
563{
564 cpu_outw(env, port, data & 0xffff);
565}
566
567target_ulong helper_inw(uint32_t port)
568{
569 return cpu_inw(env, port);
570}
571
572void helper_outl(uint32_t port, uint32_t data)
573{
574 cpu_outl(env, port, data);
575}
576
577target_ulong helper_inl(uint32_t port)
578{
579 return cpu_inl(env, port);
580}
581
582static inline unsigned int get_sp_mask(unsigned int e2)
583{
584 if (e2 & DESC_B_MASK)
585 return 0xffffffff;
586 else
587 return 0xffff;
588}
589
590#ifdef TARGET_X86_64
591#define SET_ESP(val, sp_mask)\
592do {\
593 if ((sp_mask) == 0xffff)\
594 ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
595 else if ((sp_mask) == 0xffffffffLL)\
596 ESP = (uint32_t)(val);\
597 else\
598 ESP = (val);\
599} while (0)
600#else
601#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
602#endif
603
c0a04f0e
AL
604/* in 64-bit machines, this can overflow. So this segment addition macro
605 * can be used to trim the value to 32-bit whenever needed */
606#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
607
eaa728ee
FB
608/* XXX: add a is_user flag to have proper security support */
609#define PUSHW(ssp, sp, sp_mask, val)\
610{\
611 sp -= 2;\
612 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
613}
614
615#define PUSHL(ssp, sp, sp_mask, val)\
616{\
617 sp -= 4;\
c0a04f0e 618 stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
eaa728ee
FB
619}
620
621#define POPW(ssp, sp, sp_mask, val)\
622{\
623 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
624 sp += 2;\
625}
626
627#define POPL(ssp, sp, sp_mask, val)\
628{\
c0a04f0e 629 val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
eaa728ee
FB
630 sp += 4;\
631}
632
633/* protected mode interrupt */
634static void do_interrupt_protected(int intno, int is_int, int error_code,
635 unsigned int next_eip, int is_hw)
636{
637 SegmentCache *dt;
638 target_ulong ptr, ssp;
639 int type, dpl, selector, ss_dpl, cpl;
640 int has_error_code, new_stack, shift;
641 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
642 uint32_t old_eip, sp_mask;
eaa728ee 643
eaa728ee
FB
644 has_error_code = 0;
645 if (!is_int && !is_hw) {
646 switch(intno) {
647 case 8:
648 case 10:
649 case 11:
650 case 12:
651 case 13:
652 case 14:
653 case 17:
654 has_error_code = 1;
655 break;
656 }
657 }
658 if (is_int)
659 old_eip = next_eip;
660 else
661 old_eip = env->eip;
662
663 dt = &env->idt;
664 if (intno * 8 + 7 > dt->limit)
665 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
666 ptr = dt->base + intno * 8;
667 e1 = ldl_kernel(ptr);
668 e2 = ldl_kernel(ptr + 4);
669 /* check gate type */
670 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
671 switch(type) {
672 case 5: /* task gate */
673 /* must do that check here to return the correct error code */
674 if (!(e2 & DESC_P_MASK))
675 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
676 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
677 if (has_error_code) {
678 int type;
679 uint32_t mask;
680 /* push the error code */
681 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
682 shift = type >> 3;
683 if (env->segs[R_SS].flags & DESC_B_MASK)
684 mask = 0xffffffff;
685 else
686 mask = 0xffff;
687 esp = (ESP - (2 << shift)) & mask;
688 ssp = env->segs[R_SS].base + esp;
689 if (shift)
690 stl_kernel(ssp, error_code);
691 else
692 stw_kernel(ssp, error_code);
693 SET_ESP(esp, mask);
694 }
695 return;
696 case 6: /* 286 interrupt gate */
697 case 7: /* 286 trap gate */
698 case 14: /* 386 interrupt gate */
699 case 15: /* 386 trap gate */
700 break;
701 default:
702 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
703 break;
704 }
705 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
706 cpl = env->hflags & HF_CPL_MASK;
1235fc06 707 /* check privilege if software int */
eaa728ee
FB
708 if (is_int && dpl < cpl)
709 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
710 /* check valid bit */
711 if (!(e2 & DESC_P_MASK))
712 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
713 selector = e1 >> 16;
714 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
715 if ((selector & 0xfffc) == 0)
716 raise_exception_err(EXCP0D_GPF, 0);
717
718 if (load_segment(&e1, &e2, selector) != 0)
719 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
720 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
721 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
722 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
723 if (dpl > cpl)
724 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
725 if (!(e2 & DESC_P_MASK))
726 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
727 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
728 /* to inner privilege */
729 get_ss_esp_from_tss(&ss, &esp, dpl);
730 if ((ss & 0xfffc) == 0)
731 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
732 if ((ss & 3) != dpl)
733 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
734 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
735 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
736 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
737 if (ss_dpl != dpl)
738 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
739 if (!(ss_e2 & DESC_S_MASK) ||
740 (ss_e2 & DESC_CS_MASK) ||
741 !(ss_e2 & DESC_W_MASK))
742 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
743 if (!(ss_e2 & DESC_P_MASK))
744 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
745 new_stack = 1;
746 sp_mask = get_sp_mask(ss_e2);
747 ssp = get_seg_base(ss_e1, ss_e2);
748 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
749 /* to same privilege */
750 if (env->eflags & VM_MASK)
751 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
752 new_stack = 0;
753 sp_mask = get_sp_mask(env->segs[R_SS].flags);
754 ssp = env->segs[R_SS].base;
755 esp = ESP;
756 dpl = cpl;
757 } else {
758 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
759 new_stack = 0; /* avoid warning */
760 sp_mask = 0; /* avoid warning */
761 ssp = 0; /* avoid warning */
762 esp = 0; /* avoid warning */
763 }
764
765 shift = type >> 3;
766
767#if 0
768 /* XXX: check that enough room is available */
769 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
770 if (env->eflags & VM_MASK)
771 push_size += 8;
772 push_size <<= shift;
773#endif
774 if (shift == 1) {
775 if (new_stack) {
776 if (env->eflags & VM_MASK) {
777 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
778 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
779 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
780 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
781 }
782 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
783 PUSHL(ssp, esp, sp_mask, ESP);
784 }
785 PUSHL(ssp, esp, sp_mask, compute_eflags());
786 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
787 PUSHL(ssp, esp, sp_mask, old_eip);
788 if (has_error_code) {
789 PUSHL(ssp, esp, sp_mask, error_code);
790 }
791 } else {
792 if (new_stack) {
793 if (env->eflags & VM_MASK) {
794 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
795 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
796 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
797 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
798 }
799 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
800 PUSHW(ssp, esp, sp_mask, ESP);
801 }
802 PUSHW(ssp, esp, sp_mask, compute_eflags());
803 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
804 PUSHW(ssp, esp, sp_mask, old_eip);
805 if (has_error_code) {
806 PUSHW(ssp, esp, sp_mask, error_code);
807 }
808 }
809
810 if (new_stack) {
811 if (env->eflags & VM_MASK) {
812 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
813 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
814 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
815 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
816 }
817 ss = (ss & ~3) | dpl;
818 cpu_x86_load_seg_cache(env, R_SS, ss,
819 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
820 }
821 SET_ESP(esp, sp_mask);
822
823 selector = (selector & ~3) | dpl;
824 cpu_x86_load_seg_cache(env, R_CS, selector,
825 get_seg_base(e1, e2),
826 get_seg_limit(e1, e2),
827 e2);
828 cpu_x86_set_cpl(env, dpl);
829 env->eip = offset;
830
831 /* interrupt gate clear IF mask */
832 if ((type & 1) == 0) {
833 env->eflags &= ~IF_MASK;
834 }
835 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
836}
837
838#ifdef TARGET_X86_64
839
840#define PUSHQ(sp, val)\
841{\
842 sp -= 8;\
843 stq_kernel(sp, (val));\
844}
845
846#define POPQ(sp, val)\
847{\
848 val = ldq_kernel(sp);\
849 sp += 8;\
850}
851
852static inline target_ulong get_rsp_from_tss(int level)
853{
854 int index;
855
856#if 0
857 printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
858 env->tr.base, env->tr.limit);
859#endif
860
861 if (!(env->tr.flags & DESC_P_MASK))
862 cpu_abort(env, "invalid tss");
863 index = 8 * level + 4;
864 if ((index + 7) > env->tr.limit)
865 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
866 return ldq_kernel(env->tr.base + index);
867}
868
869/* 64 bit interrupt */
870static void do_interrupt64(int intno, int is_int, int error_code,
871 target_ulong next_eip, int is_hw)
872{
873 SegmentCache *dt;
874 target_ulong ptr;
875 int type, dpl, selector, cpl, ist;
876 int has_error_code, new_stack;
877 uint32_t e1, e2, e3, ss;
878 target_ulong old_eip, esp, offset;
eaa728ee 879
eaa728ee
FB
880 has_error_code = 0;
881 if (!is_int && !is_hw) {
882 switch(intno) {
883 case 8:
884 case 10:
885 case 11:
886 case 12:
887 case 13:
888 case 14:
889 case 17:
890 has_error_code = 1;
891 break;
892 }
893 }
894 if (is_int)
895 old_eip = next_eip;
896 else
897 old_eip = env->eip;
898
899 dt = &env->idt;
900 if (intno * 16 + 15 > dt->limit)
901 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
902 ptr = dt->base + intno * 16;
903 e1 = ldl_kernel(ptr);
904 e2 = ldl_kernel(ptr + 4);
905 e3 = ldl_kernel(ptr + 8);
906 /* check gate type */
907 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
908 switch(type) {
909 case 14: /* 386 interrupt gate */
910 case 15: /* 386 trap gate */
911 break;
912 default:
913 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
914 break;
915 }
916 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
917 cpl = env->hflags & HF_CPL_MASK;
1235fc06 918 /* check privilege if software int */
eaa728ee
FB
919 if (is_int && dpl < cpl)
920 raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
921 /* check valid bit */
922 if (!(e2 & DESC_P_MASK))
923 raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
924 selector = e1 >> 16;
925 offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
926 ist = e2 & 7;
927 if ((selector & 0xfffc) == 0)
928 raise_exception_err(EXCP0D_GPF, 0);
929
930 if (load_segment(&e1, &e2, selector) != 0)
931 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
932 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
933 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
934 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
935 if (dpl > cpl)
936 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
937 if (!(e2 & DESC_P_MASK))
938 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
939 if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
940 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
941 if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
942 /* to inner privilege */
943 if (ist != 0)
944 esp = get_rsp_from_tss(ist + 3);
945 else
946 esp = get_rsp_from_tss(dpl);
947 esp &= ~0xfLL; /* align stack */
948 ss = 0;
949 new_stack = 1;
950 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
951 /* to same privilege */
952 if (env->eflags & VM_MASK)
953 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
954 new_stack = 0;
955 if (ist != 0)
956 esp = get_rsp_from_tss(ist + 3);
957 else
958 esp = ESP;
959 esp &= ~0xfLL; /* align stack */
960 dpl = cpl;
961 } else {
962 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
963 new_stack = 0; /* avoid warning */
964 esp = 0; /* avoid warning */
965 }
966
967 PUSHQ(esp, env->segs[R_SS].selector);
968 PUSHQ(esp, ESP);
969 PUSHQ(esp, compute_eflags());
970 PUSHQ(esp, env->segs[R_CS].selector);
971 PUSHQ(esp, old_eip);
972 if (has_error_code) {
973 PUSHQ(esp, error_code);
974 }
975
976 if (new_stack) {
977 ss = 0 | dpl;
978 cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
979 }
980 ESP = esp;
981
982 selector = (selector & ~3) | dpl;
983 cpu_x86_load_seg_cache(env, R_CS, selector,
984 get_seg_base(e1, e2),
985 get_seg_limit(e1, e2),
986 e2);
987 cpu_x86_set_cpl(env, dpl);
988 env->eip = offset;
989
990 /* interrupt gate clear IF mask */
991 if ((type & 1) == 0) {
992 env->eflags &= ~IF_MASK;
993 }
994 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
995}
996#endif
997
998#if defined(CONFIG_USER_ONLY)
999void helper_syscall(int next_eip_addend)
1000{
1001 env->exception_index = EXCP_SYSCALL;
1002 env->exception_next_eip = env->eip + next_eip_addend;
1003 cpu_loop_exit();
1004}
1005#else
1006void helper_syscall(int next_eip_addend)
1007{
1008 int selector;
1009
1010 if (!(env->efer & MSR_EFER_SCE)) {
1011 raise_exception_err(EXCP06_ILLOP, 0);
1012 }
1013 selector = (env->star >> 32) & 0xffff;
1014#ifdef TARGET_X86_64
1015 if (env->hflags & HF_LMA_MASK) {
1016 int code64;
1017
1018 ECX = env->eip + next_eip_addend;
1019 env->regs[11] = compute_eflags();
1020
1021 code64 = env->hflags & HF_CS64_MASK;
1022
1023 cpu_x86_set_cpl(env, 0);
1024 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1025 0, 0xffffffff,
1026 DESC_G_MASK | DESC_P_MASK |
1027 DESC_S_MASK |
1028 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
1029 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1030 0, 0xffffffff,
1031 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1032 DESC_S_MASK |
1033 DESC_W_MASK | DESC_A_MASK);
1034 env->eflags &= ~env->fmask;
1035 load_eflags(env->eflags, 0);
1036 if (code64)
1037 env->eip = env->lstar;
1038 else
1039 env->eip = env->cstar;
1040 } else
1041#endif
1042 {
1043 ECX = (uint32_t)(env->eip + next_eip_addend);
1044
1045 cpu_x86_set_cpl(env, 0);
1046 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1047 0, 0xffffffff,
1048 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1049 DESC_S_MASK |
1050 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1051 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1052 0, 0xffffffff,
1053 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1054 DESC_S_MASK |
1055 DESC_W_MASK | DESC_A_MASK);
1056 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1057 env->eip = (uint32_t)env->star;
1058 }
1059}
1060#endif
1061
1062void helper_sysret(int dflag)
1063{
1064 int cpl, selector;
1065
1066 if (!(env->efer & MSR_EFER_SCE)) {
1067 raise_exception_err(EXCP06_ILLOP, 0);
1068 }
1069 cpl = env->hflags & HF_CPL_MASK;
1070 if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1071 raise_exception_err(EXCP0D_GPF, 0);
1072 }
1073 selector = (env->star >> 48) & 0xffff;
1074#ifdef TARGET_X86_64
1075 if (env->hflags & HF_LMA_MASK) {
1076 if (dflag == 2) {
1077 cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1078 0, 0xffffffff,
1079 DESC_G_MASK | DESC_P_MASK |
1080 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1081 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1082 DESC_L_MASK);
1083 env->eip = ECX;
1084 } else {
1085 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1086 0, 0xffffffff,
1087 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1088 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1089 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1090 env->eip = (uint32_t)ECX;
1091 }
1092 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1093 0, 0xffffffff,
1094 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1095 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1096 DESC_W_MASK | DESC_A_MASK);
1097 load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1098 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1099 cpu_x86_set_cpl(env, 3);
1100 } else
1101#endif
1102 {
1103 cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1104 0, 0xffffffff,
1105 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1106 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1107 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1108 env->eip = (uint32_t)ECX;
1109 cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1110 0, 0xffffffff,
1111 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1112 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1113 DESC_W_MASK | DESC_A_MASK);
1114 env->eflags |= IF_MASK;
1115 cpu_x86_set_cpl(env, 3);
1116 }
1117#ifdef USE_KQEMU
1118 if (kqemu_is_ok(env)) {
1119 if (env->hflags & HF_LMA_MASK)
1120 CC_OP = CC_OP_EFLAGS;
1121 env->exception_index = -1;
1122 cpu_loop_exit();
1123 }
1124#endif
1125}
1126
1127/* real mode interrupt */
1128static void do_interrupt_real(int intno, int is_int, int error_code,
1129 unsigned int next_eip)
1130{
1131 SegmentCache *dt;
1132 target_ulong ptr, ssp;
1133 int selector;
1134 uint32_t offset, esp;
1135 uint32_t old_cs, old_eip;
eaa728ee 1136
eaa728ee
FB
1137 /* real mode (simpler !) */
1138 dt = &env->idt;
1139 if (intno * 4 + 3 > dt->limit)
1140 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1141 ptr = dt->base + intno * 4;
1142 offset = lduw_kernel(ptr);
1143 selector = lduw_kernel(ptr + 2);
1144 esp = ESP;
1145 ssp = env->segs[R_SS].base;
1146 if (is_int)
1147 old_eip = next_eip;
1148 else
1149 old_eip = env->eip;
1150 old_cs = env->segs[R_CS].selector;
1151 /* XXX: use SS segment size ? */
1152 PUSHW(ssp, esp, 0xffff, compute_eflags());
1153 PUSHW(ssp, esp, 0xffff, old_cs);
1154 PUSHW(ssp, esp, 0xffff, old_eip);
1155
1156 /* update processor state */
1157 ESP = (ESP & ~0xffff) | (esp & 0xffff);
1158 env->eip = offset;
1159 env->segs[R_CS].selector = selector;
1160 env->segs[R_CS].base = (selector << 4);
1161 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1162}
1163
1164/* fake user mode interrupt */
1165void do_interrupt_user(int intno, int is_int, int error_code,
1166 target_ulong next_eip)
1167{
1168 SegmentCache *dt;
1169 target_ulong ptr;
1170 int dpl, cpl, shift;
1171 uint32_t e2;
1172
1173 dt = &env->idt;
1174 if (env->hflags & HF_LMA_MASK) {
1175 shift = 4;
1176 } else {
1177 shift = 3;
1178 }
1179 ptr = dt->base + (intno << shift);
1180 e2 = ldl_kernel(ptr + 4);
1181
1182 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1183 cpl = env->hflags & HF_CPL_MASK;
1235fc06 1184 /* check privilege if software int */
eaa728ee
FB
1185 if (is_int && dpl < cpl)
1186 raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
1187
1188 /* Since we emulate only user space, we cannot do more than
1189 exiting the emulation with the suitable exception and error
1190 code */
1191 if (is_int)
1192 EIP = next_eip;
1193}
1194
1195/*
1196 * Begin execution of an interruption. is_int is TRUE if coming from
1197 * the int instruction. next_eip is the EIP value AFTER the interrupt
1198 * instruction. It is only relevant if is_int is TRUE.
1199 */
1200void do_interrupt(int intno, int is_int, int error_code,
1201 target_ulong next_eip, int is_hw)
1202{
1203 if (loglevel & CPU_LOG_INT) {
1204 if ((env->cr[0] & CR0_PE_MASK)) {
1205 static int count;
1206 fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1207 count, intno, error_code, is_int,
1208 env->hflags & HF_CPL_MASK,
1209 env->segs[R_CS].selector, EIP,
1210 (int)env->segs[R_CS].base + EIP,
1211 env->segs[R_SS].selector, ESP);
1212 if (intno == 0x0e) {
1213 fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1214 } else {
1215 fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1216 }
1217 fprintf(logfile, "\n");
1218 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1219#if 0
1220 {
1221 int i;
1222 uint8_t *ptr;
1223 fprintf(logfile, " code=");
1224 ptr = env->segs[R_CS].base + env->eip;
1225 for(i = 0; i < 16; i++) {
1226 fprintf(logfile, " %02x", ldub(ptr + i));
1227 }
1228 fprintf(logfile, "\n");
1229 }
1230#endif
1231 count++;
1232 }
1233 }
1234 if (env->cr[0] & CR0_PE_MASK) {
eb38c52c 1235#ifdef TARGET_X86_64
eaa728ee
FB
1236 if (env->hflags & HF_LMA_MASK) {
1237 do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1238 } else
1239#endif
1240 {
1241 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1242 }
1243 } else {
1244 do_interrupt_real(intno, is_int, error_code, next_eip);
1245 }
1246}
1247
1248/*
1249 * Check nested exceptions and change to double or triple fault if
1250 * needed. It should only be called, if this is not an interrupt.
1251 * Returns the new exception number.
1252 */
1253static int check_exception(int intno, int *error_code)
1254{
1255 int first_contributory = env->old_exception == 0 ||
1256 (env->old_exception >= 10 &&
1257 env->old_exception <= 13);
1258 int second_contributory = intno == 0 ||
1259 (intno >= 10 && intno <= 13);
1260
1261 if (loglevel & CPU_LOG_INT)
1262 fprintf(logfile, "check_exception old: 0x%x new 0x%x\n",
1263 env->old_exception, intno);
1264
1265 if (env->old_exception == EXCP08_DBLE)
1266 cpu_abort(env, "triple fault");
1267
1268 if ((first_contributory && second_contributory)
1269 || (env->old_exception == EXCP0E_PAGE &&
1270 (second_contributory || (intno == EXCP0E_PAGE)))) {
1271 intno = EXCP08_DBLE;
1272 *error_code = 0;
1273 }
1274
1275 if (second_contributory || (intno == EXCP0E_PAGE) ||
1276 (intno == EXCP08_DBLE))
1277 env->old_exception = intno;
1278
1279 return intno;
1280}
1281
1282/*
1283 * Signal an interruption. It is executed in the main CPU loop.
1284 * is_int is TRUE if coming from the int instruction. next_eip is the
1285 * EIP value AFTER the interrupt instruction. It is only relevant if
1286 * is_int is TRUE.
1287 */
1288void raise_interrupt(int intno, int is_int, int error_code,
1289 int next_eip_addend)
1290{
1291 if (!is_int) {
1292 helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1293 intno = check_exception(intno, &error_code);
872929aa
FB
1294 } else {
1295 helper_svm_check_intercept_param(SVM_EXIT_SWINT, 0);
eaa728ee
FB
1296 }
1297
1298 env->exception_index = intno;
1299 env->error_code = error_code;
1300 env->exception_is_int = is_int;
1301 env->exception_next_eip = env->eip + next_eip_addend;
1302 cpu_loop_exit();
1303}
1304
eaa728ee
FB
1305/* shortcuts to generate exceptions */
1306
1307void (raise_exception_err)(int exception_index, int error_code)
1308{
1309 raise_interrupt(exception_index, 0, error_code, 0);
1310}
1311
1312void raise_exception(int exception_index)
1313{
1314 raise_interrupt(exception_index, 0, 0, 0);
1315}
1316
1317/* SMM support */
1318
1319#if defined(CONFIG_USER_ONLY)
1320
1321void do_smm_enter(void)
1322{
1323}
1324
1325void helper_rsm(void)
1326{
1327}
1328
1329#else
1330
1331#ifdef TARGET_X86_64
1332#define SMM_REVISION_ID 0x00020064
1333#else
1334#define SMM_REVISION_ID 0x00020000
1335#endif
1336
1337void do_smm_enter(void)
1338{
1339 target_ulong sm_state;
1340 SegmentCache *dt;
1341 int i, offset;
1342
1343 if (loglevel & CPU_LOG_INT) {
1344 fprintf(logfile, "SMM: enter\n");
1345 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1346 }
1347
1348 env->hflags |= HF_SMM_MASK;
1349 cpu_smm_update(env);
1350
1351 sm_state = env->smbase + 0x8000;
1352
1353#ifdef TARGET_X86_64
1354 for(i = 0; i < 6; i++) {
1355 dt = &env->segs[i];
1356 offset = 0x7e00 + i * 16;
1357 stw_phys(sm_state + offset, dt->selector);
1358 stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1359 stl_phys(sm_state + offset + 4, dt->limit);
1360 stq_phys(sm_state + offset + 8, dt->base);
1361 }
1362
1363 stq_phys(sm_state + 0x7e68, env->gdt.base);
1364 stl_phys(sm_state + 0x7e64, env->gdt.limit);
1365
1366 stw_phys(sm_state + 0x7e70, env->ldt.selector);
1367 stq_phys(sm_state + 0x7e78, env->ldt.base);
1368 stl_phys(sm_state + 0x7e74, env->ldt.limit);
1369 stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1370
1371 stq_phys(sm_state + 0x7e88, env->idt.base);
1372 stl_phys(sm_state + 0x7e84, env->idt.limit);
1373
1374 stw_phys(sm_state + 0x7e90, env->tr.selector);
1375 stq_phys(sm_state + 0x7e98, env->tr.base);
1376 stl_phys(sm_state + 0x7e94, env->tr.limit);
1377 stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1378
1379 stq_phys(sm_state + 0x7ed0, env->efer);
1380
1381 stq_phys(sm_state + 0x7ff8, EAX);
1382 stq_phys(sm_state + 0x7ff0, ECX);
1383 stq_phys(sm_state + 0x7fe8, EDX);
1384 stq_phys(sm_state + 0x7fe0, EBX);
1385 stq_phys(sm_state + 0x7fd8, ESP);
1386 stq_phys(sm_state + 0x7fd0, EBP);
1387 stq_phys(sm_state + 0x7fc8, ESI);
1388 stq_phys(sm_state + 0x7fc0, EDI);
1389 for(i = 8; i < 16; i++)
1390 stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1391 stq_phys(sm_state + 0x7f78, env->eip);
1392 stl_phys(sm_state + 0x7f70, compute_eflags());
1393 stl_phys(sm_state + 0x7f68, env->dr[6]);
1394 stl_phys(sm_state + 0x7f60, env->dr[7]);
1395
1396 stl_phys(sm_state + 0x7f48, env->cr[4]);
1397 stl_phys(sm_state + 0x7f50, env->cr[3]);
1398 stl_phys(sm_state + 0x7f58, env->cr[0]);
1399
1400 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1401 stl_phys(sm_state + 0x7f00, env->smbase);
1402#else
1403 stl_phys(sm_state + 0x7ffc, env->cr[0]);
1404 stl_phys(sm_state + 0x7ff8, env->cr[3]);
1405 stl_phys(sm_state + 0x7ff4, compute_eflags());
1406 stl_phys(sm_state + 0x7ff0, env->eip);
1407 stl_phys(sm_state + 0x7fec, EDI);
1408 stl_phys(sm_state + 0x7fe8, ESI);
1409 stl_phys(sm_state + 0x7fe4, EBP);
1410 stl_phys(sm_state + 0x7fe0, ESP);
1411 stl_phys(sm_state + 0x7fdc, EBX);
1412 stl_phys(sm_state + 0x7fd8, EDX);
1413 stl_phys(sm_state + 0x7fd4, ECX);
1414 stl_phys(sm_state + 0x7fd0, EAX);
1415 stl_phys(sm_state + 0x7fcc, env->dr[6]);
1416 stl_phys(sm_state + 0x7fc8, env->dr[7]);
1417
1418 stl_phys(sm_state + 0x7fc4, env->tr.selector);
1419 stl_phys(sm_state + 0x7f64, env->tr.base);
1420 stl_phys(sm_state + 0x7f60, env->tr.limit);
1421 stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1422
1423 stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1424 stl_phys(sm_state + 0x7f80, env->ldt.base);
1425 stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1426 stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1427
1428 stl_phys(sm_state + 0x7f74, env->gdt.base);
1429 stl_phys(sm_state + 0x7f70, env->gdt.limit);
1430
1431 stl_phys(sm_state + 0x7f58, env->idt.base);
1432 stl_phys(sm_state + 0x7f54, env->idt.limit);
1433
1434 for(i = 0; i < 6; i++) {
1435 dt = &env->segs[i];
1436 if (i < 3)
1437 offset = 0x7f84 + i * 12;
1438 else
1439 offset = 0x7f2c + (i - 3) * 12;
1440 stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1441 stl_phys(sm_state + offset + 8, dt->base);
1442 stl_phys(sm_state + offset + 4, dt->limit);
1443 stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1444 }
1445 stl_phys(sm_state + 0x7f14, env->cr[4]);
1446
1447 stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1448 stl_phys(sm_state + 0x7ef8, env->smbase);
1449#endif
1450 /* init SMM cpu state */
1451
1452#ifdef TARGET_X86_64
5efc27bb 1453 cpu_load_efer(env, 0);
eaa728ee
FB
1454#endif
1455 load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1456 env->eip = 0x00008000;
1457 cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1458 0xffffffff, 0);
1459 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1460 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1461 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1462 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1463 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1464
1465 cpu_x86_update_cr0(env,
1466 env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1467 cpu_x86_update_cr4(env, 0);
1468 env->dr[7] = 0x00000400;
1469 CC_OP = CC_OP_EFLAGS;
1470}
1471
1472void helper_rsm(void)
1473{
1474 target_ulong sm_state;
1475 int i, offset;
1476 uint32_t val;
1477
1478 sm_state = env->smbase + 0x8000;
1479#ifdef TARGET_X86_64
5efc27bb 1480 cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
eaa728ee
FB
1481
1482 for(i = 0; i < 6; i++) {
1483 offset = 0x7e00 + i * 16;
1484 cpu_x86_load_seg_cache(env, i,
1485 lduw_phys(sm_state + offset),
1486 ldq_phys(sm_state + offset + 8),
1487 ldl_phys(sm_state + offset + 4),
1488 (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1489 }
1490
1491 env->gdt.base = ldq_phys(sm_state + 0x7e68);
1492 env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1493
1494 env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1495 env->ldt.base = ldq_phys(sm_state + 0x7e78);
1496 env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1497 env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1498
1499 env->idt.base = ldq_phys(sm_state + 0x7e88);
1500 env->idt.limit = ldl_phys(sm_state + 0x7e84);
1501
1502 env->tr.selector = lduw_phys(sm_state + 0x7e90);
1503 env->tr.base = ldq_phys(sm_state + 0x7e98);
1504 env->tr.limit = ldl_phys(sm_state + 0x7e94);
1505 env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1506
1507 EAX = ldq_phys(sm_state + 0x7ff8);
1508 ECX = ldq_phys(sm_state + 0x7ff0);
1509 EDX = ldq_phys(sm_state + 0x7fe8);
1510 EBX = ldq_phys(sm_state + 0x7fe0);
1511 ESP = ldq_phys(sm_state + 0x7fd8);
1512 EBP = ldq_phys(sm_state + 0x7fd0);
1513 ESI = ldq_phys(sm_state + 0x7fc8);
1514 EDI = ldq_phys(sm_state + 0x7fc0);
1515 for(i = 8; i < 16; i++)
1516 env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1517 env->eip = ldq_phys(sm_state + 0x7f78);
1518 load_eflags(ldl_phys(sm_state + 0x7f70),
1519 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1520 env->dr[6] = ldl_phys(sm_state + 0x7f68);
1521 env->dr[7] = ldl_phys(sm_state + 0x7f60);
1522
1523 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1524 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1525 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1526
1527 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1528 if (val & 0x20000) {
1529 env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1530 }
1531#else
1532 cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1533 cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1534 load_eflags(ldl_phys(sm_state + 0x7ff4),
1535 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1536 env->eip = ldl_phys(sm_state + 0x7ff0);
1537 EDI = ldl_phys(sm_state + 0x7fec);
1538 ESI = ldl_phys(sm_state + 0x7fe8);
1539 EBP = ldl_phys(sm_state + 0x7fe4);
1540 ESP = ldl_phys(sm_state + 0x7fe0);
1541 EBX = ldl_phys(sm_state + 0x7fdc);
1542 EDX = ldl_phys(sm_state + 0x7fd8);
1543 ECX = ldl_phys(sm_state + 0x7fd4);
1544 EAX = ldl_phys(sm_state + 0x7fd0);
1545 env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1546 env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1547
1548 env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1549 env->tr.base = ldl_phys(sm_state + 0x7f64);
1550 env->tr.limit = ldl_phys(sm_state + 0x7f60);
1551 env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1552
1553 env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1554 env->ldt.base = ldl_phys(sm_state + 0x7f80);
1555 env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1556 env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1557
1558 env->gdt.base = ldl_phys(sm_state + 0x7f74);
1559 env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1560
1561 env->idt.base = ldl_phys(sm_state + 0x7f58);
1562 env->idt.limit = ldl_phys(sm_state + 0x7f54);
1563
1564 for(i = 0; i < 6; i++) {
1565 if (i < 3)
1566 offset = 0x7f84 + i * 12;
1567 else
1568 offset = 0x7f2c + (i - 3) * 12;
1569 cpu_x86_load_seg_cache(env, i,
1570 ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1571 ldl_phys(sm_state + offset + 8),
1572 ldl_phys(sm_state + offset + 4),
1573 (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1574 }
1575 cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1576
1577 val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1578 if (val & 0x20000) {
1579 env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1580 }
1581#endif
1582 CC_OP = CC_OP_EFLAGS;
1583 env->hflags &= ~HF_SMM_MASK;
1584 cpu_smm_update(env);
1585
1586 if (loglevel & CPU_LOG_INT) {
1587 fprintf(logfile, "SMM: after RSM\n");
1588 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1589 }
1590}
1591
1592#endif /* !CONFIG_USER_ONLY */
1593
1594
1595/* division, flags are undefined */
1596
1597void helper_divb_AL(target_ulong t0)
1598{
1599 unsigned int num, den, q, r;
1600
1601 num = (EAX & 0xffff);
1602 den = (t0 & 0xff);
1603 if (den == 0) {
1604 raise_exception(EXCP00_DIVZ);
1605 }
1606 q = (num / den);
1607 if (q > 0xff)
1608 raise_exception(EXCP00_DIVZ);
1609 q &= 0xff;
1610 r = (num % den) & 0xff;
1611 EAX = (EAX & ~0xffff) | (r << 8) | q;
1612}
1613
1614void helper_idivb_AL(target_ulong t0)
1615{
1616 int num, den, q, r;
1617
1618 num = (int16_t)EAX;
1619 den = (int8_t)t0;
1620 if (den == 0) {
1621 raise_exception(EXCP00_DIVZ);
1622 }
1623 q = (num / den);
1624 if (q != (int8_t)q)
1625 raise_exception(EXCP00_DIVZ);
1626 q &= 0xff;
1627 r = (num % den) & 0xff;
1628 EAX = (EAX & ~0xffff) | (r << 8) | q;
1629}
1630
1631void helper_divw_AX(target_ulong t0)
1632{
1633 unsigned int num, den, q, r;
1634
1635 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1636 den = (t0 & 0xffff);
1637 if (den == 0) {
1638 raise_exception(EXCP00_DIVZ);
1639 }
1640 q = (num / den);
1641 if (q > 0xffff)
1642 raise_exception(EXCP00_DIVZ);
1643 q &= 0xffff;
1644 r = (num % den) & 0xffff;
1645 EAX = (EAX & ~0xffff) | q;
1646 EDX = (EDX & ~0xffff) | r;
1647}
1648
1649void helper_idivw_AX(target_ulong t0)
1650{
1651 int num, den, q, r;
1652
1653 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
1654 den = (int16_t)t0;
1655 if (den == 0) {
1656 raise_exception(EXCP00_DIVZ);
1657 }
1658 q = (num / den);
1659 if (q != (int16_t)q)
1660 raise_exception(EXCP00_DIVZ);
1661 q &= 0xffff;
1662 r = (num % den) & 0xffff;
1663 EAX = (EAX & ~0xffff) | q;
1664 EDX = (EDX & ~0xffff) | r;
1665}
1666
1667void helper_divl_EAX(target_ulong t0)
1668{
1669 unsigned int den, r;
1670 uint64_t num, q;
1671
1672 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1673 den = t0;
1674 if (den == 0) {
1675 raise_exception(EXCP00_DIVZ);
1676 }
1677 q = (num / den);
1678 r = (num % den);
1679 if (q > 0xffffffff)
1680 raise_exception(EXCP00_DIVZ);
1681 EAX = (uint32_t)q;
1682 EDX = (uint32_t)r;
1683}
1684
1685void helper_idivl_EAX(target_ulong t0)
1686{
1687 int den, r;
1688 int64_t num, q;
1689
1690 num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1691 den = t0;
1692 if (den == 0) {
1693 raise_exception(EXCP00_DIVZ);
1694 }
1695 q = (num / den);
1696 r = (num % den);
1697 if (q != (int32_t)q)
1698 raise_exception(EXCP00_DIVZ);
1699 EAX = (uint32_t)q;
1700 EDX = (uint32_t)r;
1701}
1702
1703/* bcd */
1704
1705/* XXX: exception */
1706void helper_aam(int base)
1707{
1708 int al, ah;
1709 al = EAX & 0xff;
1710 ah = al / base;
1711 al = al % base;
1712 EAX = (EAX & ~0xffff) | al | (ah << 8);
1713 CC_DST = al;
1714}
1715
1716void helper_aad(int base)
1717{
1718 int al, ah;
1719 al = EAX & 0xff;
1720 ah = (EAX >> 8) & 0xff;
1721 al = ((ah * base) + al) & 0xff;
1722 EAX = (EAX & ~0xffff) | al;
1723 CC_DST = al;
1724}
1725
1726void helper_aaa(void)
1727{
1728 int icarry;
1729 int al, ah, af;
1730 int eflags;
1731
a7812ae4 1732 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1733 af = eflags & CC_A;
1734 al = EAX & 0xff;
1735 ah = (EAX >> 8) & 0xff;
1736
1737 icarry = (al > 0xf9);
1738 if (((al & 0x0f) > 9 ) || af) {
1739 al = (al + 6) & 0x0f;
1740 ah = (ah + 1 + icarry) & 0xff;
1741 eflags |= CC_C | CC_A;
1742 } else {
1743 eflags &= ~(CC_C | CC_A);
1744 al &= 0x0f;
1745 }
1746 EAX = (EAX & ~0xffff) | al | (ah << 8);
1747 CC_SRC = eflags;
1748 FORCE_RET();
1749}
1750
1751void helper_aas(void)
1752{
1753 int icarry;
1754 int al, ah, af;
1755 int eflags;
1756
a7812ae4 1757 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1758 af = eflags & CC_A;
1759 al = EAX & 0xff;
1760 ah = (EAX >> 8) & 0xff;
1761
1762 icarry = (al < 6);
1763 if (((al & 0x0f) > 9 ) || af) {
1764 al = (al - 6) & 0x0f;
1765 ah = (ah - 1 - icarry) & 0xff;
1766 eflags |= CC_C | CC_A;
1767 } else {
1768 eflags &= ~(CC_C | CC_A);
1769 al &= 0x0f;
1770 }
1771 EAX = (EAX & ~0xffff) | al | (ah << 8);
1772 CC_SRC = eflags;
1773 FORCE_RET();
1774}
1775
1776void helper_daa(void)
1777{
1778 int al, af, cf;
1779 int eflags;
1780
a7812ae4 1781 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1782 cf = eflags & CC_C;
1783 af = eflags & CC_A;
1784 al = EAX & 0xff;
1785
1786 eflags = 0;
1787 if (((al & 0x0f) > 9 ) || af) {
1788 al = (al + 6) & 0xff;
1789 eflags |= CC_A;
1790 }
1791 if ((al > 0x9f) || cf) {
1792 al = (al + 0x60) & 0xff;
1793 eflags |= CC_C;
1794 }
1795 EAX = (EAX & ~0xff) | al;
1796 /* well, speed is not an issue here, so we compute the flags by hand */
1797 eflags |= (al == 0) << 6; /* zf */
1798 eflags |= parity_table[al]; /* pf */
1799 eflags |= (al & 0x80); /* sf */
1800 CC_SRC = eflags;
1801 FORCE_RET();
1802}
1803
1804void helper_das(void)
1805{
1806 int al, al1, af, cf;
1807 int eflags;
1808
a7812ae4 1809 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1810 cf = eflags & CC_C;
1811 af = eflags & CC_A;
1812 al = EAX & 0xff;
1813
1814 eflags = 0;
1815 al1 = al;
1816 if (((al & 0x0f) > 9 ) || af) {
1817 eflags |= CC_A;
1818 if (al < 6 || cf)
1819 eflags |= CC_C;
1820 al = (al - 6) & 0xff;
1821 }
1822 if ((al1 > 0x99) || cf) {
1823 al = (al - 0x60) & 0xff;
1824 eflags |= CC_C;
1825 }
1826 EAX = (EAX & ~0xff) | al;
1827 /* well, speed is not an issue here, so we compute the flags by hand */
1828 eflags |= (al == 0) << 6; /* zf */
1829 eflags |= parity_table[al]; /* pf */
1830 eflags |= (al & 0x80); /* sf */
1831 CC_SRC = eflags;
1832 FORCE_RET();
1833}
1834
1835void helper_into(int next_eip_addend)
1836{
1837 int eflags;
a7812ae4 1838 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1839 if (eflags & CC_O) {
1840 raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
1841 }
1842}
1843
1844void helper_cmpxchg8b(target_ulong a0)
1845{
1846 uint64_t d;
1847 int eflags;
1848
a7812ae4 1849 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1850 d = ldq(a0);
1851 if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
1852 stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
1853 eflags |= CC_Z;
1854 } else {
278ed7c3
FB
1855 /* always do the store */
1856 stq(a0, d);
eaa728ee
FB
1857 EDX = (uint32_t)(d >> 32);
1858 EAX = (uint32_t)d;
1859 eflags &= ~CC_Z;
1860 }
1861 CC_SRC = eflags;
1862}
1863
1864#ifdef TARGET_X86_64
1865void helper_cmpxchg16b(target_ulong a0)
1866{
1867 uint64_t d0, d1;
1868 int eflags;
1869
278ed7c3
FB
1870 if ((a0 & 0xf) != 0)
1871 raise_exception(EXCP0D_GPF);
a7812ae4 1872 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
1873 d0 = ldq(a0);
1874 d1 = ldq(a0 + 8);
1875 if (d0 == EAX && d1 == EDX) {
1876 stq(a0, EBX);
1877 stq(a0 + 8, ECX);
1878 eflags |= CC_Z;
1879 } else {
278ed7c3
FB
1880 /* always do the store */
1881 stq(a0, d0);
1882 stq(a0 + 8, d1);
eaa728ee
FB
1883 EDX = d1;
1884 EAX = d0;
1885 eflags &= ~CC_Z;
1886 }
1887 CC_SRC = eflags;
1888}
1889#endif
1890
1891void helper_single_step(void)
1892{
01df040b
AL
1893#ifndef CONFIG_USER_ONLY
1894 check_hw_breakpoints(env, 1);
1895 env->dr[6] |= DR6_BS;
1896#endif
1897 raise_exception(EXCP01_DB);
eaa728ee
FB
1898}
1899
1900void helper_cpuid(void)
1901{
6fd805e1 1902 uint32_t eax, ebx, ecx, edx;
eaa728ee 1903
872929aa 1904 helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
e737b32a 1905
6fd805e1
AL
1906 cpu_x86_cpuid(env, (uint32_t)EAX, &eax, &ebx, &ecx, &edx);
1907 EAX = eax;
1908 EBX = ebx;
1909 ECX = ecx;
1910 EDX = edx;
eaa728ee
FB
1911}
1912
1913void helper_enter_level(int level, int data32, target_ulong t1)
1914{
1915 target_ulong ssp;
1916 uint32_t esp_mask, esp, ebp;
1917
1918 esp_mask = get_sp_mask(env->segs[R_SS].flags);
1919 ssp = env->segs[R_SS].base;
1920 ebp = EBP;
1921 esp = ESP;
1922 if (data32) {
1923 /* 32 bit */
1924 esp -= 4;
1925 while (--level) {
1926 esp -= 4;
1927 ebp -= 4;
1928 stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1929 }
1930 esp -= 4;
1931 stl(ssp + (esp & esp_mask), t1);
1932 } else {
1933 /* 16 bit */
1934 esp -= 2;
1935 while (--level) {
1936 esp -= 2;
1937 ebp -= 2;
1938 stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1939 }
1940 esp -= 2;
1941 stw(ssp + (esp & esp_mask), t1);
1942 }
1943}
1944
1945#ifdef TARGET_X86_64
1946void helper_enter64_level(int level, int data64, target_ulong t1)
1947{
1948 target_ulong esp, ebp;
1949 ebp = EBP;
1950 esp = ESP;
1951
1952 if (data64) {
1953 /* 64 bit */
1954 esp -= 8;
1955 while (--level) {
1956 esp -= 8;
1957 ebp -= 8;
1958 stq(esp, ldq(ebp));
1959 }
1960 esp -= 8;
1961 stq(esp, t1);
1962 } else {
1963 /* 16 bit */
1964 esp -= 2;
1965 while (--level) {
1966 esp -= 2;
1967 ebp -= 2;
1968 stw(esp, lduw(ebp));
1969 }
1970 esp -= 2;
1971 stw(esp, t1);
1972 }
1973}
1974#endif
1975
1976void helper_lldt(int selector)
1977{
1978 SegmentCache *dt;
1979 uint32_t e1, e2;
1980 int index, entry_limit;
1981 target_ulong ptr;
1982
1983 selector &= 0xffff;
1984 if ((selector & 0xfffc) == 0) {
1985 /* XXX: NULL selector case: invalid LDT */
1986 env->ldt.base = 0;
1987 env->ldt.limit = 0;
1988 } else {
1989 if (selector & 0x4)
1990 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1991 dt = &env->gdt;
1992 index = selector & ~7;
1993#ifdef TARGET_X86_64
1994 if (env->hflags & HF_LMA_MASK)
1995 entry_limit = 15;
1996 else
1997#endif
1998 entry_limit = 7;
1999 if ((index + entry_limit) > dt->limit)
2000 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2001 ptr = dt->base + index;
2002 e1 = ldl_kernel(ptr);
2003 e2 = ldl_kernel(ptr + 4);
2004 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
2005 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2006 if (!(e2 & DESC_P_MASK))
2007 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2008#ifdef TARGET_X86_64
2009 if (env->hflags & HF_LMA_MASK) {
2010 uint32_t e3;
2011 e3 = ldl_kernel(ptr + 8);
2012 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2013 env->ldt.base |= (target_ulong)e3 << 32;
2014 } else
2015#endif
2016 {
2017 load_seg_cache_raw_dt(&env->ldt, e1, e2);
2018 }
2019 }
2020 env->ldt.selector = selector;
2021}
2022
2023void helper_ltr(int selector)
2024{
2025 SegmentCache *dt;
2026 uint32_t e1, e2;
2027 int index, type, entry_limit;
2028 target_ulong ptr;
2029
2030 selector &= 0xffff;
2031 if ((selector & 0xfffc) == 0) {
2032 /* NULL selector case: invalid TR */
2033 env->tr.base = 0;
2034 env->tr.limit = 0;
2035 env->tr.flags = 0;
2036 } else {
2037 if (selector & 0x4)
2038 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2039 dt = &env->gdt;
2040 index = selector & ~7;
2041#ifdef TARGET_X86_64
2042 if (env->hflags & HF_LMA_MASK)
2043 entry_limit = 15;
2044 else
2045#endif
2046 entry_limit = 7;
2047 if ((index + entry_limit) > dt->limit)
2048 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2049 ptr = dt->base + index;
2050 e1 = ldl_kernel(ptr);
2051 e2 = ldl_kernel(ptr + 4);
2052 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2053 if ((e2 & DESC_S_MASK) ||
2054 (type != 1 && type != 9))
2055 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2056 if (!(e2 & DESC_P_MASK))
2057 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2058#ifdef TARGET_X86_64
2059 if (env->hflags & HF_LMA_MASK) {
2060 uint32_t e3, e4;
2061 e3 = ldl_kernel(ptr + 8);
2062 e4 = ldl_kernel(ptr + 12);
2063 if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
2064 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2065 load_seg_cache_raw_dt(&env->tr, e1, e2);
2066 env->tr.base |= (target_ulong)e3 << 32;
2067 } else
2068#endif
2069 {
2070 load_seg_cache_raw_dt(&env->tr, e1, e2);
2071 }
2072 e2 |= DESC_TSS_BUSY_MASK;
2073 stl_kernel(ptr + 4, e2);
2074 }
2075 env->tr.selector = selector;
2076}
2077
2078/* only works if protected mode and not VM86. seg_reg must be != R_CS */
2079void helper_load_seg(int seg_reg, int selector)
2080{
2081 uint32_t e1, e2;
2082 int cpl, dpl, rpl;
2083 SegmentCache *dt;
2084 int index;
2085 target_ulong ptr;
2086
2087 selector &= 0xffff;
2088 cpl = env->hflags & HF_CPL_MASK;
2089 if ((selector & 0xfffc) == 0) {
2090 /* null selector case */
2091 if (seg_reg == R_SS
2092#ifdef TARGET_X86_64
2093 && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
2094#endif
2095 )
2096 raise_exception_err(EXCP0D_GPF, 0);
2097 cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
2098 } else {
2099
2100 if (selector & 0x4)
2101 dt = &env->ldt;
2102 else
2103 dt = &env->gdt;
2104 index = selector & ~7;
2105 if ((index + 7) > dt->limit)
2106 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2107 ptr = dt->base + index;
2108 e1 = ldl_kernel(ptr);
2109 e2 = ldl_kernel(ptr + 4);
2110
2111 if (!(e2 & DESC_S_MASK))
2112 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2113 rpl = selector & 3;
2114 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2115 if (seg_reg == R_SS) {
2116 /* must be writable segment */
2117 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2118 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2119 if (rpl != cpl || dpl != cpl)
2120 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2121 } else {
2122 /* must be readable segment */
2123 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2124 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2125
2126 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2127 /* if not conforming code, test rights */
2128 if (dpl < cpl || dpl < rpl)
2129 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2130 }
2131 }
2132
2133 if (!(e2 & DESC_P_MASK)) {
2134 if (seg_reg == R_SS)
2135 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
2136 else
2137 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2138 }
2139
2140 /* set the access bit if not already set */
2141 if (!(e2 & DESC_A_MASK)) {
2142 e2 |= DESC_A_MASK;
2143 stl_kernel(ptr + 4, e2);
2144 }
2145
2146 cpu_x86_load_seg_cache(env, seg_reg, selector,
2147 get_seg_base(e1, e2),
2148 get_seg_limit(e1, e2),
2149 e2);
2150#if 0
2151 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
2152 selector, (unsigned long)sc->base, sc->limit, sc->flags);
2153#endif
2154 }
2155}
2156
2157/* protected mode jump */
2158void helper_ljmp_protected(int new_cs, target_ulong new_eip,
2159 int next_eip_addend)
2160{
2161 int gate_cs, type;
2162 uint32_t e1, e2, cpl, dpl, rpl, limit;
2163 target_ulong next_eip;
2164
2165 if ((new_cs & 0xfffc) == 0)
2166 raise_exception_err(EXCP0D_GPF, 0);
2167 if (load_segment(&e1, &e2, new_cs) != 0)
2168 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2169 cpl = env->hflags & HF_CPL_MASK;
2170 if (e2 & DESC_S_MASK) {
2171 if (!(e2 & DESC_CS_MASK))
2172 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2173 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2174 if (e2 & DESC_C_MASK) {
2175 /* conforming code segment */
2176 if (dpl > cpl)
2177 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2178 } else {
2179 /* non conforming code segment */
2180 rpl = new_cs & 3;
2181 if (rpl > cpl)
2182 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2183 if (dpl != cpl)
2184 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2185 }
2186 if (!(e2 & DESC_P_MASK))
2187 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2188 limit = get_seg_limit(e1, e2);
2189 if (new_eip > limit &&
2190 !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2191 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2192 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2193 get_seg_base(e1, e2), limit, e2);
2194 EIP = new_eip;
2195 } else {
2196 /* jump to call or task gate */
2197 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2198 rpl = new_cs & 3;
2199 cpl = env->hflags & HF_CPL_MASK;
2200 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2201 switch(type) {
2202 case 1: /* 286 TSS */
2203 case 9: /* 386 TSS */
2204 case 5: /* task gate */
2205 if (dpl < cpl || dpl < rpl)
2206 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2207 next_eip = env->eip + next_eip_addend;
2208 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2209 CC_OP = CC_OP_EFLAGS;
2210 break;
2211 case 4: /* 286 call gate */
2212 case 12: /* 386 call gate */
2213 if ((dpl < cpl) || (dpl < rpl))
2214 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2215 if (!(e2 & DESC_P_MASK))
2216 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2217 gate_cs = e1 >> 16;
2218 new_eip = (e1 & 0xffff);
2219 if (type == 12)
2220 new_eip |= (e2 & 0xffff0000);
2221 if (load_segment(&e1, &e2, gate_cs) != 0)
2222 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2223 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2224 /* must be code segment */
2225 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2226 (DESC_S_MASK | DESC_CS_MASK)))
2227 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2228 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2229 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2230 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2231 if (!(e2 & DESC_P_MASK))
2232 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2233 limit = get_seg_limit(e1, e2);
2234 if (new_eip > limit)
2235 raise_exception_err(EXCP0D_GPF, 0);
2236 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2237 get_seg_base(e1, e2), limit, e2);
2238 EIP = new_eip;
2239 break;
2240 default:
2241 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2242 break;
2243 }
2244 }
2245}
2246
2247/* real mode call */
2248void helper_lcall_real(int new_cs, target_ulong new_eip1,
2249 int shift, int next_eip)
2250{
2251 int new_eip;
2252 uint32_t esp, esp_mask;
2253 target_ulong ssp;
2254
2255 new_eip = new_eip1;
2256 esp = ESP;
2257 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2258 ssp = env->segs[R_SS].base;
2259 if (shift) {
2260 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2261 PUSHL(ssp, esp, esp_mask, next_eip);
2262 } else {
2263 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2264 PUSHW(ssp, esp, esp_mask, next_eip);
2265 }
2266
2267 SET_ESP(esp, esp_mask);
2268 env->eip = new_eip;
2269 env->segs[R_CS].selector = new_cs;
2270 env->segs[R_CS].base = (new_cs << 4);
2271}
2272
2273/* protected mode call */
2274void helper_lcall_protected(int new_cs, target_ulong new_eip,
2275 int shift, int next_eip_addend)
2276{
2277 int new_stack, i;
2278 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2279 uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2280 uint32_t val, limit, old_sp_mask;
2281 target_ulong ssp, old_ssp, next_eip;
2282
2283 next_eip = env->eip + next_eip_addend;
2284#ifdef DEBUG_PCALL
2285 if (loglevel & CPU_LOG_PCALL) {
2286 fprintf(logfile, "lcall %04x:%08x s=%d\n",
2287 new_cs, (uint32_t)new_eip, shift);
2288 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2289 }
2290#endif
2291 if ((new_cs & 0xfffc) == 0)
2292 raise_exception_err(EXCP0D_GPF, 0);
2293 if (load_segment(&e1, &e2, new_cs) != 0)
2294 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2295 cpl = env->hflags & HF_CPL_MASK;
2296#ifdef DEBUG_PCALL
2297 if (loglevel & CPU_LOG_PCALL) {
2298 fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2299 }
2300#endif
2301 if (e2 & DESC_S_MASK) {
2302 if (!(e2 & DESC_CS_MASK))
2303 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2304 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2305 if (e2 & DESC_C_MASK) {
2306 /* conforming code segment */
2307 if (dpl > cpl)
2308 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2309 } else {
2310 /* non conforming code segment */
2311 rpl = new_cs & 3;
2312 if (rpl > cpl)
2313 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2314 if (dpl != cpl)
2315 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2316 }
2317 if (!(e2 & DESC_P_MASK))
2318 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2319
2320#ifdef TARGET_X86_64
2321 /* XXX: check 16/32 bit cases in long mode */
2322 if (shift == 2) {
2323 target_ulong rsp;
2324 /* 64 bit case */
2325 rsp = ESP;
2326 PUSHQ(rsp, env->segs[R_CS].selector);
2327 PUSHQ(rsp, next_eip);
2328 /* from this point, not restartable */
2329 ESP = rsp;
2330 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2331 get_seg_base(e1, e2),
2332 get_seg_limit(e1, e2), e2);
2333 EIP = new_eip;
2334 } else
2335#endif
2336 {
2337 sp = ESP;
2338 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2339 ssp = env->segs[R_SS].base;
2340 if (shift) {
2341 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2342 PUSHL(ssp, sp, sp_mask, next_eip);
2343 } else {
2344 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2345 PUSHW(ssp, sp, sp_mask, next_eip);
2346 }
2347
2348 limit = get_seg_limit(e1, e2);
2349 if (new_eip > limit)
2350 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2351 /* from this point, not restartable */
2352 SET_ESP(sp, sp_mask);
2353 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2354 get_seg_base(e1, e2), limit, e2);
2355 EIP = new_eip;
2356 }
2357 } else {
2358 /* check gate type */
2359 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2360 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2361 rpl = new_cs & 3;
2362 switch(type) {
2363 case 1: /* available 286 TSS */
2364 case 9: /* available 386 TSS */
2365 case 5: /* task gate */
2366 if (dpl < cpl || dpl < rpl)
2367 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2368 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2369 CC_OP = CC_OP_EFLAGS;
2370 return;
2371 case 4: /* 286 call gate */
2372 case 12: /* 386 call gate */
2373 break;
2374 default:
2375 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2376 break;
2377 }
2378 shift = type >> 3;
2379
2380 if (dpl < cpl || dpl < rpl)
2381 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2382 /* check valid bit */
2383 if (!(e2 & DESC_P_MASK))
2384 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2385 selector = e1 >> 16;
2386 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2387 param_count = e2 & 0x1f;
2388 if ((selector & 0xfffc) == 0)
2389 raise_exception_err(EXCP0D_GPF, 0);
2390
2391 if (load_segment(&e1, &e2, selector) != 0)
2392 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2393 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2394 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2395 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2396 if (dpl > cpl)
2397 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2398 if (!(e2 & DESC_P_MASK))
2399 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2400
2401 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2402 /* to inner privilege */
2403 get_ss_esp_from_tss(&ss, &sp, dpl);
2404#ifdef DEBUG_PCALL
2405 if (loglevel & CPU_LOG_PCALL)
2406 fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2407 ss, sp, param_count, ESP);
2408#endif
2409 if ((ss & 0xfffc) == 0)
2410 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2411 if ((ss & 3) != dpl)
2412 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2413 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2414 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2415 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2416 if (ss_dpl != dpl)
2417 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2418 if (!(ss_e2 & DESC_S_MASK) ||
2419 (ss_e2 & DESC_CS_MASK) ||
2420 !(ss_e2 & DESC_W_MASK))
2421 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2422 if (!(ss_e2 & DESC_P_MASK))
2423 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2424
2425 // push_size = ((param_count * 2) + 8) << shift;
2426
2427 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2428 old_ssp = env->segs[R_SS].base;
2429
2430 sp_mask = get_sp_mask(ss_e2);
2431 ssp = get_seg_base(ss_e1, ss_e2);
2432 if (shift) {
2433 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2434 PUSHL(ssp, sp, sp_mask, ESP);
2435 for(i = param_count - 1; i >= 0; i--) {
2436 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2437 PUSHL(ssp, sp, sp_mask, val);
2438 }
2439 } else {
2440 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2441 PUSHW(ssp, sp, sp_mask, ESP);
2442 for(i = param_count - 1; i >= 0; i--) {
2443 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2444 PUSHW(ssp, sp, sp_mask, val);
2445 }
2446 }
2447 new_stack = 1;
2448 } else {
2449 /* to same privilege */
2450 sp = ESP;
2451 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2452 ssp = env->segs[R_SS].base;
2453 // push_size = (4 << shift);
2454 new_stack = 0;
2455 }
2456
2457 if (shift) {
2458 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2459 PUSHL(ssp, sp, sp_mask, next_eip);
2460 } else {
2461 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2462 PUSHW(ssp, sp, sp_mask, next_eip);
2463 }
2464
2465 /* from this point, not restartable */
2466
2467 if (new_stack) {
2468 ss = (ss & ~3) | dpl;
2469 cpu_x86_load_seg_cache(env, R_SS, ss,
2470 ssp,
2471 get_seg_limit(ss_e1, ss_e2),
2472 ss_e2);
2473 }
2474
2475 selector = (selector & ~3) | dpl;
2476 cpu_x86_load_seg_cache(env, R_CS, selector,
2477 get_seg_base(e1, e2),
2478 get_seg_limit(e1, e2),
2479 e2);
2480 cpu_x86_set_cpl(env, dpl);
2481 SET_ESP(sp, sp_mask);
2482 EIP = offset;
2483 }
2484#ifdef USE_KQEMU
2485 if (kqemu_is_ok(env)) {
2486 env->exception_index = -1;
2487 cpu_loop_exit();
2488 }
2489#endif
2490}
2491
2492/* real and vm86 mode iret */
2493void helper_iret_real(int shift)
2494{
2495 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2496 target_ulong ssp;
2497 int eflags_mask;
2498
2499 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2500 sp = ESP;
2501 ssp = env->segs[R_SS].base;
2502 if (shift == 1) {
2503 /* 32 bits */
2504 POPL(ssp, sp, sp_mask, new_eip);
2505 POPL(ssp, sp, sp_mask, new_cs);
2506 new_cs &= 0xffff;
2507 POPL(ssp, sp, sp_mask, new_eflags);
2508 } else {
2509 /* 16 bits */
2510 POPW(ssp, sp, sp_mask, new_eip);
2511 POPW(ssp, sp, sp_mask, new_cs);
2512 POPW(ssp, sp, sp_mask, new_eflags);
2513 }
2514 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
bdadc0b5 2515 env->segs[R_CS].selector = new_cs;
2516 env->segs[R_CS].base = (new_cs << 4);
eaa728ee
FB
2517 env->eip = new_eip;
2518 if (env->eflags & VM_MASK)
2519 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2520 else
2521 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2522 if (shift == 0)
2523 eflags_mask &= 0xffff;
2524 load_eflags(new_eflags, eflags_mask);
db620f46 2525 env->hflags2 &= ~HF2_NMI_MASK;
eaa728ee
FB
2526}
2527
2528static inline void validate_seg(int seg_reg, int cpl)
2529{
2530 int dpl;
2531 uint32_t e2;
2532
2533 /* XXX: on x86_64, we do not want to nullify FS and GS because
2534 they may still contain a valid base. I would be interested to
2535 know how a real x86_64 CPU behaves */
2536 if ((seg_reg == R_FS || seg_reg == R_GS) &&
2537 (env->segs[seg_reg].selector & 0xfffc) == 0)
2538 return;
2539
2540 e2 = env->segs[seg_reg].flags;
2541 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2542 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2543 /* data or non conforming code segment */
2544 if (dpl < cpl) {
2545 cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2546 }
2547 }
2548}
2549
2550/* protected mode iret */
2551static inline void helper_ret_protected(int shift, int is_iret, int addend)
2552{
2553 uint32_t new_cs, new_eflags, new_ss;
2554 uint32_t new_es, new_ds, new_fs, new_gs;
2555 uint32_t e1, e2, ss_e1, ss_e2;
2556 int cpl, dpl, rpl, eflags_mask, iopl;
2557 target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2558
2559#ifdef TARGET_X86_64
2560 if (shift == 2)
2561 sp_mask = -1;
2562 else
2563#endif
2564 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2565 sp = ESP;
2566 ssp = env->segs[R_SS].base;
2567 new_eflags = 0; /* avoid warning */
2568#ifdef TARGET_X86_64
2569 if (shift == 2) {
2570 POPQ(sp, new_eip);
2571 POPQ(sp, new_cs);
2572 new_cs &= 0xffff;
2573 if (is_iret) {
2574 POPQ(sp, new_eflags);
2575 }
2576 } else
2577#endif
2578 if (shift == 1) {
2579 /* 32 bits */
2580 POPL(ssp, sp, sp_mask, new_eip);
2581 POPL(ssp, sp, sp_mask, new_cs);
2582 new_cs &= 0xffff;
2583 if (is_iret) {
2584 POPL(ssp, sp, sp_mask, new_eflags);
2585 if (new_eflags & VM_MASK)
2586 goto return_to_vm86;
2587 }
2588 } else {
2589 /* 16 bits */
2590 POPW(ssp, sp, sp_mask, new_eip);
2591 POPW(ssp, sp, sp_mask, new_cs);
2592 if (is_iret)
2593 POPW(ssp, sp, sp_mask, new_eflags);
2594 }
2595#ifdef DEBUG_PCALL
2596 if (loglevel & CPU_LOG_PCALL) {
2597 fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2598 new_cs, new_eip, shift, addend);
2599 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2600 }
2601#endif
2602 if ((new_cs & 0xfffc) == 0)
2603 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2604 if (load_segment(&e1, &e2, new_cs) != 0)
2605 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2606 if (!(e2 & DESC_S_MASK) ||
2607 !(e2 & DESC_CS_MASK))
2608 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2609 cpl = env->hflags & HF_CPL_MASK;
2610 rpl = new_cs & 3;
2611 if (rpl < cpl)
2612 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2613 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2614 if (e2 & DESC_C_MASK) {
2615 if (dpl > rpl)
2616 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2617 } else {
2618 if (dpl != rpl)
2619 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2620 }
2621 if (!(e2 & DESC_P_MASK))
2622 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2623
2624 sp += addend;
2625 if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2626 ((env->hflags & HF_CS64_MASK) && !is_iret))) {
1235fc06 2627 /* return to same privilege level */
eaa728ee
FB
2628 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2629 get_seg_base(e1, e2),
2630 get_seg_limit(e1, e2),
2631 e2);
2632 } else {
2633 /* return to different privilege level */
2634#ifdef TARGET_X86_64
2635 if (shift == 2) {
2636 POPQ(sp, new_esp);
2637 POPQ(sp, new_ss);
2638 new_ss &= 0xffff;
2639 } else
2640#endif
2641 if (shift == 1) {
2642 /* 32 bits */
2643 POPL(ssp, sp, sp_mask, new_esp);
2644 POPL(ssp, sp, sp_mask, new_ss);
2645 new_ss &= 0xffff;
2646 } else {
2647 /* 16 bits */
2648 POPW(ssp, sp, sp_mask, new_esp);
2649 POPW(ssp, sp, sp_mask, new_ss);
2650 }
2651#ifdef DEBUG_PCALL
2652 if (loglevel & CPU_LOG_PCALL) {
2653 fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2654 new_ss, new_esp);
2655 }
2656#endif
2657 if ((new_ss & 0xfffc) == 0) {
2658#ifdef TARGET_X86_64
2659 /* NULL ss is allowed in long mode if cpl != 3*/
2660 /* XXX: test CS64 ? */
2661 if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2662 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2663 0, 0xffffffff,
2664 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2665 DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2666 DESC_W_MASK | DESC_A_MASK);
2667 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2668 } else
2669#endif
2670 {
2671 raise_exception_err(EXCP0D_GPF, 0);
2672 }
2673 } else {
2674 if ((new_ss & 3) != rpl)
2675 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2676 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2677 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2678 if (!(ss_e2 & DESC_S_MASK) ||
2679 (ss_e2 & DESC_CS_MASK) ||
2680 !(ss_e2 & DESC_W_MASK))
2681 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2682 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2683 if (dpl != rpl)
2684 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2685 if (!(ss_e2 & DESC_P_MASK))
2686 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2687 cpu_x86_load_seg_cache(env, R_SS, new_ss,
2688 get_seg_base(ss_e1, ss_e2),
2689 get_seg_limit(ss_e1, ss_e2),
2690 ss_e2);
2691 }
2692
2693 cpu_x86_load_seg_cache(env, R_CS, new_cs,
2694 get_seg_base(e1, e2),
2695 get_seg_limit(e1, e2),
2696 e2);
2697 cpu_x86_set_cpl(env, rpl);
2698 sp = new_esp;
2699#ifdef TARGET_X86_64
2700 if (env->hflags & HF_CS64_MASK)
2701 sp_mask = -1;
2702 else
2703#endif
2704 sp_mask = get_sp_mask(ss_e2);
2705
2706 /* validate data segments */
2707 validate_seg(R_ES, rpl);
2708 validate_seg(R_DS, rpl);
2709 validate_seg(R_FS, rpl);
2710 validate_seg(R_GS, rpl);
2711
2712 sp += addend;
2713 }
2714 SET_ESP(sp, sp_mask);
2715 env->eip = new_eip;
2716 if (is_iret) {
2717 /* NOTE: 'cpl' is the _old_ CPL */
2718 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2719 if (cpl == 0)
2720 eflags_mask |= IOPL_MASK;
2721 iopl = (env->eflags >> IOPL_SHIFT) & 3;
2722 if (cpl <= iopl)
2723 eflags_mask |= IF_MASK;
2724 if (shift == 0)
2725 eflags_mask &= 0xffff;
2726 load_eflags(new_eflags, eflags_mask);
2727 }
2728 return;
2729
2730 return_to_vm86:
2731 POPL(ssp, sp, sp_mask, new_esp);
2732 POPL(ssp, sp, sp_mask, new_ss);
2733 POPL(ssp, sp, sp_mask, new_es);
2734 POPL(ssp, sp, sp_mask, new_ds);
2735 POPL(ssp, sp, sp_mask, new_fs);
2736 POPL(ssp, sp, sp_mask, new_gs);
2737
2738 /* modify processor state */
2739 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2740 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2741 load_seg_vm(R_CS, new_cs & 0xffff);
2742 cpu_x86_set_cpl(env, 3);
2743 load_seg_vm(R_SS, new_ss & 0xffff);
2744 load_seg_vm(R_ES, new_es & 0xffff);
2745 load_seg_vm(R_DS, new_ds & 0xffff);
2746 load_seg_vm(R_FS, new_fs & 0xffff);
2747 load_seg_vm(R_GS, new_gs & 0xffff);
2748
2749 env->eip = new_eip & 0xffff;
2750 ESP = new_esp;
2751}
2752
2753void helper_iret_protected(int shift, int next_eip)
2754{
2755 int tss_selector, type;
2756 uint32_t e1, e2;
2757
2758 /* specific case for TSS */
2759 if (env->eflags & NT_MASK) {
2760#ifdef TARGET_X86_64
2761 if (env->hflags & HF_LMA_MASK)
2762 raise_exception_err(EXCP0D_GPF, 0);
2763#endif
2764 tss_selector = lduw_kernel(env->tr.base + 0);
2765 if (tss_selector & 4)
2766 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2767 if (load_segment(&e1, &e2, tss_selector) != 0)
2768 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2769 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2770 /* NOTE: we check both segment and busy TSS */
2771 if (type != 3)
2772 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2773 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2774 } else {
2775 helper_ret_protected(shift, 1, 0);
2776 }
db620f46 2777 env->hflags2 &= ~HF2_NMI_MASK;
eaa728ee
FB
2778#ifdef USE_KQEMU
2779 if (kqemu_is_ok(env)) {
2780 CC_OP = CC_OP_EFLAGS;
2781 env->exception_index = -1;
2782 cpu_loop_exit();
2783 }
2784#endif
2785}
2786
2787void helper_lret_protected(int shift, int addend)
2788{
2789 helper_ret_protected(shift, 0, addend);
2790#ifdef USE_KQEMU
2791 if (kqemu_is_ok(env)) {
2792 env->exception_index = -1;
2793 cpu_loop_exit();
2794 }
2795#endif
2796}
2797
2798void helper_sysenter(void)
2799{
2800 if (env->sysenter_cs == 0) {
2801 raise_exception_err(EXCP0D_GPF, 0);
2802 }
2803 env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2804 cpu_x86_set_cpl(env, 0);
2436b61a
AZ
2805
2806#ifdef TARGET_X86_64
2807 if (env->hflags & HF_LMA_MASK) {
2808 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2809 0, 0xffffffff,
2810 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2811 DESC_S_MASK |
2812 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2813 } else
2814#endif
2815 {
2816 cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2817 0, 0xffffffff,
2818 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2819 DESC_S_MASK |
2820 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2821 }
eaa728ee
FB
2822 cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2823 0, 0xffffffff,
2824 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2825 DESC_S_MASK |
2826 DESC_W_MASK | DESC_A_MASK);
2827 ESP = env->sysenter_esp;
2828 EIP = env->sysenter_eip;
2829}
2830
2436b61a 2831void helper_sysexit(int dflag)
eaa728ee
FB
2832{
2833 int cpl;
2834
2835 cpl = env->hflags & HF_CPL_MASK;
2836 if (env->sysenter_cs == 0 || cpl != 0) {
2837 raise_exception_err(EXCP0D_GPF, 0);
2838 }
2839 cpu_x86_set_cpl(env, 3);
2436b61a
AZ
2840#ifdef TARGET_X86_64
2841 if (dflag == 2) {
2842 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
2843 0, 0xffffffff,
2844 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2845 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2846 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
2847 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
2848 0, 0xffffffff,
2849 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2850 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2851 DESC_W_MASK | DESC_A_MASK);
2852 } else
2853#endif
2854 {
2855 cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2856 0, 0xffffffff,
2857 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2858 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2859 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2860 cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2861 0, 0xffffffff,
2862 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2863 DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2864 DESC_W_MASK | DESC_A_MASK);
2865 }
eaa728ee
FB
2866 ESP = ECX;
2867 EIP = EDX;
2868#ifdef USE_KQEMU
2869 if (kqemu_is_ok(env)) {
2870 env->exception_index = -1;
2871 cpu_loop_exit();
2872 }
2873#endif
2874}
2875
872929aa
FB
2876#if defined(CONFIG_USER_ONLY)
2877target_ulong helper_read_crN(int reg)
eaa728ee 2878{
872929aa
FB
2879 return 0;
2880}
2881
2882void helper_write_crN(int reg, target_ulong t0)
2883{
2884}
01df040b
AL
2885
2886void helper_movl_drN_T0(int reg, target_ulong t0)
2887{
2888}
872929aa
FB
2889#else
2890target_ulong helper_read_crN(int reg)
2891{
2892 target_ulong val;
2893
2894 helper_svm_check_intercept_param(SVM_EXIT_READ_CR0 + reg, 0);
2895 switch(reg) {
2896 default:
2897 val = env->cr[reg];
2898 break;
2899 case 8:
db620f46
FB
2900 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2901 val = cpu_get_apic_tpr(env);
2902 } else {
2903 val = env->v_tpr;
2904 }
872929aa
FB
2905 break;
2906 }
2907 return val;
2908}
2909
2910void helper_write_crN(int reg, target_ulong t0)
2911{
2912 helper_svm_check_intercept_param(SVM_EXIT_WRITE_CR0 + reg, 0);
eaa728ee
FB
2913 switch(reg) {
2914 case 0:
2915 cpu_x86_update_cr0(env, t0);
2916 break;
2917 case 3:
2918 cpu_x86_update_cr3(env, t0);
2919 break;
2920 case 4:
2921 cpu_x86_update_cr4(env, t0);
2922 break;
2923 case 8:
db620f46
FB
2924 if (!(env->hflags2 & HF2_VINTR_MASK)) {
2925 cpu_set_apic_tpr(env, t0);
2926 }
2927 env->v_tpr = t0 & 0x0f;
eaa728ee
FB
2928 break;
2929 default:
2930 env->cr[reg] = t0;
2931 break;
2932 }
eaa728ee 2933}
01df040b
AL
2934
2935void helper_movl_drN_T0(int reg, target_ulong t0)
2936{
2937 int i;
2938
2939 if (reg < 4) {
2940 hw_breakpoint_remove(env, reg);
2941 env->dr[reg] = t0;
2942 hw_breakpoint_insert(env, reg);
2943 } else if (reg == 7) {
2944 for (i = 0; i < 4; i++)
2945 hw_breakpoint_remove(env, i);
2946 env->dr[7] = t0;
2947 for (i = 0; i < 4; i++)
2948 hw_breakpoint_insert(env, i);
2949 } else
2950 env->dr[reg] = t0;
2951}
872929aa 2952#endif
eaa728ee
FB
2953
2954void helper_lmsw(target_ulong t0)
2955{
2956 /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
2957 if already set to one. */
2958 t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
872929aa 2959 helper_write_crN(0, t0);
eaa728ee
FB
2960}
2961
2962void helper_clts(void)
2963{
2964 env->cr[0] &= ~CR0_TS_MASK;
2965 env->hflags &= ~HF_TS_MASK;
2966}
2967
eaa728ee
FB
2968void helper_invlpg(target_ulong addr)
2969{
872929aa 2970 helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
914178d3 2971 tlb_flush_page(env, addr);
eaa728ee
FB
2972}
2973
2974void helper_rdtsc(void)
2975{
2976 uint64_t val;
2977
2978 if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2979 raise_exception(EXCP0D_GPF);
2980 }
872929aa
FB
2981 helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
2982
33c263df 2983 val = cpu_get_tsc(env) + env->tsc_offset;
eaa728ee
FB
2984 EAX = (uint32_t)(val);
2985 EDX = (uint32_t)(val >> 32);
2986}
2987
2988void helper_rdpmc(void)
2989{
2990 if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2991 raise_exception(EXCP0D_GPF);
2992 }
eaa728ee
FB
2993 helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
2994
2995 /* currently unimplemented */
2996 raise_exception_err(EXCP06_ILLOP, 0);
2997}
2998
2999#if defined(CONFIG_USER_ONLY)
3000void helper_wrmsr(void)
3001{
3002}
3003
3004void helper_rdmsr(void)
3005{
3006}
3007#else
3008void helper_wrmsr(void)
3009{
3010 uint64_t val;
3011
872929aa
FB
3012 helper_svm_check_intercept_param(SVM_EXIT_MSR, 1);
3013
eaa728ee
FB
3014 val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
3015
3016 switch((uint32_t)ECX) {
3017 case MSR_IA32_SYSENTER_CS:
3018 env->sysenter_cs = val & 0xffff;
3019 break;
3020 case MSR_IA32_SYSENTER_ESP:
3021 env->sysenter_esp = val;
3022 break;
3023 case MSR_IA32_SYSENTER_EIP:
3024 env->sysenter_eip = val;
3025 break;
3026 case MSR_IA32_APICBASE:
3027 cpu_set_apic_base(env, val);
3028 break;
3029 case MSR_EFER:
3030 {
3031 uint64_t update_mask;
3032 update_mask = 0;
3033 if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
3034 update_mask |= MSR_EFER_SCE;
3035 if (env->cpuid_ext2_features & CPUID_EXT2_LM)
3036 update_mask |= MSR_EFER_LME;
3037 if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
3038 update_mask |= MSR_EFER_FFXSR;
3039 if (env->cpuid_ext2_features & CPUID_EXT2_NX)
3040 update_mask |= MSR_EFER_NXE;
5efc27bb
FB
3041 if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
3042 update_mask |= MSR_EFER_SVME;
3043 cpu_load_efer(env, (env->efer & ~update_mask) |
3044 (val & update_mask));
eaa728ee
FB
3045 }
3046 break;
3047 case MSR_STAR:
3048 env->star = val;
3049 break;
3050 case MSR_PAT:
3051 env->pat = val;
3052 break;
3053 case MSR_VM_HSAVE_PA:
3054 env->vm_hsave = val;
3055 break;
3056#ifdef TARGET_X86_64
3057 case MSR_LSTAR:
3058 env->lstar = val;
3059 break;
3060 case MSR_CSTAR:
3061 env->cstar = val;
3062 break;
3063 case MSR_FMASK:
3064 env->fmask = val;
3065 break;
3066 case MSR_FSBASE:
3067 env->segs[R_FS].base = val;
3068 break;
3069 case MSR_GSBASE:
3070 env->segs[R_GS].base = val;
3071 break;
3072 case MSR_KERNELGSBASE:
3073 env->kernelgsbase = val;
3074 break;
3075#endif
3076 default:
3077 /* XXX: exception ? */
3078 break;
3079 }
3080}
3081
3082void helper_rdmsr(void)
3083{
3084 uint64_t val;
872929aa
FB
3085
3086 helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
3087
eaa728ee
FB
3088 switch((uint32_t)ECX) {
3089 case MSR_IA32_SYSENTER_CS:
3090 val = env->sysenter_cs;
3091 break;
3092 case MSR_IA32_SYSENTER_ESP:
3093 val = env->sysenter_esp;
3094 break;
3095 case MSR_IA32_SYSENTER_EIP:
3096 val = env->sysenter_eip;
3097 break;
3098 case MSR_IA32_APICBASE:
3099 val = cpu_get_apic_base(env);
3100 break;
3101 case MSR_EFER:
3102 val = env->efer;
3103 break;
3104 case MSR_STAR:
3105 val = env->star;
3106 break;
3107 case MSR_PAT:
3108 val = env->pat;
3109 break;
3110 case MSR_VM_HSAVE_PA:
3111 val = env->vm_hsave;
3112 break;
d5e49a81
AZ
3113 case MSR_IA32_PERF_STATUS:
3114 /* tsc_increment_by_tick */
3115 val = 1000ULL;
3116 /* CPU multiplier */
3117 val |= (((uint64_t)4ULL) << 40);
3118 break;
eaa728ee
FB
3119#ifdef TARGET_X86_64
3120 case MSR_LSTAR:
3121 val = env->lstar;
3122 break;
3123 case MSR_CSTAR:
3124 val = env->cstar;
3125 break;
3126 case MSR_FMASK:
3127 val = env->fmask;
3128 break;
3129 case MSR_FSBASE:
3130 val = env->segs[R_FS].base;
3131 break;
3132 case MSR_GSBASE:
3133 val = env->segs[R_GS].base;
3134 break;
3135 case MSR_KERNELGSBASE:
3136 val = env->kernelgsbase;
3137 break;
da260249
FB
3138#endif
3139#ifdef USE_KQEMU
3140 case MSR_QPI_COMMBASE:
3141 if (env->kqemu_enabled) {
3142 val = kqemu_comm_base;
3143 } else {
3144 val = 0;
3145 }
3146 break;
eaa728ee
FB
3147#endif
3148 default:
3149 /* XXX: exception ? */
3150 val = 0;
3151 break;
3152 }
3153 EAX = (uint32_t)(val);
3154 EDX = (uint32_t)(val >> 32);
3155}
3156#endif
3157
3158target_ulong helper_lsl(target_ulong selector1)
3159{
3160 unsigned int limit;
3161 uint32_t e1, e2, eflags, selector;
3162 int rpl, dpl, cpl, type;
3163
3164 selector = selector1 & 0xffff;
a7812ae4 3165 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3166 if (load_segment(&e1, &e2, selector) != 0)
3167 goto fail;
3168 rpl = selector & 3;
3169 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3170 cpl = env->hflags & HF_CPL_MASK;
3171 if (e2 & DESC_S_MASK) {
3172 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3173 /* conforming */
3174 } else {
3175 if (dpl < cpl || dpl < rpl)
3176 goto fail;
3177 }
3178 } else {
3179 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3180 switch(type) {
3181 case 1:
3182 case 2:
3183 case 3:
3184 case 9:
3185 case 11:
3186 break;
3187 default:
3188 goto fail;
3189 }
3190 if (dpl < cpl || dpl < rpl) {
3191 fail:
3192 CC_SRC = eflags & ~CC_Z;
3193 return 0;
3194 }
3195 }
3196 limit = get_seg_limit(e1, e2);
3197 CC_SRC = eflags | CC_Z;
3198 return limit;
3199}
3200
3201target_ulong helper_lar(target_ulong selector1)
3202{
3203 uint32_t e1, e2, eflags, selector;
3204 int rpl, dpl, cpl, type;
3205
3206 selector = selector1 & 0xffff;
a7812ae4 3207 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3208 if ((selector & 0xfffc) == 0)
3209 goto fail;
3210 if (load_segment(&e1, &e2, selector) != 0)
3211 goto fail;
3212 rpl = selector & 3;
3213 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3214 cpl = env->hflags & HF_CPL_MASK;
3215 if (e2 & DESC_S_MASK) {
3216 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
3217 /* conforming */
3218 } else {
3219 if (dpl < cpl || dpl < rpl)
3220 goto fail;
3221 }
3222 } else {
3223 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
3224 switch(type) {
3225 case 1:
3226 case 2:
3227 case 3:
3228 case 4:
3229 case 5:
3230 case 9:
3231 case 11:
3232 case 12:
3233 break;
3234 default:
3235 goto fail;
3236 }
3237 if (dpl < cpl || dpl < rpl) {
3238 fail:
3239 CC_SRC = eflags & ~CC_Z;
3240 return 0;
3241 }
3242 }
3243 CC_SRC = eflags | CC_Z;
3244 return e2 & 0x00f0ff00;
3245}
3246
3247void helper_verr(target_ulong selector1)
3248{
3249 uint32_t e1, e2, eflags, selector;
3250 int rpl, dpl, cpl;
3251
3252 selector = selector1 & 0xffff;
a7812ae4 3253 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3254 if ((selector & 0xfffc) == 0)
3255 goto fail;
3256 if (load_segment(&e1, &e2, selector) != 0)
3257 goto fail;
3258 if (!(e2 & DESC_S_MASK))
3259 goto fail;
3260 rpl = selector & 3;
3261 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3262 cpl = env->hflags & HF_CPL_MASK;
3263 if (e2 & DESC_CS_MASK) {
3264 if (!(e2 & DESC_R_MASK))
3265 goto fail;
3266 if (!(e2 & DESC_C_MASK)) {
3267 if (dpl < cpl || dpl < rpl)
3268 goto fail;
3269 }
3270 } else {
3271 if (dpl < cpl || dpl < rpl) {
3272 fail:
3273 CC_SRC = eflags & ~CC_Z;
3274 return;
3275 }
3276 }
3277 CC_SRC = eflags | CC_Z;
3278}
3279
3280void helper_verw(target_ulong selector1)
3281{
3282 uint32_t e1, e2, eflags, selector;
3283 int rpl, dpl, cpl;
3284
3285 selector = selector1 & 0xffff;
a7812ae4 3286 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3287 if ((selector & 0xfffc) == 0)
3288 goto fail;
3289 if (load_segment(&e1, &e2, selector) != 0)
3290 goto fail;
3291 if (!(e2 & DESC_S_MASK))
3292 goto fail;
3293 rpl = selector & 3;
3294 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3295 cpl = env->hflags & HF_CPL_MASK;
3296 if (e2 & DESC_CS_MASK) {
3297 goto fail;
3298 } else {
3299 if (dpl < cpl || dpl < rpl)
3300 goto fail;
3301 if (!(e2 & DESC_W_MASK)) {
3302 fail:
3303 CC_SRC = eflags & ~CC_Z;
3304 return;
3305 }
3306 }
3307 CC_SRC = eflags | CC_Z;
3308}
3309
3310/* x87 FPU helpers */
3311
3312static void fpu_set_exception(int mask)
3313{
3314 env->fpus |= mask;
3315 if (env->fpus & (~env->fpuc & FPUC_EM))
3316 env->fpus |= FPUS_SE | FPUS_B;
3317}
3318
3319static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3320{
3321 if (b == 0.0)
3322 fpu_set_exception(FPUS_ZE);
3323 return a / b;
3324}
3325
3326void fpu_raise_exception(void)
3327{
3328 if (env->cr[0] & CR0_NE_MASK) {
3329 raise_exception(EXCP10_COPR);
3330 }
3331#if !defined(CONFIG_USER_ONLY)
3332 else {
3333 cpu_set_ferr(env);
3334 }
3335#endif
3336}
3337
3338void helper_flds_FT0(uint32_t val)
3339{
3340 union {
3341 float32 f;
3342 uint32_t i;
3343 } u;
3344 u.i = val;
3345 FT0 = float32_to_floatx(u.f, &env->fp_status);
3346}
3347
3348void helper_fldl_FT0(uint64_t val)
3349{
3350 union {
3351 float64 f;
3352 uint64_t i;
3353 } u;
3354 u.i = val;
3355 FT0 = float64_to_floatx(u.f, &env->fp_status);
3356}
3357
3358void helper_fildl_FT0(int32_t val)
3359{
3360 FT0 = int32_to_floatx(val, &env->fp_status);
3361}
3362
3363void helper_flds_ST0(uint32_t val)
3364{
3365 int new_fpstt;
3366 union {
3367 float32 f;
3368 uint32_t i;
3369 } u;
3370 new_fpstt = (env->fpstt - 1) & 7;
3371 u.i = val;
3372 env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
3373 env->fpstt = new_fpstt;
3374 env->fptags[new_fpstt] = 0; /* validate stack entry */
3375}
3376
3377void helper_fldl_ST0(uint64_t val)
3378{
3379 int new_fpstt;
3380 union {
3381 float64 f;
3382 uint64_t i;
3383 } u;
3384 new_fpstt = (env->fpstt - 1) & 7;
3385 u.i = val;
3386 env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
3387 env->fpstt = new_fpstt;
3388 env->fptags[new_fpstt] = 0; /* validate stack entry */
3389}
3390
3391void helper_fildl_ST0(int32_t val)
3392{
3393 int new_fpstt;
3394 new_fpstt = (env->fpstt - 1) & 7;
3395 env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
3396 env->fpstt = new_fpstt;
3397 env->fptags[new_fpstt] = 0; /* validate stack entry */
3398}
3399
3400void helper_fildll_ST0(int64_t val)
3401{
3402 int new_fpstt;
3403 new_fpstt = (env->fpstt - 1) & 7;
3404 env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
3405 env->fpstt = new_fpstt;
3406 env->fptags[new_fpstt] = 0; /* validate stack entry */
3407}
3408
3409uint32_t helper_fsts_ST0(void)
3410{
3411 union {
3412 float32 f;
3413 uint32_t i;
3414 } u;
3415 u.f = floatx_to_float32(ST0, &env->fp_status);
3416 return u.i;
3417}
3418
3419uint64_t helper_fstl_ST0(void)
3420{
3421 union {
3422 float64 f;
3423 uint64_t i;
3424 } u;
3425 u.f = floatx_to_float64(ST0, &env->fp_status);
3426 return u.i;
3427}
3428
3429int32_t helper_fist_ST0(void)
3430{
3431 int32_t val;
3432 val = floatx_to_int32(ST0, &env->fp_status);
3433 if (val != (int16_t)val)
3434 val = -32768;
3435 return val;
3436}
3437
3438int32_t helper_fistl_ST0(void)
3439{
3440 int32_t val;
3441 val = floatx_to_int32(ST0, &env->fp_status);
3442 return val;
3443}
3444
3445int64_t helper_fistll_ST0(void)
3446{
3447 int64_t val;
3448 val = floatx_to_int64(ST0, &env->fp_status);
3449 return val;
3450}
3451
3452int32_t helper_fistt_ST0(void)
3453{
3454 int32_t val;
3455 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3456 if (val != (int16_t)val)
3457 val = -32768;
3458 return val;
3459}
3460
3461int32_t helper_fisttl_ST0(void)
3462{
3463 int32_t val;
3464 val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
3465 return val;
3466}
3467
3468int64_t helper_fisttll_ST0(void)
3469{
3470 int64_t val;
3471 val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
3472 return val;
3473}
3474
3475void helper_fldt_ST0(target_ulong ptr)
3476{
3477 int new_fpstt;
3478 new_fpstt = (env->fpstt - 1) & 7;
3479 env->fpregs[new_fpstt].d = helper_fldt(ptr);
3480 env->fpstt = new_fpstt;
3481 env->fptags[new_fpstt] = 0; /* validate stack entry */
3482}
3483
3484void helper_fstt_ST0(target_ulong ptr)
3485{
3486 helper_fstt(ST0, ptr);
3487}
3488
3489void helper_fpush(void)
3490{
3491 fpush();
3492}
3493
3494void helper_fpop(void)
3495{
3496 fpop();
3497}
3498
3499void helper_fdecstp(void)
3500{
3501 env->fpstt = (env->fpstt - 1) & 7;
3502 env->fpus &= (~0x4700);
3503}
3504
3505void helper_fincstp(void)
3506{
3507 env->fpstt = (env->fpstt + 1) & 7;
3508 env->fpus &= (~0x4700);
3509}
3510
3511/* FPU move */
3512
3513void helper_ffree_STN(int st_index)
3514{
3515 env->fptags[(env->fpstt + st_index) & 7] = 1;
3516}
3517
3518void helper_fmov_ST0_FT0(void)
3519{
3520 ST0 = FT0;
3521}
3522
3523void helper_fmov_FT0_STN(int st_index)
3524{
3525 FT0 = ST(st_index);
3526}
3527
3528void helper_fmov_ST0_STN(int st_index)
3529{
3530 ST0 = ST(st_index);
3531}
3532
3533void helper_fmov_STN_ST0(int st_index)
3534{
3535 ST(st_index) = ST0;
3536}
3537
3538void helper_fxchg_ST0_STN(int st_index)
3539{
3540 CPU86_LDouble tmp;
3541 tmp = ST(st_index);
3542 ST(st_index) = ST0;
3543 ST0 = tmp;
3544}
3545
3546/* FPU operations */
3547
3548static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
3549
3550void helper_fcom_ST0_FT0(void)
3551{
3552 int ret;
3553
3554 ret = floatx_compare(ST0, FT0, &env->fp_status);
3555 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
3556 FORCE_RET();
3557}
3558
3559void helper_fucom_ST0_FT0(void)
3560{
3561 int ret;
3562
3563 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
3564 env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
3565 FORCE_RET();
3566}
3567
3568static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
3569
3570void helper_fcomi_ST0_FT0(void)
3571{
3572 int eflags;
3573 int ret;
3574
3575 ret = floatx_compare(ST0, FT0, &env->fp_status);
a7812ae4 3576 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3577 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3578 CC_SRC = eflags;
3579 FORCE_RET();
3580}
3581
3582void helper_fucomi_ST0_FT0(void)
3583{
3584 int eflags;
3585 int ret;
3586
3587 ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
a7812ae4 3588 eflags = helper_cc_compute_all(CC_OP);
eaa728ee
FB
3589 eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
3590 CC_SRC = eflags;
3591 FORCE_RET();
3592}
3593
3594void helper_fadd_ST0_FT0(void)
3595{
3596 ST0 += FT0;
3597}
3598
3599void helper_fmul_ST0_FT0(void)
3600{
3601 ST0 *= FT0;
3602}
3603
3604void helper_fsub_ST0_FT0(void)
3605{
3606 ST0 -= FT0;
3607}
3608
3609void helper_fsubr_ST0_FT0(void)
3610{
3611 ST0 = FT0 - ST0;
3612}
3613
3614void helper_fdiv_ST0_FT0(void)
3615{
3616 ST0 = helper_fdiv(ST0, FT0);
3617}
3618
3619void helper_fdivr_ST0_FT0(void)
3620{
3621 ST0 = helper_fdiv(FT0, ST0);
3622}
3623
3624/* fp operations between STN and ST0 */
3625
3626void helper_fadd_STN_ST0(int st_index)
3627{
3628 ST(st_index) += ST0;
3629}
3630
3631void helper_fmul_STN_ST0(int st_index)
3632{
3633 ST(st_index) *= ST0;
3634}
3635
3636void helper_fsub_STN_ST0(int st_index)
3637{
3638 ST(st_index) -= ST0;
3639}
3640
3641void helper_fsubr_STN_ST0(int st_index)
3642{
3643 CPU86_LDouble *p;
3644 p = &ST(st_index);
3645 *p = ST0 - *p;
3646}
3647
3648void helper_fdiv_STN_ST0(int st_index)
3649{
3650 CPU86_LDouble *p;
3651 p = &ST(st_index);
3652 *p = helper_fdiv(*p, ST0);
3653}
3654
3655void helper_fdivr_STN_ST0(int st_index)
3656{
3657 CPU86_LDouble *p;
3658 p = &ST(st_index);
3659 *p = helper_fdiv(ST0, *p);
3660}
3661
3662/* misc FPU operations */
3663void helper_fchs_ST0(void)
3664{
3665 ST0 = floatx_chs(ST0);
3666}
3667
3668void helper_fabs_ST0(void)
3669{
3670 ST0 = floatx_abs(ST0);
3671}
3672
3673void helper_fld1_ST0(void)
3674{
3675 ST0 = f15rk[1];
3676}
3677
3678void helper_fldl2t_ST0(void)
3679{
3680 ST0 = f15rk[6];
3681}
3682
3683void helper_fldl2e_ST0(void)
3684{
3685 ST0 = f15rk[5];
3686}
3687
3688void helper_fldpi_ST0(void)
3689{
3690 ST0 = f15rk[2];
3691}
3692
3693void helper_fldlg2_ST0(void)
3694{
3695 ST0 = f15rk[3];
3696}
3697
3698void helper_fldln2_ST0(void)
3699{
3700 ST0 = f15rk[4];
3701}
3702
3703void helper_fldz_ST0(void)
3704{
3705 ST0 = f15rk[0];
3706}
3707
3708void helper_fldz_FT0(void)
3709{
3710 FT0 = f15rk[0];
3711}
3712
3713uint32_t helper_fnstsw(void)
3714{
3715 return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3716}
3717
3718uint32_t helper_fnstcw(void)
3719{
3720 return env->fpuc;
3721}
3722
3723static void update_fp_status(void)
3724{
3725 int rnd_type;
3726
3727 /* set rounding mode */
3728 switch(env->fpuc & RC_MASK) {
3729 default:
3730 case RC_NEAR:
3731 rnd_type = float_round_nearest_even;
3732 break;
3733 case RC_DOWN:
3734 rnd_type = float_round_down;
3735 break;
3736 case RC_UP:
3737 rnd_type = float_round_up;
3738 break;
3739 case RC_CHOP:
3740 rnd_type = float_round_to_zero;
3741 break;
3742 }
3743 set_float_rounding_mode(rnd_type, &env->fp_status);
3744#ifdef FLOATX80
3745 switch((env->fpuc >> 8) & 3) {
3746 case 0:
3747 rnd_type = 32;
3748 break;
3749 case 2:
3750 rnd_type = 64;
3751 break;
3752 case 3:
3753 default:
3754 rnd_type = 80;
3755 break;
3756 }
3757 set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3758#endif
3759}
3760
3761void helper_fldcw(uint32_t val)
3762{
3763 env->fpuc = val;
3764 update_fp_status();
3765}
3766
3767void helper_fclex(void)
3768{
3769 env->fpus &= 0x7f00;
3770}
3771
3772void helper_fwait(void)
3773{
3774 if (env->fpus & FPUS_SE)
3775 fpu_raise_exception();
3776 FORCE_RET();
3777}
3778
3779void helper_fninit(void)
3780{
3781 env->fpus = 0;
3782 env->fpstt = 0;
3783 env->fpuc = 0x37f;
3784 env->fptags[0] = 1;
3785 env->fptags[1] = 1;
3786 env->fptags[2] = 1;
3787 env->fptags[3] = 1;
3788 env->fptags[4] = 1;
3789 env->fptags[5] = 1;
3790 env->fptags[6] = 1;
3791 env->fptags[7] = 1;
3792}
3793
3794/* BCD ops */
3795
3796void helper_fbld_ST0(target_ulong ptr)
3797{
3798 CPU86_LDouble tmp;
3799 uint64_t val;
3800 unsigned int v;
3801 int i;
3802
3803 val = 0;
3804 for(i = 8; i >= 0; i--) {
3805 v = ldub(ptr + i);
3806 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3807 }
3808 tmp = val;
3809 if (ldub(ptr + 9) & 0x80)
3810 tmp = -tmp;
3811 fpush();
3812 ST0 = tmp;
3813}
3814
3815void helper_fbst_ST0(target_ulong ptr)
3816{
3817 int v;
3818 target_ulong mem_ref, mem_end;
3819 int64_t val;
3820
3821 val = floatx_to_int64(ST0, &env->fp_status);
3822 mem_ref = ptr;
3823 mem_end = mem_ref + 9;
3824 if (val < 0) {
3825 stb(mem_end, 0x80);
3826 val = -val;
3827 } else {
3828 stb(mem_end, 0x00);
3829 }
3830 while (mem_ref < mem_end) {
3831 if (val == 0)
3832 break;
3833 v = val % 100;
3834 val = val / 100;
3835 v = ((v / 10) << 4) | (v % 10);
3836 stb(mem_ref++, v);
3837 }
3838 while (mem_ref < mem_end) {
3839 stb(mem_ref++, 0);
3840 }
3841}
3842
3843void helper_f2xm1(void)
3844{
3845 ST0 = pow(2.0,ST0) - 1.0;
3846}
3847
3848void helper_fyl2x(void)
3849{
3850 CPU86_LDouble fptemp;
3851
3852 fptemp = ST0;
3853 if (fptemp>0.0){
3854 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
3855 ST1 *= fptemp;
3856 fpop();
3857 } else {
3858 env->fpus &= (~0x4700);
3859 env->fpus |= 0x400;
3860 }
3861}
3862
3863void helper_fptan(void)
3864{
3865 CPU86_LDouble fptemp;
3866
3867 fptemp = ST0;
3868 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3869 env->fpus |= 0x400;
3870 } else {
3871 ST0 = tan(fptemp);
3872 fpush();
3873 ST0 = 1.0;
3874 env->fpus &= (~0x400); /* C2 <-- 0 */
3875 /* the above code is for |arg| < 2**52 only */
3876 }
3877}
3878
3879void helper_fpatan(void)
3880{
3881 CPU86_LDouble fptemp, fpsrcop;
3882
3883 fpsrcop = ST1;
3884 fptemp = ST0;
3885 ST1 = atan2(fpsrcop,fptemp);
3886 fpop();
3887}
3888
3889void helper_fxtract(void)
3890{
3891 CPU86_LDoubleU temp;
3892 unsigned int expdif;
3893
3894 temp.d = ST0;
3895 expdif = EXPD(temp) - EXPBIAS;
3896 /*DP exponent bias*/
3897 ST0 = expdif;
3898 fpush();
3899 BIASEXPONENT(temp);
3900 ST0 = temp.d;
3901}
3902
3903void helper_fprem1(void)
3904{
3905 CPU86_LDouble dblq, fpsrcop, fptemp;
3906 CPU86_LDoubleU fpsrcop1, fptemp1;
3907 int expdif;
3908 signed long long int q;
3909
3910 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3911 ST0 = 0.0 / 0.0; /* NaN */
3912 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3913 return;
3914 }
3915
3916 fpsrcop = ST0;
3917 fptemp = ST1;
3918 fpsrcop1.d = fpsrcop;
3919 fptemp1.d = fptemp;
3920 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3921
3922 if (expdif < 0) {
3923 /* optimisation? taken from the AMD docs */
3924 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3925 /* ST0 is unchanged */
3926 return;
3927 }
3928
3929 if (expdif < 53) {
3930 dblq = fpsrcop / fptemp;
3931 /* round dblq towards nearest integer */
3932 dblq = rint(dblq);
3933 ST0 = fpsrcop - fptemp * dblq;
3934
3935 /* convert dblq to q by truncating towards zero */
3936 if (dblq < 0.0)
3937 q = (signed long long int)(-dblq);
3938 else
3939 q = (signed long long int)dblq;
3940
3941 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3942 /* (C0,C3,C1) <-- (q2,q1,q0) */
3943 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3944 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3945 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
3946 } else {
3947 env->fpus |= 0x400; /* C2 <-- 1 */
3948 fptemp = pow(2.0, expdif - 50);
3949 fpsrcop = (ST0 / ST1) / fptemp;
3950 /* fpsrcop = integer obtained by chopping */
3951 fpsrcop = (fpsrcop < 0.0) ?
3952 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3953 ST0 -= (ST1 * fpsrcop * fptemp);
3954 }
3955}
3956
3957void helper_fprem(void)
3958{
3959 CPU86_LDouble dblq, fpsrcop, fptemp;
3960 CPU86_LDoubleU fpsrcop1, fptemp1;
3961 int expdif;
3962 signed long long int q;
3963
3964 if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3965 ST0 = 0.0 / 0.0; /* NaN */
3966 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3967 return;
3968 }
3969
3970 fpsrcop = (CPU86_LDouble)ST0;
3971 fptemp = (CPU86_LDouble)ST1;
3972 fpsrcop1.d = fpsrcop;
3973 fptemp1.d = fptemp;
3974 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3975
3976 if (expdif < 0) {
3977 /* optimisation? taken from the AMD docs */
3978 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3979 /* ST0 is unchanged */
3980 return;
3981 }
3982
3983 if ( expdif < 53 ) {
3984 dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
3985 /* round dblq towards zero */
3986 dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
3987 ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
3988
3989 /* convert dblq to q by truncating towards zero */
3990 if (dblq < 0.0)
3991 q = (signed long long int)(-dblq);
3992 else
3993 q = (signed long long int)dblq;
3994
3995 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3996 /* (C0,C3,C1) <-- (q2,q1,q0) */
3997 env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
3998 env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3999 env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
4000 } else {
4001 int N = 32 + (expdif % 32); /* as per AMD docs */
4002 env->fpus |= 0x400; /* C2 <-- 1 */
4003 fptemp = pow(2.0, (double)(expdif - N));
4004 fpsrcop = (ST0 / ST1) / fptemp;
4005 /* fpsrcop = integer obtained by chopping */
4006 fpsrcop = (fpsrcop < 0.0) ?
4007 -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4008 ST0 -= (ST1 * fpsrcop * fptemp);
4009 }
4010}
4011
4012void helper_fyl2xp1(void)
4013{
4014 CPU86_LDouble fptemp;
4015
4016 fptemp = ST0;
4017 if ((fptemp+1.0)>0.0) {
4018 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
4019 ST1 *= fptemp;
4020 fpop();
4021 } else {
4022 env->fpus &= (~0x4700);
4023 env->fpus |= 0x400;
4024 }
4025}
4026
4027void helper_fsqrt(void)
4028{
4029 CPU86_LDouble fptemp;
4030
4031 fptemp = ST0;
4032 if (fptemp<0.0) {
4033 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4034 env->fpus |= 0x400;
4035 }
4036 ST0 = sqrt(fptemp);
4037}
4038
4039void helper_fsincos(void)
4040{
4041 CPU86_LDouble fptemp;
4042
4043 fptemp = ST0;
4044 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4045 env->fpus |= 0x400;
4046 } else {
4047 ST0 = sin(fptemp);
4048 fpush();
4049 ST0 = cos(fptemp);
4050 env->fpus &= (~0x400); /* C2 <-- 0 */
4051 /* the above code is for |arg| < 2**63 only */
4052 }
4053}
4054
4055void helper_frndint(void)
4056{
4057 ST0 = floatx_round_to_int(ST0, &env->fp_status);
4058}
4059
4060void helper_fscale(void)
4061{
4062 ST0 = ldexp (ST0, (int)(ST1));
4063}
4064
4065void helper_fsin(void)
4066{
4067 CPU86_LDouble fptemp;
4068
4069 fptemp = ST0;
4070 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4071 env->fpus |= 0x400;
4072 } else {
4073 ST0 = sin(fptemp);
4074 env->fpus &= (~0x400); /* C2 <-- 0 */
4075 /* the above code is for |arg| < 2**53 only */
4076 }
4077}
4078
4079void helper_fcos(void)
4080{
4081 CPU86_LDouble fptemp;
4082
4083 fptemp = ST0;
4084 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
4085 env->fpus |= 0x400;
4086 } else {
4087 ST0 = cos(fptemp);
4088 env->fpus &= (~0x400); /* C2 <-- 0 */
4089 /* the above code is for |arg5 < 2**63 only */
4090 }
4091}
4092
4093void helper_fxam_ST0(void)
4094{
4095 CPU86_LDoubleU temp;
4096 int expdif;
4097
4098 temp.d = ST0;
4099
4100 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
4101 if (SIGND(temp))
4102 env->fpus |= 0x200; /* C1 <-- 1 */
4103
4104 /* XXX: test fptags too */
4105 expdif = EXPD(temp);
4106 if (expdif == MAXEXPD) {
4107#ifdef USE_X86LDOUBLE
4108 if (MANTD(temp) == 0x8000000000000000ULL)
4109#else
4110 if (MANTD(temp) == 0)
4111#endif
4112 env->fpus |= 0x500 /*Infinity*/;
4113 else
4114 env->fpus |= 0x100 /*NaN*/;
4115 } else if (expdif == 0) {
4116 if (MANTD(temp) == 0)
4117 env->fpus |= 0x4000 /*Zero*/;
4118 else
4119 env->fpus |= 0x4400 /*Denormal*/;
4120 } else {
4121 env->fpus |= 0x400;
4122 }
4123}
4124
4125void helper_fstenv(target_ulong ptr, int data32)
4126{
4127 int fpus, fptag, exp, i;
4128 uint64_t mant;
4129 CPU86_LDoubleU tmp;
4130
4131 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4132 fptag = 0;
4133 for (i=7; i>=0; i--) {
4134 fptag <<= 2;
4135 if (env->fptags[i]) {
4136 fptag |= 3;
4137 } else {
4138 tmp.d = env->fpregs[i].d;
4139 exp = EXPD(tmp);
4140 mant = MANTD(tmp);
4141 if (exp == 0 && mant == 0) {
4142 /* zero */
4143 fptag |= 1;
4144 } else if (exp == 0 || exp == MAXEXPD
4145#ifdef USE_X86LDOUBLE
4146 || (mant & (1LL << 63)) == 0
4147#endif
4148 ) {
4149 /* NaNs, infinity, denormal */
4150 fptag |= 2;
4151 }
4152 }
4153 }
4154 if (data32) {
4155 /* 32 bit */
4156 stl(ptr, env->fpuc);
4157 stl(ptr + 4, fpus);
4158 stl(ptr + 8, fptag);
4159 stl(ptr + 12, 0); /* fpip */
4160 stl(ptr + 16, 0); /* fpcs */
4161 stl(ptr + 20, 0); /* fpoo */
4162 stl(ptr + 24, 0); /* fpos */
4163 } else {
4164 /* 16 bit */
4165 stw(ptr, env->fpuc);
4166 stw(ptr + 2, fpus);
4167 stw(ptr + 4, fptag);
4168 stw(ptr + 6, 0);
4169 stw(ptr + 8, 0);
4170 stw(ptr + 10, 0);
4171 stw(ptr + 12, 0);
4172 }
4173}
4174
4175void helper_fldenv(target_ulong ptr, int data32)
4176{
4177 int i, fpus, fptag;
4178
4179 if (data32) {
4180 env->fpuc = lduw(ptr);
4181 fpus = lduw(ptr + 4);
4182 fptag = lduw(ptr + 8);
4183 }
4184 else {
4185 env->fpuc = lduw(ptr);
4186 fpus = lduw(ptr + 2);
4187 fptag = lduw(ptr + 4);
4188 }
4189 env->fpstt = (fpus >> 11) & 7;
4190 env->fpus = fpus & ~0x3800;
4191 for(i = 0;i < 8; i++) {
4192 env->fptags[i] = ((fptag & 3) == 3);
4193 fptag >>= 2;
4194 }
4195}
4196
4197void helper_fsave(target_ulong ptr, int data32)
4198{
4199 CPU86_LDouble tmp;
4200 int i;
4201
4202 helper_fstenv(ptr, data32);
4203
4204 ptr += (14 << data32);
4205 for(i = 0;i < 8; i++) {
4206 tmp = ST(i);
4207 helper_fstt(tmp, ptr);
4208 ptr += 10;
4209 }
4210
4211 /* fninit */
4212 env->fpus = 0;
4213 env->fpstt = 0;
4214 env->fpuc = 0x37f;
4215 env->fptags[0] = 1;
4216 env->fptags[1] = 1;
4217 env->fptags[2] = 1;
4218 env->fptags[3] = 1;
4219 env->fptags[4] = 1;
4220 env->fptags[5] = 1;
4221 env->fptags[6] = 1;
4222 env->fptags[7] = 1;
4223}
4224
4225void helper_frstor(target_ulong ptr, int data32)
4226{
4227 CPU86_LDouble tmp;
4228 int i;
4229
4230 helper_fldenv(ptr, data32);
4231 ptr += (14 << data32);
4232
4233 for(i = 0;i < 8; i++) {
4234 tmp = helper_fldt(ptr);
4235 ST(i) = tmp;
4236 ptr += 10;
4237 }
4238}
4239
4240void helper_fxsave(target_ulong ptr, int data64)
4241{
4242 int fpus, fptag, i, nb_xmm_regs;
4243 CPU86_LDouble tmp;
4244 target_ulong addr;
4245
4246 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4247 fptag = 0;
4248 for(i = 0; i < 8; i++) {
4249 fptag |= (env->fptags[i] << i);
4250 }
4251 stw(ptr, env->fpuc);
4252 stw(ptr + 2, fpus);
4253 stw(ptr + 4, fptag ^ 0xff);
4254#ifdef TARGET_X86_64
4255 if (data64) {
4256 stq(ptr + 0x08, 0); /* rip */
4257 stq(ptr + 0x10, 0); /* rdp */
4258 } else
4259#endif
4260 {
4261 stl(ptr + 0x08, 0); /* eip */
4262 stl(ptr + 0x0c, 0); /* sel */
4263 stl(ptr + 0x10, 0); /* dp */
4264 stl(ptr + 0x14, 0); /* sel */
4265 }
4266
4267 addr = ptr + 0x20;
4268 for(i = 0;i < 8; i++) {
4269 tmp = ST(i);
4270 helper_fstt(tmp, addr);
4271 addr += 16;
4272 }
4273
4274 if (env->cr[4] & CR4_OSFXSR_MASK) {
4275 /* XXX: finish it */
4276 stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4277 stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4278 if (env->hflags & HF_CS64_MASK)
4279 nb_xmm_regs = 16;
4280 else
4281 nb_xmm_regs = 8;
4282 addr = ptr + 0xa0;
4283 for(i = 0; i < nb_xmm_regs; i++) {
4284 stq(addr, env->xmm_regs[i].XMM_Q(0));
4285 stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4286 addr += 16;
4287 }
4288 }
4289}
4290
4291void helper_fxrstor(target_ulong ptr, int data64)
4292{
4293 int i, fpus, fptag, nb_xmm_regs;
4294 CPU86_LDouble tmp;
4295 target_ulong addr;
4296
4297 env->fpuc = lduw(ptr);
4298 fpus = lduw(ptr + 2);
4299 fptag = lduw(ptr + 4);
4300 env->fpstt = (fpus >> 11) & 7;
4301 env->fpus = fpus & ~0x3800;
4302 fptag ^= 0xff;
4303 for(i = 0;i < 8; i++) {
4304 env->fptags[i] = ((fptag >> i) & 1);
4305 }
4306
4307 addr = ptr + 0x20;
4308 for(i = 0;i < 8; i++) {
4309 tmp = helper_fldt(addr);
4310 ST(i) = tmp;
4311 addr += 16;
4312 }
4313
4314 if (env->cr[4] & CR4_OSFXSR_MASK) {
4315 /* XXX: finish it */
4316 env->mxcsr = ldl(ptr + 0x18);
4317 //ldl(ptr + 0x1c);
4318 if (env->hflags & HF_CS64_MASK)
4319 nb_xmm_regs = 16;
4320 else
4321 nb_xmm_regs = 8;
4322 addr = ptr + 0xa0;
4323 for(i = 0; i < nb_xmm_regs; i++) {
4324 env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4325 env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4326 addr += 16;
4327 }
4328 }
4329}
4330
4331#ifndef USE_X86LDOUBLE
4332
4333void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4334{
4335 CPU86_LDoubleU temp;
4336 int e;
4337
4338 temp.d = f;
4339 /* mantissa */
4340 *pmant = (MANTD(temp) << 11) | (1LL << 63);
4341 /* exponent + sign */
4342 e = EXPD(temp) - EXPBIAS + 16383;
4343 e |= SIGND(temp) >> 16;
4344 *pexp = e;
4345}
4346
4347CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4348{
4349 CPU86_LDoubleU temp;
4350 int e;
4351 uint64_t ll;
4352
4353 /* XXX: handle overflow ? */
4354 e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
4355 e |= (upper >> 4) & 0x800; /* sign */
4356 ll = (mant >> 11) & ((1LL << 52) - 1);
4357#ifdef __arm__
4358 temp.l.upper = (e << 20) | (ll >> 32);
4359 temp.l.lower = ll;
4360#else
4361 temp.ll = ll | ((uint64_t)e << 52);
4362#endif
4363 return temp.d;
4364}
4365
4366#else
4367
4368void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
4369{
4370 CPU86_LDoubleU temp;
4371
4372 temp.d = f;
4373 *pmant = temp.l.lower;
4374 *pexp = temp.l.upper;
4375}
4376
4377CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
4378{
4379 CPU86_LDoubleU temp;
4380
4381 temp.l.upper = upper;
4382 temp.l.lower = mant;
4383 return temp.d;
4384}
4385#endif
4386
4387#ifdef TARGET_X86_64
4388
4389//#define DEBUG_MULDIV
4390
4391static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4392{
4393 *plow += a;
4394 /* carry test */
4395 if (*plow < a)
4396 (*phigh)++;
4397 *phigh += b;
4398}
4399
4400static void neg128(uint64_t *plow, uint64_t *phigh)
4401{
4402 *plow = ~ *plow;
4403 *phigh = ~ *phigh;
4404 add128(plow, phigh, 1, 0);
4405}
4406
4407/* return TRUE if overflow */
4408static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4409{
4410 uint64_t q, r, a1, a0;
4411 int i, qb, ab;
4412
4413 a0 = *plow;
4414 a1 = *phigh;
4415 if (a1 == 0) {
4416 q = a0 / b;
4417 r = a0 % b;
4418 *plow = q;
4419 *phigh = r;
4420 } else {
4421 if (a1 >= b)
4422 return 1;
4423 /* XXX: use a better algorithm */
4424 for(i = 0; i < 64; i++) {
4425 ab = a1 >> 63;
4426 a1 = (a1 << 1) | (a0 >> 63);
4427 if (ab || a1 >= b) {
4428 a1 -= b;
4429 qb = 1;
4430 } else {
4431 qb = 0;
4432 }
4433 a0 = (a0 << 1) | qb;
4434 }
4435#if defined(DEBUG_MULDIV)
4436 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
4437 *phigh, *plow, b, a0, a1);
4438#endif
4439 *plow = a0;
4440 *phigh = a1;
4441 }
4442 return 0;
4443}
4444
4445/* return TRUE if overflow */
4446static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
4447{
4448 int sa, sb;
4449 sa = ((int64_t)*phigh < 0);
4450 if (sa)
4451 neg128(plow, phigh);
4452 sb = (b < 0);
4453 if (sb)
4454 b = -b;
4455 if (div64(plow, phigh, b) != 0)
4456 return 1;
4457 if (sa ^ sb) {
4458 if (*plow > (1ULL << 63))
4459 return 1;
4460 *plow = - *plow;
4461 } else {
4462 if (*plow >= (1ULL << 63))
4463 return 1;
4464 }
4465 if (sa)
4466 *phigh = - *phigh;
4467 return 0;
4468}
4469
4470void helper_mulq_EAX_T0(target_ulong t0)
4471{
4472 uint64_t r0, r1;
4473
4474 mulu64(&r0, &r1, EAX, t0);
4475 EAX = r0;
4476 EDX = r1;
4477 CC_DST = r0;
4478 CC_SRC = r1;
4479}
4480
4481void helper_imulq_EAX_T0(target_ulong t0)
4482{
4483 uint64_t r0, r1;
4484
4485 muls64(&r0, &r1, EAX, t0);
4486 EAX = r0;
4487 EDX = r1;
4488 CC_DST = r0;
4489 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4490}
4491
4492target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
4493{
4494 uint64_t r0, r1;
4495
4496 muls64(&r0, &r1, t0, t1);
4497 CC_DST = r0;
4498 CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
4499 return r0;
4500}
4501
4502void helper_divq_EAX(target_ulong t0)
4503{
4504 uint64_t r0, r1;
4505 if (t0 == 0) {
4506 raise_exception(EXCP00_DIVZ);
4507 }
4508 r0 = EAX;
4509 r1 = EDX;
4510 if (div64(&r0, &r1, t0))
4511 raise_exception(EXCP00_DIVZ);
4512 EAX = r0;
4513 EDX = r1;
4514}
4515
4516void helper_idivq_EAX(target_ulong t0)
4517{
4518 uint64_t r0, r1;
4519 if (t0 == 0) {
4520 raise_exception(EXCP00_DIVZ);
4521 }
4522 r0 = EAX;
4523 r1 = EDX;
4524 if (idiv64(&r0, &r1, t0))
4525 raise_exception(EXCP00_DIVZ);
4526 EAX = r0;
4527 EDX = r1;
4528}
4529#endif
4530
94451178 4531static void do_hlt(void)
eaa728ee
FB
4532{
4533 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
ce5232c5 4534 env->halted = 1;
eaa728ee
FB
4535 env->exception_index = EXCP_HLT;
4536 cpu_loop_exit();
4537}
4538
94451178
FB
4539void helper_hlt(int next_eip_addend)
4540{
4541 helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
4542 EIP += next_eip_addend;
4543
4544 do_hlt();
4545}
4546
eaa728ee
FB
4547void helper_monitor(target_ulong ptr)
4548{
4549 if ((uint32_t)ECX != 0)
4550 raise_exception(EXCP0D_GPF);
4551 /* XXX: store address ? */
872929aa 4552 helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
eaa728ee
FB
4553}
4554
94451178 4555void helper_mwait(int next_eip_addend)
eaa728ee
FB
4556{
4557 if ((uint32_t)ECX != 0)
4558 raise_exception(EXCP0D_GPF);
872929aa 4559 helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
94451178
FB
4560 EIP += next_eip_addend;
4561
eaa728ee
FB
4562 /* XXX: not complete but not completely erroneous */
4563 if (env->cpu_index != 0 || env->next_cpu != NULL) {
4564 /* more than one CPU: do not sleep because another CPU may
4565 wake this one */
4566 } else {
94451178 4567 do_hlt();
eaa728ee
FB
4568 }
4569}
4570
4571void helper_debug(void)
4572{
4573 env->exception_index = EXCP_DEBUG;
4574 cpu_loop_exit();
4575}
4576
4577void helper_raise_interrupt(int intno, int next_eip_addend)
4578{
4579 raise_interrupt(intno, 1, 0, next_eip_addend);
4580}
4581
4582void helper_raise_exception(int exception_index)
4583{
4584 raise_exception(exception_index);
4585}
4586
4587void helper_cli(void)
4588{
4589 env->eflags &= ~IF_MASK;
4590}
4591
4592void helper_sti(void)
4593{
4594 env->eflags |= IF_MASK;
4595}
4596
4597#if 0
4598/* vm86plus instructions */
4599void helper_cli_vm(void)
4600{
4601 env->eflags &= ~VIF_MASK;
4602}
4603
4604void helper_sti_vm(void)
4605{
4606 env->eflags |= VIF_MASK;
4607 if (env->eflags & VIP_MASK) {
4608 raise_exception(EXCP0D_GPF);
4609 }
4610}
4611#endif
4612
4613void helper_set_inhibit_irq(void)
4614{
4615 env->hflags |= HF_INHIBIT_IRQ_MASK;
4616}
4617
4618void helper_reset_inhibit_irq(void)
4619{
4620 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4621}
4622
4623void helper_boundw(target_ulong a0, int v)
4624{
4625 int low, high;
4626 low = ldsw(a0);
4627 high = ldsw(a0 + 2);
4628 v = (int16_t)v;
4629 if (v < low || v > high) {
4630 raise_exception(EXCP05_BOUND);
4631 }
4632 FORCE_RET();
4633}
4634
4635void helper_boundl(target_ulong a0, int v)
4636{
4637 int low, high;
4638 low = ldl(a0);
4639 high = ldl(a0 + 4);
4640 if (v < low || v > high) {
4641 raise_exception(EXCP05_BOUND);
4642 }
4643 FORCE_RET();
4644}
4645
4646static float approx_rsqrt(float a)
4647{
4648 return 1.0 / sqrt(a);
4649}
4650
4651static float approx_rcp(float a)
4652{
4653 return 1.0 / a;
4654}
4655
4656#if !defined(CONFIG_USER_ONLY)
4657
4658#define MMUSUFFIX _mmu
4659
4660#define SHIFT 0
4661#include "softmmu_template.h"
4662
4663#define SHIFT 1
4664#include "softmmu_template.h"
4665
4666#define SHIFT 2
4667#include "softmmu_template.h"
4668
4669#define SHIFT 3
4670#include "softmmu_template.h"
4671
4672#endif
4673
4674/* try to fill the TLB and return an exception if error. If retaddr is
4675 NULL, it means that the function was called in C code (i.e. not
4676 from generated code or from helper.c) */
4677/* XXX: fix it to restore all registers */
4678void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
4679{
4680 TranslationBlock *tb;
4681 int ret;
4682 unsigned long pc;
4683 CPUX86State *saved_env;
4684
4685 /* XXX: hack to restore env in all cases, even if not called from
4686 generated code */
4687 saved_env = env;
4688 env = cpu_single_env;
4689
4690 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
4691 if (ret) {
4692 if (retaddr) {
4693 /* now we have a real cpu fault */
4694 pc = (unsigned long)retaddr;
4695 tb = tb_find_pc(pc);
4696 if (tb) {
4697 /* the PC is inside the translated code. It means that we have
4698 a virtual CPU fault */
4699 cpu_restore_state(tb, env, pc, NULL);
4700 }
4701 }
872929aa 4702 raise_exception_err(env->exception_index, env->error_code);
eaa728ee
FB
4703 }
4704 env = saved_env;
4705}
4706
4707
4708/* Secure Virtual Machine helpers */
4709
eaa728ee
FB
4710#if defined(CONFIG_USER_ONLY)
4711
db620f46 4712void helper_vmrun(int aflag, int next_eip_addend)
eaa728ee
FB
4713{
4714}
4715void helper_vmmcall(void)
4716{
4717}
914178d3 4718void helper_vmload(int aflag)
eaa728ee
FB
4719{
4720}
914178d3 4721void helper_vmsave(int aflag)
eaa728ee
FB
4722{
4723}
872929aa
FB
4724void helper_stgi(void)
4725{
4726}
4727void helper_clgi(void)
4728{
4729}
eaa728ee
FB
4730void helper_skinit(void)
4731{
4732}
914178d3 4733void helper_invlpga(int aflag)
eaa728ee
FB
4734{
4735}
4736void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
4737{
4738}
4739void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
4740{
4741}
4742
4743void helper_svm_check_io(uint32_t port, uint32_t param,
4744 uint32_t next_eip_addend)
4745{
4746}
4747#else
4748
872929aa
FB
4749static inline void svm_save_seg(target_phys_addr_t addr,
4750 const SegmentCache *sc)
eaa728ee 4751{
872929aa
FB
4752 stw_phys(addr + offsetof(struct vmcb_seg, selector),
4753 sc->selector);
4754 stq_phys(addr + offsetof(struct vmcb_seg, base),
4755 sc->base);
4756 stl_phys(addr + offsetof(struct vmcb_seg, limit),
4757 sc->limit);
4758 stw_phys(addr + offsetof(struct vmcb_seg, attrib),
e72210e1 4759 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
872929aa
FB
4760}
4761
4762static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
4763{
4764 unsigned int flags;
4765
4766 sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
4767 sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
4768 sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
4769 flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
4770 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
eaa728ee
FB
4771}
4772
872929aa
FB
4773static inline void svm_load_seg_cache(target_phys_addr_t addr,
4774 CPUState *env, int seg_reg)
eaa728ee 4775{
872929aa
FB
4776 SegmentCache sc1, *sc = &sc1;
4777 svm_load_seg(addr, sc);
4778 cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
4779 sc->base, sc->limit, sc->flags);
eaa728ee
FB
4780}
4781
db620f46 4782void helper_vmrun(int aflag, int next_eip_addend)
eaa728ee
FB
4783{
4784 target_ulong addr;
4785 uint32_t event_inj;
4786 uint32_t int_ctl;
4787
872929aa
FB
4788 helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
4789
914178d3
FB
4790 if (aflag == 2)
4791 addr = EAX;
4792 else
4793 addr = (uint32_t)EAX;
4794
eaa728ee
FB
4795 if (loglevel & CPU_LOG_TB_IN_ASM)
4796 fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
4797
4798 env->vm_vmcb = addr;
4799
4800 /* save the current CPU state in the hsave page */
4801 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4802 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4803
4804 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4805 stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4806
4807 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
4808 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
4809 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
4810 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
eaa728ee
FB
4811 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
4812 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
4813
4814 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
4815 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
4816
872929aa
FB
4817 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
4818 &env->segs[R_ES]);
4819 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
4820 &env->segs[R_CS]);
4821 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
4822 &env->segs[R_SS]);
4823 svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
4824 &env->segs[R_DS]);
eaa728ee 4825
db620f46
FB
4826 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
4827 EIP + next_eip_addend);
eaa728ee
FB
4828 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4829 stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4830
4831 /* load the interception bitmaps so we do not need to access the
4832 vmcb in svm mode */
872929aa 4833 env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept));
eaa728ee
FB
4834 env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4835 env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4836 env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4837 env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4838 env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4839
872929aa
FB
4840 /* enable intercepts */
4841 env->hflags |= HF_SVMI_MASK;
4842
33c263df
FB
4843 env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
4844
eaa728ee
FB
4845 env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4846 env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4847
4848 env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4849 env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4850
4851 /* clear exit_info_2 so we behave like the real hardware */
4852 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4853
4854 cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4855 cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4856 cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4857 env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4858 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
db620f46 4859 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
eaa728ee 4860 if (int_ctl & V_INTR_MASKING_MASK) {
db620f46
FB
4861 env->v_tpr = int_ctl & V_TPR_MASK;
4862 env->hflags2 |= HF2_VINTR_MASK;
eaa728ee 4863 if (env->eflags & IF_MASK)
db620f46 4864 env->hflags2 |= HF2_HIF_MASK;
eaa728ee
FB
4865 }
4866
5efc27bb
FB
4867 cpu_load_efer(env,
4868 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
eaa728ee
FB
4869 env->eflags = 0;
4870 load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
4871 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4872 CC_OP = CC_OP_EFLAGS;
eaa728ee 4873
872929aa
FB
4874 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
4875 env, R_ES);
4876 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
4877 env, R_CS);
4878 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
4879 env, R_SS);
4880 svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
4881 env, R_DS);
eaa728ee
FB
4882
4883 EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
4884 env->eip = EIP;
4885 ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
4886 EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
4887 env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
4888 env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
4889 cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
4890
4891 /* FIXME: guest state consistency checks */
4892
4893 switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
4894 case TLB_CONTROL_DO_NOTHING:
4895 break;
4896 case TLB_CONTROL_FLUSH_ALL_ASID:
4897 /* FIXME: this is not 100% correct but should work for now */
4898 tlb_flush(env, 1);
4899 break;
4900 }
4901
960540b4 4902 env->hflags2 |= HF2_GIF_MASK;
eaa728ee 4903
db620f46
FB
4904 if (int_ctl & V_IRQ_MASK) {
4905 env->interrupt_request |= CPU_INTERRUPT_VIRQ;
4906 }
4907
eaa728ee
FB
4908 /* maybe we need to inject an event */
4909 event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
4910 if (event_inj & SVM_EVTINJ_VALID) {
4911 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4912 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
4913 uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
4914 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
4915
4916 if (loglevel & CPU_LOG_TB_IN_ASM)
4917 fprintf(logfile, "Injecting(%#hx): ", valid_err);
4918 /* FIXME: need to implement valid_err */
4919 switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4920 case SVM_EVTINJ_TYPE_INTR:
4921 env->exception_index = vector;
4922 env->error_code = event_inj_err;
4923 env->exception_is_int = 0;
4924 env->exception_next_eip = -1;
4925 if (loglevel & CPU_LOG_TB_IN_ASM)
4926 fprintf(logfile, "INTR");
db620f46
FB
4927 /* XXX: is it always correct ? */
4928 do_interrupt(vector, 0, 0, 0, 1);
eaa728ee
FB
4929 break;
4930 case SVM_EVTINJ_TYPE_NMI:
db620f46 4931 env->exception_index = EXCP02_NMI;
eaa728ee
FB
4932 env->error_code = event_inj_err;
4933 env->exception_is_int = 0;
4934 env->exception_next_eip = EIP;
4935 if (loglevel & CPU_LOG_TB_IN_ASM)
4936 fprintf(logfile, "NMI");
db620f46 4937 cpu_loop_exit();
eaa728ee
FB
4938 break;
4939 case SVM_EVTINJ_TYPE_EXEPT:
4940 env->exception_index = vector;
4941 env->error_code = event_inj_err;
4942 env->exception_is_int = 0;
4943 env->exception_next_eip = -1;
4944 if (loglevel & CPU_LOG_TB_IN_ASM)
4945 fprintf(logfile, "EXEPT");
db620f46 4946 cpu_loop_exit();
eaa728ee
FB
4947 break;
4948 case SVM_EVTINJ_TYPE_SOFT:
4949 env->exception_index = vector;
4950 env->error_code = event_inj_err;
4951 env->exception_is_int = 1;
4952 env->exception_next_eip = EIP;
4953 if (loglevel & CPU_LOG_TB_IN_ASM)
4954 fprintf(logfile, "SOFT");
db620f46 4955 cpu_loop_exit();
eaa728ee
FB
4956 break;
4957 }
4958 if (loglevel & CPU_LOG_TB_IN_ASM)
4959 fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
4960 }
eaa728ee
FB
4961}
4962
4963void helper_vmmcall(void)
4964{
872929aa
FB
4965 helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
4966 raise_exception(EXCP06_ILLOP);
eaa728ee
FB
4967}
4968
914178d3 4969void helper_vmload(int aflag)
eaa728ee
FB
4970{
4971 target_ulong addr;
872929aa
FB
4972 helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
4973
914178d3
FB
4974 if (aflag == 2)
4975 addr = EAX;
4976 else
4977 addr = (uint32_t)EAX;
4978
eaa728ee
FB
4979 if (loglevel & CPU_LOG_TB_IN_ASM)
4980 fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4981 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4982 env->segs[R_FS].base);
4983
872929aa
FB
4984 svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
4985 env, R_FS);
4986 svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
4987 env, R_GS);
4988 svm_load_seg(addr + offsetof(struct vmcb, save.tr),
4989 &env->tr);
4990 svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
4991 &env->ldt);
eaa728ee
FB
4992
4993#ifdef TARGET_X86_64
4994 env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
4995 env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
4996 env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
4997 env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
4998#endif
4999 env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
5000 env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
5001 env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
5002 env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
5003}
5004
914178d3 5005void helper_vmsave(int aflag)
eaa728ee
FB
5006{
5007 target_ulong addr;
872929aa 5008 helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
914178d3
FB
5009
5010 if (aflag == 2)
5011 addr = EAX;
5012 else
5013 addr = (uint32_t)EAX;
5014
eaa728ee
FB
5015 if (loglevel & CPU_LOG_TB_IN_ASM)
5016 fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
5017 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
5018 env->segs[R_FS].base);
5019
872929aa
FB
5020 svm_save_seg(addr + offsetof(struct vmcb, save.fs),
5021 &env->segs[R_FS]);
5022 svm_save_seg(addr + offsetof(struct vmcb, save.gs),
5023 &env->segs[R_GS]);
5024 svm_save_seg(addr + offsetof(struct vmcb, save.tr),
5025 &env->tr);
5026 svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
5027 &env->ldt);
eaa728ee
FB
5028
5029#ifdef TARGET_X86_64
5030 stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
5031 stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
5032 stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
5033 stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
5034#endif
5035 stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5036 stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5037 stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5038 stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5039}
5040
872929aa
FB
5041void helper_stgi(void)
5042{
5043 helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
db620f46 5044 env->hflags2 |= HF2_GIF_MASK;
872929aa
FB
5045}
5046
5047void helper_clgi(void)
5048{
5049 helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
db620f46 5050 env->hflags2 &= ~HF2_GIF_MASK;
872929aa
FB
5051}
5052
eaa728ee
FB
5053void helper_skinit(void)
5054{
872929aa
FB
5055 helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
5056 /* XXX: not implemented */
872929aa 5057 raise_exception(EXCP06_ILLOP);
eaa728ee
FB
5058}
5059
914178d3 5060void helper_invlpga(int aflag)
eaa728ee 5061{
914178d3 5062 target_ulong addr;
872929aa 5063 helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
914178d3
FB
5064
5065 if (aflag == 2)
5066 addr = EAX;
5067 else
5068 addr = (uint32_t)EAX;
5069
5070 /* XXX: could use the ASID to see if it is needed to do the
5071 flush */
5072 tlb_flush_page(env, addr);
eaa728ee
FB
5073}
5074
5075void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5076{
872929aa
FB
5077 if (likely(!(env->hflags & HF_SVMI_MASK)))
5078 return;
eaa728ee
FB
5079 switch(type) {
5080 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
872929aa 5081 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
eaa728ee
FB
5082 helper_vmexit(type, param);
5083 }
5084 break;
872929aa
FB
5085 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5086 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
eaa728ee
FB
5087 helper_vmexit(type, param);
5088 }
5089 break;
872929aa
FB
5090 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
5091 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
eaa728ee
FB
5092 helper_vmexit(type, param);
5093 }
5094 break;
872929aa
FB
5095 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
5096 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
eaa728ee
FB
5097 helper_vmexit(type, param);
5098 }
5099 break;
872929aa
FB
5100 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
5101 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
eaa728ee
FB
5102 helper_vmexit(type, param);
5103 }
5104 break;
eaa728ee 5105 case SVM_EXIT_MSR:
872929aa 5106 if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
eaa728ee
FB
5107 /* FIXME: this should be read in at vmrun (faster this way?) */
5108 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5109 uint32_t t0, t1;
5110 switch((uint32_t)ECX) {
5111 case 0 ... 0x1fff:
5112 t0 = (ECX * 2) % 8;
5113 t1 = ECX / 8;
5114 break;
5115 case 0xc0000000 ... 0xc0001fff:
5116 t0 = (8192 + ECX - 0xc0000000) * 2;
5117 t1 = (t0 / 8);
5118 t0 %= 8;
5119 break;
5120 case 0xc0010000 ... 0xc0011fff:
5121 t0 = (16384 + ECX - 0xc0010000) * 2;
5122 t1 = (t0 / 8);
5123 t0 %= 8;
5124 break;
5125 default:
5126 helper_vmexit(type, param);
5127 t0 = 0;
5128 t1 = 0;
5129 break;
5130 }
5131 if (ldub_phys(addr + t1) & ((1 << param) << t0))
5132 helper_vmexit(type, param);
5133 }
5134 break;
5135 default:
872929aa 5136 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
eaa728ee
FB
5137 helper_vmexit(type, param);
5138 }
5139 break;
5140 }
5141}
5142
5143void helper_svm_check_io(uint32_t port, uint32_t param,
5144 uint32_t next_eip_addend)
5145{
872929aa 5146 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
eaa728ee
FB
5147 /* FIXME: this should be read in at vmrun (faster this way?) */
5148 uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5149 uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5150 if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5151 /* next EIP */
5152 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
5153 env->eip + next_eip_addend);
5154 helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5155 }
5156 }
5157}
5158
5159/* Note: currently only 32 bits of exit_code are used */
5160void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5161{
5162 uint32_t int_ctl;
5163
5164 if (loglevel & CPU_LOG_TB_IN_ASM)
5165 fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5166 exit_code, exit_info_1,
5167 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5168 EIP);
5169
5170 if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5171 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5172 env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5173 } else {
5174 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5175 }
5176
5177 /* Save the VM state in the vmcb */
872929aa
FB
5178 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
5179 &env->segs[R_ES]);
5180 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
5181 &env->segs[R_CS]);
5182 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
5183 &env->segs[R_SS]);
5184 svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
5185 &env->segs[R_DS]);
eaa728ee
FB
5186
5187 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5188 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5189
5190 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5191 stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5192
5193 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5194 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5195 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5196 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5197 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5198
db620f46
FB
5199 int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
5200 int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
5201 int_ctl |= env->v_tpr & V_TPR_MASK;
5202 if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
5203 int_ctl |= V_IRQ_MASK;
5204 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
eaa728ee
FB
5205
5206 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5207 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5208 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5209 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5210 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5211 stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5212 stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5213
5214 /* Reload the host state from vm_hsave */
db620f46 5215 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
872929aa 5216 env->hflags &= ~HF_SVMI_MASK;
eaa728ee
FB
5217 env->intercept = 0;
5218 env->intercept_exceptions = 0;
5219 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
33c263df 5220 env->tsc_offset = 0;
eaa728ee
FB
5221
5222 env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5223 env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5224
5225 env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5226 env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5227
5228 cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5229 cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5230 cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5efc27bb
FB
5231 /* we need to set the efer after the crs so the hidden flags get
5232 set properly */
5efc27bb
FB
5233 cpu_load_efer(env,
5234 ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
eaa728ee
FB
5235 env->eflags = 0;
5236 load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5237 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5238 CC_OP = CC_OP_EFLAGS;
5239
872929aa
FB
5240 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
5241 env, R_ES);
5242 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
5243 env, R_CS);
5244 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
5245 env, R_SS);
5246 svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
5247 env, R_DS);
eaa728ee
FB
5248
5249 EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5250 ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5251 EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5252
5253 env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5254 env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5255
5256 /* other setups */
5257 cpu_x86_set_cpl(env, 0);
5258 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5259 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5260
960540b4 5261 env->hflags2 &= ~HF2_GIF_MASK;
eaa728ee
FB
5262 /* FIXME: Resets the current ASID register to zero (host ASID). */
5263
5264 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5265
5266 /* Clears the TSC_OFFSET inside the processor. */
5267
5268 /* If the host is in PAE mode, the processor reloads the host's PDPEs
5269 from the page table indicated the host's CR3. If the PDPEs contain
5270 illegal state, the processor causes a shutdown. */
5271
5272 /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5273 env->cr[0] |= CR0_PE_MASK;
5274 env->eflags &= ~VM_MASK;
5275
5276 /* Disables all breakpoints in the host DR7 register. */
5277
5278 /* Checks the reloaded host state for consistency. */
5279
5280 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5281 host's code segment or non-canonical (in the case of long mode), a
5282 #GP fault is delivered inside the host.) */
5283
5284 /* remove any pending exception */
5285 env->exception_index = -1;
5286 env->error_code = 0;
5287 env->old_exception = -1;
5288
5289 cpu_loop_exit();
5290}
5291
5292#endif
5293
5294/* MMX/SSE */
5295/* XXX: optimize by storing fptt and fptags in the static cpu state */
5296void helper_enter_mmx(void)
5297{
5298 env->fpstt = 0;
5299 *(uint32_t *)(env->fptags) = 0;
5300 *(uint32_t *)(env->fptags + 4) = 0;
5301}
5302
5303void helper_emms(void)
5304{
5305 /* set to empty state */
5306 *(uint32_t *)(env->fptags) = 0x01010101;
5307 *(uint32_t *)(env->fptags + 4) = 0x01010101;
5308}
5309
5310/* XXX: suppress */
a7812ae4 5311void helper_movq(void *d, void *s)
eaa728ee 5312{
a7812ae4 5313 *(uint64_t *)d = *(uint64_t *)s;
eaa728ee
FB
5314}
5315
5316#define SHIFT 0
5317#include "ops_sse.h"
5318
5319#define SHIFT 1
5320#include "ops_sse.h"
5321
5322#define SHIFT 0
5323#include "helper_template.h"
5324#undef SHIFT
5325
5326#define SHIFT 1
5327#include "helper_template.h"
5328#undef SHIFT
5329
5330#define SHIFT 2
5331#include "helper_template.h"
5332#undef SHIFT
5333
5334#ifdef TARGET_X86_64
5335
5336#define SHIFT 3
5337#include "helper_template.h"
5338#undef SHIFT
5339
5340#endif
5341
5342/* bit operations */
5343target_ulong helper_bsf(target_ulong t0)
5344{
5345 int count;
5346 target_ulong res;
5347
5348 res = t0;
5349 count = 0;
5350 while ((res & 1) == 0) {
5351 count++;
5352 res >>= 1;
5353 }
5354 return count;
5355}
5356
5357target_ulong helper_bsr(target_ulong t0)
5358{
5359 int count;
5360 target_ulong res, mask;
5361
5362 res = t0;
5363 count = TARGET_LONG_BITS - 1;
5364 mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5365 while ((res & mask) == 0) {
5366 count--;
5367 res <<= 1;
5368 }
5369 return count;
5370}
5371
5372
5373static int compute_all_eflags(void)
5374{
5375 return CC_SRC;
5376}
5377
5378static int compute_c_eflags(void)
5379{
5380 return CC_SRC & CC_C;
5381}
5382
a7812ae4
PB
5383uint32_t helper_cc_compute_all(int op)
5384{
5385 switch (op) {
5386 default: /* should never happen */ return 0;
eaa728ee 5387
a7812ae4 5388 case CC_OP_EFLAGS: return compute_all_eflags();
eaa728ee 5389
a7812ae4
PB
5390 case CC_OP_MULB: return compute_all_mulb();
5391 case CC_OP_MULW: return compute_all_mulw();
5392 case CC_OP_MULL: return compute_all_mull();
eaa728ee 5393
a7812ae4
PB
5394 case CC_OP_ADDB: return compute_all_addb();
5395 case CC_OP_ADDW: return compute_all_addw();
5396 case CC_OP_ADDL: return compute_all_addl();
eaa728ee 5397
a7812ae4
PB
5398 case CC_OP_ADCB: return compute_all_adcb();
5399 case CC_OP_ADCW: return compute_all_adcw();
5400 case CC_OP_ADCL: return compute_all_adcl();
eaa728ee 5401
a7812ae4
PB
5402 case CC_OP_SUBB: return compute_all_subb();
5403 case CC_OP_SUBW: return compute_all_subw();
5404 case CC_OP_SUBL: return compute_all_subl();
eaa728ee 5405
a7812ae4
PB
5406 case CC_OP_SBBB: return compute_all_sbbb();
5407 case CC_OP_SBBW: return compute_all_sbbw();
5408 case CC_OP_SBBL: return compute_all_sbbl();
eaa728ee 5409
a7812ae4
PB
5410 case CC_OP_LOGICB: return compute_all_logicb();
5411 case CC_OP_LOGICW: return compute_all_logicw();
5412 case CC_OP_LOGICL: return compute_all_logicl();
eaa728ee 5413
a7812ae4
PB
5414 case CC_OP_INCB: return compute_all_incb();
5415 case CC_OP_INCW: return compute_all_incw();
5416 case CC_OP_INCL: return compute_all_incl();
eaa728ee 5417
a7812ae4
PB
5418 case CC_OP_DECB: return compute_all_decb();
5419 case CC_OP_DECW: return compute_all_decw();
5420 case CC_OP_DECL: return compute_all_decl();
eaa728ee 5421
a7812ae4
PB
5422 case CC_OP_SHLB: return compute_all_shlb();
5423 case CC_OP_SHLW: return compute_all_shlw();
5424 case CC_OP_SHLL: return compute_all_shll();
eaa728ee 5425
a7812ae4
PB
5426 case CC_OP_SARB: return compute_all_sarb();
5427 case CC_OP_SARW: return compute_all_sarw();
5428 case CC_OP_SARL: return compute_all_sarl();
eaa728ee
FB
5429
5430#ifdef TARGET_X86_64
a7812ae4 5431 case CC_OP_MULQ: return compute_all_mulq();
eaa728ee 5432
a7812ae4 5433 case CC_OP_ADDQ: return compute_all_addq();
eaa728ee 5434
a7812ae4 5435 case CC_OP_ADCQ: return compute_all_adcq();
eaa728ee 5436
a7812ae4 5437 case CC_OP_SUBQ: return compute_all_subq();
eaa728ee 5438
a7812ae4 5439 case CC_OP_SBBQ: return compute_all_sbbq();
eaa728ee 5440
a7812ae4 5441 case CC_OP_LOGICQ: return compute_all_logicq();
eaa728ee 5442
a7812ae4 5443 case CC_OP_INCQ: return compute_all_incq();
eaa728ee 5444
a7812ae4 5445 case CC_OP_DECQ: return compute_all_decq();
eaa728ee 5446
a7812ae4 5447 case CC_OP_SHLQ: return compute_all_shlq();
eaa728ee 5448
a7812ae4 5449 case CC_OP_SARQ: return compute_all_sarq();
eaa728ee 5450#endif
a7812ae4
PB
5451 }
5452}
5453
5454uint32_t helper_cc_compute_c(int op)
5455{
5456 switch (op) {
5457 default: /* should never happen */ return 0;
5458
5459 case CC_OP_EFLAGS: return compute_c_eflags();
5460
5461 case CC_OP_MULB: return compute_c_mull();
5462 case CC_OP_MULW: return compute_c_mull();
5463 case CC_OP_MULL: return compute_c_mull();
5464
5465 case CC_OP_ADDB: return compute_c_addb();
5466 case CC_OP_ADDW: return compute_c_addw();
5467 case CC_OP_ADDL: return compute_c_addl();
5468
5469 case CC_OP_ADCB: return compute_c_adcb();
5470 case CC_OP_ADCW: return compute_c_adcw();
5471 case CC_OP_ADCL: return compute_c_adcl();
5472
5473 case CC_OP_SUBB: return compute_c_subb();
5474 case CC_OP_SUBW: return compute_c_subw();
5475 case CC_OP_SUBL: return compute_c_subl();
5476
5477 case CC_OP_SBBB: return compute_c_sbbb();
5478 case CC_OP_SBBW: return compute_c_sbbw();
5479 case CC_OP_SBBL: return compute_c_sbbl();
5480
5481 case CC_OP_LOGICB: return compute_c_logicb();
5482 case CC_OP_LOGICW: return compute_c_logicw();
5483 case CC_OP_LOGICL: return compute_c_logicl();
5484
5485 case CC_OP_INCB: return compute_c_incl();
5486 case CC_OP_INCW: return compute_c_incl();
5487 case CC_OP_INCL: return compute_c_incl();
5488
5489 case CC_OP_DECB: return compute_c_incl();
5490 case CC_OP_DECW: return compute_c_incl();
5491 case CC_OP_DECL: return compute_c_incl();
eaa728ee 5492
a7812ae4
PB
5493 case CC_OP_SHLB: return compute_c_shlb();
5494 case CC_OP_SHLW: return compute_c_shlw();
5495 case CC_OP_SHLL: return compute_c_shll();
5496
5497 case CC_OP_SARB: return compute_c_sarl();
5498 case CC_OP_SARW: return compute_c_sarl();
5499 case CC_OP_SARL: return compute_c_sarl();
5500
5501#ifdef TARGET_X86_64
5502 case CC_OP_MULQ: return compute_c_mull();
5503
5504 case CC_OP_ADDQ: return compute_c_addq();
5505
5506 case CC_OP_ADCQ: return compute_c_adcq();
5507
5508 case CC_OP_SUBQ: return compute_c_subq();
5509
5510 case CC_OP_SBBQ: return compute_c_sbbq();
5511
5512 case CC_OP_LOGICQ: return compute_c_logicq();
5513
5514 case CC_OP_INCQ: return compute_c_incl();
5515
5516 case CC_OP_DECQ: return compute_c_incl();
5517
5518 case CC_OP_SHLQ: return compute_c_shlq();
5519
5520 case CC_OP_SARQ: return compute_c_sarl();
5521#endif
5522 }
5523}