Statistics
| Branch: | Revision:

root / helper-i386.c @ 3b22c470

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