Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 26a76461

History | View | Annotate | Download (97.8 kB)

1 2c0262af bellard
/*
2 2c0262af bellard
 *  i386 helpers
3 2c0262af bellard
 * 
4 2c0262af bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 2c0262af bellard
 *
6 2c0262af bellard
 * This library is free software; you can redistribute it and/or
7 2c0262af bellard
 * modify it under the terms of the GNU Lesser General Public
8 2c0262af bellard
 * License as published by the Free Software Foundation; either
9 2c0262af bellard
 * version 2 of the License, or (at your option) any later version.
10 2c0262af bellard
 *
11 2c0262af bellard
 * This library is distributed in the hope that it will be useful,
12 2c0262af bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 2c0262af bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 2c0262af bellard
 * Lesser General Public License for more details.
15 2c0262af bellard
 *
16 2c0262af bellard
 * You should have received a copy of the GNU Lesser General Public
17 2c0262af bellard
 * License along with this library; if not, write to the Free Software
18 2c0262af bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 2c0262af bellard
 */
20 2c0262af bellard
#include "exec.h"
21 2c0262af bellard
22 f3f2d9be bellard
//#define DEBUG_PCALL
23 f3f2d9be bellard
24 8145122b bellard
#if 0
25 8145122b bellard
#define raise_exception_err(a, b)\
26 8145122b bellard
do {\
27 9540a78b bellard
    if (logfile)\
28 9540a78b bellard
        fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
29 8145122b bellard
    (raise_exception_err)(a, b);\
30 8145122b bellard
} while (0)
31 8145122b bellard
#endif
32 8145122b bellard
33 2c0262af bellard
const uint8_t parity_table[256] = {
34 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
35 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
36 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
40 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
43 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
45 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
52 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
58 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
59 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
60 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
61 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
62 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
64 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
65 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
66 2c0262af bellard
};
67 2c0262af bellard
68 2c0262af bellard
/* modulo 17 table */
69 2c0262af bellard
const uint8_t rclw_table[32] = {
70 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
71 2c0262af bellard
    8, 9,10,11,12,13,14,15,
72 2c0262af bellard
   16, 0, 1, 2, 3, 4, 5, 6,
73 2c0262af bellard
    7, 8, 9,10,11,12,13,14,
74 2c0262af bellard
};
75 2c0262af bellard
76 2c0262af bellard
/* modulo 9 table */
77 2c0262af bellard
const uint8_t rclb_table[32] = {
78 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
79 2c0262af bellard
    8, 0, 1, 2, 3, 4, 5, 6,
80 2c0262af bellard
    7, 8, 0, 1, 2, 3, 4, 5, 
81 2c0262af bellard
    6, 7, 8, 0, 1, 2, 3, 4,
82 2c0262af bellard
};
83 2c0262af bellard
84 2c0262af bellard
const CPU86_LDouble f15rk[7] =
85 2c0262af bellard
{
86 2c0262af bellard
    0.00000000000000000000L,
87 2c0262af bellard
    1.00000000000000000000L,
88 2c0262af bellard
    3.14159265358979323851L,  /*pi*/
89 2c0262af bellard
    0.30102999566398119523L,  /*lg2*/
90 2c0262af bellard
    0.69314718055994530943L,  /*ln2*/
91 2c0262af bellard
    1.44269504088896340739L,  /*l2e*/
92 2c0262af bellard
    3.32192809488736234781L,  /*l2t*/
93 2c0262af bellard
};
94 2c0262af bellard
    
95 2c0262af bellard
/* thread support */
96 2c0262af bellard
97 2c0262af bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
98 2c0262af bellard
99 2c0262af bellard
void cpu_lock(void)
100 2c0262af bellard
{
101 2c0262af bellard
    spin_lock(&global_cpu_lock);
102 2c0262af bellard
}
103 2c0262af bellard
104 2c0262af bellard
void cpu_unlock(void)
105 2c0262af bellard
{
106 2c0262af bellard
    spin_unlock(&global_cpu_lock);
107 2c0262af bellard
}
108 2c0262af bellard
109 2c0262af bellard
void cpu_loop_exit(void)
110 2c0262af bellard
{
111 2c0262af bellard
    /* NOTE: the register at this point must be saved by hand because
112 2c0262af bellard
       longjmp restore them */
113 0d1a29f9 bellard
    regs_to_env();
114 2c0262af bellard
    longjmp(env->jmp_env, 1);
115 2c0262af bellard
}
116 2c0262af bellard
117 7e84c249 bellard
/* return non zero if error */
118 7e84c249 bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
119 7e84c249 bellard
                               int selector)
120 7e84c249 bellard
{
121 7e84c249 bellard
    SegmentCache *dt;
122 7e84c249 bellard
    int index;
123 14ce26e7 bellard
    target_ulong ptr;
124 7e84c249 bellard
125 7e84c249 bellard
    if (selector & 0x4)
126 7e84c249 bellard
        dt = &env->ldt;
127 7e84c249 bellard
    else
128 7e84c249 bellard
        dt = &env->gdt;
129 7e84c249 bellard
    index = selector & ~7;
130 7e84c249 bellard
    if ((index + 7) > dt->limit)
131 7e84c249 bellard
        return -1;
132 7e84c249 bellard
    ptr = dt->base + index;
133 7e84c249 bellard
    *e1_ptr = ldl_kernel(ptr);
134 7e84c249 bellard
    *e2_ptr = ldl_kernel(ptr + 4);
135 7e84c249 bellard
    return 0;
136 7e84c249 bellard
}
137 7e84c249 bellard
                                     
138 7e84c249 bellard
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
139 7e84c249 bellard
{
140 7e84c249 bellard
    unsigned int limit;
141 7e84c249 bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
142 7e84c249 bellard
    if (e2 & DESC_G_MASK)
143 7e84c249 bellard
        limit = (limit << 12) | 0xfff;
144 7e84c249 bellard
    return limit;
145 7e84c249 bellard
}
146 7e84c249 bellard
147 14ce26e7 bellard
static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
148 7e84c249 bellard
{
149 14ce26e7 bellard
    return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
150 7e84c249 bellard
}
151 7e84c249 bellard
152 7e84c249 bellard
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
153 7e84c249 bellard
{
154 7e84c249 bellard
    sc->base = get_seg_base(e1, e2);
155 7e84c249 bellard
    sc->limit = get_seg_limit(e1, e2);
156 7e84c249 bellard
    sc->flags = e2;
157 7e84c249 bellard
}
158 7e84c249 bellard
159 7e84c249 bellard
/* init the segment cache in vm86 mode. */
160 7e84c249 bellard
static inline void load_seg_vm(int seg, int selector)
161 7e84c249 bellard
{
162 7e84c249 bellard
    selector &= 0xffff;
163 7e84c249 bellard
    cpu_x86_load_seg_cache(env, seg, selector, 
164 14ce26e7 bellard
                           (selector << 4), 0xffff, 0);
165 7e84c249 bellard
}
166 7e84c249 bellard
167 2c0262af bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
168 2c0262af bellard
                                       uint32_t *esp_ptr, int dpl)
169 2c0262af bellard
{
170 2c0262af bellard
    int type, index, shift;
171 2c0262af bellard
    
172 2c0262af bellard
#if 0
173 2c0262af bellard
    {
174 2c0262af bellard
        int i;
175 2c0262af bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
176 2c0262af bellard
        for(i=0;i<env->tr.limit;i++) {
177 2c0262af bellard
            printf("%02x ", env->tr.base[i]);
178 2c0262af bellard
            if ((i & 7) == 7) printf("\n");
179 2c0262af bellard
        }
180 2c0262af bellard
        printf("\n");
181 2c0262af bellard
    }
182 2c0262af bellard
#endif
183 2c0262af bellard
184 2c0262af bellard
    if (!(env->tr.flags & DESC_P_MASK))
185 2c0262af bellard
        cpu_abort(env, "invalid tss");
186 2c0262af bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
187 2c0262af bellard
    if ((type & 7) != 1)
188 2c0262af bellard
        cpu_abort(env, "invalid tss type");
189 2c0262af bellard
    shift = type >> 3;
190 2c0262af bellard
    index = (dpl * 4 + 2) << shift;
191 2c0262af bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
192 2c0262af bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
193 2c0262af bellard
    if (shift == 0) {
194 61382a50 bellard
        *esp_ptr = lduw_kernel(env->tr.base + index);
195 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
196 2c0262af bellard
    } else {
197 61382a50 bellard
        *esp_ptr = ldl_kernel(env->tr.base + index);
198 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
199 2c0262af bellard
    }
200 2c0262af bellard
}
201 2c0262af bellard
202 7e84c249 bellard
/* XXX: merge with load_seg() */
203 7e84c249 bellard
static void tss_load_seg(int seg_reg, int selector)
204 7e84c249 bellard
{
205 7e84c249 bellard
    uint32_t e1, e2;
206 7e84c249 bellard
    int rpl, dpl, cpl;
207 7e84c249 bellard
208 7e84c249 bellard
    if ((selector & 0xfffc) != 0) {
209 7e84c249 bellard
        if (load_segment(&e1, &e2, selector) != 0)
210 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
211 7e84c249 bellard
        if (!(e2 & DESC_S_MASK))
212 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
213 7e84c249 bellard
        rpl = selector & 3;
214 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
215 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
216 7e84c249 bellard
        if (seg_reg == R_CS) {
217 7e84c249 bellard
            if (!(e2 & DESC_CS_MASK))
218 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
219 9540a78b bellard
            /* XXX: is it correct ? */
220 7e84c249 bellard
            if (dpl != rpl)
221 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
222 7e84c249 bellard
            if ((e2 & DESC_C_MASK) && dpl > rpl)
223 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
224 7e84c249 bellard
        } else if (seg_reg == R_SS) {
225 7e84c249 bellard
            /* SS must be writable data */
226 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
227 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
228 7e84c249 bellard
            if (dpl != cpl || dpl != rpl)
229 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230 7e84c249 bellard
        } else {
231 7e84c249 bellard
            /* not readable code */
232 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
233 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
234 7e84c249 bellard
            /* if data or non conforming code, checks the rights */
235 7e84c249 bellard
            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
236 7e84c249 bellard
                if (dpl < cpl || dpl < rpl)
237 7e84c249 bellard
                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
238 7e84c249 bellard
            }
239 7e84c249 bellard
        }
240 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
241 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
242 7e84c249 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
243 7e84c249 bellard
                       get_seg_base(e1, e2),
244 7e84c249 bellard
                       get_seg_limit(e1, e2),
245 7e84c249 bellard
                       e2);
246 7e84c249 bellard
    } else {
247 7e84c249 bellard
        if (seg_reg == R_SS || seg_reg == R_CS) 
248 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
249 7e84c249 bellard
    }
250 7e84c249 bellard
}
251 7e84c249 bellard
252 7e84c249 bellard
#define SWITCH_TSS_JMP  0
253 7e84c249 bellard
#define SWITCH_TSS_IRET 1
254 7e84c249 bellard
#define SWITCH_TSS_CALL 2
255 7e84c249 bellard
256 7e84c249 bellard
/* XXX: restore CPU state in registers (PowerPC case) */
257 7e84c249 bellard
static void switch_tss(int tss_selector, 
258 883da8e2 bellard
                       uint32_t e1, uint32_t e2, int source,
259 883da8e2 bellard
                       uint32_t next_eip)
260 2c0262af bellard
{
261 7e84c249 bellard
    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
262 14ce26e7 bellard
    target_ulong tss_base;
263 7e84c249 bellard
    uint32_t new_regs[8], new_segs[6];
264 7e84c249 bellard
    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
265 7e84c249 bellard
    uint32_t old_eflags, eflags_mask;
266 2c0262af bellard
    SegmentCache *dt;
267 2c0262af bellard
    int index;
268 14ce26e7 bellard
    target_ulong ptr;
269 2c0262af bellard
270 7e84c249 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
271 dc6f57fd bellard
#ifdef DEBUG_PCALL
272 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL)
273 dc6f57fd bellard
        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
274 dc6f57fd bellard
#endif
275 7e84c249 bellard
276 7e84c249 bellard
    /* if task gate, we read the TSS segment and we load it */
277 7e84c249 bellard
    if (type == 5) {
278 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
279 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
280 7e84c249 bellard
        tss_selector = e1 >> 16;
281 7e84c249 bellard
        if (tss_selector & 4)
282 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
283 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
284 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
285 7e84c249 bellard
        if (e2 & DESC_S_MASK)
286 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
287 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
288 7e84c249 bellard
        if ((type & 7) != 1)
289 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
290 7e84c249 bellard
    }
291 7e84c249 bellard
292 7e84c249 bellard
    if (!(e2 & DESC_P_MASK))
293 7e84c249 bellard
        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
294 7e84c249 bellard
295 7e84c249 bellard
    if (type & 8)
296 7e84c249 bellard
        tss_limit_max = 103;
297 2c0262af bellard
    else
298 7e84c249 bellard
        tss_limit_max = 43;
299 7e84c249 bellard
    tss_limit = get_seg_limit(e1, e2);
300 7e84c249 bellard
    tss_base = get_seg_base(e1, e2);
301 7e84c249 bellard
    if ((tss_selector & 4) != 0 || 
302 7e84c249 bellard
        tss_limit < tss_limit_max)
303 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
304 7e84c249 bellard
    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
305 7e84c249 bellard
    if (old_type & 8)
306 7e84c249 bellard
        old_tss_limit_max = 103;
307 7e84c249 bellard
    else
308 7e84c249 bellard
        old_tss_limit_max = 43;
309 7e84c249 bellard
310 7e84c249 bellard
    /* read all the registers from the new TSS */
311 7e84c249 bellard
    if (type & 8) {
312 7e84c249 bellard
        /* 32 bit */
313 7e84c249 bellard
        new_cr3 = ldl_kernel(tss_base + 0x1c);
314 7e84c249 bellard
        new_eip = ldl_kernel(tss_base + 0x20);
315 7e84c249 bellard
        new_eflags = ldl_kernel(tss_base + 0x24);
316 7e84c249 bellard
        for(i = 0; i < 8; i++)
317 7e84c249 bellard
            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
318 7e84c249 bellard
        for(i = 0; i < 6; i++)
319 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
320 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x60);
321 7e84c249 bellard
        new_trap = ldl_kernel(tss_base + 0x64);
322 7e84c249 bellard
    } else {
323 7e84c249 bellard
        /* 16 bit */
324 7e84c249 bellard
        new_cr3 = 0;
325 7e84c249 bellard
        new_eip = lduw_kernel(tss_base + 0x0e);
326 7e84c249 bellard
        new_eflags = lduw_kernel(tss_base + 0x10);
327 7e84c249 bellard
        for(i = 0; i < 8; i++)
328 7e84c249 bellard
            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
329 7e84c249 bellard
        for(i = 0; i < 4; i++)
330 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
331 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x2a);
332 7e84c249 bellard
        new_segs[R_FS] = 0;
333 7e84c249 bellard
        new_segs[R_GS] = 0;
334 7e84c249 bellard
        new_trap = 0;
335 7e84c249 bellard
    }
336 7e84c249 bellard
    
337 7e84c249 bellard
    /* NOTE: we must avoid memory exceptions during the task switch,
338 7e84c249 bellard
       so we make dummy accesses before */
339 7e84c249 bellard
    /* XXX: it can still fail in some cases, so a bigger hack is
340 7e84c249 bellard
       necessary to valid the TLB after having done the accesses */
341 7e84c249 bellard
342 7e84c249 bellard
    v1 = ldub_kernel(env->tr.base);
343 265d3497 bellard
    v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
344 7e84c249 bellard
    stb_kernel(env->tr.base, v1);
345 7e84c249 bellard
    stb_kernel(env->tr.base + old_tss_limit_max, v2);
346 7e84c249 bellard
    
347 7e84c249 bellard
    /* clear busy bit (it is restartable) */
348 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
349 14ce26e7 bellard
        target_ulong ptr;
350 7e84c249 bellard
        uint32_t e2;
351 883da8e2 bellard
        ptr = env->gdt.base + (env->tr.selector & ~7);
352 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
353 7e84c249 bellard
        e2 &= ~DESC_TSS_BUSY_MASK;
354 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
355 7e84c249 bellard
    }
356 7e84c249 bellard
    old_eflags = compute_eflags();
357 7e84c249 bellard
    if (source == SWITCH_TSS_IRET)
358 7e84c249 bellard
        old_eflags &= ~NT_MASK;
359 7e84c249 bellard
    
360 7e84c249 bellard
    /* save the current state in the old TSS */
361 7e84c249 bellard
    if (type & 8) {
362 7e84c249 bellard
        /* 32 bit */
363 883da8e2 bellard
        stl_kernel(env->tr.base + 0x20, next_eip);
364 7e84c249 bellard
        stl_kernel(env->tr.base + 0x24, old_eflags);
365 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
366 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
367 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
368 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
369 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
370 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
371 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
372 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
373 7e84c249 bellard
        for(i = 0; i < 6; i++)
374 7e84c249 bellard
            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
375 7e84c249 bellard
    } else {
376 7e84c249 bellard
        /* 16 bit */
377 883da8e2 bellard
        stw_kernel(env->tr.base + 0x0e, next_eip);
378 7e84c249 bellard
        stw_kernel(env->tr.base + 0x10, old_eflags);
379 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
380 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
381 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
382 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
383 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
384 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
385 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
386 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
387 7e84c249 bellard
        for(i = 0; i < 4; i++)
388 7e84c249 bellard
            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
389 7e84c249 bellard
    }
390 7e84c249 bellard
    
391 7e84c249 bellard
    /* now if an exception occurs, it will occurs in the next task
392 7e84c249 bellard
       context */
393 7e84c249 bellard
394 7e84c249 bellard
    if (source == SWITCH_TSS_CALL) {
395 7e84c249 bellard
        stw_kernel(tss_base, env->tr.selector);
396 7e84c249 bellard
        new_eflags |= NT_MASK;
397 7e84c249 bellard
    }
398 7e84c249 bellard
399 7e84c249 bellard
    /* set busy bit */
400 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
401 14ce26e7 bellard
        target_ulong ptr;
402 7e84c249 bellard
        uint32_t e2;
403 883da8e2 bellard
        ptr = env->gdt.base + (tss_selector & ~7);
404 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
405 7e84c249 bellard
        e2 |= DESC_TSS_BUSY_MASK;
406 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
407 7e84c249 bellard
    }
408 7e84c249 bellard
409 7e84c249 bellard
    /* set the new CPU state */
410 7e84c249 bellard
    /* from this point, any exception which occurs can give problems */
411 7e84c249 bellard
    env->cr[0] |= CR0_TS_MASK;
412 883da8e2 bellard
    env->hflags |= HF_TS_MASK;
413 7e84c249 bellard
    env->tr.selector = tss_selector;
414 7e84c249 bellard
    env->tr.base = tss_base;
415 7e84c249 bellard
    env->tr.limit = tss_limit;
416 7e84c249 bellard
    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
417 7e84c249 bellard
    
418 7e84c249 bellard
    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
419 1ac157da bellard
        cpu_x86_update_cr3(env, new_cr3);
420 7e84c249 bellard
    }
421 7e84c249 bellard
    
422 7e84c249 bellard
    /* load all registers without an exception, then reload them with
423 7e84c249 bellard
       possible exception */
424 7e84c249 bellard
    env->eip = new_eip;
425 4136f33c bellard
    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
426 8145122b bellard
        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
427 7e84c249 bellard
    if (!(type & 8))
428 7e84c249 bellard
        eflags_mask &= 0xffff;
429 7e84c249 bellard
    load_eflags(new_eflags, eflags_mask);
430 0d1a29f9 bellard
    /* XXX: what to do in 16 bit case ? */
431 0d1a29f9 bellard
    EAX = new_regs[0];
432 0d1a29f9 bellard
    ECX = new_regs[1];
433 0d1a29f9 bellard
    EDX = new_regs[2];
434 0d1a29f9 bellard
    EBX = new_regs[3];
435 0d1a29f9 bellard
    ESP = new_regs[4];
436 0d1a29f9 bellard
    EBP = new_regs[5];
437 0d1a29f9 bellard
    ESI = new_regs[6];
438 0d1a29f9 bellard
    EDI = new_regs[7];
439 7e84c249 bellard
    if (new_eflags & VM_MASK) {
440 7e84c249 bellard
        for(i = 0; i < 6; i++) 
441 7e84c249 bellard
            load_seg_vm(i, new_segs[i]);
442 7e84c249 bellard
        /* in vm86, CPL is always 3 */
443 7e84c249 bellard
        cpu_x86_set_cpl(env, 3);
444 7e84c249 bellard
    } else {
445 7e84c249 bellard
        /* CPL is set the RPL of CS */
446 7e84c249 bellard
        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
447 7e84c249 bellard
        /* first just selectors as the rest may trigger exceptions */
448 7e84c249 bellard
        for(i = 0; i < 6; i++)
449 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
450 7e84c249 bellard
    }
451 7e84c249 bellard
    
452 7e84c249 bellard
    env->ldt.selector = new_ldt & ~4;
453 14ce26e7 bellard
    env->ldt.base = 0;
454 7e84c249 bellard
    env->ldt.limit = 0;
455 7e84c249 bellard
    env->ldt.flags = 0;
456 7e84c249 bellard
457 7e84c249 bellard
    /* load the LDT */
458 7e84c249 bellard
    if (new_ldt & 4)
459 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
460 7e84c249 bellard
461 8145122b bellard
    if ((new_ldt & 0xfffc) != 0) {
462 8145122b bellard
        dt = &env->gdt;
463 8145122b bellard
        index = new_ldt & ~7;
464 8145122b bellard
        if ((index + 7) > dt->limit)
465 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
466 8145122b bellard
        ptr = dt->base + index;
467 8145122b bellard
        e1 = ldl_kernel(ptr);
468 8145122b bellard
        e2 = ldl_kernel(ptr + 4);
469 8145122b bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
470 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
471 8145122b bellard
        if (!(e2 & DESC_P_MASK))
472 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
473 8145122b bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
474 8145122b bellard
    }
475 7e84c249 bellard
    
476 7e84c249 bellard
    /* load the segments */
477 7e84c249 bellard
    if (!(new_eflags & VM_MASK)) {
478 7e84c249 bellard
        tss_load_seg(R_CS, new_segs[R_CS]);
479 7e84c249 bellard
        tss_load_seg(R_SS, new_segs[R_SS]);
480 7e84c249 bellard
        tss_load_seg(R_ES, new_segs[R_ES]);
481 7e84c249 bellard
        tss_load_seg(R_DS, new_segs[R_DS]);
482 7e84c249 bellard
        tss_load_seg(R_FS, new_segs[R_FS]);
483 7e84c249 bellard
        tss_load_seg(R_GS, new_segs[R_GS]);
484 7e84c249 bellard
    }
485 7e84c249 bellard
    
486 7e84c249 bellard
    /* check that EIP is in the CS segment limits */
487 7e84c249 bellard
    if (new_eip > env->segs[R_CS].limit) {
488 883da8e2 bellard
        /* XXX: different exception if CALL ? */
489 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
490 7e84c249 bellard
    }
491 2c0262af bellard
}
492 7e84c249 bellard
493 7e84c249 bellard
/* check if Port I/O is allowed in TSS */
494 7e84c249 bellard
static inline void check_io(int addr, int size)
495 2c0262af bellard
{
496 7e84c249 bellard
    int io_offset, val, mask;
497 7e84c249 bellard
    
498 7e84c249 bellard
    /* TSS must be a valid 32 bit one */
499 7e84c249 bellard
    if (!(env->tr.flags & DESC_P_MASK) ||
500 7e84c249 bellard
        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
501 7e84c249 bellard
        env->tr.limit < 103)
502 7e84c249 bellard
        goto fail;
503 7e84c249 bellard
    io_offset = lduw_kernel(env->tr.base + 0x66);
504 7e84c249 bellard
    io_offset += (addr >> 3);
505 7e84c249 bellard
    /* Note: the check needs two bytes */
506 7e84c249 bellard
    if ((io_offset + 1) > env->tr.limit)
507 7e84c249 bellard
        goto fail;
508 7e84c249 bellard
    val = lduw_kernel(env->tr.base + io_offset);
509 7e84c249 bellard
    val >>= (addr & 7);
510 7e84c249 bellard
    mask = (1 << size) - 1;
511 7e84c249 bellard
    /* all bits must be zero to allow the I/O */
512 7e84c249 bellard
    if ((val & mask) != 0) {
513 7e84c249 bellard
    fail:
514 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
515 7e84c249 bellard
    }
516 2c0262af bellard
}
517 2c0262af bellard
518 7e84c249 bellard
void check_iob_T0(void)
519 2c0262af bellard
{
520 7e84c249 bellard
    check_io(T0, 1);
521 2c0262af bellard
}
522 2c0262af bellard
523 7e84c249 bellard
void check_iow_T0(void)
524 2c0262af bellard
{
525 7e84c249 bellard
    check_io(T0, 2);
526 2c0262af bellard
}
527 2c0262af bellard
528 7e84c249 bellard
void check_iol_T0(void)
529 2c0262af bellard
{
530 7e84c249 bellard
    check_io(T0, 4);
531 7e84c249 bellard
}
532 7e84c249 bellard
533 7e84c249 bellard
void check_iob_DX(void)
534 7e84c249 bellard
{
535 7e84c249 bellard
    check_io(EDX & 0xffff, 1);
536 7e84c249 bellard
}
537 7e84c249 bellard
538 7e84c249 bellard
void check_iow_DX(void)
539 7e84c249 bellard
{
540 7e84c249 bellard
    check_io(EDX & 0xffff, 2);
541 7e84c249 bellard
}
542 7e84c249 bellard
543 7e84c249 bellard
void check_iol_DX(void)
544 7e84c249 bellard
{
545 7e84c249 bellard
    check_io(EDX & 0xffff, 4);
546 2c0262af bellard
}
547 2c0262af bellard
548 891b38e4 bellard
static inline unsigned int get_sp_mask(unsigned int e2)
549 891b38e4 bellard
{
550 891b38e4 bellard
    if (e2 & DESC_B_MASK)
551 891b38e4 bellard
        return 0xffffffff;
552 891b38e4 bellard
    else
553 891b38e4 bellard
        return 0xffff;
554 891b38e4 bellard
}
555 891b38e4 bellard
556 891b38e4 bellard
/* XXX: add a is_user flag to have proper security support */
557 891b38e4 bellard
#define PUSHW(ssp, sp, sp_mask, val)\
558 891b38e4 bellard
{\
559 891b38e4 bellard
    sp -= 2;\
560 891b38e4 bellard
    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
561 891b38e4 bellard
}
562 891b38e4 bellard
563 891b38e4 bellard
#define PUSHL(ssp, sp, sp_mask, val)\
564 891b38e4 bellard
{\
565 891b38e4 bellard
    sp -= 4;\
566 891b38e4 bellard
    stl_kernel((ssp) + (sp & (sp_mask)), (val));\
567 891b38e4 bellard
}
568 891b38e4 bellard
569 891b38e4 bellard
#define POPW(ssp, sp, sp_mask, val)\
570 891b38e4 bellard
{\
571 891b38e4 bellard
    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
572 891b38e4 bellard
    sp += 2;\
573 891b38e4 bellard
}
574 891b38e4 bellard
575 891b38e4 bellard
#define POPL(ssp, sp, sp_mask, val)\
576 891b38e4 bellard
{\
577 14ce26e7 bellard
    val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
578 891b38e4 bellard
    sp += 4;\
579 891b38e4 bellard
}
580 891b38e4 bellard
581 2c0262af bellard
/* protected mode interrupt */
582 2c0262af bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
583 2c0262af bellard
                                   unsigned int next_eip, int is_hw)
584 2c0262af bellard
{
585 2c0262af bellard
    SegmentCache *dt;
586 14ce26e7 bellard
    target_ulong ptr, ssp;
587 891b38e4 bellard
    int type, dpl, selector, ss_dpl, cpl, sp_mask;
588 2c0262af bellard
    int has_error_code, new_stack, shift;
589 891b38e4 bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
590 891b38e4 bellard
    uint32_t old_eip;
591 2c0262af bellard
592 7e84c249 bellard
    has_error_code = 0;
593 7e84c249 bellard
    if (!is_int && !is_hw) {
594 7e84c249 bellard
        switch(intno) {
595 7e84c249 bellard
        case 8:
596 7e84c249 bellard
        case 10:
597 7e84c249 bellard
        case 11:
598 7e84c249 bellard
        case 12:
599 7e84c249 bellard
        case 13:
600 7e84c249 bellard
        case 14:
601 7e84c249 bellard
        case 17:
602 7e84c249 bellard
            has_error_code = 1;
603 7e84c249 bellard
            break;
604 7e84c249 bellard
        }
605 7e84c249 bellard
    }
606 883da8e2 bellard
    if (is_int)
607 883da8e2 bellard
        old_eip = next_eip;
608 883da8e2 bellard
    else
609 883da8e2 bellard
        old_eip = env->eip;
610 7e84c249 bellard
611 2c0262af bellard
    dt = &env->idt;
612 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
613 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
614 2c0262af bellard
    ptr = dt->base + intno * 8;
615 61382a50 bellard
    e1 = ldl_kernel(ptr);
616 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
617 2c0262af bellard
    /* check gate type */
618 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
619 2c0262af bellard
    switch(type) {
620 2c0262af bellard
    case 5: /* task gate */
621 7e84c249 bellard
        /* must do that check here to return the correct error code */
622 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
623 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
624 883da8e2 bellard
        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
625 7e84c249 bellard
        if (has_error_code) {
626 3f20e1dd bellard
            int mask, type;
627 7e84c249 bellard
            /* push the error code */
628 3f20e1dd bellard
            type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
629 3f20e1dd bellard
            shift = type >> 3;
630 7e84c249 bellard
            if (env->segs[R_SS].flags & DESC_B_MASK)
631 7e84c249 bellard
                mask = 0xffffffff;
632 7e84c249 bellard
            else
633 7e84c249 bellard
                mask = 0xffff;
634 0d1a29f9 bellard
            esp = (ESP - (2 << shift)) & mask;
635 7e84c249 bellard
            ssp = env->segs[R_SS].base + esp;
636 7e84c249 bellard
            if (shift)
637 7e84c249 bellard
                stl_kernel(ssp, error_code);
638 7e84c249 bellard
            else
639 7e84c249 bellard
                stw_kernel(ssp, error_code);
640 0d1a29f9 bellard
            ESP = (esp & mask) | (ESP & ~mask);
641 7e84c249 bellard
        }
642 7e84c249 bellard
        return;
643 2c0262af bellard
    case 6: /* 286 interrupt gate */
644 2c0262af bellard
    case 7: /* 286 trap gate */
645 2c0262af bellard
    case 14: /* 386 interrupt gate */
646 2c0262af bellard
    case 15: /* 386 trap gate */
647 2c0262af bellard
        break;
648 2c0262af bellard
    default:
649 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
650 2c0262af bellard
        break;
651 2c0262af bellard
    }
652 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
653 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
654 2c0262af bellard
    /* check privledge if software int */
655 2c0262af bellard
    if (is_int && dpl < cpl)
656 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
657 2c0262af bellard
    /* check valid bit */
658 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
659 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
660 2c0262af bellard
    selector = e1 >> 16;
661 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
662 2c0262af bellard
    if ((selector & 0xfffc) == 0)
663 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
664 2c0262af bellard
665 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
666 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
667 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
668 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
669 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
670 2c0262af bellard
    if (dpl > cpl)
671 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
672 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
673 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
674 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
675 2c0262af bellard
        /* to inner priviledge */
676 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
677 2c0262af bellard
        if ((ss & 0xfffc) == 0)
678 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
679 2c0262af bellard
        if ((ss & 3) != dpl)
680 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
681 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
682 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
683 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
684 2c0262af bellard
        if (ss_dpl != dpl)
685 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
686 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
687 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
688 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
689 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
690 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
691 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
692 2c0262af bellard
        new_stack = 1;
693 891b38e4 bellard
        sp_mask = get_sp_mask(ss_e2);
694 891b38e4 bellard
        ssp = get_seg_base(ss_e1, ss_e2);
695 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
696 2c0262af bellard
        /* to same priviledge */
697 8e682019 bellard
        if (env->eflags & VM_MASK)
698 8e682019 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
699 2c0262af bellard
        new_stack = 0;
700 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
701 891b38e4 bellard
        ssp = env->segs[R_SS].base;
702 891b38e4 bellard
        esp = ESP;
703 4796f5e9 bellard
        dpl = cpl;
704 2c0262af bellard
    } else {
705 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
706 2c0262af bellard
        new_stack = 0; /* avoid warning */
707 891b38e4 bellard
        sp_mask = 0; /* avoid warning */
708 14ce26e7 bellard
        ssp = 0; /* avoid warning */
709 891b38e4 bellard
        esp = 0; /* avoid warning */
710 2c0262af bellard
    }
711 2c0262af bellard
712 2c0262af bellard
    shift = type >> 3;
713 891b38e4 bellard
714 891b38e4 bellard
#if 0
715 891b38e4 bellard
    /* XXX: check that enough room is available */
716 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
717 2c0262af bellard
    if (env->eflags & VM_MASK)
718 2c0262af bellard
        push_size += 8;
719 2c0262af bellard
    push_size <<= shift;
720 891b38e4 bellard
#endif
721 2c0262af bellard
    if (shift == 1) {
722 2c0262af bellard
        if (new_stack) {
723 8e682019 bellard
            if (env->eflags & VM_MASK) {
724 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
725 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
726 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
727 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
728 8e682019 bellard
            }
729 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
730 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, ESP);
731 2c0262af bellard
        }
732 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, compute_eflags());
733 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
734 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, old_eip);
735 2c0262af bellard
        if (has_error_code) {
736 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, error_code);
737 2c0262af bellard
        }
738 2c0262af bellard
    } else {
739 2c0262af bellard
        if (new_stack) {
740 8e682019 bellard
            if (env->eflags & VM_MASK) {
741 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
742 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
743 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
744 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
745 8e682019 bellard
            }
746 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
747 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, ESP);
748 2c0262af bellard
        }
749 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, compute_eflags());
750 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
751 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, old_eip);
752 2c0262af bellard
        if (has_error_code) {
753 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, error_code);
754 2c0262af bellard
        }
755 2c0262af bellard
    }
756 2c0262af bellard
    
757 891b38e4 bellard
    if (new_stack) {
758 8e682019 bellard
        if (env->eflags & VM_MASK) {
759 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
760 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
761 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
762 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
763 8e682019 bellard
        }
764 891b38e4 bellard
        ss = (ss & ~3) | dpl;
765 891b38e4 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
766 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
767 891b38e4 bellard
    }
768 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (esp & sp_mask);
769 891b38e4 bellard
770 891b38e4 bellard
    selector = (selector & ~3) | dpl;
771 891b38e4 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
772 891b38e4 bellard
                   get_seg_base(e1, e2),
773 891b38e4 bellard
                   get_seg_limit(e1, e2),
774 891b38e4 bellard
                   e2);
775 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
776 891b38e4 bellard
    env->eip = offset;
777 891b38e4 bellard
778 2c0262af bellard
    /* interrupt gate clear IF mask */
779 2c0262af bellard
    if ((type & 1) == 0) {
780 2c0262af bellard
        env->eflags &= ~IF_MASK;
781 2c0262af bellard
    }
782 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
783 2c0262af bellard
}
784 2c0262af bellard
785 14ce26e7 bellard
#ifdef TARGET_X86_64
786 14ce26e7 bellard
787 14ce26e7 bellard
#define PUSHQ(sp, val)\
788 14ce26e7 bellard
{\
789 14ce26e7 bellard
    sp -= 8;\
790 14ce26e7 bellard
    stq_kernel(sp, (val));\
791 14ce26e7 bellard
}
792 14ce26e7 bellard
793 14ce26e7 bellard
#define POPQ(sp, val)\
794 14ce26e7 bellard
{\
795 14ce26e7 bellard
    val = ldq_kernel(sp);\
796 14ce26e7 bellard
    sp += 8;\
797 14ce26e7 bellard
}
798 14ce26e7 bellard
799 14ce26e7 bellard
static inline target_ulong get_rsp_from_tss(int level)
800 14ce26e7 bellard
{
801 14ce26e7 bellard
    int index;
802 14ce26e7 bellard
    
803 14ce26e7 bellard
#if 0
804 14ce26e7 bellard
    printf("TR: base=" TARGET_FMT_lx " limit=%x\n", 
805 14ce26e7 bellard
           env->tr.base, env->tr.limit);
806 14ce26e7 bellard
#endif
807 14ce26e7 bellard
808 14ce26e7 bellard
    if (!(env->tr.flags & DESC_P_MASK))
809 14ce26e7 bellard
        cpu_abort(env, "invalid tss");
810 14ce26e7 bellard
    index = 8 * level + 4;
811 14ce26e7 bellard
    if ((index + 7) > env->tr.limit)
812 14ce26e7 bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
813 14ce26e7 bellard
    return ldq_kernel(env->tr.base + index);
814 14ce26e7 bellard
}
815 14ce26e7 bellard
816 14ce26e7 bellard
/* 64 bit interrupt */
817 14ce26e7 bellard
static void do_interrupt64(int intno, int is_int, int error_code,
818 14ce26e7 bellard
                           target_ulong next_eip, int is_hw)
819 14ce26e7 bellard
{
820 14ce26e7 bellard
    SegmentCache *dt;
821 14ce26e7 bellard
    target_ulong ptr;
822 14ce26e7 bellard
    int type, dpl, selector, cpl, ist;
823 14ce26e7 bellard
    int has_error_code, new_stack;
824 14ce26e7 bellard
    uint32_t e1, e2, e3, ss;
825 14ce26e7 bellard
    target_ulong old_eip, esp, offset;
826 14ce26e7 bellard
827 14ce26e7 bellard
    has_error_code = 0;
828 14ce26e7 bellard
    if (!is_int && !is_hw) {
829 14ce26e7 bellard
        switch(intno) {
830 14ce26e7 bellard
        case 8:
831 14ce26e7 bellard
        case 10:
832 14ce26e7 bellard
        case 11:
833 14ce26e7 bellard
        case 12:
834 14ce26e7 bellard
        case 13:
835 14ce26e7 bellard
        case 14:
836 14ce26e7 bellard
        case 17:
837 14ce26e7 bellard
            has_error_code = 1;
838 14ce26e7 bellard
            break;
839 14ce26e7 bellard
        }
840 14ce26e7 bellard
    }
841 14ce26e7 bellard
    if (is_int)
842 14ce26e7 bellard
        old_eip = next_eip;
843 14ce26e7 bellard
    else
844 14ce26e7 bellard
        old_eip = env->eip;
845 14ce26e7 bellard
846 14ce26e7 bellard
    dt = &env->idt;
847 14ce26e7 bellard
    if (intno * 16 + 15 > dt->limit)
848 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
849 14ce26e7 bellard
    ptr = dt->base + intno * 16;
850 14ce26e7 bellard
    e1 = ldl_kernel(ptr);
851 14ce26e7 bellard
    e2 = ldl_kernel(ptr + 4);
852 14ce26e7 bellard
    e3 = ldl_kernel(ptr + 8);
853 14ce26e7 bellard
    /* check gate type */
854 14ce26e7 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
855 14ce26e7 bellard
    switch(type) {
856 14ce26e7 bellard
    case 14: /* 386 interrupt gate */
857 14ce26e7 bellard
    case 15: /* 386 trap gate */
858 14ce26e7 bellard
        break;
859 14ce26e7 bellard
    default:
860 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
861 14ce26e7 bellard
        break;
862 14ce26e7 bellard
    }
863 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
864 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
865 14ce26e7 bellard
    /* check privledge if software int */
866 14ce26e7 bellard
    if (is_int && dpl < cpl)
867 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
868 14ce26e7 bellard
    /* check valid bit */
869 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
870 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
871 14ce26e7 bellard
    selector = e1 >> 16;
872 14ce26e7 bellard
    offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
873 14ce26e7 bellard
    ist = e2 & 7;
874 14ce26e7 bellard
    if ((selector & 0xfffc) == 0)
875 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
876 14ce26e7 bellard
877 14ce26e7 bellard
    if (load_segment(&e1, &e2, selector) != 0)
878 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
879 14ce26e7 bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
880 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
881 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
882 14ce26e7 bellard
    if (dpl > cpl)
883 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
884 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
885 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
886 14ce26e7 bellard
    if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
887 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
888 14ce26e7 bellard
    if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
889 14ce26e7 bellard
        /* to inner priviledge */
890 14ce26e7 bellard
        if (ist != 0)
891 14ce26e7 bellard
            esp = get_rsp_from_tss(ist + 3);
892 14ce26e7 bellard
        else
893 14ce26e7 bellard
            esp = get_rsp_from_tss(dpl);
894 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
895 14ce26e7 bellard
        ss = 0;
896 14ce26e7 bellard
        new_stack = 1;
897 14ce26e7 bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
898 14ce26e7 bellard
        /* to same priviledge */
899 14ce26e7 bellard
        if (env->eflags & VM_MASK)
900 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
901 14ce26e7 bellard
        new_stack = 0;
902 9540a78b bellard
        if (ist != 0)
903 9540a78b bellard
            esp = get_rsp_from_tss(ist + 3);
904 9540a78b bellard
        else
905 9540a78b bellard
            esp = ESP;
906 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
907 14ce26e7 bellard
        dpl = cpl;
908 14ce26e7 bellard
    } else {
909 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
910 14ce26e7 bellard
        new_stack = 0; /* avoid warning */
911 14ce26e7 bellard
        esp = 0; /* avoid warning */
912 14ce26e7 bellard
    }
913 14ce26e7 bellard
914 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_SS].selector);
915 14ce26e7 bellard
    PUSHQ(esp, ESP);
916 14ce26e7 bellard
    PUSHQ(esp, compute_eflags());
917 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_CS].selector);
918 14ce26e7 bellard
    PUSHQ(esp, old_eip);
919 14ce26e7 bellard
    if (has_error_code) {
920 14ce26e7 bellard
        PUSHQ(esp, error_code);
921 14ce26e7 bellard
    }
922 14ce26e7 bellard
    
923 14ce26e7 bellard
    if (new_stack) {
924 14ce26e7 bellard
        ss = 0 | dpl;
925 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
926 14ce26e7 bellard
    }
927 14ce26e7 bellard
    ESP = esp;
928 14ce26e7 bellard
929 14ce26e7 bellard
    selector = (selector & ~3) | dpl;
930 14ce26e7 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
931 14ce26e7 bellard
                   get_seg_base(e1, e2),
932 14ce26e7 bellard
                   get_seg_limit(e1, e2),
933 14ce26e7 bellard
                   e2);
934 14ce26e7 bellard
    cpu_x86_set_cpl(env, dpl);
935 14ce26e7 bellard
    env->eip = offset;
936 14ce26e7 bellard
937 14ce26e7 bellard
    /* interrupt gate clear IF mask */
938 14ce26e7 bellard
    if ((type & 1) == 0) {
939 14ce26e7 bellard
        env->eflags &= ~IF_MASK;
940 14ce26e7 bellard
    }
941 14ce26e7 bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
942 14ce26e7 bellard
}
943 f419b321 bellard
#endif
944 14ce26e7 bellard
945 06c2f506 bellard
void helper_syscall(int next_eip_addend)
946 14ce26e7 bellard
{
947 14ce26e7 bellard
    int selector;
948 14ce26e7 bellard
949 14ce26e7 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
950 14ce26e7 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
951 14ce26e7 bellard
    }
952 14ce26e7 bellard
    selector = (env->star >> 32) & 0xffff;
953 f419b321 bellard
#ifdef TARGET_X86_64
954 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
955 9540a78b bellard
        int code64;
956 9540a78b bellard
957 06c2f506 bellard
        ECX = env->eip + next_eip_addend;
958 14ce26e7 bellard
        env->regs[11] = compute_eflags();
959 9540a78b bellard
        
960 9540a78b bellard
        code64 = env->hflags & HF_CS64_MASK;
961 14ce26e7 bellard
962 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
963 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
964 14ce26e7 bellard
                           0, 0xffffffff, 
965 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
966 14ce26e7 bellard
                               DESC_S_MASK |
967 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
968 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
969 14ce26e7 bellard
                               0, 0xffffffff,
970 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
971 14ce26e7 bellard
                               DESC_S_MASK |
972 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
973 14ce26e7 bellard
        env->eflags &= ~env->fmask;
974 9540a78b bellard
        if (code64)
975 14ce26e7 bellard
            env->eip = env->lstar;
976 14ce26e7 bellard
        else
977 14ce26e7 bellard
            env->eip = env->cstar;
978 f419b321 bellard
    } else 
979 f419b321 bellard
#endif
980 f419b321 bellard
    {
981 06c2f506 bellard
        ECX = (uint32_t)(env->eip + next_eip_addend);
982 14ce26e7 bellard
        
983 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
984 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
985 14ce26e7 bellard
                           0, 0xffffffff, 
986 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
987 14ce26e7 bellard
                               DESC_S_MASK |
988 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
989 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
990 14ce26e7 bellard
                               0, 0xffffffff,
991 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
992 14ce26e7 bellard
                               DESC_S_MASK |
993 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
994 14ce26e7 bellard
        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
995 14ce26e7 bellard
        env->eip = (uint32_t)env->star;
996 14ce26e7 bellard
    }
997 14ce26e7 bellard
}
998 14ce26e7 bellard
999 14ce26e7 bellard
void helper_sysret(int dflag)
1000 14ce26e7 bellard
{
1001 14ce26e7 bellard
    int cpl, selector;
1002 14ce26e7 bellard
1003 f419b321 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
1004 f419b321 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
1005 f419b321 bellard
    }
1006 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1007 14ce26e7 bellard
    if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1008 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
1009 14ce26e7 bellard
    }
1010 14ce26e7 bellard
    selector = (env->star >> 48) & 0xffff;
1011 f419b321 bellard
#ifdef TARGET_X86_64
1012 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
1013 14ce26e7 bellard
        if (dflag == 2) {
1014 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 
1015 14ce26e7 bellard
                                   0, 0xffffffff, 
1016 14ce26e7 bellard
                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1017 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1018 14ce26e7 bellard
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | 
1019 14ce26e7 bellard
                                   DESC_L_MASK);
1020 14ce26e7 bellard
            env->eip = ECX;
1021 14ce26e7 bellard
        } else {
1022 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
1023 14ce26e7 bellard
                                   0, 0xffffffff, 
1024 14ce26e7 bellard
                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1025 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1026 14ce26e7 bellard
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1027 14ce26e7 bellard
            env->eip = (uint32_t)ECX;
1028 14ce26e7 bellard
        }
1029 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
1030 14ce26e7 bellard
                               0, 0xffffffff,
1031 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1032 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1033 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1034 31313213 bellard
        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | 
1035 31313213 bellard
                    IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1036 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1037 f419b321 bellard
    } else 
1038 f419b321 bellard
#endif
1039 f419b321 bellard
    {
1040 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
1041 14ce26e7 bellard
                               0, 0xffffffff, 
1042 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1043 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1044 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1045 14ce26e7 bellard
        env->eip = (uint32_t)ECX;
1046 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
1047 14ce26e7 bellard
                               0, 0xffffffff,
1048 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1049 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1050 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1051 14ce26e7 bellard
        env->eflags |= IF_MASK;
1052 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1053 14ce26e7 bellard
    }
1054 f419b321 bellard
#ifdef USE_KQEMU
1055 f419b321 bellard
    if (kqemu_is_ok(env)) {
1056 f419b321 bellard
        if (env->hflags & HF_LMA_MASK)
1057 f419b321 bellard
            CC_OP = CC_OP_EFLAGS;
1058 f419b321 bellard
        env->exception_index = -1;
1059 f419b321 bellard
        cpu_loop_exit();
1060 f419b321 bellard
    }
1061 14ce26e7 bellard
#endif
1062 f419b321 bellard
}
1063 14ce26e7 bellard
1064 2c0262af bellard
/* real mode interrupt */
1065 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
1066 4136f33c bellard
                              unsigned int next_eip)
1067 2c0262af bellard
{
1068 2c0262af bellard
    SegmentCache *dt;
1069 14ce26e7 bellard
    target_ulong ptr, ssp;
1070 2c0262af bellard
    int selector;
1071 2c0262af bellard
    uint32_t offset, esp;
1072 2c0262af bellard
    uint32_t old_cs, old_eip;
1073 2c0262af bellard
1074 2c0262af bellard
    /* real mode (simpler !) */
1075 2c0262af bellard
    dt = &env->idt;
1076 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
1077 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1078 2c0262af bellard
    ptr = dt->base + intno * 4;
1079 61382a50 bellard
    offset = lduw_kernel(ptr);
1080 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
1081 2c0262af bellard
    esp = ESP;
1082 2c0262af bellard
    ssp = env->segs[R_SS].base;
1083 2c0262af bellard
    if (is_int)
1084 2c0262af bellard
        old_eip = next_eip;
1085 2c0262af bellard
    else
1086 2c0262af bellard
        old_eip = env->eip;
1087 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
1088 891b38e4 bellard
    /* XXX: use SS segment size ? */
1089 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
1090 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
1091 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
1092 2c0262af bellard
    
1093 2c0262af bellard
    /* update processor state */
1094 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
1095 2c0262af bellard
    env->eip = offset;
1096 2c0262af bellard
    env->segs[R_CS].selector = selector;
1097 14ce26e7 bellard
    env->segs[R_CS].base = (selector << 4);
1098 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1099 2c0262af bellard
}
1100 2c0262af bellard
1101 2c0262af bellard
/* fake user mode interrupt */
1102 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
1103 14ce26e7 bellard
                       target_ulong next_eip)
1104 2c0262af bellard
{
1105 2c0262af bellard
    SegmentCache *dt;
1106 14ce26e7 bellard
    target_ulong ptr;
1107 2c0262af bellard
    int dpl, cpl;
1108 2c0262af bellard
    uint32_t e2;
1109 2c0262af bellard
1110 2c0262af bellard
    dt = &env->idt;
1111 2c0262af bellard
    ptr = dt->base + (intno * 8);
1112 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
1113 2c0262af bellard
    
1114 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1115 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1116 2c0262af bellard
    /* check privledge if software int */
1117 2c0262af bellard
    if (is_int && dpl < cpl)
1118 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1119 2c0262af bellard
1120 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
1121 2c0262af bellard
       exiting the emulation with the suitable exception and error
1122 2c0262af bellard
       code */
1123 2c0262af bellard
    if (is_int)
1124 2c0262af bellard
        EIP = next_eip;
1125 2c0262af bellard
}
1126 2c0262af bellard
1127 2c0262af bellard
/*
1128 e19e89a5 bellard
 * Begin execution of an interruption. is_int is TRUE if coming from
1129 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
1130 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
1131 2c0262af bellard
 */
1132 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
1133 14ce26e7 bellard
                  target_ulong next_eip, int is_hw)
1134 2c0262af bellard
{
1135 1247c5f7 bellard
    if (loglevel & CPU_LOG_INT) {
1136 e19e89a5 bellard
        if ((env->cr[0] & CR0_PE_MASK)) {
1137 e19e89a5 bellard
            static int count;
1138 14ce26e7 bellard
            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1139 dc6f57fd bellard
                    count, intno, error_code, is_int,
1140 dc6f57fd bellard
                    env->hflags & HF_CPL_MASK,
1141 dc6f57fd bellard
                    env->segs[R_CS].selector, EIP,
1142 2ee73ac3 bellard
                    (int)env->segs[R_CS].base + EIP,
1143 8145122b bellard
                    env->segs[R_SS].selector, ESP);
1144 8145122b bellard
            if (intno == 0x0e) {
1145 14ce26e7 bellard
                fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1146 8145122b bellard
            } else {
1147 14ce26e7 bellard
                fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1148 8145122b bellard
            }
1149 e19e89a5 bellard
            fprintf(logfile, "\n");
1150 06c2f506 bellard
            cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1151 1247c5f7 bellard
#if 0
1152 e19e89a5 bellard
            {
1153 e19e89a5 bellard
                int i;
1154 e19e89a5 bellard
                uint8_t *ptr;
1155 e19e89a5 bellard
                fprintf(logfile, "       code=");
1156 e19e89a5 bellard
                ptr = env->segs[R_CS].base + env->eip;
1157 e19e89a5 bellard
                for(i = 0; i < 16; i++) {
1158 e19e89a5 bellard
                    fprintf(logfile, " %02x", ldub(ptr + i));
1159 dc6f57fd bellard
                }
1160 e19e89a5 bellard
                fprintf(logfile, "\n");
1161 dc6f57fd bellard
            }
1162 8e682019 bellard
#endif
1163 e19e89a5 bellard
            count++;
1164 4136f33c bellard
        }
1165 4136f33c bellard
    }
1166 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
1167 14ce26e7 bellard
#if TARGET_X86_64
1168 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1169 14ce26e7 bellard
            do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1170 14ce26e7 bellard
        } else
1171 14ce26e7 bellard
#endif
1172 14ce26e7 bellard
        {
1173 14ce26e7 bellard
            do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1174 14ce26e7 bellard
        }
1175 2c0262af bellard
    } else {
1176 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
1177 2c0262af bellard
    }
1178 2c0262af bellard
}
1179 2c0262af bellard
1180 2c0262af bellard
/*
1181 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
1182 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
1183 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
1184 2c0262af bellard
 * is_int is TRUE.  
1185 2c0262af bellard
 */
1186 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
1187 a8ede8ba bellard
                     int next_eip_addend)
1188 2c0262af bellard
{
1189 2c0262af bellard
    env->exception_index = intno;
1190 2c0262af bellard
    env->error_code = error_code;
1191 2c0262af bellard
    env->exception_is_int = is_int;
1192 a8ede8ba bellard
    env->exception_next_eip = env->eip + next_eip_addend;
1193 2c0262af bellard
    cpu_loop_exit();
1194 2c0262af bellard
}
1195 2c0262af bellard
1196 0d1a29f9 bellard
/* same as raise_exception_err, but do not restore global registers */
1197 0d1a29f9 bellard
static void raise_exception_err_norestore(int exception_index, int error_code)
1198 0d1a29f9 bellard
{
1199 0d1a29f9 bellard
    env->exception_index = exception_index;
1200 0d1a29f9 bellard
    env->error_code = error_code;
1201 0d1a29f9 bellard
    env->exception_is_int = 0;
1202 0d1a29f9 bellard
    env->exception_next_eip = 0;
1203 0d1a29f9 bellard
    longjmp(env->jmp_env, 1);
1204 0d1a29f9 bellard
}
1205 0d1a29f9 bellard
1206 2c0262af bellard
/* shortcuts to generate exceptions */
1207 8145122b bellard
1208 8145122b bellard
void (raise_exception_err)(int exception_index, int error_code)
1209 2c0262af bellard
{
1210 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
1211 2c0262af bellard
}
1212 2c0262af bellard
1213 2c0262af bellard
void raise_exception(int exception_index)
1214 2c0262af bellard
{
1215 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
1216 2c0262af bellard
}
1217 2c0262af bellard
1218 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1219 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1220 2c0262af bellard
   call it from another function */
1221 45bbbb46 bellard
uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1222 2c0262af bellard
{
1223 2c0262af bellard
    *q_ptr = num / den;
1224 2c0262af bellard
    return num % den;
1225 2c0262af bellard
}
1226 2c0262af bellard
1227 45bbbb46 bellard
int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1228 2c0262af bellard
{
1229 2c0262af bellard
    *q_ptr = num / den;
1230 2c0262af bellard
    return num % den;
1231 2c0262af bellard
}
1232 2c0262af bellard
#endif
1233 2c0262af bellard
1234 14ce26e7 bellard
void helper_divl_EAX_T0(void)
1235 2c0262af bellard
{
1236 45bbbb46 bellard
    unsigned int den, r;
1237 45bbbb46 bellard
    uint64_t num, q;
1238 2c0262af bellard
    
1239 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1240 2c0262af bellard
    den = T0;
1241 2c0262af bellard
    if (den == 0) {
1242 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1243 2c0262af bellard
    }
1244 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1245 14ce26e7 bellard
    r = div32(&q, num, den);
1246 2c0262af bellard
#else
1247 2c0262af bellard
    q = (num / den);
1248 2c0262af bellard
    r = (num % den);
1249 2c0262af bellard
#endif
1250 45bbbb46 bellard
    if (q > 0xffffffff)
1251 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1252 14ce26e7 bellard
    EAX = (uint32_t)q;
1253 14ce26e7 bellard
    EDX = (uint32_t)r;
1254 2c0262af bellard
}
1255 2c0262af bellard
1256 14ce26e7 bellard
void helper_idivl_EAX_T0(void)
1257 2c0262af bellard
{
1258 45bbbb46 bellard
    int den, r;
1259 45bbbb46 bellard
    int64_t num, q;
1260 2c0262af bellard
    
1261 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1262 2c0262af bellard
    den = T0;
1263 2c0262af bellard
    if (den == 0) {
1264 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1265 2c0262af bellard
    }
1266 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1267 14ce26e7 bellard
    r = idiv32(&q, num, den);
1268 2c0262af bellard
#else
1269 2c0262af bellard
    q = (num / den);
1270 2c0262af bellard
    r = (num % den);
1271 2c0262af bellard
#endif
1272 45bbbb46 bellard
    if (q != (int32_t)q)
1273 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1274 14ce26e7 bellard
    EAX = (uint32_t)q;
1275 14ce26e7 bellard
    EDX = (uint32_t)r;
1276 2c0262af bellard
}
1277 2c0262af bellard
1278 2c0262af bellard
void helper_cmpxchg8b(void)
1279 2c0262af bellard
{
1280 2c0262af bellard
    uint64_t d;
1281 2c0262af bellard
    int eflags;
1282 2c0262af bellard
1283 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
1284 14ce26e7 bellard
    d = ldq(A0);
1285 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
1286 14ce26e7 bellard
        stq(A0, ((uint64_t)ECX << 32) | EBX);
1287 2c0262af bellard
        eflags |= CC_Z;
1288 2c0262af bellard
    } else {
1289 2c0262af bellard
        EDX = d >> 32;
1290 2c0262af bellard
        EAX = d;
1291 2c0262af bellard
        eflags &= ~CC_Z;
1292 2c0262af bellard
    }
1293 2c0262af bellard
    CC_SRC = eflags;
1294 2c0262af bellard
}
1295 2c0262af bellard
1296 2c0262af bellard
void helper_cpuid(void)
1297 2c0262af bellard
{
1298 f419b321 bellard
    uint32_t index;
1299 f419b321 bellard
    index = (uint32_t)EAX;
1300 f419b321 bellard
    
1301 f419b321 bellard
    /* test if maximum index reached */
1302 f419b321 bellard
    if (index & 0x80000000) {
1303 f419b321 bellard
        if (index > env->cpuid_xlevel) 
1304 f419b321 bellard
            index = env->cpuid_level;
1305 f419b321 bellard
    } else {
1306 f419b321 bellard
        if (index > env->cpuid_level) 
1307 f419b321 bellard
            index = env->cpuid_level;
1308 f419b321 bellard
    }
1309 f419b321 bellard
        
1310 f419b321 bellard
    switch(index) {
1311 8e682019 bellard
    case 0:
1312 f419b321 bellard
        EAX = env->cpuid_level;
1313 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1314 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1315 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1316 8e682019 bellard
        break;
1317 8e682019 bellard
    case 1:
1318 14ce26e7 bellard
        EAX = env->cpuid_version;
1319 1f3358c8 bellard
        EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
1320 9df217a3 bellard
        ECX = env->cpuid_ext_features;
1321 14ce26e7 bellard
        EDX = env->cpuid_features;
1322 8e682019 bellard
        break;
1323 f419b321 bellard
    case 2:
1324 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1325 8e682019 bellard
        EAX = 0x410601;
1326 2c0262af bellard
        EBX = 0;
1327 2c0262af bellard
        ECX = 0;
1328 8e682019 bellard
        EDX = 0;
1329 8e682019 bellard
        break;
1330 14ce26e7 bellard
    case 0x80000000:
1331 f419b321 bellard
        EAX = env->cpuid_xlevel;
1332 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1333 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1334 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1335 14ce26e7 bellard
        break;
1336 14ce26e7 bellard
    case 0x80000001:
1337 14ce26e7 bellard
        EAX = env->cpuid_features;
1338 14ce26e7 bellard
        EBX = 0;
1339 14ce26e7 bellard
        ECX = 0;
1340 f419b321 bellard
        EDX = env->cpuid_ext2_features;
1341 f419b321 bellard
        break;
1342 f419b321 bellard
    case 0x80000002:
1343 f419b321 bellard
    case 0x80000003:
1344 f419b321 bellard
    case 0x80000004:
1345 f419b321 bellard
        EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
1346 f419b321 bellard
        EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
1347 f419b321 bellard
        ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
1348 f419b321 bellard
        EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
1349 14ce26e7 bellard
        break;
1350 8f091a59 bellard
    case 0x80000005:
1351 8f091a59 bellard
        /* cache info (L1 cache) */
1352 8f091a59 bellard
        EAX = 0x01ff01ff;
1353 8f091a59 bellard
        EBX = 0x01ff01ff;
1354 8f091a59 bellard
        ECX = 0x40020140;
1355 8f091a59 bellard
        EDX = 0x40020140;
1356 8f091a59 bellard
        break;
1357 8f091a59 bellard
    case 0x80000006:
1358 8f091a59 bellard
        /* cache info (L2 cache) */
1359 8f091a59 bellard
        EAX = 0;
1360 8f091a59 bellard
        EBX = 0x42004200;
1361 8f091a59 bellard
        ECX = 0x02008140;
1362 8f091a59 bellard
        EDX = 0;
1363 8f091a59 bellard
        break;
1364 14ce26e7 bellard
    case 0x80000008:
1365 14ce26e7 bellard
        /* virtual & phys address size in low 2 bytes. */
1366 14ce26e7 bellard
        EAX = 0x00003028;
1367 14ce26e7 bellard
        EBX = 0;
1368 14ce26e7 bellard
        ECX = 0;
1369 14ce26e7 bellard
        EDX = 0;
1370 14ce26e7 bellard
        break;
1371 f419b321 bellard
    default:
1372 f419b321 bellard
        /* reserved values: zero */
1373 f419b321 bellard
        EAX = 0;
1374 f419b321 bellard
        EBX = 0;
1375 f419b321 bellard
        ECX = 0;
1376 f419b321 bellard
        EDX = 0;
1377 f419b321 bellard
        break;
1378 2c0262af bellard
    }
1379 2c0262af bellard
}
1380 2c0262af bellard
1381 61a8c4ec bellard
void helper_enter_level(int level, int data32)
1382 61a8c4ec bellard
{
1383 14ce26e7 bellard
    target_ulong ssp;
1384 61a8c4ec bellard
    uint32_t esp_mask, esp, ebp;
1385 61a8c4ec bellard
1386 61a8c4ec bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1387 61a8c4ec bellard
    ssp = env->segs[R_SS].base;
1388 61a8c4ec bellard
    ebp = EBP;
1389 61a8c4ec bellard
    esp = ESP;
1390 61a8c4ec bellard
    if (data32) {
1391 61a8c4ec bellard
        /* 32 bit */
1392 61a8c4ec bellard
        esp -= 4;
1393 61a8c4ec bellard
        while (--level) {
1394 61a8c4ec bellard
            esp -= 4;
1395 61a8c4ec bellard
            ebp -= 4;
1396 61a8c4ec bellard
            stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1397 61a8c4ec bellard
        }
1398 61a8c4ec bellard
        esp -= 4;
1399 61a8c4ec bellard
        stl(ssp + (esp & esp_mask), T1);
1400 61a8c4ec bellard
    } else {
1401 61a8c4ec bellard
        /* 16 bit */
1402 61a8c4ec bellard
        esp -= 2;
1403 61a8c4ec bellard
        while (--level) {
1404 61a8c4ec bellard
            esp -= 2;
1405 61a8c4ec bellard
            ebp -= 2;
1406 61a8c4ec bellard
            stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1407 61a8c4ec bellard
        }
1408 61a8c4ec bellard
        esp -= 2;
1409 61a8c4ec bellard
        stw(ssp + (esp & esp_mask), T1);
1410 61a8c4ec bellard
    }
1411 61a8c4ec bellard
}
1412 61a8c4ec bellard
1413 8f091a59 bellard
#ifdef TARGET_X86_64
1414 8f091a59 bellard
void helper_enter64_level(int level, int data64)
1415 8f091a59 bellard
{
1416 8f091a59 bellard
    target_ulong esp, ebp;
1417 8f091a59 bellard
    ebp = EBP;
1418 8f091a59 bellard
    esp = ESP;
1419 8f091a59 bellard
1420 8f091a59 bellard
    if (data64) {
1421 8f091a59 bellard
        /* 64 bit */
1422 8f091a59 bellard
        esp -= 8;
1423 8f091a59 bellard
        while (--level) {
1424 8f091a59 bellard
            esp -= 8;
1425 8f091a59 bellard
            ebp -= 8;
1426 8f091a59 bellard
            stq(esp, ldq(ebp));
1427 8f091a59 bellard
        }
1428 8f091a59 bellard
        esp -= 8;
1429 8f091a59 bellard
        stq(esp, T1);
1430 8f091a59 bellard
    } else {
1431 8f091a59 bellard
        /* 16 bit */
1432 8f091a59 bellard
        esp -= 2;
1433 8f091a59 bellard
        while (--level) {
1434 8f091a59 bellard
            esp -= 2;
1435 8f091a59 bellard
            ebp -= 2;
1436 8f091a59 bellard
            stw(esp, lduw(ebp));
1437 8f091a59 bellard
        }
1438 8f091a59 bellard
        esp -= 2;
1439 8f091a59 bellard
        stw(esp, T1);
1440 8f091a59 bellard
    }
1441 8f091a59 bellard
}
1442 8f091a59 bellard
#endif
1443 8f091a59 bellard
1444 2c0262af bellard
void helper_lldt_T0(void)
1445 2c0262af bellard
{
1446 2c0262af bellard
    int selector;
1447 2c0262af bellard
    SegmentCache *dt;
1448 2c0262af bellard
    uint32_t e1, e2;
1449 14ce26e7 bellard
    int index, entry_limit;
1450 14ce26e7 bellard
    target_ulong ptr;
1451 2c0262af bellard
    
1452 2c0262af bellard
    selector = T0 & 0xffff;
1453 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1454 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1455 14ce26e7 bellard
        env->ldt.base = 0;
1456 2c0262af bellard
        env->ldt.limit = 0;
1457 2c0262af bellard
    } else {
1458 2c0262af bellard
        if (selector & 0x4)
1459 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1460 2c0262af bellard
        dt = &env->gdt;
1461 2c0262af bellard
        index = selector & ~7;
1462 14ce26e7 bellard
#ifdef TARGET_X86_64
1463 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1464 14ce26e7 bellard
            entry_limit = 15;
1465 14ce26e7 bellard
        else
1466 14ce26e7 bellard
#endif            
1467 14ce26e7 bellard
            entry_limit = 7;
1468 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1469 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1470 2c0262af bellard
        ptr = dt->base + index;
1471 61382a50 bellard
        e1 = ldl_kernel(ptr);
1472 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1473 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1474 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1475 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1476 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1477 14ce26e7 bellard
#ifdef TARGET_X86_64
1478 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1479 14ce26e7 bellard
            uint32_t e3;
1480 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1481 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1482 14ce26e7 bellard
            env->ldt.base |= (target_ulong)e3 << 32;
1483 14ce26e7 bellard
        } else
1484 14ce26e7 bellard
#endif
1485 14ce26e7 bellard
        {
1486 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1487 14ce26e7 bellard
        }
1488 2c0262af bellard
    }
1489 2c0262af bellard
    env->ldt.selector = selector;
1490 2c0262af bellard
}
1491 2c0262af bellard
1492 2c0262af bellard
void helper_ltr_T0(void)
1493 2c0262af bellard
{
1494 2c0262af bellard
    int selector;
1495 2c0262af bellard
    SegmentCache *dt;
1496 2c0262af bellard
    uint32_t e1, e2;
1497 14ce26e7 bellard
    int index, type, entry_limit;
1498 14ce26e7 bellard
    target_ulong ptr;
1499 2c0262af bellard
    
1500 2c0262af bellard
    selector = T0 & 0xffff;
1501 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1502 14ce26e7 bellard
        /* NULL selector case: invalid TR */
1503 14ce26e7 bellard
        env->tr.base = 0;
1504 2c0262af bellard
        env->tr.limit = 0;
1505 2c0262af bellard
        env->tr.flags = 0;
1506 2c0262af bellard
    } else {
1507 2c0262af bellard
        if (selector & 0x4)
1508 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1509 2c0262af bellard
        dt = &env->gdt;
1510 2c0262af bellard
        index = selector & ~7;
1511 14ce26e7 bellard
#ifdef TARGET_X86_64
1512 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1513 14ce26e7 bellard
            entry_limit = 15;
1514 14ce26e7 bellard
        else
1515 14ce26e7 bellard
#endif            
1516 14ce26e7 bellard
            entry_limit = 7;
1517 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1518 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1519 2c0262af bellard
        ptr = dt->base + index;
1520 61382a50 bellard
        e1 = ldl_kernel(ptr);
1521 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1522 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1523 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
1524 7e84c249 bellard
            (type != 1 && type != 9))
1525 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1526 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1527 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1528 14ce26e7 bellard
#ifdef TARGET_X86_64
1529 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1530 14ce26e7 bellard
            uint32_t e3;
1531 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1532 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1533 14ce26e7 bellard
            env->tr.base |= (target_ulong)e3 << 32;
1534 14ce26e7 bellard
        } else 
1535 14ce26e7 bellard
#endif
1536 14ce26e7 bellard
        {
1537 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1538 14ce26e7 bellard
        }
1539 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1540 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1541 2c0262af bellard
    }
1542 2c0262af bellard
    env->tr.selector = selector;
1543 2c0262af bellard
}
1544 2c0262af bellard
1545 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1546 8e682019 bellard
void load_seg(int seg_reg, int selector)
1547 2c0262af bellard
{
1548 2c0262af bellard
    uint32_t e1, e2;
1549 3ab493de bellard
    int cpl, dpl, rpl;
1550 3ab493de bellard
    SegmentCache *dt;
1551 3ab493de bellard
    int index;
1552 14ce26e7 bellard
    target_ulong ptr;
1553 3ab493de bellard
1554 8e682019 bellard
    selector &= 0xffff;
1555 b359d4e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1556 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1557 2c0262af bellard
        /* null selector case */
1558 4d6b6c0a bellard
        if (seg_reg == R_SS
1559 4d6b6c0a bellard
#ifdef TARGET_X86_64
1560 b359d4e7 bellard
            && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
1561 4d6b6c0a bellard
#endif
1562 4d6b6c0a bellard
            )
1563 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1564 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
1565 2c0262af bellard
    } else {
1566 3ab493de bellard
        
1567 3ab493de bellard
        if (selector & 0x4)
1568 3ab493de bellard
            dt = &env->ldt;
1569 3ab493de bellard
        else
1570 3ab493de bellard
            dt = &env->gdt;
1571 3ab493de bellard
        index = selector & ~7;
1572 8e682019 bellard
        if ((index + 7) > dt->limit)
1573 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1574 3ab493de bellard
        ptr = dt->base + index;
1575 3ab493de bellard
        e1 = ldl_kernel(ptr);
1576 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1577 14ce26e7 bellard
        
1578 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1579 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1580 3ab493de bellard
        rpl = selector & 3;
1581 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1582 2c0262af bellard
        if (seg_reg == R_SS) {
1583 3ab493de bellard
            /* must be writable segment */
1584 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1585 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1586 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1587 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1588 2c0262af bellard
        } else {
1589 3ab493de bellard
            /* must be readable segment */
1590 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1591 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1592 3ab493de bellard
            
1593 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1594 3ab493de bellard
                /* if not conforming code, test rights */
1595 89984cd2 bellard
                if (dpl < cpl || dpl < rpl) 
1596 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1597 3ab493de bellard
            }
1598 2c0262af bellard
        }
1599 2c0262af bellard
1600 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1601 2c0262af bellard
            if (seg_reg == R_SS)
1602 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1603 2c0262af bellard
            else
1604 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1605 2c0262af bellard
        }
1606 3ab493de bellard
1607 3ab493de bellard
        /* set the access bit if not already set */
1608 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1609 3ab493de bellard
            e2 |= DESC_A_MASK;
1610 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1611 3ab493de bellard
        }
1612 3ab493de bellard
1613 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
1614 2c0262af bellard
                       get_seg_base(e1, e2),
1615 2c0262af bellard
                       get_seg_limit(e1, e2),
1616 2c0262af bellard
                       e2);
1617 2c0262af bellard
#if 0
1618 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
1619 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1620 2c0262af bellard
#endif
1621 2c0262af bellard
    }
1622 2c0262af bellard
}
1623 2c0262af bellard
1624 2c0262af bellard
/* protected mode jump */
1625 f419b321 bellard
void helper_ljmp_protected_T0_T1(int next_eip_addend)
1626 2c0262af bellard
{
1627 14ce26e7 bellard
    int new_cs, gate_cs, type;
1628 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
1629 f419b321 bellard
    target_ulong new_eip, next_eip;
1630 14ce26e7 bellard
    
1631 2c0262af bellard
    new_cs = T0;
1632 2c0262af bellard
    new_eip = T1;
1633 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1634 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1635 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1636 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1637 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1638 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1639 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1640 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1641 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1642 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1643 2c0262af bellard
            /* conforming code segment */
1644 2c0262af bellard
            if (dpl > cpl)
1645 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1646 2c0262af bellard
        } else {
1647 2c0262af bellard
            /* non conforming code segment */
1648 2c0262af bellard
            rpl = new_cs & 3;
1649 2c0262af bellard
            if (rpl > cpl)
1650 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1651 2c0262af bellard
            if (dpl != cpl)
1652 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1653 2c0262af bellard
        }
1654 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1655 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1656 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1657 ca954f6d bellard
        if (new_eip > limit && 
1658 ca954f6d bellard
            !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
1659 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1660 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1661 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1662 2c0262af bellard
        EIP = new_eip;
1663 2c0262af bellard
    } else {
1664 7e84c249 bellard
        /* jump to call or task gate */
1665 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1666 7e84c249 bellard
        rpl = new_cs & 3;
1667 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
1668 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1669 7e84c249 bellard
        switch(type) {
1670 7e84c249 bellard
        case 1: /* 286 TSS */
1671 7e84c249 bellard
        case 9: /* 386 TSS */
1672 7e84c249 bellard
        case 5: /* task gate */
1673 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1674 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1675 f419b321 bellard
            next_eip = env->eip + next_eip_addend;
1676 08cea4ee bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
1677 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
1678 7e84c249 bellard
            break;
1679 7e84c249 bellard
        case 4: /* 286 call gate */
1680 7e84c249 bellard
        case 12: /* 386 call gate */
1681 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
1682 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1683 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1684 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1685 7e84c249 bellard
            gate_cs = e1 >> 16;
1686 516633dc bellard
            new_eip = (e1 & 0xffff);
1687 516633dc bellard
            if (type == 12)
1688 516633dc bellard
                new_eip |= (e2 & 0xffff0000);
1689 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
1690 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1691 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1692 7e84c249 bellard
            /* must be code segment */
1693 7e84c249 bellard
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
1694 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
1695 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1696 14ce26e7 bellard
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) || 
1697 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1698 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1699 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1700 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1701 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
1702 7e84c249 bellard
            if (new_eip > limit)
1703 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
1704 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1705 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
1706 7e84c249 bellard
            EIP = new_eip;
1707 7e84c249 bellard
            break;
1708 7e84c249 bellard
        default:
1709 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1710 7e84c249 bellard
            break;
1711 7e84c249 bellard
        }
1712 2c0262af bellard
    }
1713 2c0262af bellard
}
1714 2c0262af bellard
1715 2c0262af bellard
/* real mode call */
1716 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
1717 2c0262af bellard
{
1718 2c0262af bellard
    int new_cs, new_eip;
1719 2c0262af bellard
    uint32_t esp, esp_mask;
1720 14ce26e7 bellard
    target_ulong ssp;
1721 2c0262af bellard
1722 2c0262af bellard
    new_cs = T0;
1723 2c0262af bellard
    new_eip = T1;
1724 2c0262af bellard
    esp = ESP;
1725 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1726 2c0262af bellard
    ssp = env->segs[R_SS].base;
1727 2c0262af bellard
    if (shift) {
1728 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1729 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
1730 2c0262af bellard
    } else {
1731 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1732 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
1733 2c0262af bellard
    }
1734 2c0262af bellard
1735 891b38e4 bellard
    ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1736 2c0262af bellard
    env->eip = new_eip;
1737 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
1738 14ce26e7 bellard
    env->segs[R_CS].base = (new_cs << 4);
1739 2c0262af bellard
}
1740 2c0262af bellard
1741 2c0262af bellard
/* protected mode call */
1742 f419b321 bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
1743 2c0262af bellard
{
1744 649ea05a bellard
    int new_cs, new_stack, i;
1745 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1746 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1747 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
1748 649ea05a bellard
    target_ulong ssp, old_ssp, next_eip, new_eip;
1749 2c0262af bellard
    
1750 2c0262af bellard
    new_cs = T0;
1751 2c0262af bellard
    new_eip = T1;
1752 f419b321 bellard
    next_eip = env->eip + next_eip_addend;
1753 f3f2d9be bellard
#ifdef DEBUG_PCALL
1754 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
1755 e19e89a5 bellard
        fprintf(logfile, "lcall %04x:%08x s=%d\n",
1756 649ea05a bellard
                new_cs, (uint32_t)new_eip, shift);
1757 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1758 f3f2d9be bellard
    }
1759 f3f2d9be bellard
#endif
1760 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1761 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1762 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1763 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1764 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1765 f3f2d9be bellard
#ifdef DEBUG_PCALL
1766 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
1767 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1768 f3f2d9be bellard
    }
1769 f3f2d9be bellard
#endif
1770 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1771 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1772 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1773 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1774 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1775 2c0262af bellard
            /* conforming code segment */
1776 2c0262af bellard
            if (dpl > cpl)
1777 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1778 2c0262af bellard
        } else {
1779 2c0262af bellard
            /* non conforming code segment */
1780 2c0262af bellard
            rpl = new_cs & 3;
1781 2c0262af bellard
            if (rpl > cpl)
1782 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1783 2c0262af bellard
            if (dpl != cpl)
1784 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1785 2c0262af bellard
        }
1786 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1787 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1788 2c0262af bellard
1789 f419b321 bellard
#ifdef TARGET_X86_64
1790 f419b321 bellard
        /* XXX: check 16/32 bit cases in long mode */
1791 f419b321 bellard
        if (shift == 2) {
1792 f419b321 bellard
            target_ulong rsp;
1793 f419b321 bellard
            /* 64 bit case */
1794 f419b321 bellard
            rsp = ESP;
1795 f419b321 bellard
            PUSHQ(rsp, env->segs[R_CS].selector);
1796 f419b321 bellard
            PUSHQ(rsp, next_eip);
1797 f419b321 bellard
            /* from this point, not restartable */
1798 f419b321 bellard
            ESP = rsp;
1799 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1800 f419b321 bellard
                                   get_seg_base(e1, e2), 
1801 f419b321 bellard
                                   get_seg_limit(e1, e2), e2);
1802 f419b321 bellard
            EIP = new_eip;
1803 f419b321 bellard
        } else 
1804 f419b321 bellard
#endif
1805 f419b321 bellard
        {
1806 f419b321 bellard
            sp = ESP;
1807 f419b321 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
1808 f419b321 bellard
            ssp = env->segs[R_SS].base;
1809 f419b321 bellard
            if (shift) {
1810 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1811 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, next_eip);
1812 f419b321 bellard
            } else {
1813 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1814 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, next_eip);
1815 f419b321 bellard
            }
1816 f419b321 bellard
            
1817 f419b321 bellard
            limit = get_seg_limit(e1, e2);
1818 f419b321 bellard
            if (new_eip > limit)
1819 f419b321 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1820 f419b321 bellard
            /* from this point, not restartable */
1821 f419b321 bellard
            ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1822 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1823 f419b321 bellard
                                   get_seg_base(e1, e2), limit, e2);
1824 f419b321 bellard
            EIP = new_eip;
1825 2c0262af bellard
        }
1826 2c0262af bellard
    } else {
1827 2c0262af bellard
        /* check gate type */
1828 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1829 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1830 7e84c249 bellard
        rpl = new_cs & 3;
1831 2c0262af bellard
        switch(type) {
1832 2c0262af bellard
        case 1: /* available 286 TSS */
1833 2c0262af bellard
        case 9: /* available 386 TSS */
1834 2c0262af bellard
        case 5: /* task gate */
1835 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1836 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1837 883da8e2 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
1838 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
1839 8145122b bellard
            return;
1840 2c0262af bellard
        case 4: /* 286 call gate */
1841 2c0262af bellard
        case 12: /* 386 call gate */
1842 2c0262af bellard
            break;
1843 2c0262af bellard
        default:
1844 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1845 2c0262af bellard
            break;
1846 2c0262af bellard
        }
1847 2c0262af bellard
        shift = type >> 3;
1848 2c0262af bellard
1849 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
1850 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1851 2c0262af bellard
        /* check valid bit */
1852 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1853 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
1854 2c0262af bellard
        selector = e1 >> 16;
1855 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1856 f3f2d9be bellard
        param_count = e2 & 0x1f;
1857 2c0262af bellard
        if ((selector & 0xfffc) == 0)
1858 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1859 2c0262af bellard
1860 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
1861 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1862 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1863 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1864 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1865 2c0262af bellard
        if (dpl > cpl)
1866 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1867 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1868 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1869 2c0262af bellard
1870 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1871 2c0262af bellard
            /* to inner priviledge */
1872 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
1873 f3f2d9be bellard
#ifdef DEBUG_PCALL
1874 e19e89a5 bellard
            if (loglevel & CPU_LOG_PCALL)
1875 14ce26e7 bellard
                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", 
1876 f3f2d9be bellard
                        ss, sp, param_count, ESP);
1877 f3f2d9be bellard
#endif
1878 2c0262af bellard
            if ((ss & 0xfffc) == 0)
1879 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1880 2c0262af bellard
            if ((ss & 3) != dpl)
1881 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1882 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1883 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1884 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1885 2c0262af bellard
            if (ss_dpl != dpl)
1886 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1887 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
1888 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
1889 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
1890 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1891 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
1892 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1893 2c0262af bellard
            
1894 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
1895 2c0262af bellard
1896 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1897 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
1898 2c0262af bellard
            
1899 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
1900 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
1901 2c0262af bellard
            if (shift) {
1902 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1903 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
1904 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1905 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1906 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
1907 2c0262af bellard
                }
1908 2c0262af bellard
            } else {
1909 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1910 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
1911 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1912 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1913 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
1914 2c0262af bellard
                }
1915 2c0262af bellard
            }
1916 891b38e4 bellard
            new_stack = 1;
1917 2c0262af bellard
        } else {
1918 2c0262af bellard
            /* to same priviledge */
1919 891b38e4 bellard
            sp = ESP;
1920 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
1921 891b38e4 bellard
            ssp = env->segs[R_SS].base;
1922 891b38e4 bellard
            //            push_size = (4 << shift);
1923 891b38e4 bellard
            new_stack = 0;
1924 2c0262af bellard
        }
1925 2c0262af bellard
1926 2c0262af bellard
        if (shift) {
1927 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1928 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1929 2c0262af bellard
        } else {
1930 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1931 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1932 891b38e4 bellard
        }
1933 891b38e4 bellard
1934 891b38e4 bellard
        /* from this point, not restartable */
1935 891b38e4 bellard
1936 891b38e4 bellard
        if (new_stack) {
1937 891b38e4 bellard
            ss = (ss & ~3) | dpl;
1938 891b38e4 bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
1939 891b38e4 bellard
                                   ssp,
1940 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
1941 891b38e4 bellard
                                   ss_e2);
1942 2c0262af bellard
        }
1943 2c0262af bellard
1944 2c0262af bellard
        selector = (selector & ~3) | dpl;
1945 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
1946 2c0262af bellard
                       get_seg_base(e1, e2),
1947 2c0262af bellard
                       get_seg_limit(e1, e2),
1948 2c0262af bellard
                       e2);
1949 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
1950 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1951 2c0262af bellard
        EIP = offset;
1952 2c0262af bellard
    }
1953 9df217a3 bellard
#ifdef USE_KQEMU
1954 9df217a3 bellard
    if (kqemu_is_ok(env)) {
1955 9df217a3 bellard
        env->exception_index = -1;
1956 9df217a3 bellard
        cpu_loop_exit();
1957 9df217a3 bellard
    }
1958 9df217a3 bellard
#endif
1959 2c0262af bellard
}
1960 2c0262af bellard
1961 7e84c249 bellard
/* real and vm86 mode iret */
1962 2c0262af bellard
void helper_iret_real(int shift)
1963 2c0262af bellard
{
1964 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1965 14ce26e7 bellard
    target_ulong ssp;
1966 2c0262af bellard
    int eflags_mask;
1967 7e84c249 bellard
1968 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1969 891b38e4 bellard
    sp = ESP;
1970 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1971 2c0262af bellard
    if (shift == 1) {
1972 2c0262af bellard
        /* 32 bits */
1973 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1974 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1975 891b38e4 bellard
        new_cs &= 0xffff;
1976 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
1977 2c0262af bellard
    } else {
1978 2c0262af bellard
        /* 16 bits */
1979 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1980 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1981 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
1982 2c0262af bellard
    }
1983 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1984 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1985 2c0262af bellard
    env->eip = new_eip;
1986 7e84c249 bellard
    if (env->eflags & VM_MASK)
1987 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
1988 7e84c249 bellard
    else
1989 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
1990 2c0262af bellard
    if (shift == 0)
1991 2c0262af bellard
        eflags_mask &= 0xffff;
1992 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
1993 2c0262af bellard
}
1994 2c0262af bellard
1995 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
1996 8e682019 bellard
{
1997 8e682019 bellard
    int dpl;
1998 8e682019 bellard
    uint32_t e2;
1999 cd072e01 bellard
2000 cd072e01 bellard
    /* XXX: on x86_64, we do not want to nullify FS and GS because
2001 cd072e01 bellard
       they may still contain a valid base. I would be interested to
2002 cd072e01 bellard
       know how a real x86_64 CPU behaves */
2003 cd072e01 bellard
    if ((seg_reg == R_FS || seg_reg == R_GS) && 
2004 cd072e01 bellard
        (env->segs[seg_reg].selector & 0xfffc) == 0)
2005 cd072e01 bellard
        return;
2006 cd072e01 bellard
2007 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
2008 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2009 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2010 8e682019 bellard
        /* data or non conforming code segment */
2011 8e682019 bellard
        if (dpl < cpl) {
2012 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2013 8e682019 bellard
        }
2014 8e682019 bellard
    }
2015 8e682019 bellard
}
2016 8e682019 bellard
2017 2c0262af bellard
/* protected mode iret */
2018 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
2019 2c0262af bellard
{
2020 14ce26e7 bellard
    uint32_t new_cs, new_eflags, new_ss;
2021 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
2022 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
2023 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
2024 14ce26e7 bellard
    target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2025 2c0262af bellard
    
2026 14ce26e7 bellard
#ifdef TARGET_X86_64
2027 14ce26e7 bellard
    if (shift == 2)
2028 14ce26e7 bellard
        sp_mask = -1;
2029 14ce26e7 bellard
    else
2030 14ce26e7 bellard
#endif
2031 14ce26e7 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
2032 2c0262af bellard
    sp = ESP;
2033 891b38e4 bellard
    ssp = env->segs[R_SS].base;
2034 354ff226 bellard
    new_eflags = 0; /* avoid warning */
2035 14ce26e7 bellard
#ifdef TARGET_X86_64
2036 14ce26e7 bellard
    if (shift == 2) {
2037 14ce26e7 bellard
        POPQ(sp, new_eip);
2038 14ce26e7 bellard
        POPQ(sp, new_cs);
2039 14ce26e7 bellard
        new_cs &= 0xffff;
2040 14ce26e7 bellard
        if (is_iret) {
2041 14ce26e7 bellard
            POPQ(sp, new_eflags);
2042 14ce26e7 bellard
        }
2043 14ce26e7 bellard
    } else
2044 14ce26e7 bellard
#endif
2045 2c0262af bellard
    if (shift == 1) {
2046 2c0262af bellard
        /* 32 bits */
2047 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
2048 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
2049 891b38e4 bellard
        new_cs &= 0xffff;
2050 891b38e4 bellard
        if (is_iret) {
2051 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
2052 891b38e4 bellard
            if (new_eflags & VM_MASK)
2053 891b38e4 bellard
                goto return_to_vm86;
2054 891b38e4 bellard
        }
2055 2c0262af bellard
    } else {
2056 2c0262af bellard
        /* 16 bits */
2057 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
2058 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
2059 2c0262af bellard
        if (is_iret)
2060 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
2061 2c0262af bellard
    }
2062 891b38e4 bellard
#ifdef DEBUG_PCALL
2063 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2064 14ce26e7 bellard
        fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2065 e19e89a5 bellard
                new_cs, new_eip, shift, addend);
2066 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2067 891b38e4 bellard
    }
2068 891b38e4 bellard
#endif
2069 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2070 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2071 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2072 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2073 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
2074 2c0262af bellard
        !(e2 & DESC_CS_MASK))
2075 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2076 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2077 2c0262af bellard
    rpl = new_cs & 3; 
2078 2c0262af bellard
    if (rpl < cpl)
2079 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2080 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2081 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
2082 2c0262af bellard
        if (dpl > rpl)
2083 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2084 2c0262af bellard
    } else {
2085 2c0262af bellard
        if (dpl != rpl)
2086 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2087 2c0262af bellard
    }
2088 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
2089 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2090 2c0262af bellard
    
2091 891b38e4 bellard
    sp += addend;
2092 ca954f6d bellard
    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || 
2093 ca954f6d bellard
                       ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2094 2c0262af bellard
        /* return to same priledge level */
2095 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
2096 2c0262af bellard
                       get_seg_base(e1, e2),
2097 2c0262af bellard
                       get_seg_limit(e1, e2),
2098 2c0262af bellard
                       e2);
2099 2c0262af bellard
    } else {
2100 2c0262af bellard
        /* return to different priviledge level */
2101 14ce26e7 bellard
#ifdef TARGET_X86_64
2102 14ce26e7 bellard
        if (shift == 2) {
2103 14ce26e7 bellard
            POPQ(sp, new_esp);
2104 14ce26e7 bellard
            POPQ(sp, new_ss);
2105 14ce26e7 bellard
            new_ss &= 0xffff;
2106 14ce26e7 bellard
        } else
2107 14ce26e7 bellard
#endif
2108 2c0262af bellard
        if (shift == 1) {
2109 2c0262af bellard
            /* 32 bits */
2110 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
2111 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
2112 891b38e4 bellard
            new_ss &= 0xffff;
2113 2c0262af bellard
        } else {
2114 2c0262af bellard
            /* 16 bits */
2115 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
2116 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
2117 2c0262af bellard
        }
2118 e19e89a5 bellard
#ifdef DEBUG_PCALL
2119 e19e89a5 bellard
        if (loglevel & CPU_LOG_PCALL) {
2120 14ce26e7 bellard
            fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2121 e19e89a5 bellard
                    new_ss, new_esp);
2122 e19e89a5 bellard
        }
2123 e19e89a5 bellard
#endif
2124 b359d4e7 bellard
        if ((new_ss & 0xfffc) == 0) {
2125 b359d4e7 bellard
#ifdef TARGET_X86_64
2126 b359d4e7 bellard
            /* NULL ss is allowed in long mode if cpl != 3*/
2127 b359d4e7 bellard
            if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2128 b359d4e7 bellard
                cpu_x86_load_seg_cache(env, R_SS, new_ss, 
2129 b359d4e7 bellard
                                       0, 0xffffffff,
2130 b359d4e7 bellard
                                       DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2131 b359d4e7 bellard
                                       DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2132 b359d4e7 bellard
                                       DESC_W_MASK | DESC_A_MASK);
2133 b359d4e7 bellard
            } else 
2134 b359d4e7 bellard
#endif
2135 b359d4e7 bellard
            {
2136 b359d4e7 bellard
                raise_exception_err(EXCP0D_GPF, 0);
2137 b359d4e7 bellard
            }
2138 14ce26e7 bellard
        } else {
2139 14ce26e7 bellard
            if ((new_ss & 3) != rpl)
2140 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2141 14ce26e7 bellard
            if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2142 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2143 14ce26e7 bellard
            if (!(ss_e2 & DESC_S_MASK) ||
2144 14ce26e7 bellard
                (ss_e2 & DESC_CS_MASK) ||
2145 14ce26e7 bellard
                !(ss_e2 & DESC_W_MASK))
2146 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2147 14ce26e7 bellard
            dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2148 14ce26e7 bellard
            if (dpl != rpl)
2149 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2150 14ce26e7 bellard
            if (!(ss_e2 & DESC_P_MASK))
2151 14ce26e7 bellard
                raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2152 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_SS, new_ss, 
2153 14ce26e7 bellard
                                   get_seg_base(ss_e1, ss_e2),
2154 14ce26e7 bellard
                                   get_seg_limit(ss_e1, ss_e2),
2155 14ce26e7 bellard
                                   ss_e2);
2156 14ce26e7 bellard
        }
2157 2c0262af bellard
2158 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
2159 2c0262af bellard
                       get_seg_base(e1, e2),
2160 2c0262af bellard
                       get_seg_limit(e1, e2),
2161 2c0262af bellard
                       e2);
2162 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
2163 891b38e4 bellard
        sp = new_esp;
2164 14ce26e7 bellard
#ifdef TARGET_X86_64
2165 2c8e0301 bellard
        if (env->hflags & HF_CS64_MASK)
2166 14ce26e7 bellard
            sp_mask = -1;
2167 14ce26e7 bellard
        else
2168 14ce26e7 bellard
#endif
2169 14ce26e7 bellard
            sp_mask = get_sp_mask(ss_e2);
2170 8e682019 bellard
2171 8e682019 bellard
        /* validate data segments */
2172 89984cd2 bellard
        validate_seg(R_ES, rpl);
2173 89984cd2 bellard
        validate_seg(R_DS, rpl);
2174 89984cd2 bellard
        validate_seg(R_FS, rpl);
2175 89984cd2 bellard
        validate_seg(R_GS, rpl);
2176 4afa6482 bellard
2177 4afa6482 bellard
        sp += addend;
2178 2c0262af bellard
    }
2179 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2180 2c0262af bellard
    env->eip = new_eip;
2181 2c0262af bellard
    if (is_iret) {
2182 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
2183 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2184 2c0262af bellard
        if (cpl == 0)
2185 4136f33c bellard
            eflags_mask |= IOPL_MASK;
2186 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
2187 4136f33c bellard
        if (cpl <= iopl)
2188 4136f33c bellard
            eflags_mask |= IF_MASK;
2189 2c0262af bellard
        if (shift == 0)
2190 2c0262af bellard
            eflags_mask &= 0xffff;
2191 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
2192 2c0262af bellard
    }
2193 2c0262af bellard
    return;
2194 2c0262af bellard
2195 2c0262af bellard
 return_to_vm86:
2196 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
2197 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
2198 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
2199 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
2200 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
2201 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
2202 2c0262af bellard
    
2203 2c0262af bellard
    /* modify processor state */
2204 4136f33c bellard
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
2205 8145122b bellard
                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2206 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
2207 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
2208 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
2209 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
2210 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
2211 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
2212 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
2213 2c0262af bellard
2214 fd836909 bellard
    env->eip = new_eip & 0xffff;
2215 2c0262af bellard
    ESP = new_esp;
2216 2c0262af bellard
}
2217 2c0262af bellard
2218 08cea4ee bellard
void helper_iret_protected(int shift, int next_eip)
2219 2c0262af bellard
{
2220 7e84c249 bellard
    int tss_selector, type;
2221 7e84c249 bellard
    uint32_t e1, e2;
2222 7e84c249 bellard
    
2223 7e84c249 bellard
    /* specific case for TSS */
2224 7e84c249 bellard
    if (env->eflags & NT_MASK) {
2225 14ce26e7 bellard
#ifdef TARGET_X86_64
2226 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
2227 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, 0);
2228 14ce26e7 bellard
#endif
2229 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
2230 7e84c249 bellard
        if (tss_selector & 4)
2231 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2232 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
2233 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2234 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2235 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
2236 7e84c249 bellard
        if (type != 3)
2237 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2238 08cea4ee bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2239 7e84c249 bellard
    } else {
2240 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
2241 7e84c249 bellard
    }
2242 9df217a3 bellard
#ifdef USE_KQEMU
2243 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2244 9df217a3 bellard
        CC_OP = CC_OP_EFLAGS;
2245 9df217a3 bellard
        env->exception_index = -1;
2246 9df217a3 bellard
        cpu_loop_exit();
2247 9df217a3 bellard
    }
2248 9df217a3 bellard
#endif
2249 2c0262af bellard
}
2250 2c0262af bellard
2251 2c0262af bellard
void helper_lret_protected(int shift, int addend)
2252 2c0262af bellard
{
2253 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
2254 9df217a3 bellard
#ifdef USE_KQEMU
2255 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2256 9df217a3 bellard
        env->exception_index = -1;
2257 9df217a3 bellard
        cpu_loop_exit();
2258 9df217a3 bellard
    }
2259 9df217a3 bellard
#endif
2260 2c0262af bellard
}
2261 2c0262af bellard
2262 023fe10d bellard
void helper_sysenter(void)
2263 023fe10d bellard
{
2264 023fe10d bellard
    if (env->sysenter_cs == 0) {
2265 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2266 023fe10d bellard
    }
2267 023fe10d bellard
    env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2268 023fe10d bellard
    cpu_x86_set_cpl(env, 0);
2269 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, 
2270 14ce26e7 bellard
                           0, 0xffffffff, 
2271 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2272 023fe10d bellard
                           DESC_S_MASK |
2273 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2274 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, 
2275 14ce26e7 bellard
                           0, 0xffffffff,
2276 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2277 023fe10d bellard
                           DESC_S_MASK |
2278 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2279 023fe10d bellard
    ESP = env->sysenter_esp;
2280 023fe10d bellard
    EIP = env->sysenter_eip;
2281 023fe10d bellard
}
2282 023fe10d bellard
2283 023fe10d bellard
void helper_sysexit(void)
2284 023fe10d bellard
{
2285 023fe10d bellard
    int cpl;
2286 023fe10d bellard
2287 023fe10d bellard
    cpl = env->hflags & HF_CPL_MASK;
2288 023fe10d bellard
    if (env->sysenter_cs == 0 || cpl != 0) {
2289 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2290 023fe10d bellard
    }
2291 023fe10d bellard
    cpu_x86_set_cpl(env, 3);
2292 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, 
2293 14ce26e7 bellard
                           0, 0xffffffff, 
2294 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2295 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2296 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2297 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, 
2298 14ce26e7 bellard
                           0, 0xffffffff,
2299 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2300 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2301 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2302 023fe10d bellard
    ESP = ECX;
2303 023fe10d bellard
    EIP = EDX;
2304 9df217a3 bellard
#ifdef USE_KQEMU
2305 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2306 9df217a3 bellard
        env->exception_index = -1;
2307 9df217a3 bellard
        cpu_loop_exit();
2308 9df217a3 bellard
    }
2309 9df217a3 bellard
#endif
2310 023fe10d bellard
}
2311 023fe10d bellard
2312 2c0262af bellard
void helper_movl_crN_T0(int reg)
2313 2c0262af bellard
{
2314 4d6b6c0a bellard
#if !defined(CONFIG_USER_ONLY) 
2315 2c0262af bellard
    switch(reg) {
2316 2c0262af bellard
    case 0:
2317 1ac157da bellard
        cpu_x86_update_cr0(env, T0);
2318 2c0262af bellard
        break;
2319 2c0262af bellard
    case 3:
2320 1ac157da bellard
        cpu_x86_update_cr3(env, T0);
2321 1ac157da bellard
        break;
2322 1ac157da bellard
    case 4:
2323 1ac157da bellard
        cpu_x86_update_cr4(env, T0);
2324 1ac157da bellard
        break;
2325 4d6b6c0a bellard
    case 8:
2326 4d6b6c0a bellard
        cpu_set_apic_tpr(env, T0);
2327 4d6b6c0a bellard
        break;
2328 1ac157da bellard
    default:
2329 1ac157da bellard
        env->cr[reg] = T0;
2330 2c0262af bellard
        break;
2331 2c0262af bellard
    }
2332 4d6b6c0a bellard
#endif
2333 2c0262af bellard
}
2334 2c0262af bellard
2335 2c0262af bellard
/* XXX: do more */
2336 2c0262af bellard
void helper_movl_drN_T0(int reg)
2337 2c0262af bellard
{
2338 2c0262af bellard
    env->dr[reg] = T0;
2339 2c0262af bellard
}
2340 2c0262af bellard
2341 8f091a59 bellard
void helper_invlpg(target_ulong addr)
2342 2c0262af bellard
{
2343 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
2344 2c0262af bellard
}
2345 2c0262af bellard
2346 2c0262af bellard
void helper_rdtsc(void)
2347 2c0262af bellard
{
2348 2c0262af bellard
    uint64_t val;
2349 ecada8a2 bellard
2350 ecada8a2 bellard
    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2351 ecada8a2 bellard
        raise_exception(EXCP0D_GPF);
2352 ecada8a2 bellard
    }
2353 28ab0e2e bellard
    val = cpu_get_tsc(env);
2354 14ce26e7 bellard
    EAX = (uint32_t)(val);
2355 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2356 14ce26e7 bellard
}
2357 14ce26e7 bellard
2358 14ce26e7 bellard
#if defined(CONFIG_USER_ONLY) 
2359 14ce26e7 bellard
void helper_wrmsr(void)
2360 14ce26e7 bellard
{
2361 2c0262af bellard
}
2362 2c0262af bellard
2363 14ce26e7 bellard
void helper_rdmsr(void)
2364 14ce26e7 bellard
{
2365 14ce26e7 bellard
}
2366 14ce26e7 bellard
#else
2367 2c0262af bellard
void helper_wrmsr(void)
2368 2c0262af bellard
{
2369 14ce26e7 bellard
    uint64_t val;
2370 14ce26e7 bellard
2371 14ce26e7 bellard
    val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2372 14ce26e7 bellard
2373 14ce26e7 bellard
    switch((uint32_t)ECX) {
2374 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2375 14ce26e7 bellard
        env->sysenter_cs = val & 0xffff;
2376 2c0262af bellard
        break;
2377 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2378 14ce26e7 bellard
        env->sysenter_esp = val;
2379 2c0262af bellard
        break;
2380 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2381 14ce26e7 bellard
        env->sysenter_eip = val;
2382 14ce26e7 bellard
        break;
2383 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2384 14ce26e7 bellard
        cpu_set_apic_base(env, val);
2385 14ce26e7 bellard
        break;
2386 14ce26e7 bellard
    case MSR_EFER:
2387 f419b321 bellard
        {
2388 f419b321 bellard
            uint64_t update_mask;
2389 f419b321 bellard
            update_mask = 0;
2390 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
2391 f419b321 bellard
                update_mask |= MSR_EFER_SCE;
2392 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_LM)
2393 f419b321 bellard
                update_mask |= MSR_EFER_LME;
2394 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
2395 f419b321 bellard
                update_mask |= MSR_EFER_FFXSR;
2396 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_NX)
2397 f419b321 bellard
                update_mask |= MSR_EFER_NXE;
2398 f419b321 bellard
            env->efer = (env->efer & ~update_mask) | 
2399 f419b321 bellard
            (val & update_mask);
2400 f419b321 bellard
        }
2401 2c0262af bellard
        break;
2402 14ce26e7 bellard
    case MSR_STAR:
2403 14ce26e7 bellard
        env->star = val;
2404 14ce26e7 bellard
        break;
2405 8f091a59 bellard
    case MSR_PAT:
2406 8f091a59 bellard
        env->pat = val;
2407 8f091a59 bellard
        break;
2408 f419b321 bellard
#ifdef TARGET_X86_64
2409 14ce26e7 bellard
    case MSR_LSTAR:
2410 14ce26e7 bellard
        env->lstar = val;
2411 14ce26e7 bellard
        break;
2412 14ce26e7 bellard
    case MSR_CSTAR:
2413 14ce26e7 bellard
        env->cstar = val;
2414 14ce26e7 bellard
        break;
2415 14ce26e7 bellard
    case MSR_FMASK:
2416 14ce26e7 bellard
        env->fmask = val;
2417 14ce26e7 bellard
        break;
2418 14ce26e7 bellard
    case MSR_FSBASE:
2419 14ce26e7 bellard
        env->segs[R_FS].base = val;
2420 14ce26e7 bellard
        break;
2421 14ce26e7 bellard
    case MSR_GSBASE:
2422 14ce26e7 bellard
        env->segs[R_GS].base = val;
2423 14ce26e7 bellard
        break;
2424 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2425 14ce26e7 bellard
        env->kernelgsbase = val;
2426 14ce26e7 bellard
        break;
2427 14ce26e7 bellard
#endif
2428 2c0262af bellard
    default:
2429 2c0262af bellard
        /* XXX: exception ? */
2430 2c0262af bellard
        break; 
2431 2c0262af bellard
    }
2432 2c0262af bellard
}
2433 2c0262af bellard
2434 2c0262af bellard
void helper_rdmsr(void)
2435 2c0262af bellard
{
2436 14ce26e7 bellard
    uint64_t val;
2437 14ce26e7 bellard
    switch((uint32_t)ECX) {
2438 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2439 14ce26e7 bellard
        val = env->sysenter_cs;
2440 2c0262af bellard
        break;
2441 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2442 14ce26e7 bellard
        val = env->sysenter_esp;
2443 2c0262af bellard
        break;
2444 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2445 14ce26e7 bellard
        val = env->sysenter_eip;
2446 14ce26e7 bellard
        break;
2447 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2448 14ce26e7 bellard
        val = cpu_get_apic_base(env);
2449 14ce26e7 bellard
        break;
2450 14ce26e7 bellard
    case MSR_EFER:
2451 14ce26e7 bellard
        val = env->efer;
2452 14ce26e7 bellard
        break;
2453 14ce26e7 bellard
    case MSR_STAR:
2454 14ce26e7 bellard
        val = env->star;
2455 14ce26e7 bellard
        break;
2456 8f091a59 bellard
    case MSR_PAT:
2457 8f091a59 bellard
        val = env->pat;
2458 8f091a59 bellard
        break;
2459 f419b321 bellard
#ifdef TARGET_X86_64
2460 14ce26e7 bellard
    case MSR_LSTAR:
2461 14ce26e7 bellard
        val = env->lstar;
2462 14ce26e7 bellard
        break;
2463 14ce26e7 bellard
    case MSR_CSTAR:
2464 14ce26e7 bellard
        val = env->cstar;
2465 14ce26e7 bellard
        break;
2466 14ce26e7 bellard
    case MSR_FMASK:
2467 14ce26e7 bellard
        val = env->fmask;
2468 14ce26e7 bellard
        break;
2469 14ce26e7 bellard
    case MSR_FSBASE:
2470 14ce26e7 bellard
        val = env->segs[R_FS].base;
2471 14ce26e7 bellard
        break;
2472 14ce26e7 bellard
    case MSR_GSBASE:
2473 14ce26e7 bellard
        val = env->segs[R_GS].base;
2474 2c0262af bellard
        break;
2475 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2476 14ce26e7 bellard
        val = env->kernelgsbase;
2477 14ce26e7 bellard
        break;
2478 14ce26e7 bellard
#endif
2479 2c0262af bellard
    default:
2480 2c0262af bellard
        /* XXX: exception ? */
2481 14ce26e7 bellard
        val = 0;
2482 2c0262af bellard
        break; 
2483 2c0262af bellard
    }
2484 14ce26e7 bellard
    EAX = (uint32_t)(val);
2485 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2486 2c0262af bellard
}
2487 14ce26e7 bellard
#endif
2488 2c0262af bellard
2489 2c0262af bellard
void helper_lsl(void)
2490 2c0262af bellard
{
2491 2c0262af bellard
    unsigned int selector, limit;
2492 5516d670 bellard
    uint32_t e1, e2, eflags;
2493 3ab493de bellard
    int rpl, dpl, cpl, type;
2494 2c0262af bellard
2495 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2496 2c0262af bellard
    selector = T0 & 0xffff;
2497 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
2498 5516d670 bellard
        goto fail;
2499 3ab493de bellard
    rpl = selector & 3;
2500 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2501 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2502 3ab493de bellard
    if (e2 & DESC_S_MASK) {
2503 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2504 3ab493de bellard
            /* conforming */
2505 3ab493de bellard
        } else {
2506 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2507 5516d670 bellard
                goto fail;
2508 3ab493de bellard
        }
2509 3ab493de bellard
    } else {
2510 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2511 3ab493de bellard
        switch(type) {
2512 3ab493de bellard
        case 1:
2513 3ab493de bellard
        case 2:
2514 3ab493de bellard
        case 3:
2515 3ab493de bellard
        case 9:
2516 3ab493de bellard
        case 11:
2517 3ab493de bellard
            break;
2518 3ab493de bellard
        default:
2519 5516d670 bellard
            goto fail;
2520 3ab493de bellard
        }
2521 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2522 5516d670 bellard
        fail:
2523 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2524 3ab493de bellard
            return;
2525 5516d670 bellard
        }
2526 3ab493de bellard
    }
2527 3ab493de bellard
    limit = get_seg_limit(e1, e2);
2528 2c0262af bellard
    T1 = limit;
2529 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2530 2c0262af bellard
}
2531 2c0262af bellard
2532 2c0262af bellard
void helper_lar(void)
2533 2c0262af bellard
{
2534 2c0262af bellard
    unsigned int selector;
2535 5516d670 bellard
    uint32_t e1, e2, eflags;
2536 3ab493de bellard
    int rpl, dpl, cpl, type;
2537 2c0262af bellard
2538 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2539 2c0262af bellard
    selector = T0 & 0xffff;
2540 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2541 5516d670 bellard
        goto fail;
2542 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
2543 5516d670 bellard
        goto fail;
2544 3ab493de bellard
    rpl = selector & 3;
2545 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2546 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2547 3ab493de bellard
    if (e2 & DESC_S_MASK) {
2548 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2549 3ab493de bellard
            /* conforming */
2550 3ab493de bellard
        } else {
2551 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2552 5516d670 bellard
                goto fail;
2553 3ab493de bellard
        }
2554 3ab493de bellard
    } else {
2555 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2556 3ab493de bellard
        switch(type) {
2557 3ab493de bellard
        case 1:
2558 3ab493de bellard
        case 2:
2559 3ab493de bellard
        case 3:
2560 3ab493de bellard
        case 4:
2561 3ab493de bellard
        case 5:
2562 3ab493de bellard
        case 9:
2563 3ab493de bellard
        case 11:
2564 3ab493de bellard
        case 12:
2565 3ab493de bellard
            break;
2566 3ab493de bellard
        default:
2567 5516d670 bellard
            goto fail;
2568 3ab493de bellard
        }
2569 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2570 5516d670 bellard
        fail:
2571 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2572 3ab493de bellard
            return;
2573 5516d670 bellard
        }
2574 3ab493de bellard
    }
2575 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
2576 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2577 2c0262af bellard
}
2578 2c0262af bellard
2579 3ab493de bellard
void helper_verr(void)
2580 3ab493de bellard
{
2581 3ab493de bellard
    unsigned int selector;
2582 5516d670 bellard
    uint32_t e1, e2, eflags;
2583 3ab493de bellard
    int rpl, dpl, cpl;
2584 3ab493de bellard
2585 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2586 3ab493de bellard
    selector = T0 & 0xffff;
2587 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2588 5516d670 bellard
        goto fail;
2589 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
2590 5516d670 bellard
        goto fail;
2591 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
2592 5516d670 bellard
        goto fail;
2593 3ab493de bellard
    rpl = selector & 3;
2594 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2595 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2596 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
2597 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
2598 5516d670 bellard
            goto fail;
2599 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
2600 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2601 5516d670 bellard
                goto fail;
2602 3ab493de bellard
        }
2603 3ab493de bellard
    } else {
2604 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2605 5516d670 bellard
        fail:
2606 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2607 3ab493de bellard
            return;
2608 5516d670 bellard
        }
2609 3ab493de bellard
    }
2610 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2611 3ab493de bellard
}
2612 3ab493de bellard
2613 3ab493de bellard
void helper_verw(void)
2614 3ab493de bellard
{
2615 3ab493de bellard
    unsigned int selector;
2616 5516d670 bellard
    uint32_t e1, e2, eflags;
2617 3ab493de bellard
    int rpl, dpl, cpl;
2618 3ab493de bellard
2619 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2620 3ab493de bellard
    selector = T0 & 0xffff;
2621 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2622 5516d670 bellard
        goto fail;
2623 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
2624 5516d670 bellard
        goto fail;
2625 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
2626 5516d670 bellard
        goto fail;
2627 3ab493de bellard
    rpl = selector & 3;
2628 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2629 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2630 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
2631 5516d670 bellard
        goto fail;
2632 3ab493de bellard
    } else {
2633 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
2634 5516d670 bellard
            goto fail;
2635 5516d670 bellard
        if (!(e2 & DESC_W_MASK)) {
2636 5516d670 bellard
        fail:
2637 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2638 3ab493de bellard
            return;
2639 5516d670 bellard
        }
2640 3ab493de bellard
    }
2641 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2642 3ab493de bellard
}
2643 3ab493de bellard
2644 2c0262af bellard
/* FPU helpers */
2645 2c0262af bellard
2646 2c0262af bellard
void helper_fldt_ST0_A0(void)
2647 2c0262af bellard
{
2648 2c0262af bellard
    int new_fpstt;
2649 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
2650 664e0f19 bellard
    env->fpregs[new_fpstt].d = helper_fldt(A0);
2651 2c0262af bellard
    env->fpstt = new_fpstt;
2652 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
2653 2c0262af bellard
}
2654 2c0262af bellard
2655 2c0262af bellard
void helper_fstt_ST0_A0(void)
2656 2c0262af bellard
{
2657 14ce26e7 bellard
    helper_fstt(ST0, A0);
2658 2c0262af bellard
}
2659 2c0262af bellard
2660 2ee73ac3 bellard
void fpu_set_exception(int mask)
2661 2ee73ac3 bellard
{
2662 2ee73ac3 bellard
    env->fpus |= mask;
2663 2ee73ac3 bellard
    if (env->fpus & (~env->fpuc & FPUC_EM))
2664 2ee73ac3 bellard
        env->fpus |= FPUS_SE | FPUS_B;
2665 2ee73ac3 bellard
}
2666 2ee73ac3 bellard
2667 2ee73ac3 bellard
CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
2668 2ee73ac3 bellard
{
2669 2ee73ac3 bellard
    if (b == 0.0) 
2670 2ee73ac3 bellard
        fpu_set_exception(FPUS_ZE);
2671 2ee73ac3 bellard
    return a / b;
2672 2ee73ac3 bellard
}
2673 2ee73ac3 bellard
2674 2ee73ac3 bellard
void fpu_raise_exception(void)
2675 2ee73ac3 bellard
{
2676 2ee73ac3 bellard
    if (env->cr[0] & CR0_NE_MASK) {
2677 2ee73ac3 bellard
        raise_exception(EXCP10_COPR);
2678 2ee73ac3 bellard
    } 
2679 2ee73ac3 bellard
#if !defined(CONFIG_USER_ONLY) 
2680 2ee73ac3 bellard
    else {
2681 2ee73ac3 bellard
        cpu_set_ferr(env);
2682 2ee73ac3 bellard
    }
2683 2ee73ac3 bellard
#endif
2684 2ee73ac3 bellard
}
2685 2ee73ac3 bellard
2686 2c0262af bellard
/* BCD ops */
2687 2c0262af bellard
2688 2c0262af bellard
void helper_fbld_ST0_A0(void)
2689 2c0262af bellard
{
2690 2c0262af bellard
    CPU86_LDouble tmp;
2691 2c0262af bellard
    uint64_t val;
2692 2c0262af bellard
    unsigned int v;
2693 2c0262af bellard
    int i;
2694 2c0262af bellard
2695 2c0262af bellard
    val = 0;
2696 2c0262af bellard
    for(i = 8; i >= 0; i--) {
2697 14ce26e7 bellard
        v = ldub(A0 + i);
2698 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2699 2c0262af bellard
    }
2700 2c0262af bellard
    tmp = val;
2701 14ce26e7 bellard
    if (ldub(A0 + 9) & 0x80)
2702 2c0262af bellard
        tmp = -tmp;
2703 2c0262af bellard
    fpush();
2704 2c0262af bellard
    ST0 = tmp;
2705 2c0262af bellard
}
2706 2c0262af bellard
2707 2c0262af bellard
void helper_fbst_ST0_A0(void)
2708 2c0262af bellard
{
2709 2c0262af bellard
    int v;
2710 14ce26e7 bellard
    target_ulong mem_ref, mem_end;
2711 2c0262af bellard
    int64_t val;
2712 2c0262af bellard
2713 7a0e1f41 bellard
    val = floatx_to_int64(ST0, &env->fp_status);
2714 14ce26e7 bellard
    mem_ref = A0;
2715 2c0262af bellard
    mem_end = mem_ref + 9;
2716 2c0262af bellard
    if (val < 0) {
2717 2c0262af bellard
        stb(mem_end, 0x80);
2718 2c0262af bellard
        val = -val;
2719 2c0262af bellard
    } else {
2720 2c0262af bellard
        stb(mem_end, 0x00);
2721 2c0262af bellard
    }
2722 2c0262af bellard
    while (mem_ref < mem_end) {
2723 2c0262af bellard
        if (val == 0)
2724 2c0262af bellard
            break;
2725 2c0262af bellard
        v = val % 100;
2726 2c0262af bellard
        val = val / 100;
2727 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
2728 2c0262af bellard
        stb(mem_ref++, v);
2729 2c0262af bellard
    }
2730 2c0262af bellard
    while (mem_ref < mem_end) {
2731 2c0262af bellard
        stb(mem_ref++, 0);
2732 2c0262af bellard
    }
2733 2c0262af bellard
}
2734 2c0262af bellard
2735 2c0262af bellard
void helper_f2xm1(void)
2736 2c0262af bellard
{
2737 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
2738 2c0262af bellard
}
2739 2c0262af bellard
2740 2c0262af bellard
void helper_fyl2x(void)
2741 2c0262af bellard
{
2742 2c0262af bellard
    CPU86_LDouble fptemp;
2743 2c0262af bellard
    
2744 2c0262af bellard
    fptemp = ST0;
2745 2c0262af bellard
    if (fptemp>0.0){
2746 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
2747 2c0262af bellard
        ST1 *= fptemp;
2748 2c0262af bellard
        fpop();
2749 2c0262af bellard
    } else { 
2750 2c0262af bellard
        env->fpus &= (~0x4700);
2751 2c0262af bellard
        env->fpus |= 0x400;
2752 2c0262af bellard
    }
2753 2c0262af bellard
}
2754 2c0262af bellard
2755 2c0262af bellard
void helper_fptan(void)
2756 2c0262af bellard
{
2757 2c0262af bellard
    CPU86_LDouble fptemp;
2758 2c0262af bellard
2759 2c0262af bellard
    fptemp = ST0;
2760 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2761 2c0262af bellard
        env->fpus |= 0x400;
2762 2c0262af bellard
    } else {
2763 2c0262af bellard
        ST0 = tan(fptemp);
2764 2c0262af bellard
        fpush();
2765 2c0262af bellard
        ST0 = 1.0;
2766 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2767 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
2768 2c0262af bellard
    }
2769 2c0262af bellard
}
2770 2c0262af bellard
2771 2c0262af bellard
void helper_fpatan(void)
2772 2c0262af bellard
{
2773 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
2774 2c0262af bellard
2775 2c0262af bellard
    fpsrcop = ST1;
2776 2c0262af bellard
    fptemp = ST0;
2777 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
2778 2c0262af bellard
    fpop();
2779 2c0262af bellard
}
2780 2c0262af bellard
2781 2c0262af bellard
void helper_fxtract(void)
2782 2c0262af bellard
{
2783 2c0262af bellard
    CPU86_LDoubleU temp;
2784 2c0262af bellard
    unsigned int expdif;
2785 2c0262af bellard
2786 2c0262af bellard
    temp.d = ST0;
2787 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
2788 2c0262af bellard
    /*DP exponent bias*/
2789 2c0262af bellard
    ST0 = expdif;
2790 2c0262af bellard
    fpush();
2791 2c0262af bellard
    BIASEXPONENT(temp);
2792 2c0262af bellard
    ST0 = temp.d;
2793 2c0262af bellard
}
2794 2c0262af bellard
2795 2c0262af bellard
void helper_fprem1(void)
2796 2c0262af bellard
{
2797 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2798 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2799 2c0262af bellard
    int expdif;
2800 2c0262af bellard
    int q;
2801 2c0262af bellard
2802 2c0262af bellard
    fpsrcop = ST0;
2803 2c0262af bellard
    fptemp = ST1;
2804 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2805 2c0262af bellard
    fptemp1.d = fptemp;
2806 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2807 2c0262af bellard
    if (expdif < 53) {
2808 2c0262af bellard
        dblq = fpsrcop / fptemp;
2809 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2810 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2811 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2812 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2813 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2814 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2815 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2816 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2817 2c0262af bellard
    } else {
2818 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2819 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2820 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2821 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
2822 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2823 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
2824 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2825 2c0262af bellard
    }
2826 2c0262af bellard
}
2827 2c0262af bellard
2828 2c0262af bellard
void helper_fprem(void)
2829 2c0262af bellard
{
2830 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2831 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2832 2c0262af bellard
    int expdif;
2833 2c0262af bellard
    int q;
2834 2c0262af bellard
    
2835 2c0262af bellard
    fpsrcop = ST0;
2836 2c0262af bellard
    fptemp = ST1;
2837 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2838 2c0262af bellard
    fptemp1.d = fptemp;
2839 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2840 2c0262af bellard
    if ( expdif < 53 ) {
2841 2c0262af bellard
        dblq = fpsrcop / fptemp;
2842 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2843 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2844 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2845 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2846 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2847 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2848 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2849 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2850 2c0262af bellard
    } else {
2851 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2852 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2853 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2854 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
2855 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
2856 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
2857 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2858 2c0262af bellard
    }
2859 2c0262af bellard
}
2860 2c0262af bellard
2861 2c0262af bellard
void helper_fyl2xp1(void)
2862 2c0262af bellard
{
2863 2c0262af bellard
    CPU86_LDouble fptemp;
2864 2c0262af bellard
2865 2c0262af bellard
    fptemp = ST0;
2866 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
2867 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2868 2c0262af bellard
        ST1 *= fptemp;
2869 2c0262af bellard
        fpop();
2870 2c0262af bellard
    } else { 
2871 2c0262af bellard
        env->fpus &= (~0x4700);
2872 2c0262af bellard
        env->fpus |= 0x400;
2873 2c0262af bellard
    }
2874 2c0262af bellard
}
2875 2c0262af bellard
2876 2c0262af bellard
void helper_fsqrt(void)
2877 2c0262af bellard
{
2878 2c0262af bellard
    CPU86_LDouble fptemp;
2879 2c0262af bellard
2880 2c0262af bellard
    fptemp = ST0;
2881 2c0262af bellard
    if (fptemp<0.0) { 
2882 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2883 2c0262af bellard
        env->fpus |= 0x400;
2884 2c0262af bellard
    }
2885 2c0262af bellard
    ST0 = sqrt(fptemp);
2886 2c0262af bellard
}
2887 2c0262af bellard
2888 2c0262af bellard
void helper_fsincos(void)
2889 2c0262af bellard
{
2890 2c0262af bellard
    CPU86_LDouble fptemp;
2891 2c0262af bellard
2892 2c0262af bellard
    fptemp = ST0;
2893 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2894 2c0262af bellard
        env->fpus |= 0x400;
2895 2c0262af bellard
    } else {
2896 2c0262af bellard
        ST0 = sin(fptemp);
2897 2c0262af bellard
        fpush();
2898 2c0262af bellard
        ST0 = cos(fptemp);
2899 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2900 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
2901 2c0262af bellard
    }
2902 2c0262af bellard
}
2903 2c0262af bellard
2904 2c0262af bellard
void helper_frndint(void)
2905 2c0262af bellard
{
2906 7a0e1f41 bellard
    ST0 = floatx_round_to_int(ST0, &env->fp_status);
2907 2c0262af bellard
}
2908 2c0262af bellard
2909 2c0262af bellard
void helper_fscale(void)
2910 2c0262af bellard
{
2911 57e4c06e bellard
    ST0 = ldexp (ST0, (int)(ST1)); 
2912 2c0262af bellard
}
2913 2c0262af bellard
2914 2c0262af bellard
void helper_fsin(void)
2915 2c0262af bellard
{
2916 2c0262af bellard
    CPU86_LDouble fptemp;
2917 2c0262af bellard
2918 2c0262af bellard
    fptemp = ST0;
2919 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2920 2c0262af bellard
        env->fpus |= 0x400;
2921 2c0262af bellard
    } else {
2922 2c0262af bellard
        ST0 = sin(fptemp);
2923 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2924 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
2925 2c0262af bellard
    }
2926 2c0262af bellard
}
2927 2c0262af bellard
2928 2c0262af bellard
void helper_fcos(void)
2929 2c0262af bellard
{
2930 2c0262af bellard
    CPU86_LDouble fptemp;
2931 2c0262af bellard
2932 2c0262af bellard
    fptemp = ST0;
2933 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2934 2c0262af bellard
        env->fpus |= 0x400;
2935 2c0262af bellard
    } else {
2936 2c0262af bellard
        ST0 = cos(fptemp);
2937 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2938 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
2939 2c0262af bellard
    }
2940 2c0262af bellard
}
2941 2c0262af bellard
2942 2c0262af bellard
void helper_fxam_ST0(void)
2943 2c0262af bellard
{
2944 2c0262af bellard
    CPU86_LDoubleU temp;
2945 2c0262af bellard
    int expdif;
2946 2c0262af bellard
2947 2c0262af bellard
    temp.d = ST0;
2948 2c0262af bellard
2949 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2950 2c0262af bellard
    if (SIGND(temp))
2951 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
2952 2c0262af bellard
2953 a891c7a1 bellard
    /* XXX: test fptags too */
2954 2c0262af bellard
    expdif = EXPD(temp);
2955 2c0262af bellard
    if (expdif == MAXEXPD) {
2956 a891c7a1 bellard
#ifdef USE_X86LDOUBLE
2957 a891c7a1 bellard
        if (MANTD(temp) == 0x8000000000000000ULL)
2958 a891c7a1 bellard
#else
2959 2c0262af bellard
        if (MANTD(temp) == 0)
2960 a891c7a1 bellard
#endif
2961 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
2962 2c0262af bellard
        else
2963 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
2964 2c0262af bellard
    } else if (expdif == 0) {
2965 2c0262af bellard
        if (MANTD(temp) == 0)
2966 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
2967 2c0262af bellard
        else
2968 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
2969 2c0262af bellard
    } else {
2970 2c0262af bellard
        env->fpus |= 0x400;
2971 2c0262af bellard
    }
2972 2c0262af bellard
}
2973 2c0262af bellard
2974 14ce26e7 bellard
void helper_fstenv(target_ulong ptr, int data32)
2975 2c0262af bellard
{
2976 2c0262af bellard
    int fpus, fptag, exp, i;
2977 2c0262af bellard
    uint64_t mant;
2978 2c0262af bellard
    CPU86_LDoubleU tmp;
2979 2c0262af bellard
2980 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2981 2c0262af bellard
    fptag = 0;
2982 2c0262af bellard
    for (i=7; i>=0; i--) {
2983 2c0262af bellard
        fptag <<= 2;
2984 2c0262af bellard
        if (env->fptags[i]) {
2985 2c0262af bellard
            fptag |= 3;
2986 2c0262af bellard
        } else {
2987 664e0f19 bellard
            tmp.d = env->fpregs[i].d;
2988 2c0262af bellard
            exp = EXPD(tmp);
2989 2c0262af bellard
            mant = MANTD(tmp);
2990 2c0262af bellard
            if (exp == 0 && mant == 0) {
2991 2c0262af bellard
                /* zero */
2992 2c0262af bellard
                fptag |= 1;
2993 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
2994 2c0262af bellard
#ifdef USE_X86LDOUBLE
2995 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
2996 2c0262af bellard
#endif
2997 2c0262af bellard
                       ) {
2998 2c0262af bellard
                /* NaNs, infinity, denormal */
2999 2c0262af bellard
                fptag |= 2;
3000 2c0262af bellard
            }
3001 2c0262af bellard
        }
3002 2c0262af bellard
    }
3003 2c0262af bellard
    if (data32) {
3004 2c0262af bellard
        /* 32 bit */
3005 2c0262af bellard
        stl(ptr, env->fpuc);
3006 2c0262af bellard
        stl(ptr + 4, fpus);
3007 2c0262af bellard
        stl(ptr + 8, fptag);
3008 2edcdce3 bellard
        stl(ptr + 12, 0); /* fpip */
3009 2edcdce3 bellard
        stl(ptr + 16, 0); /* fpcs */
3010 2edcdce3 bellard
        stl(ptr + 20, 0); /* fpoo */
3011 2edcdce3 bellard
        stl(ptr + 24, 0); /* fpos */
3012 2c0262af bellard
    } else {
3013 2c0262af bellard
        /* 16 bit */
3014 2c0262af bellard
        stw(ptr, env->fpuc);
3015 2c0262af bellard
        stw(ptr + 2, fpus);
3016 2c0262af bellard
        stw(ptr + 4, fptag);
3017 2c0262af bellard
        stw(ptr + 6, 0);
3018 2c0262af bellard
        stw(ptr + 8, 0);
3019 2c0262af bellard
        stw(ptr + 10, 0);
3020 2c0262af bellard
        stw(ptr + 12, 0);
3021 2c0262af bellard
    }
3022 2c0262af bellard
}
3023 2c0262af bellard
3024 14ce26e7 bellard
void helper_fldenv(target_ulong ptr, int data32)
3025 2c0262af bellard
{
3026 2c0262af bellard
    int i, fpus, fptag;
3027 2c0262af bellard
3028 2c0262af bellard
    if (data32) {
3029 2c0262af bellard
        env->fpuc = lduw(ptr);
3030 2c0262af bellard
        fpus = lduw(ptr + 4);
3031 2c0262af bellard
        fptag = lduw(ptr + 8);
3032 2c0262af bellard
    }
3033 2c0262af bellard
    else {
3034 2c0262af bellard
        env->fpuc = lduw(ptr);
3035 2c0262af bellard
        fpus = lduw(ptr + 2);
3036 2c0262af bellard
        fptag = lduw(ptr + 4);
3037 2c0262af bellard
    }
3038 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
3039 2c0262af bellard
    env->fpus = fpus & ~0x3800;
3040 2edcdce3 bellard
    for(i = 0;i < 8; i++) {
3041 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
3042 2c0262af bellard
        fptag >>= 2;
3043 2c0262af bellard
    }
3044 2c0262af bellard
}
3045 2c0262af bellard
3046 14ce26e7 bellard
void helper_fsave(target_ulong ptr, int data32)
3047 2c0262af bellard
{
3048 2c0262af bellard
    CPU86_LDouble tmp;
3049 2c0262af bellard
    int i;
3050 2c0262af bellard
3051 2c0262af bellard
    helper_fstenv(ptr, data32);
3052 2c0262af bellard
3053 2c0262af bellard
    ptr += (14 << data32);
3054 2c0262af bellard
    for(i = 0;i < 8; i++) {
3055 2c0262af bellard
        tmp = ST(i);
3056 2c0262af bellard
        helper_fstt(tmp, ptr);
3057 2c0262af bellard
        ptr += 10;
3058 2c0262af bellard
    }
3059 2c0262af bellard
3060 2c0262af bellard
    /* fninit */
3061 2c0262af bellard
    env->fpus = 0;
3062 2c0262af bellard
    env->fpstt = 0;
3063 2c0262af bellard
    env->fpuc = 0x37f;
3064 2c0262af bellard
    env->fptags[0] = 1;
3065 2c0262af bellard
    env->fptags[1] = 1;
3066 2c0262af bellard
    env->fptags[2] = 1;
3067 2c0262af bellard
    env->fptags[3] = 1;
3068 2c0262af bellard
    env->fptags[4] = 1;
3069 2c0262af bellard
    env->fptags[5] = 1;
3070 2c0262af bellard
    env->fptags[6] = 1;
3071 2c0262af bellard
    env->fptags[7] = 1;
3072 2c0262af bellard
}
3073 2c0262af bellard
3074 14ce26e7 bellard
void helper_frstor(target_ulong ptr, int data32)
3075 2c0262af bellard
{
3076 2c0262af bellard
    CPU86_LDouble tmp;
3077 2c0262af bellard
    int i;
3078 2c0262af bellard
3079 2c0262af bellard
    helper_fldenv(ptr, data32);
3080 2c0262af bellard
    ptr += (14 << data32);
3081 2c0262af bellard
3082 2c0262af bellard
    for(i = 0;i < 8; i++) {
3083 2c0262af bellard
        tmp = helper_fldt(ptr);
3084 2c0262af bellard
        ST(i) = tmp;
3085 2c0262af bellard
        ptr += 10;
3086 2c0262af bellard
    }
3087 2c0262af bellard
}
3088 2c0262af bellard
3089 14ce26e7 bellard
void helper_fxsave(target_ulong ptr, int data64)
3090 14ce26e7 bellard
{
3091 14ce26e7 bellard
    int fpus, fptag, i, nb_xmm_regs;
3092 14ce26e7 bellard
    CPU86_LDouble tmp;
3093 14ce26e7 bellard
    target_ulong addr;
3094 14ce26e7 bellard
3095 14ce26e7 bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3096 14ce26e7 bellard
    fptag = 0;
3097 14ce26e7 bellard
    for(i = 0; i < 8; i++) {
3098 d3c61721 bellard
        fptag |= (env->fptags[i] << i);
3099 14ce26e7 bellard
    }
3100 14ce26e7 bellard
    stw(ptr, env->fpuc);
3101 14ce26e7 bellard
    stw(ptr + 2, fpus);
3102 d3c61721 bellard
    stw(ptr + 4, fptag ^ 0xff);
3103 14ce26e7 bellard
3104 14ce26e7 bellard
    addr = ptr + 0x20;
3105 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3106 14ce26e7 bellard
        tmp = ST(i);
3107 14ce26e7 bellard
        helper_fstt(tmp, addr);
3108 14ce26e7 bellard
        addr += 16;
3109 14ce26e7 bellard
    }
3110 14ce26e7 bellard
    
3111 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3112 a8ede8ba bellard
        /* XXX: finish it */
3113 664e0f19 bellard
        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3114 d3c61721 bellard
        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3115 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3116 14ce26e7 bellard
        addr = ptr + 0xa0;
3117 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3118 a8ede8ba bellard
            stq(addr, env->xmm_regs[i].XMM_Q(0));
3119 a8ede8ba bellard
            stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3120 14ce26e7 bellard
            addr += 16;
3121 14ce26e7 bellard
        }
3122 14ce26e7 bellard
    }
3123 14ce26e7 bellard
}
3124 14ce26e7 bellard
3125 14ce26e7 bellard
void helper_fxrstor(target_ulong ptr, int data64)
3126 14ce26e7 bellard
{
3127 14ce26e7 bellard
    int i, fpus, fptag, nb_xmm_regs;
3128 14ce26e7 bellard
    CPU86_LDouble tmp;
3129 14ce26e7 bellard
    target_ulong addr;
3130 14ce26e7 bellard
3131 14ce26e7 bellard
    env->fpuc = lduw(ptr);
3132 14ce26e7 bellard
    fpus = lduw(ptr + 2);
3133 d3c61721 bellard
    fptag = lduw(ptr + 4);
3134 14ce26e7 bellard
    env->fpstt = (fpus >> 11) & 7;
3135 14ce26e7 bellard
    env->fpus = fpus & ~0x3800;
3136 14ce26e7 bellard
    fptag ^= 0xff;
3137 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3138 d3c61721 bellard
        env->fptags[i] = ((fptag >> i) & 1);
3139 14ce26e7 bellard
    }
3140 14ce26e7 bellard
3141 14ce26e7 bellard
    addr = ptr + 0x20;
3142 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3143 14ce26e7 bellard
        tmp = helper_fldt(addr);
3144 14ce26e7 bellard
        ST(i) = tmp;
3145 14ce26e7 bellard
        addr += 16;
3146 14ce26e7 bellard
    }
3147 14ce26e7 bellard
3148 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3149 31313213 bellard
        /* XXX: finish it */
3150 664e0f19 bellard
        env->mxcsr = ldl(ptr + 0x18);
3151 14ce26e7 bellard
        //ldl(ptr + 0x1c);
3152 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3153 14ce26e7 bellard
        addr = ptr + 0xa0;
3154 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3155 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3156 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3157 14ce26e7 bellard
            addr += 16;
3158 14ce26e7 bellard
        }
3159 14ce26e7 bellard
    }
3160 14ce26e7 bellard
}
3161 1f1af9fd bellard
3162 1f1af9fd bellard
#ifndef USE_X86LDOUBLE
3163 1f1af9fd bellard
3164 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3165 1f1af9fd bellard
{
3166 1f1af9fd bellard
    CPU86_LDoubleU temp;
3167 1f1af9fd bellard
    int e;
3168 1f1af9fd bellard
3169 1f1af9fd bellard
    temp.d = f;
3170 1f1af9fd bellard
    /* mantissa */
3171 1f1af9fd bellard
    *pmant = (MANTD(temp) << 11) | (1LL << 63);
3172 1f1af9fd bellard
    /* exponent + sign */
3173 1f1af9fd bellard
    e = EXPD(temp) - EXPBIAS + 16383;
3174 1f1af9fd bellard
    e |= SIGND(temp) >> 16;
3175 1f1af9fd bellard
    *pexp = e;
3176 1f1af9fd bellard
}
3177 1f1af9fd bellard
3178 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3179 1f1af9fd bellard
{
3180 1f1af9fd bellard
    CPU86_LDoubleU temp;
3181 1f1af9fd bellard
    int e;
3182 1f1af9fd bellard
    uint64_t ll;
3183 1f1af9fd bellard
3184 1f1af9fd bellard
    /* XXX: handle overflow ? */
3185 1f1af9fd bellard
    e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3186 1f1af9fd bellard
    e |= (upper >> 4) & 0x800; /* sign */
3187 1f1af9fd bellard
    ll = (mant >> 11) & ((1LL << 52) - 1);
3188 1f1af9fd bellard
#ifdef __arm__
3189 1f1af9fd bellard
    temp.l.upper = (e << 20) | (ll >> 32);
3190 1f1af9fd bellard
    temp.l.lower = ll;
3191 1f1af9fd bellard
#else
3192 1f1af9fd bellard
    temp.ll = ll | ((uint64_t)e << 52);
3193 1f1af9fd bellard
#endif
3194 1f1af9fd bellard
    return temp.d;
3195 1f1af9fd bellard
}
3196 1f1af9fd bellard
3197 1f1af9fd bellard
#else
3198 1f1af9fd bellard
3199 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3200 1f1af9fd bellard
{
3201 1f1af9fd bellard
    CPU86_LDoubleU temp;
3202 1f1af9fd bellard
3203 1f1af9fd bellard
    temp.d = f;
3204 1f1af9fd bellard
    *pmant = temp.l.lower;
3205 1f1af9fd bellard
    *pexp = temp.l.upper;
3206 1f1af9fd bellard
}
3207 1f1af9fd bellard
3208 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3209 1f1af9fd bellard
{
3210 1f1af9fd bellard
    CPU86_LDoubleU temp;
3211 1f1af9fd bellard
3212 1f1af9fd bellard
    temp.l.upper = upper;
3213 1f1af9fd bellard
    temp.l.lower = mant;
3214 1f1af9fd bellard
    return temp.d;
3215 1f1af9fd bellard
}
3216 1f1af9fd bellard
#endif
3217 1f1af9fd bellard
3218 14ce26e7 bellard
#ifdef TARGET_X86_64
3219 14ce26e7 bellard
3220 14ce26e7 bellard
//#define DEBUG_MULDIV
3221 14ce26e7 bellard
3222 14ce26e7 bellard
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3223 14ce26e7 bellard
{
3224 14ce26e7 bellard
    *plow += a;
3225 14ce26e7 bellard
    /* carry test */
3226 14ce26e7 bellard
    if (*plow < a)
3227 14ce26e7 bellard
        (*phigh)++;
3228 14ce26e7 bellard
    *phigh += b;
3229 14ce26e7 bellard
}
3230 14ce26e7 bellard
3231 14ce26e7 bellard
static void neg128(uint64_t *plow, uint64_t *phigh)
3232 14ce26e7 bellard
{
3233 14ce26e7 bellard
    *plow = ~ *plow;
3234 14ce26e7 bellard
    *phigh = ~ *phigh;
3235 14ce26e7 bellard
    add128(plow, phigh, 1, 0);
3236 14ce26e7 bellard
}
3237 14ce26e7 bellard
3238 14ce26e7 bellard
static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3239 14ce26e7 bellard
{
3240 14ce26e7 bellard
    uint32_t a0, a1, b0, b1;
3241 14ce26e7 bellard
    uint64_t v;
3242 14ce26e7 bellard
3243 14ce26e7 bellard
    a0 = a;
3244 14ce26e7 bellard
    a1 = a >> 32;
3245 14ce26e7 bellard
3246 14ce26e7 bellard
    b0 = b;
3247 14ce26e7 bellard
    b1 = b >> 32;
3248 14ce26e7 bellard
    
3249 14ce26e7 bellard
    v = (uint64_t)a0 * (uint64_t)b0;
3250 14ce26e7 bellard
    *plow = v;
3251 14ce26e7 bellard
    *phigh = 0;
3252 14ce26e7 bellard
3253 14ce26e7 bellard
    v = (uint64_t)a0 * (uint64_t)b1;
3254 14ce26e7 bellard
    add128(plow, phigh, v << 32, v >> 32);
3255 14ce26e7 bellard
    
3256 14ce26e7 bellard
    v = (uint64_t)a1 * (uint64_t)b0;
3257 14ce26e7 bellard
    add128(plow, phigh, v << 32, v >> 32);
3258 14ce26e7 bellard
    
3259 14ce26e7 bellard
    v = (uint64_t)a1 * (uint64_t)b1;
3260 14ce26e7 bellard
    *phigh += v;
3261 14ce26e7 bellard
#ifdef DEBUG_MULDIV
3262 26a76461 bellard
    printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
3263 14ce26e7 bellard
           a, b, *phigh, *plow);
3264 14ce26e7 bellard
#endif
3265 14ce26e7 bellard
}
3266 14ce26e7 bellard
3267 14ce26e7 bellard
static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
3268 14ce26e7 bellard
{
3269 14ce26e7 bellard
    int sa, sb;
3270 14ce26e7 bellard
    sa = (a < 0);
3271 14ce26e7 bellard
    if (sa)
3272 14ce26e7 bellard
        a = -a;
3273 14ce26e7 bellard
    sb = (b < 0);
3274 14ce26e7 bellard
    if (sb)
3275 14ce26e7 bellard
        b = -b;
3276 14ce26e7 bellard
    mul64(plow, phigh, a, b);
3277 14ce26e7 bellard
    if (sa ^ sb) {
3278 14ce26e7 bellard
        neg128(plow, phigh);
3279 14ce26e7 bellard
    }
3280 14ce26e7 bellard
}
3281 14ce26e7 bellard
3282 45bbbb46 bellard
/* return TRUE if overflow */
3283 45bbbb46 bellard
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3284 14ce26e7 bellard
{
3285 14ce26e7 bellard
    uint64_t q, r, a1, a0;
3286 c0b24a1d bellard
    int i, qb, ab;
3287 14ce26e7 bellard
3288 14ce26e7 bellard
    a0 = *plow;
3289 14ce26e7 bellard
    a1 = *phigh;
3290 14ce26e7 bellard
    if (a1 == 0) {
3291 14ce26e7 bellard
        q = a0 / b;
3292 14ce26e7 bellard
        r = a0 % b;
3293 14ce26e7 bellard
        *plow = q;
3294 14ce26e7 bellard
        *phigh = r;
3295 14ce26e7 bellard
    } else {
3296 45bbbb46 bellard
        if (a1 >= b)
3297 45bbbb46 bellard
            return 1;
3298 14ce26e7 bellard
        /* XXX: use a better algorithm */
3299 14ce26e7 bellard
        for(i = 0; i < 64; i++) {
3300 c0b24a1d bellard
            ab = a1 >> 63;
3301 a8ede8ba bellard
            a1 = (a1 << 1) | (a0 >> 63);
3302 c0b24a1d bellard
            if (ab || a1 >= b) {
3303 14ce26e7 bellard
                a1 -= b;
3304 14ce26e7 bellard
                qb = 1;
3305 14ce26e7 bellard
            } else {
3306 14ce26e7 bellard
                qb = 0;
3307 14ce26e7 bellard
            }
3308 14ce26e7 bellard
            a0 = (a0 << 1) | qb;
3309 14ce26e7 bellard
        }
3310 a8ede8ba bellard
#if defined(DEBUG_MULDIV)
3311 26a76461 bellard
        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
3312 14ce26e7 bellard
               *phigh, *plow, b, a0, a1);
3313 14ce26e7 bellard
#endif
3314 14ce26e7 bellard
        *plow = a0;
3315 14ce26e7 bellard
        *phigh = a1;
3316 14ce26e7 bellard
    }
3317 45bbbb46 bellard
    return 0;
3318 14ce26e7 bellard
}
3319 14ce26e7 bellard
3320 45bbbb46 bellard
/* return TRUE if overflow */
3321 45bbbb46 bellard
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3322 14ce26e7 bellard
{
3323 14ce26e7 bellard
    int sa, sb;
3324 14ce26e7 bellard
    sa = ((int64_t)*phigh < 0);
3325 14ce26e7 bellard
    if (sa)
3326 14ce26e7 bellard
        neg128(plow, phigh);
3327 14ce26e7 bellard
    sb = (b < 0);
3328 14ce26e7 bellard
    if (sb)
3329 14ce26e7 bellard
        b = -b;
3330 45bbbb46 bellard
    if (div64(plow, phigh, b) != 0)
3331 45bbbb46 bellard
        return 1;
3332 45bbbb46 bellard
    if (sa ^ sb) {
3333 45bbbb46 bellard
        if (*plow > (1ULL << 63))
3334 45bbbb46 bellard
            return 1;
3335 14ce26e7 bellard
        *plow = - *plow;
3336 45bbbb46 bellard
    } else {
3337 45bbbb46 bellard
        if (*plow >= (1ULL << 63))
3338 45bbbb46 bellard
            return 1;
3339 45bbbb46 bellard
    }
3340 31313213 bellard
    if (sa)
3341 14ce26e7 bellard
        *phigh = - *phigh;
3342 45bbbb46 bellard
    return 0;
3343 14ce26e7 bellard
}
3344 14ce26e7 bellard
3345 14ce26e7 bellard
void helper_mulq_EAX_T0(void)
3346 14ce26e7 bellard
{
3347 14ce26e7 bellard
    uint64_t r0, r1;
3348 14ce26e7 bellard
3349 14ce26e7 bellard
    mul64(&r0, &r1, EAX, T0);
3350 14ce26e7 bellard
    EAX = r0;
3351 14ce26e7 bellard
    EDX = r1;
3352 14ce26e7 bellard
    CC_DST = r0;
3353 14ce26e7 bellard
    CC_SRC = r1;
3354 14ce26e7 bellard
}
3355 14ce26e7 bellard
3356 14ce26e7 bellard
void helper_imulq_EAX_T0(void)
3357 14ce26e7 bellard
{
3358 14ce26e7 bellard
    uint64_t r0, r1;
3359 14ce26e7 bellard
3360 14ce26e7 bellard
    imul64(&r0, &r1, EAX, T0);
3361 14ce26e7 bellard
    EAX = r0;
3362 14ce26e7 bellard
    EDX = r1;
3363 14ce26e7 bellard
    CC_DST = r0;
3364 a8ede8ba bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3365 14ce26e7 bellard
}
3366 14ce26e7 bellard
3367 14ce26e7 bellard
void helper_imulq_T0_T1(void)
3368 14ce26e7 bellard
{
3369 14ce26e7 bellard
    uint64_t r0, r1;
3370 14ce26e7 bellard
3371 14ce26e7 bellard
    imul64(&r0, &r1, T0, T1);
3372 14ce26e7 bellard
    T0 = r0;
3373 14ce26e7 bellard
    CC_DST = r0;
3374 14ce26e7 bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3375 14ce26e7 bellard
}
3376 14ce26e7 bellard
3377 14ce26e7 bellard
void helper_divq_EAX_T0(void)
3378 14ce26e7 bellard
{
3379 14ce26e7 bellard
    uint64_t r0, r1;
3380 14ce26e7 bellard
    if (T0 == 0) {
3381 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3382 14ce26e7 bellard
    }
3383 14ce26e7 bellard
    r0 = EAX;
3384 14ce26e7 bellard
    r1 = EDX;
3385 45bbbb46 bellard
    if (div64(&r0, &r1, T0))
3386 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3387 14ce26e7 bellard
    EAX = r0;
3388 14ce26e7 bellard
    EDX = r1;
3389 14ce26e7 bellard
}
3390 14ce26e7 bellard
3391 14ce26e7 bellard
void helper_idivq_EAX_T0(void)
3392 14ce26e7 bellard
{
3393 14ce26e7 bellard
    uint64_t r0, r1;
3394 14ce26e7 bellard
    if (T0 == 0) {
3395 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3396 14ce26e7 bellard
    }
3397 14ce26e7 bellard
    r0 = EAX;
3398 14ce26e7 bellard
    r1 = EDX;
3399 45bbbb46 bellard
    if (idiv64(&r0, &r1, T0))
3400 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3401 14ce26e7 bellard
    EAX = r0;
3402 14ce26e7 bellard
    EDX = r1;
3403 14ce26e7 bellard
}
3404 14ce26e7 bellard
3405 68cae3d8 bellard
void helper_bswapq_T0(void)
3406 68cae3d8 bellard
{
3407 68cae3d8 bellard
    T0 = bswap64(T0);
3408 68cae3d8 bellard
}
3409 14ce26e7 bellard
#endif
3410 14ce26e7 bellard
3411 664e0f19 bellard
float approx_rsqrt(float a)
3412 664e0f19 bellard
{
3413 664e0f19 bellard
    return 1.0 / sqrt(a);
3414 664e0f19 bellard
}
3415 664e0f19 bellard
3416 664e0f19 bellard
float approx_rcp(float a)
3417 664e0f19 bellard
{
3418 664e0f19 bellard
    return 1.0 / a;
3419 664e0f19 bellard
}
3420 664e0f19 bellard
3421 7a0e1f41 bellard
void update_fp_status(void)
3422 4d6b6c0a bellard
{
3423 7a0e1f41 bellard
    int rnd_type;
3424 4d6b6c0a bellard
3425 7a0e1f41 bellard
    /* set rounding mode */
3426 7a0e1f41 bellard
    switch(env->fpuc & RC_MASK) {
3427 7a0e1f41 bellard
    default:
3428 7a0e1f41 bellard
    case RC_NEAR:
3429 7a0e1f41 bellard
        rnd_type = float_round_nearest_even;
3430 7a0e1f41 bellard
        break;
3431 7a0e1f41 bellard
    case RC_DOWN:
3432 7a0e1f41 bellard
        rnd_type = float_round_down;
3433 7a0e1f41 bellard
        break;
3434 7a0e1f41 bellard
    case RC_UP:
3435 7a0e1f41 bellard
        rnd_type = float_round_up;
3436 7a0e1f41 bellard
        break;
3437 7a0e1f41 bellard
    case RC_CHOP:
3438 7a0e1f41 bellard
        rnd_type = float_round_to_zero;
3439 7a0e1f41 bellard
        break;
3440 7a0e1f41 bellard
    }
3441 7a0e1f41 bellard
    set_float_rounding_mode(rnd_type, &env->fp_status);
3442 7a0e1f41 bellard
#ifdef FLOATX80
3443 7a0e1f41 bellard
    switch((env->fpuc >> 8) & 3) {
3444 7a0e1f41 bellard
    case 0:
3445 7a0e1f41 bellard
        rnd_type = 32;
3446 7a0e1f41 bellard
        break;
3447 7a0e1f41 bellard
    case 2:
3448 7a0e1f41 bellard
        rnd_type = 64;
3449 7a0e1f41 bellard
        break;
3450 7a0e1f41 bellard
    case 3:
3451 7a0e1f41 bellard
    default:
3452 7a0e1f41 bellard
        rnd_type = 80;
3453 7a0e1f41 bellard
        break;
3454 7a0e1f41 bellard
    }
3455 7a0e1f41 bellard
    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3456 4d6b6c0a bellard
#endif
3457 7a0e1f41 bellard
}
3458 664e0f19 bellard
3459 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
3460 61382a50 bellard
3461 61382a50 bellard
#define MMUSUFFIX _mmu
3462 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
3463 61382a50 bellard
3464 2c0262af bellard
#define SHIFT 0
3465 2c0262af bellard
#include "softmmu_template.h"
3466 2c0262af bellard
3467 2c0262af bellard
#define SHIFT 1
3468 2c0262af bellard
#include "softmmu_template.h"
3469 2c0262af bellard
3470 2c0262af bellard
#define SHIFT 2
3471 2c0262af bellard
#include "softmmu_template.h"
3472 2c0262af bellard
3473 2c0262af bellard
#define SHIFT 3
3474 2c0262af bellard
#include "softmmu_template.h"
3475 2c0262af bellard
3476 61382a50 bellard
#endif
3477 61382a50 bellard
3478 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
3479 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
3480 61382a50 bellard
   from generated code or from helper.c) */
3481 61382a50 bellard
/* XXX: fix it to restore all registers */
3482 14ce26e7 bellard
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
3483 2c0262af bellard
{
3484 2c0262af bellard
    TranslationBlock *tb;
3485 2c0262af bellard
    int ret;
3486 2c0262af bellard
    unsigned long pc;
3487 61382a50 bellard
    CPUX86State *saved_env;
3488 61382a50 bellard
3489 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
3490 61382a50 bellard
       generated code */
3491 61382a50 bellard
    saved_env = env;
3492 61382a50 bellard
    env = cpu_single_env;
3493 61382a50 bellard
3494 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
3495 2c0262af bellard
    if (ret) {
3496 61382a50 bellard
        if (retaddr) {
3497 61382a50 bellard
            /* now we have a real cpu fault */
3498 61382a50 bellard
            pc = (unsigned long)retaddr;
3499 61382a50 bellard
            tb = tb_find_pc(pc);
3500 61382a50 bellard
            if (tb) {
3501 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
3502 61382a50 bellard
                   a virtual CPU fault */
3503 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
3504 61382a50 bellard
            }
3505 2c0262af bellard
        }
3506 0d1a29f9 bellard
        if (retaddr)
3507 54ca9095 bellard
            raise_exception_err(env->exception_index, env->error_code);
3508 0d1a29f9 bellard
        else
3509 54ca9095 bellard
            raise_exception_err_norestore(env->exception_index, env->error_code);
3510 2c0262af bellard
    }
3511 61382a50 bellard
    env = saved_env;
3512 2c0262af bellard
}