Statistics
| Branch: | Revision:

root / helper-i386.c @ b67d5959

History | View | Annotate | Download (47.8 kB)

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