Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 9951bf39

History | View | Annotate | Download (48.8 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 2c0262af bellard
const uint8_t parity_table[256] = {
23 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
24 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
25 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
26 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
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
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
30 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
31 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
32 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
33 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
34 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
35 2c0262af bellard
    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
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
38 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
39 2c0262af bellard
    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
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
42 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
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
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
48 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
51 2c0262af bellard
    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
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
55 2c0262af bellard
};
56 2c0262af bellard
57 2c0262af bellard
/* modulo 17 table */
58 2c0262af bellard
const uint8_t rclw_table[32] = {
59 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
60 2c0262af bellard
    8, 9,10,11,12,13,14,15,
61 2c0262af bellard
   16, 0, 1, 2, 3, 4, 5, 6,
62 2c0262af bellard
    7, 8, 9,10,11,12,13,14,
63 2c0262af bellard
};
64 2c0262af bellard
65 2c0262af bellard
/* modulo 9 table */
66 2c0262af bellard
const uint8_t rclb_table[32] = {
67 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
68 2c0262af bellard
    8, 0, 1, 2, 3, 4, 5, 6,
69 2c0262af bellard
    7, 8, 0, 1, 2, 3, 4, 5, 
70 2c0262af bellard
    6, 7, 8, 0, 1, 2, 3, 4,
71 2c0262af bellard
};
72 2c0262af bellard
73 2c0262af bellard
const CPU86_LDouble f15rk[7] =
74 2c0262af bellard
{
75 2c0262af bellard
    0.00000000000000000000L,
76 2c0262af bellard
    1.00000000000000000000L,
77 2c0262af bellard
    3.14159265358979323851L,  /*pi*/
78 2c0262af bellard
    0.30102999566398119523L,  /*lg2*/
79 2c0262af bellard
    0.69314718055994530943L,  /*ln2*/
80 2c0262af bellard
    1.44269504088896340739L,  /*l2e*/
81 2c0262af bellard
    3.32192809488736234781L,  /*l2t*/
82 2c0262af bellard
};
83 2c0262af bellard
    
84 2c0262af bellard
/* thread support */
85 2c0262af bellard
86 2c0262af bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
87 2c0262af bellard
88 2c0262af bellard
void cpu_lock(void)
89 2c0262af bellard
{
90 2c0262af bellard
    spin_lock(&global_cpu_lock);
91 2c0262af bellard
}
92 2c0262af bellard
93 2c0262af bellard
void cpu_unlock(void)
94 2c0262af bellard
{
95 2c0262af bellard
    spin_unlock(&global_cpu_lock);
96 2c0262af bellard
}
97 2c0262af bellard
98 2c0262af bellard
void cpu_loop_exit(void)
99 2c0262af bellard
{
100 2c0262af bellard
    /* NOTE: the register at this point must be saved by hand because
101 2c0262af bellard
       longjmp restore them */
102 2c0262af bellard
#ifdef reg_EAX
103 2c0262af bellard
    env->regs[R_EAX] = EAX;
104 2c0262af bellard
#endif
105 2c0262af bellard
#ifdef reg_ECX
106 2c0262af bellard
    env->regs[R_ECX] = ECX;
107 2c0262af bellard
#endif
108 2c0262af bellard
#ifdef reg_EDX
109 2c0262af bellard
    env->regs[R_EDX] = EDX;
110 2c0262af bellard
#endif
111 2c0262af bellard
#ifdef reg_EBX
112 2c0262af bellard
    env->regs[R_EBX] = EBX;
113 2c0262af bellard
#endif
114 2c0262af bellard
#ifdef reg_ESP
115 2c0262af bellard
    env->regs[R_ESP] = ESP;
116 2c0262af bellard
#endif
117 2c0262af bellard
#ifdef reg_EBP
118 2c0262af bellard
    env->regs[R_EBP] = EBP;
119 2c0262af bellard
#endif
120 2c0262af bellard
#ifdef reg_ESI
121 2c0262af bellard
    env->regs[R_ESI] = ESI;
122 2c0262af bellard
#endif
123 2c0262af bellard
#ifdef reg_EDI
124 2c0262af bellard
    env->regs[R_EDI] = EDI;
125 2c0262af bellard
#endif
126 2c0262af bellard
    longjmp(env->jmp_env, 1);
127 2c0262af bellard
}
128 2c0262af bellard
129 2c0262af bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
130 2c0262af bellard
                                       uint32_t *esp_ptr, int dpl)
131 2c0262af bellard
{
132 2c0262af bellard
    int type, index, shift;
133 2c0262af bellard
    
134 2c0262af bellard
#if 0
135 2c0262af bellard
    {
136 2c0262af bellard
        int i;
137 2c0262af bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
138 2c0262af bellard
        for(i=0;i<env->tr.limit;i++) {
139 2c0262af bellard
            printf("%02x ", env->tr.base[i]);
140 2c0262af bellard
            if ((i & 7) == 7) printf("\n");
141 2c0262af bellard
        }
142 2c0262af bellard
        printf("\n");
143 2c0262af bellard
    }
144 2c0262af bellard
#endif
145 2c0262af bellard
146 2c0262af bellard
    if (!(env->tr.flags & DESC_P_MASK))
147 2c0262af bellard
        cpu_abort(env, "invalid tss");
148 2c0262af bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
149 2c0262af bellard
    if ((type & 7) != 1)
150 2c0262af bellard
        cpu_abort(env, "invalid tss type");
151 2c0262af bellard
    shift = type >> 3;
152 2c0262af bellard
    index = (dpl * 4 + 2) << shift;
153 2c0262af bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
154 2c0262af bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
155 2c0262af bellard
    if (shift == 0) {
156 61382a50 bellard
        *esp_ptr = lduw_kernel(env->tr.base + index);
157 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
158 2c0262af bellard
    } else {
159 61382a50 bellard
        *esp_ptr = ldl_kernel(env->tr.base + index);
160 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
161 2c0262af bellard
    }
162 2c0262af bellard
}
163 2c0262af bellard
164 2c0262af bellard
/* return non zero if error */
165 2c0262af bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
166 2c0262af bellard
                               int selector)
167 2c0262af bellard
{
168 2c0262af bellard
    SegmentCache *dt;
169 2c0262af bellard
    int index;
170 2c0262af bellard
    uint8_t *ptr;
171 2c0262af bellard
172 2c0262af bellard
    if (selector & 0x4)
173 2c0262af bellard
        dt = &env->ldt;
174 2c0262af bellard
    else
175 2c0262af bellard
        dt = &env->gdt;
176 2c0262af bellard
    index = selector & ~7;
177 2c0262af bellard
    if ((index + 7) > dt->limit)
178 2c0262af bellard
        return -1;
179 2c0262af bellard
    ptr = dt->base + index;
180 61382a50 bellard
    *e1_ptr = ldl_kernel(ptr);
181 61382a50 bellard
    *e2_ptr = ldl_kernel(ptr + 4);
182 2c0262af bellard
    return 0;
183 2c0262af bellard
}
184 2c0262af bellard
                                     
185 2c0262af bellard
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
186 2c0262af bellard
{
187 2c0262af bellard
    unsigned int limit;
188 2c0262af bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
189 2c0262af bellard
    if (e2 & DESC_G_MASK)
190 2c0262af bellard
        limit = (limit << 12) | 0xfff;
191 2c0262af bellard
    return limit;
192 2c0262af bellard
}
193 2c0262af bellard
194 2c0262af bellard
static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
195 2c0262af bellard
{
196 2c0262af bellard
    return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
197 2c0262af bellard
}
198 2c0262af bellard
199 2c0262af bellard
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
200 2c0262af bellard
{
201 2c0262af bellard
    sc->base = get_seg_base(e1, e2);
202 2c0262af bellard
    sc->limit = get_seg_limit(e1, e2);
203 2c0262af bellard
    sc->flags = e2;
204 2c0262af bellard
}
205 2c0262af bellard
206 2c0262af bellard
/* init the segment cache in vm86 mode. */
207 2c0262af bellard
static inline void load_seg_vm(int seg, int selector)
208 2c0262af bellard
{
209 2c0262af bellard
    selector &= 0xffff;
210 2c0262af bellard
    cpu_x86_load_seg_cache(env, seg, selector, 
211 2c0262af bellard
                           (uint8_t *)(selector << 4), 0xffff, 0);
212 2c0262af bellard
}
213 2c0262af bellard
214 2c0262af bellard
/* protected mode interrupt */
215 2c0262af bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
216 2c0262af bellard
                                   unsigned int next_eip, int is_hw)
217 2c0262af bellard
{
218 2c0262af bellard
    SegmentCache *dt;
219 2c0262af bellard
    uint8_t *ptr, *ssp;
220 2c0262af bellard
    int type, dpl, selector, ss_dpl, cpl;
221 2c0262af bellard
    int has_error_code, new_stack, shift;
222 2c0262af bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
223 2c0262af bellard
    uint32_t old_cs, old_ss, old_esp, old_eip;
224 2c0262af bellard
225 2c0262af bellard
    dt = &env->idt;
226 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
227 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
228 2c0262af bellard
    ptr = dt->base + intno * 8;
229 61382a50 bellard
    e1 = ldl_kernel(ptr);
230 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
231 2c0262af bellard
    /* check gate type */
232 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
233 2c0262af bellard
    switch(type) {
234 2c0262af bellard
    case 5: /* task gate */
235 2c0262af bellard
        cpu_abort(env, "task gate not supported");
236 2c0262af bellard
        break;
237 2c0262af bellard
    case 6: /* 286 interrupt gate */
238 2c0262af bellard
    case 7: /* 286 trap gate */
239 2c0262af bellard
    case 14: /* 386 interrupt gate */
240 2c0262af bellard
    case 15: /* 386 trap gate */
241 2c0262af bellard
        break;
242 2c0262af bellard
    default:
243 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
244 2c0262af bellard
        break;
245 2c0262af bellard
    }
246 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
247 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
248 2c0262af bellard
    /* check privledge if software int */
249 2c0262af bellard
    if (is_int && dpl < cpl)
250 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
251 2c0262af bellard
    /* check valid bit */
252 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
253 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
254 2c0262af bellard
    selector = e1 >> 16;
255 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
256 2c0262af bellard
    if ((selector & 0xfffc) == 0)
257 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
258 2c0262af bellard
259 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
260 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
261 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
262 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
263 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
264 2c0262af bellard
    if (dpl > cpl)
265 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
266 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
267 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
268 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
269 2c0262af bellard
        /* to inner priviledge */
270 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
271 2c0262af bellard
        if ((ss & 0xfffc) == 0)
272 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
273 2c0262af bellard
        if ((ss & 3) != dpl)
274 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
275 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
276 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
277 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
278 2c0262af bellard
        if (ss_dpl != dpl)
279 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
280 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
281 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
282 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
283 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
284 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
285 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
286 2c0262af bellard
        new_stack = 1;
287 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
288 2c0262af bellard
        /* to same priviledge */
289 2c0262af bellard
        new_stack = 0;
290 2c0262af bellard
    } else {
291 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
292 2c0262af bellard
        new_stack = 0; /* avoid warning */
293 2c0262af bellard
    }
294 2c0262af bellard
295 2c0262af bellard
    shift = type >> 3;
296 2c0262af bellard
    has_error_code = 0;
297 2c0262af bellard
    if (!is_int && !is_hw) {
298 2c0262af bellard
        switch(intno) {
299 2c0262af bellard
        case 8:
300 2c0262af bellard
        case 10:
301 2c0262af bellard
        case 11:
302 2c0262af bellard
        case 12:
303 2c0262af bellard
        case 13:
304 2c0262af bellard
        case 14:
305 2c0262af bellard
        case 17:
306 2c0262af bellard
            has_error_code = 1;
307 2c0262af bellard
            break;
308 2c0262af bellard
        }
309 2c0262af bellard
    }
310 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
311 2c0262af bellard
    if (env->eflags & VM_MASK)
312 2c0262af bellard
        push_size += 8;
313 2c0262af bellard
    push_size <<= shift;
314 2c0262af bellard
315 2c0262af bellard
    /* XXX: check that enough room is available */
316 2c0262af bellard
    if (new_stack) {
317 2c0262af bellard
        old_esp = ESP;
318 2c0262af bellard
        old_ss = env->segs[R_SS].selector;
319 2c0262af bellard
        ss = (ss & ~3) | dpl;
320 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
321 2c0262af bellard
                       get_seg_base(ss_e1, ss_e2),
322 2c0262af bellard
                       get_seg_limit(ss_e1, ss_e2),
323 2c0262af bellard
                       ss_e2);
324 2c0262af bellard
    } else {
325 2c0262af bellard
        old_esp = 0;
326 2c0262af bellard
        old_ss = 0;
327 2c0262af bellard
        esp = ESP;
328 2c0262af bellard
    }
329 2c0262af bellard
    if (is_int)
330 2c0262af bellard
        old_eip = next_eip;
331 2c0262af bellard
    else
332 2c0262af bellard
        old_eip = env->eip;
333 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
334 2c0262af bellard
    selector = (selector & ~3) | dpl;
335 2c0262af bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
336 2c0262af bellard
                   get_seg_base(e1, e2),
337 2c0262af bellard
                   get_seg_limit(e1, e2),
338 2c0262af bellard
                   e2);
339 2c0262af bellard
    cpu_x86_set_cpl(env, dpl);
340 2c0262af bellard
    env->eip = offset;
341 2c0262af bellard
    ESP = esp - push_size;
342 2c0262af bellard
    ssp = env->segs[R_SS].base + esp;
343 2c0262af bellard
    if (shift == 1) {
344 2c0262af bellard
        int old_eflags;
345 2c0262af bellard
        if (env->eflags & VM_MASK) {
346 2c0262af bellard
            ssp -= 4;
347 61382a50 bellard
            stl_kernel(ssp, env->segs[R_GS].selector);
348 2c0262af bellard
            ssp -= 4;
349 61382a50 bellard
            stl_kernel(ssp, env->segs[R_FS].selector);
350 2c0262af bellard
            ssp -= 4;
351 61382a50 bellard
            stl_kernel(ssp, env->segs[R_DS].selector);
352 2c0262af bellard
            ssp -= 4;
353 61382a50 bellard
            stl_kernel(ssp, env->segs[R_ES].selector);
354 2c0262af bellard
        }
355 2c0262af bellard
        if (new_stack) {
356 2c0262af bellard
            ssp -= 4;
357 61382a50 bellard
            stl_kernel(ssp, old_ss);
358 2c0262af bellard
            ssp -= 4;
359 61382a50 bellard
            stl_kernel(ssp, old_esp);
360 2c0262af bellard
        }
361 2c0262af bellard
        ssp -= 4;
362 2c0262af bellard
        old_eflags = compute_eflags();
363 61382a50 bellard
        stl_kernel(ssp, old_eflags);
364 2c0262af bellard
        ssp -= 4;
365 61382a50 bellard
        stl_kernel(ssp, old_cs);
366 2c0262af bellard
        ssp -= 4;
367 61382a50 bellard
        stl_kernel(ssp, old_eip);
368 2c0262af bellard
        if (has_error_code) {
369 2c0262af bellard
            ssp -= 4;
370 61382a50 bellard
            stl_kernel(ssp, error_code);
371 2c0262af bellard
        }
372 2c0262af bellard
    } else {
373 2c0262af bellard
        if (new_stack) {
374 2c0262af bellard
            ssp -= 2;
375 61382a50 bellard
            stw_kernel(ssp, old_ss);
376 2c0262af bellard
            ssp -= 2;
377 61382a50 bellard
            stw_kernel(ssp, old_esp);
378 2c0262af bellard
        }
379 2c0262af bellard
        ssp -= 2;
380 61382a50 bellard
        stw_kernel(ssp, compute_eflags());
381 2c0262af bellard
        ssp -= 2;
382 61382a50 bellard
        stw_kernel(ssp, old_cs);
383 2c0262af bellard
        ssp -= 2;
384 61382a50 bellard
        stw_kernel(ssp, old_eip);
385 2c0262af bellard
        if (has_error_code) {
386 2c0262af bellard
            ssp -= 2;
387 61382a50 bellard
            stw_kernel(ssp, error_code);
388 2c0262af bellard
        }
389 2c0262af bellard
    }
390 2c0262af bellard
    
391 2c0262af bellard
    /* interrupt gate clear IF mask */
392 2c0262af bellard
    if ((type & 1) == 0) {
393 2c0262af bellard
        env->eflags &= ~IF_MASK;
394 2c0262af bellard
    }
395 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
396 2c0262af bellard
}
397 2c0262af bellard
398 2c0262af bellard
/* real mode interrupt */
399 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
400 2c0262af bellard
                                 unsigned int next_eip)
401 2c0262af bellard
{
402 2c0262af bellard
    SegmentCache *dt;
403 2c0262af bellard
    uint8_t *ptr, *ssp;
404 2c0262af bellard
    int selector;
405 2c0262af bellard
    uint32_t offset, esp;
406 2c0262af bellard
    uint32_t old_cs, old_eip;
407 2c0262af bellard
408 2c0262af bellard
    /* real mode (simpler !) */
409 2c0262af bellard
    dt = &env->idt;
410 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
411 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
412 2c0262af bellard
    ptr = dt->base + intno * 4;
413 61382a50 bellard
    offset = lduw_kernel(ptr);
414 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
415 2c0262af bellard
    esp = ESP;
416 2c0262af bellard
    ssp = env->segs[R_SS].base;
417 2c0262af bellard
    if (is_int)
418 2c0262af bellard
        old_eip = next_eip;
419 2c0262af bellard
    else
420 2c0262af bellard
        old_eip = env->eip;
421 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
422 2c0262af bellard
    esp -= 2;
423 61382a50 bellard
    stw_kernel(ssp + (esp & 0xffff), compute_eflags());
424 2c0262af bellard
    esp -= 2;
425 61382a50 bellard
    stw_kernel(ssp + (esp & 0xffff), old_cs);
426 2c0262af bellard
    esp -= 2;
427 61382a50 bellard
    stw_kernel(ssp + (esp & 0xffff), old_eip);
428 2c0262af bellard
    
429 2c0262af bellard
    /* update processor state */
430 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
431 2c0262af bellard
    env->eip = offset;
432 2c0262af bellard
    env->segs[R_CS].selector = selector;
433 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(selector << 4);
434 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
435 2c0262af bellard
}
436 2c0262af bellard
437 2c0262af bellard
/* fake user mode interrupt */
438 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
439 2c0262af bellard
                       unsigned int next_eip)
440 2c0262af bellard
{
441 2c0262af bellard
    SegmentCache *dt;
442 2c0262af bellard
    uint8_t *ptr;
443 2c0262af bellard
    int dpl, cpl;
444 2c0262af bellard
    uint32_t e2;
445 2c0262af bellard
446 2c0262af bellard
    dt = &env->idt;
447 2c0262af bellard
    ptr = dt->base + (intno * 8);
448 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
449 2c0262af bellard
    
450 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
451 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
452 2c0262af bellard
    /* check privledge if software int */
453 2c0262af bellard
    if (is_int && dpl < cpl)
454 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
455 2c0262af bellard
456 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
457 2c0262af bellard
       exiting the emulation with the suitable exception and error
458 2c0262af bellard
       code */
459 2c0262af bellard
    if (is_int)
460 2c0262af bellard
        EIP = next_eip;
461 2c0262af bellard
}
462 2c0262af bellard
463 2c0262af bellard
/*
464 2c0262af bellard
 * Begin excution of an interruption. is_int is TRUE if coming from
465 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
466 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
467 2c0262af bellard
 */
468 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
469 2c0262af bellard
                  unsigned int next_eip, int is_hw)
470 2c0262af bellard
{
471 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
472 2c0262af bellard
        do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
473 2c0262af bellard
    } else {
474 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
475 2c0262af bellard
    }
476 2c0262af bellard
}
477 2c0262af bellard
478 2c0262af bellard
/*
479 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
480 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
481 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
482 2c0262af bellard
 * is_int is TRUE.  
483 2c0262af bellard
 */
484 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
485 2c0262af bellard
                     unsigned int next_eip)
486 2c0262af bellard
{
487 2c0262af bellard
    env->exception_index = intno;
488 2c0262af bellard
    env->error_code = error_code;
489 2c0262af bellard
    env->exception_is_int = is_int;
490 2c0262af bellard
    env->exception_next_eip = next_eip;
491 2c0262af bellard
    cpu_loop_exit();
492 2c0262af bellard
}
493 2c0262af bellard
494 2c0262af bellard
/* shortcuts to generate exceptions */
495 2c0262af bellard
void raise_exception_err(int exception_index, int error_code)
496 2c0262af bellard
{
497 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
498 2c0262af bellard
}
499 2c0262af bellard
500 2c0262af bellard
void raise_exception(int exception_index)
501 2c0262af bellard
{
502 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
503 2c0262af bellard
}
504 2c0262af bellard
505 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
506 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
507 2c0262af bellard
   call it from another function */
508 2c0262af bellard
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
509 2c0262af bellard
{
510 2c0262af bellard
    *q_ptr = num / den;
511 2c0262af bellard
    return num % den;
512 2c0262af bellard
}
513 2c0262af bellard
514 2c0262af bellard
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
515 2c0262af bellard
{
516 2c0262af bellard
    *q_ptr = num / den;
517 2c0262af bellard
    return num % den;
518 2c0262af bellard
}
519 2c0262af bellard
#endif
520 2c0262af bellard
521 2c0262af bellard
void helper_divl_EAX_T0(uint32_t eip)
522 2c0262af bellard
{
523 2c0262af bellard
    unsigned int den, q, r;
524 2c0262af bellard
    uint64_t num;
525 2c0262af bellard
    
526 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
527 2c0262af bellard
    den = T0;
528 2c0262af bellard
    if (den == 0) {
529 2c0262af bellard
        EIP = eip;
530 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
531 2c0262af bellard
    }
532 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
533 2c0262af bellard
    r = div64(&q, num, den);
534 2c0262af bellard
#else
535 2c0262af bellard
    q = (num / den);
536 2c0262af bellard
    r = (num % den);
537 2c0262af bellard
#endif
538 2c0262af bellard
    EAX = q;
539 2c0262af bellard
    EDX = r;
540 2c0262af bellard
}
541 2c0262af bellard
542 2c0262af bellard
void helper_idivl_EAX_T0(uint32_t eip)
543 2c0262af bellard
{
544 2c0262af bellard
    int den, q, r;
545 2c0262af bellard
    int64_t num;
546 2c0262af bellard
    
547 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
548 2c0262af bellard
    den = T0;
549 2c0262af bellard
    if (den == 0) {
550 2c0262af bellard
        EIP = eip;
551 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
552 2c0262af bellard
    }
553 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
554 2c0262af bellard
    r = idiv64(&q, num, den);
555 2c0262af bellard
#else
556 2c0262af bellard
    q = (num / den);
557 2c0262af bellard
    r = (num % den);
558 2c0262af bellard
#endif
559 2c0262af bellard
    EAX = q;
560 2c0262af bellard
    EDX = r;
561 2c0262af bellard
}
562 2c0262af bellard
563 2c0262af bellard
void helper_cmpxchg8b(void)
564 2c0262af bellard
{
565 2c0262af bellard
    uint64_t d;
566 2c0262af bellard
    int eflags;
567 2c0262af bellard
568 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
569 2c0262af bellard
    d = ldq((uint8_t *)A0);
570 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
571 2c0262af bellard
        stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
572 2c0262af bellard
        eflags |= CC_Z;
573 2c0262af bellard
    } else {
574 2c0262af bellard
        EDX = d >> 32;
575 2c0262af bellard
        EAX = d;
576 2c0262af bellard
        eflags &= ~CC_Z;
577 2c0262af bellard
    }
578 2c0262af bellard
    CC_SRC = eflags;
579 2c0262af bellard
}
580 2c0262af bellard
581 2c0262af bellard
/* We simulate a pre-MMX pentium as in valgrind */
582 2c0262af bellard
#define CPUID_FP87 (1 << 0)
583 2c0262af bellard
#define CPUID_VME  (1 << 1)
584 2c0262af bellard
#define CPUID_DE   (1 << 2)
585 2c0262af bellard
#define CPUID_PSE  (1 << 3)
586 2c0262af bellard
#define CPUID_TSC  (1 << 4)
587 2c0262af bellard
#define CPUID_MSR  (1 << 5)
588 2c0262af bellard
#define CPUID_PAE  (1 << 6)
589 2c0262af bellard
#define CPUID_MCE  (1 << 7)
590 2c0262af bellard
#define CPUID_CX8  (1 << 8)
591 2c0262af bellard
#define CPUID_APIC (1 << 9)
592 2c0262af bellard
#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
593 2c0262af bellard
#define CPUID_MTRR (1 << 12)
594 2c0262af bellard
#define CPUID_PGE  (1 << 13)
595 2c0262af bellard
#define CPUID_MCA  (1 << 14)
596 2c0262af bellard
#define CPUID_CMOV (1 << 15)
597 2c0262af bellard
/* ... */
598 2c0262af bellard
#define CPUID_MMX  (1 << 23)
599 2c0262af bellard
#define CPUID_FXSR (1 << 24)
600 2c0262af bellard
#define CPUID_SSE  (1 << 25)
601 2c0262af bellard
#define CPUID_SSE2 (1 << 26)
602 2c0262af bellard
603 2c0262af bellard
void helper_cpuid(void)
604 2c0262af bellard
{
605 2c0262af bellard
    if (EAX == 0) {
606 2c0262af bellard
        EAX = 1; /* max EAX index supported */
607 2c0262af bellard
        EBX = 0x756e6547;
608 2c0262af bellard
        ECX = 0x6c65746e;
609 2c0262af bellard
        EDX = 0x49656e69;
610 2c0262af bellard
    } else if (EAX == 1) {
611 2c0262af bellard
        int family, model, stepping;
612 2c0262af bellard
        /* EAX = 1 info */
613 2c0262af bellard
#if 0
614 2c0262af bellard
        /* pentium 75-200 */
615 2c0262af bellard
        family = 5;
616 2c0262af bellard
        model = 2;
617 2c0262af bellard
        stepping = 11;
618 2c0262af bellard
#else
619 2c0262af bellard
        /* pentium pro */
620 2c0262af bellard
        family = 6;
621 2c0262af bellard
        model = 1;
622 2c0262af bellard
        stepping = 3;
623 2c0262af bellard
#endif
624 2c0262af bellard
        EAX = (family << 8) | (model << 4) | stepping;
625 2c0262af bellard
        EBX = 0;
626 2c0262af bellard
        ECX = 0;
627 2c0262af bellard
        EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
628 2c0262af bellard
            CPUID_TSC | CPUID_MSR | CPUID_MCE |
629 2c0262af bellard
            CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
630 2c0262af bellard
    }
631 2c0262af bellard
}
632 2c0262af bellard
633 2c0262af bellard
void helper_lldt_T0(void)
634 2c0262af bellard
{
635 2c0262af bellard
    int selector;
636 2c0262af bellard
    SegmentCache *dt;
637 2c0262af bellard
    uint32_t e1, e2;
638 2c0262af bellard
    int index;
639 2c0262af bellard
    uint8_t *ptr;
640 2c0262af bellard
    
641 2c0262af bellard
    selector = T0 & 0xffff;
642 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
643 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
644 2c0262af bellard
        env->ldt.base = NULL;
645 2c0262af bellard
        env->ldt.limit = 0;
646 2c0262af bellard
    } else {
647 2c0262af bellard
        if (selector & 0x4)
648 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
649 2c0262af bellard
        dt = &env->gdt;
650 2c0262af bellard
        index = selector & ~7;
651 2c0262af bellard
        if ((index + 7) > dt->limit)
652 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
653 2c0262af bellard
        ptr = dt->base + index;
654 61382a50 bellard
        e1 = ldl_kernel(ptr);
655 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
656 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
657 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
658 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
659 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
660 2c0262af bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
661 2c0262af bellard
    }
662 2c0262af bellard
    env->ldt.selector = selector;
663 2c0262af bellard
}
664 2c0262af bellard
665 2c0262af bellard
void helper_ltr_T0(void)
666 2c0262af bellard
{
667 2c0262af bellard
    int selector;
668 2c0262af bellard
    SegmentCache *dt;
669 2c0262af bellard
    uint32_t e1, e2;
670 2c0262af bellard
    int index, type;
671 2c0262af bellard
    uint8_t *ptr;
672 2c0262af bellard
    
673 2c0262af bellard
    selector = T0 & 0xffff;
674 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
675 2c0262af bellard
        /* NULL selector case: invalid LDT */
676 2c0262af bellard
        env->tr.base = NULL;
677 2c0262af bellard
        env->tr.limit = 0;
678 2c0262af bellard
        env->tr.flags = 0;
679 2c0262af bellard
    } else {
680 2c0262af bellard
        if (selector & 0x4)
681 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
682 2c0262af bellard
        dt = &env->gdt;
683 2c0262af bellard
        index = selector & ~7;
684 2c0262af bellard
        if ((index + 7) > dt->limit)
685 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
686 2c0262af bellard
        ptr = dt->base + index;
687 61382a50 bellard
        e1 = ldl_kernel(ptr);
688 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
689 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
690 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
691 2c0262af bellard
            (type != 2 && type != 9))
692 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
693 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
694 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
695 2c0262af bellard
        load_seg_cache_raw_dt(&env->tr, e1, e2);
696 2c0262af bellard
        e2 |= 0x00000200; /* set the busy bit */
697 61382a50 bellard
        stl_kernel(ptr + 4, e2);
698 2c0262af bellard
    }
699 2c0262af bellard
    env->tr.selector = selector;
700 2c0262af bellard
}
701 2c0262af bellard
702 2c0262af bellard
/* only works if protected mode and not VM86. Calling load_seg with
703 2c0262af bellard
   seg_reg == R_CS is discouraged */
704 2c0262af bellard
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
705 2c0262af bellard
{
706 2c0262af bellard
    uint32_t e1, e2;
707 2c0262af bellard
    
708 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
709 2c0262af bellard
        /* null selector case */
710 2c0262af bellard
        if (seg_reg == R_SS) {
711 2c0262af bellard
            EIP = cur_eip;
712 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
713 2c0262af bellard
        } else {
714 2c0262af bellard
            cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
715 2c0262af bellard
        }
716 2c0262af bellard
    } else {
717 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0) {
718 2c0262af bellard
            EIP = cur_eip;
719 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
720 2c0262af bellard
        }
721 2c0262af bellard
        if (!(e2 & DESC_S_MASK) ||
722 2c0262af bellard
            (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
723 2c0262af bellard
            EIP = cur_eip;
724 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
725 2c0262af bellard
        }
726 2c0262af bellard
727 2c0262af bellard
        if (seg_reg == R_SS) {
728 2c0262af bellard
            if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
729 2c0262af bellard
                EIP = cur_eip;
730 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
731 2c0262af bellard
            }
732 2c0262af bellard
        } else {
733 2c0262af bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
734 2c0262af bellard
                EIP = cur_eip;
735 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
736 2c0262af bellard
            }
737 2c0262af bellard
        }
738 2c0262af bellard
739 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
740 2c0262af bellard
            EIP = cur_eip;
741 2c0262af bellard
            if (seg_reg == R_SS)
742 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
743 2c0262af bellard
            else
744 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
745 2c0262af bellard
        }
746 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
747 2c0262af bellard
                       get_seg_base(e1, e2),
748 2c0262af bellard
                       get_seg_limit(e1, e2),
749 2c0262af bellard
                       e2);
750 2c0262af bellard
#if 0
751 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
752 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
753 2c0262af bellard
#endif
754 2c0262af bellard
    }
755 2c0262af bellard
}
756 2c0262af bellard
757 2c0262af bellard
/* protected mode jump */
758 2c0262af bellard
void helper_ljmp_protected_T0_T1(void)
759 2c0262af bellard
{
760 2c0262af bellard
    int new_cs, new_eip;
761 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
762 2c0262af bellard
763 2c0262af bellard
    new_cs = T0;
764 2c0262af bellard
    new_eip = T1;
765 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
766 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
767 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
768 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
769 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
770 2c0262af bellard
    if (e2 & DESC_S_MASK) {
771 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
772 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
773 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
774 2c0262af bellard
        if (e2 & DESC_CS_MASK) {
775 2c0262af bellard
            /* conforming code segment */
776 2c0262af bellard
            if (dpl > cpl)
777 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
778 2c0262af bellard
        } else {
779 2c0262af bellard
            /* non conforming code segment */
780 2c0262af bellard
            rpl = new_cs & 3;
781 2c0262af bellard
            if (rpl > cpl)
782 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
783 2c0262af bellard
            if (dpl != cpl)
784 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
785 2c0262af bellard
        }
786 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
787 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
788 2c0262af bellard
        limit = get_seg_limit(e1, e2);
789 2c0262af bellard
        if (new_eip > limit)
790 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
791 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
792 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
793 2c0262af bellard
        EIP = new_eip;
794 2c0262af bellard
    } else {
795 2c0262af bellard
        cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", 
796 2c0262af bellard
                  new_cs, new_eip);
797 2c0262af bellard
    }
798 2c0262af bellard
}
799 2c0262af bellard
800 2c0262af bellard
/* real mode call */
801 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
802 2c0262af bellard
{
803 2c0262af bellard
    int new_cs, new_eip;
804 2c0262af bellard
    uint32_t esp, esp_mask;
805 2c0262af bellard
    uint8_t *ssp;
806 2c0262af bellard
807 2c0262af bellard
    new_cs = T0;
808 2c0262af bellard
    new_eip = T1;
809 2c0262af bellard
    esp = ESP;
810 2c0262af bellard
    esp_mask = 0xffffffff;
811 2c0262af bellard
    if (!(env->segs[R_SS].flags & DESC_B_MASK))
812 2c0262af bellard
        esp_mask = 0xffff;
813 2c0262af bellard
    ssp = env->segs[R_SS].base;
814 2c0262af bellard
    if (shift) {
815 2c0262af bellard
        esp -= 4;
816 61382a50 bellard
        stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);
817 2c0262af bellard
        esp -= 4;
818 61382a50 bellard
        stl_kernel(ssp + (esp & esp_mask), next_eip);
819 2c0262af bellard
    } else {
820 2c0262af bellard
        esp -= 2;
821 61382a50 bellard
        stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);
822 2c0262af bellard
        esp -= 2;
823 61382a50 bellard
        stw_kernel(ssp + (esp & esp_mask), next_eip);
824 2c0262af bellard
    }
825 2c0262af bellard
826 2c0262af bellard
    if (!(env->segs[R_SS].flags & DESC_B_MASK))
827 2c0262af bellard
        ESP = (ESP & ~0xffff) | (esp & 0xffff);
828 2c0262af bellard
    else
829 2c0262af bellard
        ESP = esp;
830 2c0262af bellard
    env->eip = new_eip;
831 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
832 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
833 2c0262af bellard
}
834 2c0262af bellard
835 2c0262af bellard
/* protected mode call */
836 2c0262af bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip)
837 2c0262af bellard
{
838 2c0262af bellard
    int new_cs, new_eip;
839 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
840 2c0262af bellard
    uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;
841 2c0262af bellard
    uint32_t old_ss, old_esp, val, i, limit;
842 2c0262af bellard
    uint8_t *ssp, *old_ssp;
843 2c0262af bellard
    
844 2c0262af bellard
    new_cs = T0;
845 2c0262af bellard
    new_eip = T1;
846 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
847 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
848 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
849 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
850 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
851 2c0262af bellard
    if (e2 & DESC_S_MASK) {
852 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
853 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
854 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
855 2c0262af bellard
        if (e2 & DESC_CS_MASK) {
856 2c0262af bellard
            /* conforming code segment */
857 2c0262af bellard
            if (dpl > cpl)
858 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
859 2c0262af bellard
        } else {
860 2c0262af bellard
            /* non conforming code segment */
861 2c0262af bellard
            rpl = new_cs & 3;
862 2c0262af bellard
            if (rpl > cpl)
863 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
864 2c0262af bellard
            if (dpl != cpl)
865 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
866 2c0262af bellard
        }
867 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
868 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
869 2c0262af bellard
870 2c0262af bellard
        sp = ESP;
871 2c0262af bellard
        if (!(env->segs[R_SS].flags & DESC_B_MASK))
872 2c0262af bellard
            sp &= 0xffff;
873 2c0262af bellard
        ssp = env->segs[R_SS].base + sp;
874 2c0262af bellard
        if (shift) {
875 2c0262af bellard
            ssp -= 4;
876 61382a50 bellard
            stl_kernel(ssp, env->segs[R_CS].selector);
877 2c0262af bellard
            ssp -= 4;
878 61382a50 bellard
            stl_kernel(ssp, next_eip);
879 2c0262af bellard
        } else {
880 2c0262af bellard
            ssp -= 2;
881 61382a50 bellard
            stw_kernel(ssp, env->segs[R_CS].selector);
882 2c0262af bellard
            ssp -= 2;
883 61382a50 bellard
            stw_kernel(ssp, next_eip);
884 2c0262af bellard
        }
885 2c0262af bellard
        sp -= (4 << shift);
886 2c0262af bellard
        
887 2c0262af bellard
        limit = get_seg_limit(e1, e2);
888 2c0262af bellard
        if (new_eip > limit)
889 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
890 2c0262af bellard
        /* from this point, not restartable */
891 2c0262af bellard
        if (!(env->segs[R_SS].flags & DESC_B_MASK))
892 2c0262af bellard
            ESP = (ESP & 0xffff0000) | (sp & 0xffff);
893 2c0262af bellard
        else
894 2c0262af bellard
            ESP = sp;
895 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
896 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
897 2c0262af bellard
        EIP = new_eip;
898 2c0262af bellard
    } else {
899 2c0262af bellard
        /* check gate type */
900 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
901 2c0262af bellard
        switch(type) {
902 2c0262af bellard
        case 1: /* available 286 TSS */
903 2c0262af bellard
        case 9: /* available 386 TSS */
904 2c0262af bellard
        case 5: /* task gate */
905 2c0262af bellard
            cpu_abort(env, "task gate not supported");
906 2c0262af bellard
            break;
907 2c0262af bellard
        case 4: /* 286 call gate */
908 2c0262af bellard
        case 12: /* 386 call gate */
909 2c0262af bellard
            break;
910 2c0262af bellard
        default:
911 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
912 2c0262af bellard
            break;
913 2c0262af bellard
        }
914 2c0262af bellard
        shift = type >> 3;
915 2c0262af bellard
916 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
917 2c0262af bellard
        rpl = new_cs & 3;
918 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
919 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
920 2c0262af bellard
        /* check valid bit */
921 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
922 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
923 2c0262af bellard
        selector = e1 >> 16;
924 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
925 2c0262af bellard
        if ((selector & 0xfffc) == 0)
926 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
927 2c0262af bellard
928 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
929 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
930 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
931 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
932 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
933 2c0262af bellard
        if (dpl > cpl)
934 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
935 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
936 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
937 2c0262af bellard
938 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
939 2c0262af bellard
            /* to inner priviledge */
940 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
941 2c0262af bellard
            if ((ss & 0xfffc) == 0)
942 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
943 2c0262af bellard
            if ((ss & 3) != dpl)
944 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
945 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
946 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
947 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
948 2c0262af bellard
            if (ss_dpl != dpl)
949 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
950 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
951 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
952 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
953 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
954 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
955 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
956 2c0262af bellard
            
957 2c0262af bellard
            param_count = e2 & 0x1f;
958 2c0262af bellard
            push_size = ((param_count * 2) + 8) << shift;
959 2c0262af bellard
960 2c0262af bellard
            old_esp = ESP;
961 2c0262af bellard
            old_ss = env->segs[R_SS].selector;
962 2c0262af bellard
            if (!(env->segs[R_SS].flags & DESC_B_MASK))
963 2c0262af bellard
                old_esp &= 0xffff;
964 2c0262af bellard
            old_ssp = env->segs[R_SS].base + old_esp;
965 2c0262af bellard
            
966 2c0262af bellard
            /* XXX: from this point not restartable */
967 2c0262af bellard
            ss = (ss & ~3) | dpl;
968 2c0262af bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
969 2c0262af bellard
                           get_seg_base(ss_e1, ss_e2),
970 2c0262af bellard
                           get_seg_limit(ss_e1, ss_e2),
971 2c0262af bellard
                           ss_e2);
972 2c0262af bellard
973 2c0262af bellard
            if (!(env->segs[R_SS].flags & DESC_B_MASK))
974 2c0262af bellard
                sp &= 0xffff;
975 2c0262af bellard
            ssp = env->segs[R_SS].base + sp;
976 2c0262af bellard
            if (shift) {
977 2c0262af bellard
                ssp -= 4;
978 61382a50 bellard
                stl_kernel(ssp, old_ss);
979 2c0262af bellard
                ssp -= 4;
980 61382a50 bellard
                stl_kernel(ssp, old_esp);
981 2c0262af bellard
                ssp -= 4 * param_count;
982 2c0262af bellard
                for(i = 0; i < param_count; i++) {
983 61382a50 bellard
                    val = ldl_kernel(old_ssp + i * 4);
984 61382a50 bellard
                    stl_kernel(ssp + i * 4, val);
985 2c0262af bellard
                }
986 2c0262af bellard
            } else {
987 2c0262af bellard
                ssp -= 2;
988 61382a50 bellard
                stw_kernel(ssp, old_ss);
989 2c0262af bellard
                ssp -= 2;
990 61382a50 bellard
                stw_kernel(ssp, old_esp);
991 2c0262af bellard
                ssp -= 2 * param_count;
992 2c0262af bellard
                for(i = 0; i < param_count; i++) {
993 61382a50 bellard
                    val = lduw_kernel(old_ssp + i * 2);
994 61382a50 bellard
                    stw_kernel(ssp + i * 2, val);
995 2c0262af bellard
                }
996 2c0262af bellard
            }
997 2c0262af bellard
        } else {
998 2c0262af bellard
            /* to same priviledge */
999 2c0262af bellard
            if (!(env->segs[R_SS].flags & DESC_B_MASK))
1000 2c0262af bellard
                sp &= 0xffff;
1001 2c0262af bellard
            ssp = env->segs[R_SS].base + sp;
1002 2c0262af bellard
            push_size = (4 << shift);
1003 2c0262af bellard
        }
1004 2c0262af bellard
1005 2c0262af bellard
        if (shift) {
1006 2c0262af bellard
            ssp -= 4;
1007 61382a50 bellard
            stl_kernel(ssp, env->segs[R_CS].selector);
1008 2c0262af bellard
            ssp -= 4;
1009 61382a50 bellard
            stl_kernel(ssp, next_eip);
1010 2c0262af bellard
        } else {
1011 2c0262af bellard
            ssp -= 2;
1012 61382a50 bellard
            stw_kernel(ssp, env->segs[R_CS].selector);
1013 2c0262af bellard
            ssp -= 2;
1014 61382a50 bellard
            stw_kernel(ssp, next_eip);
1015 2c0262af bellard
        }
1016 2c0262af bellard
1017 2c0262af bellard
        sp -= push_size;
1018 2c0262af bellard
        selector = (selector & ~3) | dpl;
1019 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
1020 2c0262af bellard
                       get_seg_base(e1, e2),
1021 2c0262af bellard
                       get_seg_limit(e1, e2),
1022 2c0262af bellard
                       e2);
1023 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
1024 2c0262af bellard
        
1025 2c0262af bellard
        /* from this point, not restartable if same priviledge */
1026 2c0262af bellard
        if (!(env->segs[R_SS].flags & DESC_B_MASK))
1027 2c0262af bellard
            ESP = (ESP & 0xffff0000) | (sp & 0xffff);
1028 2c0262af bellard
        else
1029 2c0262af bellard
            ESP = sp;
1030 2c0262af bellard
        EIP = offset;
1031 2c0262af bellard
    }
1032 2c0262af bellard
}
1033 2c0262af bellard
1034 2c0262af bellard
/* real mode iret */
1035 2c0262af bellard
void helper_iret_real(int shift)
1036 2c0262af bellard
{
1037 2c0262af bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
1038 2c0262af bellard
    uint8_t *ssp;
1039 2c0262af bellard
    int eflags_mask;
1040 2c0262af bellard
    
1041 2c0262af bellard
    sp = ESP & 0xffff;
1042 2c0262af bellard
    ssp = env->segs[R_SS].base + sp;
1043 2c0262af bellard
    if (shift == 1) {
1044 2c0262af bellard
        /* 32 bits */
1045 61382a50 bellard
        new_eflags = ldl_kernel(ssp + 8);
1046 61382a50 bellard
        new_cs = ldl_kernel(ssp + 4) & 0xffff;
1047 61382a50 bellard
        new_eip = ldl_kernel(ssp) & 0xffff;
1048 2c0262af bellard
    } else {
1049 2c0262af bellard
        /* 16 bits */
1050 61382a50 bellard
        new_eflags = lduw_kernel(ssp + 4);
1051 61382a50 bellard
        new_cs = lduw_kernel(ssp + 2);
1052 61382a50 bellard
        new_eip = lduw_kernel(ssp);
1053 2c0262af bellard
    }
1054 2c0262af bellard
    new_esp = sp + (6 << shift);
1055 2c0262af bellard
    ESP = (ESP & 0xffff0000) | 
1056 2c0262af bellard
        (new_esp & 0xffff);
1057 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1058 2c0262af bellard
    env->eip = new_eip;
1059 2c0262af bellard
    eflags_mask = FL_UPDATE_CPL0_MASK;
1060 2c0262af bellard
    if (shift == 0)
1061 2c0262af bellard
        eflags_mask &= 0xffff;
1062 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
1063 2c0262af bellard
}
1064 2c0262af bellard
1065 2c0262af bellard
/* protected mode iret */
1066 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
1067 2c0262af bellard
{
1068 2c0262af bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;
1069 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
1070 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
1071 2c0262af bellard
    int cpl, dpl, rpl, eflags_mask;
1072 2c0262af bellard
    uint8_t *ssp;
1073 2c0262af bellard
    
1074 2c0262af bellard
    sp = ESP;
1075 2c0262af bellard
    if (!(env->segs[R_SS].flags & DESC_B_MASK))
1076 2c0262af bellard
        sp &= 0xffff;
1077 2c0262af bellard
    ssp = env->segs[R_SS].base + sp;
1078 2c0262af bellard
    if (shift == 1) {
1079 2c0262af bellard
        /* 32 bits */
1080 2c0262af bellard
        if (is_iret)
1081 61382a50 bellard
            new_eflags = ldl_kernel(ssp + 8);
1082 61382a50 bellard
        new_cs = ldl_kernel(ssp + 4) & 0xffff;
1083 61382a50 bellard
        new_eip = ldl_kernel(ssp);
1084 2c0262af bellard
        if (is_iret && (new_eflags & VM_MASK))
1085 2c0262af bellard
            goto return_to_vm86;
1086 2c0262af bellard
    } else {
1087 2c0262af bellard
        /* 16 bits */
1088 2c0262af bellard
        if (is_iret)
1089 61382a50 bellard
            new_eflags = lduw_kernel(ssp + 4);
1090 61382a50 bellard
        new_cs = lduw_kernel(ssp + 2);
1091 61382a50 bellard
        new_eip = lduw_kernel(ssp);
1092 2c0262af bellard
    }
1093 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1094 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1095 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1096 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1097 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
1098 2c0262af bellard
        !(e2 & DESC_CS_MASK))
1099 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1100 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1101 2c0262af bellard
    rpl = new_cs & 3; 
1102 2c0262af bellard
    if (rpl < cpl)
1103 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1104 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1105 2c0262af bellard
    if (e2 & DESC_CS_MASK) {
1106 2c0262af bellard
        if (dpl > rpl)
1107 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1108 2c0262af bellard
    } else {
1109 2c0262af bellard
        if (dpl != rpl)
1110 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1111 2c0262af bellard
    }
1112 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
1113 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1114 2c0262af bellard
    
1115 2c0262af bellard
    if (rpl == cpl) {
1116 2c0262af bellard
        /* return to same priledge level */
1117 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1118 2c0262af bellard
                       get_seg_base(e1, e2),
1119 2c0262af bellard
                       get_seg_limit(e1, e2),
1120 2c0262af bellard
                       e2);
1121 2c0262af bellard
        new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend;
1122 2c0262af bellard
    } else {
1123 2c0262af bellard
        /* return to different priviledge level */
1124 2c0262af bellard
        ssp += (4 << shift) + ((2 * is_iret) << shift) + addend;
1125 2c0262af bellard
        if (shift == 1) {
1126 2c0262af bellard
            /* 32 bits */
1127 61382a50 bellard
            new_esp = ldl_kernel(ssp);
1128 61382a50 bellard
            new_ss = ldl_kernel(ssp + 4) & 0xffff;
1129 2c0262af bellard
        } else {
1130 2c0262af bellard
            /* 16 bits */
1131 61382a50 bellard
            new_esp = lduw_kernel(ssp);
1132 61382a50 bellard
            new_ss = lduw_kernel(ssp + 2);
1133 2c0262af bellard
        }
1134 2c0262af bellard
        
1135 2c0262af bellard
        if ((new_ss & 3) != rpl)
1136 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1137 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
1138 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1139 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
1140 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
1141 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
1142 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1143 2c0262af bellard
        dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1144 2c0262af bellard
        if (dpl != rpl)
1145 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1146 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
1147 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
1148 2c0262af bellard
1149 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1150 2c0262af bellard
                       get_seg_base(e1, e2),
1151 2c0262af bellard
                       get_seg_limit(e1, e2),
1152 2c0262af bellard
                       e2);
1153 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_SS, new_ss, 
1154 2c0262af bellard
                       get_seg_base(ss_e1, ss_e2),
1155 2c0262af bellard
                       get_seg_limit(ss_e1, ss_e2),
1156 2c0262af bellard
                       ss_e2);
1157 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
1158 2c0262af bellard
    }
1159 2c0262af bellard
    if (env->segs[R_SS].flags & DESC_B_MASK)
1160 2c0262af bellard
        ESP = new_esp;
1161 2c0262af bellard
    else
1162 2c0262af bellard
        ESP = (ESP & 0xffff0000) | 
1163 2c0262af bellard
            (new_esp & 0xffff);
1164 2c0262af bellard
    env->eip = new_eip;
1165 2c0262af bellard
    if (is_iret) {
1166 2c0262af bellard
        /* NOTE: 'cpl' can be different from the current CPL */
1167 2c0262af bellard
        if (cpl == 0)
1168 2c0262af bellard
            eflags_mask = FL_UPDATE_CPL0_MASK;
1169 2c0262af bellard
        else
1170 2c0262af bellard
            eflags_mask = FL_UPDATE_MASK32;
1171 2c0262af bellard
        if (shift == 0)
1172 2c0262af bellard
            eflags_mask &= 0xffff;
1173 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
1174 2c0262af bellard
    }
1175 2c0262af bellard
    return;
1176 2c0262af bellard
1177 2c0262af bellard
 return_to_vm86:
1178 61382a50 bellard
    new_esp = ldl_kernel(ssp + 12);
1179 61382a50 bellard
    new_ss = ldl_kernel(ssp + 16);
1180 61382a50 bellard
    new_es = ldl_kernel(ssp + 20);
1181 61382a50 bellard
    new_ds = ldl_kernel(ssp + 24);
1182 61382a50 bellard
    new_fs = ldl_kernel(ssp + 28);
1183 61382a50 bellard
    new_gs = ldl_kernel(ssp + 32);
1184 2c0262af bellard
    
1185 2c0262af bellard
    /* modify processor state */
1186 2c0262af bellard
    load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
1187 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1188 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
1189 2c0262af bellard
    load_seg_vm(R_SS, new_ss);
1190 2c0262af bellard
    load_seg_vm(R_ES, new_es);
1191 2c0262af bellard
    load_seg_vm(R_DS, new_ds);
1192 2c0262af bellard
    load_seg_vm(R_FS, new_fs);
1193 2c0262af bellard
    load_seg_vm(R_GS, new_gs);
1194 2c0262af bellard
1195 2c0262af bellard
    env->eip = new_eip;
1196 2c0262af bellard
    ESP = new_esp;
1197 2c0262af bellard
}
1198 2c0262af bellard
1199 2c0262af bellard
void helper_iret_protected(int shift)
1200 2c0262af bellard
{
1201 2c0262af bellard
    helper_ret_protected(shift, 1, 0);
1202 2c0262af bellard
}
1203 2c0262af bellard
1204 2c0262af bellard
void helper_lret_protected(int shift, int addend)
1205 2c0262af bellard
{
1206 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
1207 2c0262af bellard
}
1208 2c0262af bellard
1209 2c0262af bellard
void helper_movl_crN_T0(int reg)
1210 2c0262af bellard
{
1211 2c0262af bellard
    env->cr[reg] = T0;
1212 2c0262af bellard
    switch(reg) {
1213 2c0262af bellard
    case 0:
1214 2c0262af bellard
        cpu_x86_update_cr0(env);
1215 2c0262af bellard
        break;
1216 2c0262af bellard
    case 3:
1217 2c0262af bellard
        cpu_x86_update_cr3(env);
1218 2c0262af bellard
        break;
1219 2c0262af bellard
    }
1220 2c0262af bellard
}
1221 2c0262af bellard
1222 2c0262af bellard
/* XXX: do more */
1223 2c0262af bellard
void helper_movl_drN_T0(int reg)
1224 2c0262af bellard
{
1225 2c0262af bellard
    env->dr[reg] = T0;
1226 2c0262af bellard
}
1227 2c0262af bellard
1228 2c0262af bellard
void helper_invlpg(unsigned int addr)
1229 2c0262af bellard
{
1230 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
1231 2c0262af bellard
}
1232 2c0262af bellard
1233 2c0262af bellard
/* rdtsc */
1234 2c0262af bellard
#ifndef __i386__
1235 2c0262af bellard
uint64_t emu_time;
1236 2c0262af bellard
#endif
1237 2c0262af bellard
1238 2c0262af bellard
void helper_rdtsc(void)
1239 2c0262af bellard
{
1240 2c0262af bellard
    uint64_t val;
1241 2c0262af bellard
#ifdef __i386__
1242 2c0262af bellard
    asm("rdtsc" : "=A" (val));
1243 2c0262af bellard
#else
1244 2c0262af bellard
    /* better than nothing: the time increases */
1245 2c0262af bellard
    val = emu_time++;
1246 2c0262af bellard
#endif
1247 2c0262af bellard
    EAX = val;
1248 2c0262af bellard
    EDX = val >> 32;
1249 2c0262af bellard
}
1250 2c0262af bellard
1251 2c0262af bellard
void helper_wrmsr(void)
1252 2c0262af bellard
{
1253 2c0262af bellard
    switch(ECX) {
1254 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1255 2c0262af bellard
        env->sysenter_cs = EAX & 0xffff;
1256 2c0262af bellard
        break;
1257 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1258 2c0262af bellard
        env->sysenter_esp = EAX;
1259 2c0262af bellard
        break;
1260 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1261 2c0262af bellard
        env->sysenter_eip = EAX;
1262 2c0262af bellard
        break;
1263 2c0262af bellard
    default:
1264 2c0262af bellard
        /* XXX: exception ? */
1265 2c0262af bellard
        break; 
1266 2c0262af bellard
    }
1267 2c0262af bellard
}
1268 2c0262af bellard
1269 2c0262af bellard
void helper_rdmsr(void)
1270 2c0262af bellard
{
1271 2c0262af bellard
    switch(ECX) {
1272 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1273 2c0262af bellard
        EAX = env->sysenter_cs;
1274 2c0262af bellard
        EDX = 0;
1275 2c0262af bellard
        break;
1276 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1277 2c0262af bellard
        EAX = env->sysenter_esp;
1278 2c0262af bellard
        EDX = 0;
1279 2c0262af bellard
        break;
1280 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1281 2c0262af bellard
        EAX = env->sysenter_eip;
1282 2c0262af bellard
        EDX = 0;
1283 2c0262af bellard
        break;
1284 2c0262af bellard
    default:
1285 2c0262af bellard
        /* XXX: exception ? */
1286 2c0262af bellard
        break; 
1287 2c0262af bellard
    }
1288 2c0262af bellard
}
1289 2c0262af bellard
1290 2c0262af bellard
void helper_lsl(void)
1291 2c0262af bellard
{
1292 2c0262af bellard
    unsigned int selector, limit;
1293 2c0262af bellard
    uint32_t e1, e2;
1294 2c0262af bellard
1295 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1296 2c0262af bellard
    selector = T0 & 0xffff;
1297 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1298 2c0262af bellard
        return;
1299 2c0262af bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1300 2c0262af bellard
    if (e2 & (1 << 23))
1301 2c0262af bellard
        limit = (limit << 12) | 0xfff;
1302 2c0262af bellard
    T1 = limit;
1303 2c0262af bellard
    CC_SRC |= CC_Z;
1304 2c0262af bellard
}
1305 2c0262af bellard
1306 2c0262af bellard
void helper_lar(void)
1307 2c0262af bellard
{
1308 2c0262af bellard
    unsigned int selector;
1309 2c0262af bellard
    uint32_t e1, e2;
1310 2c0262af bellard
1311 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1312 2c0262af bellard
    selector = T0 & 0xffff;
1313 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1314 2c0262af bellard
        return;
1315 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
1316 2c0262af bellard
    CC_SRC |= CC_Z;
1317 2c0262af bellard
}
1318 2c0262af bellard
1319 2c0262af bellard
/* FPU helpers */
1320 2c0262af bellard
1321 2c0262af bellard
void helper_fldt_ST0_A0(void)
1322 2c0262af bellard
{
1323 2c0262af bellard
    int new_fpstt;
1324 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
1325 2c0262af bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1326 2c0262af bellard
    env->fpstt = new_fpstt;
1327 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
1328 2c0262af bellard
}
1329 2c0262af bellard
1330 2c0262af bellard
void helper_fstt_ST0_A0(void)
1331 2c0262af bellard
{
1332 2c0262af bellard
    helper_fstt(ST0, (uint8_t *)A0);
1333 2c0262af bellard
}
1334 2c0262af bellard
1335 2c0262af bellard
/* BCD ops */
1336 2c0262af bellard
1337 2c0262af bellard
#define MUL10(iv) ( iv + iv + (iv << 3) )
1338 2c0262af bellard
1339 2c0262af bellard
void helper_fbld_ST0_A0(void)
1340 2c0262af bellard
{
1341 2c0262af bellard
    CPU86_LDouble tmp;
1342 2c0262af bellard
    uint64_t val;
1343 2c0262af bellard
    unsigned int v;
1344 2c0262af bellard
    int i;
1345 2c0262af bellard
1346 2c0262af bellard
    val = 0;
1347 2c0262af bellard
    for(i = 8; i >= 0; i--) {
1348 2c0262af bellard
        v = ldub((uint8_t *)A0 + i);
1349 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
1350 2c0262af bellard
    }
1351 2c0262af bellard
    tmp = val;
1352 2c0262af bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
1353 2c0262af bellard
        tmp = -tmp;
1354 2c0262af bellard
    fpush();
1355 2c0262af bellard
    ST0 = tmp;
1356 2c0262af bellard
}
1357 2c0262af bellard
1358 2c0262af bellard
void helper_fbst_ST0_A0(void)
1359 2c0262af bellard
{
1360 2c0262af bellard
    CPU86_LDouble tmp;
1361 2c0262af bellard
    int v;
1362 2c0262af bellard
    uint8_t *mem_ref, *mem_end;
1363 2c0262af bellard
    int64_t val;
1364 2c0262af bellard
1365 2c0262af bellard
    tmp = rint(ST0);
1366 2c0262af bellard
    val = (int64_t)tmp;
1367 2c0262af bellard
    mem_ref = (uint8_t *)A0;
1368 2c0262af bellard
    mem_end = mem_ref + 9;
1369 2c0262af bellard
    if (val < 0) {
1370 2c0262af bellard
        stb(mem_end, 0x80);
1371 2c0262af bellard
        val = -val;
1372 2c0262af bellard
    } else {
1373 2c0262af bellard
        stb(mem_end, 0x00);
1374 2c0262af bellard
    }
1375 2c0262af bellard
    while (mem_ref < mem_end) {
1376 2c0262af bellard
        if (val == 0)
1377 2c0262af bellard
            break;
1378 2c0262af bellard
        v = val % 100;
1379 2c0262af bellard
        val = val / 100;
1380 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
1381 2c0262af bellard
        stb(mem_ref++, v);
1382 2c0262af bellard
    }
1383 2c0262af bellard
    while (mem_ref < mem_end) {
1384 2c0262af bellard
        stb(mem_ref++, 0);
1385 2c0262af bellard
    }
1386 2c0262af bellard
}
1387 2c0262af bellard
1388 2c0262af bellard
void helper_f2xm1(void)
1389 2c0262af bellard
{
1390 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
1391 2c0262af bellard
}
1392 2c0262af bellard
1393 2c0262af bellard
void helper_fyl2x(void)
1394 2c0262af bellard
{
1395 2c0262af bellard
    CPU86_LDouble fptemp;
1396 2c0262af bellard
    
1397 2c0262af bellard
    fptemp = ST0;
1398 2c0262af bellard
    if (fptemp>0.0){
1399 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
1400 2c0262af bellard
        ST1 *= fptemp;
1401 2c0262af bellard
        fpop();
1402 2c0262af bellard
    } else { 
1403 2c0262af bellard
        env->fpus &= (~0x4700);
1404 2c0262af bellard
        env->fpus |= 0x400;
1405 2c0262af bellard
    }
1406 2c0262af bellard
}
1407 2c0262af bellard
1408 2c0262af bellard
void helper_fptan(void)
1409 2c0262af bellard
{
1410 2c0262af bellard
    CPU86_LDouble fptemp;
1411 2c0262af bellard
1412 2c0262af bellard
    fptemp = ST0;
1413 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1414 2c0262af bellard
        env->fpus |= 0x400;
1415 2c0262af bellard
    } else {
1416 2c0262af bellard
        ST0 = tan(fptemp);
1417 2c0262af bellard
        fpush();
1418 2c0262af bellard
        ST0 = 1.0;
1419 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1420 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
1421 2c0262af bellard
    }
1422 2c0262af bellard
}
1423 2c0262af bellard
1424 2c0262af bellard
void helper_fpatan(void)
1425 2c0262af bellard
{
1426 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
1427 2c0262af bellard
1428 2c0262af bellard
    fpsrcop = ST1;
1429 2c0262af bellard
    fptemp = ST0;
1430 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
1431 2c0262af bellard
    fpop();
1432 2c0262af bellard
}
1433 2c0262af bellard
1434 2c0262af bellard
void helper_fxtract(void)
1435 2c0262af bellard
{
1436 2c0262af bellard
    CPU86_LDoubleU temp;
1437 2c0262af bellard
    unsigned int expdif;
1438 2c0262af bellard
1439 2c0262af bellard
    temp.d = ST0;
1440 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
1441 2c0262af bellard
    /*DP exponent bias*/
1442 2c0262af bellard
    ST0 = expdif;
1443 2c0262af bellard
    fpush();
1444 2c0262af bellard
    BIASEXPONENT(temp);
1445 2c0262af bellard
    ST0 = temp.d;
1446 2c0262af bellard
}
1447 2c0262af bellard
1448 2c0262af bellard
void helper_fprem1(void)
1449 2c0262af bellard
{
1450 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
1451 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
1452 2c0262af bellard
    int expdif;
1453 2c0262af bellard
    int q;
1454 2c0262af bellard
1455 2c0262af bellard
    fpsrcop = ST0;
1456 2c0262af bellard
    fptemp = ST1;
1457 2c0262af bellard
    fpsrcop1.d = fpsrcop;
1458 2c0262af bellard
    fptemp1.d = fptemp;
1459 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1460 2c0262af bellard
    if (expdif < 53) {
1461 2c0262af bellard
        dblq = fpsrcop / fptemp;
1462 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1463 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
1464 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
1465 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1466 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
1467 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1468 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1469 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1470 2c0262af bellard
    } else {
1471 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
1472 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
1473 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
1474 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
1475 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
1476 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
1477 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
1478 2c0262af bellard
    }
1479 2c0262af bellard
}
1480 2c0262af bellard
1481 2c0262af bellard
void helper_fprem(void)
1482 2c0262af bellard
{
1483 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
1484 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
1485 2c0262af bellard
    int expdif;
1486 2c0262af bellard
    int q;
1487 2c0262af bellard
    
1488 2c0262af bellard
    fpsrcop = ST0;
1489 2c0262af bellard
    fptemp = ST1;
1490 2c0262af bellard
    fpsrcop1.d = fpsrcop;
1491 2c0262af bellard
    fptemp1.d = fptemp;
1492 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1493 2c0262af bellard
    if ( expdif < 53 ) {
1494 2c0262af bellard
        dblq = fpsrcop / fptemp;
1495 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1496 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
1497 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
1498 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1499 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
1500 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1501 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1502 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1503 2c0262af bellard
    } else {
1504 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
1505 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
1506 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
1507 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
1508 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
1509 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
1510 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
1511 2c0262af bellard
    }
1512 2c0262af bellard
}
1513 2c0262af bellard
1514 2c0262af bellard
void helper_fyl2xp1(void)
1515 2c0262af bellard
{
1516 2c0262af bellard
    CPU86_LDouble fptemp;
1517 2c0262af bellard
1518 2c0262af bellard
    fptemp = ST0;
1519 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
1520 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
1521 2c0262af bellard
        ST1 *= fptemp;
1522 2c0262af bellard
        fpop();
1523 2c0262af bellard
    } else { 
1524 2c0262af bellard
        env->fpus &= (~0x4700);
1525 2c0262af bellard
        env->fpus |= 0x400;
1526 2c0262af bellard
    }
1527 2c0262af bellard
}
1528 2c0262af bellard
1529 2c0262af bellard
void helper_fsqrt(void)
1530 2c0262af bellard
{
1531 2c0262af bellard
    CPU86_LDouble fptemp;
1532 2c0262af bellard
1533 2c0262af bellard
    fptemp = ST0;
1534 2c0262af bellard
    if (fptemp<0.0) { 
1535 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
1536 2c0262af bellard
        env->fpus |= 0x400;
1537 2c0262af bellard
    }
1538 2c0262af bellard
    ST0 = sqrt(fptemp);
1539 2c0262af bellard
}
1540 2c0262af bellard
1541 2c0262af bellard
void helper_fsincos(void)
1542 2c0262af bellard
{
1543 2c0262af bellard
    CPU86_LDouble fptemp;
1544 2c0262af bellard
1545 2c0262af bellard
    fptemp = ST0;
1546 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1547 2c0262af bellard
        env->fpus |= 0x400;
1548 2c0262af bellard
    } else {
1549 2c0262af bellard
        ST0 = sin(fptemp);
1550 2c0262af bellard
        fpush();
1551 2c0262af bellard
        ST0 = cos(fptemp);
1552 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1553 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
1554 2c0262af bellard
    }
1555 2c0262af bellard
}
1556 2c0262af bellard
1557 2c0262af bellard
void helper_frndint(void)
1558 2c0262af bellard
{
1559 2c0262af bellard
    CPU86_LDouble a;
1560 2c0262af bellard
1561 2c0262af bellard
    a = ST0;
1562 2c0262af bellard
#ifdef __arm__
1563 2c0262af bellard
    switch(env->fpuc & RC_MASK) {
1564 2c0262af bellard
    default:
1565 2c0262af bellard
    case RC_NEAR:
1566 2c0262af bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
1567 2c0262af bellard
        break;
1568 2c0262af bellard
    case RC_DOWN:
1569 2c0262af bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
1570 2c0262af bellard
        break;
1571 2c0262af bellard
    case RC_UP:
1572 2c0262af bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
1573 2c0262af bellard
        break;
1574 2c0262af bellard
    case RC_CHOP:
1575 2c0262af bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
1576 2c0262af bellard
        break;
1577 2c0262af bellard
    }
1578 2c0262af bellard
#else
1579 2c0262af bellard
    a = rint(a);
1580 2c0262af bellard
#endif
1581 2c0262af bellard
    ST0 = a;
1582 2c0262af bellard
}
1583 2c0262af bellard
1584 2c0262af bellard
void helper_fscale(void)
1585 2c0262af bellard
{
1586 2c0262af bellard
    CPU86_LDouble fpsrcop, fptemp;
1587 2c0262af bellard
1588 2c0262af bellard
    fpsrcop = 2.0;
1589 2c0262af bellard
    fptemp = pow(fpsrcop,ST1);
1590 2c0262af bellard
    ST0 *= fptemp;
1591 2c0262af bellard
}
1592 2c0262af bellard
1593 2c0262af bellard
void helper_fsin(void)
1594 2c0262af bellard
{
1595 2c0262af bellard
    CPU86_LDouble fptemp;
1596 2c0262af bellard
1597 2c0262af bellard
    fptemp = ST0;
1598 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1599 2c0262af bellard
        env->fpus |= 0x400;
1600 2c0262af bellard
    } else {
1601 2c0262af bellard
        ST0 = sin(fptemp);
1602 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1603 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
1604 2c0262af bellard
    }
1605 2c0262af bellard
}
1606 2c0262af bellard
1607 2c0262af bellard
void helper_fcos(void)
1608 2c0262af bellard
{
1609 2c0262af bellard
    CPU86_LDouble fptemp;
1610 2c0262af bellard
1611 2c0262af bellard
    fptemp = ST0;
1612 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1613 2c0262af bellard
        env->fpus |= 0x400;
1614 2c0262af bellard
    } else {
1615 2c0262af bellard
        ST0 = cos(fptemp);
1616 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1617 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
1618 2c0262af bellard
    }
1619 2c0262af bellard
}
1620 2c0262af bellard
1621 2c0262af bellard
void helper_fxam_ST0(void)
1622 2c0262af bellard
{
1623 2c0262af bellard
    CPU86_LDoubleU temp;
1624 2c0262af bellard
    int expdif;
1625 2c0262af bellard
1626 2c0262af bellard
    temp.d = ST0;
1627 2c0262af bellard
1628 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
1629 2c0262af bellard
    if (SIGND(temp))
1630 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
1631 2c0262af bellard
1632 2c0262af bellard
    expdif = EXPD(temp);
1633 2c0262af bellard
    if (expdif == MAXEXPD) {
1634 2c0262af bellard
        if (MANTD(temp) == 0)
1635 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
1636 2c0262af bellard
        else
1637 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
1638 2c0262af bellard
    } else if (expdif == 0) {
1639 2c0262af bellard
        if (MANTD(temp) == 0)
1640 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
1641 2c0262af bellard
        else
1642 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
1643 2c0262af bellard
    } else {
1644 2c0262af bellard
        env->fpus |= 0x400;
1645 2c0262af bellard
    }
1646 2c0262af bellard
}
1647 2c0262af bellard
1648 2c0262af bellard
void helper_fstenv(uint8_t *ptr, int data32)
1649 2c0262af bellard
{
1650 2c0262af bellard
    int fpus, fptag, exp, i;
1651 2c0262af bellard
    uint64_t mant;
1652 2c0262af bellard
    CPU86_LDoubleU tmp;
1653 2c0262af bellard
1654 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1655 2c0262af bellard
    fptag = 0;
1656 2c0262af bellard
    for (i=7; i>=0; i--) {
1657 2c0262af bellard
        fptag <<= 2;
1658 2c0262af bellard
        if (env->fptags[i]) {
1659 2c0262af bellard
            fptag |= 3;
1660 2c0262af bellard
        } else {
1661 2c0262af bellard
            tmp.d = env->fpregs[i];
1662 2c0262af bellard
            exp = EXPD(tmp);
1663 2c0262af bellard
            mant = MANTD(tmp);
1664 2c0262af bellard
            if (exp == 0 && mant == 0) {
1665 2c0262af bellard
                /* zero */
1666 2c0262af bellard
                fptag |= 1;
1667 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
1668 2c0262af bellard
#ifdef USE_X86LDOUBLE
1669 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
1670 2c0262af bellard
#endif
1671 2c0262af bellard
                       ) {
1672 2c0262af bellard
                /* NaNs, infinity, denormal */
1673 2c0262af bellard
                fptag |= 2;
1674 2c0262af bellard
            }
1675 2c0262af bellard
        }
1676 2c0262af bellard
    }
1677 2c0262af bellard
    if (data32) {
1678 2c0262af bellard
        /* 32 bit */
1679 2c0262af bellard
        stl(ptr, env->fpuc);
1680 2c0262af bellard
        stl(ptr + 4, fpus);
1681 2c0262af bellard
        stl(ptr + 8, fptag);
1682 2c0262af bellard
        stl(ptr + 12, 0);
1683 2c0262af bellard
        stl(ptr + 16, 0);
1684 2c0262af bellard
        stl(ptr + 20, 0);
1685 2c0262af bellard
        stl(ptr + 24, 0);
1686 2c0262af bellard
    } else {
1687 2c0262af bellard
        /* 16 bit */
1688 2c0262af bellard
        stw(ptr, env->fpuc);
1689 2c0262af bellard
        stw(ptr + 2, fpus);
1690 2c0262af bellard
        stw(ptr + 4, fptag);
1691 2c0262af bellard
        stw(ptr + 6, 0);
1692 2c0262af bellard
        stw(ptr + 8, 0);
1693 2c0262af bellard
        stw(ptr + 10, 0);
1694 2c0262af bellard
        stw(ptr + 12, 0);
1695 2c0262af bellard
    }
1696 2c0262af bellard
}
1697 2c0262af bellard
1698 2c0262af bellard
void helper_fldenv(uint8_t *ptr, int data32)
1699 2c0262af bellard
{
1700 2c0262af bellard
    int i, fpus, fptag;
1701 2c0262af bellard
1702 2c0262af bellard
    if (data32) {
1703 2c0262af bellard
        env->fpuc = lduw(ptr);
1704 2c0262af bellard
        fpus = lduw(ptr + 4);
1705 2c0262af bellard
        fptag = lduw(ptr + 8);
1706 2c0262af bellard
    }
1707 2c0262af bellard
    else {
1708 2c0262af bellard
        env->fpuc = lduw(ptr);
1709 2c0262af bellard
        fpus = lduw(ptr + 2);
1710 2c0262af bellard
        fptag = lduw(ptr + 4);
1711 2c0262af bellard
    }
1712 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
1713 2c0262af bellard
    env->fpus = fpus & ~0x3800;
1714 2c0262af bellard
    for(i = 0;i < 7; i++) {
1715 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
1716 2c0262af bellard
        fptag >>= 2;
1717 2c0262af bellard
    }
1718 2c0262af bellard
}
1719 2c0262af bellard
1720 2c0262af bellard
void helper_fsave(uint8_t *ptr, int data32)
1721 2c0262af bellard
{
1722 2c0262af bellard
    CPU86_LDouble tmp;
1723 2c0262af bellard
    int i;
1724 2c0262af bellard
1725 2c0262af bellard
    helper_fstenv(ptr, data32);
1726 2c0262af bellard
1727 2c0262af bellard
    ptr += (14 << data32);
1728 2c0262af bellard
    for(i = 0;i < 8; i++) {
1729 2c0262af bellard
        tmp = ST(i);
1730 2c0262af bellard
        helper_fstt(tmp, ptr);
1731 2c0262af bellard
        ptr += 10;
1732 2c0262af bellard
    }
1733 2c0262af bellard
1734 2c0262af bellard
    /* fninit */
1735 2c0262af bellard
    env->fpus = 0;
1736 2c0262af bellard
    env->fpstt = 0;
1737 2c0262af bellard
    env->fpuc = 0x37f;
1738 2c0262af bellard
    env->fptags[0] = 1;
1739 2c0262af bellard
    env->fptags[1] = 1;
1740 2c0262af bellard
    env->fptags[2] = 1;
1741 2c0262af bellard
    env->fptags[3] = 1;
1742 2c0262af bellard
    env->fptags[4] = 1;
1743 2c0262af bellard
    env->fptags[5] = 1;
1744 2c0262af bellard
    env->fptags[6] = 1;
1745 2c0262af bellard
    env->fptags[7] = 1;
1746 2c0262af bellard
}
1747 2c0262af bellard
1748 2c0262af bellard
void helper_frstor(uint8_t *ptr, int data32)
1749 2c0262af bellard
{
1750 2c0262af bellard
    CPU86_LDouble tmp;
1751 2c0262af bellard
    int i;
1752 2c0262af bellard
1753 2c0262af bellard
    helper_fldenv(ptr, data32);
1754 2c0262af bellard
    ptr += (14 << data32);
1755 2c0262af bellard
1756 2c0262af bellard
    for(i = 0;i < 8; i++) {
1757 2c0262af bellard
        tmp = helper_fldt(ptr);
1758 2c0262af bellard
        ST(i) = tmp;
1759 2c0262af bellard
        ptr += 10;
1760 2c0262af bellard
    }
1761 2c0262af bellard
}
1762 2c0262af bellard
1763 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
1764 61382a50 bellard
1765 61382a50 bellard
#define MMUSUFFIX _mmu
1766 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
1767 61382a50 bellard
1768 2c0262af bellard
#define SHIFT 0
1769 2c0262af bellard
#include "softmmu_template.h"
1770 2c0262af bellard
1771 2c0262af bellard
#define SHIFT 1
1772 2c0262af bellard
#include "softmmu_template.h"
1773 2c0262af bellard
1774 2c0262af bellard
#define SHIFT 2
1775 2c0262af bellard
#include "softmmu_template.h"
1776 2c0262af bellard
1777 2c0262af bellard
#define SHIFT 3
1778 2c0262af bellard
#include "softmmu_template.h"
1779 2c0262af bellard
1780 61382a50 bellard
#endif
1781 61382a50 bellard
1782 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
1783 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
1784 61382a50 bellard
   from generated code or from helper.c) */
1785 61382a50 bellard
/* XXX: fix it to restore all registers */
1786 61382a50 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
1787 2c0262af bellard
{
1788 2c0262af bellard
    TranslationBlock *tb;
1789 2c0262af bellard
    int ret;
1790 2c0262af bellard
    unsigned long pc;
1791 61382a50 bellard
    CPUX86State *saved_env;
1792 61382a50 bellard
1793 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
1794 61382a50 bellard
       generated code */
1795 61382a50 bellard
    saved_env = env;
1796 61382a50 bellard
    env = cpu_single_env;
1797 61382a50 bellard
    if (is_write && page_unprotect(addr)) {
1798 61382a50 bellard
        /* nothing more to do: the page was write protected because
1799 61382a50 bellard
           there was code in it. page_unprotect() flushed the code. */
1800 61382a50 bellard
    }
1801 61382a50 bellard
1802 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
1803 2c0262af bellard
    if (ret) {
1804 61382a50 bellard
        if (retaddr) {
1805 61382a50 bellard
            /* now we have a real cpu fault */
1806 61382a50 bellard
            pc = (unsigned long)retaddr;
1807 61382a50 bellard
            tb = tb_find_pc(pc);
1808 61382a50 bellard
            if (tb) {
1809 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
1810 61382a50 bellard
                   a virtual CPU fault */
1811 61382a50 bellard
                cpu_restore_state(tb, env, pc);
1812 61382a50 bellard
            }
1813 2c0262af bellard
        }
1814 2c0262af bellard
        raise_exception_err(EXCP0E_PAGE, env->error_code);
1815 2c0262af bellard
    }
1816 61382a50 bellard
    env = saved_env;
1817 2c0262af bellard
}