Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 61a8c4ec

History | View | Annotate | Download (74.5 kB)

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