Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ b359d4e7

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