Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 2ee73ac3

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