Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ d1d9f421

History | View | Annotate | Download (72.9 kB)

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