Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 0e4b179d

History | View | Annotate | Download (70.3 kB)

1 2c0262af bellard
/*
2 2c0262af bellard
 *  i386 helpers
3 2c0262af bellard
 * 
4 2c0262af bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 2c0262af bellard
 *
6 2c0262af bellard
 * This library is free software; you can redistribute it and/or
7 2c0262af bellard
 * modify it under the terms of the GNU Lesser General Public
8 2c0262af bellard
 * License as published by the Free Software Foundation; either
9 2c0262af bellard
 * version 2 of the License, or (at your option) any later version.
10 2c0262af bellard
 *
11 2c0262af bellard
 * This library is distributed in the hope that it will be useful,
12 2c0262af bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 2c0262af bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 2c0262af bellard
 * Lesser General Public License for more details.
15 2c0262af bellard
 *
16 2c0262af bellard
 * You should have received a copy of the GNU Lesser General Public
17 2c0262af bellard
 * License along with this library; if not, write to the Free Software
18 2c0262af bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 2c0262af bellard
 */
20 2c0262af bellard
#include "exec.h"
21 2c0262af bellard
22 f3f2d9be bellard
//#define DEBUG_PCALL
23 f3f2d9be bellard
24 8145122b bellard
#if 0
25 8145122b bellard
#define raise_exception_err(a, b)\
26 8145122b bellard
do {\
27 8145122b bellard
    printf("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 2c0262af bellard
#ifdef reg_EAX
113 2c0262af bellard
    env->regs[R_EAX] = EAX;
114 2c0262af bellard
#endif
115 2c0262af bellard
#ifdef reg_ECX
116 2c0262af bellard
    env->regs[R_ECX] = ECX;
117 2c0262af bellard
#endif
118 2c0262af bellard
#ifdef reg_EDX
119 2c0262af bellard
    env->regs[R_EDX] = EDX;
120 2c0262af bellard
#endif
121 2c0262af bellard
#ifdef reg_EBX
122 2c0262af bellard
    env->regs[R_EBX] = EBX;
123 2c0262af bellard
#endif
124 2c0262af bellard
#ifdef reg_ESP
125 2c0262af bellard
    env->regs[R_ESP] = ESP;
126 2c0262af bellard
#endif
127 2c0262af bellard
#ifdef reg_EBP
128 2c0262af bellard
    env->regs[R_EBP] = EBP;
129 2c0262af bellard
#endif
130 2c0262af bellard
#ifdef reg_ESI
131 2c0262af bellard
    env->regs[R_ESI] = ESI;
132 2c0262af bellard
#endif
133 2c0262af bellard
#ifdef reg_EDI
134 2c0262af bellard
    env->regs[R_EDI] = EDI;
135 2c0262af bellard
#endif
136 2c0262af bellard
    longjmp(env->jmp_env, 1);
137 2c0262af bellard
}
138 2c0262af bellard
139 7e84c249 bellard
/* return non zero if error */
140 7e84c249 bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
141 7e84c249 bellard
                               int selector)
142 7e84c249 bellard
{
143 7e84c249 bellard
    SegmentCache *dt;
144 7e84c249 bellard
    int index;
145 7e84c249 bellard
    uint8_t *ptr;
146 7e84c249 bellard
147 7e84c249 bellard
    if (selector & 0x4)
148 7e84c249 bellard
        dt = &env->ldt;
149 7e84c249 bellard
    else
150 7e84c249 bellard
        dt = &env->gdt;
151 7e84c249 bellard
    index = selector & ~7;
152 7e84c249 bellard
    if ((index + 7) > dt->limit)
153 7e84c249 bellard
        return -1;
154 7e84c249 bellard
    ptr = dt->base + index;
155 7e84c249 bellard
    *e1_ptr = ldl_kernel(ptr);
156 7e84c249 bellard
    *e2_ptr = ldl_kernel(ptr + 4);
157 7e84c249 bellard
    return 0;
158 7e84c249 bellard
}
159 7e84c249 bellard
                                     
160 7e84c249 bellard
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
161 7e84c249 bellard
{
162 7e84c249 bellard
    unsigned int limit;
163 7e84c249 bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
164 7e84c249 bellard
    if (e2 & DESC_G_MASK)
165 7e84c249 bellard
        limit = (limit << 12) | 0xfff;
166 7e84c249 bellard
    return limit;
167 7e84c249 bellard
}
168 7e84c249 bellard
169 7e84c249 bellard
static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
170 7e84c249 bellard
{
171 7e84c249 bellard
    return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
172 7e84c249 bellard
}
173 7e84c249 bellard
174 7e84c249 bellard
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
175 7e84c249 bellard
{
176 7e84c249 bellard
    sc->base = get_seg_base(e1, e2);
177 7e84c249 bellard
    sc->limit = get_seg_limit(e1, e2);
178 7e84c249 bellard
    sc->flags = e2;
179 7e84c249 bellard
}
180 7e84c249 bellard
181 7e84c249 bellard
/* init the segment cache in vm86 mode. */
182 7e84c249 bellard
static inline void load_seg_vm(int seg, int selector)
183 7e84c249 bellard
{
184 7e84c249 bellard
    selector &= 0xffff;
185 7e84c249 bellard
    cpu_x86_load_seg_cache(env, seg, selector, 
186 7e84c249 bellard
                           (uint8_t *)(selector << 4), 0xffff, 0);
187 7e84c249 bellard
}
188 7e84c249 bellard
189 2c0262af bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
190 2c0262af bellard
                                       uint32_t *esp_ptr, int dpl)
191 2c0262af bellard
{
192 2c0262af bellard
    int type, index, shift;
193 2c0262af bellard
    
194 2c0262af bellard
#if 0
195 2c0262af bellard
    {
196 2c0262af bellard
        int i;
197 2c0262af bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
198 2c0262af bellard
        for(i=0;i<env->tr.limit;i++) {
199 2c0262af bellard
            printf("%02x ", env->tr.base[i]);
200 2c0262af bellard
            if ((i & 7) == 7) printf("\n");
201 2c0262af bellard
        }
202 2c0262af bellard
        printf("\n");
203 2c0262af bellard
    }
204 2c0262af bellard
#endif
205 2c0262af bellard
206 2c0262af bellard
    if (!(env->tr.flags & DESC_P_MASK))
207 2c0262af bellard
        cpu_abort(env, "invalid tss");
208 2c0262af bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
209 2c0262af bellard
    if ((type & 7) != 1)
210 2c0262af bellard
        cpu_abort(env, "invalid tss type");
211 2c0262af bellard
    shift = type >> 3;
212 2c0262af bellard
    index = (dpl * 4 + 2) << shift;
213 2c0262af bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
214 2c0262af bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
215 2c0262af bellard
    if (shift == 0) {
216 61382a50 bellard
        *esp_ptr = lduw_kernel(env->tr.base + index);
217 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
218 2c0262af bellard
    } else {
219 61382a50 bellard
        *esp_ptr = ldl_kernel(env->tr.base + index);
220 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
221 2c0262af bellard
    }
222 2c0262af bellard
}
223 2c0262af bellard
224 7e84c249 bellard
/* XXX: merge with load_seg() */
225 7e84c249 bellard
static void tss_load_seg(int seg_reg, int selector)
226 7e84c249 bellard
{
227 7e84c249 bellard
    uint32_t e1, e2;
228 7e84c249 bellard
    int rpl, dpl, cpl;
229 7e84c249 bellard
230 7e84c249 bellard
    if ((selector & 0xfffc) != 0) {
231 7e84c249 bellard
        if (load_segment(&e1, &e2, selector) != 0)
232 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
233 7e84c249 bellard
        if (!(e2 & DESC_S_MASK))
234 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
235 7e84c249 bellard
        rpl = selector & 3;
236 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
237 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
238 7e84c249 bellard
        if (seg_reg == R_CS) {
239 7e84c249 bellard
            if (!(e2 & DESC_CS_MASK))
240 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
241 7e84c249 bellard
            if (dpl != rpl)
242 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
243 7e84c249 bellard
            if ((e2 & DESC_C_MASK) && dpl > rpl)
244 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
245 7e84c249 bellard
                
246 7e84c249 bellard
        } else if (seg_reg == R_SS) {
247 7e84c249 bellard
            /* SS must be writable data */
248 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
249 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
250 7e84c249 bellard
            if (dpl != cpl || dpl != rpl)
251 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
252 7e84c249 bellard
        } else {
253 7e84c249 bellard
            /* not readable code */
254 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
255 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
256 7e84c249 bellard
            /* if data or non conforming code, checks the rights */
257 7e84c249 bellard
            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
258 7e84c249 bellard
                if (dpl < cpl || dpl < rpl)
259 7e84c249 bellard
                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
260 7e84c249 bellard
            }
261 7e84c249 bellard
        }
262 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
263 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
264 7e84c249 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
265 7e84c249 bellard
                       get_seg_base(e1, e2),
266 7e84c249 bellard
                       get_seg_limit(e1, e2),
267 7e84c249 bellard
                       e2);
268 7e84c249 bellard
    } else {
269 7e84c249 bellard
        if (seg_reg == R_SS || seg_reg == R_CS) 
270 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
271 7e84c249 bellard
    }
272 7e84c249 bellard
}
273 7e84c249 bellard
274 7e84c249 bellard
#define SWITCH_TSS_JMP  0
275 7e84c249 bellard
#define SWITCH_TSS_IRET 1
276 7e84c249 bellard
#define SWITCH_TSS_CALL 2
277 7e84c249 bellard
278 7e84c249 bellard
/* XXX: restore CPU state in registers (PowerPC case) */
279 7e84c249 bellard
static void switch_tss(int tss_selector, 
280 7e84c249 bellard
                       uint32_t e1, uint32_t e2, int source)
281 2c0262af bellard
{
282 7e84c249 bellard
    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
283 7e84c249 bellard
    uint8_t *tss_base;
284 7e84c249 bellard
    uint32_t new_regs[8], new_segs[6];
285 7e84c249 bellard
    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
286 7e84c249 bellard
    uint32_t old_eflags, eflags_mask;
287 2c0262af bellard
    SegmentCache *dt;
288 2c0262af bellard
    int index;
289 2c0262af bellard
    uint8_t *ptr;
290 2c0262af bellard
291 7e84c249 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
292 dc6f57fd bellard
#ifdef DEBUG_PCALL
293 dc6f57fd bellard
    if (loglevel)
294 dc6f57fd bellard
        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
295 dc6f57fd bellard
#endif
296 7e84c249 bellard
297 7e84c249 bellard
    /* if task gate, we read the TSS segment and we load it */
298 7e84c249 bellard
    if (type == 5) {
299 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
300 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
301 7e84c249 bellard
        tss_selector = e1 >> 16;
302 7e84c249 bellard
        if (tss_selector & 4)
303 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
304 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
305 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
306 7e84c249 bellard
        if (e2 & DESC_S_MASK)
307 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
308 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
309 7e84c249 bellard
        if ((type & 7) != 1)
310 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
311 7e84c249 bellard
    }
312 7e84c249 bellard
313 7e84c249 bellard
    if (!(e2 & DESC_P_MASK))
314 7e84c249 bellard
        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
315 7e84c249 bellard
316 7e84c249 bellard
    if (type & 8)
317 7e84c249 bellard
        tss_limit_max = 103;
318 2c0262af bellard
    else
319 7e84c249 bellard
        tss_limit_max = 43;
320 7e84c249 bellard
    tss_limit = get_seg_limit(e1, e2);
321 7e84c249 bellard
    tss_base = get_seg_base(e1, e2);
322 7e84c249 bellard
    if ((tss_selector & 4) != 0 || 
323 7e84c249 bellard
        tss_limit < tss_limit_max)
324 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
325 7e84c249 bellard
    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
326 7e84c249 bellard
    if (old_type & 8)
327 7e84c249 bellard
        old_tss_limit_max = 103;
328 7e84c249 bellard
    else
329 7e84c249 bellard
        old_tss_limit_max = 43;
330 7e84c249 bellard
331 7e84c249 bellard
    /* read all the registers from the new TSS */
332 7e84c249 bellard
    if (type & 8) {
333 7e84c249 bellard
        /* 32 bit */
334 7e84c249 bellard
        new_cr3 = ldl_kernel(tss_base + 0x1c);
335 7e84c249 bellard
        new_eip = ldl_kernel(tss_base + 0x20);
336 7e84c249 bellard
        new_eflags = ldl_kernel(tss_base + 0x24);
337 7e84c249 bellard
        for(i = 0; i < 8; i++)
338 7e84c249 bellard
            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
339 7e84c249 bellard
        for(i = 0; i < 6; i++)
340 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
341 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x60);
342 7e84c249 bellard
        new_trap = ldl_kernel(tss_base + 0x64);
343 7e84c249 bellard
    } else {
344 7e84c249 bellard
        /* 16 bit */
345 7e84c249 bellard
        new_cr3 = 0;
346 7e84c249 bellard
        new_eip = lduw_kernel(tss_base + 0x0e);
347 7e84c249 bellard
        new_eflags = lduw_kernel(tss_base + 0x10);
348 7e84c249 bellard
        for(i = 0; i < 8; i++)
349 7e84c249 bellard
            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
350 7e84c249 bellard
        for(i = 0; i < 4; i++)
351 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
352 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x2a);
353 7e84c249 bellard
        new_segs[R_FS] = 0;
354 7e84c249 bellard
        new_segs[R_GS] = 0;
355 7e84c249 bellard
        new_trap = 0;
356 7e84c249 bellard
    }
357 7e84c249 bellard
    
358 7e84c249 bellard
    /* NOTE: we must avoid memory exceptions during the task switch,
359 7e84c249 bellard
       so we make dummy accesses before */
360 7e84c249 bellard
    /* XXX: it can still fail in some cases, so a bigger hack is
361 7e84c249 bellard
       necessary to valid the TLB after having done the accesses */
362 7e84c249 bellard
363 7e84c249 bellard
    v1 = ldub_kernel(env->tr.base);
364 7e84c249 bellard
    v2 = ldub(env->tr.base + old_tss_limit_max);
365 7e84c249 bellard
    stb_kernel(env->tr.base, v1);
366 7e84c249 bellard
    stb_kernel(env->tr.base + old_tss_limit_max, v2);
367 7e84c249 bellard
    
368 7e84c249 bellard
    /* clear busy bit (it is restartable) */
369 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
370 7e84c249 bellard
        uint8_t *ptr;
371 7e84c249 bellard
        uint32_t e2;
372 7e84c249 bellard
        ptr = env->gdt.base + (env->tr.selector << 3);
373 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
374 7e84c249 bellard
        e2 &= ~DESC_TSS_BUSY_MASK;
375 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
376 7e84c249 bellard
    }
377 7e84c249 bellard
    old_eflags = compute_eflags();
378 7e84c249 bellard
    if (source == SWITCH_TSS_IRET)
379 7e84c249 bellard
        old_eflags &= ~NT_MASK;
380 7e84c249 bellard
    
381 7e84c249 bellard
    /* save the current state in the old TSS */
382 7e84c249 bellard
    if (type & 8) {
383 7e84c249 bellard
        /* 32 bit */
384 7e84c249 bellard
        stl_kernel(env->tr.base + 0x20, env->eip);
385 7e84c249 bellard
        stl_kernel(env->tr.base + 0x24, old_eflags);
386 7e84c249 bellard
        for(i = 0; i < 8; i++)
387 7e84c249 bellard
            stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]);
388 7e84c249 bellard
        for(i = 0; i < 6; i++)
389 7e84c249 bellard
            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
390 7e84c249 bellard
    } else {
391 7e84c249 bellard
        /* 16 bit */
392 7e84c249 bellard
        stw_kernel(env->tr.base + 0x0e, new_eip);
393 7e84c249 bellard
        stw_kernel(env->tr.base + 0x10, old_eflags);
394 7e84c249 bellard
        for(i = 0; i < 8; i++)
395 7e84c249 bellard
            stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]);
396 7e84c249 bellard
        for(i = 0; i < 4; i++)
397 7e84c249 bellard
            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
398 7e84c249 bellard
    }
399 7e84c249 bellard
    
400 7e84c249 bellard
    /* now if an exception occurs, it will occurs in the next task
401 7e84c249 bellard
       context */
402 7e84c249 bellard
403 7e84c249 bellard
    if (source == SWITCH_TSS_CALL) {
404 7e84c249 bellard
        stw_kernel(tss_base, env->tr.selector);
405 7e84c249 bellard
        new_eflags |= NT_MASK;
406 7e84c249 bellard
    }
407 7e84c249 bellard
408 7e84c249 bellard
    /* set busy bit */
409 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
410 7e84c249 bellard
        uint8_t *ptr;
411 7e84c249 bellard
        uint32_t e2;
412 7e84c249 bellard
        ptr = env->gdt.base + (tss_selector << 3);
413 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
414 7e84c249 bellard
        e2 |= DESC_TSS_BUSY_MASK;
415 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
416 7e84c249 bellard
    }
417 7e84c249 bellard
418 7e84c249 bellard
    /* set the new CPU state */
419 7e84c249 bellard
    /* from this point, any exception which occurs can give problems */
420 7e84c249 bellard
    env->cr[0] |= CR0_TS_MASK;
421 7e84c249 bellard
    env->tr.selector = tss_selector;
422 7e84c249 bellard
    env->tr.base = tss_base;
423 7e84c249 bellard
    env->tr.limit = tss_limit;
424 7e84c249 bellard
    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
425 7e84c249 bellard
    
426 7e84c249 bellard
    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
427 1ac157da bellard
        cpu_x86_update_cr3(env, new_cr3);
428 7e84c249 bellard
    }
429 7e84c249 bellard
    
430 7e84c249 bellard
    /* load all registers without an exception, then reload them with
431 7e84c249 bellard
       possible exception */
432 7e84c249 bellard
    env->eip = new_eip;
433 4136f33c bellard
    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
434 8145122b bellard
        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
435 7e84c249 bellard
    if (!(type & 8))
436 7e84c249 bellard
        eflags_mask &= 0xffff;
437 7e84c249 bellard
    load_eflags(new_eflags, eflags_mask);
438 7e84c249 bellard
    for(i = 0; i < 8; i++)
439 7e84c249 bellard
        env->regs[i] = new_regs[i];
440 7e84c249 bellard
    if (new_eflags & VM_MASK) {
441 7e84c249 bellard
        for(i = 0; i < 6; i++) 
442 7e84c249 bellard
            load_seg_vm(i, new_segs[i]);
443 7e84c249 bellard
        /* in vm86, CPL is always 3 */
444 7e84c249 bellard
        cpu_x86_set_cpl(env, 3);
445 7e84c249 bellard
    } else {
446 7e84c249 bellard
        /* CPL is set the RPL of CS */
447 7e84c249 bellard
        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
448 7e84c249 bellard
        /* first just selectors as the rest may trigger exceptions */
449 7e84c249 bellard
        for(i = 0; i < 6; i++)
450 7e84c249 bellard
            cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0);
451 7e84c249 bellard
    }
452 7e84c249 bellard
    
453 7e84c249 bellard
    env->ldt.selector = new_ldt & ~4;
454 7e84c249 bellard
    env->ldt.base = NULL;
455 7e84c249 bellard
    env->ldt.limit = 0;
456 7e84c249 bellard
    env->ldt.flags = 0;
457 7e84c249 bellard
458 7e84c249 bellard
    /* load the LDT */
459 7e84c249 bellard
    if (new_ldt & 4)
460 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
461 7e84c249 bellard
462 8145122b bellard
    if ((new_ldt & 0xfffc) != 0) {
463 8145122b bellard
        dt = &env->gdt;
464 8145122b bellard
        index = new_ldt & ~7;
465 8145122b bellard
        if ((index + 7) > dt->limit)
466 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
467 8145122b bellard
        ptr = dt->base + index;
468 8145122b bellard
        e1 = ldl_kernel(ptr);
469 8145122b bellard
        e2 = ldl_kernel(ptr + 4);
470 8145122b bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
471 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
472 8145122b bellard
        if (!(e2 & DESC_P_MASK))
473 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
474 8145122b bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
475 8145122b bellard
    }
476 7e84c249 bellard
    
477 7e84c249 bellard
    /* load the segments */
478 7e84c249 bellard
    if (!(new_eflags & VM_MASK)) {
479 7e84c249 bellard
        tss_load_seg(R_CS, new_segs[R_CS]);
480 7e84c249 bellard
        tss_load_seg(R_SS, new_segs[R_SS]);
481 7e84c249 bellard
        tss_load_seg(R_ES, new_segs[R_ES]);
482 7e84c249 bellard
        tss_load_seg(R_DS, new_segs[R_DS]);
483 7e84c249 bellard
        tss_load_seg(R_FS, new_segs[R_FS]);
484 7e84c249 bellard
        tss_load_seg(R_GS, new_segs[R_GS]);
485 7e84c249 bellard
    }
486 7e84c249 bellard
    
487 7e84c249 bellard
    /* check that EIP is in the CS segment limits */
488 7e84c249 bellard
    if (new_eip > env->segs[R_CS].limit) {
489 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
490 7e84c249 bellard
    }
491 2c0262af bellard
}
492 7e84c249 bellard
493 7e84c249 bellard
/* check if Port I/O is allowed in TSS */
494 7e84c249 bellard
static inline void check_io(int addr, int size)
495 2c0262af bellard
{
496 7e84c249 bellard
    int io_offset, val, mask;
497 7e84c249 bellard
    
498 7e84c249 bellard
    /* TSS must be a valid 32 bit one */
499 7e84c249 bellard
    if (!(env->tr.flags & DESC_P_MASK) ||
500 7e84c249 bellard
        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
501 7e84c249 bellard
        env->tr.limit < 103)
502 7e84c249 bellard
        goto fail;
503 7e84c249 bellard
    io_offset = lduw_kernel(env->tr.base + 0x66);
504 7e84c249 bellard
    io_offset += (addr >> 3);
505 7e84c249 bellard
    /* Note: the check needs two bytes */
506 7e84c249 bellard
    if ((io_offset + 1) > env->tr.limit)
507 7e84c249 bellard
        goto fail;
508 7e84c249 bellard
    val = lduw_kernel(env->tr.base + io_offset);
509 7e84c249 bellard
    val >>= (addr & 7);
510 7e84c249 bellard
    mask = (1 << size) - 1;
511 7e84c249 bellard
    /* all bits must be zero to allow the I/O */
512 7e84c249 bellard
    if ((val & mask) != 0) {
513 7e84c249 bellard
    fail:
514 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
515 7e84c249 bellard
    }
516 2c0262af bellard
}
517 2c0262af bellard
518 7e84c249 bellard
void check_iob_T0(void)
519 2c0262af bellard
{
520 7e84c249 bellard
    check_io(T0, 1);
521 2c0262af bellard
}
522 2c0262af bellard
523 7e84c249 bellard
void check_iow_T0(void)
524 2c0262af bellard
{
525 7e84c249 bellard
    check_io(T0, 2);
526 2c0262af bellard
}
527 2c0262af bellard
528 7e84c249 bellard
void check_iol_T0(void)
529 2c0262af bellard
{
530 7e84c249 bellard
    check_io(T0, 4);
531 7e84c249 bellard
}
532 7e84c249 bellard
533 7e84c249 bellard
void check_iob_DX(void)
534 7e84c249 bellard
{
535 7e84c249 bellard
    check_io(EDX & 0xffff, 1);
536 7e84c249 bellard
}
537 7e84c249 bellard
538 7e84c249 bellard
void check_iow_DX(void)
539 7e84c249 bellard
{
540 7e84c249 bellard
    check_io(EDX & 0xffff, 2);
541 7e84c249 bellard
}
542 7e84c249 bellard
543 7e84c249 bellard
void check_iol_DX(void)
544 7e84c249 bellard
{
545 7e84c249 bellard
    check_io(EDX & 0xffff, 4);
546 2c0262af bellard
}
547 2c0262af bellard
548 891b38e4 bellard
static inline unsigned int get_sp_mask(unsigned int e2)
549 891b38e4 bellard
{
550 891b38e4 bellard
    if (e2 & DESC_B_MASK)
551 891b38e4 bellard
        return 0xffffffff;
552 891b38e4 bellard
    else
553 891b38e4 bellard
        return 0xffff;
554 891b38e4 bellard
}
555 891b38e4 bellard
556 891b38e4 bellard
/* XXX: add a is_user flag to have proper security support */
557 891b38e4 bellard
#define PUSHW(ssp, sp, sp_mask, val)\
558 891b38e4 bellard
{\
559 891b38e4 bellard
    sp -= 2;\
560 891b38e4 bellard
    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
561 891b38e4 bellard
}
562 891b38e4 bellard
563 891b38e4 bellard
#define PUSHL(ssp, sp, sp_mask, val)\
564 891b38e4 bellard
{\
565 891b38e4 bellard
    sp -= 4;\
566 891b38e4 bellard
    stl_kernel((ssp) + (sp & (sp_mask)), (val));\
567 891b38e4 bellard
}
568 891b38e4 bellard
569 891b38e4 bellard
#define POPW(ssp, sp, sp_mask, val)\
570 891b38e4 bellard
{\
571 891b38e4 bellard
    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
572 891b38e4 bellard
    sp += 2;\
573 891b38e4 bellard
}
574 891b38e4 bellard
575 891b38e4 bellard
#define POPL(ssp, sp, sp_mask, val)\
576 891b38e4 bellard
{\
577 891b38e4 bellard
    val = ldl_kernel((ssp) + (sp & (sp_mask)));\
578 891b38e4 bellard
    sp += 4;\
579 891b38e4 bellard
}
580 891b38e4 bellard
581 2c0262af bellard
/* protected mode interrupt */
582 2c0262af bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
583 2c0262af bellard
                                   unsigned int next_eip, int is_hw)
584 2c0262af bellard
{
585 2c0262af bellard
    SegmentCache *dt;
586 2c0262af bellard
    uint8_t *ptr, *ssp;
587 891b38e4 bellard
    int type, dpl, selector, ss_dpl, cpl, sp_mask;
588 2c0262af bellard
    int has_error_code, new_stack, shift;
589 891b38e4 bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
590 891b38e4 bellard
    uint32_t old_eip;
591 2c0262af bellard
592 7e84c249 bellard
    has_error_code = 0;
593 7e84c249 bellard
    if (!is_int && !is_hw) {
594 7e84c249 bellard
        switch(intno) {
595 7e84c249 bellard
        case 8:
596 7e84c249 bellard
        case 10:
597 7e84c249 bellard
        case 11:
598 7e84c249 bellard
        case 12:
599 7e84c249 bellard
        case 13:
600 7e84c249 bellard
        case 14:
601 7e84c249 bellard
        case 17:
602 7e84c249 bellard
            has_error_code = 1;
603 7e84c249 bellard
            break;
604 7e84c249 bellard
        }
605 7e84c249 bellard
    }
606 7e84c249 bellard
607 2c0262af bellard
    dt = &env->idt;
608 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
609 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
610 2c0262af bellard
    ptr = dt->base + intno * 8;
611 61382a50 bellard
    e1 = ldl_kernel(ptr);
612 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
613 2c0262af bellard
    /* check gate type */
614 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
615 2c0262af bellard
    switch(type) {
616 2c0262af bellard
    case 5: /* task gate */
617 7e84c249 bellard
        /* must do that check here to return the correct error code */
618 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
619 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
620 7e84c249 bellard
        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL);
621 7e84c249 bellard
        if (has_error_code) {
622 7e84c249 bellard
            int mask;
623 7e84c249 bellard
            /* push the error code */
624 7e84c249 bellard
            shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1;
625 7e84c249 bellard
            if (env->segs[R_SS].flags & DESC_B_MASK)
626 7e84c249 bellard
                mask = 0xffffffff;
627 7e84c249 bellard
            else
628 7e84c249 bellard
                mask = 0xffff;
629 7e84c249 bellard
            esp = (env->regs[R_ESP] - (2 << shift)) & mask;
630 7e84c249 bellard
            ssp = env->segs[R_SS].base + esp;
631 7e84c249 bellard
            if (shift)
632 7e84c249 bellard
                stl_kernel(ssp, error_code);
633 7e84c249 bellard
            else
634 7e84c249 bellard
                stw_kernel(ssp, error_code);
635 7e84c249 bellard
            env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask);
636 7e84c249 bellard
        }
637 7e84c249 bellard
        return;
638 2c0262af bellard
    case 6: /* 286 interrupt gate */
639 2c0262af bellard
    case 7: /* 286 trap gate */
640 2c0262af bellard
    case 14: /* 386 interrupt gate */
641 2c0262af bellard
    case 15: /* 386 trap gate */
642 2c0262af bellard
        break;
643 2c0262af bellard
    default:
644 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
645 2c0262af bellard
        break;
646 2c0262af bellard
    }
647 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
648 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
649 2c0262af bellard
    /* check privledge if software int */
650 2c0262af bellard
    if (is_int && dpl < cpl)
651 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
652 2c0262af bellard
    /* check valid bit */
653 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
654 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
655 2c0262af bellard
    selector = e1 >> 16;
656 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
657 2c0262af bellard
    if ((selector & 0xfffc) == 0)
658 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
659 2c0262af bellard
660 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
661 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
662 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
663 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
664 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
665 2c0262af bellard
    if (dpl > cpl)
666 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
667 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
668 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
669 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
670 2c0262af bellard
        /* to inner priviledge */
671 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
672 2c0262af bellard
        if ((ss & 0xfffc) == 0)
673 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
674 2c0262af bellard
        if ((ss & 3) != dpl)
675 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
676 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
677 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
678 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
679 2c0262af bellard
        if (ss_dpl != dpl)
680 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
681 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
682 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
683 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
684 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
685 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
686 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
687 2c0262af bellard
        new_stack = 1;
688 891b38e4 bellard
        sp_mask = get_sp_mask(ss_e2);
689 891b38e4 bellard
        ssp = get_seg_base(ss_e1, ss_e2);
690 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
691 2c0262af bellard
        /* to same priviledge */
692 8e682019 bellard
        if (env->eflags & VM_MASK)
693 8e682019 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
694 2c0262af bellard
        new_stack = 0;
695 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
696 891b38e4 bellard
        ssp = env->segs[R_SS].base;
697 891b38e4 bellard
        esp = ESP;
698 4796f5e9 bellard
        dpl = cpl;
699 2c0262af bellard
    } else {
700 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
701 2c0262af bellard
        new_stack = 0; /* avoid warning */
702 891b38e4 bellard
        sp_mask = 0; /* avoid warning */
703 891b38e4 bellard
        ssp = NULL; /* avoid warning */
704 891b38e4 bellard
        esp = 0; /* avoid warning */
705 2c0262af bellard
    }
706 2c0262af bellard
707 2c0262af bellard
    shift = type >> 3;
708 891b38e4 bellard
709 891b38e4 bellard
#if 0
710 891b38e4 bellard
    /* XXX: check that enough room is available */
711 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
712 2c0262af bellard
    if (env->eflags & VM_MASK)
713 2c0262af bellard
        push_size += 8;
714 2c0262af bellard
    push_size <<= shift;
715 891b38e4 bellard
#endif
716 2c0262af bellard
    if (is_int)
717 2c0262af bellard
        old_eip = next_eip;
718 2c0262af bellard
    else
719 2c0262af bellard
        old_eip = env->eip;
720 2c0262af bellard
    if (shift == 1) {
721 2c0262af bellard
        if (new_stack) {
722 8e682019 bellard
            if (env->eflags & VM_MASK) {
723 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
724 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
725 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
726 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
727 8e682019 bellard
            }
728 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
729 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, ESP);
730 2c0262af bellard
        }
731 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, compute_eflags());
732 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
733 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, old_eip);
734 2c0262af bellard
        if (has_error_code) {
735 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, error_code);
736 2c0262af bellard
        }
737 2c0262af bellard
    } else {
738 2c0262af bellard
        if (new_stack) {
739 8e682019 bellard
            if (env->eflags & VM_MASK) {
740 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
741 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
742 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
743 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
744 8e682019 bellard
            }
745 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
746 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, ESP);
747 2c0262af bellard
        }
748 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, compute_eflags());
749 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
750 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, old_eip);
751 2c0262af bellard
        if (has_error_code) {
752 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, error_code);
753 2c0262af bellard
        }
754 2c0262af bellard
    }
755 2c0262af bellard
    
756 891b38e4 bellard
    if (new_stack) {
757 8e682019 bellard
        if (env->eflags & VM_MASK) {
758 8e682019 bellard
            /* XXX: explain me why W2K hangs if the whole segment cache is
759 8e682019 bellard
               reset ? */
760 8145122b bellard
#if 1
761 8e682019 bellard
            env->segs[R_ES].selector = 0;
762 8e682019 bellard
            env->segs[R_ES].flags = 0;
763 8e682019 bellard
            env->segs[R_DS].selector = 0;
764 8e682019 bellard
            env->segs[R_DS].flags = 0;
765 8e682019 bellard
            env->segs[R_FS].selector = 0;
766 8e682019 bellard
            env->segs[R_FS].flags = 0;
767 8e682019 bellard
            env->segs[R_GS].selector = 0;
768 8e682019 bellard
            env->segs[R_GS].flags = 0;
769 8145122b bellard
#else
770 8145122b bellard
            cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0);
771 8145122b bellard
            cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0);
772 8145122b bellard
            cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0);
773 8145122b bellard
            cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0);
774 8145122b bellard
#endif
775 8e682019 bellard
        }
776 891b38e4 bellard
        ss = (ss & ~3) | dpl;
777 891b38e4 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
778 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
779 891b38e4 bellard
    }
780 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (esp & sp_mask);
781 891b38e4 bellard
782 891b38e4 bellard
    selector = (selector & ~3) | dpl;
783 891b38e4 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
784 891b38e4 bellard
                   get_seg_base(e1, e2),
785 891b38e4 bellard
                   get_seg_limit(e1, e2),
786 891b38e4 bellard
                   e2);
787 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
788 891b38e4 bellard
    env->eip = offset;
789 891b38e4 bellard
790 2c0262af bellard
    /* interrupt gate clear IF mask */
791 2c0262af bellard
    if ((type & 1) == 0) {
792 2c0262af bellard
        env->eflags &= ~IF_MASK;
793 2c0262af bellard
    }
794 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
795 2c0262af bellard
}
796 2c0262af bellard
797 2c0262af bellard
/* real mode interrupt */
798 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
799 4136f33c bellard
                              unsigned int next_eip)
800 2c0262af bellard
{
801 2c0262af bellard
    SegmentCache *dt;
802 2c0262af bellard
    uint8_t *ptr, *ssp;
803 2c0262af bellard
    int selector;
804 2c0262af bellard
    uint32_t offset, esp;
805 2c0262af bellard
    uint32_t old_cs, old_eip;
806 2c0262af bellard
807 2c0262af bellard
    /* real mode (simpler !) */
808 2c0262af bellard
    dt = &env->idt;
809 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
810 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
811 2c0262af bellard
    ptr = dt->base + intno * 4;
812 61382a50 bellard
    offset = lduw_kernel(ptr);
813 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
814 2c0262af bellard
    esp = ESP;
815 2c0262af bellard
    ssp = env->segs[R_SS].base;
816 2c0262af bellard
    if (is_int)
817 2c0262af bellard
        old_eip = next_eip;
818 2c0262af bellard
    else
819 2c0262af bellard
        old_eip = env->eip;
820 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
821 891b38e4 bellard
    /* XXX: use SS segment size ? */
822 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
823 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
824 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
825 2c0262af bellard
    
826 2c0262af bellard
    /* update processor state */
827 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
828 2c0262af bellard
    env->eip = offset;
829 2c0262af bellard
    env->segs[R_CS].selector = selector;
830 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(selector << 4);
831 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
832 2c0262af bellard
}
833 2c0262af bellard
834 2c0262af bellard
/* fake user mode interrupt */
835 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
836 2c0262af bellard
                       unsigned int next_eip)
837 2c0262af bellard
{
838 2c0262af bellard
    SegmentCache *dt;
839 2c0262af bellard
    uint8_t *ptr;
840 2c0262af bellard
    int dpl, cpl;
841 2c0262af bellard
    uint32_t e2;
842 2c0262af bellard
843 2c0262af bellard
    dt = &env->idt;
844 2c0262af bellard
    ptr = dt->base + (intno * 8);
845 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
846 2c0262af bellard
    
847 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
848 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
849 2c0262af bellard
    /* check privledge if software int */
850 2c0262af bellard
    if (is_int && dpl < cpl)
851 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
852 2c0262af bellard
853 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
854 2c0262af bellard
       exiting the emulation with the suitable exception and error
855 2c0262af bellard
       code */
856 2c0262af bellard
    if (is_int)
857 2c0262af bellard
        EIP = next_eip;
858 2c0262af bellard
}
859 2c0262af bellard
860 2c0262af bellard
/*
861 2c0262af bellard
 * Begin excution of an interruption. is_int is TRUE if coming from
862 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
863 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
864 2c0262af bellard
 */
865 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
866 2c0262af bellard
                  unsigned int next_eip, int is_hw)
867 2c0262af bellard
{
868 8e682019 bellard
#if 0
869 8e682019 bellard
    {
870 8e682019 bellard
        extern FILE *stdout;
871 8e682019 bellard
        static int count;
872 8145122b bellard
        if (env->cr[0] & CR0_PE_MASK) {
873 8145122b bellard
            fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x",
874 dc6f57fd bellard
                    count, intno, error_code, is_int,
875 dc6f57fd bellard
                    env->hflags & HF_CPL_MASK,
876 dc6f57fd bellard
                    env->segs[R_CS].selector, EIP,
877 8145122b bellard
                    env->segs[R_SS].selector, ESP);
878 8145122b bellard
            if (intno == 0x0e) {
879 8145122b bellard
                fprintf(stdout, " CR2=%08x", env->cr[2]);
880 8145122b bellard
            } else {
881 8145122b bellard
                fprintf(stdout, " EAX=%08x", env->regs[R_EAX]);
882 8145122b bellard
            }
883 8145122b bellard
            fprintf(stdout, "\n");
884 8145122b bellard

885 dc6f57fd bellard
            if (0) {
886 dc6f57fd bellard
                cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP);
887 dc6f57fd bellard
#if 0
888 dc6f57fd bellard
                {
889 dc6f57fd bellard
                    int i;
890 dc6f57fd bellard
                    uint8_t *ptr;
891 dc6f57fd bellard
                    fprintf(stdout, "       code=");
892 dc6f57fd bellard
                    ptr = env->segs[R_CS].base + env->eip;
893 dc6f57fd bellard
                    for(i = 0; i < 16; i++) {
894 dc6f57fd bellard
                        fprintf(stdout, " %02x", ldub(ptr + i));
895 dc6f57fd bellard
                    }
896 dc6f57fd bellard
                    fprintf(stdout, "\n");
897 dc6f57fd bellard
                }
898 dc6f57fd bellard
#endif
899 dc6f57fd bellard
            }
900 8e682019 bellard
            count++;
901 8e682019 bellard
        }
902 8e682019 bellard
    }
903 8e682019 bellard
#endif
904 4136f33c bellard
#ifdef DEBUG_PCALL
905 4136f33c bellard
    if (loglevel) {
906 4136f33c bellard
        static int count;
907 4136f33c bellard
        fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
908 4136f33c bellard
                count, intno, error_code, is_int);
909 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
910 dc6f57fd bellard
#if 0
911 4136f33c bellard
        {
912 4136f33c bellard
            int i;
913 4136f33c bellard
            uint8_t *ptr;
914 8e682019 bellard
            fprintf(logfile, "       code=");
915 4136f33c bellard
            ptr = env->segs[R_CS].base + env->eip;
916 4136f33c bellard
            for(i = 0; i < 16; i++) {
917 8e682019 bellard
                fprintf(logfile, " %02x", ldub(ptr + i));
918 4136f33c bellard
            }
919 8e682019 bellard
            fprintf(logfile, "\n");
920 4136f33c bellard
        }
921 4136f33c bellard
#endif
922 4136f33c bellard
        count++;
923 4136f33c bellard
    }
924 4136f33c bellard
#endif
925 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
926 2c0262af bellard
        do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
927 2c0262af bellard
    } else {
928 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
929 2c0262af bellard
    }
930 2c0262af bellard
}
931 2c0262af bellard
932 2c0262af bellard
/*
933 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
934 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
935 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
936 2c0262af bellard
 * is_int is TRUE.  
937 2c0262af bellard
 */
938 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
939 2c0262af bellard
                     unsigned int next_eip)
940 2c0262af bellard
{
941 2c0262af bellard
    env->exception_index = intno;
942 2c0262af bellard
    env->error_code = error_code;
943 2c0262af bellard
    env->exception_is_int = is_int;
944 2c0262af bellard
    env->exception_next_eip = next_eip;
945 2c0262af bellard
    cpu_loop_exit();
946 2c0262af bellard
}
947 2c0262af bellard
948 2c0262af bellard
/* shortcuts to generate exceptions */
949 8145122b bellard
950 8145122b bellard
void (raise_exception_err)(int exception_index, int error_code)
951 2c0262af bellard
{
952 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
953 2c0262af bellard
}
954 2c0262af bellard
955 2c0262af bellard
void raise_exception(int exception_index)
956 2c0262af bellard
{
957 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
958 2c0262af bellard
}
959 2c0262af bellard
960 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
961 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
962 2c0262af bellard
   call it from another function */
963 2c0262af bellard
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
964 2c0262af bellard
{
965 2c0262af bellard
    *q_ptr = num / den;
966 2c0262af bellard
    return num % den;
967 2c0262af bellard
}
968 2c0262af bellard
969 2c0262af bellard
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
970 2c0262af bellard
{
971 2c0262af bellard
    *q_ptr = num / den;
972 2c0262af bellard
    return num % den;
973 2c0262af bellard
}
974 2c0262af bellard
#endif
975 2c0262af bellard
976 2c0262af bellard
void helper_divl_EAX_T0(uint32_t eip)
977 2c0262af bellard
{
978 2c0262af bellard
    unsigned int den, q, r;
979 2c0262af bellard
    uint64_t num;
980 2c0262af bellard
    
981 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
982 2c0262af bellard
    den = T0;
983 2c0262af bellard
    if (den == 0) {
984 2c0262af bellard
        EIP = eip;
985 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
986 2c0262af bellard
    }
987 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
988 2c0262af bellard
    r = div64(&q, num, den);
989 2c0262af bellard
#else
990 2c0262af bellard
    q = (num / den);
991 2c0262af bellard
    r = (num % den);
992 2c0262af bellard
#endif
993 2c0262af bellard
    EAX = q;
994 2c0262af bellard
    EDX = r;
995 2c0262af bellard
}
996 2c0262af bellard
997 2c0262af bellard
void helper_idivl_EAX_T0(uint32_t eip)
998 2c0262af bellard
{
999 2c0262af bellard
    int den, q, r;
1000 2c0262af bellard
    int64_t num;
1001 2c0262af bellard
    
1002 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
1003 2c0262af bellard
    den = T0;
1004 2c0262af bellard
    if (den == 0) {
1005 2c0262af bellard
        EIP = eip;
1006 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1007 2c0262af bellard
    }
1008 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1009 2c0262af bellard
    r = idiv64(&q, num, den);
1010 2c0262af bellard
#else
1011 2c0262af bellard
    q = (num / den);
1012 2c0262af bellard
    r = (num % den);
1013 2c0262af bellard
#endif
1014 2c0262af bellard
    EAX = q;
1015 2c0262af bellard
    EDX = r;
1016 2c0262af bellard
}
1017 2c0262af bellard
1018 2c0262af bellard
void helper_cmpxchg8b(void)
1019 2c0262af bellard
{
1020 2c0262af bellard
    uint64_t d;
1021 2c0262af bellard
    int eflags;
1022 2c0262af bellard
1023 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
1024 2c0262af bellard
    d = ldq((uint8_t *)A0);
1025 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
1026 2c0262af bellard
        stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
1027 2c0262af bellard
        eflags |= CC_Z;
1028 2c0262af bellard
    } else {
1029 2c0262af bellard
        EDX = d >> 32;
1030 2c0262af bellard
        EAX = d;
1031 2c0262af bellard
        eflags &= ~CC_Z;
1032 2c0262af bellard
    }
1033 2c0262af bellard
    CC_SRC = eflags;
1034 2c0262af bellard
}
1035 2c0262af bellard
1036 2c0262af bellard
#define CPUID_FP87 (1 << 0)
1037 2c0262af bellard
#define CPUID_VME  (1 << 1)
1038 2c0262af bellard
#define CPUID_DE   (1 << 2)
1039 2c0262af bellard
#define CPUID_PSE  (1 << 3)
1040 2c0262af bellard
#define CPUID_TSC  (1 << 4)
1041 2c0262af bellard
#define CPUID_MSR  (1 << 5)
1042 2c0262af bellard
#define CPUID_PAE  (1 << 6)
1043 2c0262af bellard
#define CPUID_MCE  (1 << 7)
1044 2c0262af bellard
#define CPUID_CX8  (1 << 8)
1045 2c0262af bellard
#define CPUID_APIC (1 << 9)
1046 2c0262af bellard
#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
1047 2c0262af bellard
#define CPUID_MTRR (1 << 12)
1048 2c0262af bellard
#define CPUID_PGE  (1 << 13)
1049 2c0262af bellard
#define CPUID_MCA  (1 << 14)
1050 2c0262af bellard
#define CPUID_CMOV (1 << 15)
1051 2c0262af bellard
/* ... */
1052 2c0262af bellard
#define CPUID_MMX  (1 << 23)
1053 2c0262af bellard
#define CPUID_FXSR (1 << 24)
1054 2c0262af bellard
#define CPUID_SSE  (1 << 25)
1055 2c0262af bellard
#define CPUID_SSE2 (1 << 26)
1056 2c0262af bellard
1057 2c0262af bellard
void helper_cpuid(void)
1058 2c0262af bellard
{
1059 8e682019 bellard
    switch(EAX) {
1060 8e682019 bellard
    case 0:
1061 8e682019 bellard
        EAX = 2; /* max EAX index supported */
1062 2c0262af bellard
        EBX = 0x756e6547;
1063 2c0262af bellard
        ECX = 0x6c65746e;
1064 2c0262af bellard
        EDX = 0x49656e69;
1065 8e682019 bellard
        break;
1066 8e682019 bellard
    case 1:
1067 8e682019 bellard
        {
1068 8e682019 bellard
            int family, model, stepping;
1069 8e682019 bellard
            /* EAX = 1 info */
1070 2c0262af bellard
#if 0
1071 8e682019 bellard
            /* pentium 75-200 */
1072 8e682019 bellard
            family = 5;
1073 8e682019 bellard
            model = 2;
1074 8e682019 bellard
            stepping = 11;
1075 2c0262af bellard
#else
1076 8e682019 bellard
            /* pentium pro */
1077 8e682019 bellard
            family = 6;
1078 8e682019 bellard
            model = 1;
1079 8e682019 bellard
            stepping = 3;
1080 2c0262af bellard
#endif
1081 8e682019 bellard
            EAX = (family << 8) | (model << 4) | stepping;
1082 8e682019 bellard
            EBX = 0;
1083 8e682019 bellard
            ECX = 0;
1084 8e682019 bellard
            EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
1085 8e682019 bellard
                CPUID_TSC | CPUID_MSR | CPUID_MCE |
1086 8e682019 bellard
                CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
1087 8e682019 bellard
        }
1088 8e682019 bellard
        break;
1089 8e682019 bellard
    default:
1090 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1091 8e682019 bellard
        EAX = 0x410601;
1092 2c0262af bellard
        EBX = 0;
1093 2c0262af bellard
        ECX = 0;
1094 8e682019 bellard
        EDX = 0;
1095 8e682019 bellard
        break;
1096 2c0262af bellard
    }
1097 2c0262af bellard
}
1098 2c0262af bellard
1099 2c0262af bellard
void helper_lldt_T0(void)
1100 2c0262af bellard
{
1101 2c0262af bellard
    int selector;
1102 2c0262af bellard
    SegmentCache *dt;
1103 2c0262af bellard
    uint32_t e1, e2;
1104 2c0262af bellard
    int index;
1105 2c0262af bellard
    uint8_t *ptr;
1106 2c0262af bellard
    
1107 2c0262af bellard
    selector = T0 & 0xffff;
1108 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1109 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1110 2c0262af bellard
        env->ldt.base = NULL;
1111 2c0262af bellard
        env->ldt.limit = 0;
1112 2c0262af bellard
    } else {
1113 2c0262af bellard
        if (selector & 0x4)
1114 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1115 2c0262af bellard
        dt = &env->gdt;
1116 2c0262af bellard
        index = selector & ~7;
1117 2c0262af bellard
        if ((index + 7) > dt->limit)
1118 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1119 2c0262af bellard
        ptr = dt->base + index;
1120 61382a50 bellard
        e1 = ldl_kernel(ptr);
1121 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1122 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1123 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1124 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1125 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1126 2c0262af bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
1127 2c0262af bellard
    }
1128 2c0262af bellard
    env->ldt.selector = selector;
1129 2c0262af bellard
}
1130 2c0262af bellard
1131 2c0262af bellard
void helper_ltr_T0(void)
1132 2c0262af bellard
{
1133 2c0262af bellard
    int selector;
1134 2c0262af bellard
    SegmentCache *dt;
1135 2c0262af bellard
    uint32_t e1, e2;
1136 2c0262af bellard
    int index, type;
1137 2c0262af bellard
    uint8_t *ptr;
1138 2c0262af bellard
    
1139 2c0262af bellard
    selector = T0 & 0xffff;
1140 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1141 2c0262af bellard
        /* NULL selector case: invalid LDT */
1142 2c0262af bellard
        env->tr.base = NULL;
1143 2c0262af bellard
        env->tr.limit = 0;
1144 2c0262af bellard
        env->tr.flags = 0;
1145 2c0262af bellard
    } else {
1146 2c0262af bellard
        if (selector & 0x4)
1147 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1148 2c0262af bellard
        dt = &env->gdt;
1149 2c0262af bellard
        index = selector & ~7;
1150 2c0262af bellard
        if ((index + 7) > dt->limit)
1151 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1152 2c0262af bellard
        ptr = dt->base + index;
1153 61382a50 bellard
        e1 = ldl_kernel(ptr);
1154 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1155 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1156 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
1157 7e84c249 bellard
            (type != 1 && type != 9))
1158 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1159 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1160 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1161 2c0262af bellard
        load_seg_cache_raw_dt(&env->tr, e1, e2);
1162 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1163 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1164 2c0262af bellard
    }
1165 2c0262af bellard
    env->tr.selector = selector;
1166 2c0262af bellard
}
1167 2c0262af bellard
1168 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1169 8e682019 bellard
void load_seg(int seg_reg, int selector)
1170 2c0262af bellard
{
1171 2c0262af bellard
    uint32_t e1, e2;
1172 3ab493de bellard
    int cpl, dpl, rpl;
1173 3ab493de bellard
    SegmentCache *dt;
1174 3ab493de bellard
    int index;
1175 3ab493de bellard
    uint8_t *ptr;
1176 3ab493de bellard
1177 8e682019 bellard
    selector &= 0xffff;
1178 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1179 2c0262af bellard
        /* null selector case */
1180 8e682019 bellard
        if (seg_reg == R_SS)
1181 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1182 8e682019 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
1183 2c0262af bellard
    } else {
1184 3ab493de bellard
        
1185 3ab493de bellard
        if (selector & 0x4)
1186 3ab493de bellard
            dt = &env->ldt;
1187 3ab493de bellard
        else
1188 3ab493de bellard
            dt = &env->gdt;
1189 3ab493de bellard
        index = selector & ~7;
1190 8e682019 bellard
        if ((index + 7) > dt->limit)
1191 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1192 3ab493de bellard
        ptr = dt->base + index;
1193 3ab493de bellard
        e1 = ldl_kernel(ptr);
1194 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1195 3ab493de bellard
1196 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1197 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1198 3ab493de bellard
        rpl = selector & 3;
1199 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1200 3ab493de bellard
        cpl = env->hflags & HF_CPL_MASK;
1201 2c0262af bellard
        if (seg_reg == R_SS) {
1202 3ab493de bellard
            /* must be writable segment */
1203 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1204 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1205 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1206 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1207 2c0262af bellard
        } else {
1208 3ab493de bellard
            /* must be readable segment */
1209 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1210 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1211 3ab493de bellard
            
1212 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1213 3ab493de bellard
                /* if not conforming code, test rights */
1214 8e682019 bellard
                if (dpl < cpl || dpl < rpl)
1215 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1216 3ab493de bellard
            }
1217 2c0262af bellard
        }
1218 2c0262af bellard
1219 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1220 2c0262af bellard
            if (seg_reg == R_SS)
1221 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1222 2c0262af bellard
            else
1223 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1224 2c0262af bellard
        }
1225 3ab493de bellard
1226 3ab493de bellard
        /* set the access bit if not already set */
1227 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1228 3ab493de bellard
            e2 |= DESC_A_MASK;
1229 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1230 3ab493de bellard
        }
1231 3ab493de bellard
1232 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
1233 2c0262af bellard
                       get_seg_base(e1, e2),
1234 2c0262af bellard
                       get_seg_limit(e1, e2),
1235 2c0262af bellard
                       e2);
1236 2c0262af bellard
#if 0
1237 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
1238 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1239 2c0262af bellard
#endif
1240 2c0262af bellard
    }
1241 2c0262af bellard
}
1242 2c0262af bellard
1243 2c0262af bellard
/* protected mode jump */
1244 2c0262af bellard
void helper_ljmp_protected_T0_T1(void)
1245 2c0262af bellard
{
1246 7e84c249 bellard
    int new_cs, new_eip, gate_cs, type;
1247 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
1248 2c0262af bellard
1249 2c0262af bellard
    new_cs = T0;
1250 2c0262af bellard
    new_eip = T1;
1251 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1252 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1253 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1254 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1255 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1256 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1257 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1258 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1259 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1260 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1261 2c0262af bellard
            /* conforming code segment */
1262 2c0262af bellard
            if (dpl > cpl)
1263 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1264 2c0262af bellard
        } else {
1265 2c0262af bellard
            /* non conforming code segment */
1266 2c0262af bellard
            rpl = new_cs & 3;
1267 2c0262af bellard
            if (rpl > cpl)
1268 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1269 2c0262af bellard
            if (dpl != cpl)
1270 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1271 2c0262af bellard
        }
1272 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1273 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1274 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1275 2c0262af bellard
        if (new_eip > limit)
1276 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1277 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1278 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1279 2c0262af bellard
        EIP = new_eip;
1280 2c0262af bellard
    } else {
1281 7e84c249 bellard
        /* jump to call or task gate */
1282 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1283 7e84c249 bellard
        rpl = new_cs & 3;
1284 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
1285 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1286 7e84c249 bellard
        switch(type) {
1287 7e84c249 bellard
        case 1: /* 286 TSS */
1288 7e84c249 bellard
        case 9: /* 386 TSS */
1289 7e84c249 bellard
        case 5: /* task gate */
1290 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1291 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1292 7e84c249 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP);
1293 7e84c249 bellard
            break;
1294 7e84c249 bellard
        case 4: /* 286 call gate */
1295 7e84c249 bellard
        case 12: /* 386 call gate */
1296 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
1297 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1298 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1299 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1300 7e84c249 bellard
            gate_cs = e1 >> 16;
1301 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
1302 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1303 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1304 7e84c249 bellard
            /* must be code segment */
1305 7e84c249 bellard
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
1306 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
1307 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1308 7e84c249 bellard
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1309 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1310 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1311 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1312 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1313 7e84c249 bellard
            new_eip = (e1 & 0xffff);
1314 7e84c249 bellard
            if (type == 12)
1315 7e84c249 bellard
                new_eip |= (e2 & 0xffff0000);
1316 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
1317 7e84c249 bellard
            if (new_eip > limit)
1318 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
1319 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1320 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
1321 7e84c249 bellard
            EIP = new_eip;
1322 7e84c249 bellard
            break;
1323 7e84c249 bellard
        default:
1324 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1325 7e84c249 bellard
            break;
1326 7e84c249 bellard
        }
1327 2c0262af bellard
    }
1328 2c0262af bellard
}
1329 2c0262af bellard
1330 2c0262af bellard
/* real mode call */
1331 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
1332 2c0262af bellard
{
1333 2c0262af bellard
    int new_cs, new_eip;
1334 2c0262af bellard
    uint32_t esp, esp_mask;
1335 2c0262af bellard
    uint8_t *ssp;
1336 2c0262af bellard
1337 2c0262af bellard
    new_cs = T0;
1338 2c0262af bellard
    new_eip = T1;
1339 2c0262af bellard
    esp = ESP;
1340 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1341 2c0262af bellard
    ssp = env->segs[R_SS].base;
1342 2c0262af bellard
    if (shift) {
1343 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1344 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
1345 2c0262af bellard
    } else {
1346 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1347 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
1348 2c0262af bellard
    }
1349 2c0262af bellard
1350 891b38e4 bellard
    ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1351 2c0262af bellard
    env->eip = new_eip;
1352 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
1353 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
1354 2c0262af bellard
}
1355 2c0262af bellard
1356 2c0262af bellard
/* protected mode call */
1357 2c0262af bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip)
1358 2c0262af bellard
{
1359 891b38e4 bellard
    int new_cs, new_eip, new_stack, i;
1360 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1361 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1362 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
1363 2c0262af bellard
    uint8_t *ssp, *old_ssp;
1364 2c0262af bellard
    
1365 2c0262af bellard
    new_cs = T0;
1366 2c0262af bellard
    new_eip = T1;
1367 f3f2d9be bellard
#ifdef DEBUG_PCALL
1368 f3f2d9be bellard
    if (loglevel) {
1369 f3f2d9be bellard
        fprintf(logfile, "lcall %04x:%08x\n",
1370 f3f2d9be bellard
                new_cs, new_eip);
1371 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1372 f3f2d9be bellard
    }
1373 f3f2d9be bellard
#endif
1374 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1375 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1376 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1377 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1378 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1379 f3f2d9be bellard
#ifdef DEBUG_PCALL
1380 f3f2d9be bellard
    if (loglevel) {
1381 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1382 f3f2d9be bellard
    }
1383 f3f2d9be bellard
#endif
1384 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1385 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1386 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1387 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1388 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1389 2c0262af bellard
            /* conforming code segment */
1390 2c0262af bellard
            if (dpl > cpl)
1391 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1392 2c0262af bellard
        } else {
1393 2c0262af bellard
            /* non conforming code segment */
1394 2c0262af bellard
            rpl = new_cs & 3;
1395 2c0262af bellard
            if (rpl > cpl)
1396 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1397 2c0262af bellard
            if (dpl != cpl)
1398 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1399 2c0262af bellard
        }
1400 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1401 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1402 2c0262af bellard
1403 2c0262af bellard
        sp = ESP;
1404 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
1405 891b38e4 bellard
        ssp = env->segs[R_SS].base;
1406 2c0262af bellard
        if (shift) {
1407 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1408 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1409 2c0262af bellard
        } else {
1410 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1411 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1412 2c0262af bellard
        }
1413 2c0262af bellard
        
1414 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1415 2c0262af bellard
        if (new_eip > limit)
1416 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1417 2c0262af bellard
        /* from this point, not restartable */
1418 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1419 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1420 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1421 2c0262af bellard
        EIP = new_eip;
1422 2c0262af bellard
    } else {
1423 2c0262af bellard
        /* check gate type */
1424 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1425 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1426 7e84c249 bellard
        rpl = new_cs & 3;
1427 2c0262af bellard
        switch(type) {
1428 2c0262af bellard
        case 1: /* available 286 TSS */
1429 2c0262af bellard
        case 9: /* available 386 TSS */
1430 2c0262af bellard
        case 5: /* task gate */
1431 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1432 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1433 7e84c249 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL);
1434 8145122b bellard
            return;
1435 2c0262af bellard
        case 4: /* 286 call gate */
1436 2c0262af bellard
        case 12: /* 386 call gate */
1437 2c0262af bellard
            break;
1438 2c0262af bellard
        default:
1439 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1440 2c0262af bellard
            break;
1441 2c0262af bellard
        }
1442 2c0262af bellard
        shift = type >> 3;
1443 2c0262af bellard
1444 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
1445 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1446 2c0262af bellard
        /* check valid bit */
1447 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1448 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
1449 2c0262af bellard
        selector = e1 >> 16;
1450 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1451 f3f2d9be bellard
        param_count = e2 & 0x1f;
1452 2c0262af bellard
        if ((selector & 0xfffc) == 0)
1453 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1454 2c0262af bellard
1455 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
1456 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1457 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1458 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1459 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1460 2c0262af bellard
        if (dpl > cpl)
1461 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1462 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1463 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1464 2c0262af bellard
1465 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1466 2c0262af bellard
            /* to inner priviledge */
1467 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
1468 f3f2d9be bellard
#ifdef DEBUG_PCALL
1469 f3f2d9be bellard
            if (loglevel)
1470 f3f2d9be bellard
                fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n", 
1471 f3f2d9be bellard
                        ss, sp, param_count, ESP);
1472 f3f2d9be bellard
#endif
1473 2c0262af bellard
            if ((ss & 0xfffc) == 0)
1474 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1475 2c0262af bellard
            if ((ss & 3) != dpl)
1476 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1477 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1478 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1479 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1480 2c0262af bellard
            if (ss_dpl != dpl)
1481 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1482 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
1483 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
1484 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
1485 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1486 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
1487 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1488 2c0262af bellard
            
1489 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
1490 2c0262af bellard
1491 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1492 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
1493 2c0262af bellard
            
1494 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
1495 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
1496 2c0262af bellard
            if (shift) {
1497 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1498 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
1499 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1500 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1501 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
1502 2c0262af bellard
                }
1503 2c0262af bellard
            } else {
1504 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1505 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
1506 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1507 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1508 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
1509 2c0262af bellard
                }
1510 2c0262af bellard
            }
1511 891b38e4 bellard
            new_stack = 1;
1512 2c0262af bellard
        } else {
1513 2c0262af bellard
            /* to same priviledge */
1514 891b38e4 bellard
            sp = ESP;
1515 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
1516 891b38e4 bellard
            ssp = env->segs[R_SS].base;
1517 891b38e4 bellard
            //            push_size = (4 << shift);
1518 891b38e4 bellard
            new_stack = 0;
1519 2c0262af bellard
        }
1520 2c0262af bellard
1521 2c0262af bellard
        if (shift) {
1522 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1523 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1524 2c0262af bellard
        } else {
1525 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1526 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1527 891b38e4 bellard
        }
1528 891b38e4 bellard
1529 891b38e4 bellard
        /* from this point, not restartable */
1530 891b38e4 bellard
1531 891b38e4 bellard
        if (new_stack) {
1532 891b38e4 bellard
            ss = (ss & ~3) | dpl;
1533 891b38e4 bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
1534 891b38e4 bellard
                                   ssp,
1535 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
1536 891b38e4 bellard
                                   ss_e2);
1537 2c0262af bellard
        }
1538 2c0262af bellard
1539 2c0262af bellard
        selector = (selector & ~3) | dpl;
1540 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
1541 2c0262af bellard
                       get_seg_base(e1, e2),
1542 2c0262af bellard
                       get_seg_limit(e1, e2),
1543 2c0262af bellard
                       e2);
1544 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
1545 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1546 2c0262af bellard
        EIP = offset;
1547 2c0262af bellard
    }
1548 2c0262af bellard
}
1549 2c0262af bellard
1550 7e84c249 bellard
/* real and vm86 mode iret */
1551 2c0262af bellard
void helper_iret_real(int shift)
1552 2c0262af bellard
{
1553 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1554 2c0262af bellard
    uint8_t *ssp;
1555 2c0262af bellard
    int eflags_mask;
1556 7e84c249 bellard
1557 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1558 891b38e4 bellard
    sp = ESP;
1559 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1560 2c0262af bellard
    if (shift == 1) {
1561 2c0262af bellard
        /* 32 bits */
1562 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1563 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1564 891b38e4 bellard
        new_cs &= 0xffff;
1565 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
1566 2c0262af bellard
    } else {
1567 2c0262af bellard
        /* 16 bits */
1568 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1569 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1570 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
1571 2c0262af bellard
    }
1572 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1573 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1574 2c0262af bellard
    env->eip = new_eip;
1575 7e84c249 bellard
    if (env->eflags & VM_MASK)
1576 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
1577 7e84c249 bellard
    else
1578 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
1579 2c0262af bellard
    if (shift == 0)
1580 2c0262af bellard
        eflags_mask &= 0xffff;
1581 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
1582 2c0262af bellard
}
1583 2c0262af bellard
1584 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
1585 8e682019 bellard
{
1586 8e682019 bellard
    int dpl;
1587 8e682019 bellard
    uint32_t e2;
1588 8e682019 bellard
    
1589 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
1590 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1591 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1592 8e682019 bellard
        /* data or non conforming code segment */
1593 8e682019 bellard
        if (dpl < cpl) {
1594 8e682019 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
1595 8e682019 bellard
        }
1596 8e682019 bellard
    }
1597 8e682019 bellard
}
1598 8e682019 bellard
1599 2c0262af bellard
/* protected mode iret */
1600 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
1601 2c0262af bellard
{
1602 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
1603 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
1604 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
1605 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
1606 2c0262af bellard
    uint8_t *ssp;
1607 2c0262af bellard
    
1608 891b38e4 bellard
    sp_mask = get_sp_mask(env->segs[R_SS].flags);
1609 2c0262af bellard
    sp = ESP;
1610 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1611 2c0262af bellard
    if (shift == 1) {
1612 2c0262af bellard
        /* 32 bits */
1613 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1614 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1615 891b38e4 bellard
        new_cs &= 0xffff;
1616 891b38e4 bellard
        if (is_iret) {
1617 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
1618 891b38e4 bellard
            if (new_eflags & VM_MASK)
1619 891b38e4 bellard
                goto return_to_vm86;
1620 891b38e4 bellard
        }
1621 2c0262af bellard
    } else {
1622 2c0262af bellard
        /* 16 bits */
1623 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1624 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1625 2c0262af bellard
        if (is_iret)
1626 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
1627 2c0262af bellard
    }
1628 891b38e4 bellard
#ifdef DEBUG_PCALL
1629 891b38e4 bellard
    if (loglevel) {
1630 4136f33c bellard
        fprintf(logfile, "lret new %04x:%08x addend=0x%x\n",
1631 4136f33c bellard
                new_cs, new_eip, addend);
1632 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1633 891b38e4 bellard
    }
1634 891b38e4 bellard
#endif
1635 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1636 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1637 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1638 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1639 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
1640 2c0262af bellard
        !(e2 & DESC_CS_MASK))
1641 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1642 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1643 2c0262af bellard
    rpl = new_cs & 3; 
1644 2c0262af bellard
    if (rpl < cpl)
1645 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1646 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1647 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
1648 2c0262af bellard
        if (dpl > rpl)
1649 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1650 2c0262af bellard
    } else {
1651 2c0262af bellard
        if (dpl != rpl)
1652 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1653 2c0262af bellard
    }
1654 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
1655 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1656 2c0262af bellard
    
1657 891b38e4 bellard
    sp += addend;
1658 2c0262af bellard
    if (rpl == cpl) {
1659 2c0262af bellard
        /* return to same priledge level */
1660 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1661 2c0262af bellard
                       get_seg_base(e1, e2),
1662 2c0262af bellard
                       get_seg_limit(e1, e2),
1663 2c0262af bellard
                       e2);
1664 2c0262af bellard
    } else {
1665 2c0262af bellard
        /* return to different priviledge level */
1666 2c0262af bellard
        if (shift == 1) {
1667 2c0262af bellard
            /* 32 bits */
1668 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
1669 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
1670 891b38e4 bellard
            new_ss &= 0xffff;
1671 2c0262af bellard
        } else {
1672 2c0262af bellard
            /* 16 bits */
1673 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
1674 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
1675 2c0262af bellard
        }
1676 2c0262af bellard
        
1677 2c0262af bellard
        if ((new_ss & 3) != rpl)
1678 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1679 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
1680 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1681 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
1682 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
1683 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
1684 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1685 2c0262af bellard
        dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1686 2c0262af bellard
        if (dpl != rpl)
1687 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1688 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
1689 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
1690 2c0262af bellard
1691 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1692 2c0262af bellard
                       get_seg_base(e1, e2),
1693 2c0262af bellard
                       get_seg_limit(e1, e2),
1694 2c0262af bellard
                       e2);
1695 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_SS, new_ss, 
1696 2c0262af bellard
                       get_seg_base(ss_e1, ss_e2),
1697 2c0262af bellard
                       get_seg_limit(ss_e1, ss_e2),
1698 2c0262af bellard
                       ss_e2);
1699 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
1700 891b38e4 bellard
        sp = new_esp;
1701 891b38e4 bellard
        /* XXX: change sp_mask according to old segment ? */
1702 8e682019 bellard
1703 8e682019 bellard
        /* validate data segments */
1704 8e682019 bellard
        validate_seg(R_ES, cpl);
1705 8e682019 bellard
        validate_seg(R_DS, cpl);
1706 8e682019 bellard
        validate_seg(R_FS, cpl);
1707 8e682019 bellard
        validate_seg(R_GS, cpl);
1708 2c0262af bellard
    }
1709 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1710 2c0262af bellard
    env->eip = new_eip;
1711 2c0262af bellard
    if (is_iret) {
1712 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
1713 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
1714 2c0262af bellard
        if (cpl == 0)
1715 4136f33c bellard
            eflags_mask |= IOPL_MASK;
1716 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
1717 4136f33c bellard
        if (cpl <= iopl)
1718 4136f33c bellard
            eflags_mask |= IF_MASK;
1719 2c0262af bellard
        if (shift == 0)
1720 2c0262af bellard
            eflags_mask &= 0xffff;
1721 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
1722 2c0262af bellard
    }
1723 2c0262af bellard
    return;
1724 2c0262af bellard
1725 2c0262af bellard
 return_to_vm86:
1726 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
1727 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
1728 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
1729 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
1730 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
1731 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
1732 2c0262af bellard
    
1733 2c0262af bellard
    /* modify processor state */
1734 4136f33c bellard
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
1735 8145122b bellard
                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
1736 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
1737 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
1738 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
1739 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
1740 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
1741 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
1742 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
1743 2c0262af bellard
1744 2c0262af bellard
    env->eip = new_eip;
1745 2c0262af bellard
    ESP = new_esp;
1746 2c0262af bellard
}
1747 2c0262af bellard
1748 2c0262af bellard
void helper_iret_protected(int shift)
1749 2c0262af bellard
{
1750 7e84c249 bellard
    int tss_selector, type;
1751 7e84c249 bellard
    uint32_t e1, e2;
1752 7e84c249 bellard
    
1753 7e84c249 bellard
    /* specific case for TSS */
1754 7e84c249 bellard
    if (env->eflags & NT_MASK) {
1755 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
1756 7e84c249 bellard
        if (tss_selector & 4)
1757 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1758 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
1759 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1760 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
1761 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
1762 7e84c249 bellard
        if (type != 3)
1763 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1764 7e84c249 bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET);
1765 7e84c249 bellard
    } else {
1766 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
1767 7e84c249 bellard
    }
1768 2c0262af bellard
}
1769 2c0262af bellard
1770 2c0262af bellard
void helper_lret_protected(int shift, int addend)
1771 2c0262af bellard
{
1772 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
1773 2c0262af bellard
}
1774 2c0262af bellard
1775 2c0262af bellard
void helper_movl_crN_T0(int reg)
1776 2c0262af bellard
{
1777 2c0262af bellard
    switch(reg) {
1778 2c0262af bellard
    case 0:
1779 1ac157da bellard
        cpu_x86_update_cr0(env, T0);
1780 2c0262af bellard
        break;
1781 2c0262af bellard
    case 3:
1782 1ac157da bellard
        cpu_x86_update_cr3(env, T0);
1783 1ac157da bellard
        break;
1784 1ac157da bellard
    case 4:
1785 1ac157da bellard
        cpu_x86_update_cr4(env, T0);
1786 1ac157da bellard
        break;
1787 1ac157da bellard
    default:
1788 1ac157da bellard
        env->cr[reg] = T0;
1789 2c0262af bellard
        break;
1790 2c0262af bellard
    }
1791 2c0262af bellard
}
1792 2c0262af bellard
1793 2c0262af bellard
/* XXX: do more */
1794 2c0262af bellard
void helper_movl_drN_T0(int reg)
1795 2c0262af bellard
{
1796 2c0262af bellard
    env->dr[reg] = T0;
1797 2c0262af bellard
}
1798 2c0262af bellard
1799 2c0262af bellard
void helper_invlpg(unsigned int addr)
1800 2c0262af bellard
{
1801 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
1802 2c0262af bellard
}
1803 2c0262af bellard
1804 2c0262af bellard
/* rdtsc */
1805 2c0262af bellard
#ifndef __i386__
1806 2c0262af bellard
uint64_t emu_time;
1807 2c0262af bellard
#endif
1808 2c0262af bellard
1809 2c0262af bellard
void helper_rdtsc(void)
1810 2c0262af bellard
{
1811 2c0262af bellard
    uint64_t val;
1812 2c0262af bellard
#ifdef __i386__
1813 2c0262af bellard
    asm("rdtsc" : "=A" (val));
1814 2c0262af bellard
#else
1815 2c0262af bellard
    /* better than nothing: the time increases */
1816 2c0262af bellard
    val = emu_time++;
1817 2c0262af bellard
#endif
1818 2c0262af bellard
    EAX = val;
1819 2c0262af bellard
    EDX = val >> 32;
1820 2c0262af bellard
}
1821 2c0262af bellard
1822 2c0262af bellard
void helper_wrmsr(void)
1823 2c0262af bellard
{
1824 2c0262af bellard
    switch(ECX) {
1825 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1826 2c0262af bellard
        env->sysenter_cs = EAX & 0xffff;
1827 2c0262af bellard
        break;
1828 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1829 2c0262af bellard
        env->sysenter_esp = EAX;
1830 2c0262af bellard
        break;
1831 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1832 2c0262af bellard
        env->sysenter_eip = EAX;
1833 2c0262af bellard
        break;
1834 2c0262af bellard
    default:
1835 2c0262af bellard
        /* XXX: exception ? */
1836 2c0262af bellard
        break; 
1837 2c0262af bellard
    }
1838 2c0262af bellard
}
1839 2c0262af bellard
1840 2c0262af bellard
void helper_rdmsr(void)
1841 2c0262af bellard
{
1842 2c0262af bellard
    switch(ECX) {
1843 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1844 2c0262af bellard
        EAX = env->sysenter_cs;
1845 2c0262af bellard
        EDX = 0;
1846 2c0262af bellard
        break;
1847 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1848 2c0262af bellard
        EAX = env->sysenter_esp;
1849 2c0262af bellard
        EDX = 0;
1850 2c0262af bellard
        break;
1851 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1852 2c0262af bellard
        EAX = env->sysenter_eip;
1853 2c0262af bellard
        EDX = 0;
1854 2c0262af bellard
        break;
1855 2c0262af bellard
    default:
1856 2c0262af bellard
        /* XXX: exception ? */
1857 2c0262af bellard
        break; 
1858 2c0262af bellard
    }
1859 2c0262af bellard
}
1860 2c0262af bellard
1861 2c0262af bellard
void helper_lsl(void)
1862 2c0262af bellard
{
1863 2c0262af bellard
    unsigned int selector, limit;
1864 2c0262af bellard
    uint32_t e1, e2;
1865 3ab493de bellard
    int rpl, dpl, cpl, type;
1866 2c0262af bellard
1867 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1868 2c0262af bellard
    selector = T0 & 0xffff;
1869 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1870 2c0262af bellard
        return;
1871 3ab493de bellard
    rpl = selector & 3;
1872 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1873 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1874 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1875 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1876 3ab493de bellard
            /* conforming */
1877 3ab493de bellard
        } else {
1878 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1879 3ab493de bellard
                return;
1880 3ab493de bellard
        }
1881 3ab493de bellard
    } else {
1882 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1883 3ab493de bellard
        switch(type) {
1884 3ab493de bellard
        case 1:
1885 3ab493de bellard
        case 2:
1886 3ab493de bellard
        case 3:
1887 3ab493de bellard
        case 9:
1888 3ab493de bellard
        case 11:
1889 3ab493de bellard
            break;
1890 3ab493de bellard
        default:
1891 3ab493de bellard
            return;
1892 3ab493de bellard
        }
1893 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1894 3ab493de bellard
            return;
1895 3ab493de bellard
    }
1896 3ab493de bellard
    limit = get_seg_limit(e1, e2);
1897 2c0262af bellard
    T1 = limit;
1898 2c0262af bellard
    CC_SRC |= CC_Z;
1899 2c0262af bellard
}
1900 2c0262af bellard
1901 2c0262af bellard
void helper_lar(void)
1902 2c0262af bellard
{
1903 2c0262af bellard
    unsigned int selector;
1904 2c0262af bellard
    uint32_t e1, e2;
1905 3ab493de bellard
    int rpl, dpl, cpl, type;
1906 2c0262af bellard
1907 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1908 2c0262af bellard
    selector = T0 & 0xffff;
1909 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1910 3ab493de bellard
        return;
1911 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1912 2c0262af bellard
        return;
1913 3ab493de bellard
    rpl = selector & 3;
1914 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1915 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1916 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1917 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1918 3ab493de bellard
            /* conforming */
1919 3ab493de bellard
        } else {
1920 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1921 3ab493de bellard
                return;
1922 3ab493de bellard
        }
1923 3ab493de bellard
    } else {
1924 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1925 3ab493de bellard
        switch(type) {
1926 3ab493de bellard
        case 1:
1927 3ab493de bellard
        case 2:
1928 3ab493de bellard
        case 3:
1929 3ab493de bellard
        case 4:
1930 3ab493de bellard
        case 5:
1931 3ab493de bellard
        case 9:
1932 3ab493de bellard
        case 11:
1933 3ab493de bellard
        case 12:
1934 3ab493de bellard
            break;
1935 3ab493de bellard
        default:
1936 3ab493de bellard
            return;
1937 3ab493de bellard
        }
1938 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1939 3ab493de bellard
            return;
1940 3ab493de bellard
    }
1941 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
1942 2c0262af bellard
    CC_SRC |= CC_Z;
1943 2c0262af bellard
}
1944 2c0262af bellard
1945 3ab493de bellard
void helper_verr(void)
1946 3ab493de bellard
{
1947 3ab493de bellard
    unsigned int selector;
1948 3ab493de bellard
    uint32_t e1, e2;
1949 3ab493de bellard
    int rpl, dpl, cpl;
1950 3ab493de bellard
1951 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1952 3ab493de bellard
    selector = T0 & 0xffff;
1953 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1954 3ab493de bellard
        return;
1955 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1956 3ab493de bellard
        return;
1957 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1958 3ab493de bellard
        return;
1959 3ab493de bellard
    rpl = selector & 3;
1960 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1961 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1962 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1963 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
1964 3ab493de bellard
            return;
1965 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
1966 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1967 3ab493de bellard
                return;
1968 3ab493de bellard
        }
1969 3ab493de bellard
    } else {
1970 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1971 3ab493de bellard
            return;
1972 3ab493de bellard
    }
1973 f3f2d9be bellard
    CC_SRC |= CC_Z;
1974 3ab493de bellard
}
1975 3ab493de bellard
1976 3ab493de bellard
void helper_verw(void)
1977 3ab493de bellard
{
1978 3ab493de bellard
    unsigned int selector;
1979 3ab493de bellard
    uint32_t e1, e2;
1980 3ab493de bellard
    int rpl, dpl, cpl;
1981 3ab493de bellard
1982 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1983 3ab493de bellard
    selector = T0 & 0xffff;
1984 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1985 3ab493de bellard
        return;
1986 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1987 3ab493de bellard
        return;
1988 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1989 3ab493de bellard
        return;
1990 3ab493de bellard
    rpl = selector & 3;
1991 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1992 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1993 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1994 3ab493de bellard
        return;
1995 3ab493de bellard
    } else {
1996 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1997 3ab493de bellard
            return;
1998 3ab493de bellard
        if (!(e2 & DESC_W_MASK))
1999 3ab493de bellard
            return;
2000 3ab493de bellard
    }
2001 f3f2d9be bellard
    CC_SRC |= CC_Z;
2002 3ab493de bellard
}
2003 3ab493de bellard
2004 2c0262af bellard
/* FPU helpers */
2005 2c0262af bellard
2006 2c0262af bellard
void helper_fldt_ST0_A0(void)
2007 2c0262af bellard
{
2008 2c0262af bellard
    int new_fpstt;
2009 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
2010 2c0262af bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
2011 2c0262af bellard
    env->fpstt = new_fpstt;
2012 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
2013 2c0262af bellard
}
2014 2c0262af bellard
2015 2c0262af bellard
void helper_fstt_ST0_A0(void)
2016 2c0262af bellard
{
2017 2c0262af bellard
    helper_fstt(ST0, (uint8_t *)A0);
2018 2c0262af bellard
}
2019 2c0262af bellard
2020 2c0262af bellard
/* BCD ops */
2021 2c0262af bellard
2022 2c0262af bellard
#define MUL10(iv) ( iv + iv + (iv << 3) )
2023 2c0262af bellard
2024 2c0262af bellard
void helper_fbld_ST0_A0(void)
2025 2c0262af bellard
{
2026 2c0262af bellard
    CPU86_LDouble tmp;
2027 2c0262af bellard
    uint64_t val;
2028 2c0262af bellard
    unsigned int v;
2029 2c0262af bellard
    int i;
2030 2c0262af bellard
2031 2c0262af bellard
    val = 0;
2032 2c0262af bellard
    for(i = 8; i >= 0; i--) {
2033 2c0262af bellard
        v = ldub((uint8_t *)A0 + i);
2034 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2035 2c0262af bellard
    }
2036 2c0262af bellard
    tmp = val;
2037 2c0262af bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
2038 2c0262af bellard
        tmp = -tmp;
2039 2c0262af bellard
    fpush();
2040 2c0262af bellard
    ST0 = tmp;
2041 2c0262af bellard
}
2042 2c0262af bellard
2043 2c0262af bellard
void helper_fbst_ST0_A0(void)
2044 2c0262af bellard
{
2045 2c0262af bellard
    CPU86_LDouble tmp;
2046 2c0262af bellard
    int v;
2047 2c0262af bellard
    uint8_t *mem_ref, *mem_end;
2048 2c0262af bellard
    int64_t val;
2049 2c0262af bellard
2050 2c0262af bellard
    tmp = rint(ST0);
2051 2c0262af bellard
    val = (int64_t)tmp;
2052 2c0262af bellard
    mem_ref = (uint8_t *)A0;
2053 2c0262af bellard
    mem_end = mem_ref + 9;
2054 2c0262af bellard
    if (val < 0) {
2055 2c0262af bellard
        stb(mem_end, 0x80);
2056 2c0262af bellard
        val = -val;
2057 2c0262af bellard
    } else {
2058 2c0262af bellard
        stb(mem_end, 0x00);
2059 2c0262af bellard
    }
2060 2c0262af bellard
    while (mem_ref < mem_end) {
2061 2c0262af bellard
        if (val == 0)
2062 2c0262af bellard
            break;
2063 2c0262af bellard
        v = val % 100;
2064 2c0262af bellard
        val = val / 100;
2065 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
2066 2c0262af bellard
        stb(mem_ref++, v);
2067 2c0262af bellard
    }
2068 2c0262af bellard
    while (mem_ref < mem_end) {
2069 2c0262af bellard
        stb(mem_ref++, 0);
2070 2c0262af bellard
    }
2071 2c0262af bellard
}
2072 2c0262af bellard
2073 2c0262af bellard
void helper_f2xm1(void)
2074 2c0262af bellard
{
2075 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
2076 2c0262af bellard
}
2077 2c0262af bellard
2078 2c0262af bellard
void helper_fyl2x(void)
2079 2c0262af bellard
{
2080 2c0262af bellard
    CPU86_LDouble fptemp;
2081 2c0262af bellard
    
2082 2c0262af bellard
    fptemp = ST0;
2083 2c0262af bellard
    if (fptemp>0.0){
2084 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
2085 2c0262af bellard
        ST1 *= fptemp;
2086 2c0262af bellard
        fpop();
2087 2c0262af bellard
    } else { 
2088 2c0262af bellard
        env->fpus &= (~0x4700);
2089 2c0262af bellard
        env->fpus |= 0x400;
2090 2c0262af bellard
    }
2091 2c0262af bellard
}
2092 2c0262af bellard
2093 2c0262af bellard
void helper_fptan(void)
2094 2c0262af bellard
{
2095 2c0262af bellard
    CPU86_LDouble fptemp;
2096 2c0262af bellard
2097 2c0262af bellard
    fptemp = ST0;
2098 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2099 2c0262af bellard
        env->fpus |= 0x400;
2100 2c0262af bellard
    } else {
2101 2c0262af bellard
        ST0 = tan(fptemp);
2102 2c0262af bellard
        fpush();
2103 2c0262af bellard
        ST0 = 1.0;
2104 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2105 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
2106 2c0262af bellard
    }
2107 2c0262af bellard
}
2108 2c0262af bellard
2109 2c0262af bellard
void helper_fpatan(void)
2110 2c0262af bellard
{
2111 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
2112 2c0262af bellard
2113 2c0262af bellard
    fpsrcop = ST1;
2114 2c0262af bellard
    fptemp = ST0;
2115 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
2116 2c0262af bellard
    fpop();
2117 2c0262af bellard
}
2118 2c0262af bellard
2119 2c0262af bellard
void helper_fxtract(void)
2120 2c0262af bellard
{
2121 2c0262af bellard
    CPU86_LDoubleU temp;
2122 2c0262af bellard
    unsigned int expdif;
2123 2c0262af bellard
2124 2c0262af bellard
    temp.d = ST0;
2125 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
2126 2c0262af bellard
    /*DP exponent bias*/
2127 2c0262af bellard
    ST0 = expdif;
2128 2c0262af bellard
    fpush();
2129 2c0262af bellard
    BIASEXPONENT(temp);
2130 2c0262af bellard
    ST0 = temp.d;
2131 2c0262af bellard
}
2132 2c0262af bellard
2133 2c0262af bellard
void helper_fprem1(void)
2134 2c0262af bellard
{
2135 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2136 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2137 2c0262af bellard
    int expdif;
2138 2c0262af bellard
    int q;
2139 2c0262af bellard
2140 2c0262af bellard
    fpsrcop = ST0;
2141 2c0262af bellard
    fptemp = ST1;
2142 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2143 2c0262af bellard
    fptemp1.d = fptemp;
2144 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2145 2c0262af bellard
    if (expdif < 53) {
2146 2c0262af bellard
        dblq = fpsrcop / fptemp;
2147 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2148 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2149 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2150 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2151 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2152 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2153 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2154 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2155 2c0262af bellard
    } else {
2156 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2157 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2158 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2159 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
2160 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2161 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
2162 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2163 2c0262af bellard
    }
2164 2c0262af bellard
}
2165 2c0262af bellard
2166 2c0262af bellard
void helper_fprem(void)
2167 2c0262af bellard
{
2168 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2169 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2170 2c0262af bellard
    int expdif;
2171 2c0262af bellard
    int q;
2172 2c0262af bellard
    
2173 2c0262af bellard
    fpsrcop = ST0;
2174 2c0262af bellard
    fptemp = ST1;
2175 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2176 2c0262af bellard
    fptemp1.d = fptemp;
2177 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2178 2c0262af bellard
    if ( expdif < 53 ) {
2179 2c0262af bellard
        dblq = fpsrcop / fptemp;
2180 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2181 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2182 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2183 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2184 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2185 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2186 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2187 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2188 2c0262af bellard
    } else {
2189 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2190 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2191 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2192 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
2193 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
2194 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
2195 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2196 2c0262af bellard
    }
2197 2c0262af bellard
}
2198 2c0262af bellard
2199 2c0262af bellard
void helper_fyl2xp1(void)
2200 2c0262af bellard
{
2201 2c0262af bellard
    CPU86_LDouble fptemp;
2202 2c0262af bellard
2203 2c0262af bellard
    fptemp = ST0;
2204 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
2205 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2206 2c0262af bellard
        ST1 *= fptemp;
2207 2c0262af bellard
        fpop();
2208 2c0262af bellard
    } else { 
2209 2c0262af bellard
        env->fpus &= (~0x4700);
2210 2c0262af bellard
        env->fpus |= 0x400;
2211 2c0262af bellard
    }
2212 2c0262af bellard
}
2213 2c0262af bellard
2214 2c0262af bellard
void helper_fsqrt(void)
2215 2c0262af bellard
{
2216 2c0262af bellard
    CPU86_LDouble fptemp;
2217 2c0262af bellard
2218 2c0262af bellard
    fptemp = ST0;
2219 2c0262af bellard
    if (fptemp<0.0) { 
2220 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2221 2c0262af bellard
        env->fpus |= 0x400;
2222 2c0262af bellard
    }
2223 2c0262af bellard
    ST0 = sqrt(fptemp);
2224 2c0262af bellard
}
2225 2c0262af bellard
2226 2c0262af bellard
void helper_fsincos(void)
2227 2c0262af bellard
{
2228 2c0262af bellard
    CPU86_LDouble fptemp;
2229 2c0262af bellard
2230 2c0262af bellard
    fptemp = ST0;
2231 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2232 2c0262af bellard
        env->fpus |= 0x400;
2233 2c0262af bellard
    } else {
2234 2c0262af bellard
        ST0 = sin(fptemp);
2235 2c0262af bellard
        fpush();
2236 2c0262af bellard
        ST0 = cos(fptemp);
2237 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2238 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
2239 2c0262af bellard
    }
2240 2c0262af bellard
}
2241 2c0262af bellard
2242 2c0262af bellard
void helper_frndint(void)
2243 2c0262af bellard
{
2244 2c0262af bellard
    CPU86_LDouble a;
2245 2c0262af bellard
2246 2c0262af bellard
    a = ST0;
2247 2c0262af bellard
#ifdef __arm__
2248 2c0262af bellard
    switch(env->fpuc & RC_MASK) {
2249 2c0262af bellard
    default:
2250 2c0262af bellard
    case RC_NEAR:
2251 2c0262af bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
2252 2c0262af bellard
        break;
2253 2c0262af bellard
    case RC_DOWN:
2254 2c0262af bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
2255 2c0262af bellard
        break;
2256 2c0262af bellard
    case RC_UP:
2257 2c0262af bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
2258 2c0262af bellard
        break;
2259 2c0262af bellard
    case RC_CHOP:
2260 2c0262af bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
2261 2c0262af bellard
        break;
2262 2c0262af bellard
    }
2263 2c0262af bellard
#else
2264 2c0262af bellard
    a = rint(a);
2265 2c0262af bellard
#endif
2266 2c0262af bellard
    ST0 = a;
2267 2c0262af bellard
}
2268 2c0262af bellard
2269 2c0262af bellard
void helper_fscale(void)
2270 2c0262af bellard
{
2271 2c0262af bellard
    CPU86_LDouble fpsrcop, fptemp;
2272 2c0262af bellard
2273 2c0262af bellard
    fpsrcop = 2.0;
2274 2c0262af bellard
    fptemp = pow(fpsrcop,ST1);
2275 2c0262af bellard
    ST0 *= fptemp;
2276 2c0262af bellard
}
2277 2c0262af bellard
2278 2c0262af bellard
void helper_fsin(void)
2279 2c0262af bellard
{
2280 2c0262af bellard
    CPU86_LDouble fptemp;
2281 2c0262af bellard
2282 2c0262af bellard
    fptemp = ST0;
2283 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2284 2c0262af bellard
        env->fpus |= 0x400;
2285 2c0262af bellard
    } else {
2286 2c0262af bellard
        ST0 = sin(fptemp);
2287 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2288 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
2289 2c0262af bellard
    }
2290 2c0262af bellard
}
2291 2c0262af bellard
2292 2c0262af bellard
void helper_fcos(void)
2293 2c0262af bellard
{
2294 2c0262af bellard
    CPU86_LDouble fptemp;
2295 2c0262af bellard
2296 2c0262af bellard
    fptemp = ST0;
2297 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2298 2c0262af bellard
        env->fpus |= 0x400;
2299 2c0262af bellard
    } else {
2300 2c0262af bellard
        ST0 = cos(fptemp);
2301 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2302 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
2303 2c0262af bellard
    }
2304 2c0262af bellard
}
2305 2c0262af bellard
2306 2c0262af bellard
void helper_fxam_ST0(void)
2307 2c0262af bellard
{
2308 2c0262af bellard
    CPU86_LDoubleU temp;
2309 2c0262af bellard
    int expdif;
2310 2c0262af bellard
2311 2c0262af bellard
    temp.d = ST0;
2312 2c0262af bellard
2313 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2314 2c0262af bellard
    if (SIGND(temp))
2315 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
2316 2c0262af bellard
2317 2c0262af bellard
    expdif = EXPD(temp);
2318 2c0262af bellard
    if (expdif == MAXEXPD) {
2319 2c0262af bellard
        if (MANTD(temp) == 0)
2320 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
2321 2c0262af bellard
        else
2322 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
2323 2c0262af bellard
    } else if (expdif == 0) {
2324 2c0262af bellard
        if (MANTD(temp) == 0)
2325 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
2326 2c0262af bellard
        else
2327 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
2328 2c0262af bellard
    } else {
2329 2c0262af bellard
        env->fpus |= 0x400;
2330 2c0262af bellard
    }
2331 2c0262af bellard
}
2332 2c0262af bellard
2333 2c0262af bellard
void helper_fstenv(uint8_t *ptr, int data32)
2334 2c0262af bellard
{
2335 2c0262af bellard
    int fpus, fptag, exp, i;
2336 2c0262af bellard
    uint64_t mant;
2337 2c0262af bellard
    CPU86_LDoubleU tmp;
2338 2c0262af bellard
2339 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2340 2c0262af bellard
    fptag = 0;
2341 2c0262af bellard
    for (i=7; i>=0; i--) {
2342 2c0262af bellard
        fptag <<= 2;
2343 2c0262af bellard
        if (env->fptags[i]) {
2344 2c0262af bellard
            fptag |= 3;
2345 2c0262af bellard
        } else {
2346 2c0262af bellard
            tmp.d = env->fpregs[i];
2347 2c0262af bellard
            exp = EXPD(tmp);
2348 2c0262af bellard
            mant = MANTD(tmp);
2349 2c0262af bellard
            if (exp == 0 && mant == 0) {
2350 2c0262af bellard
                /* zero */
2351 2c0262af bellard
                fptag |= 1;
2352 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
2353 2c0262af bellard
#ifdef USE_X86LDOUBLE
2354 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
2355 2c0262af bellard
#endif
2356 2c0262af bellard
                       ) {
2357 2c0262af bellard
                /* NaNs, infinity, denormal */
2358 2c0262af bellard
                fptag |= 2;
2359 2c0262af bellard
            }
2360 2c0262af bellard
        }
2361 2c0262af bellard
    }
2362 2c0262af bellard
    if (data32) {
2363 2c0262af bellard
        /* 32 bit */
2364 2c0262af bellard
        stl(ptr, env->fpuc);
2365 2c0262af bellard
        stl(ptr + 4, fpus);
2366 2c0262af bellard
        stl(ptr + 8, fptag);
2367 2c0262af bellard
        stl(ptr + 12, 0);
2368 2c0262af bellard
        stl(ptr + 16, 0);
2369 2c0262af bellard
        stl(ptr + 20, 0);
2370 2c0262af bellard
        stl(ptr + 24, 0);
2371 2c0262af bellard
    } else {
2372 2c0262af bellard
        /* 16 bit */
2373 2c0262af bellard
        stw(ptr, env->fpuc);
2374 2c0262af bellard
        stw(ptr + 2, fpus);
2375 2c0262af bellard
        stw(ptr + 4, fptag);
2376 2c0262af bellard
        stw(ptr + 6, 0);
2377 2c0262af bellard
        stw(ptr + 8, 0);
2378 2c0262af bellard
        stw(ptr + 10, 0);
2379 2c0262af bellard
        stw(ptr + 12, 0);
2380 2c0262af bellard
    }
2381 2c0262af bellard
}
2382 2c0262af bellard
2383 2c0262af bellard
void helper_fldenv(uint8_t *ptr, int data32)
2384 2c0262af bellard
{
2385 2c0262af bellard
    int i, fpus, fptag;
2386 2c0262af bellard
2387 2c0262af bellard
    if (data32) {
2388 2c0262af bellard
        env->fpuc = lduw(ptr);
2389 2c0262af bellard
        fpus = lduw(ptr + 4);
2390 2c0262af bellard
        fptag = lduw(ptr + 8);
2391 2c0262af bellard
    }
2392 2c0262af bellard
    else {
2393 2c0262af bellard
        env->fpuc = lduw(ptr);
2394 2c0262af bellard
        fpus = lduw(ptr + 2);
2395 2c0262af bellard
        fptag = lduw(ptr + 4);
2396 2c0262af bellard
    }
2397 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
2398 2c0262af bellard
    env->fpus = fpus & ~0x3800;
2399 2c0262af bellard
    for(i = 0;i < 7; i++) {
2400 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
2401 2c0262af bellard
        fptag >>= 2;
2402 2c0262af bellard
    }
2403 2c0262af bellard
}
2404 2c0262af bellard
2405 2c0262af bellard
void helper_fsave(uint8_t *ptr, int data32)
2406 2c0262af bellard
{
2407 2c0262af bellard
    CPU86_LDouble tmp;
2408 2c0262af bellard
    int i;
2409 2c0262af bellard
2410 2c0262af bellard
    helper_fstenv(ptr, data32);
2411 2c0262af bellard
2412 2c0262af bellard
    ptr += (14 << data32);
2413 2c0262af bellard
    for(i = 0;i < 8; i++) {
2414 2c0262af bellard
        tmp = ST(i);
2415 2c0262af bellard
        helper_fstt(tmp, ptr);
2416 2c0262af bellard
        ptr += 10;
2417 2c0262af bellard
    }
2418 2c0262af bellard
2419 2c0262af bellard
    /* fninit */
2420 2c0262af bellard
    env->fpus = 0;
2421 2c0262af bellard
    env->fpstt = 0;
2422 2c0262af bellard
    env->fpuc = 0x37f;
2423 2c0262af bellard
    env->fptags[0] = 1;
2424 2c0262af bellard
    env->fptags[1] = 1;
2425 2c0262af bellard
    env->fptags[2] = 1;
2426 2c0262af bellard
    env->fptags[3] = 1;
2427 2c0262af bellard
    env->fptags[4] = 1;
2428 2c0262af bellard
    env->fptags[5] = 1;
2429 2c0262af bellard
    env->fptags[6] = 1;
2430 2c0262af bellard
    env->fptags[7] = 1;
2431 2c0262af bellard
}
2432 2c0262af bellard
2433 2c0262af bellard
void helper_frstor(uint8_t *ptr, int data32)
2434 2c0262af bellard
{
2435 2c0262af bellard
    CPU86_LDouble tmp;
2436 2c0262af bellard
    int i;
2437 2c0262af bellard
2438 2c0262af bellard
    helper_fldenv(ptr, data32);
2439 2c0262af bellard
    ptr += (14 << data32);
2440 2c0262af bellard
2441 2c0262af bellard
    for(i = 0;i < 8; i++) {
2442 2c0262af bellard
        tmp = helper_fldt(ptr);
2443 2c0262af bellard
        ST(i) = tmp;
2444 2c0262af bellard
        ptr += 10;
2445 2c0262af bellard
    }
2446 2c0262af bellard
}
2447 2c0262af bellard
2448 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
2449 61382a50 bellard
2450 61382a50 bellard
#define MMUSUFFIX _mmu
2451 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
2452 61382a50 bellard
2453 2c0262af bellard
#define SHIFT 0
2454 2c0262af bellard
#include "softmmu_template.h"
2455 2c0262af bellard
2456 2c0262af bellard
#define SHIFT 1
2457 2c0262af bellard
#include "softmmu_template.h"
2458 2c0262af bellard
2459 2c0262af bellard
#define SHIFT 2
2460 2c0262af bellard
#include "softmmu_template.h"
2461 2c0262af bellard
2462 2c0262af bellard
#define SHIFT 3
2463 2c0262af bellard
#include "softmmu_template.h"
2464 2c0262af bellard
2465 61382a50 bellard
#endif
2466 61382a50 bellard
2467 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
2468 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
2469 61382a50 bellard
   from generated code or from helper.c) */
2470 61382a50 bellard
/* XXX: fix it to restore all registers */
2471 61382a50 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2472 2c0262af bellard
{
2473 2c0262af bellard
    TranslationBlock *tb;
2474 2c0262af bellard
    int ret;
2475 2c0262af bellard
    unsigned long pc;
2476 61382a50 bellard
    CPUX86State *saved_env;
2477 61382a50 bellard
2478 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
2479 61382a50 bellard
       generated code */
2480 61382a50 bellard
    saved_env = env;
2481 61382a50 bellard
    env = cpu_single_env;
2482 61382a50 bellard
2483 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
2484 2c0262af bellard
    if (ret) {
2485 61382a50 bellard
        if (retaddr) {
2486 61382a50 bellard
            /* now we have a real cpu fault */
2487 61382a50 bellard
            pc = (unsigned long)retaddr;
2488 61382a50 bellard
            tb = tb_find_pc(pc);
2489 61382a50 bellard
            if (tb) {
2490 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
2491 61382a50 bellard
                   a virtual CPU fault */
2492 61382a50 bellard
                cpu_restore_state(tb, env, pc);
2493 61382a50 bellard
            }
2494 2c0262af bellard
        }
2495 2c0262af bellard
        raise_exception_err(EXCP0E_PAGE, env->error_code);
2496 2c0262af bellard
    }
2497 61382a50 bellard
    env = saved_env;
2498 2c0262af bellard
}