Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 3ab493de

History | View | Annotate | Download (66.1 kB)

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