Statistics
| Branch: | Revision:

root / helper-i386.c @ 2c1794c4

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