Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 08cea4ee

History | View | Annotate | Download (70.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 8145122b bellard
    printf("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 8e682019 bellard
            /* XXX: explain me why W2K hangs if the whole segment cache is
762 8e682019 bellard
               reset ? */
763 8145122b bellard
#if 1
764 8e682019 bellard
            env->segs[R_ES].selector = 0;
765 8e682019 bellard
            env->segs[R_ES].flags = 0;
766 8e682019 bellard
            env->segs[R_DS].selector = 0;
767 8e682019 bellard
            env->segs[R_DS].flags = 0;
768 8e682019 bellard
            env->segs[R_FS].selector = 0;
769 8e682019 bellard
            env->segs[R_FS].flags = 0;
770 8e682019 bellard
            env->segs[R_GS].selector = 0;
771 8e682019 bellard
            env->segs[R_GS].flags = 0;
772 8145122b bellard
#else
773 8145122b bellard
            cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0);
774 8145122b bellard
            cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0);
775 8145122b bellard
            cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0);
776 8145122b bellard
            cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0);
777 8145122b bellard
#endif
778 8e682019 bellard
        }
779 891b38e4 bellard
        ss = (ss & ~3) | dpl;
780 891b38e4 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
781 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
782 891b38e4 bellard
    }
783 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (esp & sp_mask);
784 891b38e4 bellard
785 891b38e4 bellard
    selector = (selector & ~3) | dpl;
786 891b38e4 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
787 891b38e4 bellard
                   get_seg_base(e1, e2),
788 891b38e4 bellard
                   get_seg_limit(e1, e2),
789 891b38e4 bellard
                   e2);
790 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
791 891b38e4 bellard
    env->eip = offset;
792 891b38e4 bellard
793 2c0262af bellard
    /* interrupt gate clear IF mask */
794 2c0262af bellard
    if ((type & 1) == 0) {
795 2c0262af bellard
        env->eflags &= ~IF_MASK;
796 2c0262af bellard
    }
797 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
798 2c0262af bellard
}
799 2c0262af bellard
800 2c0262af bellard
/* real mode interrupt */
801 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
802 4136f33c bellard
                              unsigned int next_eip)
803 2c0262af bellard
{
804 2c0262af bellard
    SegmentCache *dt;
805 2c0262af bellard
    uint8_t *ptr, *ssp;
806 2c0262af bellard
    int selector;
807 2c0262af bellard
    uint32_t offset, esp;
808 2c0262af bellard
    uint32_t old_cs, old_eip;
809 2c0262af bellard
810 2c0262af bellard
    /* real mode (simpler !) */
811 2c0262af bellard
    dt = &env->idt;
812 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
813 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
814 2c0262af bellard
    ptr = dt->base + intno * 4;
815 61382a50 bellard
    offset = lduw_kernel(ptr);
816 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
817 2c0262af bellard
    esp = ESP;
818 2c0262af bellard
    ssp = env->segs[R_SS].base;
819 2c0262af bellard
    if (is_int)
820 2c0262af bellard
        old_eip = next_eip;
821 2c0262af bellard
    else
822 2c0262af bellard
        old_eip = env->eip;
823 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
824 891b38e4 bellard
    /* XXX: use SS segment size ? */
825 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
826 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
827 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
828 2c0262af bellard
    
829 2c0262af bellard
    /* update processor state */
830 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
831 2c0262af bellard
    env->eip = offset;
832 2c0262af bellard
    env->segs[R_CS].selector = selector;
833 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(selector << 4);
834 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
835 2c0262af bellard
}
836 2c0262af bellard
837 2c0262af bellard
/* fake user mode interrupt */
838 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
839 2c0262af bellard
                       unsigned int next_eip)
840 2c0262af bellard
{
841 2c0262af bellard
    SegmentCache *dt;
842 2c0262af bellard
    uint8_t *ptr;
843 2c0262af bellard
    int dpl, cpl;
844 2c0262af bellard
    uint32_t e2;
845 2c0262af bellard
846 2c0262af bellard
    dt = &env->idt;
847 2c0262af bellard
    ptr = dt->base + (intno * 8);
848 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
849 2c0262af bellard
    
850 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
851 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
852 2c0262af bellard
    /* check privledge if software int */
853 2c0262af bellard
    if (is_int && dpl < cpl)
854 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
855 2c0262af bellard
856 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
857 2c0262af bellard
       exiting the emulation with the suitable exception and error
858 2c0262af bellard
       code */
859 2c0262af bellard
    if (is_int)
860 2c0262af bellard
        EIP = next_eip;
861 2c0262af bellard
}
862 2c0262af bellard
863 2c0262af bellard
/*
864 e19e89a5 bellard
 * Begin execution of an interruption. is_int is TRUE if coming from
865 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
866 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
867 2c0262af bellard
 */
868 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
869 2c0262af bellard
                  unsigned int next_eip, int is_hw)
870 2c0262af bellard
{
871 e19e89a5 bellard
#ifdef DEBUG_PCALL
872 e19e89a5 bellard
    if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) {
873 e19e89a5 bellard
        if ((env->cr[0] & CR0_PE_MASK)) {
874 e19e89a5 bellard
            static int count;
875 e19e89a5 bellard
            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x SP=%04x:%08x",
876 dc6f57fd bellard
                    count, intno, error_code, is_int,
877 dc6f57fd bellard
                    env->hflags & HF_CPL_MASK,
878 dc6f57fd bellard
                    env->segs[R_CS].selector, EIP,
879 8145122b bellard
                    env->segs[R_SS].selector, ESP);
880 8145122b bellard
            if (intno == 0x0e) {
881 e19e89a5 bellard
                fprintf(logfile, " CR2=%08x", env->cr[2]);
882 8145122b bellard
            } else {
883 e19e89a5 bellard
                fprintf(logfile, " EAX=%08x", env->regs[R_EAX]);
884 8145122b bellard
            }
885 e19e89a5 bellard
            fprintf(logfile, "\n");
886 dc6f57fd bellard
#if 0
887 e19e89a5 bellard
            cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
888 e19e89a5 bellard
            {
889 e19e89a5 bellard
                int i;
890 e19e89a5 bellard
                uint8_t *ptr;
891 e19e89a5 bellard
                fprintf(logfile, "       code=");
892 e19e89a5 bellard
                ptr = env->segs[R_CS].base + env->eip;
893 e19e89a5 bellard
                for(i = 0; i < 16; i++) {
894 e19e89a5 bellard
                    fprintf(logfile, " %02x", ldub(ptr + i));
895 dc6f57fd bellard
                }
896 e19e89a5 bellard
                fprintf(logfile, "\n");
897 dc6f57fd bellard
            }
898 8e682019 bellard
#endif
899 e19e89a5 bellard
            count++;
900 4136f33c bellard
        }
901 4136f33c bellard
    }
902 4136f33c bellard
#endif
903 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
904 2c0262af bellard
        do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
905 2c0262af bellard
    } else {
906 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
907 2c0262af bellard
    }
908 2c0262af bellard
}
909 2c0262af bellard
910 2c0262af bellard
/*
911 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
912 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
913 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
914 2c0262af bellard
 * is_int is TRUE.  
915 2c0262af bellard
 */
916 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
917 2c0262af bellard
                     unsigned int next_eip)
918 2c0262af bellard
{
919 2c0262af bellard
    env->exception_index = intno;
920 2c0262af bellard
    env->error_code = error_code;
921 2c0262af bellard
    env->exception_is_int = is_int;
922 2c0262af bellard
    env->exception_next_eip = next_eip;
923 2c0262af bellard
    cpu_loop_exit();
924 2c0262af bellard
}
925 2c0262af bellard
926 2c0262af bellard
/* shortcuts to generate exceptions */
927 8145122b bellard
928 8145122b bellard
void (raise_exception_err)(int exception_index, int error_code)
929 2c0262af bellard
{
930 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
931 2c0262af bellard
}
932 2c0262af bellard
933 2c0262af bellard
void raise_exception(int exception_index)
934 2c0262af bellard
{
935 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
936 2c0262af bellard
}
937 2c0262af bellard
938 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
939 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
940 2c0262af bellard
   call it from another function */
941 2c0262af bellard
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
942 2c0262af bellard
{
943 2c0262af bellard
    *q_ptr = num / den;
944 2c0262af bellard
    return num % den;
945 2c0262af bellard
}
946 2c0262af bellard
947 2c0262af bellard
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
948 2c0262af bellard
{
949 2c0262af bellard
    *q_ptr = num / den;
950 2c0262af bellard
    return num % den;
951 2c0262af bellard
}
952 2c0262af bellard
#endif
953 2c0262af bellard
954 2c0262af bellard
void helper_divl_EAX_T0(uint32_t eip)
955 2c0262af bellard
{
956 2c0262af bellard
    unsigned int den, q, r;
957 2c0262af bellard
    uint64_t num;
958 2c0262af bellard
    
959 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
960 2c0262af bellard
    den = T0;
961 2c0262af bellard
    if (den == 0) {
962 2c0262af bellard
        EIP = eip;
963 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
964 2c0262af bellard
    }
965 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
966 2c0262af bellard
    r = div64(&q, num, den);
967 2c0262af bellard
#else
968 2c0262af bellard
    q = (num / den);
969 2c0262af bellard
    r = (num % den);
970 2c0262af bellard
#endif
971 2c0262af bellard
    EAX = q;
972 2c0262af bellard
    EDX = r;
973 2c0262af bellard
}
974 2c0262af bellard
975 2c0262af bellard
void helper_idivl_EAX_T0(uint32_t eip)
976 2c0262af bellard
{
977 2c0262af bellard
    int den, q, r;
978 2c0262af bellard
    int64_t num;
979 2c0262af bellard
    
980 2c0262af bellard
    num = EAX | ((uint64_t)EDX << 32);
981 2c0262af bellard
    den = T0;
982 2c0262af bellard
    if (den == 0) {
983 2c0262af bellard
        EIP = eip;
984 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
985 2c0262af bellard
    }
986 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
987 2c0262af bellard
    r = idiv64(&q, num, den);
988 2c0262af bellard
#else
989 2c0262af bellard
    q = (num / den);
990 2c0262af bellard
    r = (num % den);
991 2c0262af bellard
#endif
992 2c0262af bellard
    EAX = q;
993 2c0262af bellard
    EDX = r;
994 2c0262af bellard
}
995 2c0262af bellard
996 2c0262af bellard
void helper_cmpxchg8b(void)
997 2c0262af bellard
{
998 2c0262af bellard
    uint64_t d;
999 2c0262af bellard
    int eflags;
1000 2c0262af bellard
1001 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
1002 2c0262af bellard
    d = ldq((uint8_t *)A0);
1003 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
1004 2c0262af bellard
        stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
1005 2c0262af bellard
        eflags |= CC_Z;
1006 2c0262af bellard
    } else {
1007 2c0262af bellard
        EDX = d >> 32;
1008 2c0262af bellard
        EAX = d;
1009 2c0262af bellard
        eflags &= ~CC_Z;
1010 2c0262af bellard
    }
1011 2c0262af bellard
    CC_SRC = eflags;
1012 2c0262af bellard
}
1013 2c0262af bellard
1014 2c0262af bellard
#define CPUID_FP87 (1 << 0)
1015 2c0262af bellard
#define CPUID_VME  (1 << 1)
1016 2c0262af bellard
#define CPUID_DE   (1 << 2)
1017 2c0262af bellard
#define CPUID_PSE  (1 << 3)
1018 2c0262af bellard
#define CPUID_TSC  (1 << 4)
1019 2c0262af bellard
#define CPUID_MSR  (1 << 5)
1020 2c0262af bellard
#define CPUID_PAE  (1 << 6)
1021 2c0262af bellard
#define CPUID_MCE  (1 << 7)
1022 2c0262af bellard
#define CPUID_CX8  (1 << 8)
1023 2c0262af bellard
#define CPUID_APIC (1 << 9)
1024 2c0262af bellard
#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
1025 2c0262af bellard
#define CPUID_MTRR (1 << 12)
1026 2c0262af bellard
#define CPUID_PGE  (1 << 13)
1027 2c0262af bellard
#define CPUID_MCA  (1 << 14)
1028 2c0262af bellard
#define CPUID_CMOV (1 << 15)
1029 2c0262af bellard
/* ... */
1030 2c0262af bellard
#define CPUID_MMX  (1 << 23)
1031 2c0262af bellard
#define CPUID_FXSR (1 << 24)
1032 2c0262af bellard
#define CPUID_SSE  (1 << 25)
1033 2c0262af bellard
#define CPUID_SSE2 (1 << 26)
1034 2c0262af bellard
1035 2c0262af bellard
void helper_cpuid(void)
1036 2c0262af bellard
{
1037 8e682019 bellard
    switch(EAX) {
1038 8e682019 bellard
    case 0:
1039 8e682019 bellard
        EAX = 2; /* max EAX index supported */
1040 2c0262af bellard
        EBX = 0x756e6547;
1041 2c0262af bellard
        ECX = 0x6c65746e;
1042 2c0262af bellard
        EDX = 0x49656e69;
1043 8e682019 bellard
        break;
1044 8e682019 bellard
    case 1:
1045 8e682019 bellard
        {
1046 8e682019 bellard
            int family, model, stepping;
1047 8e682019 bellard
            /* EAX = 1 info */
1048 2c0262af bellard
#if 0
1049 8e682019 bellard
            /* pentium 75-200 */
1050 8e682019 bellard
            family = 5;
1051 8e682019 bellard
            model = 2;
1052 8e682019 bellard
            stepping = 11;
1053 2c0262af bellard
#else
1054 8e682019 bellard
            /* pentium pro */
1055 8e682019 bellard
            family = 6;
1056 8e682019 bellard
            model = 1;
1057 8e682019 bellard
            stepping = 3;
1058 2c0262af bellard
#endif
1059 8e682019 bellard
            EAX = (family << 8) | (model << 4) | stepping;
1060 8e682019 bellard
            EBX = 0;
1061 8e682019 bellard
            ECX = 0;
1062 8e682019 bellard
            EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
1063 8e682019 bellard
                CPUID_TSC | CPUID_MSR | CPUID_MCE |
1064 8e682019 bellard
                CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
1065 8e682019 bellard
        }
1066 8e682019 bellard
        break;
1067 8e682019 bellard
    default:
1068 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1069 8e682019 bellard
        EAX = 0x410601;
1070 2c0262af bellard
        EBX = 0;
1071 2c0262af bellard
        ECX = 0;
1072 8e682019 bellard
        EDX = 0;
1073 8e682019 bellard
        break;
1074 2c0262af bellard
    }
1075 2c0262af bellard
}
1076 2c0262af bellard
1077 2c0262af bellard
void helper_lldt_T0(void)
1078 2c0262af bellard
{
1079 2c0262af bellard
    int selector;
1080 2c0262af bellard
    SegmentCache *dt;
1081 2c0262af bellard
    uint32_t e1, e2;
1082 2c0262af bellard
    int index;
1083 2c0262af bellard
    uint8_t *ptr;
1084 2c0262af bellard
    
1085 2c0262af bellard
    selector = T0 & 0xffff;
1086 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1087 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1088 2c0262af bellard
        env->ldt.base = NULL;
1089 2c0262af bellard
        env->ldt.limit = 0;
1090 2c0262af bellard
    } else {
1091 2c0262af bellard
        if (selector & 0x4)
1092 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1093 2c0262af bellard
        dt = &env->gdt;
1094 2c0262af bellard
        index = selector & ~7;
1095 2c0262af bellard
        if ((index + 7) > dt->limit)
1096 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1097 2c0262af bellard
        ptr = dt->base + index;
1098 61382a50 bellard
        e1 = ldl_kernel(ptr);
1099 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1100 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1101 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1102 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1103 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1104 2c0262af bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
1105 2c0262af bellard
    }
1106 2c0262af bellard
    env->ldt.selector = selector;
1107 2c0262af bellard
}
1108 2c0262af bellard
1109 2c0262af bellard
void helper_ltr_T0(void)
1110 2c0262af bellard
{
1111 2c0262af bellard
    int selector;
1112 2c0262af bellard
    SegmentCache *dt;
1113 2c0262af bellard
    uint32_t e1, e2;
1114 2c0262af bellard
    int index, type;
1115 2c0262af bellard
    uint8_t *ptr;
1116 2c0262af bellard
    
1117 2c0262af bellard
    selector = T0 & 0xffff;
1118 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1119 2c0262af bellard
        /* NULL selector case: invalid LDT */
1120 2c0262af bellard
        env->tr.base = NULL;
1121 2c0262af bellard
        env->tr.limit = 0;
1122 2c0262af bellard
        env->tr.flags = 0;
1123 2c0262af bellard
    } else {
1124 2c0262af bellard
        if (selector & 0x4)
1125 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1126 2c0262af bellard
        dt = &env->gdt;
1127 2c0262af bellard
        index = selector & ~7;
1128 2c0262af bellard
        if ((index + 7) > dt->limit)
1129 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1130 2c0262af bellard
        ptr = dt->base + index;
1131 61382a50 bellard
        e1 = ldl_kernel(ptr);
1132 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1133 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1134 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
1135 7e84c249 bellard
            (type != 1 && type != 9))
1136 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1137 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1138 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1139 2c0262af bellard
        load_seg_cache_raw_dt(&env->tr, e1, e2);
1140 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1141 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1142 2c0262af bellard
    }
1143 2c0262af bellard
    env->tr.selector = selector;
1144 2c0262af bellard
}
1145 2c0262af bellard
1146 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1147 8e682019 bellard
void load_seg(int seg_reg, int selector)
1148 2c0262af bellard
{
1149 2c0262af bellard
    uint32_t e1, e2;
1150 3ab493de bellard
    int cpl, dpl, rpl;
1151 3ab493de bellard
    SegmentCache *dt;
1152 3ab493de bellard
    int index;
1153 3ab493de bellard
    uint8_t *ptr;
1154 3ab493de bellard
1155 8e682019 bellard
    selector &= 0xffff;
1156 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1157 2c0262af bellard
        /* null selector case */
1158 8e682019 bellard
        if (seg_reg == R_SS)
1159 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1160 8e682019 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
1161 2c0262af bellard
    } else {
1162 3ab493de bellard
        
1163 3ab493de bellard
        if (selector & 0x4)
1164 3ab493de bellard
            dt = &env->ldt;
1165 3ab493de bellard
        else
1166 3ab493de bellard
            dt = &env->gdt;
1167 3ab493de bellard
        index = selector & ~7;
1168 8e682019 bellard
        if ((index + 7) > dt->limit)
1169 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1170 3ab493de bellard
        ptr = dt->base + index;
1171 3ab493de bellard
        e1 = ldl_kernel(ptr);
1172 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1173 3ab493de bellard
1174 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1175 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1176 3ab493de bellard
        rpl = selector & 3;
1177 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1178 3ab493de bellard
        cpl = env->hflags & HF_CPL_MASK;
1179 2c0262af bellard
        if (seg_reg == R_SS) {
1180 3ab493de bellard
            /* must be writable segment */
1181 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1182 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1183 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1184 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1185 2c0262af bellard
        } else {
1186 3ab493de bellard
            /* must be readable segment */
1187 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1188 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1189 3ab493de bellard
            
1190 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1191 3ab493de bellard
                /* if not conforming code, test rights */
1192 8e682019 bellard
                if (dpl < cpl || dpl < rpl)
1193 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1194 3ab493de bellard
            }
1195 2c0262af bellard
        }
1196 2c0262af bellard
1197 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1198 2c0262af bellard
            if (seg_reg == R_SS)
1199 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1200 2c0262af bellard
            else
1201 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1202 2c0262af bellard
        }
1203 3ab493de bellard
1204 3ab493de bellard
        /* set the access bit if not already set */
1205 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1206 3ab493de bellard
            e2 |= DESC_A_MASK;
1207 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1208 3ab493de bellard
        }
1209 3ab493de bellard
1210 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
1211 2c0262af bellard
                       get_seg_base(e1, e2),
1212 2c0262af bellard
                       get_seg_limit(e1, e2),
1213 2c0262af bellard
                       e2);
1214 2c0262af bellard
#if 0
1215 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
1216 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1217 2c0262af bellard
#endif
1218 2c0262af bellard
    }
1219 2c0262af bellard
}
1220 2c0262af bellard
1221 2c0262af bellard
/* protected mode jump */
1222 08cea4ee bellard
void helper_ljmp_protected_T0_T1(int next_eip)
1223 2c0262af bellard
{
1224 7e84c249 bellard
    int new_cs, new_eip, gate_cs, type;
1225 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
1226 2c0262af bellard
1227 2c0262af bellard
    new_cs = T0;
1228 2c0262af bellard
    new_eip = T1;
1229 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1230 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1231 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1232 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1233 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1234 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1235 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1236 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1237 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1238 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1239 2c0262af bellard
            /* conforming code segment */
1240 2c0262af bellard
            if (dpl > cpl)
1241 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1242 2c0262af bellard
        } else {
1243 2c0262af bellard
            /* non conforming code segment */
1244 2c0262af bellard
            rpl = new_cs & 3;
1245 2c0262af bellard
            if (rpl > cpl)
1246 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1247 2c0262af bellard
            if (dpl != cpl)
1248 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1249 2c0262af bellard
        }
1250 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1251 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1252 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1253 2c0262af bellard
        if (new_eip > limit)
1254 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1255 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1256 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1257 2c0262af bellard
        EIP = new_eip;
1258 2c0262af bellard
    } else {
1259 7e84c249 bellard
        /* jump to call or task gate */
1260 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1261 7e84c249 bellard
        rpl = new_cs & 3;
1262 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
1263 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1264 7e84c249 bellard
        switch(type) {
1265 7e84c249 bellard
        case 1: /* 286 TSS */
1266 7e84c249 bellard
        case 9: /* 386 TSS */
1267 7e84c249 bellard
        case 5: /* task gate */
1268 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1269 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1270 08cea4ee bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
1271 7e84c249 bellard
            break;
1272 7e84c249 bellard
        case 4: /* 286 call gate */
1273 7e84c249 bellard
        case 12: /* 386 call gate */
1274 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
1275 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1276 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1277 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1278 7e84c249 bellard
            gate_cs = e1 >> 16;
1279 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
1280 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1281 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1282 7e84c249 bellard
            /* must be code segment */
1283 7e84c249 bellard
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
1284 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
1285 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1286 7e84c249 bellard
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
1287 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
1288 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1289 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
1290 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
1291 7e84c249 bellard
            new_eip = (e1 & 0xffff);
1292 7e84c249 bellard
            if (type == 12)
1293 7e84c249 bellard
                new_eip |= (e2 & 0xffff0000);
1294 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
1295 7e84c249 bellard
            if (new_eip > limit)
1296 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
1297 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
1298 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
1299 7e84c249 bellard
            EIP = new_eip;
1300 7e84c249 bellard
            break;
1301 7e84c249 bellard
        default:
1302 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1303 7e84c249 bellard
            break;
1304 7e84c249 bellard
        }
1305 2c0262af bellard
    }
1306 2c0262af bellard
}
1307 2c0262af bellard
1308 2c0262af bellard
/* real mode call */
1309 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
1310 2c0262af bellard
{
1311 2c0262af bellard
    int new_cs, new_eip;
1312 2c0262af bellard
    uint32_t esp, esp_mask;
1313 2c0262af bellard
    uint8_t *ssp;
1314 2c0262af bellard
1315 2c0262af bellard
    new_cs = T0;
1316 2c0262af bellard
    new_eip = T1;
1317 2c0262af bellard
    esp = ESP;
1318 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1319 2c0262af bellard
    ssp = env->segs[R_SS].base;
1320 2c0262af bellard
    if (shift) {
1321 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1322 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
1323 2c0262af bellard
    } else {
1324 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1325 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
1326 2c0262af bellard
    }
1327 2c0262af bellard
1328 891b38e4 bellard
    ESP = (ESP & ~esp_mask) | (esp & esp_mask);
1329 2c0262af bellard
    env->eip = new_eip;
1330 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
1331 2c0262af bellard
    env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
1332 2c0262af bellard
}
1333 2c0262af bellard
1334 2c0262af bellard
/* protected mode call */
1335 2c0262af bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip)
1336 2c0262af bellard
{
1337 891b38e4 bellard
    int new_cs, new_eip, new_stack, i;
1338 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1339 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1340 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
1341 2c0262af bellard
    uint8_t *ssp, *old_ssp;
1342 2c0262af bellard
    
1343 2c0262af bellard
    new_cs = T0;
1344 2c0262af bellard
    new_eip = T1;
1345 f3f2d9be bellard
#ifdef DEBUG_PCALL
1346 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
1347 e19e89a5 bellard
        fprintf(logfile, "lcall %04x:%08x s=%d\n",
1348 e19e89a5 bellard
                new_cs, new_eip, shift);
1349 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1350 f3f2d9be bellard
    }
1351 f3f2d9be bellard
#endif
1352 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1353 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1354 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1355 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1356 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1357 f3f2d9be bellard
#ifdef DEBUG_PCALL
1358 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
1359 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
1360 f3f2d9be bellard
    }
1361 f3f2d9be bellard
#endif
1362 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1363 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1364 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1365 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1366 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1367 2c0262af bellard
            /* conforming code segment */
1368 2c0262af bellard
            if (dpl > cpl)
1369 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1370 2c0262af bellard
        } else {
1371 2c0262af bellard
            /* non conforming code segment */
1372 2c0262af bellard
            rpl = new_cs & 3;
1373 2c0262af bellard
            if (rpl > cpl)
1374 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1375 2c0262af bellard
            if (dpl != cpl)
1376 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1377 2c0262af bellard
        }
1378 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1379 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1380 2c0262af bellard
1381 2c0262af bellard
        sp = ESP;
1382 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
1383 891b38e4 bellard
        ssp = env->segs[R_SS].base;
1384 2c0262af bellard
        if (shift) {
1385 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1386 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1387 2c0262af bellard
        } else {
1388 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1389 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1390 2c0262af bellard
        }
1391 2c0262af bellard
        
1392 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1393 2c0262af bellard
        if (new_eip > limit)
1394 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1395 2c0262af bellard
        /* from this point, not restartable */
1396 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1397 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1398 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1399 2c0262af bellard
        EIP = new_eip;
1400 2c0262af bellard
    } else {
1401 2c0262af bellard
        /* check gate type */
1402 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
1403 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1404 7e84c249 bellard
        rpl = new_cs & 3;
1405 2c0262af bellard
        switch(type) {
1406 2c0262af bellard
        case 1: /* available 286 TSS */
1407 2c0262af bellard
        case 9: /* available 386 TSS */
1408 2c0262af bellard
        case 5: /* task gate */
1409 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
1410 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1411 883da8e2 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
1412 8145122b bellard
            return;
1413 2c0262af bellard
        case 4: /* 286 call gate */
1414 2c0262af bellard
        case 12: /* 386 call gate */
1415 2c0262af bellard
            break;
1416 2c0262af bellard
        default:
1417 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1418 2c0262af bellard
            break;
1419 2c0262af bellard
        }
1420 2c0262af bellard
        shift = type >> 3;
1421 2c0262af bellard
1422 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
1423 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1424 2c0262af bellard
        /* check valid bit */
1425 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1426 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
1427 2c0262af bellard
        selector = e1 >> 16;
1428 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
1429 f3f2d9be bellard
        param_count = e2 & 0x1f;
1430 2c0262af bellard
        if ((selector & 0xfffc) == 0)
1431 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1432 2c0262af bellard
1433 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
1434 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1435 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
1436 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1437 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1438 2c0262af bellard
        if (dpl > cpl)
1439 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1440 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1441 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1442 2c0262af bellard
1443 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
1444 2c0262af bellard
            /* to inner priviledge */
1445 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
1446 f3f2d9be bellard
#ifdef DEBUG_PCALL
1447 e19e89a5 bellard
            if (loglevel & CPU_LOG_PCALL)
1448 e19e89a5 bellard
                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=%x\n", 
1449 f3f2d9be bellard
                        ss, sp, param_count, ESP);
1450 f3f2d9be bellard
#endif
1451 2c0262af bellard
            if ((ss & 0xfffc) == 0)
1452 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1453 2c0262af bellard
            if ((ss & 3) != dpl)
1454 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1455 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
1456 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1457 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1458 2c0262af bellard
            if (ss_dpl != dpl)
1459 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1460 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
1461 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
1462 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
1463 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1464 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
1465 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1466 2c0262af bellard
            
1467 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
1468 2c0262af bellard
1469 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1470 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
1471 2c0262af bellard
            
1472 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
1473 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
1474 2c0262af bellard
            if (shift) {
1475 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1476 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
1477 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1478 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1479 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
1480 2c0262af bellard
                }
1481 2c0262af bellard
            } else {
1482 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1483 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
1484 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
1485 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1486 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
1487 2c0262af bellard
                }
1488 2c0262af bellard
            }
1489 891b38e4 bellard
            new_stack = 1;
1490 2c0262af bellard
        } else {
1491 2c0262af bellard
            /* to same priviledge */
1492 891b38e4 bellard
            sp = ESP;
1493 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
1494 891b38e4 bellard
            ssp = env->segs[R_SS].base;
1495 891b38e4 bellard
            //            push_size = (4 << shift);
1496 891b38e4 bellard
            new_stack = 0;
1497 2c0262af bellard
        }
1498 2c0262af bellard
1499 2c0262af bellard
        if (shift) {
1500 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1501 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
1502 2c0262af bellard
        } else {
1503 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1504 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
1505 891b38e4 bellard
        }
1506 891b38e4 bellard
1507 891b38e4 bellard
        /* from this point, not restartable */
1508 891b38e4 bellard
1509 891b38e4 bellard
        if (new_stack) {
1510 891b38e4 bellard
            ss = (ss & ~3) | dpl;
1511 891b38e4 bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
1512 891b38e4 bellard
                                   ssp,
1513 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
1514 891b38e4 bellard
                                   ss_e2);
1515 2c0262af bellard
        }
1516 2c0262af bellard
1517 2c0262af bellard
        selector = (selector & ~3) | dpl;
1518 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
1519 2c0262af bellard
                       get_seg_base(e1, e2),
1520 2c0262af bellard
                       get_seg_limit(e1, e2),
1521 2c0262af bellard
                       e2);
1522 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
1523 891b38e4 bellard
        ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1524 2c0262af bellard
        EIP = offset;
1525 2c0262af bellard
    }
1526 2c0262af bellard
}
1527 2c0262af bellard
1528 7e84c249 bellard
/* real and vm86 mode iret */
1529 2c0262af bellard
void helper_iret_real(int shift)
1530 2c0262af bellard
{
1531 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1532 2c0262af bellard
    uint8_t *ssp;
1533 2c0262af bellard
    int eflags_mask;
1534 7e84c249 bellard
1535 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1536 891b38e4 bellard
    sp = ESP;
1537 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1538 2c0262af bellard
    if (shift == 1) {
1539 2c0262af bellard
        /* 32 bits */
1540 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1541 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1542 891b38e4 bellard
        new_cs &= 0xffff;
1543 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
1544 2c0262af bellard
    } else {
1545 2c0262af bellard
        /* 16 bits */
1546 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1547 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1548 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
1549 2c0262af bellard
    }
1550 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1551 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
1552 2c0262af bellard
    env->eip = new_eip;
1553 7e84c249 bellard
    if (env->eflags & VM_MASK)
1554 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
1555 7e84c249 bellard
    else
1556 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
1557 2c0262af bellard
    if (shift == 0)
1558 2c0262af bellard
        eflags_mask &= 0xffff;
1559 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
1560 2c0262af bellard
}
1561 2c0262af bellard
1562 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
1563 8e682019 bellard
{
1564 8e682019 bellard
    int dpl;
1565 8e682019 bellard
    uint32_t e2;
1566 8e682019 bellard
    
1567 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
1568 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1569 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1570 8e682019 bellard
        /* data or non conforming code segment */
1571 8e682019 bellard
        if (dpl < cpl) {
1572 8e682019 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
1573 8e682019 bellard
        }
1574 8e682019 bellard
    }
1575 8e682019 bellard
}
1576 8e682019 bellard
1577 2c0262af bellard
/* protected mode iret */
1578 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
1579 2c0262af bellard
{
1580 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
1581 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
1582 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
1583 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
1584 2c0262af bellard
    uint8_t *ssp;
1585 2c0262af bellard
    
1586 891b38e4 bellard
    sp_mask = get_sp_mask(env->segs[R_SS].flags);
1587 2c0262af bellard
    sp = ESP;
1588 891b38e4 bellard
    ssp = env->segs[R_SS].base;
1589 2c0262af bellard
    if (shift == 1) {
1590 2c0262af bellard
        /* 32 bits */
1591 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
1592 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
1593 891b38e4 bellard
        new_cs &= 0xffff;
1594 891b38e4 bellard
        if (is_iret) {
1595 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
1596 891b38e4 bellard
            if (new_eflags & VM_MASK)
1597 891b38e4 bellard
                goto return_to_vm86;
1598 891b38e4 bellard
        }
1599 2c0262af bellard
    } else {
1600 2c0262af bellard
        /* 16 bits */
1601 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
1602 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
1603 2c0262af bellard
        if (is_iret)
1604 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
1605 2c0262af bellard
    }
1606 891b38e4 bellard
#ifdef DEBUG_PCALL
1607 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
1608 e19e89a5 bellard
        fprintf(logfile, "lret new %04x:%08x s=%d addend=0x%x\n",
1609 e19e89a5 bellard
                new_cs, new_eip, shift, addend);
1610 4136f33c bellard
        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
1611 891b38e4 bellard
    }
1612 891b38e4 bellard
#endif
1613 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1614 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1615 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1616 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1617 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
1618 2c0262af bellard
        !(e2 & DESC_CS_MASK))
1619 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1620 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1621 2c0262af bellard
    rpl = new_cs & 3; 
1622 2c0262af bellard
    if (rpl < cpl)
1623 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1624 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1625 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
1626 2c0262af bellard
        if (dpl > rpl)
1627 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1628 2c0262af bellard
    } else {
1629 2c0262af bellard
        if (dpl != rpl)
1630 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1631 2c0262af bellard
    }
1632 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
1633 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1634 2c0262af bellard
    
1635 891b38e4 bellard
    sp += addend;
1636 2c0262af bellard
    if (rpl == cpl) {
1637 2c0262af bellard
        /* return to same priledge level */
1638 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1639 2c0262af bellard
                       get_seg_base(e1, e2),
1640 2c0262af bellard
                       get_seg_limit(e1, e2),
1641 2c0262af bellard
                       e2);
1642 2c0262af bellard
    } else {
1643 2c0262af bellard
        /* return to different priviledge level */
1644 2c0262af bellard
        if (shift == 1) {
1645 2c0262af bellard
            /* 32 bits */
1646 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
1647 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
1648 891b38e4 bellard
            new_ss &= 0xffff;
1649 2c0262af bellard
        } else {
1650 2c0262af bellard
            /* 16 bits */
1651 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
1652 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
1653 2c0262af bellard
        }
1654 e19e89a5 bellard
#ifdef DEBUG_PCALL
1655 e19e89a5 bellard
        if (loglevel & CPU_LOG_PCALL) {
1656 e19e89a5 bellard
            fprintf(logfile, "new ss:esp=%04x:%08x\n",
1657 e19e89a5 bellard
                    new_ss, new_esp);
1658 e19e89a5 bellard
        }
1659 e19e89a5 bellard
#endif
1660 2c0262af bellard
        
1661 2c0262af bellard
        if ((new_ss & 3) != rpl)
1662 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1663 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
1664 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1665 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
1666 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
1667 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
1668 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1669 2c0262af bellard
        dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
1670 2c0262af bellard
        if (dpl != rpl)
1671 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
1672 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
1673 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
1674 2c0262af bellard
1675 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
1676 2c0262af bellard
                       get_seg_base(e1, e2),
1677 2c0262af bellard
                       get_seg_limit(e1, e2),
1678 2c0262af bellard
                       e2);
1679 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_SS, new_ss, 
1680 2c0262af bellard
                       get_seg_base(ss_e1, ss_e2),
1681 2c0262af bellard
                       get_seg_limit(ss_e1, ss_e2),
1682 2c0262af bellard
                       ss_e2);
1683 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
1684 891b38e4 bellard
        sp = new_esp;
1685 11774f54 bellard
        sp_mask = get_sp_mask(ss_e2);
1686 8e682019 bellard
1687 8e682019 bellard
        /* validate data segments */
1688 8e682019 bellard
        validate_seg(R_ES, cpl);
1689 8e682019 bellard
        validate_seg(R_DS, cpl);
1690 8e682019 bellard
        validate_seg(R_FS, cpl);
1691 8e682019 bellard
        validate_seg(R_GS, cpl);
1692 4afa6482 bellard
1693 4afa6482 bellard
        sp += addend;
1694 2c0262af bellard
    }
1695 891b38e4 bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
1696 2c0262af bellard
    env->eip = new_eip;
1697 2c0262af bellard
    if (is_iret) {
1698 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
1699 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
1700 2c0262af bellard
        if (cpl == 0)
1701 4136f33c bellard
            eflags_mask |= IOPL_MASK;
1702 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
1703 4136f33c bellard
        if (cpl <= iopl)
1704 4136f33c bellard
            eflags_mask |= IF_MASK;
1705 2c0262af bellard
        if (shift == 0)
1706 2c0262af bellard
            eflags_mask &= 0xffff;
1707 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
1708 2c0262af bellard
    }
1709 2c0262af bellard
    return;
1710 2c0262af bellard
1711 2c0262af bellard
 return_to_vm86:
1712 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
1713 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
1714 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
1715 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
1716 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
1717 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
1718 2c0262af bellard
    
1719 2c0262af bellard
    /* modify processor state */
1720 4136f33c bellard
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
1721 8145122b bellard
                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
1722 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
1723 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
1724 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
1725 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
1726 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
1727 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
1728 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
1729 2c0262af bellard
1730 2c0262af bellard
    env->eip = new_eip;
1731 2c0262af bellard
    ESP = new_esp;
1732 2c0262af bellard
}
1733 2c0262af bellard
1734 08cea4ee bellard
void helper_iret_protected(int shift, int next_eip)
1735 2c0262af bellard
{
1736 7e84c249 bellard
    int tss_selector, type;
1737 7e84c249 bellard
    uint32_t e1, e2;
1738 7e84c249 bellard
    
1739 7e84c249 bellard
    /* specific case for TSS */
1740 7e84c249 bellard
    if (env->eflags & NT_MASK) {
1741 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
1742 7e84c249 bellard
        if (tss_selector & 4)
1743 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1744 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
1745 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1746 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
1747 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
1748 7e84c249 bellard
        if (type != 3)
1749 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1750 08cea4ee bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
1751 7e84c249 bellard
    } else {
1752 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
1753 7e84c249 bellard
    }
1754 2c0262af bellard
}
1755 2c0262af bellard
1756 2c0262af bellard
void helper_lret_protected(int shift, int addend)
1757 2c0262af bellard
{
1758 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
1759 2c0262af bellard
}
1760 2c0262af bellard
1761 2c0262af bellard
void helper_movl_crN_T0(int reg)
1762 2c0262af bellard
{
1763 2c0262af bellard
    switch(reg) {
1764 2c0262af bellard
    case 0:
1765 1ac157da bellard
        cpu_x86_update_cr0(env, T0);
1766 2c0262af bellard
        break;
1767 2c0262af bellard
    case 3:
1768 1ac157da bellard
        cpu_x86_update_cr3(env, T0);
1769 1ac157da bellard
        break;
1770 1ac157da bellard
    case 4:
1771 1ac157da bellard
        cpu_x86_update_cr4(env, T0);
1772 1ac157da bellard
        break;
1773 1ac157da bellard
    default:
1774 1ac157da bellard
        env->cr[reg] = T0;
1775 2c0262af bellard
        break;
1776 2c0262af bellard
    }
1777 2c0262af bellard
}
1778 2c0262af bellard
1779 2c0262af bellard
/* XXX: do more */
1780 2c0262af bellard
void helper_movl_drN_T0(int reg)
1781 2c0262af bellard
{
1782 2c0262af bellard
    env->dr[reg] = T0;
1783 2c0262af bellard
}
1784 2c0262af bellard
1785 2c0262af bellard
void helper_invlpg(unsigned int addr)
1786 2c0262af bellard
{
1787 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
1788 2c0262af bellard
}
1789 2c0262af bellard
1790 2c0262af bellard
/* rdtsc */
1791 bc51c5c9 bellard
#if !defined(__i386__) && !defined(__x86_64__)
1792 2c0262af bellard
uint64_t emu_time;
1793 2c0262af bellard
#endif
1794 2c0262af bellard
1795 2c0262af bellard
void helper_rdtsc(void)
1796 2c0262af bellard
{
1797 2c0262af bellard
    uint64_t val;
1798 bc51c5c9 bellard
#if defined(__i386__) || defined(__x86_64__)
1799 2c0262af bellard
    asm("rdtsc" : "=A" (val));
1800 2c0262af bellard
#else
1801 2c0262af bellard
    /* better than nothing: the time increases */
1802 2c0262af bellard
    val = emu_time++;
1803 2c0262af bellard
#endif
1804 2c0262af bellard
    EAX = val;
1805 2c0262af bellard
    EDX = val >> 32;
1806 2c0262af bellard
}
1807 2c0262af bellard
1808 2c0262af bellard
void helper_wrmsr(void)
1809 2c0262af bellard
{
1810 2c0262af bellard
    switch(ECX) {
1811 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1812 2c0262af bellard
        env->sysenter_cs = EAX & 0xffff;
1813 2c0262af bellard
        break;
1814 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1815 2c0262af bellard
        env->sysenter_esp = EAX;
1816 2c0262af bellard
        break;
1817 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1818 2c0262af bellard
        env->sysenter_eip = EAX;
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_rdmsr(void)
1827 2c0262af bellard
{
1828 2c0262af bellard
    switch(ECX) {
1829 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
1830 2c0262af bellard
        EAX = env->sysenter_cs;
1831 2c0262af bellard
        EDX = 0;
1832 2c0262af bellard
        break;
1833 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
1834 2c0262af bellard
        EAX = env->sysenter_esp;
1835 2c0262af bellard
        EDX = 0;
1836 2c0262af bellard
        break;
1837 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
1838 2c0262af bellard
        EAX = env->sysenter_eip;
1839 2c0262af bellard
        EDX = 0;
1840 2c0262af bellard
        break;
1841 2c0262af bellard
    default:
1842 2c0262af bellard
        /* XXX: exception ? */
1843 2c0262af bellard
        break; 
1844 2c0262af bellard
    }
1845 2c0262af bellard
}
1846 2c0262af bellard
1847 2c0262af bellard
void helper_lsl(void)
1848 2c0262af bellard
{
1849 2c0262af bellard
    unsigned int selector, limit;
1850 2c0262af bellard
    uint32_t e1, e2;
1851 3ab493de bellard
    int rpl, dpl, cpl, type;
1852 2c0262af bellard
1853 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1854 2c0262af bellard
    selector = T0 & 0xffff;
1855 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1856 2c0262af bellard
        return;
1857 3ab493de bellard
    rpl = selector & 3;
1858 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1859 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1860 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1861 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1862 3ab493de bellard
            /* conforming */
1863 3ab493de bellard
        } else {
1864 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1865 3ab493de bellard
                return;
1866 3ab493de bellard
        }
1867 3ab493de bellard
    } else {
1868 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1869 3ab493de bellard
        switch(type) {
1870 3ab493de bellard
        case 1:
1871 3ab493de bellard
        case 2:
1872 3ab493de bellard
        case 3:
1873 3ab493de bellard
        case 9:
1874 3ab493de bellard
        case 11:
1875 3ab493de bellard
            break;
1876 3ab493de bellard
        default:
1877 3ab493de bellard
            return;
1878 3ab493de bellard
        }
1879 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1880 3ab493de bellard
            return;
1881 3ab493de bellard
    }
1882 3ab493de bellard
    limit = get_seg_limit(e1, e2);
1883 2c0262af bellard
    T1 = limit;
1884 2c0262af bellard
    CC_SRC |= CC_Z;
1885 2c0262af bellard
}
1886 2c0262af bellard
1887 2c0262af bellard
void helper_lar(void)
1888 2c0262af bellard
{
1889 2c0262af bellard
    unsigned int selector;
1890 2c0262af bellard
    uint32_t e1, e2;
1891 3ab493de bellard
    int rpl, dpl, cpl, type;
1892 2c0262af bellard
1893 2c0262af bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1894 2c0262af bellard
    selector = T0 & 0xffff;
1895 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1896 3ab493de bellard
        return;
1897 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
1898 2c0262af bellard
        return;
1899 3ab493de bellard
    rpl = selector & 3;
1900 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1901 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1902 3ab493de bellard
    if (e2 & DESC_S_MASK) {
1903 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
1904 3ab493de bellard
            /* conforming */
1905 3ab493de bellard
        } else {
1906 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1907 3ab493de bellard
                return;
1908 3ab493de bellard
        }
1909 3ab493de bellard
    } else {
1910 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1911 3ab493de bellard
        switch(type) {
1912 3ab493de bellard
        case 1:
1913 3ab493de bellard
        case 2:
1914 3ab493de bellard
        case 3:
1915 3ab493de bellard
        case 4:
1916 3ab493de bellard
        case 5:
1917 3ab493de bellard
        case 9:
1918 3ab493de bellard
        case 11:
1919 3ab493de bellard
        case 12:
1920 3ab493de bellard
            break;
1921 3ab493de bellard
        default:
1922 3ab493de bellard
            return;
1923 3ab493de bellard
        }
1924 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1925 3ab493de bellard
            return;
1926 3ab493de bellard
    }
1927 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
1928 2c0262af bellard
    CC_SRC |= CC_Z;
1929 2c0262af bellard
}
1930 2c0262af bellard
1931 3ab493de bellard
void helper_verr(void)
1932 3ab493de bellard
{
1933 3ab493de bellard
    unsigned int selector;
1934 3ab493de bellard
    uint32_t e1, e2;
1935 3ab493de bellard
    int rpl, dpl, cpl;
1936 3ab493de bellard
1937 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1938 3ab493de bellard
    selector = T0 & 0xffff;
1939 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1940 3ab493de bellard
        return;
1941 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1942 3ab493de bellard
        return;
1943 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1944 3ab493de bellard
        return;
1945 3ab493de bellard
    rpl = selector & 3;
1946 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1947 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1948 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1949 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
1950 3ab493de bellard
            return;
1951 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
1952 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
1953 3ab493de bellard
                return;
1954 3ab493de bellard
        }
1955 3ab493de bellard
    } else {
1956 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1957 3ab493de bellard
            return;
1958 3ab493de bellard
    }
1959 f3f2d9be bellard
    CC_SRC |= CC_Z;
1960 3ab493de bellard
}
1961 3ab493de bellard
1962 3ab493de bellard
void helper_verw(void)
1963 3ab493de bellard
{
1964 3ab493de bellard
    unsigned int selector;
1965 3ab493de bellard
    uint32_t e1, e2;
1966 3ab493de bellard
    int rpl, dpl, cpl;
1967 3ab493de bellard
1968 3ab493de bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1969 3ab493de bellard
    selector = T0 & 0xffff;
1970 3ab493de bellard
    if ((selector & 0xfffc) == 0)
1971 3ab493de bellard
        return;
1972 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
1973 3ab493de bellard
        return;
1974 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
1975 3ab493de bellard
        return;
1976 3ab493de bellard
    rpl = selector & 3;
1977 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1978 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
1979 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
1980 3ab493de bellard
        return;
1981 3ab493de bellard
    } else {
1982 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
1983 3ab493de bellard
            return;
1984 3ab493de bellard
        if (!(e2 & DESC_W_MASK))
1985 3ab493de bellard
            return;
1986 3ab493de bellard
    }
1987 f3f2d9be bellard
    CC_SRC |= CC_Z;
1988 3ab493de bellard
}
1989 3ab493de bellard
1990 2c0262af bellard
/* FPU helpers */
1991 2c0262af bellard
1992 2c0262af bellard
void helper_fldt_ST0_A0(void)
1993 2c0262af bellard
{
1994 2c0262af bellard
    int new_fpstt;
1995 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
1996 2c0262af bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1997 2c0262af bellard
    env->fpstt = new_fpstt;
1998 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
1999 2c0262af bellard
}
2000 2c0262af bellard
2001 2c0262af bellard
void helper_fstt_ST0_A0(void)
2002 2c0262af bellard
{
2003 2c0262af bellard
    helper_fstt(ST0, (uint8_t *)A0);
2004 2c0262af bellard
}
2005 2c0262af bellard
2006 2c0262af bellard
/* BCD ops */
2007 2c0262af bellard
2008 2c0262af bellard
#define MUL10(iv) ( iv + iv + (iv << 3) )
2009 2c0262af bellard
2010 2c0262af bellard
void helper_fbld_ST0_A0(void)
2011 2c0262af bellard
{
2012 2c0262af bellard
    CPU86_LDouble tmp;
2013 2c0262af bellard
    uint64_t val;
2014 2c0262af bellard
    unsigned int v;
2015 2c0262af bellard
    int i;
2016 2c0262af bellard
2017 2c0262af bellard
    val = 0;
2018 2c0262af bellard
    for(i = 8; i >= 0; i--) {
2019 2c0262af bellard
        v = ldub((uint8_t *)A0 + i);
2020 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
2021 2c0262af bellard
    }
2022 2c0262af bellard
    tmp = val;
2023 2c0262af bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
2024 2c0262af bellard
        tmp = -tmp;
2025 2c0262af bellard
    fpush();
2026 2c0262af bellard
    ST0 = tmp;
2027 2c0262af bellard
}
2028 2c0262af bellard
2029 2c0262af bellard
void helper_fbst_ST0_A0(void)
2030 2c0262af bellard
{
2031 2c0262af bellard
    CPU86_LDouble tmp;
2032 2c0262af bellard
    int v;
2033 2c0262af bellard
    uint8_t *mem_ref, *mem_end;
2034 2c0262af bellard
    int64_t val;
2035 2c0262af bellard
2036 2c0262af bellard
    tmp = rint(ST0);
2037 2c0262af bellard
    val = (int64_t)tmp;
2038 2c0262af bellard
    mem_ref = (uint8_t *)A0;
2039 2c0262af bellard
    mem_end = mem_ref + 9;
2040 2c0262af bellard
    if (val < 0) {
2041 2c0262af bellard
        stb(mem_end, 0x80);
2042 2c0262af bellard
        val = -val;
2043 2c0262af bellard
    } else {
2044 2c0262af bellard
        stb(mem_end, 0x00);
2045 2c0262af bellard
    }
2046 2c0262af bellard
    while (mem_ref < mem_end) {
2047 2c0262af bellard
        if (val == 0)
2048 2c0262af bellard
            break;
2049 2c0262af bellard
        v = val % 100;
2050 2c0262af bellard
        val = val / 100;
2051 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
2052 2c0262af bellard
        stb(mem_ref++, v);
2053 2c0262af bellard
    }
2054 2c0262af bellard
    while (mem_ref < mem_end) {
2055 2c0262af bellard
        stb(mem_ref++, 0);
2056 2c0262af bellard
    }
2057 2c0262af bellard
}
2058 2c0262af bellard
2059 2c0262af bellard
void helper_f2xm1(void)
2060 2c0262af bellard
{
2061 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
2062 2c0262af bellard
}
2063 2c0262af bellard
2064 2c0262af bellard
void helper_fyl2x(void)
2065 2c0262af bellard
{
2066 2c0262af bellard
    CPU86_LDouble fptemp;
2067 2c0262af bellard
    
2068 2c0262af bellard
    fptemp = ST0;
2069 2c0262af bellard
    if (fptemp>0.0){
2070 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
2071 2c0262af bellard
        ST1 *= fptemp;
2072 2c0262af bellard
        fpop();
2073 2c0262af bellard
    } else { 
2074 2c0262af bellard
        env->fpus &= (~0x4700);
2075 2c0262af bellard
        env->fpus |= 0x400;
2076 2c0262af bellard
    }
2077 2c0262af bellard
}
2078 2c0262af bellard
2079 2c0262af bellard
void helper_fptan(void)
2080 2c0262af bellard
{
2081 2c0262af bellard
    CPU86_LDouble fptemp;
2082 2c0262af bellard
2083 2c0262af bellard
    fptemp = ST0;
2084 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2085 2c0262af bellard
        env->fpus |= 0x400;
2086 2c0262af bellard
    } else {
2087 2c0262af bellard
        ST0 = tan(fptemp);
2088 2c0262af bellard
        fpush();
2089 2c0262af bellard
        ST0 = 1.0;
2090 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2091 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
2092 2c0262af bellard
    }
2093 2c0262af bellard
}
2094 2c0262af bellard
2095 2c0262af bellard
void helper_fpatan(void)
2096 2c0262af bellard
{
2097 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
2098 2c0262af bellard
2099 2c0262af bellard
    fpsrcop = ST1;
2100 2c0262af bellard
    fptemp = ST0;
2101 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
2102 2c0262af bellard
    fpop();
2103 2c0262af bellard
}
2104 2c0262af bellard
2105 2c0262af bellard
void helper_fxtract(void)
2106 2c0262af bellard
{
2107 2c0262af bellard
    CPU86_LDoubleU temp;
2108 2c0262af bellard
    unsigned int expdif;
2109 2c0262af bellard
2110 2c0262af bellard
    temp.d = ST0;
2111 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
2112 2c0262af bellard
    /*DP exponent bias*/
2113 2c0262af bellard
    ST0 = expdif;
2114 2c0262af bellard
    fpush();
2115 2c0262af bellard
    BIASEXPONENT(temp);
2116 2c0262af bellard
    ST0 = temp.d;
2117 2c0262af bellard
}
2118 2c0262af bellard
2119 2c0262af bellard
void helper_fprem1(void)
2120 2c0262af bellard
{
2121 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2122 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2123 2c0262af bellard
    int expdif;
2124 2c0262af bellard
    int q;
2125 2c0262af bellard
2126 2c0262af bellard
    fpsrcop = ST0;
2127 2c0262af bellard
    fptemp = ST1;
2128 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2129 2c0262af bellard
    fptemp1.d = fptemp;
2130 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2131 2c0262af bellard
    if (expdif < 53) {
2132 2c0262af bellard
        dblq = fpsrcop / fptemp;
2133 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2134 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2135 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2136 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2137 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2138 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2139 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2140 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2141 2c0262af bellard
    } else {
2142 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2143 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2144 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2145 2c0262af bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
2146 2c0262af bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
2147 2c0262af bellard
            floor(fpsrcop): ceil(fpsrcop);
2148 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2149 2c0262af bellard
    }
2150 2c0262af bellard
}
2151 2c0262af bellard
2152 2c0262af bellard
void helper_fprem(void)
2153 2c0262af bellard
{
2154 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
2155 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
2156 2c0262af bellard
    int expdif;
2157 2c0262af bellard
    int q;
2158 2c0262af bellard
    
2159 2c0262af bellard
    fpsrcop = ST0;
2160 2c0262af bellard
    fptemp = ST1;
2161 2c0262af bellard
    fpsrcop1.d = fpsrcop;
2162 2c0262af bellard
    fptemp1.d = fptemp;
2163 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
2164 2c0262af bellard
    if ( expdif < 53 ) {
2165 2c0262af bellard
        dblq = fpsrcop / fptemp;
2166 2c0262af bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
2167 2c0262af bellard
        ST0 = fpsrcop - fptemp*dblq;
2168 2c0262af bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
2169 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
2170 2c0262af bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
2171 2c0262af bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
2172 2c0262af bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
2173 2c0262af bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
2174 2c0262af bellard
    } else {
2175 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
2176 2c0262af bellard
        fptemp = pow(2.0, expdif-50);
2177 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
2178 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
2179 2c0262af bellard
        fpsrcop = (fpsrcop < 0.0)?
2180 2c0262af bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
2181 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
2182 2c0262af bellard
    }
2183 2c0262af bellard
}
2184 2c0262af bellard
2185 2c0262af bellard
void helper_fyl2xp1(void)
2186 2c0262af bellard
{
2187 2c0262af bellard
    CPU86_LDouble fptemp;
2188 2c0262af bellard
2189 2c0262af bellard
    fptemp = ST0;
2190 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
2191 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
2192 2c0262af bellard
        ST1 *= fptemp;
2193 2c0262af bellard
        fpop();
2194 2c0262af bellard
    } else { 
2195 2c0262af bellard
        env->fpus &= (~0x4700);
2196 2c0262af bellard
        env->fpus |= 0x400;
2197 2c0262af bellard
    }
2198 2c0262af bellard
}
2199 2c0262af bellard
2200 2c0262af bellard
void helper_fsqrt(void)
2201 2c0262af bellard
{
2202 2c0262af bellard
    CPU86_LDouble fptemp;
2203 2c0262af bellard
2204 2c0262af bellard
    fptemp = ST0;
2205 2c0262af bellard
    if (fptemp<0.0) { 
2206 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2207 2c0262af bellard
        env->fpus |= 0x400;
2208 2c0262af bellard
    }
2209 2c0262af bellard
    ST0 = sqrt(fptemp);
2210 2c0262af bellard
}
2211 2c0262af bellard
2212 2c0262af bellard
void helper_fsincos(void)
2213 2c0262af bellard
{
2214 2c0262af bellard
    CPU86_LDouble fptemp;
2215 2c0262af bellard
2216 2c0262af bellard
    fptemp = ST0;
2217 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2218 2c0262af bellard
        env->fpus |= 0x400;
2219 2c0262af bellard
    } else {
2220 2c0262af bellard
        ST0 = sin(fptemp);
2221 2c0262af bellard
        fpush();
2222 2c0262af bellard
        ST0 = cos(fptemp);
2223 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2224 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
2225 2c0262af bellard
    }
2226 2c0262af bellard
}
2227 2c0262af bellard
2228 2c0262af bellard
void helper_frndint(void)
2229 2c0262af bellard
{
2230 2c0262af bellard
    CPU86_LDouble a;
2231 2c0262af bellard
2232 2c0262af bellard
    a = ST0;
2233 2c0262af bellard
#ifdef __arm__
2234 2c0262af bellard
    switch(env->fpuc & RC_MASK) {
2235 2c0262af bellard
    default:
2236 2c0262af bellard
    case RC_NEAR:
2237 2c0262af bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
2238 2c0262af bellard
        break;
2239 2c0262af bellard
    case RC_DOWN:
2240 2c0262af bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
2241 2c0262af bellard
        break;
2242 2c0262af bellard
    case RC_UP:
2243 2c0262af bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
2244 2c0262af bellard
        break;
2245 2c0262af bellard
    case RC_CHOP:
2246 2c0262af bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
2247 2c0262af bellard
        break;
2248 2c0262af bellard
    }
2249 2c0262af bellard
#else
2250 2c0262af bellard
    a = rint(a);
2251 2c0262af bellard
#endif
2252 2c0262af bellard
    ST0 = a;
2253 2c0262af bellard
}
2254 2c0262af bellard
2255 2c0262af bellard
void helper_fscale(void)
2256 2c0262af bellard
{
2257 2c0262af bellard
    CPU86_LDouble fpsrcop, fptemp;
2258 2c0262af bellard
2259 2c0262af bellard
    fpsrcop = 2.0;
2260 2c0262af bellard
    fptemp = pow(fpsrcop,ST1);
2261 2c0262af bellard
    ST0 *= fptemp;
2262 2c0262af bellard
}
2263 2c0262af bellard
2264 2c0262af bellard
void helper_fsin(void)
2265 2c0262af bellard
{
2266 2c0262af bellard
    CPU86_LDouble fptemp;
2267 2c0262af bellard
2268 2c0262af bellard
    fptemp = ST0;
2269 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2270 2c0262af bellard
        env->fpus |= 0x400;
2271 2c0262af bellard
    } else {
2272 2c0262af bellard
        ST0 = sin(fptemp);
2273 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2274 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
2275 2c0262af bellard
    }
2276 2c0262af bellard
}
2277 2c0262af bellard
2278 2c0262af bellard
void helper_fcos(void)
2279 2c0262af bellard
{
2280 2c0262af bellard
    CPU86_LDouble fptemp;
2281 2c0262af bellard
2282 2c0262af bellard
    fptemp = ST0;
2283 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
2284 2c0262af bellard
        env->fpus |= 0x400;
2285 2c0262af bellard
    } else {
2286 2c0262af bellard
        ST0 = cos(fptemp);
2287 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
2288 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
2289 2c0262af bellard
    }
2290 2c0262af bellard
}
2291 2c0262af bellard
2292 2c0262af bellard
void helper_fxam_ST0(void)
2293 2c0262af bellard
{
2294 2c0262af bellard
    CPU86_LDoubleU temp;
2295 2c0262af bellard
    int expdif;
2296 2c0262af bellard
2297 2c0262af bellard
    temp.d = ST0;
2298 2c0262af bellard
2299 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
2300 2c0262af bellard
    if (SIGND(temp))
2301 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
2302 2c0262af bellard
2303 2c0262af bellard
    expdif = EXPD(temp);
2304 2c0262af bellard
    if (expdif == MAXEXPD) {
2305 2c0262af bellard
        if (MANTD(temp) == 0)
2306 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
2307 2c0262af bellard
        else
2308 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
2309 2c0262af bellard
    } else if (expdif == 0) {
2310 2c0262af bellard
        if (MANTD(temp) == 0)
2311 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
2312 2c0262af bellard
        else
2313 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
2314 2c0262af bellard
    } else {
2315 2c0262af bellard
        env->fpus |= 0x400;
2316 2c0262af bellard
    }
2317 2c0262af bellard
}
2318 2c0262af bellard
2319 2c0262af bellard
void helper_fstenv(uint8_t *ptr, int data32)
2320 2c0262af bellard
{
2321 2c0262af bellard
    int fpus, fptag, exp, i;
2322 2c0262af bellard
    uint64_t mant;
2323 2c0262af bellard
    CPU86_LDoubleU tmp;
2324 2c0262af bellard
2325 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
2326 2c0262af bellard
    fptag = 0;
2327 2c0262af bellard
    for (i=7; i>=0; i--) {
2328 2c0262af bellard
        fptag <<= 2;
2329 2c0262af bellard
        if (env->fptags[i]) {
2330 2c0262af bellard
            fptag |= 3;
2331 2c0262af bellard
        } else {
2332 2c0262af bellard
            tmp.d = env->fpregs[i];
2333 2c0262af bellard
            exp = EXPD(tmp);
2334 2c0262af bellard
            mant = MANTD(tmp);
2335 2c0262af bellard
            if (exp == 0 && mant == 0) {
2336 2c0262af bellard
                /* zero */
2337 2c0262af bellard
                fptag |= 1;
2338 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
2339 2c0262af bellard
#ifdef USE_X86LDOUBLE
2340 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
2341 2c0262af bellard
#endif
2342 2c0262af bellard
                       ) {
2343 2c0262af bellard
                /* NaNs, infinity, denormal */
2344 2c0262af bellard
                fptag |= 2;
2345 2c0262af bellard
            }
2346 2c0262af bellard
        }
2347 2c0262af bellard
    }
2348 2c0262af bellard
    if (data32) {
2349 2c0262af bellard
        /* 32 bit */
2350 2c0262af bellard
        stl(ptr, env->fpuc);
2351 2c0262af bellard
        stl(ptr + 4, fpus);
2352 2c0262af bellard
        stl(ptr + 8, fptag);
2353 2edcdce3 bellard
        stl(ptr + 12, 0); /* fpip */
2354 2edcdce3 bellard
        stl(ptr + 16, 0); /* fpcs */
2355 2edcdce3 bellard
        stl(ptr + 20, 0); /* fpoo */
2356 2edcdce3 bellard
        stl(ptr + 24, 0); /* fpos */
2357 2c0262af bellard
    } else {
2358 2c0262af bellard
        /* 16 bit */
2359 2c0262af bellard
        stw(ptr, env->fpuc);
2360 2c0262af bellard
        stw(ptr + 2, fpus);
2361 2c0262af bellard
        stw(ptr + 4, fptag);
2362 2c0262af bellard
        stw(ptr + 6, 0);
2363 2c0262af bellard
        stw(ptr + 8, 0);
2364 2c0262af bellard
        stw(ptr + 10, 0);
2365 2c0262af bellard
        stw(ptr + 12, 0);
2366 2c0262af bellard
    }
2367 2c0262af bellard
}
2368 2c0262af bellard
2369 2c0262af bellard
void helper_fldenv(uint8_t *ptr, int data32)
2370 2c0262af bellard
{
2371 2c0262af bellard
    int i, fpus, fptag;
2372 2c0262af bellard
2373 2c0262af bellard
    if (data32) {
2374 2c0262af bellard
        env->fpuc = lduw(ptr);
2375 2c0262af bellard
        fpus = lduw(ptr + 4);
2376 2c0262af bellard
        fptag = lduw(ptr + 8);
2377 2c0262af bellard
    }
2378 2c0262af bellard
    else {
2379 2c0262af bellard
        env->fpuc = lduw(ptr);
2380 2c0262af bellard
        fpus = lduw(ptr + 2);
2381 2c0262af bellard
        fptag = lduw(ptr + 4);
2382 2c0262af bellard
    }
2383 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
2384 2c0262af bellard
    env->fpus = fpus & ~0x3800;
2385 2edcdce3 bellard
    for(i = 0;i < 8; i++) {
2386 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
2387 2c0262af bellard
        fptag >>= 2;
2388 2c0262af bellard
    }
2389 2c0262af bellard
}
2390 2c0262af bellard
2391 2c0262af bellard
void helper_fsave(uint8_t *ptr, int data32)
2392 2c0262af bellard
{
2393 2c0262af bellard
    CPU86_LDouble tmp;
2394 2c0262af bellard
    int i;
2395 2c0262af bellard
2396 2c0262af bellard
    helper_fstenv(ptr, data32);
2397 2c0262af bellard
2398 2c0262af bellard
    ptr += (14 << data32);
2399 2c0262af bellard
    for(i = 0;i < 8; i++) {
2400 2c0262af bellard
        tmp = ST(i);
2401 2c0262af bellard
        helper_fstt(tmp, ptr);
2402 2c0262af bellard
        ptr += 10;
2403 2c0262af bellard
    }
2404 2c0262af bellard
2405 2c0262af bellard
    /* fninit */
2406 2c0262af bellard
    env->fpus = 0;
2407 2c0262af bellard
    env->fpstt = 0;
2408 2c0262af bellard
    env->fpuc = 0x37f;
2409 2c0262af bellard
    env->fptags[0] = 1;
2410 2c0262af bellard
    env->fptags[1] = 1;
2411 2c0262af bellard
    env->fptags[2] = 1;
2412 2c0262af bellard
    env->fptags[3] = 1;
2413 2c0262af bellard
    env->fptags[4] = 1;
2414 2c0262af bellard
    env->fptags[5] = 1;
2415 2c0262af bellard
    env->fptags[6] = 1;
2416 2c0262af bellard
    env->fptags[7] = 1;
2417 2c0262af bellard
}
2418 2c0262af bellard
2419 2c0262af bellard
void helper_frstor(uint8_t *ptr, int data32)
2420 2c0262af bellard
{
2421 2c0262af bellard
    CPU86_LDouble tmp;
2422 2c0262af bellard
    int i;
2423 2c0262af bellard
2424 2c0262af bellard
    helper_fldenv(ptr, data32);
2425 2c0262af bellard
    ptr += (14 << data32);
2426 2c0262af bellard
2427 2c0262af bellard
    for(i = 0;i < 8; i++) {
2428 2c0262af bellard
        tmp = helper_fldt(ptr);
2429 2c0262af bellard
        ST(i) = tmp;
2430 2c0262af bellard
        ptr += 10;
2431 2c0262af bellard
    }
2432 2c0262af bellard
}
2433 2c0262af bellard
2434 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
2435 61382a50 bellard
2436 61382a50 bellard
#define MMUSUFFIX _mmu
2437 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
2438 61382a50 bellard
2439 2c0262af bellard
#define SHIFT 0
2440 2c0262af bellard
#include "softmmu_template.h"
2441 2c0262af bellard
2442 2c0262af bellard
#define SHIFT 1
2443 2c0262af bellard
#include "softmmu_template.h"
2444 2c0262af bellard
2445 2c0262af bellard
#define SHIFT 2
2446 2c0262af bellard
#include "softmmu_template.h"
2447 2c0262af bellard
2448 2c0262af bellard
#define SHIFT 3
2449 2c0262af bellard
#include "softmmu_template.h"
2450 2c0262af bellard
2451 61382a50 bellard
#endif
2452 61382a50 bellard
2453 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
2454 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
2455 61382a50 bellard
   from generated code or from helper.c) */
2456 61382a50 bellard
/* XXX: fix it to restore all registers */
2457 61382a50 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2458 2c0262af bellard
{
2459 2c0262af bellard
    TranslationBlock *tb;
2460 2c0262af bellard
    int ret;
2461 2c0262af bellard
    unsigned long pc;
2462 61382a50 bellard
    CPUX86State *saved_env;
2463 61382a50 bellard
2464 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
2465 61382a50 bellard
       generated code */
2466 61382a50 bellard
    saved_env = env;
2467 61382a50 bellard
    env = cpu_single_env;
2468 61382a50 bellard
2469 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
2470 2c0262af bellard
    if (ret) {
2471 61382a50 bellard
        if (retaddr) {
2472 61382a50 bellard
            /* now we have a real cpu fault */
2473 61382a50 bellard
            pc = (unsigned long)retaddr;
2474 61382a50 bellard
            tb = tb_find_pc(pc);
2475 61382a50 bellard
            if (tb) {
2476 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
2477 61382a50 bellard
                   a virtual CPU fault */
2478 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
2479 61382a50 bellard
            }
2480 2c0262af bellard
        }
2481 2c0262af bellard
        raise_exception_err(EXCP0E_PAGE, env->error_code);
2482 2c0262af bellard
    }
2483 61382a50 bellard
    env = saved_env;
2484 2c0262af bellard
}