Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 263466f5

History | View | Annotate | Download (108.1 kB)

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