Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ afc7df11

History | View | Annotate | Download (92.6 kB)

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