Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 8e682019

History | View | Annotate | Download (68.9 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 2c0262af bellard
const uint8_t parity_table[256] = {
25 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
26 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
27 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
28 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
29 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
30 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
31 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
32 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
33 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
34 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
35 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
36 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
40 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42 2c0262af bellard
    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
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
56 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57 2c0262af bellard
};
58 2c0262af bellard
59 2c0262af bellard
/* modulo 17 table */
60 2c0262af bellard
const uint8_t rclw_table[32] = {
61 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
62 2c0262af bellard
    8, 9,10,11,12,13,14,15,
63 2c0262af bellard
   16, 0, 1, 2, 3, 4, 5, 6,
64 2c0262af bellard
    7, 8, 9,10,11,12,13,14,
65 2c0262af bellard
};
66 2c0262af bellard
67 2c0262af bellard
/* modulo 9 table */
68 2c0262af bellard
const uint8_t rclb_table[32] = {
69 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
70 2c0262af bellard
    8, 0, 1, 2, 3, 4, 5, 6,
71 2c0262af bellard
    7, 8, 0, 1, 2, 3, 4, 5, 
72 2c0262af bellard
    6, 7, 8, 0, 1, 2, 3, 4,
73 2c0262af bellard
};
74 2c0262af bellard
75 2c0262af bellard
const CPU86_LDouble f15rk[7] =
76 2c0262af bellard
{
77 2c0262af bellard
    0.00000000000000000000L,
78 2c0262af bellard
    1.00000000000000000000L,
79 2c0262af bellard
    3.14159265358979323851L,  /*pi*/
80 2c0262af bellard
    0.30102999566398119523L,  /*lg2*/
81 2c0262af bellard
    0.69314718055994530943L,  /*ln2*/
82 2c0262af bellard
    1.44269504088896340739L,  /*l2e*/
83 2c0262af bellard
    3.32192809488736234781L,  /*l2t*/
84 2c0262af bellard
};
85 2c0262af bellard
    
86 2c0262af bellard
/* thread support */
87 2c0262af bellard
88 2c0262af bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
89 2c0262af bellard
90 2c0262af bellard
void cpu_lock(void)
91 2c0262af bellard
{
92 2c0262af bellard
    spin_lock(&global_cpu_lock);
93 2c0262af bellard
}
94 2c0262af bellard
95 2c0262af bellard
void cpu_unlock(void)
96 2c0262af bellard
{
97 2c0262af bellard
    spin_unlock(&global_cpu_lock);
98 2c0262af bellard
}
99 2c0262af bellard
100 2c0262af bellard
void cpu_loop_exit(void)
101 2c0262af bellard
{
102 2c0262af bellard
    /* NOTE: the register at this point must be saved by hand because
103 2c0262af bellard
       longjmp restore them */
104 2c0262af bellard
#ifdef reg_EAX
105 2c0262af bellard
    env->regs[R_EAX] = EAX;
106 2c0262af bellard
#endif
107 2c0262af bellard
#ifdef reg_ECX
108 2c0262af bellard
    env->regs[R_ECX] = ECX;
109 2c0262af bellard
#endif
110 2c0262af bellard
#ifdef reg_EDX
111 2c0262af bellard
    env->regs[R_EDX] = EDX;
112 2c0262af bellard
#endif
113 2c0262af bellard
#ifdef reg_EBX
114 2c0262af bellard
    env->regs[R_EBX] = EBX;
115 2c0262af bellard
#endif
116 2c0262af bellard
#ifdef reg_ESP
117 2c0262af bellard
    env->regs[R_ESP] = ESP;
118 2c0262af bellard
#endif
119 2c0262af bellard
#ifdef reg_EBP
120 2c0262af bellard
    env->regs[R_EBP] = EBP;
121 2c0262af bellard
#endif
122 2c0262af bellard
#ifdef reg_ESI
123 2c0262af bellard
    env->regs[R_ESI] = ESI;
124 2c0262af bellard
#endif
125 2c0262af bellard
#ifdef reg_EDI
126 2c0262af bellard
    env->regs[R_EDI] = EDI;
127 2c0262af bellard
#endif
128 2c0262af bellard
    longjmp(env->jmp_env, 1);
129 2c0262af bellard
}
130 2c0262af bellard
131 7e84c249 bellard
/* return non zero if error */
132 7e84c249 bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
133 7e84c249 bellard
                               int selector)
134 7e84c249 bellard
{
135 7e84c249 bellard
    SegmentCache *dt;
136 7e84c249 bellard
    int index;
137 7e84c249 bellard
    uint8_t *ptr;
138 7e84c249 bellard
139 7e84c249 bellard
    if (selector & 0x4)
140 7e84c249 bellard
        dt = &env->ldt;
141 7e84c249 bellard
    else
142 7e84c249 bellard
        dt = &env->gdt;
143 7e84c249 bellard
    index = selector & ~7;
144 7e84c249 bellard
    if ((index + 7) > dt->limit)
145 7e84c249 bellard
        return -1;
146 7e84c249 bellard
    ptr = dt->base + index;
147 7e84c249 bellard
    *e1_ptr = ldl_kernel(ptr);
148 7e84c249 bellard
    *e2_ptr = ldl_kernel(ptr + 4);
149 7e84c249 bellard
    return 0;
150 7e84c249 bellard
}
151 7e84c249 bellard
                                     
152 7e84c249 bellard
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
153 7e84c249 bellard
{
154 7e84c249 bellard
    unsigned int limit;
155 7e84c249 bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
156 7e84c249 bellard
    if (e2 & DESC_G_MASK)
157 7e84c249 bellard
        limit = (limit << 12) | 0xfff;
158 7e84c249 bellard
    return limit;
159 7e84c249 bellard
}
160 7e84c249 bellard
161 7e84c249 bellard
static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
162 7e84c249 bellard
{
163 7e84c249 bellard
    return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
164 7e84c249 bellard
}
165 7e84c249 bellard
166 7e84c249 bellard
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
167 7e84c249 bellard
{
168 7e84c249 bellard
    sc->base = get_seg_base(e1, e2);
169 7e84c249 bellard
    sc->limit = get_seg_limit(e1, e2);
170 7e84c249 bellard
    sc->flags = e2;
171 7e84c249 bellard
}
172 7e84c249 bellard
173 7e84c249 bellard
/* init the segment cache in vm86 mode. */
174 7e84c249 bellard
static inline void load_seg_vm(int seg, int selector)
175 7e84c249 bellard
{
176 7e84c249 bellard
    selector &= 0xffff;
177 7e84c249 bellard
    cpu_x86_load_seg_cache(env, seg, selector, 
178 7e84c249 bellard
                           (uint8_t *)(selector << 4), 0xffff, 0);
179 7e84c249 bellard
}
180 7e84c249 bellard
181 2c0262af bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
182 2c0262af bellard
                                       uint32_t *esp_ptr, int dpl)
183 2c0262af bellard
{
184 2c0262af bellard
    int type, index, shift;
185 2c0262af bellard
    
186 2c0262af bellard
#if 0
187 2c0262af bellard
    {
188 2c0262af bellard
        int i;
189 2c0262af bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
190 2c0262af bellard
        for(i=0;i<env->tr.limit;i++) {
191 2c0262af bellard
            printf("%02x ", env->tr.base[i]);
192 2c0262af bellard
            if ((i & 7) == 7) printf("\n");
193 2c0262af bellard
        }
194 2c0262af bellard
        printf("\n");
195 2c0262af bellard
    }
196 2c0262af bellard
#endif
197 2c0262af bellard
198 2c0262af bellard
    if (!(env->tr.flags & DESC_P_MASK))
199 2c0262af bellard
        cpu_abort(env, "invalid tss");
200 2c0262af bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
201 2c0262af bellard
    if ((type & 7) != 1)
202 2c0262af bellard
        cpu_abort(env, "invalid tss type");
203 2c0262af bellard
    shift = type >> 3;
204 2c0262af bellard
    index = (dpl * 4 + 2) << shift;
205 2c0262af bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
206 2c0262af bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
207 2c0262af bellard
    if (shift == 0) {
208 61382a50 bellard
        *esp_ptr = lduw_kernel(env->tr.base + index);
209 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
210 2c0262af bellard
    } else {
211 61382a50 bellard
        *esp_ptr = ldl_kernel(env->tr.base + index);
212 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
213 2c0262af bellard
    }
214 2c0262af bellard
}
215 2c0262af bellard
216 7e84c249 bellard
/* XXX: merge with load_seg() */
217 7e84c249 bellard
static void tss_load_seg(int seg_reg, int selector)
218 7e84c249 bellard
{
219 7e84c249 bellard
    uint32_t e1, e2;
220 7e84c249 bellard
    int rpl, dpl, cpl;
221 7e84c249 bellard
222 7e84c249 bellard
    if ((selector & 0xfffc) != 0) {
223 7e84c249 bellard
        if (load_segment(&e1, &e2, selector) != 0)
224 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
225 7e84c249 bellard
        if (!(e2 & DESC_S_MASK))
226 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
227 7e84c249 bellard
        rpl = selector & 3;
228 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
229 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
230 7e84c249 bellard
        if (seg_reg == R_CS) {
231 7e84c249 bellard
            if (!(e2 & DESC_CS_MASK))
232 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
233 7e84c249 bellard
            if (dpl != rpl)
234 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
235 7e84c249 bellard
            if ((e2 & DESC_C_MASK) && dpl > rpl)
236 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
237 7e84c249 bellard
                
238 7e84c249 bellard
        } else if (seg_reg == R_SS) {
239 7e84c249 bellard
            /* SS must be writable data */
240 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
241 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
242 7e84c249 bellard
            if (dpl != cpl || dpl != rpl)
243 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
244 7e84c249 bellard
        } else {
245 7e84c249 bellard
            /* not readable code */
246 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
247 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
248 7e84c249 bellard
            /* if data or non conforming code, checks the rights */
249 7e84c249 bellard
            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
250 7e84c249 bellard
                if (dpl < cpl || dpl < rpl)
251 7e84c249 bellard
                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
252 7e84c249 bellard
            }
253 7e84c249 bellard
        }
254 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
255 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
256 7e84c249 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
257 7e84c249 bellard
                       get_seg_base(e1, e2),
258 7e84c249 bellard
                       get_seg_limit(e1, e2),
259 7e84c249 bellard
                       e2);
260 7e84c249 bellard
    } else {
261 7e84c249 bellard
        if (seg_reg == R_SS || seg_reg == R_CS) 
262 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
263 7e84c249 bellard
    }
264 7e84c249 bellard
}
265 7e84c249 bellard
266 7e84c249 bellard
#define SWITCH_TSS_JMP  0
267 7e84c249 bellard
#define SWITCH_TSS_IRET 1
268 7e84c249 bellard
#define SWITCH_TSS_CALL 2
269 7e84c249 bellard
270 7e84c249 bellard
/* XXX: restore CPU state in registers (PowerPC case) */
271 7e84c249 bellard
static void switch_tss(int tss_selector, 
272 7e84c249 bellard
                       uint32_t e1, uint32_t e2, int source)
273 2c0262af bellard
{
274 7e84c249 bellard
    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
275 7e84c249 bellard
    uint8_t *tss_base;
276 7e84c249 bellard
    uint32_t new_regs[8], new_segs[6];
277 7e84c249 bellard
    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
278 7e84c249 bellard
    uint32_t old_eflags, eflags_mask;
279 2c0262af bellard
    SegmentCache *dt;
280 2c0262af bellard
    int index;
281 2c0262af bellard
    uint8_t *ptr;
282 2c0262af bellard
283 7e84c249 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
284 7e84c249 bellard
285 7e84c249 bellard
    /* if task gate, we read the TSS segment and we load it */
286 7e84c249 bellard
    if (type == 5) {
287 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
288 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
289 7e84c249 bellard
        tss_selector = e1 >> 16;
290 7e84c249 bellard
        if (tss_selector & 4)
291 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
292 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
293 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
294 7e84c249 bellard
        if (e2 & DESC_S_MASK)
295 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
296 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
297 7e84c249 bellard
        if ((type & 7) != 1)
298 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
299 7e84c249 bellard
    }
300 7e84c249 bellard
301 7e84c249 bellard
    if (!(e2 & DESC_P_MASK))
302 7e84c249 bellard
        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
303 7e84c249 bellard
304 7e84c249 bellard
    if (type & 8)
305 7e84c249 bellard
        tss_limit_max = 103;
306 2c0262af bellard
    else
307 7e84c249 bellard
        tss_limit_max = 43;
308 7e84c249 bellard
    tss_limit = get_seg_limit(e1, e2);
309 7e84c249 bellard
    tss_base = get_seg_base(e1, e2);
310 7e84c249 bellard
    if ((tss_selector & 4) != 0 || 
311 7e84c249 bellard
        tss_limit < tss_limit_max)
312 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
313 7e84c249 bellard
    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
314 7e84c249 bellard
    if (old_type & 8)
315 7e84c249 bellard
        old_tss_limit_max = 103;
316 7e84c249 bellard
    else
317 7e84c249 bellard
        old_tss_limit_max = 43;
318 7e84c249 bellard
319 7e84c249 bellard
    /* read all the registers from the new TSS */
320 7e84c249 bellard
    if (type & 8) {
321 7e84c249 bellard
        /* 32 bit */
322 7e84c249 bellard
        new_cr3 = ldl_kernel(tss_base + 0x1c);
323 7e84c249 bellard
        new_eip = ldl_kernel(tss_base + 0x20);
324 7e84c249 bellard
        new_eflags = ldl_kernel(tss_base + 0x24);
325 7e84c249 bellard
        for(i = 0; i < 8; i++)
326 7e84c249 bellard
            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
327 7e84c249 bellard
        for(i = 0; i < 6; i++)
328 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
329 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x60);
330 7e84c249 bellard
        new_trap = ldl_kernel(tss_base + 0x64);
331 7e84c249 bellard
    } else {
332 7e84c249 bellard
        /* 16 bit */
333 7e84c249 bellard
        new_cr3 = 0;
334 7e84c249 bellard
        new_eip = lduw_kernel(tss_base + 0x0e);
335 7e84c249 bellard
        new_eflags = lduw_kernel(tss_base + 0x10);
336 7e84c249 bellard
        for(i = 0; i < 8; i++)
337 7e84c249 bellard
            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
338 7e84c249 bellard
        for(i = 0; i < 4; i++)
339 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
340 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x2a);
341 7e84c249 bellard
        new_segs[R_FS] = 0;
342 7e84c249 bellard
        new_segs[R_GS] = 0;
343 7e84c249 bellard
        new_trap = 0;
344 7e84c249 bellard
    }
345 7e84c249 bellard
    
346 7e84c249 bellard
    /* NOTE: we must avoid memory exceptions during the task switch,
347 7e84c249 bellard
       so we make dummy accesses before */
348 7e84c249 bellard
    /* XXX: it can still fail in some cases, so a bigger hack is
349 7e84c249 bellard
       necessary to valid the TLB after having done the accesses */
350 7e84c249 bellard
351 7e84c249 bellard
    v1 = ldub_kernel(env->tr.base);
352 7e84c249 bellard
    v2 = ldub(env->tr.base + old_tss_limit_max);
353 7e84c249 bellard
    stb_kernel(env->tr.base, v1);
354 7e84c249 bellard
    stb_kernel(env->tr.base + old_tss_limit_max, v2);
355 7e84c249 bellard
    
356 7e84c249 bellard
    /* clear busy bit (it is restartable) */
357 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
358 7e84c249 bellard
        uint8_t *ptr;
359 7e84c249 bellard
        uint32_t e2;
360 7e84c249 bellard
        ptr = env->gdt.base + (env->tr.selector << 3);
361 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
362 7e84c249 bellard
        e2 &= ~DESC_TSS_BUSY_MASK;
363 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
364 7e84c249 bellard
    }
365 7e84c249 bellard
    old_eflags = compute_eflags();
366 7e84c249 bellard
    if (source == SWITCH_TSS_IRET)
367 7e84c249 bellard
        old_eflags &= ~NT_MASK;
368 7e84c249 bellard
    
369 7e84c249 bellard
    /* save the current state in the old TSS */
370 7e84c249 bellard
    if (type & 8) {
371 7e84c249 bellard
        /* 32 bit */
372 7e84c249 bellard
        stl_kernel(env->tr.base + 0x20, env->eip);
373 7e84c249 bellard
        stl_kernel(env->tr.base + 0x24, old_eflags);
374 7e84c249 bellard
        for(i = 0; i < 8; i++)
375 7e84c249 bellard
            stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]);
376 7e84c249 bellard
        for(i = 0; i < 6; i++)
377 7e84c249 bellard
            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
378 7e84c249 bellard
    } else {
379 7e84c249 bellard
        /* 16 bit */
380 7e84c249 bellard
        stw_kernel(env->tr.base + 0x0e, new_eip);
381 7e84c249 bellard
        stw_kernel(env->tr.base + 0x10, old_eflags);
382 7e84c249 bellard
        for(i = 0; i < 8; i++)
383 7e84c249 bellard
            stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]);
384 7e84c249 bellard
        for(i = 0; i < 4; i++)
385 7e84c249 bellard
            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
386 7e84c249 bellard
    }
387 7e84c249 bellard
    
388 7e84c249 bellard
    /* now if an exception occurs, it will occurs in the next task
389 7e84c249 bellard
       context */
390 7e84c249 bellard
391 7e84c249 bellard
    if (source == SWITCH_TSS_CALL) {
392 7e84c249 bellard
        stw_kernel(tss_base, env->tr.selector);
393 7e84c249 bellard
        new_eflags |= NT_MASK;
394 7e84c249 bellard
    }
395 7e84c249 bellard
396 7e84c249 bellard
    /* set busy bit */
397 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
398 7e84c249 bellard
        uint8_t *ptr;
399 7e84c249 bellard
        uint32_t e2;
400 7e84c249 bellard
        ptr = env->gdt.base + (tss_selector << 3);
401 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
402 7e84c249 bellard
        e2 |= DESC_TSS_BUSY_MASK;
403 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
404 7e84c249 bellard
    }
405 7e84c249 bellard
406 7e84c249 bellard
    /* set the new CPU state */
407 7e84c249 bellard
    /* from this point, any exception which occurs can give problems */
408 7e84c249 bellard
    env->cr[0] |= CR0_TS_MASK;
409 7e84c249 bellard
    env->tr.selector = tss_selector;
410 7e84c249 bellard
    env->tr.base = tss_base;
411 7e84c249 bellard
    env->tr.limit = tss_limit;
412 7e84c249 bellard
    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
413 7e84c249 bellard
    
414 7e84c249 bellard
    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
415 7e84c249 bellard
        env->cr[3] = new_cr3;
416 7e84c249 bellard
        cpu_x86_update_cr3(env);
417 7e84c249 bellard
    }
418 7e84c249 bellard
    
419 7e84c249 bellard
    /* load all registers without an exception, then reload them with
420 7e84c249 bellard
       possible exception */
421 7e84c249 bellard
    env->eip = new_eip;
422 4136f33c bellard
    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
423 4136f33c bellard
        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK;
424 7e84c249 bellard
    if (!(type & 8))
425 7e84c249 bellard
        eflags_mask &= 0xffff;
426 7e84c249 bellard
    load_eflags(new_eflags, eflags_mask);
427 7e84c249 bellard
    for(i = 0; i < 8; i++)
428 7e84c249 bellard
        env->regs[i] = new_regs[i];
429 7e84c249 bellard
    if (new_eflags & VM_MASK) {
430 7e84c249 bellard
        for(i = 0; i < 6; i++) 
431 7e84c249 bellard
            load_seg_vm(i, new_segs[i]);
432 7e84c249 bellard
        /* in vm86, CPL is always 3 */
433 7e84c249 bellard
        cpu_x86_set_cpl(env, 3);
434 7e84c249 bellard
    } else {
435 7e84c249 bellard
        /* CPL is set the RPL of CS */
436 7e84c249 bellard
        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
437 7e84c249 bellard
        /* first just selectors as the rest may trigger exceptions */
438 7e84c249 bellard
        for(i = 0; i < 6; i++)
439 7e84c249 bellard
            cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0);
440 7e84c249 bellard
    }
441 7e84c249 bellard
    
442 7e84c249 bellard
    env->ldt.selector = new_ldt & ~4;
443 7e84c249 bellard
    env->ldt.base = NULL;
444 7e84c249 bellard
    env->ldt.limit = 0;
445 7e84c249 bellard
    env->ldt.flags = 0;
446 7e84c249 bellard
447 7e84c249 bellard
    /* load the LDT */
448 7e84c249 bellard
    if (new_ldt & 4)
449 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
450 7e84c249 bellard
451 7e84c249 bellard
    dt = &env->gdt;
452 7e84c249 bellard
    index = new_ldt & ~7;
453 2c0262af bellard
    if ((index + 7) > dt->limit)
454 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
455 2c0262af bellard
    ptr = dt->base + index;
456 7e84c249 bellard
    e1 = ldl_kernel(ptr);
457 7e84c249 bellard
    e2 = ldl_kernel(ptr + 4);
458 7e84c249 bellard
    if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
459 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
460 7e84c249 bellard
    if (!(e2 & DESC_P_MASK))
461 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
462 7e84c249 bellard
    load_seg_cache_raw_dt(&env->ldt, e1, e2);
463 7e84c249 bellard
    
464 7e84c249 bellard
    /* load the segments */
465 7e84c249 bellard
    if (!(new_eflags & VM_MASK)) {
466 7e84c249 bellard
        tss_load_seg(R_CS, new_segs[R_CS]);
467 7e84c249 bellard
        tss_load_seg(R_SS, new_segs[R_SS]);
468 7e84c249 bellard
        tss_load_seg(R_ES, new_segs[R_ES]);
469 7e84c249 bellard
        tss_load_seg(R_DS, new_segs[R_DS]);
470 7e84c249 bellard
        tss_load_seg(R_FS, new_segs[R_FS]);
471 7e84c249 bellard
        tss_load_seg(R_GS, new_segs[R_GS]);
472 7e84c249 bellard
    }
473 7e84c249 bellard
    
474 7e84c249 bellard
    /* check that EIP is in the CS segment limits */
475 7e84c249 bellard
    if (new_eip > env->segs[R_CS].limit) {
476 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
477 7e84c249 bellard
    }
478 2c0262af bellard
}
479 7e84c249 bellard
480 7e84c249 bellard
/* check if Port I/O is allowed in TSS */
481 7e84c249 bellard
static inline void check_io(int addr, int size)
482 2c0262af bellard
{
483 7e84c249 bellard
    int io_offset, val, mask;
484 7e84c249 bellard
    
485 7e84c249 bellard
    /* TSS must be a valid 32 bit one */
486 7e84c249 bellard
    if (!(env->tr.flags & DESC_P_MASK) ||
487 7e84c249 bellard
        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
488 7e84c249 bellard
        env->tr.limit < 103)
489 7e84c249 bellard
        goto fail;
490 7e84c249 bellard
    io_offset = lduw_kernel(env->tr.base + 0x66);
491 7e84c249 bellard
    io_offset += (addr >> 3);
492 7e84c249 bellard
    /* Note: the check needs two bytes */
493 7e84c249 bellard
    if ((io_offset + 1) > env->tr.limit)
494 7e84c249 bellard
        goto fail;
495 7e84c249 bellard
    val = lduw_kernel(env->tr.base + io_offset);
496 7e84c249 bellard
    val >>= (addr & 7);
497 7e84c249 bellard
    mask = (1 << size) - 1;
498 7e84c249 bellard
    /* all bits must be zero to allow the I/O */
499 7e84c249 bellard
    if ((val & mask) != 0) {
500 7e84c249 bellard
    fail:
501 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
502 7e84c249 bellard
    }
503 2c0262af bellard
}
504 2c0262af bellard
505 7e84c249 bellard
void check_iob_T0(void)
506 2c0262af bellard
{
507 7e84c249 bellard
    check_io(T0, 1);
508 2c0262af bellard
}
509 2c0262af bellard
510 7e84c249 bellard
void check_iow_T0(void)
511 2c0262af bellard
{
512 7e84c249 bellard
    check_io(T0, 2);
513 2c0262af bellard
}
514 2c0262af bellard
515 7e84c249 bellard
void check_iol_T0(void)
516 2c0262af bellard
{
517 7e84c249 bellard
    check_io(T0, 4);
518 7e84c249 bellard
}
519 7e84c249 bellard
520 7e84c249 bellard
void check_iob_DX(void)
521 7e84c249 bellard
{
522 7e84c249 bellard
    check_io(EDX & 0xffff, 1);
523 7e84c249 bellard
}
524 7e84c249 bellard
525 7e84c249 bellard
void check_iow_DX(void)
526 7e84c249 bellard
{
527 7e84c249 bellard
    check_io(EDX & 0xffff, 2);
528 7e84c249 bellard
}
529 7e84c249 bellard
530 7e84c249 bellard
void check_iol_DX(void)
531 7e84c249 bellard
{
532 7e84c249 bellard
    check_io(EDX & 0xffff, 4);
533 2c0262af bellard
}
534 2c0262af bellard
535 891b38e4 bellard
static inline unsigned int get_sp_mask(unsigned int e2)
536 891b38e4 bellard
{
537 891b38e4 bellard
    if (e2 & DESC_B_MASK)
538 891b38e4 bellard
        return 0xffffffff;
539 891b38e4 bellard
    else
540 891b38e4 bellard
        return 0xffff;
541 891b38e4 bellard
}
542 891b38e4 bellard
543 891b38e4 bellard
/* XXX: add a is_user flag to have proper security support */
544 891b38e4 bellard
#define PUSHW(ssp, sp, sp_mask, val)\
545 891b38e4 bellard
{\
546 891b38e4 bellard
    sp -= 2;\
547 891b38e4 bellard
    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
548 891b38e4 bellard
}
549 891b38e4 bellard
550 891b38e4 bellard
#define PUSHL(ssp, sp, sp_mask, val)\
551 891b38e4 bellard
{\
552 891b38e4 bellard
    sp -= 4;\
553 891b38e4 bellard
    stl_kernel((ssp) + (sp & (sp_mask)), (val));\
554 891b38e4 bellard
}
555 891b38e4 bellard
556 891b38e4 bellard
#define POPW(ssp, sp, sp_mask, val)\
557 891b38e4 bellard
{\
558 891b38e4 bellard
    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
559 891b38e4 bellard
    sp += 2;\
560 891b38e4 bellard
}
561 891b38e4 bellard
562 891b38e4 bellard
#define POPL(ssp, sp, sp_mask, val)\
563 891b38e4 bellard
{\
564 891b38e4 bellard
    val = ldl_kernel((ssp) + (sp & (sp_mask)));\
565 891b38e4 bellard
    sp += 4;\
566 891b38e4 bellard
}
567 891b38e4 bellard
568 2c0262af bellard
/* protected mode interrupt */
569 2c0262af bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
570 2c0262af bellard
                                   unsigned int next_eip, int is_hw)
571 2c0262af bellard
{
572 2c0262af bellard
    SegmentCache *dt;
573 2c0262af bellard
    uint8_t *ptr, *ssp;
574 891b38e4 bellard
    int type, dpl, selector, ss_dpl, cpl, sp_mask;
575 2c0262af bellard
    int has_error_code, new_stack, shift;
576 891b38e4 bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
577 891b38e4 bellard
    uint32_t old_eip;
578 2c0262af bellard
579 7e84c249 bellard
    has_error_code = 0;
580 7e84c249 bellard
    if (!is_int && !is_hw) {
581 7e84c249 bellard
        switch(intno) {
582 7e84c249 bellard
        case 8:
583 7e84c249 bellard
        case 10:
584 7e84c249 bellard
        case 11:
585 7e84c249 bellard
        case 12:
586 7e84c249 bellard
        case 13:
587 7e84c249 bellard
        case 14:
588 7e84c249 bellard
        case 17:
589 7e84c249 bellard
            has_error_code = 1;
590 7e84c249 bellard
            break;
591 7e84c249 bellard
        }
592 7e84c249 bellard
    }
593 7e84c249 bellard
594 2c0262af bellard
    dt = &env->idt;
595 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
596 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
597 2c0262af bellard
    ptr = dt->base + intno * 8;
598 61382a50 bellard
    e1 = ldl_kernel(ptr);
599 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
600 2c0262af bellard
    /* check gate type */
601 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
602 2c0262af bellard
    switch(type) {
603 2c0262af bellard
    case 5: /* task gate */
604 7e84c249 bellard
        /* must do that check here to return the correct error code */
605 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
606 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
607 7e84c249 bellard
        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL);
608 7e84c249 bellard
        if (has_error_code) {
609 7e84c249 bellard
            int mask;
610 7e84c249 bellard
            /* push the error code */
611 7e84c249 bellard
            shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1;
612 7e84c249 bellard
            if (env->segs[R_SS].flags & DESC_B_MASK)
613 7e84c249 bellard
                mask = 0xffffffff;
614 7e84c249 bellard
            else
615 7e84c249 bellard
                mask = 0xffff;
616 7e84c249 bellard
            esp = (env->regs[R_ESP] - (2 << shift)) & mask;
617 7e84c249 bellard
            ssp = env->segs[R_SS].base + esp;
618 7e84c249 bellard
            if (shift)
619 7e84c249 bellard
                stl_kernel(ssp, error_code);
620 7e84c249 bellard
            else
621 7e84c249 bellard
                stw_kernel(ssp, error_code);
622 7e84c249 bellard
            env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask);
623 7e84c249 bellard
        }
624 7e84c249 bellard
        return;
625 2c0262af bellard
    case 6: /* 286 interrupt gate */
626 2c0262af bellard
    case 7: /* 286 trap gate */
627 2c0262af bellard
    case 14: /* 386 interrupt gate */
628 2c0262af bellard
    case 15: /* 386 trap gate */
629 2c0262af bellard
        break;
630 2c0262af bellard
    default:
631 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
632 2c0262af bellard
        break;
633 2c0262af bellard
    }
634 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
635 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
636 2c0262af bellard
    /* check privledge if software int */
637 2c0262af bellard
    if (is_int && dpl < cpl)
638 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
639 2c0262af bellard
    /* check valid bit */
640 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
641 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
642 2c0262af bellard
    selector = e1 >> 16;
643 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
644 2c0262af bellard
    if ((selector & 0xfffc) == 0)
645 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
646 2c0262af bellard
647 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
648 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
649 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
650 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
651 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
652 2c0262af bellard
    if (dpl > cpl)
653 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
654 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
655 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
656 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
657 2c0262af bellard
        /* to inner priviledge */
658 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
659 2c0262af bellard
        if ((ss & 0xfffc) == 0)
660 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
661 2c0262af bellard
        if ((ss & 3) != dpl)
662 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
663 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
664 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
665 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
666 2c0262af bellard
        if (ss_dpl != dpl)
667 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
668 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
669 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
670 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
671 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
672 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
673 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
674 2c0262af bellard
        new_stack = 1;
675 891b38e4 bellard
        sp_mask = get_sp_mask(ss_e2);
676 891b38e4 bellard
        ssp = get_seg_base(ss_e1, ss_e2);
677 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
678 2c0262af bellard
        /* to same priviledge */
679 8e682019 bellard
        if (env->eflags & VM_MASK)
680 8e682019 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
681 2c0262af bellard
        new_stack = 0;
682 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
683 891b38e4 bellard
        ssp = env->segs[R_SS].base;
684 891b38e4 bellard
        esp = ESP;
685 2c0262af bellard
    } else {
686 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
687 2c0262af bellard
        new_stack = 0; /* avoid warning */
688 891b38e4 bellard
        sp_mask = 0; /* avoid warning */
689 891b38e4 bellard
        ssp = NULL; /* avoid warning */
690 891b38e4 bellard
        esp = 0; /* avoid warning */
691 2c0262af bellard
    }
692 2c0262af bellard
693 2c0262af bellard
    shift = type >> 3;
694 891b38e4 bellard
695 891b38e4 bellard
#if 0
696 891b38e4 bellard
    /* XXX: check that enough room is available */
697 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
698 2c0262af bellard
    if (env->eflags & VM_MASK)
699 2c0262af bellard
        push_size += 8;
700 2c0262af bellard
    push_size <<= shift;
701 891b38e4 bellard
#endif
702 2c0262af bellard
    if (is_int)
703 2c0262af bellard
        old_eip = next_eip;
704 2c0262af bellard
    else
705 2c0262af bellard
        old_eip = env->eip;
706 2c0262af bellard
    if (shift == 1) {
707 2c0262af bellard
        if (new_stack) {
708 8e682019 bellard
            if (env->eflags & VM_MASK) {
709 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
710 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
711 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
712 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
713 8e682019 bellard
            }
714 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
715 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, ESP);
716 2c0262af bellard
        }
717 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, compute_eflags());
718 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
719 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, old_eip);
720 2c0262af bellard
        if (has_error_code) {
721 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, error_code);
722 2c0262af bellard
        }
723 2c0262af bellard
    } else {
724 2c0262af bellard
        if (new_stack) {
725 8e682019 bellard
            if (env->eflags & VM_MASK) {
726 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
727 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
728 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
729 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
730 8e682019 bellard
            }
731 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
732 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, ESP);
733 2c0262af bellard
        }
734 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, compute_eflags());
735 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
736 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, old_eip);
737 2c0262af bellard
        if (has_error_code) {
738 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, error_code);
739 2c0262af bellard
        }
740 2c0262af bellard
    }
741 2c0262af bellard
    
742 891b38e4 bellard
    if (new_stack) {
743 8e682019 bellard
        if (env->eflags & VM_MASK) {
744 8e682019 bellard
            /* XXX: explain me why W2K hangs if the whole segment cache is
745 8e682019 bellard
               reset ? */
746 8e682019 bellard
            env->segs[R_ES].selector = 0;
747 8e682019 bellard
            env->segs[R_ES].flags = 0;
748 8e682019 bellard
            env->segs[R_DS].selector = 0;
749 8e682019 bellard
            env->segs[R_DS].flags = 0;
750 8e682019 bellard
            env->segs[R_FS].selector = 0;
751 8e682019 bellard
            env->segs[R_FS].flags = 0;
752 8e682019 bellard
            env->segs[R_GS].selector = 0;
753 8e682019 bellard
            env->segs[R_GS].flags = 0;
754 8e682019 bellard
        }
755 891b38e4 bellard
        ss = (ss & ~3) | dpl;
756 891b38e4 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
757 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
758 891b38e4 bellard
    }
759 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (esp & sp_mask);
760 891b38e4 bellard
761 891b38e4 bellard
    selector = (selector & ~3) | dpl;
762 891b38e4 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
763 891b38e4 bellard
                   get_seg_base(e1, e2),
764 891b38e4 bellard
                   get_seg_limit(e1, e2),
765 891b38e4 bellard
                   e2);
766 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
767 891b38e4 bellard
    env->eip = offset;
768 891b38e4 bellard
769 2c0262af bellard
    /* interrupt gate clear IF mask */
770 2c0262af bellard
    if ((type & 1) == 0) {
771 2c0262af bellard
        env->eflags &= ~IF_MASK;
772 2c0262af bellard
    }
773 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
774 2c0262af bellard
}
775 2c0262af bellard
776 2c0262af bellard
/* real mode interrupt */
777 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
778 4136f33c bellard
                              unsigned int next_eip)
779 2c0262af bellard
{
780 2c0262af bellard
    SegmentCache *dt;
781 2c0262af bellard
    uint8_t *ptr, *ssp;
782 2c0262af bellard
    int selector;
783 2c0262af bellard
    uint32_t offset, esp;
784 2c0262af bellard
    uint32_t old_cs, old_eip;
785 2c0262af bellard
786 2c0262af bellard
    /* real mode (simpler !) */
787 2c0262af bellard
    dt = &env->idt;
788 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
789 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
790 2c0262af bellard
    ptr = dt->base + intno * 4;
791 61382a50 bellard
    offset = lduw_kernel(ptr);
792 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
793 2c0262af bellard
    esp = ESP;
794 2c0262af bellard
    ssp = env->segs[R_SS].base;
795 2c0262af bellard
    if (is_int)
796 2c0262af bellard
        old_eip = next_eip;
797 2c0262af bellard
    else
798 2c0262af bellard
        old_eip = env->eip;
799 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
800 891b38e4 bellard
    /* XXX: use SS segment size ? */
801 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
802 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
803 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
804 2c0262af bellard
    
805 2c0262af bellard
    /* update processor state */
806 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
807 2c0262af bellard
    env->eip = offset;
808 2c0262af bellard
    env->segs[R_CS].selector = selector;
809 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(selector << 4);
810 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
811 2c0262af bellard
}
812 2c0262af bellard
813 2c0262af bellard
/* fake user mode interrupt */
814 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
815 2c0262af bellard
                       unsigned int next_eip)
816 2c0262af bellard
{
817 2c0262af bellard
    SegmentCache *dt;
818 2c0262af bellard
    uint8_t *ptr;
819 2c0262af bellard
    int dpl, cpl;
820 2c0262af bellard
    uint32_t e2;
821 2c0262af bellard
822 2c0262af bellard
    dt = &env->idt;
823 2c0262af bellard
    ptr = dt->base + (intno * 8);
824 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
825 2c0262af bellard
    
826 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
827 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
828 2c0262af bellard
    /* check privledge if software int */
829 2c0262af bellard
    if (is_int && dpl < cpl)
830 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
831 2c0262af bellard
832 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
833 2c0262af bellard
       exiting the emulation with the suitable exception and error
834 2c0262af bellard
       code */
835 2c0262af bellard
    if (is_int)
836 2c0262af bellard
        EIP = next_eip;
837 2c0262af bellard
}
838 2c0262af bellard
839 2c0262af bellard
/*
840 2c0262af bellard
 * Begin excution of an interruption. is_int is TRUE if coming from
841 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
842 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
843 2c0262af bellard
 */
844 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
845 2c0262af bellard
                  unsigned int next_eip, int is_hw)
846 2c0262af bellard
{
847 8e682019 bellard
#if 0
848 8e682019 bellard
    {
849 8e682019 bellard
        extern FILE *stdout;
850 8e682019 bellard
        static int count;
851 8e682019 bellard
        if (env->cr[0] & CR0_PE_MASK) {
852 8e682019 bellard
            fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
853 8e682019 bellard
                    count, intno, error_code, is_int);
854 8e682019 bellard
            count++;
855 8e682019 bellard
        }
856 8e682019 bellard
    }
857 8e682019 bellard
    if ((env->cr[0] & CR0_PE_MASK) && intno == 0x10) {
858 8e682019 bellard
        tb_flush(env);
859 8e682019 bellard
        cpu_set_log(CPU_LOG_ALL);
860 8e682019 bellard
    }
861 8e682019 bellard
#endif
862 4136f33c bellard
#ifdef DEBUG_PCALL
863 4136f33c bellard
    if (loglevel) {
864 4136f33c bellard
        static int count;
865 4136f33c bellard
        fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
866 4136f33c bellard
                count, intno, error_code, is_int);
867 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
868 8e682019 bellard
#if 1
869 4136f33c bellard
        {
870 4136f33c bellard
            int i;
871 4136f33c bellard
            uint8_t *ptr;
872 8e682019 bellard
            fprintf(logfile, "       code=");
873 4136f33c bellard
            ptr = env->segs[R_CS].base + env->eip;
874 4136f33c bellard
            for(i = 0; i < 16; i++) {
875 8e682019 bellard
                fprintf(logfile, " %02x", ldub(ptr + i));
876 4136f33c bellard
            }
877 8e682019 bellard
            fprintf(logfile, "\n");
878 4136f33c bellard
        }
879 4136f33c bellard
#endif
880 4136f33c bellard
        count++;
881 4136f33c bellard
    }
882 4136f33c bellard
#endif
883 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
884 2c0262af bellard
        do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
885 2c0262af bellard
    } else {
886 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
887 2c0262af bellard
    }
888 2c0262af bellard
}
889 2c0262af bellard
890 2c0262af bellard
/*
891 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
892 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
893 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
894 2c0262af bellard
 * is_int is TRUE.  
895 2c0262af bellard
 */
896 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
897 2c0262af bellard
                     unsigned int next_eip)
898 2c0262af bellard
{
899 2c0262af bellard
    env->exception_index = intno;
900 2c0262af bellard
    env->error_code = error_code;
901 2c0262af bellard
    env->exception_is_int = is_int;
902 2c0262af bellard
    env->exception_next_eip = next_eip;
903 2c0262af bellard
    cpu_loop_exit();
904 2c0262af bellard
}
905 2c0262af bellard
906 2c0262af bellard
/* shortcuts to generate exceptions */
907 2c0262af bellard
void raise_exception_err(int exception_index, int error_code)
908 2c0262af bellard
{
909 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
910 2c0262af bellard
}
911 2c0262af bellard
912 2c0262af bellard
void raise_exception(int exception_index)
913 2c0262af bellard
{
914 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
915 2c0262af bellard
}
916 2c0262af bellard
917 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
918 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
919 2c0262af bellard
   call it from another function */
920 2c0262af bellard
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
921 2c0262af bellard
{
922 2c0262af bellard
    *q_ptr = num / den;
923 2c0262af bellard
    return num % den;
924 2c0262af bellard
}
925 2c0262af bellard
926 2c0262af bellard
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
927 2c0262af bellard
{
928 2c0262af bellard
    *q_ptr = num / den;
929 2c0262af bellard
    return num % den;
930 2c0262af bellard
}
931 2c0262af bellard
#endif
932 2c0262af bellard
933 2c0262af bellard
void helper_divl_EAX_T0(uint32_t eip)
934 2c0262af bellard
{
935 2c0262af bellard
    unsigned int den, q, r;
936 2c0262af bellard
    uint64_t num;
937 2c0262af bellard
    
938 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
939 2c0262af bellard
    den = T0;
940 2c0262af bellard
    if (den == 0) {
941 2c0262af bellard
        EIP = eip;
942 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
943 2c0262af bellard
    }
944 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
945 2c0262af bellard
    r = div64(&q, num, den);
946 2c0262af bellard
#else
947 2c0262af bellard
    q = (num / den);
948 2c0262af bellard
    r = (num % den);
949 2c0262af bellard
#endif
950 2c0262af bellard
    EAX = q;
951 2c0262af bellard
    EDX = r;
952 2c0262af bellard
}
953 2c0262af bellard
954 2c0262af bellard
void helper_idivl_EAX_T0(uint32_t eip)
955 2c0262af bellard
{
956 2c0262af bellard
    int den, q, r;
957 2c0262af bellard
    int64_t num;
958 2c0262af bellard
    
959 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
960 2c0262af bellard
    den = T0;
961 2c0262af bellard
    if (den == 0) {
962 2c0262af bellard
        EIP = eip;
963 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
964 2c0262af bellard
    }
965 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
966 2c0262af bellard
    r = idiv64(&q, num, den);
967 2c0262af bellard
#else
968 2c0262af bellard
    q = (num / den);
969 2c0262af bellard
    r = (num % den);
970 2c0262af bellard
#endif
971 2c0262af bellard
    EAX = q;
972 2c0262af bellard
    EDX = r;
973 2c0262af bellard
}
974 2c0262af bellard
975 2c0262af bellard
void helper_cmpxchg8b(void)
976 2c0262af bellard
{
977 2c0262af bellard
    uint64_t d;
978 2c0262af bellard
    int eflags;
979 2c0262af bellard
980 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
981 2c0262af bellard
    d = ldq((uint8_t *)A0);
982 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
983 2c0262af bellard
        stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
984 2c0262af bellard
        eflags |= CC_Z;
985 2c0262af bellard
    } else {
986 2c0262af bellard
        EDX = d >> 32;
987 2c0262af bellard
        EAX = d;
988 2c0262af bellard
        eflags &= ~CC_Z;
989 2c0262af bellard
    }
990 2c0262af bellard
    CC_SRC = eflags;
991 2c0262af bellard
}
992 2c0262af bellard
993 2c0262af bellard
#define CPUID_FP87 (1 << 0)
994 2c0262af bellard
#define CPUID_VME  (1 << 1)
995 2c0262af bellard
#define CPUID_DE   (1 << 2)
996 2c0262af bellard
#define CPUID_PSE  (1 << 3)
997 2c0262af bellard
#define CPUID_TSC  (1 << 4)
998 2c0262af bellard
#define CPUID_MSR  (1 << 5)
999 2c0262af bellard
#define CPUID_PAE  (1 << 6)
1000 2c0262af bellard
#define CPUID_MCE  (1 << 7)
1001 2c0262af bellard
#define CPUID_CX8  (1 << 8)
1002 2c0262af bellard
#define CPUID_APIC (1 << 9)
1003 2c0262af bellard
#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
1004 2c0262af bellard
#define CPUID_MTRR (1 << 12)
1005 2c0262af bellard
#define CPUID_PGE  (1 << 13)
1006 2c0262af bellard
#define CPUID_MCA  (1 << 14)
1007 2c0262af bellard
#define CPUID_CMOV (1 << 15)
1008 2c0262af bellard
/* ... */
1009 2c0262af bellard
#define CPUID_MMX  (1 << 23)
1010 2c0262af bellard
#define CPUID_FXSR (1 << 24)
1011 2c0262af bellard
#define CPUID_SSE  (1 << 25)
1012 2c0262af bellard
#define CPUID_SSE2 (1 << 26)
1013 2c0262af bellard
1014 2c0262af bellard
void helper_cpuid(void)
1015 2c0262af bellard
{
1016 8e682019 bellard
    switch(EAX) {
1017 8e682019 bellard
    case 0:
1018 8e682019 bellard
        EAX = 2; /* max EAX index supported */
1019 2c0262af bellard
        EBX = 0x756e6547;
1020 2c0262af bellard
        ECX = 0x6c65746e;
1021 2c0262af bellard
        EDX = 0x49656e69;
1022 8e682019 bellard
        break;
1023 8e682019 bellard
    case 1:
1024 8e682019 bellard
        {
1025 8e682019 bellard
            int family, model, stepping;
1026 8e682019 bellard
            /* EAX = 1 info */
1027 2c0262af bellard
#if 0
1028 8e682019 bellard
            /* pentium 75-200 */
1029 8e682019 bellard
            family = 5;
1030 8e682019 bellard
            model = 2;
1031 8e682019 bellard
            stepping = 11;
1032 2c0262af bellard
#else
1033 8e682019 bellard
            /* pentium pro */
1034 8e682019 bellard
            family = 6;
1035 8e682019 bellard
            model = 1;
1036 8e682019 bellard
            stepping = 3;
1037 2c0262af bellard
#endif
1038 8e682019 bellard
            EAX = (family << 8) | (model << 4) | stepping;
1039 8e682019 bellard
            EBX = 0;
1040 8e682019 bellard
            ECX = 0;
1041 8e682019 bellard
            EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
1042 8e682019 bellard
                CPUID_TSC | CPUID_MSR | CPUID_MCE |
1043 8e682019 bellard
                CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
1044 8e682019 bellard
        }
1045 8e682019 bellard
        break;
1046 8e682019 bellard
    default:
1047 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1048 8e682019 bellard
        EAX = 0x410601;
1049 2c0262af bellard
        EBX = 0;
1050 2c0262af bellard
        ECX = 0;
1051 8e682019 bellard
        EDX = 0;
1052 8e682019 bellard
        break;
1053 2c0262af bellard
    }
1054 2c0262af bellard
}
1055 2c0262af bellard
1056 2c0262af bellard
void helper_lldt_T0(void)
1057 2c0262af bellard
{
1058 2c0262af bellard
    int selector;
1059 2c0262af bellard
    SegmentCache *dt;
1060 2c0262af bellard
    uint32_t e1, e2;
1061 2c0262af bellard
    int index;
1062 2c0262af bellard
    uint8_t *ptr;
1063 2c0262af bellard
    
1064 2c0262af bellard
    selector = T0 & 0xffff;
1065 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1066 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1067 2c0262af bellard
        env->ldt.base = NULL;
1068 2c0262af bellard
        env->ldt.limit = 0;
1069 2c0262af bellard
    } else {
1070 2c0262af bellard
        if (selector & 0x4)
1071 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1072 2c0262af bellard
        dt = &env->gdt;
1073 2c0262af bellard
        index = selector & ~7;
1074 2c0262af bellard
        if ((index + 7) > dt->limit)
1075 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1076 2c0262af bellard
        ptr = dt->base + index;
1077 61382a50 bellard
        e1 = ldl_kernel(ptr);
1078 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1079 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1080 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1081 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1082 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1083 2c0262af bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
1084 2c0262af bellard
    }
1085 2c0262af bellard
    env->ldt.selector = selector;
1086 2c0262af bellard
}
1087 2c0262af bellard
1088 2c0262af bellard
void helper_ltr_T0(void)
1089 2c0262af bellard
{
1090 2c0262af bellard
    int selector;
1091 2c0262af bellard
    SegmentCache *dt;
1092 2c0262af bellard
    uint32_t e1, e2;
1093 2c0262af bellard
    int index, type;
1094 2c0262af bellard
    uint8_t *ptr;
1095 2c0262af bellard
    
1096 2c0262af bellard
    selector = T0 & 0xffff;
1097 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1098 2c0262af bellard
        /* NULL selector case: invalid LDT */
1099 2c0262af bellard
        env->tr.base = NULL;
1100 2c0262af bellard
        env->tr.limit = 0;
1101 2c0262af bellard
        env->tr.flags = 0;
1102 2c0262af bellard
    } else {
1103 2c0262af bellard
        if (selector & 0x4)
1104 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1105 2c0262af bellard
        dt = &env->gdt;
1106 2c0262af bellard
        index = selector & ~7;
1107 2c0262af bellard
        if ((index + 7) > dt->limit)
1108 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1109 2c0262af bellard
        ptr = dt->base + index;
1110 61382a50 bellard
        e1 = ldl_kernel(ptr);
1111 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1112 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1113 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
1114 7e84c249 bellard
            (type != 1 && type != 9))
1115 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1116 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1117 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1118 2c0262af bellard
        load_seg_cache_raw_dt(&env->tr, e1, e2);
1119 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1120 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1121 2c0262af bellard
    }
1122 2c0262af bellard
    env->tr.selector = selector;
1123 2c0262af bellard
}
1124 2c0262af bellard
1125 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1126 8e682019 bellard
void load_seg(int seg_reg, int selector)
1127 2c0262af bellard
{
1128 2c0262af bellard
    uint32_t e1, e2;
1129 3ab493de bellard
    int cpl, dpl, rpl;
1130 3ab493de bellard
    SegmentCache *dt;
1131 3ab493de bellard
    int index;
1132 3ab493de bellard
    uint8_t *ptr;
1133 3ab493de bellard
1134 8e682019 bellard
    selector &= 0xffff;
1135 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1136 2c0262af bellard
        /* null selector case */
1137 8e682019 bellard
        if (seg_reg == R_SS)
1138 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1139 8e682019 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
1140 2c0262af bellard
    } else {
1141 3ab493de bellard
        
1142 3ab493de bellard
        if (selector & 0x4)
1143 3ab493de bellard
            dt = &env->ldt;
1144 3ab493de bellard
        else
1145 3ab493de bellard
            dt = &env->gdt;
1146 3ab493de bellard
        index = selector & ~7;
1147 8e682019 bellard
        if ((index + 7) > dt->limit)
1148 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1149 3ab493de bellard
        ptr = dt->base + index;
1150 3ab493de bellard
        e1 = ldl_kernel(ptr);
1151 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1152 3ab493de bellard
1153 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1154 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1155 3ab493de bellard
        rpl = selector & 3;
1156 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1157 3ab493de bellard
        cpl = env->hflags & HF_CPL_MASK;
1158 2c0262af bellard
        if (seg_reg == R_SS) {
1159 3ab493de bellard
            /* must be writable segment */
1160 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1161 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1162 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1163 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1164 2c0262af bellard
        } else {
1165 3ab493de bellard
            /* must be readable segment */
1166 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1167 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1168 3ab493de bellard
            
1169 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1170 3ab493de bellard
                /* if not conforming code, test rights */
1171 8e682019 bellard
                if (dpl < cpl || dpl < rpl)
1172 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1173 3ab493de bellard
            }
1174 2c0262af bellard
        }
1175 2c0262af bellard
1176 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1177 2c0262af bellard
            if (seg_reg == R_SS)
1178 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1179 2c0262af bellard
            else
1180 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1181 2c0262af bellard
        }
1182 3ab493de bellard
1183 3ab493de bellard
        /* set the access bit if not already set */
1184 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1185 3ab493de bellard
            e2 |= DESC_A_MASK;
1186 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1187 3ab493de bellard
        }
1188 3ab493de bellard
1189 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
1190 2c0262af bellard
                       get_seg_base(e1, e2),
1191 2c0262af bellard
                       get_seg_limit(e1, e2),
1192 2c0262af bellard
                       e2);
1193 2c0262af bellard
#if 0
1194 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
1195 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1196 2c0262af bellard
#endif
1197 2c0262af bellard
    }
1198 2c0262af bellard
}
1199 2c0262af bellard
1200 2c0262af bellard
/* protected mode jump */
1201 2c0262af bellard
void helper_ljmp_protected_T0_T1(void)
1202 2c0262af bellard
{
1203 7e84c249 bellard
    int new_cs, new_eip, gate_cs, type;
1204 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
1205 2c0262af bellard
1206 2c0262af bellard
    new_cs = T0;
1207 2c0262af bellard
    new_eip = T1;
1208 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1209 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1210 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1211 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1212 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1213 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1214 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1215 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1216 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1217 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1218 2c0262af bellard
            /* conforming code segment */
1219 2c0262af bellard
            if (dpl > cpl)
1220 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1221 2c0262af bellard
        } else {
1222 2c0262af bellard
            /* non conforming code segment */
1223 2c0262af bellard
            rpl = new_cs & 3;
1224 2c0262af bellard
            if (rpl > cpl)
1225 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1226 2c0262af bellard
            if (dpl != cpl)
1227 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1228 2c0262af bellard
        }
1229 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1230 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1231 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1232 2c0262af bellard
        if (new_eip > limit)
1233 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1234 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1235 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1236 2c0262af bellard
        EIP = new_eip;
1237 2c0262af bellard
    } else {
1238 7e84c249 bellard
        /* jump to call or task gate */
1239 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1240 7e84c249 bellard
        rpl = new_cs & 3;
1241 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
1242 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1243 7e84c249 bellard
        switch(type) {
1244 7e84c249 bellard
        case 1: /* 286 TSS */
1245 7e84c249 bellard
        case 9: /* 386 TSS */
1246 7e84c249 bellard
        case 5: /* task gate */
1247 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1248 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1249 7e84c249 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP);
1250 7e84c249 bellard
            break;
1251 7e84c249 bellard
        case 4: /* 286 call gate */
1252 7e84c249 bellard
        case 12: /* 386 call gate */
1253 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
1254 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1255 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1256 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1257 7e84c249 bellard
            gate_cs = e1 >> 16;
1258 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
1259 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1260 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1261 7e84c249 bellard
            /* must be code segment */
1262 7e84c249 bellard
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
1263 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
1264 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1265 7e84c249 bellard
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1266 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1267 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1268 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1269 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1270 7e84c249 bellard
            new_eip = (e1 & 0xffff);
1271 7e84c249 bellard
            if (type == 12)
1272 7e84c249 bellard
                new_eip |= (e2 & 0xffff0000);
1273 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
1274 7e84c249 bellard
            if (new_eip > limit)
1275 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
1276 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1277 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
1278 7e84c249 bellard
            EIP = new_eip;
1279 7e84c249 bellard
            break;
1280 7e84c249 bellard
        default:
1281 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1282 7e84c249 bellard
            break;
1283 7e84c249 bellard
        }
1284 2c0262af bellard
    }
1285 2c0262af bellard
}
1286 2c0262af bellard
1287 2c0262af bellard
/* real mode call */
1288 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
1289 2c0262af bellard
{
1290 2c0262af bellard
    int new_cs, new_eip;
1291 2c0262af bellard
    uint32_t esp, esp_mask;
1292 2c0262af bellard
    uint8_t *ssp;
1293 2c0262af bellard
1294 2c0262af bellard
    new_cs = T0;
1295 2c0262af bellard
    new_eip = T1;
1296 2c0262af bellard
    esp = ESP;
1297 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1298 2c0262af bellard
    ssp = env->segs[R_SS].base;
1299 2c0262af bellard
    if (shift) {
1300 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1301 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
1302 2c0262af bellard
    } else {
1303 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1304 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
1305 2c0262af bellard
    }
1306 2c0262af bellard
1307 891b38e4 bellard
    ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1308 2c0262af bellard
    env->eip = new_eip;
1309 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
1310 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
1311 2c0262af bellard
}
1312 2c0262af bellard
1313 2c0262af bellard
/* protected mode call */
1314 2c0262af bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip)
1315 2c0262af bellard
{
1316 891b38e4 bellard
    int new_cs, new_eip, new_stack, i;
1317 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1318 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1319 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
1320 2c0262af bellard
    uint8_t *ssp, *old_ssp;
1321 2c0262af bellard
    
1322 2c0262af bellard
    new_cs = T0;
1323 2c0262af bellard
    new_eip = T1;
1324 f3f2d9be bellard
#ifdef DEBUG_PCALL
1325 f3f2d9be bellard
    if (loglevel) {
1326 f3f2d9be bellard
        fprintf(logfile, "lcall %04x:%08x\n",
1327 f3f2d9be bellard
                new_cs, new_eip);
1328 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1329 f3f2d9be bellard
    }
1330 f3f2d9be bellard
#endif
1331 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1332 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1333 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1334 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1335 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1336 f3f2d9be bellard
#ifdef DEBUG_PCALL
1337 f3f2d9be bellard
    if (loglevel) {
1338 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1339 f3f2d9be bellard
    }
1340 f3f2d9be bellard
#endif
1341 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1342 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1343 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1344 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1345 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1346 2c0262af bellard
            /* conforming code segment */
1347 2c0262af bellard
            if (dpl > cpl)
1348 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1349 2c0262af bellard
        } else {
1350 2c0262af bellard
            /* non conforming code segment */
1351 2c0262af bellard
            rpl = new_cs & 3;
1352 2c0262af bellard
            if (rpl > cpl)
1353 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1354 2c0262af bellard
            if (dpl != cpl)
1355 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1356 2c0262af bellard
        }
1357 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1358 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1359 2c0262af bellard
1360 2c0262af bellard
        sp = ESP;
1361 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
1362 891b38e4 bellard
        ssp = env->segs[R_SS].base;
1363 2c0262af bellard
        if (shift) {
1364 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1365 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1366 2c0262af bellard
        } else {
1367 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1368 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1369 2c0262af bellard
        }
1370 2c0262af bellard
        
1371 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1372 2c0262af bellard
        if (new_eip > limit)
1373 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1374 2c0262af bellard
        /* from this point, not restartable */
1375 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1376 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1377 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1378 2c0262af bellard
        EIP = new_eip;
1379 2c0262af bellard
    } else {
1380 2c0262af bellard
        /* check gate type */
1381 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1382 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1383 7e84c249 bellard
        rpl = new_cs & 3;
1384 2c0262af bellard
        switch(type) {
1385 2c0262af bellard
        case 1: /* available 286 TSS */
1386 2c0262af bellard
        case 9: /* available 386 TSS */
1387 2c0262af bellard
        case 5: /* task gate */
1388 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1389 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1390 7e84c249 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL);
1391 2c0262af bellard
            break;
1392 2c0262af bellard
        case 4: /* 286 call gate */
1393 2c0262af bellard
        case 12: /* 386 call gate */
1394 2c0262af bellard
            break;
1395 2c0262af bellard
        default:
1396 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1397 2c0262af bellard
            break;
1398 2c0262af bellard
        }
1399 2c0262af bellard
        shift = type >> 3;
1400 2c0262af bellard
1401 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
1402 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1403 2c0262af bellard
        /* check valid bit */
1404 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1405 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
1406 2c0262af bellard
        selector = e1 >> 16;
1407 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1408 f3f2d9be bellard
        param_count = e2 & 0x1f;
1409 2c0262af bellard
        if ((selector & 0xfffc) == 0)
1410 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1411 2c0262af bellard
1412 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
1413 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1414 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1415 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1416 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1417 2c0262af bellard
        if (dpl > cpl)
1418 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1419 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1420 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1421 2c0262af bellard
1422 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1423 2c0262af bellard
            /* to inner priviledge */
1424 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
1425 f3f2d9be bellard
#ifdef DEBUG_PCALL
1426 f3f2d9be bellard
            if (loglevel)
1427 f3f2d9be bellard
                fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n", 
1428 f3f2d9be bellard
                        ss, sp, param_count, ESP);
1429 f3f2d9be bellard
#endif
1430 2c0262af bellard
            if ((ss & 0xfffc) == 0)
1431 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1432 2c0262af bellard
            if ((ss & 3) != dpl)
1433 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1434 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1435 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1436 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1437 2c0262af bellard
            if (ss_dpl != dpl)
1438 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1439 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
1440 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
1441 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
1442 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1443 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
1444 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1445 2c0262af bellard
            
1446 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
1447 2c0262af bellard
1448 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1449 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
1450 2c0262af bellard
            
1451 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
1452 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
1453 2c0262af bellard
            if (shift) {
1454 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1455 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
1456 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1457 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1458 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
1459 2c0262af bellard
                }
1460 2c0262af bellard
            } else {
1461 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1462 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
1463 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1464 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1465 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
1466 2c0262af bellard
                }
1467 2c0262af bellard
            }
1468 891b38e4 bellard
            new_stack = 1;
1469 2c0262af bellard
        } else {
1470 2c0262af bellard
            /* to same priviledge */
1471 891b38e4 bellard
            sp = ESP;
1472 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
1473 891b38e4 bellard
            ssp = env->segs[R_SS].base;
1474 891b38e4 bellard
            //            push_size = (4 << shift);
1475 891b38e4 bellard
            new_stack = 0;
1476 2c0262af bellard
        }
1477 2c0262af bellard
1478 2c0262af bellard
        if (shift) {
1479 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1480 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1481 2c0262af bellard
        } else {
1482 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1483 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1484 891b38e4 bellard
        }
1485 891b38e4 bellard
1486 891b38e4 bellard
        /* from this point, not restartable */
1487 891b38e4 bellard
1488 891b38e4 bellard
        if (new_stack) {
1489 891b38e4 bellard
            ss = (ss & ~3) | dpl;
1490 891b38e4 bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
1491 891b38e4 bellard
                                   ssp,
1492 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
1493 891b38e4 bellard
                                   ss_e2);
1494 2c0262af bellard
        }
1495 2c0262af bellard
1496 2c0262af bellard
        selector = (selector & ~3) | dpl;
1497 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
1498 2c0262af bellard
                       get_seg_base(e1, e2),
1499 2c0262af bellard
                       get_seg_limit(e1, e2),
1500 2c0262af bellard
                       e2);
1501 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
1502 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1503 2c0262af bellard
        EIP = offset;
1504 2c0262af bellard
    }
1505 2c0262af bellard
}
1506 2c0262af bellard
1507 7e84c249 bellard
/* real and vm86 mode iret */
1508 2c0262af bellard
void helper_iret_real(int shift)
1509 2c0262af bellard
{
1510 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1511 2c0262af bellard
    uint8_t *ssp;
1512 2c0262af bellard
    int eflags_mask;
1513 7e84c249 bellard
1514 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1515 891b38e4 bellard
    sp = ESP;
1516 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1517 2c0262af bellard
    if (shift == 1) {
1518 2c0262af bellard
        /* 32 bits */
1519 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1520 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1521 891b38e4 bellard
        new_cs &= 0xffff;
1522 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
1523 2c0262af bellard
    } else {
1524 2c0262af bellard
        /* 16 bits */
1525 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1526 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1527 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
1528 2c0262af bellard
    }
1529 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1530 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1531 2c0262af bellard
    env->eip = new_eip;
1532 7e84c249 bellard
    if (env->eflags & VM_MASK)
1533 4136f33c bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK;
1534 7e84c249 bellard
    else
1535 4136f33c bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK;
1536 2c0262af bellard
    if (shift == 0)
1537 2c0262af bellard
        eflags_mask &= 0xffff;
1538 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
1539 2c0262af bellard
}
1540 2c0262af bellard
1541 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
1542 8e682019 bellard
{
1543 8e682019 bellard
    int dpl;
1544 8e682019 bellard
    uint32_t e2;
1545 8e682019 bellard
    
1546 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
1547 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1548 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1549 8e682019 bellard
        /* data or non conforming code segment */
1550 8e682019 bellard
        if (dpl < cpl) {
1551 8e682019 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
1552 8e682019 bellard
        }
1553 8e682019 bellard
    }
1554 8e682019 bellard
}
1555 8e682019 bellard
1556 2c0262af bellard
/* protected mode iret */
1557 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
1558 2c0262af bellard
{
1559 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
1560 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
1561 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
1562 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
1563 2c0262af bellard
    uint8_t *ssp;
1564 2c0262af bellard
    
1565 891b38e4 bellard
    sp_mask = get_sp_mask(env->segs[R_SS].flags);
1566 2c0262af bellard
    sp = ESP;
1567 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1568 2c0262af bellard
    if (shift == 1) {
1569 2c0262af bellard
        /* 32 bits */
1570 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1571 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1572 891b38e4 bellard
        new_cs &= 0xffff;
1573 891b38e4 bellard
        if (is_iret) {
1574 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
1575 891b38e4 bellard
            if (new_eflags & VM_MASK)
1576 891b38e4 bellard
                goto return_to_vm86;
1577 891b38e4 bellard
        }
1578 2c0262af bellard
    } else {
1579 2c0262af bellard
        /* 16 bits */
1580 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1581 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1582 2c0262af bellard
        if (is_iret)
1583 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
1584 2c0262af bellard
    }
1585 891b38e4 bellard
#ifdef DEBUG_PCALL
1586 891b38e4 bellard
    if (loglevel) {
1587 4136f33c bellard
        fprintf(logfile, "lret new %04x:%08x addend=0x%x\n",
1588 4136f33c bellard
                new_cs, new_eip, addend);
1589 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1590 891b38e4 bellard
    }
1591 891b38e4 bellard
#endif
1592 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1593 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1594 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1595 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1596 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
1597 2c0262af bellard
        !(e2 & DESC_CS_MASK))
1598 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1599 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1600 2c0262af bellard
    rpl = new_cs & 3; 
1601 2c0262af bellard
    if (rpl < cpl)
1602 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1603 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1604 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
1605 2c0262af bellard
        if (dpl > rpl)
1606 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1607 2c0262af bellard
    } else {
1608 2c0262af bellard
        if (dpl != rpl)
1609 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1610 2c0262af bellard
    }
1611 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
1612 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1613 2c0262af bellard
    
1614 891b38e4 bellard
    sp += addend;
1615 2c0262af bellard
    if (rpl == cpl) {
1616 2c0262af bellard
        /* return to same priledge level */
1617 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1618 2c0262af bellard
                       get_seg_base(e1, e2),
1619 2c0262af bellard
                       get_seg_limit(e1, e2),
1620 2c0262af bellard
                       e2);
1621 2c0262af bellard
    } else {
1622 2c0262af bellard
        /* return to different priviledge level */
1623 2c0262af bellard
        if (shift == 1) {
1624 2c0262af bellard
            /* 32 bits */
1625 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
1626 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
1627 891b38e4 bellard
            new_ss &= 0xffff;
1628 2c0262af bellard
        } else {
1629 2c0262af bellard
            /* 16 bits */
1630 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
1631 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
1632 2c0262af bellard
        }
1633 2c0262af bellard
        
1634 2c0262af bellard
        if ((new_ss & 3) != rpl)
1635 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1636 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
1637 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1638 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
1639 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
1640 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
1641 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1642 2c0262af bellard
        dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1643 2c0262af bellard
        if (dpl != rpl)
1644 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1645 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
1646 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
1647 2c0262af bellard
1648 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1649 2c0262af bellard
                       get_seg_base(e1, e2),
1650 2c0262af bellard
                       get_seg_limit(e1, e2),
1651 2c0262af bellard
                       e2);
1652 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_SS, new_ss, 
1653 2c0262af bellard
                       get_seg_base(ss_e1, ss_e2),
1654 2c0262af bellard
                       get_seg_limit(ss_e1, ss_e2),
1655 2c0262af bellard
                       ss_e2);
1656 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
1657 891b38e4 bellard
        sp = new_esp;
1658 891b38e4 bellard
        /* XXX: change sp_mask according to old segment ? */
1659 8e682019 bellard
1660 8e682019 bellard
        /* validate data segments */
1661 8e682019 bellard
        validate_seg(R_ES, cpl);
1662 8e682019 bellard
        validate_seg(R_DS, cpl);
1663 8e682019 bellard
        validate_seg(R_FS, cpl);
1664 8e682019 bellard
        validate_seg(R_GS, cpl);
1665 2c0262af bellard
    }
1666 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1667 2c0262af bellard
    env->eip = new_eip;
1668 2c0262af bellard
    if (is_iret) {
1669 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
1670 4136f33c bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK;
1671 2c0262af bellard
        if (cpl == 0)
1672 4136f33c bellard
            eflags_mask |= IOPL_MASK;
1673 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
1674 4136f33c bellard
        if (cpl <= iopl)
1675 4136f33c bellard
            eflags_mask |= IF_MASK;
1676 2c0262af bellard
        if (shift == 0)
1677 2c0262af bellard
            eflags_mask &= 0xffff;
1678 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
1679 2c0262af bellard
    }
1680 2c0262af bellard
    return;
1681 2c0262af bellard
1682 2c0262af bellard
 return_to_vm86:
1683 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
1684 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
1685 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
1686 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
1687 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
1688 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
1689 2c0262af bellard
    
1690 2c0262af bellard
    /* modify processor state */
1691 4136f33c bellard
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
1692 4136f33c bellard
                IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK);
1693 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
1694 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
1695 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
1696 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
1697 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
1698 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
1699 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
1700 2c0262af bellard
1701 2c0262af bellard
    env->eip = new_eip;
1702 2c0262af bellard
    ESP = new_esp;
1703 2c0262af bellard
}
1704 2c0262af bellard
1705 2c0262af bellard
void helper_iret_protected(int shift)
1706 2c0262af bellard
{
1707 7e84c249 bellard
    int tss_selector, type;
1708 7e84c249 bellard
    uint32_t e1, e2;
1709 7e84c249 bellard
    
1710 7e84c249 bellard
    /* specific case for TSS */
1711 7e84c249 bellard
    if (env->eflags & NT_MASK) {
1712 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
1713 7e84c249 bellard
        if (tss_selector & 4)
1714 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1715 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
1716 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1717 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
1718 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
1719 7e84c249 bellard
        if (type != 3)
1720 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1721 7e84c249 bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET);
1722 7e84c249 bellard
    } else {
1723 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
1724 7e84c249 bellard
    }
1725 2c0262af bellard
}
1726 2c0262af bellard
1727 2c0262af bellard
void helper_lret_protected(int shift, int addend)
1728 2c0262af bellard
{
1729 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
1730 2c0262af bellard
}
1731 2c0262af bellard
1732 2c0262af bellard
void helper_movl_crN_T0(int reg)
1733 2c0262af bellard
{
1734 2c0262af bellard
    env->cr[reg] = T0;
1735 2c0262af bellard
    switch(reg) {
1736 2c0262af bellard
    case 0:
1737 2c0262af bellard
        cpu_x86_update_cr0(env);
1738 2c0262af bellard
        break;
1739 2c0262af bellard
    case 3:
1740 2c0262af bellard
        cpu_x86_update_cr3(env);
1741 2c0262af bellard
        break;
1742 2c0262af bellard
    }
1743 2c0262af bellard
}
1744 2c0262af bellard
1745 2c0262af bellard
/* XXX: do more */
1746 2c0262af bellard
void helper_movl_drN_T0(int reg)
1747 2c0262af bellard
{
1748 2c0262af bellard
    env->dr[reg] = T0;
1749 2c0262af bellard
}
1750 2c0262af bellard
1751 2c0262af bellard
void helper_invlpg(unsigned int addr)
1752 2c0262af bellard
{
1753 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
1754 2c0262af bellard
}
1755 2c0262af bellard
1756 2c0262af bellard
/* rdtsc */
1757 2c0262af bellard
#ifndef __i386__
1758 2c0262af bellard
uint64_t emu_time;
1759 2c0262af bellard
#endif
1760 2c0262af bellard
1761 2c0262af bellard
void helper_rdtsc(void)
1762 2c0262af bellard
{
1763 2c0262af bellard
    uint64_t val;
1764 2c0262af bellard
#ifdef __i386__
1765 2c0262af bellard
    asm("rdtsc" : "=A" (val));
1766 2c0262af bellard
#else
1767 2c0262af bellard
    /* better than nothing: the time increases */
1768 2c0262af bellard
    val = emu_time++;
1769 2c0262af bellard
#endif
1770 2c0262af bellard
    EAX = val;
1771 2c0262af bellard
    EDX = val >> 32;
1772 2c0262af bellard
}
1773 2c0262af bellard
1774 2c0262af bellard
void helper_wrmsr(void)
1775 2c0262af bellard
{
1776 2c0262af bellard
    switch(ECX) {
1777 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1778 2c0262af bellard
        env->sysenter_cs = EAX & 0xffff;
1779 2c0262af bellard
        break;
1780 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1781 2c0262af bellard
        env->sysenter_esp = EAX;
1782 2c0262af bellard
        break;
1783 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1784 2c0262af bellard
        env->sysenter_eip = EAX;
1785 2c0262af bellard
        break;
1786 2c0262af bellard
    default:
1787 2c0262af bellard
        /* XXX: exception ? */
1788 2c0262af bellard
        break; 
1789 2c0262af bellard
    }
1790 2c0262af bellard
}
1791 2c0262af bellard
1792 2c0262af bellard
void helper_rdmsr(void)
1793 2c0262af bellard
{
1794 2c0262af bellard
    switch(ECX) {
1795 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1796 2c0262af bellard
        EAX = env->sysenter_cs;
1797 2c0262af bellard
        EDX = 0;
1798 2c0262af bellard
        break;
1799 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1800 2c0262af bellard
        EAX = env->sysenter_esp;
1801 2c0262af bellard
        EDX = 0;
1802 2c0262af bellard
        break;
1803 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1804 2c0262af bellard
        EAX = env->sysenter_eip;
1805 2c0262af bellard
        EDX = 0;
1806 2c0262af bellard
        break;
1807 2c0262af bellard
    default:
1808 2c0262af bellard
        /* XXX: exception ? */
1809 2c0262af bellard
        break; 
1810 2c0262af bellard
    }
1811 2c0262af bellard
}
1812 2c0262af bellard
1813 2c0262af bellard
void helper_lsl(void)
1814 2c0262af bellard
{
1815 2c0262af bellard
    unsigned int selector, limit;
1816 2c0262af bellard
    uint32_t e1, e2;
1817 3ab493de bellard
    int rpl, dpl, cpl, type;
1818 2c0262af bellard
1819 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1820 2c0262af bellard
    selector = T0 & 0xffff;
1821 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1822 2c0262af bellard
        return;
1823 3ab493de bellard
    rpl = selector & 3;
1824 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1825 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1826 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1827 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1828 3ab493de bellard
            /* conforming */
1829 3ab493de bellard
        } else {
1830 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1831 3ab493de bellard
                return;
1832 3ab493de bellard
        }
1833 3ab493de bellard
    } else {
1834 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1835 3ab493de bellard
        switch(type) {
1836 3ab493de bellard
        case 1:
1837 3ab493de bellard
        case 2:
1838 3ab493de bellard
        case 3:
1839 3ab493de bellard
        case 9:
1840 3ab493de bellard
        case 11:
1841 3ab493de bellard
            break;
1842 3ab493de bellard
        default:
1843 3ab493de bellard
            return;
1844 3ab493de bellard
        }
1845 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1846 3ab493de bellard
            return;
1847 3ab493de bellard
    }
1848 3ab493de bellard
    limit = get_seg_limit(e1, e2);
1849 2c0262af bellard
    T1 = limit;
1850 2c0262af bellard
    CC_SRC |= CC_Z;
1851 2c0262af bellard
}
1852 2c0262af bellard
1853 2c0262af bellard
void helper_lar(void)
1854 2c0262af bellard
{
1855 2c0262af bellard
    unsigned int selector;
1856 2c0262af bellard
    uint32_t e1, e2;
1857 3ab493de bellard
    int rpl, dpl, cpl, type;
1858 2c0262af bellard
1859 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1860 2c0262af bellard
    selector = T0 & 0xffff;
1861 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1862 3ab493de bellard
        return;
1863 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1864 2c0262af bellard
        return;
1865 3ab493de bellard
    rpl = selector & 3;
1866 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1867 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1868 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1869 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1870 3ab493de bellard
            /* conforming */
1871 3ab493de bellard
        } else {
1872 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1873 3ab493de bellard
                return;
1874 3ab493de bellard
        }
1875 3ab493de bellard
    } else {
1876 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1877 3ab493de bellard
        switch(type) {
1878 3ab493de bellard
        case 1:
1879 3ab493de bellard
        case 2:
1880 3ab493de bellard
        case 3:
1881 3ab493de bellard
        case 4:
1882 3ab493de bellard
        case 5:
1883 3ab493de bellard
        case 9:
1884 3ab493de bellard
        case 11:
1885 3ab493de bellard
        case 12:
1886 3ab493de bellard
            break;
1887 3ab493de bellard
        default:
1888 3ab493de bellard
            return;
1889 3ab493de bellard
        }
1890 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1891 3ab493de bellard
            return;
1892 3ab493de bellard
    }
1893 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
1894 2c0262af bellard
    CC_SRC |= CC_Z;
1895 2c0262af bellard
}
1896 2c0262af bellard
1897 3ab493de bellard
void helper_verr(void)
1898 3ab493de bellard
{
1899 3ab493de bellard
    unsigned int selector;
1900 3ab493de bellard
    uint32_t e1, e2;
1901 3ab493de bellard
    int rpl, dpl, cpl;
1902 3ab493de bellard
1903 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1904 3ab493de bellard
    selector = T0 & 0xffff;
1905 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1906 3ab493de bellard
        return;
1907 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1908 3ab493de bellard
        return;
1909 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1910 3ab493de bellard
        return;
1911 3ab493de bellard
    rpl = selector & 3;
1912 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1913 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1914 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1915 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
1916 3ab493de bellard
            return;
1917 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
1918 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1919 3ab493de bellard
                return;
1920 3ab493de bellard
        }
1921 3ab493de bellard
    } else {
1922 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1923 3ab493de bellard
            return;
1924 3ab493de bellard
    }
1925 f3f2d9be bellard
    CC_SRC |= CC_Z;
1926 3ab493de bellard
}
1927 3ab493de bellard
1928 3ab493de bellard
void helper_verw(void)
1929 3ab493de bellard
{
1930 3ab493de bellard
    unsigned int selector;
1931 3ab493de bellard
    uint32_t e1, e2;
1932 3ab493de bellard
    int rpl, dpl, cpl;
1933 3ab493de bellard
1934 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1935 3ab493de bellard
    selector = T0 & 0xffff;
1936 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1937 3ab493de bellard
        return;
1938 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1939 3ab493de bellard
        return;
1940 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1941 3ab493de bellard
        return;
1942 3ab493de bellard
    rpl = selector & 3;
1943 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1944 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1945 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1946 3ab493de bellard
        return;
1947 3ab493de bellard
    } else {
1948 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1949 3ab493de bellard
            return;
1950 3ab493de bellard
        if (!(e2 & DESC_W_MASK))
1951 3ab493de bellard
            return;
1952 3ab493de bellard
    }
1953 f3f2d9be bellard
    CC_SRC |= CC_Z;
1954 3ab493de bellard
}
1955 3ab493de bellard
1956 2c0262af bellard
/* FPU helpers */
1957 2c0262af bellard
1958 2c0262af bellard
void helper_fldt_ST0_A0(void)
1959 2c0262af bellard
{
1960 2c0262af bellard
    int new_fpstt;
1961 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
1962 2c0262af bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1963 2c0262af bellard
    env->fpstt = new_fpstt;
1964 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
1965 2c0262af bellard
}
1966 2c0262af bellard
1967 2c0262af bellard
void helper_fstt_ST0_A0(void)
1968 2c0262af bellard
{
1969 2c0262af bellard
    helper_fstt(ST0, (uint8_t *)A0);
1970 2c0262af bellard
}
1971 2c0262af bellard
1972 2c0262af bellard
/* BCD ops */
1973 2c0262af bellard
1974 2c0262af bellard
#define MUL10(iv) ( iv + iv + (iv << 3) )
1975 2c0262af bellard
1976 2c0262af bellard
void helper_fbld_ST0_A0(void)
1977 2c0262af bellard
{
1978 2c0262af bellard
    CPU86_LDouble tmp;
1979 2c0262af bellard
    uint64_t val;
1980 2c0262af bellard
    unsigned int v;
1981 2c0262af bellard
    int i;
1982 2c0262af bellard
1983 2c0262af bellard
    val = 0;
1984 2c0262af bellard
    for(i = 8; i >= 0; i--) {
1985 2c0262af bellard
        v = ldub((uint8_t *)A0 + i);
1986 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
1987 2c0262af bellard
    }
1988 2c0262af bellard
    tmp = val;
1989 2c0262af bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
1990 2c0262af bellard
        tmp = -tmp;
1991 2c0262af bellard
    fpush();
1992 2c0262af bellard
    ST0 = tmp;
1993 2c0262af bellard
}
1994 2c0262af bellard
1995 2c0262af bellard
void helper_fbst_ST0_A0(void)
1996 2c0262af bellard
{
1997 2c0262af bellard
    CPU86_LDouble tmp;
1998 2c0262af bellard
    int v;
1999 2c0262af bellard
    uint8_t *mem_ref, *mem_end;
2000 2c0262af bellard
    int64_t val;
2001 2c0262af bellard
2002 2c0262af bellard
    tmp = rint(ST0);
2003 2c0262af bellard
    val = (int64_t)tmp;
2004 2c0262af bellard
    mem_ref = (uint8_t *)A0;
2005 2c0262af bellard
    mem_end = mem_ref + 9;
2006 2c0262af bellard
    if (val < 0) {
2007 2c0262af bellard
        stb(mem_end, 0x80);
2008 2c0262af bellard
        val = -val;
2009 2c0262af bellard
    } else {
2010 2c0262af bellard
        stb(mem_end, 0x00);
2011 2c0262af bellard
    }
2012 2c0262af bellard
    while (mem_ref < mem_end) {
2013 2c0262af bellard
        if (val == 0)
2014 2c0262af bellard
            break;
2015 2c0262af bellard
        v = val % 100;
2016 2c0262af bellard
        val = val / 100;
2017 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
2018 2c0262af bellard
        stb(mem_ref++, v);
2019 2c0262af bellard
    }
2020 2c0262af bellard
    while (mem_ref < mem_end) {
2021 2c0262af bellard
        stb(mem_ref++, 0);
2022 2c0262af bellard
    }
2023 2c0262af bellard
}
2024 2c0262af bellard
2025 2c0262af bellard
void helper_f2xm1(void)
2026 2c0262af bellard
{
2027 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
2028 2c0262af bellard
}
2029 2c0262af bellard
2030 2c0262af bellard
void helper_fyl2x(void)
2031 2c0262af bellard
{
2032 2c0262af bellard
    CPU86_LDouble fptemp;
2033 2c0262af bellard
    
2034 2c0262af bellard
    fptemp = ST0;
2035 2c0262af bellard
    if (fptemp>0.0){
2036 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
2037 2c0262af bellard
        ST1 *= fptemp;
2038 2c0262af bellard
        fpop();
2039 2c0262af bellard
    } else { 
2040 2c0262af bellard
        env->fpus &= (~0x4700);
2041 2c0262af bellard
        env->fpus |= 0x400;
2042 2c0262af bellard
    }
2043 2c0262af bellard
}
2044 2c0262af bellard
2045 2c0262af bellard
void helper_fptan(void)
2046 2c0262af bellard
{
2047 2c0262af bellard
    CPU86_LDouble fptemp;
2048 2c0262af bellard
2049 2c0262af bellard
    fptemp = ST0;
2050 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2051 2c0262af bellard
        env->fpus |= 0x400;
2052 2c0262af bellard
    } else {
2053 2c0262af bellard
        ST0 = tan(fptemp);
2054 2c0262af bellard
        fpush();
2055 2c0262af bellard
        ST0 = 1.0;
2056 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2057 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
2058 2c0262af bellard
    }
2059 2c0262af bellard
}
2060 2c0262af bellard
2061 2c0262af bellard
void helper_fpatan(void)
2062 2c0262af bellard
{
2063 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
2064 2c0262af bellard
2065 2c0262af bellard
    fpsrcop = ST1;
2066 2c0262af bellard
    fptemp = ST0;
2067 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
2068 2c0262af bellard
    fpop();
2069 2c0262af bellard
}
2070 2c0262af bellard
2071 2c0262af bellard
void helper_fxtract(void)
2072 2c0262af bellard
{
2073 2c0262af bellard
    CPU86_LDoubleU temp;
2074 2c0262af bellard
    unsigned int expdif;
2075 2c0262af bellard
2076 2c0262af bellard
    temp.d = ST0;
2077 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
2078 2c0262af bellard
    /*DP exponent bias*/
2079 2c0262af bellard
    ST0 = expdif;
2080 2c0262af bellard
    fpush();
2081 2c0262af bellard
    BIASEXPONENT(temp);
2082 2c0262af bellard
    ST0 = temp.d;
2083 2c0262af bellard
}
2084 2c0262af bellard
2085 2c0262af bellard
void helper_fprem1(void)
2086 2c0262af bellard
{
2087 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2088 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2089 2c0262af bellard
    int expdif;
2090 2c0262af bellard
    int q;
2091 2c0262af bellard
2092 2c0262af bellard
    fpsrcop = ST0;
2093 2c0262af bellard
    fptemp = ST1;
2094 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2095 2c0262af bellard
    fptemp1.d = fptemp;
2096 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2097 2c0262af bellard
    if (expdif < 53) {
2098 2c0262af bellard
        dblq = fpsrcop / fptemp;
2099 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2100 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2101 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2102 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2103 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2104 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2105 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2106 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2107 2c0262af bellard
    } else {
2108 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2109 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2110 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2111 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
2112 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2113 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
2114 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2115 2c0262af bellard
    }
2116 2c0262af bellard
}
2117 2c0262af bellard
2118 2c0262af bellard
void helper_fprem(void)
2119 2c0262af bellard
{
2120 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2121 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2122 2c0262af bellard
    int expdif;
2123 2c0262af bellard
    int q;
2124 2c0262af bellard
    
2125 2c0262af bellard
    fpsrcop = ST0;
2126 2c0262af bellard
    fptemp = ST1;
2127 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2128 2c0262af bellard
    fptemp1.d = fptemp;
2129 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2130 2c0262af bellard
    if ( expdif < 53 ) {
2131 2c0262af bellard
        dblq = fpsrcop / fptemp;
2132 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2133 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2134 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2135 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2136 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2137 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2138 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2139 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2140 2c0262af bellard
    } else {
2141 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2142 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2143 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2144 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
2145 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
2146 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
2147 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2148 2c0262af bellard
    }
2149 2c0262af bellard
}
2150 2c0262af bellard
2151 2c0262af bellard
void helper_fyl2xp1(void)
2152 2c0262af bellard
{
2153 2c0262af bellard
    CPU86_LDouble fptemp;
2154 2c0262af bellard
2155 2c0262af bellard
    fptemp = ST0;
2156 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
2157 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2158 2c0262af bellard
        ST1 *= fptemp;
2159 2c0262af bellard
        fpop();
2160 2c0262af bellard
    } else { 
2161 2c0262af bellard
        env->fpus &= (~0x4700);
2162 2c0262af bellard
        env->fpus |= 0x400;
2163 2c0262af bellard
    }
2164 2c0262af bellard
}
2165 2c0262af bellard
2166 2c0262af bellard
void helper_fsqrt(void)
2167 2c0262af bellard
{
2168 2c0262af bellard
    CPU86_LDouble fptemp;
2169 2c0262af bellard
2170 2c0262af bellard
    fptemp = ST0;
2171 2c0262af bellard
    if (fptemp<0.0) { 
2172 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2173 2c0262af bellard
        env->fpus |= 0x400;
2174 2c0262af bellard
    }
2175 2c0262af bellard
    ST0 = sqrt(fptemp);
2176 2c0262af bellard
}
2177 2c0262af bellard
2178 2c0262af bellard
void helper_fsincos(void)
2179 2c0262af bellard
{
2180 2c0262af bellard
    CPU86_LDouble fptemp;
2181 2c0262af bellard
2182 2c0262af bellard
    fptemp = ST0;
2183 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2184 2c0262af bellard
        env->fpus |= 0x400;
2185 2c0262af bellard
    } else {
2186 2c0262af bellard
        ST0 = sin(fptemp);
2187 2c0262af bellard
        fpush();
2188 2c0262af bellard
        ST0 = cos(fptemp);
2189 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2190 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
2191 2c0262af bellard
    }
2192 2c0262af bellard
}
2193 2c0262af bellard
2194 2c0262af bellard
void helper_frndint(void)
2195 2c0262af bellard
{
2196 2c0262af bellard
    CPU86_LDouble a;
2197 2c0262af bellard
2198 2c0262af bellard
    a = ST0;
2199 2c0262af bellard
#ifdef __arm__
2200 2c0262af bellard
    switch(env->fpuc & RC_MASK) {
2201 2c0262af bellard
    default:
2202 2c0262af bellard
    case RC_NEAR:
2203 2c0262af bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
2204 2c0262af bellard
        break;
2205 2c0262af bellard
    case RC_DOWN:
2206 2c0262af bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
2207 2c0262af bellard
        break;
2208 2c0262af bellard
    case RC_UP:
2209 2c0262af bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
2210 2c0262af bellard
        break;
2211 2c0262af bellard
    case RC_CHOP:
2212 2c0262af bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
2213 2c0262af bellard
        break;
2214 2c0262af bellard
    }
2215 2c0262af bellard
#else
2216 2c0262af bellard
    a = rint(a);
2217 2c0262af bellard
#endif
2218 2c0262af bellard
    ST0 = a;
2219 2c0262af bellard
}
2220 2c0262af bellard
2221 2c0262af bellard
void helper_fscale(void)
2222 2c0262af bellard
{
2223 2c0262af bellard
    CPU86_LDouble fpsrcop, fptemp;
2224 2c0262af bellard
2225 2c0262af bellard
    fpsrcop = 2.0;
2226 2c0262af bellard
    fptemp = pow(fpsrcop,ST1);
2227 2c0262af bellard
    ST0 *= fptemp;
2228 2c0262af bellard
}
2229 2c0262af bellard
2230 2c0262af bellard
void helper_fsin(void)
2231 2c0262af bellard
{
2232 2c0262af bellard
    CPU86_LDouble fptemp;
2233 2c0262af bellard
2234 2c0262af bellard
    fptemp = ST0;
2235 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2236 2c0262af bellard
        env->fpus |= 0x400;
2237 2c0262af bellard
    } else {
2238 2c0262af bellard
        ST0 = sin(fptemp);
2239 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2240 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
2241 2c0262af bellard
    }
2242 2c0262af bellard
}
2243 2c0262af bellard
2244 2c0262af bellard
void helper_fcos(void)
2245 2c0262af bellard
{
2246 2c0262af bellard
    CPU86_LDouble fptemp;
2247 2c0262af bellard
2248 2c0262af bellard
    fptemp = ST0;
2249 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2250 2c0262af bellard
        env->fpus |= 0x400;
2251 2c0262af bellard
    } else {
2252 2c0262af bellard
        ST0 = cos(fptemp);
2253 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2254 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
2255 2c0262af bellard
    }
2256 2c0262af bellard
}
2257 2c0262af bellard
2258 2c0262af bellard
void helper_fxam_ST0(void)
2259 2c0262af bellard
{
2260 2c0262af bellard
    CPU86_LDoubleU temp;
2261 2c0262af bellard
    int expdif;
2262 2c0262af bellard
2263 2c0262af bellard
    temp.d = ST0;
2264 2c0262af bellard
2265 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2266 2c0262af bellard
    if (SIGND(temp))
2267 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
2268 2c0262af bellard
2269 2c0262af bellard
    expdif = EXPD(temp);
2270 2c0262af bellard
    if (expdif == MAXEXPD) {
2271 2c0262af bellard
        if (MANTD(temp) == 0)
2272 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
2273 2c0262af bellard
        else
2274 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
2275 2c0262af bellard
    } else if (expdif == 0) {
2276 2c0262af bellard
        if (MANTD(temp) == 0)
2277 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
2278 2c0262af bellard
        else
2279 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
2280 2c0262af bellard
    } else {
2281 2c0262af bellard
        env->fpus |= 0x400;
2282 2c0262af bellard
    }
2283 2c0262af bellard
}
2284 2c0262af bellard
2285 2c0262af bellard
void helper_fstenv(uint8_t *ptr, int data32)
2286 2c0262af bellard
{
2287 2c0262af bellard
    int fpus, fptag, exp, i;
2288 2c0262af bellard
    uint64_t mant;
2289 2c0262af bellard
    CPU86_LDoubleU tmp;
2290 2c0262af bellard
2291 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2292 2c0262af bellard
    fptag = 0;
2293 2c0262af bellard
    for (i=7; i>=0; i--) {
2294 2c0262af bellard
        fptag <<= 2;
2295 2c0262af bellard
        if (env->fptags[i]) {
2296 2c0262af bellard
            fptag |= 3;
2297 2c0262af bellard
        } else {
2298 2c0262af bellard
            tmp.d = env->fpregs[i];
2299 2c0262af bellard
            exp = EXPD(tmp);
2300 2c0262af bellard
            mant = MANTD(tmp);
2301 2c0262af bellard
            if (exp == 0 && mant == 0) {
2302 2c0262af bellard
                /* zero */
2303 2c0262af bellard
                fptag |= 1;
2304 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
2305 2c0262af bellard
#ifdef USE_X86LDOUBLE
2306 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
2307 2c0262af bellard
#endif
2308 2c0262af bellard
                       ) {
2309 2c0262af bellard
                /* NaNs, infinity, denormal */
2310 2c0262af bellard
                fptag |= 2;
2311 2c0262af bellard
            }
2312 2c0262af bellard
        }
2313 2c0262af bellard
    }
2314 2c0262af bellard
    if (data32) {
2315 2c0262af bellard
        /* 32 bit */
2316 2c0262af bellard
        stl(ptr, env->fpuc);
2317 2c0262af bellard
        stl(ptr + 4, fpus);
2318 2c0262af bellard
        stl(ptr + 8, fptag);
2319 2c0262af bellard
        stl(ptr + 12, 0);
2320 2c0262af bellard
        stl(ptr + 16, 0);
2321 2c0262af bellard
        stl(ptr + 20, 0);
2322 2c0262af bellard
        stl(ptr + 24, 0);
2323 2c0262af bellard
    } else {
2324 2c0262af bellard
        /* 16 bit */
2325 2c0262af bellard
        stw(ptr, env->fpuc);
2326 2c0262af bellard
        stw(ptr + 2, fpus);
2327 2c0262af bellard
        stw(ptr + 4, fptag);
2328 2c0262af bellard
        stw(ptr + 6, 0);
2329 2c0262af bellard
        stw(ptr + 8, 0);
2330 2c0262af bellard
        stw(ptr + 10, 0);
2331 2c0262af bellard
        stw(ptr + 12, 0);
2332 2c0262af bellard
    }
2333 2c0262af bellard
}
2334 2c0262af bellard
2335 2c0262af bellard
void helper_fldenv(uint8_t *ptr, int data32)
2336 2c0262af bellard
{
2337 2c0262af bellard
    int i, fpus, fptag;
2338 2c0262af bellard
2339 2c0262af bellard
    if (data32) {
2340 2c0262af bellard
        env->fpuc = lduw(ptr);
2341 2c0262af bellard
        fpus = lduw(ptr + 4);
2342 2c0262af bellard
        fptag = lduw(ptr + 8);
2343 2c0262af bellard
    }
2344 2c0262af bellard
    else {
2345 2c0262af bellard
        env->fpuc = lduw(ptr);
2346 2c0262af bellard
        fpus = lduw(ptr + 2);
2347 2c0262af bellard
        fptag = lduw(ptr + 4);
2348 2c0262af bellard
    }
2349 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
2350 2c0262af bellard
    env->fpus = fpus & ~0x3800;
2351 2c0262af bellard
    for(i = 0;i < 7; i++) {
2352 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
2353 2c0262af bellard
        fptag >>= 2;
2354 2c0262af bellard
    }
2355 2c0262af bellard
}
2356 2c0262af bellard
2357 2c0262af bellard
void helper_fsave(uint8_t *ptr, int data32)
2358 2c0262af bellard
{
2359 2c0262af bellard
    CPU86_LDouble tmp;
2360 2c0262af bellard
    int i;
2361 2c0262af bellard
2362 2c0262af bellard
    helper_fstenv(ptr, data32);
2363 2c0262af bellard
2364 2c0262af bellard
    ptr += (14 << data32);
2365 2c0262af bellard
    for(i = 0;i < 8; i++) {
2366 2c0262af bellard
        tmp = ST(i);
2367 2c0262af bellard
        helper_fstt(tmp, ptr);
2368 2c0262af bellard
        ptr += 10;
2369 2c0262af bellard
    }
2370 2c0262af bellard
2371 2c0262af bellard
    /* fninit */
2372 2c0262af bellard
    env->fpus = 0;
2373 2c0262af bellard
    env->fpstt = 0;
2374 2c0262af bellard
    env->fpuc = 0x37f;
2375 2c0262af bellard
    env->fptags[0] = 1;
2376 2c0262af bellard
    env->fptags[1] = 1;
2377 2c0262af bellard
    env->fptags[2] = 1;
2378 2c0262af bellard
    env->fptags[3] = 1;
2379 2c0262af bellard
    env->fptags[4] = 1;
2380 2c0262af bellard
    env->fptags[5] = 1;
2381 2c0262af bellard
    env->fptags[6] = 1;
2382 2c0262af bellard
    env->fptags[7] = 1;
2383 2c0262af bellard
}
2384 2c0262af bellard
2385 2c0262af bellard
void helper_frstor(uint8_t *ptr, int data32)
2386 2c0262af bellard
{
2387 2c0262af bellard
    CPU86_LDouble tmp;
2388 2c0262af bellard
    int i;
2389 2c0262af bellard
2390 2c0262af bellard
    helper_fldenv(ptr, data32);
2391 2c0262af bellard
    ptr += (14 << data32);
2392 2c0262af bellard
2393 2c0262af bellard
    for(i = 0;i < 8; i++) {
2394 2c0262af bellard
        tmp = helper_fldt(ptr);
2395 2c0262af bellard
        ST(i) = tmp;
2396 2c0262af bellard
        ptr += 10;
2397 2c0262af bellard
    }
2398 2c0262af bellard
}
2399 2c0262af bellard
2400 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
2401 61382a50 bellard
2402 61382a50 bellard
#define MMUSUFFIX _mmu
2403 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
2404 61382a50 bellard
2405 2c0262af bellard
#define SHIFT 0
2406 2c0262af bellard
#include "softmmu_template.h"
2407 2c0262af bellard
2408 2c0262af bellard
#define SHIFT 1
2409 2c0262af bellard
#include "softmmu_template.h"
2410 2c0262af bellard
2411 2c0262af bellard
#define SHIFT 2
2412 2c0262af bellard
#include "softmmu_template.h"
2413 2c0262af bellard
2414 2c0262af bellard
#define SHIFT 3
2415 2c0262af bellard
#include "softmmu_template.h"
2416 2c0262af bellard
2417 61382a50 bellard
#endif
2418 61382a50 bellard
2419 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
2420 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
2421 61382a50 bellard
   from generated code or from helper.c) */
2422 61382a50 bellard
/* XXX: fix it to restore all registers */
2423 61382a50 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2424 2c0262af bellard
{
2425 2c0262af bellard
    TranslationBlock *tb;
2426 2c0262af bellard
    int ret;
2427 2c0262af bellard
    unsigned long pc;
2428 61382a50 bellard
    CPUX86State *saved_env;
2429 61382a50 bellard
2430 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
2431 61382a50 bellard
       generated code */
2432 61382a50 bellard
    saved_env = env;
2433 61382a50 bellard
    env = cpu_single_env;
2434 61382a50 bellard
    if (is_write && page_unprotect(addr)) {
2435 61382a50 bellard
        /* nothing more to do: the page was write protected because
2436 61382a50 bellard
           there was code in it. page_unprotect() flushed the code. */
2437 61382a50 bellard
    }
2438 61382a50 bellard
2439 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
2440 2c0262af bellard
    if (ret) {
2441 61382a50 bellard
        if (retaddr) {
2442 61382a50 bellard
            /* now we have a real cpu fault */
2443 61382a50 bellard
            pc = (unsigned long)retaddr;
2444 61382a50 bellard
            tb = tb_find_pc(pc);
2445 61382a50 bellard
            if (tb) {
2446 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
2447 61382a50 bellard
                   a virtual CPU fault */
2448 61382a50 bellard
                cpu_restore_state(tb, env, pc);
2449 61382a50 bellard
            }
2450 2c0262af bellard
        }
2451 2c0262af bellard
        raise_exception_err(EXCP0E_PAGE, env->error_code);
2452 2c0262af bellard
    }
2453 61382a50 bellard
    env = saved_env;
2454 2c0262af bellard
}