]> Git Repo - qemu.git/blame - target-i386/helper.c
added PE to static CPU state (avoids flushing translated code when swiching between...
[qemu.git] / target-i386 / helper.c
CommitLineData
2c0262af
FB
1/*
2 * i386 helpers
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "exec.h"
21
f3f2d9be
FB
22//#define DEBUG_PCALL
23
2c0262af
FB
24const uint8_t parity_table[256] = {
25 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
26 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
27 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
28 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
29 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
30 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
31 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
32 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
33 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
34 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
35 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
36 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
40 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
43 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
46 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
47 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
49 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
56 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57};
58
59/* modulo 17 table */
60const uint8_t rclw_table[32] = {
61 0, 1, 2, 3, 4, 5, 6, 7,
62 8, 9,10,11,12,13,14,15,
63 16, 0, 1, 2, 3, 4, 5, 6,
64 7, 8, 9,10,11,12,13,14,
65};
66
67/* modulo 9 table */
68const uint8_t rclb_table[32] = {
69 0, 1, 2, 3, 4, 5, 6, 7,
70 8, 0, 1, 2, 3, 4, 5, 6,
71 7, 8, 0, 1, 2, 3, 4, 5,
72 6, 7, 8, 0, 1, 2, 3, 4,
73};
74
75const CPU86_LDouble f15rk[7] =
76{
77 0.00000000000000000000L,
78 1.00000000000000000000L,
79 3.14159265358979323851L, /*pi*/
80 0.30102999566398119523L, /*lg2*/
81 0.69314718055994530943L, /*ln2*/
82 1.44269504088896340739L, /*l2e*/
83 3.32192809488736234781L, /*l2t*/
84};
85
86/* thread support */
87
88spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
89
90void cpu_lock(void)
91{
92 spin_lock(&global_cpu_lock);
93}
94
95void cpu_unlock(void)
96{
97 spin_unlock(&global_cpu_lock);
98}
99
100void cpu_loop_exit(void)
101{
102 /* NOTE: the register at this point must be saved by hand because
103 longjmp restore them */
104#ifdef reg_EAX
105 env->regs[R_EAX] = EAX;
106#endif
107#ifdef reg_ECX
108 env->regs[R_ECX] = ECX;
109#endif
110#ifdef reg_EDX
111 env->regs[R_EDX] = EDX;
112#endif
113#ifdef reg_EBX
114 env->regs[R_EBX] = EBX;
115#endif
116#ifdef reg_ESP
117 env->regs[R_ESP] = ESP;
118#endif
119#ifdef reg_EBP
120 env->regs[R_EBP] = EBP;
121#endif
122#ifdef reg_ESI
123 env->regs[R_ESI] = ESI;
124#endif
125#ifdef reg_EDI
126 env->regs[R_EDI] = EDI;
127#endif
128 longjmp(env->jmp_env, 1);
129}
130
7e84c249
FB
131/* return non zero if error */
132static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
133 int selector)
134{
135 SegmentCache *dt;
136 int index;
137 uint8_t *ptr;
138
139 if (selector & 0x4)
140 dt = &env->ldt;
141 else
142 dt = &env->gdt;
143 index = selector & ~7;
144 if ((index + 7) > dt->limit)
145 return -1;
146 ptr = dt->base + index;
147 *e1_ptr = ldl_kernel(ptr);
148 *e2_ptr = ldl_kernel(ptr + 4);
149 return 0;
150}
151
152static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
153{
154 unsigned int limit;
155 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
156 if (e2 & DESC_G_MASK)
157 limit = (limit << 12) | 0xfff;
158 return limit;
159}
160
161static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
162{
163 return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
164}
165
166static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
167{
168 sc->base = get_seg_base(e1, e2);
169 sc->limit = get_seg_limit(e1, e2);
170 sc->flags = e2;
171}
172
173/* init the segment cache in vm86 mode. */
174static inline void load_seg_vm(int seg, int selector)
175{
176 selector &= 0xffff;
177 cpu_x86_load_seg_cache(env, seg, selector,
178 (uint8_t *)(selector << 4), 0xffff, 0);
179}
180
2c0262af
FB
181static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
182 uint32_t *esp_ptr, int dpl)
183{
184 int type, index, shift;
185
186#if 0
187 {
188 int i;
189 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
190 for(i=0;i<env->tr.limit;i++) {
191 printf("%02x ", env->tr.base[i]);
192 if ((i & 7) == 7) printf("\n");
193 }
194 printf("\n");
195 }
196#endif
197
198 if (!(env->tr.flags & DESC_P_MASK))
199 cpu_abort(env, "invalid tss");
200 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
201 if ((type & 7) != 1)
202 cpu_abort(env, "invalid tss type");
203 shift = type >> 3;
204 index = (dpl * 4 + 2) << shift;
205 if (index + (4 << shift) - 1 > env->tr.limit)
206 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
207 if (shift == 0) {
61382a50
FB
208 *esp_ptr = lduw_kernel(env->tr.base + index);
209 *ss_ptr = lduw_kernel(env->tr.base + index + 2);
2c0262af 210 } else {
61382a50
FB
211 *esp_ptr = ldl_kernel(env->tr.base + index);
212 *ss_ptr = lduw_kernel(env->tr.base + index + 4);
2c0262af
FB
213 }
214}
215
7e84c249
FB
216/* XXX: merge with load_seg() */
217static void tss_load_seg(int seg_reg, int selector)
218{
219 uint32_t e1, e2;
220 int rpl, dpl, cpl;
221
222 if ((selector & 0xfffc) != 0) {
223 if (load_segment(&e1, &e2, selector) != 0)
224 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
225 if (!(e2 & DESC_S_MASK))
226 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
227 rpl = selector & 3;
228 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
229 cpl = env->hflags & HF_CPL_MASK;
230 if (seg_reg == R_CS) {
231 if (!(e2 & DESC_CS_MASK))
232 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
233 if (dpl != rpl)
234 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
235 if ((e2 & DESC_C_MASK) && dpl > rpl)
236 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
237
238 } else if (seg_reg == R_SS) {
239 /* SS must be writable data */
240 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
241 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
242 if (dpl != cpl || dpl != rpl)
243 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
244 } else {
245 /* not readable code */
246 if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
247 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
248 /* if data or non conforming code, checks the rights */
249 if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
250 if (dpl < cpl || dpl < rpl)
251 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
252 }
253 }
254 if (!(e2 & DESC_P_MASK))
255 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
256 cpu_x86_load_seg_cache(env, seg_reg, selector,
257 get_seg_base(e1, e2),
258 get_seg_limit(e1, e2),
259 e2);
260 } else {
261 if (seg_reg == R_SS || seg_reg == R_CS)
262 raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
263 }
264}
265
266#define SWITCH_TSS_JMP 0
267#define SWITCH_TSS_IRET 1
268#define SWITCH_TSS_CALL 2
269
270/* XXX: restore CPU state in registers (PowerPC case) */
271static void switch_tss(int tss_selector,
272 uint32_t e1, uint32_t e2, int source)
2c0262af 273{
7e84c249
FB
274 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
275 uint8_t *tss_base;
276 uint32_t new_regs[8], new_segs[6];
277 uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
278 uint32_t old_eflags, eflags_mask;
2c0262af
FB
279 SegmentCache *dt;
280 int index;
281 uint8_t *ptr;
282
7e84c249
FB
283 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
284
285 /* if task gate, we read the TSS segment and we load it */
286 if (type == 5) {
287 if (!(e2 & DESC_P_MASK))
288 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
289 tss_selector = e1 >> 16;
290 if (tss_selector & 4)
291 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
292 if (load_segment(&e1, &e2, tss_selector) != 0)
293 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
294 if (e2 & DESC_S_MASK)
295 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
296 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
297 if ((type & 7) != 1)
298 raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
299 }
300
301 if (!(e2 & DESC_P_MASK))
302 raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
303
304 if (type & 8)
305 tss_limit_max = 103;
2c0262af 306 else
7e84c249
FB
307 tss_limit_max = 43;
308 tss_limit = get_seg_limit(e1, e2);
309 tss_base = get_seg_base(e1, e2);
310 if ((tss_selector & 4) != 0 ||
311 tss_limit < tss_limit_max)
312 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
313 old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
314 if (old_type & 8)
315 old_tss_limit_max = 103;
316 else
317 old_tss_limit_max = 43;
318
319 /* read all the registers from the new TSS */
320 if (type & 8) {
321 /* 32 bit */
322 new_cr3 = ldl_kernel(tss_base + 0x1c);
323 new_eip = ldl_kernel(tss_base + 0x20);
324 new_eflags = ldl_kernel(tss_base + 0x24);
325 for(i = 0; i < 8; i++)
326 new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
327 for(i = 0; i < 6; i++)
328 new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
329 new_ldt = lduw_kernel(tss_base + 0x60);
330 new_trap = ldl_kernel(tss_base + 0x64);
331 } else {
332 /* 16 bit */
333 new_cr3 = 0;
334 new_eip = lduw_kernel(tss_base + 0x0e);
335 new_eflags = lduw_kernel(tss_base + 0x10);
336 for(i = 0; i < 8; i++)
337 new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
338 for(i = 0; i < 4; i++)
339 new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
340 new_ldt = lduw_kernel(tss_base + 0x2a);
341 new_segs[R_FS] = 0;
342 new_segs[R_GS] = 0;
343 new_trap = 0;
344 }
345
346 /* NOTE: we must avoid memory exceptions during the task switch,
347 so we make dummy accesses before */
348 /* XXX: it can still fail in some cases, so a bigger hack is
349 necessary to valid the TLB after having done the accesses */
350
351 v1 = ldub_kernel(env->tr.base);
352 v2 = ldub(env->tr.base + old_tss_limit_max);
353 stb_kernel(env->tr.base, v1);
354 stb_kernel(env->tr.base + old_tss_limit_max, v2);
355
356 /* clear busy bit (it is restartable) */
357 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
358 uint8_t *ptr;
359 uint32_t e2;
360 ptr = env->gdt.base + (env->tr.selector << 3);
361 e2 = ldl_kernel(ptr + 4);
362 e2 &= ~DESC_TSS_BUSY_MASK;
363 stl_kernel(ptr + 4, e2);
364 }
365 old_eflags = compute_eflags();
366 if (source == SWITCH_TSS_IRET)
367 old_eflags &= ~NT_MASK;
368
369 /* save the current state in the old TSS */
370 if (type & 8) {
371 /* 32 bit */
372 stl_kernel(env->tr.base + 0x20, env->eip);
373 stl_kernel(env->tr.base + 0x24, old_eflags);
374 for(i = 0; i < 8; i++)
375 stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]);
376 for(i = 0; i < 6; i++)
377 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
378 } else {
379 /* 16 bit */
380 stw_kernel(env->tr.base + 0x0e, new_eip);
381 stw_kernel(env->tr.base + 0x10, old_eflags);
382 for(i = 0; i < 8; i++)
383 stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]);
384 for(i = 0; i < 4; i++)
385 stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
386 }
387
388 /* now if an exception occurs, it will occurs in the next task
389 context */
390
391 if (source == SWITCH_TSS_CALL) {
392 stw_kernel(tss_base, env->tr.selector);
393 new_eflags |= NT_MASK;
394 }
395
396 /* set busy bit */
397 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
398 uint8_t *ptr;
399 uint32_t e2;
400 ptr = env->gdt.base + (tss_selector << 3);
401 e2 = ldl_kernel(ptr + 4);
402 e2 |= DESC_TSS_BUSY_MASK;
403 stl_kernel(ptr + 4, e2);
404 }
405
406 /* set the new CPU state */
407 /* from this point, any exception which occurs can give problems */
408 env->cr[0] |= CR0_TS_MASK;
409 env->tr.selector = tss_selector;
410 env->tr.base = tss_base;
411 env->tr.limit = tss_limit;
412 env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
413
414 if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
415 env->cr[3] = new_cr3;
416 cpu_x86_update_cr3(env);
417 }
418
419 /* load all registers without an exception, then reload them with
420 possible exception */
421 env->eip = new_eip;
4136f33c
FB
422 eflags_mask = TF_MASK | AC_MASK | ID_MASK |
423 IF_MASK | IOPL_MASK | VM_MASK | RF_MASK;
7e84c249
FB
424 if (!(type & 8))
425 eflags_mask &= 0xffff;
426 load_eflags(new_eflags, eflags_mask);
427 for(i = 0; i < 8; i++)
428 env->regs[i] = new_regs[i];
429 if (new_eflags & VM_MASK) {
430 for(i = 0; i < 6; i++)
431 load_seg_vm(i, new_segs[i]);
432 /* in vm86, CPL is always 3 */
433 cpu_x86_set_cpl(env, 3);
434 } else {
435 /* CPL is set the RPL of CS */
436 cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
437 /* first just selectors as the rest may trigger exceptions */
438 for(i = 0; i < 6; i++)
439 cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0);
440 }
441
442 env->ldt.selector = new_ldt & ~4;
443 env->ldt.base = NULL;
444 env->ldt.limit = 0;
445 env->ldt.flags = 0;
446
447 /* load the LDT */
448 if (new_ldt & 4)
449 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
450
451 dt = &env->gdt;
452 index = new_ldt & ~7;
2c0262af 453 if ((index + 7) > dt->limit)
7e84c249 454 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
2c0262af 455 ptr = dt->base + index;
7e84c249
FB
456 e1 = ldl_kernel(ptr);
457 e2 = ldl_kernel(ptr + 4);
458 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
459 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
460 if (!(e2 & DESC_P_MASK))
461 raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
462 load_seg_cache_raw_dt(&env->ldt, e1, e2);
463
464 /* load the segments */
465 if (!(new_eflags & VM_MASK)) {
466 tss_load_seg(R_CS, new_segs[R_CS]);
467 tss_load_seg(R_SS, new_segs[R_SS]);
468 tss_load_seg(R_ES, new_segs[R_ES]);
469 tss_load_seg(R_DS, new_segs[R_DS]);
470 tss_load_seg(R_FS, new_segs[R_FS]);
471 tss_load_seg(R_GS, new_segs[R_GS]);
472 }
473
474 /* check that EIP is in the CS segment limits */
475 if (new_eip > env->segs[R_CS].limit) {
476 raise_exception_err(EXCP0D_GPF, 0);
477 }
2c0262af 478}
7e84c249
FB
479
480/* check if Port I/O is allowed in TSS */
481static inline void check_io(int addr, int size)
2c0262af 482{
7e84c249
FB
483 int io_offset, val, mask;
484
485 /* TSS must be a valid 32 bit one */
486 if (!(env->tr.flags & DESC_P_MASK) ||
487 ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
488 env->tr.limit < 103)
489 goto fail;
490 io_offset = lduw_kernel(env->tr.base + 0x66);
491 io_offset += (addr >> 3);
492 /* Note: the check needs two bytes */
493 if ((io_offset + 1) > env->tr.limit)
494 goto fail;
495 val = lduw_kernel(env->tr.base + io_offset);
496 val >>= (addr & 7);
497 mask = (1 << size) - 1;
498 /* all bits must be zero to allow the I/O */
499 if ((val & mask) != 0) {
500 fail:
501 raise_exception_err(EXCP0D_GPF, 0);
502 }
2c0262af
FB
503}
504
7e84c249 505void check_iob_T0(void)
2c0262af 506{
7e84c249 507 check_io(T0, 1);
2c0262af
FB
508}
509
7e84c249 510void check_iow_T0(void)
2c0262af 511{
7e84c249 512 check_io(T0, 2);
2c0262af
FB
513}
514
7e84c249 515void check_iol_T0(void)
2c0262af 516{
7e84c249
FB
517 check_io(T0, 4);
518}
519
520void check_iob_DX(void)
521{
522 check_io(EDX & 0xffff, 1);
523}
524
525void check_iow_DX(void)
526{
527 check_io(EDX & 0xffff, 2);
528}
529
530void check_iol_DX(void)
531{
532 check_io(EDX & 0xffff, 4);
2c0262af
FB
533}
534
891b38e4
FB
535static inline unsigned int get_sp_mask(unsigned int e2)
536{
537 if (e2 & DESC_B_MASK)
538 return 0xffffffff;
539 else
540 return 0xffff;
541}
542
543/* XXX: add a is_user flag to have proper security support */
544#define PUSHW(ssp, sp, sp_mask, val)\
545{\
546 sp -= 2;\
547 stw_kernel((ssp) + (sp & (sp_mask)), (val));\
548}
549
550#define PUSHL(ssp, sp, sp_mask, val)\
551{\
552 sp -= 4;\
553 stl_kernel((ssp) + (sp & (sp_mask)), (val));\
554}
555
556#define POPW(ssp, sp, sp_mask, val)\
557{\
558 val = lduw_kernel((ssp) + (sp & (sp_mask)));\
559 sp += 2;\
560}
561
562#define POPL(ssp, sp, sp_mask, val)\
563{\
564 val = ldl_kernel((ssp) + (sp & (sp_mask)));\
565 sp += 4;\
566}
567
2c0262af
FB
568/* protected mode interrupt */
569static void do_interrupt_protected(int intno, int is_int, int error_code,
570 unsigned int next_eip, int is_hw)
571{
572 SegmentCache *dt;
573 uint8_t *ptr, *ssp;
891b38e4 574 int type, dpl, selector, ss_dpl, cpl, sp_mask;
2c0262af 575 int has_error_code, new_stack, shift;
891b38e4
FB
576 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
577 uint32_t old_eip;
2c0262af 578
7e84c249
FB
579 has_error_code = 0;
580 if (!is_int && !is_hw) {
581 switch(intno) {
582 case 8:
583 case 10:
584 case 11:
585 case 12:
586 case 13:
587 case 14:
588 case 17:
589 has_error_code = 1;
590 break;
591 }
592 }
593
2c0262af
FB
594 dt = &env->idt;
595 if (intno * 8 + 7 > dt->limit)
596 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
597 ptr = dt->base + intno * 8;
61382a50
FB
598 e1 = ldl_kernel(ptr);
599 e2 = ldl_kernel(ptr + 4);
2c0262af
FB
600 /* check gate type */
601 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
602 switch(type) {
603 case 5: /* task gate */
7e84c249
FB
604 /* must do that check here to return the correct error code */
605 if (!(e2 & DESC_P_MASK))
606 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
607 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL);
608 if (has_error_code) {
609 int mask;
610 /* push the error code */
611 shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1;
612 if (env->segs[R_SS].flags & DESC_B_MASK)
613 mask = 0xffffffff;
614 else
615 mask = 0xffff;
616 esp = (env->regs[R_ESP] - (2 << shift)) & mask;
617 ssp = env->segs[R_SS].base + esp;
618 if (shift)
619 stl_kernel(ssp, error_code);
620 else
621 stw_kernel(ssp, error_code);
622 env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask);
623 }
624 return;
2c0262af
FB
625 case 6: /* 286 interrupt gate */
626 case 7: /* 286 trap gate */
627 case 14: /* 386 interrupt gate */
628 case 15: /* 386 trap gate */
629 break;
630 default:
631 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
632 break;
633 }
634 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
635 cpl = env->hflags & HF_CPL_MASK;
636 /* check privledge if software int */
637 if (is_int && dpl < cpl)
638 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
639 /* check valid bit */
640 if (!(e2 & DESC_P_MASK))
641 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
642 selector = e1 >> 16;
643 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
644 if ((selector & 0xfffc) == 0)
645 raise_exception_err(EXCP0D_GPF, 0);
646
647 if (load_segment(&e1, &e2, selector) != 0)
648 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
649 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
650 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
651 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
652 if (dpl > cpl)
653 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
654 if (!(e2 & DESC_P_MASK))
655 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
656 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
657 /* to inner priviledge */
658 get_ss_esp_from_tss(&ss, &esp, dpl);
659 if ((ss & 0xfffc) == 0)
660 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
661 if ((ss & 3) != dpl)
662 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
663 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
664 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
665 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
666 if (ss_dpl != dpl)
667 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
668 if (!(ss_e2 & DESC_S_MASK) ||
669 (ss_e2 & DESC_CS_MASK) ||
670 !(ss_e2 & DESC_W_MASK))
671 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
672 if (!(ss_e2 & DESC_P_MASK))
673 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
674 new_stack = 1;
891b38e4
FB
675 sp_mask = get_sp_mask(ss_e2);
676 ssp = get_seg_base(ss_e1, ss_e2);
2c0262af
FB
677 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
678 /* to same priviledge */
8e682019
FB
679 if (env->eflags & VM_MASK)
680 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2c0262af 681 new_stack = 0;
891b38e4
FB
682 sp_mask = get_sp_mask(env->segs[R_SS].flags);
683 ssp = env->segs[R_SS].base;
684 esp = ESP;
2c0262af
FB
685 } else {
686 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
687 new_stack = 0; /* avoid warning */
891b38e4
FB
688 sp_mask = 0; /* avoid warning */
689 ssp = NULL; /* avoid warning */
690 esp = 0; /* avoid warning */
2c0262af
FB
691 }
692
693 shift = type >> 3;
891b38e4
FB
694
695#if 0
696 /* XXX: check that enough room is available */
2c0262af
FB
697 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
698 if (env->eflags & VM_MASK)
699 push_size += 8;
700 push_size <<= shift;
891b38e4 701#endif
2c0262af
FB
702 if (is_int)
703 old_eip = next_eip;
704 else
705 old_eip = env->eip;
2c0262af 706 if (shift == 1) {
2c0262af 707 if (new_stack) {
8e682019
FB
708 if (env->eflags & VM_MASK) {
709 PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
710 PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
711 PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
712 PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
713 }
891b38e4
FB
714 PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
715 PUSHL(ssp, esp, sp_mask, ESP);
2c0262af 716 }
891b38e4
FB
717 PUSHL(ssp, esp, sp_mask, compute_eflags());
718 PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
719 PUSHL(ssp, esp, sp_mask, old_eip);
2c0262af 720 if (has_error_code) {
891b38e4 721 PUSHL(ssp, esp, sp_mask, error_code);
2c0262af
FB
722 }
723 } else {
724 if (new_stack) {
8e682019
FB
725 if (env->eflags & VM_MASK) {
726 PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
727 PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
728 PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
729 PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
730 }
891b38e4
FB
731 PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
732 PUSHW(ssp, esp, sp_mask, ESP);
2c0262af 733 }
891b38e4
FB
734 PUSHW(ssp, esp, sp_mask, compute_eflags());
735 PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
736 PUSHW(ssp, esp, sp_mask, old_eip);
2c0262af 737 if (has_error_code) {
891b38e4 738 PUSHW(ssp, esp, sp_mask, error_code);
2c0262af
FB
739 }
740 }
741
891b38e4 742 if (new_stack) {
8e682019
FB
743 if (env->eflags & VM_MASK) {
744 /* XXX: explain me why W2K hangs if the whole segment cache is
745 reset ? */
746 env->segs[R_ES].selector = 0;
747 env->segs[R_ES].flags = 0;
748 env->segs[R_DS].selector = 0;
749 env->segs[R_DS].flags = 0;
750 env->segs[R_FS].selector = 0;
751 env->segs[R_FS].flags = 0;
752 env->segs[R_GS].selector = 0;
753 env->segs[R_GS].flags = 0;
754 }
891b38e4
FB
755 ss = (ss & ~3) | dpl;
756 cpu_x86_load_seg_cache(env, R_SS, ss,
757 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
758 }
759 ESP = (ESP & ~sp_mask) | (esp & sp_mask);
760
761 selector = (selector & ~3) | dpl;
762 cpu_x86_load_seg_cache(env, R_CS, selector,
763 get_seg_base(e1, e2),
764 get_seg_limit(e1, e2),
765 e2);
766 cpu_x86_set_cpl(env, dpl);
767 env->eip = offset;
768
2c0262af
FB
769 /* interrupt gate clear IF mask */
770 if ((type & 1) == 0) {
771 env->eflags &= ~IF_MASK;
772 }
773 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
774}
775
776/* real mode interrupt */
777static void do_interrupt_real(int intno, int is_int, int error_code,
4136f33c 778 unsigned int next_eip)
2c0262af
FB
779{
780 SegmentCache *dt;
781 uint8_t *ptr, *ssp;
782 int selector;
783 uint32_t offset, esp;
784 uint32_t old_cs, old_eip;
785
786 /* real mode (simpler !) */
787 dt = &env->idt;
788 if (intno * 4 + 3 > dt->limit)
789 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
790 ptr = dt->base + intno * 4;
61382a50
FB
791 offset = lduw_kernel(ptr);
792 selector = lduw_kernel(ptr + 2);
2c0262af
FB
793 esp = ESP;
794 ssp = env->segs[R_SS].base;
795 if (is_int)
796 old_eip = next_eip;
797 else
798 old_eip = env->eip;
799 old_cs = env->segs[R_CS].selector;
891b38e4
FB
800 /* XXX: use SS segment size ? */
801 PUSHW(ssp, esp, 0xffff, compute_eflags());
802 PUSHW(ssp, esp, 0xffff, old_cs);
803 PUSHW(ssp, esp, 0xffff, old_eip);
2c0262af
FB
804
805 /* update processor state */
806 ESP = (ESP & ~0xffff) | (esp & 0xffff);
807 env->eip = offset;
808 env->segs[R_CS].selector = selector;
809 env->segs[R_CS].base = (uint8_t *)(selector << 4);
810 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
811}
812
813/* fake user mode interrupt */
814void do_interrupt_user(int intno, int is_int, int error_code,
815 unsigned int next_eip)
816{
817 SegmentCache *dt;
818 uint8_t *ptr;
819 int dpl, cpl;
820 uint32_t e2;
821
822 dt = &env->idt;
823 ptr = dt->base + (intno * 8);
61382a50 824 e2 = ldl_kernel(ptr + 4);
2c0262af
FB
825
826 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
827 cpl = env->hflags & HF_CPL_MASK;
828 /* check privledge if software int */
829 if (is_int && dpl < cpl)
830 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
831
832 /* Since we emulate only user space, we cannot do more than
833 exiting the emulation with the suitable exception and error
834 code */
835 if (is_int)
836 EIP = next_eip;
837}
838
839/*
840 * Begin excution of an interruption. is_int is TRUE if coming from
841 * the int instruction. next_eip is the EIP value AFTER the interrupt
842 * instruction. It is only relevant if is_int is TRUE.
843 */
844void do_interrupt(int intno, int is_int, int error_code,
845 unsigned int next_eip, int is_hw)
846{
8e682019
FB
847#if 0
848 {
849 extern FILE *stdout;
850 static int count;
851 if (env->cr[0] & CR0_PE_MASK) {
852 fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
853 count, intno, error_code, is_int);
854 count++;
855 }
856 }
857 if ((env->cr[0] & CR0_PE_MASK) && intno == 0x10) {
858 tb_flush(env);
859 cpu_set_log(CPU_LOG_ALL);
860 }
861#endif
4136f33c
FB
862#ifdef DEBUG_PCALL
863 if (loglevel) {
864 static int count;
865 fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
866 count, intno, error_code, is_int);
867 cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
8e682019 868#if 1
4136f33c
FB
869 {
870 int i;
871 uint8_t *ptr;
8e682019 872 fprintf(logfile, " code=");
4136f33c
FB
873 ptr = env->segs[R_CS].base + env->eip;
874 for(i = 0; i < 16; i++) {
8e682019 875 fprintf(logfile, " %02x", ldub(ptr + i));
4136f33c 876 }
8e682019 877 fprintf(logfile, "\n");
4136f33c
FB
878 }
879#endif
880 count++;
881 }
882#endif
2c0262af
FB
883 if (env->cr[0] & CR0_PE_MASK) {
884 do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
885 } else {
886 do_interrupt_real(intno, is_int, error_code, next_eip);
887 }
888}
889
890/*
891 * Signal an interruption. It is executed in the main CPU loop.
892 * is_int is TRUE if coming from the int instruction. next_eip is the
893 * EIP value AFTER the interrupt instruction. It is only relevant if
894 * is_int is TRUE.
895 */
896void raise_interrupt(int intno, int is_int, int error_code,
897 unsigned int next_eip)
898{
899 env->exception_index = intno;
900 env->error_code = error_code;
901 env->exception_is_int = is_int;
902 env->exception_next_eip = next_eip;
903 cpu_loop_exit();
904}
905
906/* shortcuts to generate exceptions */
907void raise_exception_err(int exception_index, int error_code)
908{
909 raise_interrupt(exception_index, 0, error_code, 0);
910}
911
912void raise_exception(int exception_index)
913{
914 raise_interrupt(exception_index, 0, 0, 0);
915}
916
917#ifdef BUGGY_GCC_DIV64
918/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
919 call it from another function */
920uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
921{
922 *q_ptr = num / den;
923 return num % den;
924}
925
926int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
927{
928 *q_ptr = num / den;
929 return num % den;
930}
931#endif
932
933void helper_divl_EAX_T0(uint32_t eip)
934{
935 unsigned int den, q, r;
936 uint64_t num;
937
938 num = EAX | ((uint64_t)EDX << 32);
939 den = T0;
940 if (den == 0) {
941 EIP = eip;
942 raise_exception(EXCP00_DIVZ);
943 }
944#ifdef BUGGY_GCC_DIV64
945 r = div64(&q, num, den);
946#else
947 q = (num / den);
948 r = (num % den);
949#endif
950 EAX = q;
951 EDX = r;
952}
953
954void helper_idivl_EAX_T0(uint32_t eip)
955{
956 int den, q, r;
957 int64_t num;
958
959 num = EAX | ((uint64_t)EDX << 32);
960 den = T0;
961 if (den == 0) {
962 EIP = eip;
963 raise_exception(EXCP00_DIVZ);
964 }
965#ifdef BUGGY_GCC_DIV64
966 r = idiv64(&q, num, den);
967#else
968 q = (num / den);
969 r = (num % den);
970#endif
971 EAX = q;
972 EDX = r;
973}
974
975void helper_cmpxchg8b(void)
976{
977 uint64_t d;
978 int eflags;
979
980 eflags = cc_table[CC_OP].compute_all();
981 d = ldq((uint8_t *)A0);
982 if (d == (((uint64_t)EDX << 32) | EAX)) {
983 stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
984 eflags |= CC_Z;
985 } else {
986 EDX = d >> 32;
987 EAX = d;
988 eflags &= ~CC_Z;
989 }
990 CC_SRC = eflags;
991}
992
2c0262af
FB
993#define CPUID_FP87 (1 << 0)
994#define CPUID_VME (1 << 1)
995#define CPUID_DE (1 << 2)
996#define CPUID_PSE (1 << 3)
997#define CPUID_TSC (1 << 4)
998#define CPUID_MSR (1 << 5)
999#define CPUID_PAE (1 << 6)
1000#define CPUID_MCE (1 << 7)
1001#define CPUID_CX8 (1 << 8)
1002#define CPUID_APIC (1 << 9)
1003#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
1004#define CPUID_MTRR (1 << 12)
1005#define CPUID_PGE (1 << 13)
1006#define CPUID_MCA (1 << 14)
1007#define CPUID_CMOV (1 << 15)
1008/* ... */
1009#define CPUID_MMX (1 << 23)
1010#define CPUID_FXSR (1 << 24)
1011#define CPUID_SSE (1 << 25)
1012#define CPUID_SSE2 (1 << 26)
1013
1014void helper_cpuid(void)
1015{
8e682019
FB
1016 switch(EAX) {
1017 case 0:
1018 EAX = 2; /* max EAX index supported */
2c0262af
FB
1019 EBX = 0x756e6547;
1020 ECX = 0x6c65746e;
1021 EDX = 0x49656e69;
8e682019
FB
1022 break;
1023 case 1:
1024 {
1025 int family, model, stepping;
1026 /* EAX = 1 info */
2c0262af 1027#if 0
8e682019
FB
1028 /* pentium 75-200 */
1029 family = 5;
1030 model = 2;
1031 stepping = 11;
2c0262af 1032#else
8e682019
FB
1033 /* pentium pro */
1034 family = 6;
1035 model = 1;
1036 stepping = 3;
2c0262af 1037#endif
8e682019
FB
1038 EAX = (family << 8) | (model << 4) | stepping;
1039 EBX = 0;
1040 ECX = 0;
1041 EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
1042 CPUID_TSC | CPUID_MSR | CPUID_MCE |
1043 CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
1044 }
1045 break;
1046 default:
1047 /* cache info: needed for Pentium Pro compatibility */
1048 EAX = 0x410601;
2c0262af
FB
1049 EBX = 0;
1050 ECX = 0;
8e682019
FB
1051 EDX = 0;
1052 break;
2c0262af
FB
1053 }
1054}
1055
1056void helper_lldt_T0(void)
1057{
1058 int selector;
1059 SegmentCache *dt;
1060 uint32_t e1, e2;
1061 int index;
1062 uint8_t *ptr;
1063
1064 selector = T0 & 0xffff;
1065 if ((selector & 0xfffc) == 0) {
1066 /* XXX: NULL selector case: invalid LDT */
1067 env->ldt.base = NULL;
1068 env->ldt.limit = 0;
1069 } else {
1070 if (selector & 0x4)
1071 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1072 dt = &env->gdt;
1073 index = selector & ~7;
1074 if ((index + 7) > dt->limit)
1075 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1076 ptr = dt->base + index;
61382a50
FB
1077 e1 = ldl_kernel(ptr);
1078 e2 = ldl_kernel(ptr + 4);
2c0262af
FB
1079 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1080 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1081 if (!(e2 & DESC_P_MASK))
1082 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1083 load_seg_cache_raw_dt(&env->ldt, e1, e2);
1084 }
1085 env->ldt.selector = selector;
1086}
1087
1088void helper_ltr_T0(void)
1089{
1090 int selector;
1091 SegmentCache *dt;
1092 uint32_t e1, e2;
1093 int index, type;
1094 uint8_t *ptr;
1095
1096 selector = T0 & 0xffff;
1097 if ((selector & 0xfffc) == 0) {
1098 /* NULL selector case: invalid LDT */
1099 env->tr.base = NULL;
1100 env->tr.limit = 0;
1101 env->tr.flags = 0;
1102 } else {
1103 if (selector & 0x4)
1104 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1105 dt = &env->gdt;
1106 index = selector & ~7;
1107 if ((index + 7) > dt->limit)
1108 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1109 ptr = dt->base + index;
61382a50
FB
1110 e1 = ldl_kernel(ptr);
1111 e2 = ldl_kernel(ptr + 4);
2c0262af
FB
1112 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1113 if ((e2 & DESC_S_MASK) ||
7e84c249 1114 (type != 1 && type != 9))
2c0262af
FB
1115 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1116 if (!(e2 & DESC_P_MASK))
1117 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1118 load_seg_cache_raw_dt(&env->tr, e1, e2);
8e682019 1119 e2 |= DESC_TSS_BUSY_MASK;
61382a50 1120 stl_kernel(ptr + 4, e2);
2c0262af
FB
1121 }
1122 env->tr.selector = selector;
1123}
1124
3ab493de 1125/* only works if protected mode and not VM86. seg_reg must be != R_CS */
8e682019 1126void load_seg(int seg_reg, int selector)
2c0262af
FB
1127{
1128 uint32_t e1, e2;
3ab493de
FB
1129 int cpl, dpl, rpl;
1130 SegmentCache *dt;
1131 int index;
1132 uint8_t *ptr;
1133
8e682019 1134 selector &= 0xffff;
2c0262af
FB
1135 if ((selector & 0xfffc) == 0) {
1136 /* null selector case */
8e682019 1137 if (seg_reg == R_SS)
2c0262af 1138 raise_exception_err(EXCP0D_GPF, 0);
8e682019 1139 cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
2c0262af 1140 } else {
3ab493de
FB
1141
1142 if (selector & 0x4)
1143 dt = &env->ldt;
1144 else
1145 dt = &env->gdt;
1146 index = selector & ~7;
8e682019 1147 if ((index + 7) > dt->limit)
2c0262af 1148 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
3ab493de
FB
1149 ptr = dt->base + index;
1150 e1 = ldl_kernel(ptr);
1151 e2 = ldl_kernel(ptr + 4);
1152
8e682019 1153 if (!(e2 & DESC_S_MASK))
2c0262af 1154 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
3ab493de
FB
1155 rpl = selector & 3;
1156 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1157 cpl = env->hflags & HF_CPL_MASK;
2c0262af 1158 if (seg_reg == R_SS) {
3ab493de 1159 /* must be writable segment */
8e682019 1160 if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
2c0262af 1161 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
8e682019 1162 if (rpl != cpl || dpl != cpl)
3ab493de 1163 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2c0262af 1164 } else {
3ab493de 1165 /* must be readable segment */
8e682019 1166 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
2c0262af 1167 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
3ab493de
FB
1168
1169 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1170 /* if not conforming code, test rights */
8e682019 1171 if (dpl < cpl || dpl < rpl)
3ab493de 1172 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
3ab493de 1173 }
2c0262af
FB
1174 }
1175
1176 if (!(e2 & DESC_P_MASK)) {
2c0262af
FB
1177 if (seg_reg == R_SS)
1178 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1179 else
1180 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1181 }
3ab493de
FB
1182
1183 /* set the access bit if not already set */
1184 if (!(e2 & DESC_A_MASK)) {
1185 e2 |= DESC_A_MASK;
1186 stl_kernel(ptr + 4, e2);
1187 }
1188
2c0262af
FB
1189 cpu_x86_load_seg_cache(env, seg_reg, selector,
1190 get_seg_base(e1, e2),
1191 get_seg_limit(e1, e2),
1192 e2);
1193#if 0
1194 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
1195 selector, (unsigned long)sc->base, sc->limit, sc->flags);
1196#endif
1197 }
1198}
1199
1200/* protected mode jump */
1201void helper_ljmp_protected_T0_T1(void)
1202{
7e84c249 1203 int new_cs, new_eip, gate_cs, type;
2c0262af
FB
1204 uint32_t e1, e2, cpl, dpl, rpl, limit;
1205
1206 new_cs = T0;
1207 new_eip = T1;
1208 if ((new_cs & 0xfffc) == 0)
1209 raise_exception_err(EXCP0D_GPF, 0);
1210 if (load_segment(&e1, &e2, new_cs) != 0)
1211 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1212 cpl = env->hflags & HF_CPL_MASK;
1213 if (e2 & DESC_S_MASK) {
1214 if (!(e2 & DESC_CS_MASK))
1215 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1216 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
7e84c249 1217 if (e2 & DESC_C_MASK) {
2c0262af
FB
1218 /* conforming code segment */
1219 if (dpl > cpl)
1220 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1221 } else {
1222 /* non conforming code segment */
1223 rpl = new_cs & 3;
1224 if (rpl > cpl)
1225 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1226 if (dpl != cpl)
1227 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1228 }
1229 if (!(e2 & DESC_P_MASK))
1230 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1231 limit = get_seg_limit(e1, e2);
1232 if (new_eip > limit)
1233 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1234 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1235 get_seg_base(e1, e2), limit, e2);
1236 EIP = new_eip;
1237 } else {
7e84c249
FB
1238 /* jump to call or task gate */
1239 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1240 rpl = new_cs & 3;
1241 cpl = env->hflags & HF_CPL_MASK;
1242 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1243 switch(type) {
1244 case 1: /* 286 TSS */
1245 case 9: /* 386 TSS */
1246 case 5: /* task gate */
1247 if (dpl < cpl || dpl < rpl)
1248 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1249 switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP);
1250 break;
1251 case 4: /* 286 call gate */
1252 case 12: /* 386 call gate */
1253 if ((dpl < cpl) || (dpl < rpl))
1254 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1255 if (!(e2 & DESC_P_MASK))
1256 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1257 gate_cs = e1 >> 16;
1258 if (load_segment(&e1, &e2, gate_cs) != 0)
1259 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1260 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1261 /* must be code segment */
1262 if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
1263 (DESC_S_MASK | DESC_CS_MASK)))
1264 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1265 if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1266 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1267 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1268 if (!(e2 & DESC_P_MASK))
1269 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1270 new_eip = (e1 & 0xffff);
1271 if (type == 12)
1272 new_eip |= (e2 & 0xffff0000);
1273 limit = get_seg_limit(e1, e2);
1274 if (new_eip > limit)
1275 raise_exception_err(EXCP0D_GPF, 0);
1276 cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1277 get_seg_base(e1, e2), limit, e2);
1278 EIP = new_eip;
1279 break;
1280 default:
1281 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1282 break;
1283 }
2c0262af
FB
1284 }
1285}
1286
1287/* real mode call */
1288void helper_lcall_real_T0_T1(int shift, int next_eip)
1289{
1290 int new_cs, new_eip;
1291 uint32_t esp, esp_mask;
1292 uint8_t *ssp;
1293
1294 new_cs = T0;
1295 new_eip = T1;
1296 esp = ESP;
891b38e4 1297 esp_mask = get_sp_mask(env->segs[R_SS].flags);
2c0262af
FB
1298 ssp = env->segs[R_SS].base;
1299 if (shift) {
891b38e4
FB
1300 PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1301 PUSHL(ssp, esp, esp_mask, next_eip);
2c0262af 1302 } else {
891b38e4
FB
1303 PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1304 PUSHW(ssp, esp, esp_mask, next_eip);
2c0262af
FB
1305 }
1306
891b38e4 1307 ESP = (ESP & ~esp_mask) | (esp & esp_mask);
2c0262af
FB
1308 env->eip = new_eip;
1309 env->segs[R_CS].selector = new_cs;
1310 env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
1311}
1312
1313/* protected mode call */
1314void helper_lcall_protected_T0_T1(int shift, int next_eip)
1315{
891b38e4 1316 int new_cs, new_eip, new_stack, i;
2c0262af 1317 uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
891b38e4
FB
1318 uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1319 uint32_t val, limit, old_sp_mask;
2c0262af
FB
1320 uint8_t *ssp, *old_ssp;
1321
1322 new_cs = T0;
1323 new_eip = T1;
f3f2d9be
FB
1324#ifdef DEBUG_PCALL
1325 if (loglevel) {
1326 fprintf(logfile, "lcall %04x:%08x\n",
1327 new_cs, new_eip);
4136f33c 1328 cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
f3f2d9be
FB
1329 }
1330#endif
2c0262af
FB
1331 if ((new_cs & 0xfffc) == 0)
1332 raise_exception_err(EXCP0D_GPF, 0);
1333 if (load_segment(&e1, &e2, new_cs) != 0)
1334 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1335 cpl = env->hflags & HF_CPL_MASK;
f3f2d9be
FB
1336#ifdef DEBUG_PCALL
1337 if (loglevel) {
1338 fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1339 }
1340#endif
2c0262af
FB
1341 if (e2 & DESC_S_MASK) {
1342 if (!(e2 & DESC_CS_MASK))
1343 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1344 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
7e84c249 1345 if (e2 & DESC_C_MASK) {
2c0262af
FB
1346 /* conforming code segment */
1347 if (dpl > cpl)
1348 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1349 } else {
1350 /* non conforming code segment */
1351 rpl = new_cs & 3;
1352 if (rpl > cpl)
1353 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1354 if (dpl != cpl)
1355 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1356 }
1357 if (!(e2 & DESC_P_MASK))
1358 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1359
1360 sp = ESP;
891b38e4
FB
1361 sp_mask = get_sp_mask(env->segs[R_SS].flags);
1362 ssp = env->segs[R_SS].base;
2c0262af 1363 if (shift) {
891b38e4
FB
1364 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1365 PUSHL(ssp, sp, sp_mask, next_eip);
2c0262af 1366 } else {
891b38e4
FB
1367 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1368 PUSHW(ssp, sp, sp_mask, next_eip);
2c0262af 1369 }
2c0262af
FB
1370
1371 limit = get_seg_limit(e1, e2);
1372 if (new_eip > limit)
1373 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1374 /* from this point, not restartable */
891b38e4 1375 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2c0262af
FB
1376 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1377 get_seg_base(e1, e2), limit, e2);
1378 EIP = new_eip;
1379 } else {
1380 /* check gate type */
1381 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
7e84c249
FB
1382 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1383 rpl = new_cs & 3;
2c0262af
FB
1384 switch(type) {
1385 case 1: /* available 286 TSS */
1386 case 9: /* available 386 TSS */
1387 case 5: /* task gate */
7e84c249
FB
1388 if (dpl < cpl || dpl < rpl)
1389 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1390 switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL);
2c0262af
FB
1391 break;
1392 case 4: /* 286 call gate */
1393 case 12: /* 386 call gate */
1394 break;
1395 default:
1396 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1397 break;
1398 }
1399 shift = type >> 3;
1400
2c0262af
FB
1401 if (dpl < cpl || dpl < rpl)
1402 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1403 /* check valid bit */
1404 if (!(e2 & DESC_P_MASK))
1405 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1406 selector = e1 >> 16;
1407 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
f3f2d9be 1408 param_count = e2 & 0x1f;
2c0262af
FB
1409 if ((selector & 0xfffc) == 0)
1410 raise_exception_err(EXCP0D_GPF, 0);
1411
1412 if (load_segment(&e1, &e2, selector) != 0)
1413 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1414 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1415 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1416 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1417 if (dpl > cpl)
1418 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1419 if (!(e2 & DESC_P_MASK))
1420 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1421
1422 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1423 /* to inner priviledge */
1424 get_ss_esp_from_tss(&ss, &sp, dpl);
f3f2d9be
FB
1425#ifdef DEBUG_PCALL
1426 if (loglevel)
1427 fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n",
1428 ss, sp, param_count, ESP);
1429#endif
2c0262af
FB
1430 if ((ss & 0xfffc) == 0)
1431 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1432 if ((ss & 3) != dpl)
1433 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1434 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1435 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1436 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1437 if (ss_dpl != dpl)
1438 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1439 if (!(ss_e2 & DESC_S_MASK) ||
1440 (ss_e2 & DESC_CS_MASK) ||
1441 !(ss_e2 & DESC_W_MASK))
1442 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1443 if (!(ss_e2 & DESC_P_MASK))
1444 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1445
891b38e4 1446 // push_size = ((param_count * 2) + 8) << shift;
2c0262af 1447
891b38e4
FB
1448 old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1449 old_ssp = env->segs[R_SS].base;
2c0262af 1450
891b38e4
FB
1451 sp_mask = get_sp_mask(ss_e2);
1452 ssp = get_seg_base(ss_e1, ss_e2);
2c0262af 1453 if (shift) {
891b38e4
FB
1454 PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1455 PUSHL(ssp, sp, sp_mask, ESP);
1456 for(i = param_count - 1; i >= 0; i--) {
1457 val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1458 PUSHL(ssp, sp, sp_mask, val);
2c0262af
FB
1459 }
1460 } else {
891b38e4
FB
1461 PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1462 PUSHW(ssp, sp, sp_mask, ESP);
1463 for(i = param_count - 1; i >= 0; i--) {
1464 val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1465 PUSHW(ssp, sp, sp_mask, val);
2c0262af
FB
1466 }
1467 }
891b38e4 1468 new_stack = 1;
2c0262af
FB
1469 } else {
1470 /* to same priviledge */
891b38e4
FB
1471 sp = ESP;
1472 sp_mask = get_sp_mask(env->segs[R_SS].flags);
1473 ssp = env->segs[R_SS].base;
1474 // push_size = (4 << shift);
1475 new_stack = 0;
2c0262af
FB
1476 }
1477
1478 if (shift) {
891b38e4
FB
1479 PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1480 PUSHL(ssp, sp, sp_mask, next_eip);
2c0262af 1481 } else {
891b38e4
FB
1482 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1483 PUSHW(ssp, sp, sp_mask, next_eip);
1484 }
1485
1486 /* from this point, not restartable */
1487
1488 if (new_stack) {
1489 ss = (ss & ~3) | dpl;
1490 cpu_x86_load_seg_cache(env, R_SS, ss,
1491 ssp,
1492 get_seg_limit(ss_e1, ss_e2),
1493 ss_e2);
2c0262af
FB
1494 }
1495
2c0262af
FB
1496 selector = (selector & ~3) | dpl;
1497 cpu_x86_load_seg_cache(env, R_CS, selector,
1498 get_seg_base(e1, e2),
1499 get_seg_limit(e1, e2),
1500 e2);
1501 cpu_x86_set_cpl(env, dpl);
891b38e4 1502 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2c0262af
FB
1503 EIP = offset;
1504 }
1505}
1506
7e84c249 1507/* real and vm86 mode iret */
2c0262af
FB
1508void helper_iret_real(int shift)
1509{
891b38e4 1510 uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2c0262af
FB
1511 uint8_t *ssp;
1512 int eflags_mask;
7e84c249 1513
891b38e4
FB
1514 sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1515 sp = ESP;
1516 ssp = env->segs[R_SS].base;
2c0262af
FB
1517 if (shift == 1) {
1518 /* 32 bits */
891b38e4
FB
1519 POPL(ssp, sp, sp_mask, new_eip);
1520 POPL(ssp, sp, sp_mask, new_cs);
1521 new_cs &= 0xffff;
1522 POPL(ssp, sp, sp_mask, new_eflags);
2c0262af
FB
1523 } else {
1524 /* 16 bits */
891b38e4
FB
1525 POPW(ssp, sp, sp_mask, new_eip);
1526 POPW(ssp, sp, sp_mask, new_cs);
1527 POPW(ssp, sp, sp_mask, new_eflags);
2c0262af 1528 }
4136f33c 1529 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2c0262af
FB
1530 load_seg_vm(R_CS, new_cs);
1531 env->eip = new_eip;
7e84c249 1532 if (env->eflags & VM_MASK)
4136f33c 1533 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK;
7e84c249 1534 else
4136f33c 1535 eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK;
2c0262af
FB
1536 if (shift == 0)
1537 eflags_mask &= 0xffff;
1538 load_eflags(new_eflags, eflags_mask);
1539}
1540
8e682019
FB
1541static inline void validate_seg(int seg_reg, int cpl)
1542{
1543 int dpl;
1544 uint32_t e2;
1545
1546 e2 = env->segs[seg_reg].flags;
1547 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1548 if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1549 /* data or non conforming code segment */
1550 if (dpl < cpl) {
1551 cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
1552 }
1553 }
1554}
1555
2c0262af
FB
1556/* protected mode iret */
1557static inline void helper_ret_protected(int shift, int is_iret, int addend)
1558{
891b38e4 1559 uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
2c0262af
FB
1560 uint32_t new_es, new_ds, new_fs, new_gs;
1561 uint32_t e1, e2, ss_e1, ss_e2;
4136f33c 1562 int cpl, dpl, rpl, eflags_mask, iopl;
2c0262af
FB
1563 uint8_t *ssp;
1564
891b38e4 1565 sp_mask = get_sp_mask(env->segs[R_SS].flags);
2c0262af 1566 sp = ESP;
891b38e4 1567 ssp = env->segs[R_SS].base;
2c0262af
FB
1568 if (shift == 1) {
1569 /* 32 bits */
891b38e4
FB
1570 POPL(ssp, sp, sp_mask, new_eip);
1571 POPL(ssp, sp, sp_mask, new_cs);
1572 new_cs &= 0xffff;
1573 if (is_iret) {
1574 POPL(ssp, sp, sp_mask, new_eflags);
1575 if (new_eflags & VM_MASK)
1576 goto return_to_vm86;
1577 }
2c0262af
FB
1578 } else {
1579 /* 16 bits */
891b38e4
FB
1580 POPW(ssp, sp, sp_mask, new_eip);
1581 POPW(ssp, sp, sp_mask, new_cs);
2c0262af 1582 if (is_iret)
891b38e4 1583 POPW(ssp, sp, sp_mask, new_eflags);
2c0262af 1584 }
891b38e4
FB
1585#ifdef DEBUG_PCALL
1586 if (loglevel) {
4136f33c
FB
1587 fprintf(logfile, "lret new %04x:%08x addend=0x%x\n",
1588 new_cs, new_eip, addend);
1589 cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
891b38e4
FB
1590 }
1591#endif
2c0262af
FB
1592 if ((new_cs & 0xfffc) == 0)
1593 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1594 if (load_segment(&e1, &e2, new_cs) != 0)
1595 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1596 if (!(e2 & DESC_S_MASK) ||
1597 !(e2 & DESC_CS_MASK))
1598 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1599 cpl = env->hflags & HF_CPL_MASK;
1600 rpl = new_cs & 3;
1601 if (rpl < cpl)
1602 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1603 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
7e84c249 1604 if (e2 & DESC_C_MASK) {
2c0262af
FB
1605 if (dpl > rpl)
1606 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1607 } else {
1608 if (dpl != rpl)
1609 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1610 }
1611 if (!(e2 & DESC_P_MASK))
1612 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1613
891b38e4 1614 sp += addend;
2c0262af
FB
1615 if (rpl == cpl) {
1616 /* return to same priledge level */
1617 cpu_x86_load_seg_cache(env, R_CS, new_cs,
1618 get_seg_base(e1, e2),
1619 get_seg_limit(e1, e2),
1620 e2);
2c0262af
FB
1621 } else {
1622 /* return to different priviledge level */
2c0262af
FB
1623 if (shift == 1) {
1624 /* 32 bits */
891b38e4
FB
1625 POPL(ssp, sp, sp_mask, new_esp);
1626 POPL(ssp, sp, sp_mask, new_ss);
1627 new_ss &= 0xffff;
2c0262af
FB
1628 } else {
1629 /* 16 bits */
891b38e4
FB
1630 POPW(ssp, sp, sp_mask, new_esp);
1631 POPW(ssp, sp, sp_mask, new_ss);
2c0262af
FB
1632 }
1633
1634 if ((new_ss & 3) != rpl)
1635 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1636 if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
1637 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1638 if (!(ss_e2 & DESC_S_MASK) ||
1639 (ss_e2 & DESC_CS_MASK) ||
1640 !(ss_e2 & DESC_W_MASK))
1641 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1642 dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1643 if (dpl != rpl)
1644 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1645 if (!(ss_e2 & DESC_P_MASK))
1646 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
1647
1648 cpu_x86_load_seg_cache(env, R_CS, new_cs,
1649 get_seg_base(e1, e2),
1650 get_seg_limit(e1, e2),
1651 e2);
1652 cpu_x86_load_seg_cache(env, R_SS, new_ss,
1653 get_seg_base(ss_e1, ss_e2),
1654 get_seg_limit(ss_e1, ss_e2),
1655 ss_e2);
1656 cpu_x86_set_cpl(env, rpl);
891b38e4
FB
1657 sp = new_esp;
1658 /* XXX: change sp_mask according to old segment ? */
8e682019
FB
1659
1660 /* validate data segments */
1661 validate_seg(R_ES, cpl);
1662 validate_seg(R_DS, cpl);
1663 validate_seg(R_FS, cpl);
1664 validate_seg(R_GS, cpl);
2c0262af 1665 }
891b38e4 1666 ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2c0262af
FB
1667 env->eip = new_eip;
1668 if (is_iret) {
4136f33c
FB
1669 /* NOTE: 'cpl' is the _old_ CPL */
1670 eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK;
2c0262af 1671 if (cpl == 0)
4136f33c
FB
1672 eflags_mask |= IOPL_MASK;
1673 iopl = (env->eflags >> IOPL_SHIFT) & 3;
1674 if (cpl <= iopl)
1675 eflags_mask |= IF_MASK;
2c0262af
FB
1676 if (shift == 0)
1677 eflags_mask &= 0xffff;
1678 load_eflags(new_eflags, eflags_mask);
1679 }
1680 return;
1681
1682 return_to_vm86:
891b38e4
FB
1683 POPL(ssp, sp, sp_mask, new_esp);
1684 POPL(ssp, sp, sp_mask, new_ss);
1685 POPL(ssp, sp, sp_mask, new_es);
1686 POPL(ssp, sp, sp_mask, new_ds);
1687 POPL(ssp, sp, sp_mask, new_fs);
1688 POPL(ssp, sp, sp_mask, new_gs);
2c0262af
FB
1689
1690 /* modify processor state */
4136f33c
FB
1691 load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
1692 IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK);
891b38e4 1693 load_seg_vm(R_CS, new_cs & 0xffff);
2c0262af 1694 cpu_x86_set_cpl(env, 3);
891b38e4
FB
1695 load_seg_vm(R_SS, new_ss & 0xffff);
1696 load_seg_vm(R_ES, new_es & 0xffff);
1697 load_seg_vm(R_DS, new_ds & 0xffff);
1698 load_seg_vm(R_FS, new_fs & 0xffff);
1699 load_seg_vm(R_GS, new_gs & 0xffff);
2c0262af
FB
1700
1701 env->eip = new_eip;
1702 ESP = new_esp;
1703}
1704
1705void helper_iret_protected(int shift)
1706{
7e84c249
FB
1707 int tss_selector, type;
1708 uint32_t e1, e2;
1709
1710 /* specific case for TSS */
1711 if (env->eflags & NT_MASK) {
1712 tss_selector = lduw_kernel(env->tr.base + 0);
1713 if (tss_selector & 4)
1714 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1715 if (load_segment(&e1, &e2, tss_selector) != 0)
1716 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1717 type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
1718 /* NOTE: we check both segment and busy TSS */
1719 if (type != 3)
1720 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1721 switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET);
1722 } else {
1723 helper_ret_protected(shift, 1, 0);
1724 }
2c0262af
FB
1725}
1726
1727void helper_lret_protected(int shift, int addend)
1728{
1729 helper_ret_protected(shift, 0, addend);
1730}
1731
1732void helper_movl_crN_T0(int reg)
1733{
1734 env->cr[reg] = T0;
1735 switch(reg) {
1736 case 0:
1737 cpu_x86_update_cr0(env);
1738 break;
1739 case 3:
1740 cpu_x86_update_cr3(env);
1741 break;
1742 }
1743}
1744
1745/* XXX: do more */
1746void helper_movl_drN_T0(int reg)
1747{
1748 env->dr[reg] = T0;
1749}
1750
1751void helper_invlpg(unsigned int addr)
1752{
1753 cpu_x86_flush_tlb(env, addr);
1754}
1755
1756/* rdtsc */
1757#ifndef __i386__
1758uint64_t emu_time;
1759#endif
1760
1761void helper_rdtsc(void)
1762{
1763 uint64_t val;
1764#ifdef __i386__
1765 asm("rdtsc" : "=A" (val));
1766#else
1767 /* better than nothing: the time increases */
1768 val = emu_time++;
1769#endif
1770 EAX = val;
1771 EDX = val >> 32;
1772}
1773
1774void helper_wrmsr(void)
1775{
1776 switch(ECX) {
1777 case MSR_IA32_SYSENTER_CS:
1778 env->sysenter_cs = EAX & 0xffff;
1779 break;
1780 case MSR_IA32_SYSENTER_ESP:
1781 env->sysenter_esp = EAX;
1782 break;
1783 case MSR_IA32_SYSENTER_EIP:
1784 env->sysenter_eip = EAX;
1785 break;
1786 default:
1787 /* XXX: exception ? */
1788 break;
1789 }
1790}
1791
1792void helper_rdmsr(void)
1793{
1794 switch(ECX) {
1795 case MSR_IA32_SYSENTER_CS:
1796 EAX = env->sysenter_cs;
1797 EDX = 0;
1798 break;
1799 case MSR_IA32_SYSENTER_ESP:
1800 EAX = env->sysenter_esp;
1801 EDX = 0;
1802 break;
1803 case MSR_IA32_SYSENTER_EIP:
1804 EAX = env->sysenter_eip;
1805 EDX = 0;
1806 break;
1807 default:
1808 /* XXX: exception ? */
1809 break;
1810 }
1811}
1812
1813void helper_lsl(void)
1814{
1815 unsigned int selector, limit;
1816 uint32_t e1, e2;
3ab493de 1817 int rpl, dpl, cpl, type;
2c0262af
FB
1818
1819 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1820 selector = T0 & 0xffff;
1821 if (load_segment(&e1, &e2, selector) != 0)
1822 return;
3ab493de
FB
1823 rpl = selector & 3;
1824 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1825 cpl = env->hflags & HF_CPL_MASK;
1826 if (e2 & DESC_S_MASK) {
1827 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1828 /* conforming */
1829 } else {
1830 if (dpl < cpl || dpl < rpl)
1831 return;
1832 }
1833 } else {
1834 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1835 switch(type) {
1836 case 1:
1837 case 2:
1838 case 3:
1839 case 9:
1840 case 11:
1841 break;
1842 default:
1843 return;
1844 }
1845 if (dpl < cpl || dpl < rpl)
1846 return;
1847 }
1848 limit = get_seg_limit(e1, e2);
2c0262af
FB
1849 T1 = limit;
1850 CC_SRC |= CC_Z;
1851}
1852
1853void helper_lar(void)
1854{
1855 unsigned int selector;
1856 uint32_t e1, e2;
3ab493de 1857 int rpl, dpl, cpl, type;
2c0262af
FB
1858
1859 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1860 selector = T0 & 0xffff;
3ab493de
FB
1861 if ((selector & 0xfffc) == 0)
1862 return;
2c0262af
FB
1863 if (load_segment(&e1, &e2, selector) != 0)
1864 return;
3ab493de
FB
1865 rpl = selector & 3;
1866 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1867 cpl = env->hflags & HF_CPL_MASK;
1868 if (e2 & DESC_S_MASK) {
1869 if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1870 /* conforming */
1871 } else {
1872 if (dpl < cpl || dpl < rpl)
1873 return;
1874 }
1875 } else {
1876 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1877 switch(type) {
1878 case 1:
1879 case 2:
1880 case 3:
1881 case 4:
1882 case 5:
1883 case 9:
1884 case 11:
1885 case 12:
1886 break;
1887 default:
1888 return;
1889 }
1890 if (dpl < cpl || dpl < rpl)
1891 return;
1892 }
2c0262af
FB
1893 T1 = e2 & 0x00f0ff00;
1894 CC_SRC |= CC_Z;
1895}
1896
3ab493de
FB
1897void helper_verr(void)
1898{
1899 unsigned int selector;
1900 uint32_t e1, e2;
1901 int rpl, dpl, cpl;
1902
1903 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1904 selector = T0 & 0xffff;
1905 if ((selector & 0xfffc) == 0)
1906 return;
1907 if (load_segment(&e1, &e2, selector) != 0)
1908 return;
1909 if (!(e2 & DESC_S_MASK))
1910 return;
1911 rpl = selector & 3;
1912 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1913 cpl = env->hflags & HF_CPL_MASK;
1914 if (e2 & DESC_CS_MASK) {
1915 if (!(e2 & DESC_R_MASK))
1916 return;
1917 if (!(e2 & DESC_C_MASK)) {
1918 if (dpl < cpl || dpl < rpl)
1919 return;
1920 }
1921 } else {
1922 if (dpl < cpl || dpl < rpl)
1923 return;
1924 }
f3f2d9be 1925 CC_SRC |= CC_Z;
3ab493de
FB
1926}
1927
1928void helper_verw(void)
1929{
1930 unsigned int selector;
1931 uint32_t e1, e2;
1932 int rpl, dpl, cpl;
1933
1934 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1935 selector = T0 & 0xffff;
1936 if ((selector & 0xfffc) == 0)
1937 return;
1938 if (load_segment(&e1, &e2, selector) != 0)
1939 return;
1940 if (!(e2 & DESC_S_MASK))
1941 return;
1942 rpl = selector & 3;
1943 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1944 cpl = env->hflags & HF_CPL_MASK;
1945 if (e2 & DESC_CS_MASK) {
1946 return;
1947 } else {
1948 if (dpl < cpl || dpl < rpl)
1949 return;
1950 if (!(e2 & DESC_W_MASK))
1951 return;
1952 }
f3f2d9be 1953 CC_SRC |= CC_Z;
3ab493de
FB
1954}
1955
2c0262af
FB
1956/* FPU helpers */
1957
2c0262af
FB
1958void helper_fldt_ST0_A0(void)
1959{
1960 int new_fpstt;
1961 new_fpstt = (env->fpstt - 1) & 7;
1962 env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1963 env->fpstt = new_fpstt;
1964 env->fptags[new_fpstt] = 0; /* validate stack entry */
1965}
1966
1967void helper_fstt_ST0_A0(void)
1968{
1969 helper_fstt(ST0, (uint8_t *)A0);
1970}
2c0262af
FB
1971
1972/* BCD ops */
1973
1974#define MUL10(iv) ( iv + iv + (iv << 3) )
1975
1976void helper_fbld_ST0_A0(void)
1977{
1978 CPU86_LDouble tmp;
1979 uint64_t val;
1980 unsigned int v;
1981 int i;
1982
1983 val = 0;
1984 for(i = 8; i >= 0; i--) {
1985 v = ldub((uint8_t *)A0 + i);
1986 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
1987 }
1988 tmp = val;
1989 if (ldub((uint8_t *)A0 + 9) & 0x80)
1990 tmp = -tmp;
1991 fpush();
1992 ST0 = tmp;
1993}
1994
1995void helper_fbst_ST0_A0(void)
1996{
1997 CPU86_LDouble tmp;
1998 int v;
1999 uint8_t *mem_ref, *mem_end;
2000 int64_t val;
2001
2002 tmp = rint(ST0);
2003 val = (int64_t)tmp;
2004 mem_ref = (uint8_t *)A0;
2005 mem_end = mem_ref + 9;
2006 if (val < 0) {
2007 stb(mem_end, 0x80);
2008 val = -val;
2009 } else {
2010 stb(mem_end, 0x00);
2011 }
2012 while (mem_ref < mem_end) {
2013 if (val == 0)
2014 break;
2015 v = val % 100;
2016 val = val / 100;
2017 v = ((v / 10) << 4) | (v % 10);
2018 stb(mem_ref++, v);
2019 }
2020 while (mem_ref < mem_end) {
2021 stb(mem_ref++, 0);
2022 }
2023}
2024
2025void helper_f2xm1(void)
2026{
2027 ST0 = pow(2.0,ST0) - 1.0;
2028}
2029
2030void helper_fyl2x(void)
2031{
2032 CPU86_LDouble fptemp;
2033
2034 fptemp = ST0;
2035 if (fptemp>0.0){
2036 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
2037 ST1 *= fptemp;
2038 fpop();
2039 } else {
2040 env->fpus &= (~0x4700);
2041 env->fpus |= 0x400;
2042 }
2043}
2044
2045void helper_fptan(void)
2046{
2047 CPU86_LDouble fptemp;
2048
2049 fptemp = ST0;
2050 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2051 env->fpus |= 0x400;
2052 } else {
2053 ST0 = tan(fptemp);
2054 fpush();
2055 ST0 = 1.0;
2056 env->fpus &= (~0x400); /* C2 <-- 0 */
2057 /* the above code is for |arg| < 2**52 only */
2058 }
2059}
2060
2061void helper_fpatan(void)
2062{
2063 CPU86_LDouble fptemp, fpsrcop;
2064
2065 fpsrcop = ST1;
2066 fptemp = ST0;
2067 ST1 = atan2(fpsrcop,fptemp);
2068 fpop();
2069}
2070
2071void helper_fxtract(void)
2072{
2073 CPU86_LDoubleU temp;
2074 unsigned int expdif;
2075
2076 temp.d = ST0;
2077 expdif = EXPD(temp) - EXPBIAS;
2078 /*DP exponent bias*/
2079 ST0 = expdif;
2080 fpush();
2081 BIASEXPONENT(temp);
2082 ST0 = temp.d;
2083}
2084
2085void helper_fprem1(void)
2086{
2087 CPU86_LDouble dblq, fpsrcop, fptemp;
2088 CPU86_LDoubleU fpsrcop1, fptemp1;
2089 int expdif;
2090 int q;
2091
2092 fpsrcop = ST0;
2093 fptemp = ST1;
2094 fpsrcop1.d = fpsrcop;
2095 fptemp1.d = fptemp;
2096 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2097 if (expdif < 53) {
2098 dblq = fpsrcop / fptemp;
2099 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2100 ST0 = fpsrcop - fptemp*dblq;
2101 q = (int)dblq; /* cutting off top bits is assumed here */
2102 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2103 /* (C0,C1,C3) <-- (q2,q1,q0) */
2104 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2105 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2106 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2107 } else {
2108 env->fpus |= 0x400; /* C2 <-- 1 */
2109 fptemp = pow(2.0, expdif-50);
2110 fpsrcop = (ST0 / ST1) / fptemp;
2111 /* fpsrcop = integer obtained by rounding to the nearest */
2112 fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2113 floor(fpsrcop): ceil(fpsrcop);
2114 ST0 -= (ST1 * fpsrcop * fptemp);
2115 }
2116}
2117
2118void helper_fprem(void)
2119{
2120 CPU86_LDouble dblq, fpsrcop, fptemp;
2121 CPU86_LDoubleU fpsrcop1, fptemp1;
2122 int expdif;
2123 int q;
2124
2125 fpsrcop = ST0;
2126 fptemp = ST1;
2127 fpsrcop1.d = fpsrcop;
2128 fptemp1.d = fptemp;
2129 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2130 if ( expdif < 53 ) {
2131 dblq = fpsrcop / fptemp;
2132 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2133 ST0 = fpsrcop - fptemp*dblq;
2134 q = (int)dblq; /* cutting off top bits is assumed here */
2135 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2136 /* (C0,C1,C3) <-- (q2,q1,q0) */
2137 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2138 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2139 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2140 } else {
2141 env->fpus |= 0x400; /* C2 <-- 1 */
2142 fptemp = pow(2.0, expdif-50);
2143 fpsrcop = (ST0 / ST1) / fptemp;
2144 /* fpsrcop = integer obtained by chopping */
2145 fpsrcop = (fpsrcop < 0.0)?
2146 -(floor(fabs(fpsrcop))): floor(fpsrcop);
2147 ST0 -= (ST1 * fpsrcop * fptemp);
2148 }
2149}
2150
2151void helper_fyl2xp1(void)
2152{
2153 CPU86_LDouble fptemp;
2154
2155 fptemp = ST0;
2156 if ((fptemp+1.0)>0.0) {
2157 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2158 ST1 *= fptemp;
2159 fpop();
2160 } else {
2161 env->fpus &= (~0x4700);
2162 env->fpus |= 0x400;
2163 }
2164}
2165
2166void helper_fsqrt(void)
2167{
2168 CPU86_LDouble fptemp;
2169
2170 fptemp = ST0;
2171 if (fptemp<0.0) {
2172 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2173 env->fpus |= 0x400;
2174 }
2175 ST0 = sqrt(fptemp);
2176}
2177
2178void helper_fsincos(void)
2179{
2180 CPU86_LDouble fptemp;
2181
2182 fptemp = ST0;
2183 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2184 env->fpus |= 0x400;
2185 } else {
2186 ST0 = sin(fptemp);
2187 fpush();
2188 ST0 = cos(fptemp);
2189 env->fpus &= (~0x400); /* C2 <-- 0 */
2190 /* the above code is for |arg| < 2**63 only */
2191 }
2192}
2193
2194void helper_frndint(void)
2195{
2196 CPU86_LDouble a;
2197
2198 a = ST0;
2199#ifdef __arm__
2200 switch(env->fpuc & RC_MASK) {
2201 default:
2202 case RC_NEAR:
2203 asm("rndd %0, %1" : "=f" (a) : "f"(a));
2204 break;
2205 case RC_DOWN:
2206 asm("rnddm %0, %1" : "=f" (a) : "f"(a));
2207 break;
2208 case RC_UP:
2209 asm("rnddp %0, %1" : "=f" (a) : "f"(a));
2210 break;
2211 case RC_CHOP:
2212 asm("rnddz %0, %1" : "=f" (a) : "f"(a));
2213 break;
2214 }
2215#else
2216 a = rint(a);
2217#endif
2218 ST0 = a;
2219}
2220
2221void helper_fscale(void)
2222{
2223 CPU86_LDouble fpsrcop, fptemp;
2224
2225 fpsrcop = 2.0;
2226 fptemp = pow(fpsrcop,ST1);
2227 ST0 *= fptemp;
2228}
2229
2230void helper_fsin(void)
2231{
2232 CPU86_LDouble fptemp;
2233
2234 fptemp = ST0;
2235 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2236 env->fpus |= 0x400;
2237 } else {
2238 ST0 = sin(fptemp);
2239 env->fpus &= (~0x400); /* C2 <-- 0 */
2240 /* the above code is for |arg| < 2**53 only */
2241 }
2242}
2243
2244void helper_fcos(void)
2245{
2246 CPU86_LDouble fptemp;
2247
2248 fptemp = ST0;
2249 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2250 env->fpus |= 0x400;
2251 } else {
2252 ST0 = cos(fptemp);
2253 env->fpus &= (~0x400); /* C2 <-- 0 */
2254 /* the above code is for |arg5 < 2**63 only */
2255 }
2256}
2257
2258void helper_fxam_ST0(void)
2259{
2260 CPU86_LDoubleU temp;
2261 int expdif;
2262
2263 temp.d = ST0;
2264
2265 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2266 if (SIGND(temp))
2267 env->fpus |= 0x200; /* C1 <-- 1 */
2268
2269 expdif = EXPD(temp);
2270 if (expdif == MAXEXPD) {
2271 if (MANTD(temp) == 0)
2272 env->fpus |= 0x500 /*Infinity*/;
2273 else
2274 env->fpus |= 0x100 /*NaN*/;
2275 } else if (expdif == 0) {
2276 if (MANTD(temp) == 0)
2277 env->fpus |= 0x4000 /*Zero*/;
2278 else
2279 env->fpus |= 0x4400 /*Denormal*/;
2280 } else {
2281 env->fpus |= 0x400;
2282 }
2283}
2284
2285void helper_fstenv(uint8_t *ptr, int data32)
2286{
2287 int fpus, fptag, exp, i;
2288 uint64_t mant;
2289 CPU86_LDoubleU tmp;
2290
2291 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2292 fptag = 0;
2293 for (i=7; i>=0; i--) {
2294 fptag <<= 2;
2295 if (env->fptags[i]) {
2296 fptag |= 3;
2297 } else {
2298 tmp.d = env->fpregs[i];
2299 exp = EXPD(tmp);
2300 mant = MANTD(tmp);
2301 if (exp == 0 && mant == 0) {
2302 /* zero */
2303 fptag |= 1;
2304 } else if (exp == 0 || exp == MAXEXPD
2305#ifdef USE_X86LDOUBLE
2306 || (mant & (1LL << 63)) == 0
2307#endif
2308 ) {
2309 /* NaNs, infinity, denormal */
2310 fptag |= 2;
2311 }
2312 }
2313 }
2314 if (data32) {
2315 /* 32 bit */
2316 stl(ptr, env->fpuc);
2317 stl(ptr + 4, fpus);
2318 stl(ptr + 8, fptag);
2319 stl(ptr + 12, 0);
2320 stl(ptr + 16, 0);
2321 stl(ptr + 20, 0);
2322 stl(ptr + 24, 0);
2323 } else {
2324 /* 16 bit */
2325 stw(ptr, env->fpuc);
2326 stw(ptr + 2, fpus);
2327 stw(ptr + 4, fptag);
2328 stw(ptr + 6, 0);
2329 stw(ptr + 8, 0);
2330 stw(ptr + 10, 0);
2331 stw(ptr + 12, 0);
2332 }
2333}
2334
2335void helper_fldenv(uint8_t *ptr, int data32)
2336{
2337 int i, fpus, fptag;
2338
2339 if (data32) {
2340 env->fpuc = lduw(ptr);
2341 fpus = lduw(ptr + 4);
2342 fptag = lduw(ptr + 8);
2343 }
2344 else {
2345 env->fpuc = lduw(ptr);
2346 fpus = lduw(ptr + 2);
2347 fptag = lduw(ptr + 4);
2348 }
2349 env->fpstt = (fpus >> 11) & 7;
2350 env->fpus = fpus & ~0x3800;
2351 for(i = 0;i < 7; i++) {
2352 env->fptags[i] = ((fptag & 3) == 3);
2353 fptag >>= 2;
2354 }
2355}
2356
2357void helper_fsave(uint8_t *ptr, int data32)
2358{
2359 CPU86_LDouble tmp;
2360 int i;
2361
2362 helper_fstenv(ptr, data32);
2363
2364 ptr += (14 << data32);
2365 for(i = 0;i < 8; i++) {
2366 tmp = ST(i);
2c0262af 2367 helper_fstt(tmp, ptr);
2c0262af
FB
2368 ptr += 10;
2369 }
2370
2371 /* fninit */
2372 env->fpus = 0;
2373 env->fpstt = 0;
2374 env->fpuc = 0x37f;
2375 env->fptags[0] = 1;
2376 env->fptags[1] = 1;
2377 env->fptags[2] = 1;
2378 env->fptags[3] = 1;
2379 env->fptags[4] = 1;
2380 env->fptags[5] = 1;
2381 env->fptags[6] = 1;
2382 env->fptags[7] = 1;
2383}
2384
2385void helper_frstor(uint8_t *ptr, int data32)
2386{
2387 CPU86_LDouble tmp;
2388 int i;
2389
2390 helper_fldenv(ptr, data32);
2391 ptr += (14 << data32);
2392
2393 for(i = 0;i < 8; i++) {
2c0262af 2394 tmp = helper_fldt(ptr);
2c0262af
FB
2395 ST(i) = tmp;
2396 ptr += 10;
2397 }
2398}
2399
61382a50
FB
2400#if !defined(CONFIG_USER_ONLY)
2401
2402#define MMUSUFFIX _mmu
2403#define GETPC() (__builtin_return_address(0))
2404
2c0262af
FB
2405#define SHIFT 0
2406#include "softmmu_template.h"
2407
2408#define SHIFT 1
2409#include "softmmu_template.h"
2410
2411#define SHIFT 2
2412#include "softmmu_template.h"
2413
2414#define SHIFT 3
2415#include "softmmu_template.h"
2416
61382a50
FB
2417#endif
2418
2419/* try to fill the TLB and return an exception if error. If retaddr is
2420 NULL, it means that the function was called in C code (i.e. not
2421 from generated code or from helper.c) */
2422/* XXX: fix it to restore all registers */
2423void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2c0262af
FB
2424{
2425 TranslationBlock *tb;
2426 int ret;
2427 unsigned long pc;
61382a50
FB
2428 CPUX86State *saved_env;
2429
2430 /* XXX: hack to restore env in all cases, even if not called from
2431 generated code */
2432 saved_env = env;
2433 env = cpu_single_env;
2434 if (is_write && page_unprotect(addr)) {
2435 /* nothing more to do: the page was write protected because
2436 there was code in it. page_unprotect() flushed the code. */
2437 }
2438
2439 ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
2c0262af 2440 if (ret) {
61382a50
FB
2441 if (retaddr) {
2442 /* now we have a real cpu fault */
2443 pc = (unsigned long)retaddr;
2444 tb = tb_find_pc(pc);
2445 if (tb) {
2446 /* the PC is inside the translated code. It means that we have
2447 a virtual CPU fault */
2448 cpu_restore_state(tb, env, pc);
2449 }
2c0262af
FB
2450 }
2451 raise_exception_err(EXCP0E_PAGE, env->error_code);
2452 }
61382a50 2453 env = saved_env;
2c0262af 2454}
This page took 0.294107 seconds and 4 git commands to generate.