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