Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 891b38e4

History | View | Annotate | Download (66.9 kB)

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