Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 1247c5f7

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