Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 28ab0e2e

History | View | Annotate | Download (71.2 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
void helper_rdtsc(void)
1779 2c0262af bellard
{
1780 2c0262af bellard
    uint64_t val;
1781 28ab0e2e bellard
    
1782 28ab0e2e bellard
    val = cpu_get_tsc(env);
1783 2c0262af bellard
    EAX = val;
1784 2c0262af bellard
    EDX = val >> 32;
1785 2c0262af bellard
}
1786 2c0262af bellard
1787 2c0262af bellard
void helper_wrmsr(void)
1788 2c0262af bellard
{
1789 2c0262af bellard
    switch(ECX) {
1790 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1791 2c0262af bellard
        env->sysenter_cs = EAX & 0xffff;
1792 2c0262af bellard
        break;
1793 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1794 2c0262af bellard
        env->sysenter_esp = EAX;
1795 2c0262af bellard
        break;
1796 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1797 2c0262af bellard
        env->sysenter_eip = EAX;
1798 2c0262af bellard
        break;
1799 2c0262af bellard
    default:
1800 2c0262af bellard
        /* XXX: exception ? */
1801 2c0262af bellard
        break; 
1802 2c0262af bellard
    }
1803 2c0262af bellard
}
1804 2c0262af bellard
1805 2c0262af bellard
void helper_rdmsr(void)
1806 2c0262af bellard
{
1807 2c0262af bellard
    switch(ECX) {
1808 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1809 2c0262af bellard
        EAX = env->sysenter_cs;
1810 2c0262af bellard
        EDX = 0;
1811 2c0262af bellard
        break;
1812 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1813 2c0262af bellard
        EAX = env->sysenter_esp;
1814 2c0262af bellard
        EDX = 0;
1815 2c0262af bellard
        break;
1816 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1817 2c0262af bellard
        EAX = env->sysenter_eip;
1818 2c0262af bellard
        EDX = 0;
1819 2c0262af bellard
        break;
1820 2c0262af bellard
    default:
1821 2c0262af bellard
        /* XXX: exception ? */
1822 2c0262af bellard
        break; 
1823 2c0262af bellard
    }
1824 2c0262af bellard
}
1825 2c0262af bellard
1826 2c0262af bellard
void helper_lsl(void)
1827 2c0262af bellard
{
1828 2c0262af bellard
    unsigned int selector, limit;
1829 2c0262af bellard
    uint32_t e1, e2;
1830 3ab493de bellard
    int rpl, dpl, cpl, type;
1831 2c0262af bellard
1832 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1833 2c0262af bellard
    selector = T0 & 0xffff;
1834 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1835 2c0262af bellard
        return;
1836 3ab493de bellard
    rpl = selector & 3;
1837 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1838 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1839 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1840 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1841 3ab493de bellard
            /* conforming */
1842 3ab493de bellard
        } else {
1843 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1844 3ab493de bellard
                return;
1845 3ab493de bellard
        }
1846 3ab493de bellard
    } else {
1847 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1848 3ab493de bellard
        switch(type) {
1849 3ab493de bellard
        case 1:
1850 3ab493de bellard
        case 2:
1851 3ab493de bellard
        case 3:
1852 3ab493de bellard
        case 9:
1853 3ab493de bellard
        case 11:
1854 3ab493de bellard
            break;
1855 3ab493de bellard
        default:
1856 3ab493de bellard
            return;
1857 3ab493de bellard
        }
1858 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1859 3ab493de bellard
            return;
1860 3ab493de bellard
    }
1861 3ab493de bellard
    limit = get_seg_limit(e1, e2);
1862 2c0262af bellard
    T1 = limit;
1863 2c0262af bellard
    CC_SRC |= CC_Z;
1864 2c0262af bellard
}
1865 2c0262af bellard
1866 2c0262af bellard
void helper_lar(void)
1867 2c0262af bellard
{
1868 2c0262af bellard
    unsigned int selector;
1869 2c0262af bellard
    uint32_t e1, e2;
1870 3ab493de bellard
    int rpl, dpl, cpl, type;
1871 2c0262af bellard
1872 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1873 2c0262af bellard
    selector = T0 & 0xffff;
1874 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1875 3ab493de bellard
        return;
1876 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1877 2c0262af bellard
        return;
1878 3ab493de bellard
    rpl = selector & 3;
1879 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1880 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1881 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1882 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1883 3ab493de bellard
            /* conforming */
1884 3ab493de bellard
        } else {
1885 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1886 3ab493de bellard
                return;
1887 3ab493de bellard
        }
1888 3ab493de bellard
    } else {
1889 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1890 3ab493de bellard
        switch(type) {
1891 3ab493de bellard
        case 1:
1892 3ab493de bellard
        case 2:
1893 3ab493de bellard
        case 3:
1894 3ab493de bellard
        case 4:
1895 3ab493de bellard
        case 5:
1896 3ab493de bellard
        case 9:
1897 3ab493de bellard
        case 11:
1898 3ab493de bellard
        case 12:
1899 3ab493de bellard
            break;
1900 3ab493de bellard
        default:
1901 3ab493de bellard
            return;
1902 3ab493de bellard
        }
1903 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1904 3ab493de bellard
            return;
1905 3ab493de bellard
    }
1906 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
1907 2c0262af bellard
    CC_SRC |= CC_Z;
1908 2c0262af bellard
}
1909 2c0262af bellard
1910 3ab493de bellard
void helper_verr(void)
1911 3ab493de bellard
{
1912 3ab493de bellard
    unsigned int selector;
1913 3ab493de bellard
    uint32_t e1, e2;
1914 3ab493de bellard
    int rpl, dpl, cpl;
1915 3ab493de bellard
1916 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1917 3ab493de bellard
    selector = T0 & 0xffff;
1918 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1919 3ab493de bellard
        return;
1920 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1921 3ab493de bellard
        return;
1922 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1923 3ab493de bellard
        return;
1924 3ab493de bellard
    rpl = selector & 3;
1925 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1926 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1927 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1928 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
1929 3ab493de bellard
            return;
1930 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
1931 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1932 3ab493de bellard
                return;
1933 3ab493de bellard
        }
1934 3ab493de bellard
    } else {
1935 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1936 3ab493de bellard
            return;
1937 3ab493de bellard
    }
1938 f3f2d9be bellard
    CC_SRC |= CC_Z;
1939 3ab493de bellard
}
1940 3ab493de bellard
1941 3ab493de bellard
void helper_verw(void)
1942 3ab493de bellard
{
1943 3ab493de bellard
    unsigned int selector;
1944 3ab493de bellard
    uint32_t e1, e2;
1945 3ab493de bellard
    int rpl, dpl, cpl;
1946 3ab493de bellard
1947 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1948 3ab493de bellard
    selector = T0 & 0xffff;
1949 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1950 3ab493de bellard
        return;
1951 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1952 3ab493de bellard
        return;
1953 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1954 3ab493de bellard
        return;
1955 3ab493de bellard
    rpl = selector & 3;
1956 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1957 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1958 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1959 3ab493de bellard
        return;
1960 3ab493de bellard
    } else {
1961 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1962 3ab493de bellard
            return;
1963 3ab493de bellard
        if (!(e2 & DESC_W_MASK))
1964 3ab493de bellard
            return;
1965 3ab493de bellard
    }
1966 f3f2d9be bellard
    CC_SRC |= CC_Z;
1967 3ab493de bellard
}
1968 3ab493de bellard
1969 2c0262af bellard
/* FPU helpers */
1970 2c0262af bellard
1971 2c0262af bellard
void helper_fldt_ST0_A0(void)
1972 2c0262af bellard
{
1973 2c0262af bellard
    int new_fpstt;
1974 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
1975 2c0262af bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1976 2c0262af bellard
    env->fpstt = new_fpstt;
1977 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
1978 2c0262af bellard
}
1979 2c0262af bellard
1980 2c0262af bellard
void helper_fstt_ST0_A0(void)
1981 2c0262af bellard
{
1982 2c0262af bellard
    helper_fstt(ST0, (uint8_t *)A0);
1983 2c0262af bellard
}
1984 2c0262af bellard
1985 2ee73ac3 bellard
void fpu_set_exception(int mask)
1986 2ee73ac3 bellard
{
1987 2ee73ac3 bellard
    env->fpus |= mask;
1988 2ee73ac3 bellard
    if (env->fpus & (~env->fpuc & FPUC_EM))
1989 2ee73ac3 bellard
        env->fpus |= FPUS_SE | FPUS_B;
1990 2ee73ac3 bellard
}
1991 2ee73ac3 bellard
1992 2ee73ac3 bellard
CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
1993 2ee73ac3 bellard
{
1994 2ee73ac3 bellard
    if (b == 0.0) 
1995 2ee73ac3 bellard
        fpu_set_exception(FPUS_ZE);
1996 2ee73ac3 bellard
    return a / b;
1997 2ee73ac3 bellard
}
1998 2ee73ac3 bellard
1999 2ee73ac3 bellard
void fpu_raise_exception(void)
2000 2ee73ac3 bellard
{
2001 2ee73ac3 bellard
    if (env->cr[0] & CR0_NE_MASK) {
2002 2ee73ac3 bellard
        raise_exception(EXCP10_COPR);
2003 2ee73ac3 bellard
    } 
2004 2ee73ac3 bellard
#if !defined(CONFIG_USER_ONLY) 
2005 2ee73ac3 bellard
    else {
2006 2ee73ac3 bellard
        cpu_set_ferr(env);
2007 2ee73ac3 bellard
    }
2008 2ee73ac3 bellard
#endif
2009 2ee73ac3 bellard
}
2010 2ee73ac3 bellard
2011 2c0262af bellard
/* BCD ops */
2012 2c0262af bellard
2013 2c0262af bellard
void helper_fbld_ST0_A0(void)
2014 2c0262af bellard
{
2015 2c0262af bellard
    CPU86_LDouble tmp;
2016 2c0262af bellard
    uint64_t val;
2017 2c0262af bellard
    unsigned int v;
2018 2c0262af bellard
    int i;
2019 2c0262af bellard
2020 2c0262af bellard
    val = 0;
2021 2c0262af bellard
    for(i = 8; i >= 0; i--) {
2022 2c0262af bellard
        v = ldub((uint8_t *)A0 + i);
2023 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2024 2c0262af bellard
    }
2025 2c0262af bellard
    tmp = val;
2026 2c0262af bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
2027 2c0262af bellard
        tmp = -tmp;
2028 2c0262af bellard
    fpush();
2029 2c0262af bellard
    ST0 = tmp;
2030 2c0262af bellard
}
2031 2c0262af bellard
2032 2c0262af bellard
void helper_fbst_ST0_A0(void)
2033 2c0262af bellard
{
2034 2c0262af bellard
    CPU86_LDouble tmp;
2035 2c0262af bellard
    int v;
2036 2c0262af bellard
    uint8_t *mem_ref, *mem_end;
2037 2c0262af bellard
    int64_t val;
2038 2c0262af bellard
2039 2c0262af bellard
    tmp = rint(ST0);
2040 2c0262af bellard
    val = (int64_t)tmp;
2041 2c0262af bellard
    mem_ref = (uint8_t *)A0;
2042 2c0262af bellard
    mem_end = mem_ref + 9;
2043 2c0262af bellard
    if (val < 0) {
2044 2c0262af bellard
        stb(mem_end, 0x80);
2045 2c0262af bellard
        val = -val;
2046 2c0262af bellard
    } else {
2047 2c0262af bellard
        stb(mem_end, 0x00);
2048 2c0262af bellard
    }
2049 2c0262af bellard
    while (mem_ref < mem_end) {
2050 2c0262af bellard
        if (val == 0)
2051 2c0262af bellard
            break;
2052 2c0262af bellard
        v = val % 100;
2053 2c0262af bellard
        val = val / 100;
2054 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
2055 2c0262af bellard
        stb(mem_ref++, v);
2056 2c0262af bellard
    }
2057 2c0262af bellard
    while (mem_ref < mem_end) {
2058 2c0262af bellard
        stb(mem_ref++, 0);
2059 2c0262af bellard
    }
2060 2c0262af bellard
}
2061 2c0262af bellard
2062 2c0262af bellard
void helper_f2xm1(void)
2063 2c0262af bellard
{
2064 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
2065 2c0262af bellard
}
2066 2c0262af bellard
2067 2c0262af bellard
void helper_fyl2x(void)
2068 2c0262af bellard
{
2069 2c0262af bellard
    CPU86_LDouble fptemp;
2070 2c0262af bellard
    
2071 2c0262af bellard
    fptemp = ST0;
2072 2c0262af bellard
    if (fptemp>0.0){
2073 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
2074 2c0262af bellard
        ST1 *= fptemp;
2075 2c0262af bellard
        fpop();
2076 2c0262af bellard
    } else { 
2077 2c0262af bellard
        env->fpus &= (~0x4700);
2078 2c0262af bellard
        env->fpus |= 0x400;
2079 2c0262af bellard
    }
2080 2c0262af bellard
}
2081 2c0262af bellard
2082 2c0262af bellard
void helper_fptan(void)
2083 2c0262af bellard
{
2084 2c0262af bellard
    CPU86_LDouble fptemp;
2085 2c0262af bellard
2086 2c0262af bellard
    fptemp = ST0;
2087 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2088 2c0262af bellard
        env->fpus |= 0x400;
2089 2c0262af bellard
    } else {
2090 2c0262af bellard
        ST0 = tan(fptemp);
2091 2c0262af bellard
        fpush();
2092 2c0262af bellard
        ST0 = 1.0;
2093 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2094 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
2095 2c0262af bellard
    }
2096 2c0262af bellard
}
2097 2c0262af bellard
2098 2c0262af bellard
void helper_fpatan(void)
2099 2c0262af bellard
{
2100 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
2101 2c0262af bellard
2102 2c0262af bellard
    fpsrcop = ST1;
2103 2c0262af bellard
    fptemp = ST0;
2104 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
2105 2c0262af bellard
    fpop();
2106 2c0262af bellard
}
2107 2c0262af bellard
2108 2c0262af bellard
void helper_fxtract(void)
2109 2c0262af bellard
{
2110 2c0262af bellard
    CPU86_LDoubleU temp;
2111 2c0262af bellard
    unsigned int expdif;
2112 2c0262af bellard
2113 2c0262af bellard
    temp.d = ST0;
2114 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
2115 2c0262af bellard
    /*DP exponent bias*/
2116 2c0262af bellard
    ST0 = expdif;
2117 2c0262af bellard
    fpush();
2118 2c0262af bellard
    BIASEXPONENT(temp);
2119 2c0262af bellard
    ST0 = temp.d;
2120 2c0262af bellard
}
2121 2c0262af bellard
2122 2c0262af bellard
void helper_fprem1(void)
2123 2c0262af bellard
{
2124 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2125 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2126 2c0262af bellard
    int expdif;
2127 2c0262af bellard
    int q;
2128 2c0262af bellard
2129 2c0262af bellard
    fpsrcop = ST0;
2130 2c0262af bellard
    fptemp = ST1;
2131 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2132 2c0262af bellard
    fptemp1.d = fptemp;
2133 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2134 2c0262af bellard
    if (expdif < 53) {
2135 2c0262af bellard
        dblq = fpsrcop / fptemp;
2136 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2137 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2138 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2139 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2140 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2141 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2142 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2143 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2144 2c0262af bellard
    } else {
2145 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2146 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2147 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2148 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
2149 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2150 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
2151 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2152 2c0262af bellard
    }
2153 2c0262af bellard
}
2154 2c0262af bellard
2155 2c0262af bellard
void helper_fprem(void)
2156 2c0262af bellard
{
2157 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2158 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2159 2c0262af bellard
    int expdif;
2160 2c0262af bellard
    int q;
2161 2c0262af bellard
    
2162 2c0262af bellard
    fpsrcop = ST0;
2163 2c0262af bellard
    fptemp = ST1;
2164 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2165 2c0262af bellard
    fptemp1.d = fptemp;
2166 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2167 2c0262af bellard
    if ( expdif < 53 ) {
2168 2c0262af bellard
        dblq = fpsrcop / fptemp;
2169 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2170 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2171 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2172 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2173 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2174 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2175 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2176 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2177 2c0262af bellard
    } else {
2178 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2179 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2180 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2181 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
2182 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
2183 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
2184 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2185 2c0262af bellard
    }
2186 2c0262af bellard
}
2187 2c0262af bellard
2188 2c0262af bellard
void helper_fyl2xp1(void)
2189 2c0262af bellard
{
2190 2c0262af bellard
    CPU86_LDouble fptemp;
2191 2c0262af bellard
2192 2c0262af bellard
    fptemp = ST0;
2193 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
2194 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2195 2c0262af bellard
        ST1 *= fptemp;
2196 2c0262af bellard
        fpop();
2197 2c0262af bellard
    } else { 
2198 2c0262af bellard
        env->fpus &= (~0x4700);
2199 2c0262af bellard
        env->fpus |= 0x400;
2200 2c0262af bellard
    }
2201 2c0262af bellard
}
2202 2c0262af bellard
2203 2c0262af bellard
void helper_fsqrt(void)
2204 2c0262af bellard
{
2205 2c0262af bellard
    CPU86_LDouble fptemp;
2206 2c0262af bellard
2207 2c0262af bellard
    fptemp = ST0;
2208 2c0262af bellard
    if (fptemp<0.0) { 
2209 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2210 2c0262af bellard
        env->fpus |= 0x400;
2211 2c0262af bellard
    }
2212 2c0262af bellard
    ST0 = sqrt(fptemp);
2213 2c0262af bellard
}
2214 2c0262af bellard
2215 2c0262af bellard
void helper_fsincos(void)
2216 2c0262af bellard
{
2217 2c0262af bellard
    CPU86_LDouble fptemp;
2218 2c0262af bellard
2219 2c0262af bellard
    fptemp = ST0;
2220 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2221 2c0262af bellard
        env->fpus |= 0x400;
2222 2c0262af bellard
    } else {
2223 2c0262af bellard
        ST0 = sin(fptemp);
2224 2c0262af bellard
        fpush();
2225 2c0262af bellard
        ST0 = cos(fptemp);
2226 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2227 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
2228 2c0262af bellard
    }
2229 2c0262af bellard
}
2230 2c0262af bellard
2231 2c0262af bellard
void helper_frndint(void)
2232 2c0262af bellard
{
2233 2c0262af bellard
    CPU86_LDouble a;
2234 2c0262af bellard
2235 2c0262af bellard
    a = ST0;
2236 2c0262af bellard
#ifdef __arm__
2237 2c0262af bellard
    switch(env->fpuc & RC_MASK) {
2238 2c0262af bellard
    default:
2239 2c0262af bellard
    case RC_NEAR:
2240 2c0262af bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
2241 2c0262af bellard
        break;
2242 2c0262af bellard
    case RC_DOWN:
2243 2c0262af bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
2244 2c0262af bellard
        break;
2245 2c0262af bellard
    case RC_UP:
2246 2c0262af bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
2247 2c0262af bellard
        break;
2248 2c0262af bellard
    case RC_CHOP:
2249 2c0262af bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
2250 2c0262af bellard
        break;
2251 2c0262af bellard
    }
2252 2c0262af bellard
#else
2253 2c0262af bellard
    a = rint(a);
2254 2c0262af bellard
#endif
2255 2c0262af bellard
    ST0 = a;
2256 2c0262af bellard
}
2257 2c0262af bellard
2258 2c0262af bellard
void helper_fscale(void)
2259 2c0262af bellard
{
2260 2c0262af bellard
    CPU86_LDouble fpsrcop, fptemp;
2261 2c0262af bellard
2262 2c0262af bellard
    fpsrcop = 2.0;
2263 2c0262af bellard
    fptemp = pow(fpsrcop,ST1);
2264 2c0262af bellard
    ST0 *= fptemp;
2265 2c0262af bellard
}
2266 2c0262af bellard
2267 2c0262af bellard
void helper_fsin(void)
2268 2c0262af bellard
{
2269 2c0262af bellard
    CPU86_LDouble fptemp;
2270 2c0262af bellard
2271 2c0262af bellard
    fptemp = ST0;
2272 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2273 2c0262af bellard
        env->fpus |= 0x400;
2274 2c0262af bellard
    } else {
2275 2c0262af bellard
        ST0 = sin(fptemp);
2276 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2277 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
2278 2c0262af bellard
    }
2279 2c0262af bellard
}
2280 2c0262af bellard
2281 2c0262af bellard
void helper_fcos(void)
2282 2c0262af bellard
{
2283 2c0262af bellard
    CPU86_LDouble fptemp;
2284 2c0262af bellard
2285 2c0262af bellard
    fptemp = ST0;
2286 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2287 2c0262af bellard
        env->fpus |= 0x400;
2288 2c0262af bellard
    } else {
2289 2c0262af bellard
        ST0 = cos(fptemp);
2290 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2291 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
2292 2c0262af bellard
    }
2293 2c0262af bellard
}
2294 2c0262af bellard
2295 2c0262af bellard
void helper_fxam_ST0(void)
2296 2c0262af bellard
{
2297 2c0262af bellard
    CPU86_LDoubleU temp;
2298 2c0262af bellard
    int expdif;
2299 2c0262af bellard
2300 2c0262af bellard
    temp.d = ST0;
2301 2c0262af bellard
2302 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2303 2c0262af bellard
    if (SIGND(temp))
2304 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
2305 2c0262af bellard
2306 2c0262af bellard
    expdif = EXPD(temp);
2307 2c0262af bellard
    if (expdif == MAXEXPD) {
2308 2c0262af bellard
        if (MANTD(temp) == 0)
2309 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
2310 2c0262af bellard
        else
2311 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
2312 2c0262af bellard
    } else if (expdif == 0) {
2313 2c0262af bellard
        if (MANTD(temp) == 0)
2314 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
2315 2c0262af bellard
        else
2316 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
2317 2c0262af bellard
    } else {
2318 2c0262af bellard
        env->fpus |= 0x400;
2319 2c0262af bellard
    }
2320 2c0262af bellard
}
2321 2c0262af bellard
2322 2c0262af bellard
void helper_fstenv(uint8_t *ptr, int data32)
2323 2c0262af bellard
{
2324 2c0262af bellard
    int fpus, fptag, exp, i;
2325 2c0262af bellard
    uint64_t mant;
2326 2c0262af bellard
    CPU86_LDoubleU tmp;
2327 2c0262af bellard
2328 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2329 2c0262af bellard
    fptag = 0;
2330 2c0262af bellard
    for (i=7; i>=0; i--) {
2331 2c0262af bellard
        fptag <<= 2;
2332 2c0262af bellard
        if (env->fptags[i]) {
2333 2c0262af bellard
            fptag |= 3;
2334 2c0262af bellard
        } else {
2335 2c0262af bellard
            tmp.d = env->fpregs[i];
2336 2c0262af bellard
            exp = EXPD(tmp);
2337 2c0262af bellard
            mant = MANTD(tmp);
2338 2c0262af bellard
            if (exp == 0 && mant == 0) {
2339 2c0262af bellard
                /* zero */
2340 2c0262af bellard
                fptag |= 1;
2341 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
2342 2c0262af bellard
#ifdef USE_X86LDOUBLE
2343 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
2344 2c0262af bellard
#endif
2345 2c0262af bellard
                       ) {
2346 2c0262af bellard
                /* NaNs, infinity, denormal */
2347 2c0262af bellard
                fptag |= 2;
2348 2c0262af bellard
            }
2349 2c0262af bellard
        }
2350 2c0262af bellard
    }
2351 2c0262af bellard
    if (data32) {
2352 2c0262af bellard
        /* 32 bit */
2353 2c0262af bellard
        stl(ptr, env->fpuc);
2354 2c0262af bellard
        stl(ptr + 4, fpus);
2355 2c0262af bellard
        stl(ptr + 8, fptag);
2356 2edcdce3 bellard
        stl(ptr + 12, 0); /* fpip */
2357 2edcdce3 bellard
        stl(ptr + 16, 0); /* fpcs */
2358 2edcdce3 bellard
        stl(ptr + 20, 0); /* fpoo */
2359 2edcdce3 bellard
        stl(ptr + 24, 0); /* fpos */
2360 2c0262af bellard
    } else {
2361 2c0262af bellard
        /* 16 bit */
2362 2c0262af bellard
        stw(ptr, env->fpuc);
2363 2c0262af bellard
        stw(ptr + 2, fpus);
2364 2c0262af bellard
        stw(ptr + 4, fptag);
2365 2c0262af bellard
        stw(ptr + 6, 0);
2366 2c0262af bellard
        stw(ptr + 8, 0);
2367 2c0262af bellard
        stw(ptr + 10, 0);
2368 2c0262af bellard
        stw(ptr + 12, 0);
2369 2c0262af bellard
    }
2370 2c0262af bellard
}
2371 2c0262af bellard
2372 2c0262af bellard
void helper_fldenv(uint8_t *ptr, int data32)
2373 2c0262af bellard
{
2374 2c0262af bellard
    int i, fpus, fptag;
2375 2c0262af bellard
2376 2c0262af bellard
    if (data32) {
2377 2c0262af bellard
        env->fpuc = lduw(ptr);
2378 2c0262af bellard
        fpus = lduw(ptr + 4);
2379 2c0262af bellard
        fptag = lduw(ptr + 8);
2380 2c0262af bellard
    }
2381 2c0262af bellard
    else {
2382 2c0262af bellard
        env->fpuc = lduw(ptr);
2383 2c0262af bellard
        fpus = lduw(ptr + 2);
2384 2c0262af bellard
        fptag = lduw(ptr + 4);
2385 2c0262af bellard
    }
2386 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
2387 2c0262af bellard
    env->fpus = fpus & ~0x3800;
2388 2edcdce3 bellard
    for(i = 0;i < 8; i++) {
2389 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
2390 2c0262af bellard
        fptag >>= 2;
2391 2c0262af bellard
    }
2392 2c0262af bellard
}
2393 2c0262af bellard
2394 2c0262af bellard
void helper_fsave(uint8_t *ptr, int data32)
2395 2c0262af bellard
{
2396 2c0262af bellard
    CPU86_LDouble tmp;
2397 2c0262af bellard
    int i;
2398 2c0262af bellard
2399 2c0262af bellard
    helper_fstenv(ptr, data32);
2400 2c0262af bellard
2401 2c0262af bellard
    ptr += (14 << data32);
2402 2c0262af bellard
    for(i = 0;i < 8; i++) {
2403 2c0262af bellard
        tmp = ST(i);
2404 2c0262af bellard
        helper_fstt(tmp, ptr);
2405 2c0262af bellard
        ptr += 10;
2406 2c0262af bellard
    }
2407 2c0262af bellard
2408 2c0262af bellard
    /* fninit */
2409 2c0262af bellard
    env->fpus = 0;
2410 2c0262af bellard
    env->fpstt = 0;
2411 2c0262af bellard
    env->fpuc = 0x37f;
2412 2c0262af bellard
    env->fptags[0] = 1;
2413 2c0262af bellard
    env->fptags[1] = 1;
2414 2c0262af bellard
    env->fptags[2] = 1;
2415 2c0262af bellard
    env->fptags[3] = 1;
2416 2c0262af bellard
    env->fptags[4] = 1;
2417 2c0262af bellard
    env->fptags[5] = 1;
2418 2c0262af bellard
    env->fptags[6] = 1;
2419 2c0262af bellard
    env->fptags[7] = 1;
2420 2c0262af bellard
}
2421 2c0262af bellard
2422 2c0262af bellard
void helper_frstor(uint8_t *ptr, int data32)
2423 2c0262af bellard
{
2424 2c0262af bellard
    CPU86_LDouble tmp;
2425 2c0262af bellard
    int i;
2426 2c0262af bellard
2427 2c0262af bellard
    helper_fldenv(ptr, data32);
2428 2c0262af bellard
    ptr += (14 << data32);
2429 2c0262af bellard
2430 2c0262af bellard
    for(i = 0;i < 8; i++) {
2431 2c0262af bellard
        tmp = helper_fldt(ptr);
2432 2c0262af bellard
        ST(i) = tmp;
2433 2c0262af bellard
        ptr += 10;
2434 2c0262af bellard
    }
2435 2c0262af bellard
}
2436 2c0262af bellard
2437 1f1af9fd bellard
/* XXX: merge with helper_fstt ? */
2438 1f1af9fd bellard
2439 1f1af9fd bellard
#ifndef USE_X86LDOUBLE
2440 1f1af9fd bellard
2441 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
2442 1f1af9fd bellard
{
2443 1f1af9fd bellard
    CPU86_LDoubleU temp;
2444 1f1af9fd bellard
    int e;
2445 1f1af9fd bellard
2446 1f1af9fd bellard
    temp.d = f;
2447 1f1af9fd bellard
    /* mantissa */
2448 1f1af9fd bellard
    *pmant = (MANTD(temp) << 11) | (1LL << 63);
2449 1f1af9fd bellard
    /* exponent + sign */
2450 1f1af9fd bellard
    e = EXPD(temp) - EXPBIAS + 16383;
2451 1f1af9fd bellard
    e |= SIGND(temp) >> 16;
2452 1f1af9fd bellard
    *pexp = e;
2453 1f1af9fd bellard
}
2454 1f1af9fd bellard
2455 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
2456 1f1af9fd bellard
{
2457 1f1af9fd bellard
    CPU86_LDoubleU temp;
2458 1f1af9fd bellard
    int e;
2459 1f1af9fd bellard
    uint64_t ll;
2460 1f1af9fd bellard
2461 1f1af9fd bellard
    /* XXX: handle overflow ? */
2462 1f1af9fd bellard
    e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
2463 1f1af9fd bellard
    e |= (upper >> 4) & 0x800; /* sign */
2464 1f1af9fd bellard
    ll = (mant >> 11) & ((1LL << 52) - 1);
2465 1f1af9fd bellard
#ifdef __arm__
2466 1f1af9fd bellard
    temp.l.upper = (e << 20) | (ll >> 32);
2467 1f1af9fd bellard
    temp.l.lower = ll;
2468 1f1af9fd bellard
#else
2469 1f1af9fd bellard
    temp.ll = ll | ((uint64_t)e << 52);
2470 1f1af9fd bellard
#endif
2471 1f1af9fd bellard
    return temp.d;
2472 1f1af9fd bellard
}
2473 1f1af9fd bellard
2474 1f1af9fd bellard
#else
2475 1f1af9fd bellard
2476 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
2477 1f1af9fd bellard
{
2478 1f1af9fd bellard
    CPU86_LDoubleU temp;
2479 1f1af9fd bellard
2480 1f1af9fd bellard
    temp.d = f;
2481 1f1af9fd bellard
    *pmant = temp.l.lower;
2482 1f1af9fd bellard
    *pexp = temp.l.upper;
2483 1f1af9fd bellard
}
2484 1f1af9fd bellard
2485 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
2486 1f1af9fd bellard
{
2487 1f1af9fd bellard
    CPU86_LDoubleU temp;
2488 1f1af9fd bellard
2489 1f1af9fd bellard
    temp.l.upper = upper;
2490 1f1af9fd bellard
    temp.l.lower = mant;
2491 1f1af9fd bellard
    return temp.d;
2492 1f1af9fd bellard
}
2493 1f1af9fd bellard
#endif
2494 1f1af9fd bellard
2495 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
2496 61382a50 bellard
2497 61382a50 bellard
#define MMUSUFFIX _mmu
2498 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
2499 61382a50 bellard
2500 2c0262af bellard
#define SHIFT 0
2501 2c0262af bellard
#include "softmmu_template.h"
2502 2c0262af bellard
2503 2c0262af bellard
#define SHIFT 1
2504 2c0262af bellard
#include "softmmu_template.h"
2505 2c0262af bellard
2506 2c0262af bellard
#define SHIFT 2
2507 2c0262af bellard
#include "softmmu_template.h"
2508 2c0262af bellard
2509 2c0262af bellard
#define SHIFT 3
2510 2c0262af bellard
#include "softmmu_template.h"
2511 2c0262af bellard
2512 61382a50 bellard
#endif
2513 61382a50 bellard
2514 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
2515 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
2516 61382a50 bellard
   from generated code or from helper.c) */
2517 61382a50 bellard
/* XXX: fix it to restore all registers */
2518 61382a50 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2519 2c0262af bellard
{
2520 2c0262af bellard
    TranslationBlock *tb;
2521 2c0262af bellard
    int ret;
2522 2c0262af bellard
    unsigned long pc;
2523 61382a50 bellard
    CPUX86State *saved_env;
2524 61382a50 bellard
2525 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
2526 61382a50 bellard
       generated code */
2527 61382a50 bellard
    saved_env = env;
2528 61382a50 bellard
    env = cpu_single_env;
2529 61382a50 bellard
2530 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
2531 2c0262af bellard
    if (ret) {
2532 61382a50 bellard
        if (retaddr) {
2533 61382a50 bellard
            /* now we have a real cpu fault */
2534 61382a50 bellard
            pc = (unsigned long)retaddr;
2535 61382a50 bellard
            tb = tb_find_pc(pc);
2536 61382a50 bellard
            if (tb) {
2537 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
2538 61382a50 bellard
                   a virtual CPU fault */
2539 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
2540 61382a50 bellard
            }
2541 2c0262af bellard
        }
2542 2c0262af bellard
        raise_exception_err(EXCP0E_PAGE, env->error_code);
2543 2c0262af bellard
    }
2544 61382a50 bellard
    env = saved_env;
2545 2c0262af bellard
}