Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 4136f33c

History | View | Annotate | Download (67.2 kB)

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