Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ a8c490cd

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