Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ d0bdf2a2

History | View | Annotate | Download (109.7 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 9540a78b bellard
    if (logfile)\
28 9540a78b bellard
        fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
29 8145122b bellard
    (raise_exception_err)(a, b);\
30 8145122b bellard
} while (0)
31 8145122b bellard
#endif
32 8145122b bellard
33 2c0262af bellard
const uint8_t parity_table[256] = {
34 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
35 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
36 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
38 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
39 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
40 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
42 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
43 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
45 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
48 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
50 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
51 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
52 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
54 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
55 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
56 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
57 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
58 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
59 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
60 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
61 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
62 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
63 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
64 2c0262af bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
65 2c0262af bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
66 2c0262af bellard
};
67 2c0262af bellard
68 2c0262af bellard
/* modulo 17 table */
69 2c0262af bellard
const uint8_t rclw_table[32] = {
70 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
71 2c0262af bellard
    8, 9,10,11,12,13,14,15,
72 2c0262af bellard
   16, 0, 1, 2, 3, 4, 5, 6,
73 2c0262af bellard
    7, 8, 9,10,11,12,13,14,
74 2c0262af bellard
};
75 2c0262af bellard
76 2c0262af bellard
/* modulo 9 table */
77 2c0262af bellard
const uint8_t rclb_table[32] = {
78 2c0262af bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
79 2c0262af bellard
    8, 0, 1, 2, 3, 4, 5, 6,
80 2c0262af bellard
    7, 8, 0, 1, 2, 3, 4, 5, 
81 2c0262af bellard
    6, 7, 8, 0, 1, 2, 3, 4,
82 2c0262af bellard
};
83 2c0262af bellard
84 2c0262af bellard
const CPU86_LDouble f15rk[7] =
85 2c0262af bellard
{
86 2c0262af bellard
    0.00000000000000000000L,
87 2c0262af bellard
    1.00000000000000000000L,
88 2c0262af bellard
    3.14159265358979323851L,  /*pi*/
89 2c0262af bellard
    0.30102999566398119523L,  /*lg2*/
90 2c0262af bellard
    0.69314718055994530943L,  /*ln2*/
91 2c0262af bellard
    1.44269504088896340739L,  /*l2e*/
92 2c0262af bellard
    3.32192809488736234781L,  /*l2t*/
93 2c0262af bellard
};
94 2c0262af bellard
    
95 2c0262af bellard
/* thread support */
96 2c0262af bellard
97 2c0262af bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
98 2c0262af bellard
99 2c0262af bellard
void cpu_lock(void)
100 2c0262af bellard
{
101 2c0262af bellard
    spin_lock(&global_cpu_lock);
102 2c0262af bellard
}
103 2c0262af bellard
104 2c0262af bellard
void cpu_unlock(void)
105 2c0262af bellard
{
106 2c0262af bellard
    spin_unlock(&global_cpu_lock);
107 2c0262af bellard
}
108 2c0262af bellard
109 7e84c249 bellard
/* return non zero if error */
110 7e84c249 bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
111 7e84c249 bellard
                               int selector)
112 7e84c249 bellard
{
113 7e84c249 bellard
    SegmentCache *dt;
114 7e84c249 bellard
    int index;
115 14ce26e7 bellard
    target_ulong ptr;
116 7e84c249 bellard
117 7e84c249 bellard
    if (selector & 0x4)
118 7e84c249 bellard
        dt = &env->ldt;
119 7e84c249 bellard
    else
120 7e84c249 bellard
        dt = &env->gdt;
121 7e84c249 bellard
    index = selector & ~7;
122 7e84c249 bellard
    if ((index + 7) > dt->limit)
123 7e84c249 bellard
        return -1;
124 7e84c249 bellard
    ptr = dt->base + index;
125 7e84c249 bellard
    *e1_ptr = ldl_kernel(ptr);
126 7e84c249 bellard
    *e2_ptr = ldl_kernel(ptr + 4);
127 7e84c249 bellard
    return 0;
128 7e84c249 bellard
}
129 7e84c249 bellard
                                     
130 7e84c249 bellard
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
131 7e84c249 bellard
{
132 7e84c249 bellard
    unsigned int limit;
133 7e84c249 bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
134 7e84c249 bellard
    if (e2 & DESC_G_MASK)
135 7e84c249 bellard
        limit = (limit << 12) | 0xfff;
136 7e84c249 bellard
    return limit;
137 7e84c249 bellard
}
138 7e84c249 bellard
139 14ce26e7 bellard
static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
140 7e84c249 bellard
{
141 14ce26e7 bellard
    return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
142 7e84c249 bellard
}
143 7e84c249 bellard
144 7e84c249 bellard
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
145 7e84c249 bellard
{
146 7e84c249 bellard
    sc->base = get_seg_base(e1, e2);
147 7e84c249 bellard
    sc->limit = get_seg_limit(e1, e2);
148 7e84c249 bellard
    sc->flags = e2;
149 7e84c249 bellard
}
150 7e84c249 bellard
151 7e84c249 bellard
/* init the segment cache in vm86 mode. */
152 7e84c249 bellard
static inline void load_seg_vm(int seg, int selector)
153 7e84c249 bellard
{
154 7e84c249 bellard
    selector &= 0xffff;
155 7e84c249 bellard
    cpu_x86_load_seg_cache(env, seg, selector, 
156 14ce26e7 bellard
                           (selector << 4), 0xffff, 0);
157 7e84c249 bellard
}
158 7e84c249 bellard
159 2c0262af bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
160 2c0262af bellard
                                       uint32_t *esp_ptr, int dpl)
161 2c0262af bellard
{
162 2c0262af bellard
    int type, index, shift;
163 2c0262af bellard
    
164 2c0262af bellard
#if 0
165 2c0262af bellard
    {
166 2c0262af bellard
        int i;
167 2c0262af bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
168 2c0262af bellard
        for(i=0;i<env->tr.limit;i++) {
169 2c0262af bellard
            printf("%02x ", env->tr.base[i]);
170 2c0262af bellard
            if ((i & 7) == 7) printf("\n");
171 2c0262af bellard
        }
172 2c0262af bellard
        printf("\n");
173 2c0262af bellard
    }
174 2c0262af bellard
#endif
175 2c0262af bellard
176 2c0262af bellard
    if (!(env->tr.flags & DESC_P_MASK))
177 2c0262af bellard
        cpu_abort(env, "invalid tss");
178 2c0262af bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
179 2c0262af bellard
    if ((type & 7) != 1)
180 2c0262af bellard
        cpu_abort(env, "invalid tss type");
181 2c0262af bellard
    shift = type >> 3;
182 2c0262af bellard
    index = (dpl * 4 + 2) << shift;
183 2c0262af bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
184 2c0262af bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
185 2c0262af bellard
    if (shift == 0) {
186 61382a50 bellard
        *esp_ptr = lduw_kernel(env->tr.base + index);
187 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 2);
188 2c0262af bellard
    } else {
189 61382a50 bellard
        *esp_ptr = ldl_kernel(env->tr.base + index);
190 61382a50 bellard
        *ss_ptr = lduw_kernel(env->tr.base + index + 4);
191 2c0262af bellard
    }
192 2c0262af bellard
}
193 2c0262af bellard
194 7e84c249 bellard
/* XXX: merge with load_seg() */
195 7e84c249 bellard
static void tss_load_seg(int seg_reg, int selector)
196 7e84c249 bellard
{
197 7e84c249 bellard
    uint32_t e1, e2;
198 7e84c249 bellard
    int rpl, dpl, cpl;
199 7e84c249 bellard
200 7e84c249 bellard
    if ((selector & 0xfffc) != 0) {
201 7e84c249 bellard
        if (load_segment(&e1, &e2, selector) != 0)
202 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
203 7e84c249 bellard
        if (!(e2 & DESC_S_MASK))
204 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
205 7e84c249 bellard
        rpl = selector & 3;
206 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
207 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
208 7e84c249 bellard
        if (seg_reg == R_CS) {
209 7e84c249 bellard
            if (!(e2 & DESC_CS_MASK))
210 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
211 9540a78b bellard
            /* XXX: is it correct ? */
212 7e84c249 bellard
            if (dpl != rpl)
213 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
214 7e84c249 bellard
            if ((e2 & DESC_C_MASK) && dpl > rpl)
215 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
216 7e84c249 bellard
        } else if (seg_reg == R_SS) {
217 7e84c249 bellard
            /* SS must be writable data */
218 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
219 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
220 7e84c249 bellard
            if (dpl != cpl || dpl != rpl)
221 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
222 7e84c249 bellard
        } else {
223 7e84c249 bellard
            /* not readable code */
224 7e84c249 bellard
            if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
225 7e84c249 bellard
                raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
226 7e84c249 bellard
            /* if data or non conforming code, checks the rights */
227 7e84c249 bellard
            if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
228 7e84c249 bellard
                if (dpl < cpl || dpl < rpl)
229 7e84c249 bellard
                    raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
230 7e84c249 bellard
            }
231 7e84c249 bellard
        }
232 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
233 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
234 7e84c249 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
235 7e84c249 bellard
                       get_seg_base(e1, e2),
236 7e84c249 bellard
                       get_seg_limit(e1, e2),
237 7e84c249 bellard
                       e2);
238 7e84c249 bellard
    } else {
239 7e84c249 bellard
        if (seg_reg == R_SS || seg_reg == R_CS) 
240 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
241 7e84c249 bellard
    }
242 7e84c249 bellard
}
243 7e84c249 bellard
244 7e84c249 bellard
#define SWITCH_TSS_JMP  0
245 7e84c249 bellard
#define SWITCH_TSS_IRET 1
246 7e84c249 bellard
#define SWITCH_TSS_CALL 2
247 7e84c249 bellard
248 7e84c249 bellard
/* XXX: restore CPU state in registers (PowerPC case) */
249 7e84c249 bellard
static void switch_tss(int tss_selector, 
250 883da8e2 bellard
                       uint32_t e1, uint32_t e2, int source,
251 883da8e2 bellard
                       uint32_t next_eip)
252 2c0262af bellard
{
253 7e84c249 bellard
    int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
254 14ce26e7 bellard
    target_ulong tss_base;
255 7e84c249 bellard
    uint32_t new_regs[8], new_segs[6];
256 7e84c249 bellard
    uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
257 7e84c249 bellard
    uint32_t old_eflags, eflags_mask;
258 2c0262af bellard
    SegmentCache *dt;
259 2c0262af bellard
    int index;
260 14ce26e7 bellard
    target_ulong ptr;
261 2c0262af bellard
262 7e84c249 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
263 dc6f57fd bellard
#ifdef DEBUG_PCALL
264 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL)
265 dc6f57fd bellard
        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
266 dc6f57fd bellard
#endif
267 7e84c249 bellard
268 7e84c249 bellard
    /* if task gate, we read the TSS segment and we load it */
269 7e84c249 bellard
    if (type == 5) {
270 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
271 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
272 7e84c249 bellard
        tss_selector = e1 >> 16;
273 7e84c249 bellard
        if (tss_selector & 4)
274 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
275 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
276 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
277 7e84c249 bellard
        if (e2 & DESC_S_MASK)
278 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
279 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
280 7e84c249 bellard
        if ((type & 7) != 1)
281 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
282 7e84c249 bellard
    }
283 7e84c249 bellard
284 7e84c249 bellard
    if (!(e2 & DESC_P_MASK))
285 7e84c249 bellard
        raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
286 7e84c249 bellard
287 7e84c249 bellard
    if (type & 8)
288 7e84c249 bellard
        tss_limit_max = 103;
289 2c0262af bellard
    else
290 7e84c249 bellard
        tss_limit_max = 43;
291 7e84c249 bellard
    tss_limit = get_seg_limit(e1, e2);
292 7e84c249 bellard
    tss_base = get_seg_base(e1, e2);
293 7e84c249 bellard
    if ((tss_selector & 4) != 0 || 
294 7e84c249 bellard
        tss_limit < tss_limit_max)
295 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
296 7e84c249 bellard
    old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
297 7e84c249 bellard
    if (old_type & 8)
298 7e84c249 bellard
        old_tss_limit_max = 103;
299 7e84c249 bellard
    else
300 7e84c249 bellard
        old_tss_limit_max = 43;
301 7e84c249 bellard
302 7e84c249 bellard
    /* read all the registers from the new TSS */
303 7e84c249 bellard
    if (type & 8) {
304 7e84c249 bellard
        /* 32 bit */
305 7e84c249 bellard
        new_cr3 = ldl_kernel(tss_base + 0x1c);
306 7e84c249 bellard
        new_eip = ldl_kernel(tss_base + 0x20);
307 7e84c249 bellard
        new_eflags = ldl_kernel(tss_base + 0x24);
308 7e84c249 bellard
        for(i = 0; i < 8; i++)
309 7e84c249 bellard
            new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
310 7e84c249 bellard
        for(i = 0; i < 6; i++)
311 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
312 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x60);
313 7e84c249 bellard
        new_trap = ldl_kernel(tss_base + 0x64);
314 7e84c249 bellard
    } else {
315 7e84c249 bellard
        /* 16 bit */
316 7e84c249 bellard
        new_cr3 = 0;
317 7e84c249 bellard
        new_eip = lduw_kernel(tss_base + 0x0e);
318 7e84c249 bellard
        new_eflags = lduw_kernel(tss_base + 0x10);
319 7e84c249 bellard
        for(i = 0; i < 8; i++)
320 7e84c249 bellard
            new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
321 7e84c249 bellard
        for(i = 0; i < 4; i++)
322 7e84c249 bellard
            new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
323 7e84c249 bellard
        new_ldt = lduw_kernel(tss_base + 0x2a);
324 7e84c249 bellard
        new_segs[R_FS] = 0;
325 7e84c249 bellard
        new_segs[R_GS] = 0;
326 7e84c249 bellard
        new_trap = 0;
327 7e84c249 bellard
    }
328 7e84c249 bellard
    
329 7e84c249 bellard
    /* NOTE: we must avoid memory exceptions during the task switch,
330 7e84c249 bellard
       so we make dummy accesses before */
331 7e84c249 bellard
    /* XXX: it can still fail in some cases, so a bigger hack is
332 7e84c249 bellard
       necessary to valid the TLB after having done the accesses */
333 7e84c249 bellard
334 7e84c249 bellard
    v1 = ldub_kernel(env->tr.base);
335 265d3497 bellard
    v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
336 7e84c249 bellard
    stb_kernel(env->tr.base, v1);
337 7e84c249 bellard
    stb_kernel(env->tr.base + old_tss_limit_max, v2);
338 7e84c249 bellard
    
339 7e84c249 bellard
    /* clear busy bit (it is restartable) */
340 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
341 14ce26e7 bellard
        target_ulong ptr;
342 7e84c249 bellard
        uint32_t e2;
343 883da8e2 bellard
        ptr = env->gdt.base + (env->tr.selector & ~7);
344 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
345 7e84c249 bellard
        e2 &= ~DESC_TSS_BUSY_MASK;
346 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
347 7e84c249 bellard
    }
348 7e84c249 bellard
    old_eflags = compute_eflags();
349 7e84c249 bellard
    if (source == SWITCH_TSS_IRET)
350 7e84c249 bellard
        old_eflags &= ~NT_MASK;
351 7e84c249 bellard
    
352 7e84c249 bellard
    /* save the current state in the old TSS */
353 7e84c249 bellard
    if (type & 8) {
354 7e84c249 bellard
        /* 32 bit */
355 883da8e2 bellard
        stl_kernel(env->tr.base + 0x20, next_eip);
356 7e84c249 bellard
        stl_kernel(env->tr.base + 0x24, old_eflags);
357 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
358 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
359 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
360 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
361 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
362 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
363 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
364 0d1a29f9 bellard
        stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
365 7e84c249 bellard
        for(i = 0; i < 6; i++)
366 7e84c249 bellard
            stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
367 7e84c249 bellard
    } else {
368 7e84c249 bellard
        /* 16 bit */
369 883da8e2 bellard
        stw_kernel(env->tr.base + 0x0e, next_eip);
370 7e84c249 bellard
        stw_kernel(env->tr.base + 0x10, old_eflags);
371 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
372 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
373 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
374 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
375 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
376 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
377 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
378 0d1a29f9 bellard
        stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
379 7e84c249 bellard
        for(i = 0; i < 4; i++)
380 7e84c249 bellard
            stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
381 7e84c249 bellard
    }
382 7e84c249 bellard
    
383 7e84c249 bellard
    /* now if an exception occurs, it will occurs in the next task
384 7e84c249 bellard
       context */
385 7e84c249 bellard
386 7e84c249 bellard
    if (source == SWITCH_TSS_CALL) {
387 7e84c249 bellard
        stw_kernel(tss_base, env->tr.selector);
388 7e84c249 bellard
        new_eflags |= NT_MASK;
389 7e84c249 bellard
    }
390 7e84c249 bellard
391 7e84c249 bellard
    /* set busy bit */
392 7e84c249 bellard
    if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
393 14ce26e7 bellard
        target_ulong ptr;
394 7e84c249 bellard
        uint32_t e2;
395 883da8e2 bellard
        ptr = env->gdt.base + (tss_selector & ~7);
396 7e84c249 bellard
        e2 = ldl_kernel(ptr + 4);
397 7e84c249 bellard
        e2 |= DESC_TSS_BUSY_MASK;
398 7e84c249 bellard
        stl_kernel(ptr + 4, e2);
399 7e84c249 bellard
    }
400 7e84c249 bellard
401 7e84c249 bellard
    /* set the new CPU state */
402 7e84c249 bellard
    /* from this point, any exception which occurs can give problems */
403 7e84c249 bellard
    env->cr[0] |= CR0_TS_MASK;
404 883da8e2 bellard
    env->hflags |= HF_TS_MASK;
405 7e84c249 bellard
    env->tr.selector = tss_selector;
406 7e84c249 bellard
    env->tr.base = tss_base;
407 7e84c249 bellard
    env->tr.limit = tss_limit;
408 7e84c249 bellard
    env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
409 7e84c249 bellard
    
410 7e84c249 bellard
    if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
411 1ac157da bellard
        cpu_x86_update_cr3(env, new_cr3);
412 7e84c249 bellard
    }
413 7e84c249 bellard
    
414 7e84c249 bellard
    /* load all registers without an exception, then reload them with
415 7e84c249 bellard
       possible exception */
416 7e84c249 bellard
    env->eip = new_eip;
417 4136f33c bellard
    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
418 8145122b bellard
        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
419 7e84c249 bellard
    if (!(type & 8))
420 7e84c249 bellard
        eflags_mask &= 0xffff;
421 7e84c249 bellard
    load_eflags(new_eflags, eflags_mask);
422 0d1a29f9 bellard
    /* XXX: what to do in 16 bit case ? */
423 0d1a29f9 bellard
    EAX = new_regs[0];
424 0d1a29f9 bellard
    ECX = new_regs[1];
425 0d1a29f9 bellard
    EDX = new_regs[2];
426 0d1a29f9 bellard
    EBX = new_regs[3];
427 0d1a29f9 bellard
    ESP = new_regs[4];
428 0d1a29f9 bellard
    EBP = new_regs[5];
429 0d1a29f9 bellard
    ESI = new_regs[6];
430 0d1a29f9 bellard
    EDI = new_regs[7];
431 7e84c249 bellard
    if (new_eflags & VM_MASK) {
432 7e84c249 bellard
        for(i = 0; i < 6; i++) 
433 7e84c249 bellard
            load_seg_vm(i, new_segs[i]);
434 7e84c249 bellard
        /* in vm86, CPL is always 3 */
435 7e84c249 bellard
        cpu_x86_set_cpl(env, 3);
436 7e84c249 bellard
    } else {
437 7e84c249 bellard
        /* CPL is set the RPL of CS */
438 7e84c249 bellard
        cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
439 7e84c249 bellard
        /* first just selectors as the rest may trigger exceptions */
440 7e84c249 bellard
        for(i = 0; i < 6; i++)
441 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
442 7e84c249 bellard
    }
443 7e84c249 bellard
    
444 7e84c249 bellard
    env->ldt.selector = new_ldt & ~4;
445 14ce26e7 bellard
    env->ldt.base = 0;
446 7e84c249 bellard
    env->ldt.limit = 0;
447 7e84c249 bellard
    env->ldt.flags = 0;
448 7e84c249 bellard
449 7e84c249 bellard
    /* load the LDT */
450 7e84c249 bellard
    if (new_ldt & 4)
451 7e84c249 bellard
        raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
452 7e84c249 bellard
453 8145122b bellard
    if ((new_ldt & 0xfffc) != 0) {
454 8145122b bellard
        dt = &env->gdt;
455 8145122b bellard
        index = new_ldt & ~7;
456 8145122b bellard
        if ((index + 7) > dt->limit)
457 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
458 8145122b bellard
        ptr = dt->base + index;
459 8145122b bellard
        e1 = ldl_kernel(ptr);
460 8145122b bellard
        e2 = ldl_kernel(ptr + 4);
461 8145122b bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
462 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
463 8145122b bellard
        if (!(e2 & DESC_P_MASK))
464 8145122b bellard
            raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
465 8145122b bellard
        load_seg_cache_raw_dt(&env->ldt, e1, e2);
466 8145122b bellard
    }
467 7e84c249 bellard
    
468 7e84c249 bellard
    /* load the segments */
469 7e84c249 bellard
    if (!(new_eflags & VM_MASK)) {
470 7e84c249 bellard
        tss_load_seg(R_CS, new_segs[R_CS]);
471 7e84c249 bellard
        tss_load_seg(R_SS, new_segs[R_SS]);
472 7e84c249 bellard
        tss_load_seg(R_ES, new_segs[R_ES]);
473 7e84c249 bellard
        tss_load_seg(R_DS, new_segs[R_DS]);
474 7e84c249 bellard
        tss_load_seg(R_FS, new_segs[R_FS]);
475 7e84c249 bellard
        tss_load_seg(R_GS, new_segs[R_GS]);
476 7e84c249 bellard
    }
477 7e84c249 bellard
    
478 7e84c249 bellard
    /* check that EIP is in the CS segment limits */
479 7e84c249 bellard
    if (new_eip > env->segs[R_CS].limit) {
480 883da8e2 bellard
        /* XXX: different exception if CALL ? */
481 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
482 7e84c249 bellard
    }
483 2c0262af bellard
}
484 7e84c249 bellard
485 7e84c249 bellard
/* check if Port I/O is allowed in TSS */
486 7e84c249 bellard
static inline void check_io(int addr, int size)
487 2c0262af bellard
{
488 7e84c249 bellard
    int io_offset, val, mask;
489 7e84c249 bellard
    
490 7e84c249 bellard
    /* TSS must be a valid 32 bit one */
491 7e84c249 bellard
    if (!(env->tr.flags & DESC_P_MASK) ||
492 7e84c249 bellard
        ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
493 7e84c249 bellard
        env->tr.limit < 103)
494 7e84c249 bellard
        goto fail;
495 7e84c249 bellard
    io_offset = lduw_kernel(env->tr.base + 0x66);
496 7e84c249 bellard
    io_offset += (addr >> 3);
497 7e84c249 bellard
    /* Note: the check needs two bytes */
498 7e84c249 bellard
    if ((io_offset + 1) > env->tr.limit)
499 7e84c249 bellard
        goto fail;
500 7e84c249 bellard
    val = lduw_kernel(env->tr.base + io_offset);
501 7e84c249 bellard
    val >>= (addr & 7);
502 7e84c249 bellard
    mask = (1 << size) - 1;
503 7e84c249 bellard
    /* all bits must be zero to allow the I/O */
504 7e84c249 bellard
    if ((val & mask) != 0) {
505 7e84c249 bellard
    fail:
506 7e84c249 bellard
        raise_exception_err(EXCP0D_GPF, 0);
507 7e84c249 bellard
    }
508 2c0262af bellard
}
509 2c0262af bellard
510 7e84c249 bellard
void check_iob_T0(void)
511 2c0262af bellard
{
512 7e84c249 bellard
    check_io(T0, 1);
513 2c0262af bellard
}
514 2c0262af bellard
515 7e84c249 bellard
void check_iow_T0(void)
516 2c0262af bellard
{
517 7e84c249 bellard
    check_io(T0, 2);
518 2c0262af bellard
}
519 2c0262af bellard
520 7e84c249 bellard
void check_iol_T0(void)
521 2c0262af bellard
{
522 7e84c249 bellard
    check_io(T0, 4);
523 7e84c249 bellard
}
524 7e84c249 bellard
525 7e84c249 bellard
void check_iob_DX(void)
526 7e84c249 bellard
{
527 7e84c249 bellard
    check_io(EDX & 0xffff, 1);
528 7e84c249 bellard
}
529 7e84c249 bellard
530 7e84c249 bellard
void check_iow_DX(void)
531 7e84c249 bellard
{
532 7e84c249 bellard
    check_io(EDX & 0xffff, 2);
533 7e84c249 bellard
}
534 7e84c249 bellard
535 7e84c249 bellard
void check_iol_DX(void)
536 7e84c249 bellard
{
537 7e84c249 bellard
    check_io(EDX & 0xffff, 4);
538 2c0262af bellard
}
539 2c0262af bellard
540 891b38e4 bellard
static inline unsigned int get_sp_mask(unsigned int e2)
541 891b38e4 bellard
{
542 891b38e4 bellard
    if (e2 & DESC_B_MASK)
543 891b38e4 bellard
        return 0xffffffff;
544 891b38e4 bellard
    else
545 891b38e4 bellard
        return 0xffff;
546 891b38e4 bellard
}
547 891b38e4 bellard
548 8d7b0fbb bellard
#ifdef TARGET_X86_64
549 8d7b0fbb bellard
#define SET_ESP(val, sp_mask)\
550 8d7b0fbb bellard
do {\
551 8d7b0fbb bellard
    if ((sp_mask) == 0xffff)\
552 8d7b0fbb bellard
        ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
553 8d7b0fbb bellard
    else if ((sp_mask) == 0xffffffffLL)\
554 8d7b0fbb bellard
        ESP = (uint32_t)(val);\
555 8d7b0fbb bellard
    else\
556 8d7b0fbb bellard
        ESP = (val);\
557 8d7b0fbb bellard
} while (0)
558 8d7b0fbb bellard
#else
559 8d7b0fbb bellard
#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
560 8d7b0fbb bellard
#endif
561 8d7b0fbb bellard
562 891b38e4 bellard
/* XXX: add a is_user flag to have proper security support */
563 891b38e4 bellard
#define PUSHW(ssp, sp, sp_mask, val)\
564 891b38e4 bellard
{\
565 891b38e4 bellard
    sp -= 2;\
566 891b38e4 bellard
    stw_kernel((ssp) + (sp & (sp_mask)), (val));\
567 891b38e4 bellard
}
568 891b38e4 bellard
569 891b38e4 bellard
#define PUSHL(ssp, sp, sp_mask, val)\
570 891b38e4 bellard
{\
571 891b38e4 bellard
    sp -= 4;\
572 891b38e4 bellard
    stl_kernel((ssp) + (sp & (sp_mask)), (val));\
573 891b38e4 bellard
}
574 891b38e4 bellard
575 891b38e4 bellard
#define POPW(ssp, sp, sp_mask, val)\
576 891b38e4 bellard
{\
577 891b38e4 bellard
    val = lduw_kernel((ssp) + (sp & (sp_mask)));\
578 891b38e4 bellard
    sp += 2;\
579 891b38e4 bellard
}
580 891b38e4 bellard
581 891b38e4 bellard
#define POPL(ssp, sp, sp_mask, val)\
582 891b38e4 bellard
{\
583 14ce26e7 bellard
    val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
584 891b38e4 bellard
    sp += 4;\
585 891b38e4 bellard
}
586 891b38e4 bellard
587 2c0262af bellard
/* protected mode interrupt */
588 2c0262af bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
589 2c0262af bellard
                                   unsigned int next_eip, int is_hw)
590 2c0262af bellard
{
591 2c0262af bellard
    SegmentCache *dt;
592 14ce26e7 bellard
    target_ulong ptr, ssp;
593 8d7b0fbb bellard
    int type, dpl, selector, ss_dpl, cpl;
594 2c0262af bellard
    int has_error_code, new_stack, shift;
595 891b38e4 bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
596 8d7b0fbb bellard
    uint32_t old_eip, sp_mask;
597 2c0262af bellard
598 7e84c249 bellard
    has_error_code = 0;
599 7e84c249 bellard
    if (!is_int && !is_hw) {
600 7e84c249 bellard
        switch(intno) {
601 7e84c249 bellard
        case 8:
602 7e84c249 bellard
        case 10:
603 7e84c249 bellard
        case 11:
604 7e84c249 bellard
        case 12:
605 7e84c249 bellard
        case 13:
606 7e84c249 bellard
        case 14:
607 7e84c249 bellard
        case 17:
608 7e84c249 bellard
            has_error_code = 1;
609 7e84c249 bellard
            break;
610 7e84c249 bellard
        }
611 7e84c249 bellard
    }
612 883da8e2 bellard
    if (is_int)
613 883da8e2 bellard
        old_eip = next_eip;
614 883da8e2 bellard
    else
615 883da8e2 bellard
        old_eip = env->eip;
616 7e84c249 bellard
617 2c0262af bellard
    dt = &env->idt;
618 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
619 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
620 2c0262af bellard
    ptr = dt->base + intno * 8;
621 61382a50 bellard
    e1 = ldl_kernel(ptr);
622 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
623 2c0262af bellard
    /* check gate type */
624 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
625 2c0262af bellard
    switch(type) {
626 2c0262af bellard
    case 5: /* task gate */
627 7e84c249 bellard
        /* must do that check here to return the correct error code */
628 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
629 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
630 883da8e2 bellard
        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
631 7e84c249 bellard
        if (has_error_code) {
632 8d7b0fbb bellard
            int type;
633 8d7b0fbb bellard
            uint32_t mask;
634 7e84c249 bellard
            /* push the error code */
635 3f20e1dd bellard
            type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
636 3f20e1dd bellard
            shift = type >> 3;
637 7e84c249 bellard
            if (env->segs[R_SS].flags & DESC_B_MASK)
638 7e84c249 bellard
                mask = 0xffffffff;
639 7e84c249 bellard
            else
640 7e84c249 bellard
                mask = 0xffff;
641 0d1a29f9 bellard
            esp = (ESP - (2 << shift)) & mask;
642 7e84c249 bellard
            ssp = env->segs[R_SS].base + esp;
643 7e84c249 bellard
            if (shift)
644 7e84c249 bellard
                stl_kernel(ssp, error_code);
645 7e84c249 bellard
            else
646 7e84c249 bellard
                stw_kernel(ssp, error_code);
647 8d7b0fbb bellard
            SET_ESP(esp, mask);
648 7e84c249 bellard
        }
649 7e84c249 bellard
        return;
650 2c0262af bellard
    case 6: /* 286 interrupt gate */
651 2c0262af bellard
    case 7: /* 286 trap gate */
652 2c0262af bellard
    case 14: /* 386 interrupt gate */
653 2c0262af bellard
    case 15: /* 386 trap gate */
654 2c0262af bellard
        break;
655 2c0262af bellard
    default:
656 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
657 2c0262af bellard
        break;
658 2c0262af bellard
    }
659 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
660 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
661 2c0262af bellard
    /* check privledge if software int */
662 2c0262af bellard
    if (is_int && dpl < cpl)
663 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
664 2c0262af bellard
    /* check valid bit */
665 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
666 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
667 2c0262af bellard
    selector = e1 >> 16;
668 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
669 2c0262af bellard
    if ((selector & 0xfffc) == 0)
670 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
671 2c0262af bellard
672 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
673 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
674 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
675 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
676 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
677 2c0262af bellard
    if (dpl > cpl)
678 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
679 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
680 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
681 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
682 7f75ffd3 blueswir1
        /* to inner privilege */
683 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
684 2c0262af bellard
        if ((ss & 0xfffc) == 0)
685 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
686 2c0262af bellard
        if ((ss & 3) != dpl)
687 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
688 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
689 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
690 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
691 2c0262af bellard
        if (ss_dpl != dpl)
692 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
693 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
694 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
695 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
696 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
697 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
698 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
699 2c0262af bellard
        new_stack = 1;
700 891b38e4 bellard
        sp_mask = get_sp_mask(ss_e2);
701 891b38e4 bellard
        ssp = get_seg_base(ss_e1, ss_e2);
702 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
703 7f75ffd3 blueswir1
        /* to same privilege */
704 8e682019 bellard
        if (env->eflags & VM_MASK)
705 8e682019 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
706 2c0262af bellard
        new_stack = 0;
707 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
708 891b38e4 bellard
        ssp = env->segs[R_SS].base;
709 891b38e4 bellard
        esp = ESP;
710 4796f5e9 bellard
        dpl = cpl;
711 2c0262af bellard
    } else {
712 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
713 2c0262af bellard
        new_stack = 0; /* avoid warning */
714 891b38e4 bellard
        sp_mask = 0; /* avoid warning */
715 14ce26e7 bellard
        ssp = 0; /* avoid warning */
716 891b38e4 bellard
        esp = 0; /* avoid warning */
717 2c0262af bellard
    }
718 2c0262af bellard
719 2c0262af bellard
    shift = type >> 3;
720 891b38e4 bellard
721 891b38e4 bellard
#if 0
722 891b38e4 bellard
    /* XXX: check that enough room is available */
723 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
724 2c0262af bellard
    if (env->eflags & VM_MASK)
725 2c0262af bellard
        push_size += 8;
726 2c0262af bellard
    push_size <<= shift;
727 891b38e4 bellard
#endif
728 2c0262af bellard
    if (shift == 1) {
729 2c0262af bellard
        if (new_stack) {
730 8e682019 bellard
            if (env->eflags & VM_MASK) {
731 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
732 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
733 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
734 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
735 8e682019 bellard
            }
736 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
737 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, ESP);
738 2c0262af bellard
        }
739 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, compute_eflags());
740 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
741 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, old_eip);
742 2c0262af bellard
        if (has_error_code) {
743 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, error_code);
744 2c0262af bellard
        }
745 2c0262af bellard
    } else {
746 2c0262af bellard
        if (new_stack) {
747 8e682019 bellard
            if (env->eflags & VM_MASK) {
748 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
749 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
750 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
751 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
752 8e682019 bellard
            }
753 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
754 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, ESP);
755 2c0262af bellard
        }
756 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, compute_eflags());
757 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
758 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, old_eip);
759 2c0262af bellard
        if (has_error_code) {
760 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, error_code);
761 2c0262af bellard
        }
762 2c0262af bellard
    }
763 2c0262af bellard
    
764 891b38e4 bellard
    if (new_stack) {
765 8e682019 bellard
        if (env->eflags & VM_MASK) {
766 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
767 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
768 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
769 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
770 8e682019 bellard
        }
771 891b38e4 bellard
        ss = (ss & ~3) | dpl;
772 891b38e4 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 
773 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
774 891b38e4 bellard
    }
775 8d7b0fbb bellard
    SET_ESP(esp, sp_mask);
776 891b38e4 bellard
777 891b38e4 bellard
    selector = (selector & ~3) | dpl;
778 891b38e4 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
779 891b38e4 bellard
                   get_seg_base(e1, e2),
780 891b38e4 bellard
                   get_seg_limit(e1, e2),
781 891b38e4 bellard
                   e2);
782 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
783 891b38e4 bellard
    env->eip = offset;
784 891b38e4 bellard
785 2c0262af bellard
    /* interrupt gate clear IF mask */
786 2c0262af bellard
    if ((type & 1) == 0) {
787 2c0262af bellard
        env->eflags &= ~IF_MASK;
788 2c0262af bellard
    }
789 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
790 2c0262af bellard
}
791 2c0262af bellard
792 14ce26e7 bellard
#ifdef TARGET_X86_64
793 14ce26e7 bellard
794 14ce26e7 bellard
#define PUSHQ(sp, val)\
795 14ce26e7 bellard
{\
796 14ce26e7 bellard
    sp -= 8;\
797 14ce26e7 bellard
    stq_kernel(sp, (val));\
798 14ce26e7 bellard
}
799 14ce26e7 bellard
800 14ce26e7 bellard
#define POPQ(sp, val)\
801 14ce26e7 bellard
{\
802 14ce26e7 bellard
    val = ldq_kernel(sp);\
803 14ce26e7 bellard
    sp += 8;\
804 14ce26e7 bellard
}
805 14ce26e7 bellard
806 14ce26e7 bellard
static inline target_ulong get_rsp_from_tss(int level)
807 14ce26e7 bellard
{
808 14ce26e7 bellard
    int index;
809 14ce26e7 bellard
    
810 14ce26e7 bellard
#if 0
811 14ce26e7 bellard
    printf("TR: base=" TARGET_FMT_lx " limit=%x\n", 
812 14ce26e7 bellard
           env->tr.base, env->tr.limit);
813 14ce26e7 bellard
#endif
814 14ce26e7 bellard
815 14ce26e7 bellard
    if (!(env->tr.flags & DESC_P_MASK))
816 14ce26e7 bellard
        cpu_abort(env, "invalid tss");
817 14ce26e7 bellard
    index = 8 * level + 4;
818 14ce26e7 bellard
    if ((index + 7) > env->tr.limit)
819 14ce26e7 bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
820 14ce26e7 bellard
    return ldq_kernel(env->tr.base + index);
821 14ce26e7 bellard
}
822 14ce26e7 bellard
823 14ce26e7 bellard
/* 64 bit interrupt */
824 14ce26e7 bellard
static void do_interrupt64(int intno, int is_int, int error_code,
825 14ce26e7 bellard
                           target_ulong next_eip, int is_hw)
826 14ce26e7 bellard
{
827 14ce26e7 bellard
    SegmentCache *dt;
828 14ce26e7 bellard
    target_ulong ptr;
829 14ce26e7 bellard
    int type, dpl, selector, cpl, ist;
830 14ce26e7 bellard
    int has_error_code, new_stack;
831 14ce26e7 bellard
    uint32_t e1, e2, e3, ss;
832 14ce26e7 bellard
    target_ulong old_eip, esp, offset;
833 14ce26e7 bellard
834 14ce26e7 bellard
    has_error_code = 0;
835 14ce26e7 bellard
    if (!is_int && !is_hw) {
836 14ce26e7 bellard
        switch(intno) {
837 14ce26e7 bellard
        case 8:
838 14ce26e7 bellard
        case 10:
839 14ce26e7 bellard
        case 11:
840 14ce26e7 bellard
        case 12:
841 14ce26e7 bellard
        case 13:
842 14ce26e7 bellard
        case 14:
843 14ce26e7 bellard
        case 17:
844 14ce26e7 bellard
            has_error_code = 1;
845 14ce26e7 bellard
            break;
846 14ce26e7 bellard
        }
847 14ce26e7 bellard
    }
848 14ce26e7 bellard
    if (is_int)
849 14ce26e7 bellard
        old_eip = next_eip;
850 14ce26e7 bellard
    else
851 14ce26e7 bellard
        old_eip = env->eip;
852 14ce26e7 bellard
853 14ce26e7 bellard
    dt = &env->idt;
854 14ce26e7 bellard
    if (intno * 16 + 15 > dt->limit)
855 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
856 14ce26e7 bellard
    ptr = dt->base + intno * 16;
857 14ce26e7 bellard
    e1 = ldl_kernel(ptr);
858 14ce26e7 bellard
    e2 = ldl_kernel(ptr + 4);
859 14ce26e7 bellard
    e3 = ldl_kernel(ptr + 8);
860 14ce26e7 bellard
    /* check gate type */
861 14ce26e7 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
862 14ce26e7 bellard
    switch(type) {
863 14ce26e7 bellard
    case 14: /* 386 interrupt gate */
864 14ce26e7 bellard
    case 15: /* 386 trap gate */
865 14ce26e7 bellard
        break;
866 14ce26e7 bellard
    default:
867 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
868 14ce26e7 bellard
        break;
869 14ce26e7 bellard
    }
870 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
871 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
872 14ce26e7 bellard
    /* check privledge if software int */
873 14ce26e7 bellard
    if (is_int && dpl < cpl)
874 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
875 14ce26e7 bellard
    /* check valid bit */
876 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
877 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
878 14ce26e7 bellard
    selector = e1 >> 16;
879 14ce26e7 bellard
    offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
880 14ce26e7 bellard
    ist = e2 & 7;
881 14ce26e7 bellard
    if ((selector & 0xfffc) == 0)
882 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
883 14ce26e7 bellard
884 14ce26e7 bellard
    if (load_segment(&e1, &e2, selector) != 0)
885 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
886 14ce26e7 bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
887 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
888 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
889 14ce26e7 bellard
    if (dpl > cpl)
890 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
891 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
892 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
893 14ce26e7 bellard
    if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
894 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
895 14ce26e7 bellard
    if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
896 7f75ffd3 blueswir1
        /* to inner privilege */
897 14ce26e7 bellard
        if (ist != 0)
898 14ce26e7 bellard
            esp = get_rsp_from_tss(ist + 3);
899 14ce26e7 bellard
        else
900 14ce26e7 bellard
            esp = get_rsp_from_tss(dpl);
901 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
902 14ce26e7 bellard
        ss = 0;
903 14ce26e7 bellard
        new_stack = 1;
904 14ce26e7 bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
905 7f75ffd3 blueswir1
        /* to same privilege */
906 14ce26e7 bellard
        if (env->eflags & VM_MASK)
907 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
908 14ce26e7 bellard
        new_stack = 0;
909 9540a78b bellard
        if (ist != 0)
910 9540a78b bellard
            esp = get_rsp_from_tss(ist + 3);
911 9540a78b bellard
        else
912 9540a78b bellard
            esp = ESP;
913 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
914 14ce26e7 bellard
        dpl = cpl;
915 14ce26e7 bellard
    } else {
916 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
917 14ce26e7 bellard
        new_stack = 0; /* avoid warning */
918 14ce26e7 bellard
        esp = 0; /* avoid warning */
919 14ce26e7 bellard
    }
920 14ce26e7 bellard
921 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_SS].selector);
922 14ce26e7 bellard
    PUSHQ(esp, ESP);
923 14ce26e7 bellard
    PUSHQ(esp, compute_eflags());
924 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_CS].selector);
925 14ce26e7 bellard
    PUSHQ(esp, old_eip);
926 14ce26e7 bellard
    if (has_error_code) {
927 14ce26e7 bellard
        PUSHQ(esp, error_code);
928 14ce26e7 bellard
    }
929 14ce26e7 bellard
    
930 14ce26e7 bellard
    if (new_stack) {
931 14ce26e7 bellard
        ss = 0 | dpl;
932 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
933 14ce26e7 bellard
    }
934 14ce26e7 bellard
    ESP = esp;
935 14ce26e7 bellard
936 14ce26e7 bellard
    selector = (selector & ~3) | dpl;
937 14ce26e7 bellard
    cpu_x86_load_seg_cache(env, R_CS, selector, 
938 14ce26e7 bellard
                   get_seg_base(e1, e2),
939 14ce26e7 bellard
                   get_seg_limit(e1, e2),
940 14ce26e7 bellard
                   e2);
941 14ce26e7 bellard
    cpu_x86_set_cpl(env, dpl);
942 14ce26e7 bellard
    env->eip = offset;
943 14ce26e7 bellard
944 14ce26e7 bellard
    /* interrupt gate clear IF mask */
945 14ce26e7 bellard
    if ((type & 1) == 0) {
946 14ce26e7 bellard
        env->eflags &= ~IF_MASK;
947 14ce26e7 bellard
    }
948 14ce26e7 bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
949 14ce26e7 bellard
}
950 f419b321 bellard
#endif
951 14ce26e7 bellard
952 06c2f506 bellard
void helper_syscall(int next_eip_addend)
953 14ce26e7 bellard
{
954 14ce26e7 bellard
    int selector;
955 14ce26e7 bellard
956 14ce26e7 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
957 14ce26e7 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
958 14ce26e7 bellard
    }
959 14ce26e7 bellard
    selector = (env->star >> 32) & 0xffff;
960 f419b321 bellard
#ifdef TARGET_X86_64
961 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
962 9540a78b bellard
        int code64;
963 9540a78b bellard
964 06c2f506 bellard
        ECX = env->eip + next_eip_addend;
965 14ce26e7 bellard
        env->regs[11] = compute_eflags();
966 9540a78b bellard
        
967 9540a78b bellard
        code64 = env->hflags & HF_CS64_MASK;
968 14ce26e7 bellard
969 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
970 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
971 14ce26e7 bellard
                           0, 0xffffffff, 
972 d80c7d1c bellard
                               DESC_G_MASK | DESC_P_MASK |
973 14ce26e7 bellard
                               DESC_S_MASK |
974 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
975 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
976 14ce26e7 bellard
                               0, 0xffffffff,
977 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
978 14ce26e7 bellard
                               DESC_S_MASK |
979 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
980 14ce26e7 bellard
        env->eflags &= ~env->fmask;
981 9540a78b bellard
        if (code64)
982 14ce26e7 bellard
            env->eip = env->lstar;
983 14ce26e7 bellard
        else
984 14ce26e7 bellard
            env->eip = env->cstar;
985 f419b321 bellard
    } else 
986 f419b321 bellard
#endif
987 f419b321 bellard
    {
988 06c2f506 bellard
        ECX = (uint32_t)(env->eip + next_eip_addend);
989 14ce26e7 bellard
        
990 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
991 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
992 14ce26e7 bellard
                           0, 0xffffffff, 
993 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
994 14ce26e7 bellard
                               DESC_S_MASK |
995 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
996 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
997 14ce26e7 bellard
                               0, 0xffffffff,
998 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
999 14ce26e7 bellard
                               DESC_S_MASK |
1000 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1001 14ce26e7 bellard
        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1002 14ce26e7 bellard
        env->eip = (uint32_t)env->star;
1003 14ce26e7 bellard
    }
1004 14ce26e7 bellard
}
1005 14ce26e7 bellard
1006 14ce26e7 bellard
void helper_sysret(int dflag)
1007 14ce26e7 bellard
{
1008 14ce26e7 bellard
    int cpl, selector;
1009 14ce26e7 bellard
1010 f419b321 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
1011 f419b321 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
1012 f419b321 bellard
    }
1013 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1014 14ce26e7 bellard
    if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1015 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
1016 14ce26e7 bellard
    }
1017 14ce26e7 bellard
    selector = (env->star >> 48) & 0xffff;
1018 f419b321 bellard
#ifdef TARGET_X86_64
1019 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
1020 14ce26e7 bellard
        if (dflag == 2) {
1021 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 
1022 14ce26e7 bellard
                                   0, 0xffffffff, 
1023 d80c7d1c bellard
                                   DESC_G_MASK | DESC_P_MASK |
1024 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1025 14ce26e7 bellard
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | 
1026 14ce26e7 bellard
                                   DESC_L_MASK);
1027 14ce26e7 bellard
            env->eip = ECX;
1028 14ce26e7 bellard
        } else {
1029 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
1030 14ce26e7 bellard
                                   0, 0xffffffff, 
1031 14ce26e7 bellard
                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1032 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1033 14ce26e7 bellard
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1034 14ce26e7 bellard
            env->eip = (uint32_t)ECX;
1035 14ce26e7 bellard
        }
1036 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
1037 14ce26e7 bellard
                               0, 0xffffffff,
1038 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1039 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1040 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1041 31313213 bellard
        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | 
1042 31313213 bellard
                    IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1043 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1044 f419b321 bellard
    } else 
1045 f419b321 bellard
#endif
1046 f419b321 bellard
    {
1047 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
1048 14ce26e7 bellard
                               0, 0xffffffff, 
1049 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1050 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1051 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1052 14ce26e7 bellard
        env->eip = (uint32_t)ECX;
1053 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
1054 14ce26e7 bellard
                               0, 0xffffffff,
1055 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1056 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1057 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1058 14ce26e7 bellard
        env->eflags |= IF_MASK;
1059 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1060 14ce26e7 bellard
    }
1061 f419b321 bellard
#ifdef USE_KQEMU
1062 f419b321 bellard
    if (kqemu_is_ok(env)) {
1063 f419b321 bellard
        if (env->hflags & HF_LMA_MASK)
1064 f419b321 bellard
            CC_OP = CC_OP_EFLAGS;
1065 f419b321 bellard
        env->exception_index = -1;
1066 f419b321 bellard
        cpu_loop_exit();
1067 f419b321 bellard
    }
1068 14ce26e7 bellard
#endif
1069 f419b321 bellard
}
1070 14ce26e7 bellard
1071 2c0262af bellard
/* real mode interrupt */
1072 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
1073 4136f33c bellard
                              unsigned int next_eip)
1074 2c0262af bellard
{
1075 2c0262af bellard
    SegmentCache *dt;
1076 14ce26e7 bellard
    target_ulong ptr, ssp;
1077 2c0262af bellard
    int selector;
1078 2c0262af bellard
    uint32_t offset, esp;
1079 2c0262af bellard
    uint32_t old_cs, old_eip;
1080 2c0262af bellard
1081 2c0262af bellard
    /* real mode (simpler !) */
1082 2c0262af bellard
    dt = &env->idt;
1083 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
1084 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1085 2c0262af bellard
    ptr = dt->base + intno * 4;
1086 61382a50 bellard
    offset = lduw_kernel(ptr);
1087 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
1088 2c0262af bellard
    esp = ESP;
1089 2c0262af bellard
    ssp = env->segs[R_SS].base;
1090 2c0262af bellard
    if (is_int)
1091 2c0262af bellard
        old_eip = next_eip;
1092 2c0262af bellard
    else
1093 2c0262af bellard
        old_eip = env->eip;
1094 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
1095 891b38e4 bellard
    /* XXX: use SS segment size ? */
1096 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
1097 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
1098 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
1099 2c0262af bellard
    
1100 2c0262af bellard
    /* update processor state */
1101 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
1102 2c0262af bellard
    env->eip = offset;
1103 2c0262af bellard
    env->segs[R_CS].selector = selector;
1104 14ce26e7 bellard
    env->segs[R_CS].base = (selector << 4);
1105 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1106 2c0262af bellard
}
1107 2c0262af bellard
1108 2c0262af bellard
/* fake user mode interrupt */
1109 2c0262af bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
1110 14ce26e7 bellard
                       target_ulong next_eip)
1111 2c0262af bellard
{
1112 2c0262af bellard
    SegmentCache *dt;
1113 14ce26e7 bellard
    target_ulong ptr;
1114 2c0262af bellard
    int dpl, cpl;
1115 2c0262af bellard
    uint32_t e2;
1116 2c0262af bellard
1117 2c0262af bellard
    dt = &env->idt;
1118 2c0262af bellard
    ptr = dt->base + (intno * 8);
1119 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
1120 2c0262af bellard
    
1121 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1122 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1123 2c0262af bellard
    /* check privledge if software int */
1124 2c0262af bellard
    if (is_int && dpl < cpl)
1125 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1126 2c0262af bellard
1127 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
1128 2c0262af bellard
       exiting the emulation with the suitable exception and error
1129 2c0262af bellard
       code */
1130 2c0262af bellard
    if (is_int)
1131 2c0262af bellard
        EIP = next_eip;
1132 2c0262af bellard
}
1133 2c0262af bellard
1134 2c0262af bellard
/*
1135 e19e89a5 bellard
 * Begin execution of an interruption. is_int is TRUE if coming from
1136 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
1137 2c0262af bellard
 * instruction. It is only relevant if is_int is TRUE.  
1138 2c0262af bellard
 */
1139 2c0262af bellard
void do_interrupt(int intno, int is_int, int error_code, 
1140 14ce26e7 bellard
                  target_ulong next_eip, int is_hw)
1141 2c0262af bellard
{
1142 1247c5f7 bellard
    if (loglevel & CPU_LOG_INT) {
1143 e19e89a5 bellard
        if ((env->cr[0] & CR0_PE_MASK)) {
1144 e19e89a5 bellard
            static int count;
1145 14ce26e7 bellard
            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
1146 dc6f57fd bellard
                    count, intno, error_code, is_int,
1147 dc6f57fd bellard
                    env->hflags & HF_CPL_MASK,
1148 dc6f57fd bellard
                    env->segs[R_CS].selector, EIP,
1149 2ee73ac3 bellard
                    (int)env->segs[R_CS].base + EIP,
1150 8145122b bellard
                    env->segs[R_SS].selector, ESP);
1151 8145122b bellard
            if (intno == 0x0e) {
1152 14ce26e7 bellard
                fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1153 8145122b bellard
            } else {
1154 14ce26e7 bellard
                fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1155 8145122b bellard
            }
1156 e19e89a5 bellard
            fprintf(logfile, "\n");
1157 06c2f506 bellard
            cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1158 1247c5f7 bellard
#if 0
1159 e19e89a5 bellard
            {
1160 e19e89a5 bellard
                int i;
1161 e19e89a5 bellard
                uint8_t *ptr;
1162 e19e89a5 bellard
                fprintf(logfile, "       code=");
1163 e19e89a5 bellard
                ptr = env->segs[R_CS].base + env->eip;
1164 e19e89a5 bellard
                for(i = 0; i < 16; i++) {
1165 e19e89a5 bellard
                    fprintf(logfile, " %02x", ldub(ptr + i));
1166 dc6f57fd bellard
                }
1167 e19e89a5 bellard
                fprintf(logfile, "\n");
1168 dc6f57fd bellard
            }
1169 8e682019 bellard
#endif
1170 e19e89a5 bellard
            count++;
1171 4136f33c bellard
        }
1172 4136f33c bellard
    }
1173 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
1174 14ce26e7 bellard
#if TARGET_X86_64
1175 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1176 14ce26e7 bellard
            do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1177 14ce26e7 bellard
        } else
1178 14ce26e7 bellard
#endif
1179 14ce26e7 bellard
        {
1180 14ce26e7 bellard
            do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1181 14ce26e7 bellard
        }
1182 2c0262af bellard
    } else {
1183 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
1184 2c0262af bellard
    }
1185 2c0262af bellard
}
1186 2c0262af bellard
1187 2c0262af bellard
/*
1188 678dde13 ths
 * Check nested exceptions and change to double or triple fault if
1189 678dde13 ths
 * needed. It should only be called, if this is not an interrupt.
1190 678dde13 ths
 * Returns the new exception number.
1191 678dde13 ths
 */
1192 678dde13 ths
int check_exception(int intno, int *error_code)
1193 678dde13 ths
{
1194 678dde13 ths
    char first_contributory = env->old_exception == 0 ||
1195 678dde13 ths
                              (env->old_exception >= 10 &&
1196 678dde13 ths
                               env->old_exception <= 13);
1197 678dde13 ths
    char second_contributory = intno == 0 ||
1198 678dde13 ths
                               (intno >= 10 && intno <= 13);
1199 678dde13 ths
1200 678dde13 ths
    if (loglevel & CPU_LOG_INT)
1201 678dde13 ths
        fprintf(logfile, "check_exception old: %x new %x\n",
1202 678dde13 ths
                env->old_exception, intno);
1203 678dde13 ths
1204 678dde13 ths
    if (env->old_exception == EXCP08_DBLE)
1205 678dde13 ths
        cpu_abort(env, "triple fault");
1206 678dde13 ths
1207 678dde13 ths
    if ((first_contributory && second_contributory)
1208 678dde13 ths
        || (env->old_exception == EXCP0E_PAGE &&
1209 678dde13 ths
            (second_contributory || (intno == EXCP0E_PAGE)))) {
1210 678dde13 ths
        intno = EXCP08_DBLE;
1211 678dde13 ths
        *error_code = 0;
1212 678dde13 ths
    }
1213 678dde13 ths
1214 678dde13 ths
    if (second_contributory || (intno == EXCP0E_PAGE) ||
1215 678dde13 ths
        (intno == EXCP08_DBLE))
1216 678dde13 ths
        env->old_exception = intno;
1217 678dde13 ths
1218 678dde13 ths
    return intno;
1219 678dde13 ths
}
1220 678dde13 ths
1221 678dde13 ths
/*
1222 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
1223 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
1224 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
1225 2c0262af bellard
 * is_int is TRUE.  
1226 2c0262af bellard
 */
1227 2c0262af bellard
void raise_interrupt(int intno, int is_int, int error_code, 
1228 a8ede8ba bellard
                     int next_eip_addend)
1229 2c0262af bellard
{
1230 678dde13 ths
    if (!is_int)
1231 678dde13 ths
        intno = check_exception(intno, &error_code);
1232 678dde13 ths
1233 2c0262af bellard
    env->exception_index = intno;
1234 2c0262af bellard
    env->error_code = error_code;
1235 2c0262af bellard
    env->exception_is_int = is_int;
1236 a8ede8ba bellard
    env->exception_next_eip = env->eip + next_eip_addend;
1237 2c0262af bellard
    cpu_loop_exit();
1238 2c0262af bellard
}
1239 2c0262af bellard
1240 0d1a29f9 bellard
/* same as raise_exception_err, but do not restore global registers */
1241 0d1a29f9 bellard
static void raise_exception_err_norestore(int exception_index, int error_code)
1242 0d1a29f9 bellard
{
1243 678dde13 ths
    exception_index = check_exception(exception_index, &error_code);
1244 678dde13 ths
1245 0d1a29f9 bellard
    env->exception_index = exception_index;
1246 0d1a29f9 bellard
    env->error_code = error_code;
1247 0d1a29f9 bellard
    env->exception_is_int = 0;
1248 0d1a29f9 bellard
    env->exception_next_eip = 0;
1249 0d1a29f9 bellard
    longjmp(env->jmp_env, 1);
1250 0d1a29f9 bellard
}
1251 0d1a29f9 bellard
1252 2c0262af bellard
/* shortcuts to generate exceptions */
1253 8145122b bellard
1254 8145122b bellard
void (raise_exception_err)(int exception_index, int error_code)
1255 2c0262af bellard
{
1256 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
1257 2c0262af bellard
}
1258 2c0262af bellard
1259 2c0262af bellard
void raise_exception(int exception_index)
1260 2c0262af bellard
{
1261 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
1262 2c0262af bellard
}
1263 2c0262af bellard
1264 3b21e03e bellard
/* SMM support */
1265 3b21e03e bellard
1266 74ce674f bellard
#if defined(CONFIG_USER_ONLY) 
1267 74ce674f bellard
1268 74ce674f bellard
void do_smm_enter(void)
1269 74ce674f bellard
{
1270 74ce674f bellard
}
1271 74ce674f bellard
1272 74ce674f bellard
void helper_rsm(void)
1273 74ce674f bellard
{
1274 74ce674f bellard
}
1275 74ce674f bellard
1276 74ce674f bellard
#else
1277 74ce674f bellard
1278 3b21e03e bellard
#ifdef TARGET_X86_64
1279 3b21e03e bellard
#define SMM_REVISION_ID 0x00020064
1280 3b21e03e bellard
#else
1281 3b21e03e bellard
#define SMM_REVISION_ID 0x00020000
1282 3b21e03e bellard
#endif
1283 3b21e03e bellard
1284 3b21e03e bellard
void do_smm_enter(void)
1285 3b21e03e bellard
{
1286 3b21e03e bellard
    target_ulong sm_state;
1287 3b21e03e bellard
    SegmentCache *dt;
1288 3b21e03e bellard
    int i, offset;
1289 3b21e03e bellard
1290 3b21e03e bellard
    if (loglevel & CPU_LOG_INT) {
1291 3b21e03e bellard
        fprintf(logfile, "SMM: enter\n");
1292 3b21e03e bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1293 3b21e03e bellard
    }
1294 3b21e03e bellard
1295 3b21e03e bellard
    env->hflags |= HF_SMM_MASK;
1296 3b21e03e bellard
    cpu_smm_update(env);
1297 3b21e03e bellard
1298 3b21e03e bellard
    sm_state = env->smbase + 0x8000;
1299 3b21e03e bellard
    
1300 3b21e03e bellard
#ifdef TARGET_X86_64
1301 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1302 3b21e03e bellard
        dt = &env->segs[i];
1303 3b21e03e bellard
        offset = 0x7e00 + i * 16;
1304 3b21e03e bellard
        stw_phys(sm_state + offset, dt->selector);
1305 3b21e03e bellard
        stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1306 3b21e03e bellard
        stl_phys(sm_state + offset + 4, dt->limit);
1307 3b21e03e bellard
        stq_phys(sm_state + offset + 8, dt->base);
1308 3b21e03e bellard
    }
1309 3b21e03e bellard
1310 3b21e03e bellard
    stq_phys(sm_state + 0x7e68, env->gdt.base);
1311 3b21e03e bellard
    stl_phys(sm_state + 0x7e64, env->gdt.limit);
1312 3b21e03e bellard
1313 3b21e03e bellard
    stw_phys(sm_state + 0x7e70, env->ldt.selector);
1314 3b21e03e bellard
    stq_phys(sm_state + 0x7e78, env->ldt.base);
1315 3b21e03e bellard
    stl_phys(sm_state + 0x7e74, env->ldt.limit);
1316 3b21e03e bellard
    stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1317 3b21e03e bellard
    
1318 3b21e03e bellard
    stq_phys(sm_state + 0x7e88, env->idt.base);
1319 3b21e03e bellard
    stl_phys(sm_state + 0x7e84, env->idt.limit);
1320 3b21e03e bellard
1321 3b21e03e bellard
    stw_phys(sm_state + 0x7e90, env->tr.selector);
1322 3b21e03e bellard
    stq_phys(sm_state + 0x7e98, env->tr.base);
1323 3b21e03e bellard
    stl_phys(sm_state + 0x7e94, env->tr.limit);
1324 3b21e03e bellard
    stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1325 3b21e03e bellard
    
1326 3b21e03e bellard
    stq_phys(sm_state + 0x7ed0, env->efer);
1327 3b21e03e bellard
1328 3b21e03e bellard
    stq_phys(sm_state + 0x7ff8, EAX);
1329 3b21e03e bellard
    stq_phys(sm_state + 0x7ff0, ECX);
1330 3b21e03e bellard
    stq_phys(sm_state + 0x7fe8, EDX);
1331 3b21e03e bellard
    stq_phys(sm_state + 0x7fe0, EBX);
1332 3b21e03e bellard
    stq_phys(sm_state + 0x7fd8, ESP);
1333 3b21e03e bellard
    stq_phys(sm_state + 0x7fd0, EBP);
1334 3b21e03e bellard
    stq_phys(sm_state + 0x7fc8, ESI);
1335 3b21e03e bellard
    stq_phys(sm_state + 0x7fc0, EDI);
1336 3b21e03e bellard
    for(i = 8; i < 16; i++) 
1337 3b21e03e bellard
        stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1338 3b21e03e bellard
    stq_phys(sm_state + 0x7f78, env->eip);
1339 3b21e03e bellard
    stl_phys(sm_state + 0x7f70, compute_eflags());
1340 3b21e03e bellard
    stl_phys(sm_state + 0x7f68, env->dr[6]);
1341 3b21e03e bellard
    stl_phys(sm_state + 0x7f60, env->dr[7]);
1342 3b21e03e bellard
1343 3b21e03e bellard
    stl_phys(sm_state + 0x7f48, env->cr[4]);
1344 3b21e03e bellard
    stl_phys(sm_state + 0x7f50, env->cr[3]);
1345 3b21e03e bellard
    stl_phys(sm_state + 0x7f58, env->cr[0]);
1346 3b21e03e bellard
1347 3b21e03e bellard
    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1348 3b21e03e bellard
    stl_phys(sm_state + 0x7f00, env->smbase);
1349 3b21e03e bellard
#else
1350 3b21e03e bellard
    stl_phys(sm_state + 0x7ffc, env->cr[0]);
1351 3b21e03e bellard
    stl_phys(sm_state + 0x7ff8, env->cr[3]);
1352 3b21e03e bellard
    stl_phys(sm_state + 0x7ff4, compute_eflags());
1353 3b21e03e bellard
    stl_phys(sm_state + 0x7ff0, env->eip);
1354 3b21e03e bellard
    stl_phys(sm_state + 0x7fec, EDI);
1355 3b21e03e bellard
    stl_phys(sm_state + 0x7fe8, ESI);
1356 3b21e03e bellard
    stl_phys(sm_state + 0x7fe4, EBP);
1357 3b21e03e bellard
    stl_phys(sm_state + 0x7fe0, ESP);
1358 3b21e03e bellard
    stl_phys(sm_state + 0x7fdc, EBX);
1359 3b21e03e bellard
    stl_phys(sm_state + 0x7fd8, EDX);
1360 3b21e03e bellard
    stl_phys(sm_state + 0x7fd4, ECX);
1361 3b21e03e bellard
    stl_phys(sm_state + 0x7fd0, EAX);
1362 3b21e03e bellard
    stl_phys(sm_state + 0x7fcc, env->dr[6]);
1363 3b21e03e bellard
    stl_phys(sm_state + 0x7fc8, env->dr[7]);
1364 3b21e03e bellard
    
1365 3b21e03e bellard
    stl_phys(sm_state + 0x7fc4, env->tr.selector);
1366 3b21e03e bellard
    stl_phys(sm_state + 0x7f64, env->tr.base);
1367 3b21e03e bellard
    stl_phys(sm_state + 0x7f60, env->tr.limit);
1368 3b21e03e bellard
    stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1369 3b21e03e bellard
    
1370 3b21e03e bellard
    stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1371 3b21e03e bellard
    stl_phys(sm_state + 0x7f80, env->ldt.base);
1372 3b21e03e bellard
    stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1373 3b21e03e bellard
    stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1374 3b21e03e bellard
    
1375 3b21e03e bellard
    stl_phys(sm_state + 0x7f74, env->gdt.base);
1376 3b21e03e bellard
    stl_phys(sm_state + 0x7f70, env->gdt.limit);
1377 3b21e03e bellard
1378 3b21e03e bellard
    stl_phys(sm_state + 0x7f58, env->idt.base);
1379 3b21e03e bellard
    stl_phys(sm_state + 0x7f54, env->idt.limit);
1380 3b21e03e bellard
1381 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1382 3b21e03e bellard
        dt = &env->segs[i];
1383 3b21e03e bellard
        if (i < 3)
1384 3b21e03e bellard
            offset = 0x7f84 + i * 12;
1385 3b21e03e bellard
        else
1386 3b21e03e bellard
            offset = 0x7f2c + (i - 3) * 12;
1387 3b21e03e bellard
        stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1388 3b21e03e bellard
        stl_phys(sm_state + offset + 8, dt->base);
1389 3b21e03e bellard
        stl_phys(sm_state + offset + 4, dt->limit);
1390 3b21e03e bellard
        stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1391 3b21e03e bellard
    }
1392 3b21e03e bellard
    stl_phys(sm_state + 0x7f14, env->cr[4]);
1393 3b21e03e bellard
1394 3b21e03e bellard
    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1395 3b21e03e bellard
    stl_phys(sm_state + 0x7ef8, env->smbase);
1396 3b21e03e bellard
#endif
1397 3b21e03e bellard
    /* init SMM cpu state */
1398 3b21e03e bellard
1399 8988ae89 bellard
#ifdef TARGET_X86_64
1400 8988ae89 bellard
    env->efer = 0;
1401 8988ae89 bellard
    env->hflags &= ~HF_LMA_MASK;
1402 8988ae89 bellard
#endif
1403 3b21e03e bellard
    load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1404 3b21e03e bellard
    env->eip = 0x00008000;
1405 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1406 3b21e03e bellard
                           0xffffffff, 0);
1407 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1408 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1409 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1410 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1411 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1412 3b21e03e bellard
    
1413 3b21e03e bellard
    cpu_x86_update_cr0(env, 
1414 3b21e03e bellard
                       env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1415 3b21e03e bellard
    cpu_x86_update_cr4(env, 0);
1416 3b21e03e bellard
    env->dr[7] = 0x00000400;
1417 3b21e03e bellard
    CC_OP = CC_OP_EFLAGS;
1418 3b21e03e bellard
}
1419 3b21e03e bellard
1420 3b21e03e bellard
void helper_rsm(void)
1421 3b21e03e bellard
{
1422 3b21e03e bellard
    target_ulong sm_state;
1423 3b21e03e bellard
    int i, offset;
1424 3b21e03e bellard
    uint32_t val;
1425 3b21e03e bellard
1426 3b21e03e bellard
    sm_state = env->smbase + 0x8000;
1427 3b21e03e bellard
#ifdef TARGET_X86_64
1428 8988ae89 bellard
    env->efer = ldq_phys(sm_state + 0x7ed0);
1429 8988ae89 bellard
    if (env->efer & MSR_EFER_LMA)
1430 8988ae89 bellard
        env->hflags |= HF_LMA_MASK;
1431 8988ae89 bellard
    else
1432 8988ae89 bellard
        env->hflags &= ~HF_LMA_MASK;
1433 8988ae89 bellard
1434 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1435 3b21e03e bellard
        offset = 0x7e00 + i * 16;
1436 3b21e03e bellard
        cpu_x86_load_seg_cache(env, i, 
1437 3b21e03e bellard
                               lduw_phys(sm_state + offset),
1438 3b21e03e bellard
                               ldq_phys(sm_state + offset + 8),
1439 3b21e03e bellard
                               ldl_phys(sm_state + offset + 4),
1440 3b21e03e bellard
                               (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1441 3b21e03e bellard
    }
1442 3b21e03e bellard
1443 3b21e03e bellard
    env->gdt.base = ldq_phys(sm_state + 0x7e68);
1444 3b21e03e bellard
    env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1445 3b21e03e bellard
1446 3b21e03e bellard
    env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1447 3b21e03e bellard
    env->ldt.base = ldq_phys(sm_state + 0x7e78);
1448 3b21e03e bellard
    env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1449 3b21e03e bellard
    env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1450 3b21e03e bellard
    
1451 3b21e03e bellard
    env->idt.base = ldq_phys(sm_state + 0x7e88);
1452 3b21e03e bellard
    env->idt.limit = ldl_phys(sm_state + 0x7e84);
1453 3b21e03e bellard
1454 3b21e03e bellard
    env->tr.selector = lduw_phys(sm_state + 0x7e90);
1455 3b21e03e bellard
    env->tr.base = ldq_phys(sm_state + 0x7e98);
1456 3b21e03e bellard
    env->tr.limit = ldl_phys(sm_state + 0x7e94);
1457 3b21e03e bellard
    env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1458 3b21e03e bellard
    
1459 3b21e03e bellard
    EAX = ldq_phys(sm_state + 0x7ff8);
1460 3b21e03e bellard
    ECX = ldq_phys(sm_state + 0x7ff0);
1461 3b21e03e bellard
    EDX = ldq_phys(sm_state + 0x7fe8);
1462 3b21e03e bellard
    EBX = ldq_phys(sm_state + 0x7fe0);
1463 3b21e03e bellard
    ESP = ldq_phys(sm_state + 0x7fd8);
1464 3b21e03e bellard
    EBP = ldq_phys(sm_state + 0x7fd0);
1465 3b21e03e bellard
    ESI = ldq_phys(sm_state + 0x7fc8);
1466 3b21e03e bellard
    EDI = ldq_phys(sm_state + 0x7fc0);
1467 3b21e03e bellard
    for(i = 8; i < 16; i++) 
1468 3b21e03e bellard
        env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1469 3b21e03e bellard
    env->eip = ldq_phys(sm_state + 0x7f78);
1470 3b21e03e bellard
    load_eflags(ldl_phys(sm_state + 0x7f70), 
1471 3b21e03e bellard
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1472 3b21e03e bellard
    env->dr[6] = ldl_phys(sm_state + 0x7f68);
1473 3b21e03e bellard
    env->dr[7] = ldl_phys(sm_state + 0x7f60);
1474 3b21e03e bellard
1475 3b21e03e bellard
    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1476 3b21e03e bellard
    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1477 3b21e03e bellard
    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1478 3b21e03e bellard
1479 3b21e03e bellard
    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1480 3b21e03e bellard
    if (val & 0x20000) {
1481 3b21e03e bellard
        env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1482 3b21e03e bellard
    }
1483 3b21e03e bellard
#else
1484 3b21e03e bellard
    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1485 3b21e03e bellard
    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1486 3b21e03e bellard
    load_eflags(ldl_phys(sm_state + 0x7ff4), 
1487 3b21e03e bellard
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1488 3b21e03e bellard
    env->eip = ldl_phys(sm_state + 0x7ff0);
1489 3b21e03e bellard
    EDI = ldl_phys(sm_state + 0x7fec);
1490 3b21e03e bellard
    ESI = ldl_phys(sm_state + 0x7fe8);
1491 3b21e03e bellard
    EBP = ldl_phys(sm_state + 0x7fe4);
1492 3b21e03e bellard
    ESP = ldl_phys(sm_state + 0x7fe0);
1493 3b21e03e bellard
    EBX = ldl_phys(sm_state + 0x7fdc);
1494 3b21e03e bellard
    EDX = ldl_phys(sm_state + 0x7fd8);
1495 3b21e03e bellard
    ECX = ldl_phys(sm_state + 0x7fd4);
1496 3b21e03e bellard
    EAX = ldl_phys(sm_state + 0x7fd0);
1497 3b21e03e bellard
    env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1498 3b21e03e bellard
    env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1499 3b21e03e bellard
    
1500 3b21e03e bellard
    env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1501 3b21e03e bellard
    env->tr.base = ldl_phys(sm_state + 0x7f64);
1502 3b21e03e bellard
    env->tr.limit = ldl_phys(sm_state + 0x7f60);
1503 3b21e03e bellard
    env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1504 3b21e03e bellard
    
1505 3b21e03e bellard
    env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1506 3b21e03e bellard
    env->ldt.base = ldl_phys(sm_state + 0x7f80);
1507 3b21e03e bellard
    env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1508 3b21e03e bellard
    env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1509 3b21e03e bellard
    
1510 3b21e03e bellard
    env->gdt.base = ldl_phys(sm_state + 0x7f74);
1511 3b21e03e bellard
    env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1512 3b21e03e bellard
1513 3b21e03e bellard
    env->idt.base = ldl_phys(sm_state + 0x7f58);
1514 3b21e03e bellard
    env->idt.limit = ldl_phys(sm_state + 0x7f54);
1515 3b21e03e bellard
1516 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1517 3b21e03e bellard
        if (i < 3)
1518 3b21e03e bellard
            offset = 0x7f84 + i * 12;
1519 3b21e03e bellard
        else
1520 3b21e03e bellard
            offset = 0x7f2c + (i - 3) * 12;
1521 3b21e03e bellard
        cpu_x86_load_seg_cache(env, i, 
1522 3b21e03e bellard
                               ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1523 3b21e03e bellard
                               ldl_phys(sm_state + offset + 8),
1524 3b21e03e bellard
                               ldl_phys(sm_state + offset + 4),
1525 3b21e03e bellard
                               (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1526 3b21e03e bellard
    }
1527 3b21e03e bellard
    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1528 3b21e03e bellard
1529 3b21e03e bellard
    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1530 3b21e03e bellard
    if (val & 0x20000) {
1531 3b21e03e bellard
        env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1532 3b21e03e bellard
    }
1533 3b21e03e bellard
#endif
1534 3b21e03e bellard
    CC_OP = CC_OP_EFLAGS;
1535 3b21e03e bellard
    env->hflags &= ~HF_SMM_MASK;
1536 3b21e03e bellard
    cpu_smm_update(env);
1537 3b21e03e bellard
1538 3b21e03e bellard
    if (loglevel & CPU_LOG_INT) {
1539 3b21e03e bellard
        fprintf(logfile, "SMM: after RSM\n");
1540 3b21e03e bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1541 3b21e03e bellard
    }
1542 3b21e03e bellard
}
1543 3b21e03e bellard
1544 74ce674f bellard
#endif /* !CONFIG_USER_ONLY */
1545 74ce674f bellard
1546 74ce674f bellard
1547 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1548 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1549 2c0262af bellard
   call it from another function */
1550 45bbbb46 bellard
uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1551 2c0262af bellard
{
1552 2c0262af bellard
    *q_ptr = num / den;
1553 2c0262af bellard
    return num % den;
1554 2c0262af bellard
}
1555 2c0262af bellard
1556 45bbbb46 bellard
int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1557 2c0262af bellard
{
1558 2c0262af bellard
    *q_ptr = num / den;
1559 2c0262af bellard
    return num % den;
1560 2c0262af bellard
}
1561 2c0262af bellard
#endif
1562 2c0262af bellard
1563 14ce26e7 bellard
void helper_divl_EAX_T0(void)
1564 2c0262af bellard
{
1565 45bbbb46 bellard
    unsigned int den, r;
1566 45bbbb46 bellard
    uint64_t num, q;
1567 2c0262af bellard
    
1568 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1569 2c0262af bellard
    den = T0;
1570 2c0262af bellard
    if (den == 0) {
1571 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1572 2c0262af bellard
    }
1573 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1574 14ce26e7 bellard
    r = div32(&q, num, den);
1575 2c0262af bellard
#else
1576 2c0262af bellard
    q = (num / den);
1577 2c0262af bellard
    r = (num % den);
1578 2c0262af bellard
#endif
1579 45bbbb46 bellard
    if (q > 0xffffffff)
1580 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1581 14ce26e7 bellard
    EAX = (uint32_t)q;
1582 14ce26e7 bellard
    EDX = (uint32_t)r;
1583 2c0262af bellard
}
1584 2c0262af bellard
1585 14ce26e7 bellard
void helper_idivl_EAX_T0(void)
1586 2c0262af bellard
{
1587 45bbbb46 bellard
    int den, r;
1588 45bbbb46 bellard
    int64_t num, q;
1589 2c0262af bellard
    
1590 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1591 2c0262af bellard
    den = T0;
1592 2c0262af bellard
    if (den == 0) {
1593 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1594 2c0262af bellard
    }
1595 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1596 14ce26e7 bellard
    r = idiv32(&q, num, den);
1597 2c0262af bellard
#else
1598 2c0262af bellard
    q = (num / den);
1599 2c0262af bellard
    r = (num % den);
1600 2c0262af bellard
#endif
1601 45bbbb46 bellard
    if (q != (int32_t)q)
1602 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1603 14ce26e7 bellard
    EAX = (uint32_t)q;
1604 14ce26e7 bellard
    EDX = (uint32_t)r;
1605 2c0262af bellard
}
1606 2c0262af bellard
1607 2c0262af bellard
void helper_cmpxchg8b(void)
1608 2c0262af bellard
{
1609 2c0262af bellard
    uint64_t d;
1610 2c0262af bellard
    int eflags;
1611 2c0262af bellard
1612 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
1613 14ce26e7 bellard
    d = ldq(A0);
1614 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
1615 14ce26e7 bellard
        stq(A0, ((uint64_t)ECX << 32) | EBX);
1616 2c0262af bellard
        eflags |= CC_Z;
1617 2c0262af bellard
    } else {
1618 2c0262af bellard
        EDX = d >> 32;
1619 2c0262af bellard
        EAX = d;
1620 2c0262af bellard
        eflags &= ~CC_Z;
1621 2c0262af bellard
    }
1622 2c0262af bellard
    CC_SRC = eflags;
1623 2c0262af bellard
}
1624 2c0262af bellard
1625 2c0262af bellard
void helper_cpuid(void)
1626 2c0262af bellard
{
1627 f419b321 bellard
    uint32_t index;
1628 f419b321 bellard
    index = (uint32_t)EAX;
1629 f419b321 bellard
    
1630 f419b321 bellard
    /* test if maximum index reached */
1631 f419b321 bellard
    if (index & 0x80000000) {
1632 f419b321 bellard
        if (index > env->cpuid_xlevel) 
1633 f419b321 bellard
            index = env->cpuid_level;
1634 f419b321 bellard
    } else {
1635 f419b321 bellard
        if (index > env->cpuid_level) 
1636 f419b321 bellard
            index = env->cpuid_level;
1637 f419b321 bellard
    }
1638 f419b321 bellard
        
1639 f419b321 bellard
    switch(index) {
1640 8e682019 bellard
    case 0:
1641 f419b321 bellard
        EAX = env->cpuid_level;
1642 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1643 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1644 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1645 8e682019 bellard
        break;
1646 8e682019 bellard
    case 1:
1647 14ce26e7 bellard
        EAX = env->cpuid_version;
1648 eae7629b ths
        EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
1649 9df217a3 bellard
        ECX = env->cpuid_ext_features;
1650 14ce26e7 bellard
        EDX = env->cpuid_features;
1651 8e682019 bellard
        break;
1652 f419b321 bellard
    case 2:
1653 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1654 8e682019 bellard
        EAX = 0x410601;
1655 2c0262af bellard
        EBX = 0;
1656 2c0262af bellard
        ECX = 0;
1657 8e682019 bellard
        EDX = 0;
1658 8e682019 bellard
        break;
1659 14ce26e7 bellard
    case 0x80000000:
1660 f419b321 bellard
        EAX = env->cpuid_xlevel;
1661 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1662 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1663 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1664 14ce26e7 bellard
        break;
1665 14ce26e7 bellard
    case 0x80000001:
1666 14ce26e7 bellard
        EAX = env->cpuid_features;
1667 14ce26e7 bellard
        EBX = 0;
1668 14ce26e7 bellard
        ECX = 0;
1669 f419b321 bellard
        EDX = env->cpuid_ext2_features;
1670 f419b321 bellard
        break;
1671 f419b321 bellard
    case 0x80000002:
1672 f419b321 bellard
    case 0x80000003:
1673 f419b321 bellard
    case 0x80000004:
1674 f419b321 bellard
        EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
1675 f419b321 bellard
        EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
1676 f419b321 bellard
        ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
1677 f419b321 bellard
        EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
1678 14ce26e7 bellard
        break;
1679 8f091a59 bellard
    case 0x80000005:
1680 8f091a59 bellard
        /* cache info (L1 cache) */
1681 8f091a59 bellard
        EAX = 0x01ff01ff;
1682 8f091a59 bellard
        EBX = 0x01ff01ff;
1683 8f091a59 bellard
        ECX = 0x40020140;
1684 8f091a59 bellard
        EDX = 0x40020140;
1685 8f091a59 bellard
        break;
1686 8f091a59 bellard
    case 0x80000006:
1687 8f091a59 bellard
        /* cache info (L2 cache) */
1688 8f091a59 bellard
        EAX = 0;
1689 8f091a59 bellard
        EBX = 0x42004200;
1690 8f091a59 bellard
        ECX = 0x02008140;
1691 8f091a59 bellard
        EDX = 0;
1692 8f091a59 bellard
        break;
1693 14ce26e7 bellard
    case 0x80000008:
1694 14ce26e7 bellard
        /* virtual & phys address size in low 2 bytes. */
1695 14ce26e7 bellard
        EAX = 0x00003028;
1696 14ce26e7 bellard
        EBX = 0;
1697 14ce26e7 bellard
        ECX = 0;
1698 14ce26e7 bellard
        EDX = 0;
1699 14ce26e7 bellard
        break;
1700 f419b321 bellard
    default:
1701 f419b321 bellard
        /* reserved values: zero */
1702 f419b321 bellard
        EAX = 0;
1703 f419b321 bellard
        EBX = 0;
1704 f419b321 bellard
        ECX = 0;
1705 f419b321 bellard
        EDX = 0;
1706 f419b321 bellard
        break;
1707 2c0262af bellard
    }
1708 2c0262af bellard
}
1709 2c0262af bellard
1710 61a8c4ec bellard
void helper_enter_level(int level, int data32)
1711 61a8c4ec bellard
{
1712 14ce26e7 bellard
    target_ulong ssp;
1713 61a8c4ec bellard
    uint32_t esp_mask, esp, ebp;
1714 61a8c4ec bellard
1715 61a8c4ec bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1716 61a8c4ec bellard
    ssp = env->segs[R_SS].base;
1717 61a8c4ec bellard
    ebp = EBP;
1718 61a8c4ec bellard
    esp = ESP;
1719 61a8c4ec bellard
    if (data32) {
1720 61a8c4ec bellard
        /* 32 bit */
1721 61a8c4ec bellard
        esp -= 4;
1722 61a8c4ec bellard
        while (--level) {
1723 61a8c4ec bellard
            esp -= 4;
1724 61a8c4ec bellard
            ebp -= 4;
1725 61a8c4ec bellard
            stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1726 61a8c4ec bellard
        }
1727 61a8c4ec bellard
        esp -= 4;
1728 61a8c4ec bellard
        stl(ssp + (esp & esp_mask), T1);
1729 61a8c4ec bellard
    } else {
1730 61a8c4ec bellard
        /* 16 bit */
1731 61a8c4ec bellard
        esp -= 2;
1732 61a8c4ec bellard
        while (--level) {
1733 61a8c4ec bellard
            esp -= 2;
1734 61a8c4ec bellard
            ebp -= 2;
1735 61a8c4ec bellard
            stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1736 61a8c4ec bellard
        }
1737 61a8c4ec bellard
        esp -= 2;
1738 61a8c4ec bellard
        stw(ssp + (esp & esp_mask), T1);
1739 61a8c4ec bellard
    }
1740 61a8c4ec bellard
}
1741 61a8c4ec bellard
1742 8f091a59 bellard
#ifdef TARGET_X86_64
1743 8f091a59 bellard
void helper_enter64_level(int level, int data64)
1744 8f091a59 bellard
{
1745 8f091a59 bellard
    target_ulong esp, ebp;
1746 8f091a59 bellard
    ebp = EBP;
1747 8f091a59 bellard
    esp = ESP;
1748 8f091a59 bellard
1749 8f091a59 bellard
    if (data64) {
1750 8f091a59 bellard
        /* 64 bit */
1751 8f091a59 bellard
        esp -= 8;
1752 8f091a59 bellard
        while (--level) {
1753 8f091a59 bellard
            esp -= 8;
1754 8f091a59 bellard
            ebp -= 8;
1755 8f091a59 bellard
            stq(esp, ldq(ebp));
1756 8f091a59 bellard
        }
1757 8f091a59 bellard
        esp -= 8;
1758 8f091a59 bellard
        stq(esp, T1);
1759 8f091a59 bellard
    } else {
1760 8f091a59 bellard
        /* 16 bit */
1761 8f091a59 bellard
        esp -= 2;
1762 8f091a59 bellard
        while (--level) {
1763 8f091a59 bellard
            esp -= 2;
1764 8f091a59 bellard
            ebp -= 2;
1765 8f091a59 bellard
            stw(esp, lduw(ebp));
1766 8f091a59 bellard
        }
1767 8f091a59 bellard
        esp -= 2;
1768 8f091a59 bellard
        stw(esp, T1);
1769 8f091a59 bellard
    }
1770 8f091a59 bellard
}
1771 8f091a59 bellard
#endif
1772 8f091a59 bellard
1773 2c0262af bellard
void helper_lldt_T0(void)
1774 2c0262af bellard
{
1775 2c0262af bellard
    int selector;
1776 2c0262af bellard
    SegmentCache *dt;
1777 2c0262af bellard
    uint32_t e1, e2;
1778 14ce26e7 bellard
    int index, entry_limit;
1779 14ce26e7 bellard
    target_ulong ptr;
1780 2c0262af bellard
    
1781 2c0262af bellard
    selector = T0 & 0xffff;
1782 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1783 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1784 14ce26e7 bellard
        env->ldt.base = 0;
1785 2c0262af bellard
        env->ldt.limit = 0;
1786 2c0262af bellard
    } else {
1787 2c0262af bellard
        if (selector & 0x4)
1788 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1789 2c0262af bellard
        dt = &env->gdt;
1790 2c0262af bellard
        index = selector & ~7;
1791 14ce26e7 bellard
#ifdef TARGET_X86_64
1792 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1793 14ce26e7 bellard
            entry_limit = 15;
1794 14ce26e7 bellard
        else
1795 14ce26e7 bellard
#endif            
1796 14ce26e7 bellard
            entry_limit = 7;
1797 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1798 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1799 2c0262af bellard
        ptr = dt->base + index;
1800 61382a50 bellard
        e1 = ldl_kernel(ptr);
1801 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1802 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1803 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1804 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1805 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1806 14ce26e7 bellard
#ifdef TARGET_X86_64
1807 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1808 14ce26e7 bellard
            uint32_t e3;
1809 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1810 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1811 14ce26e7 bellard
            env->ldt.base |= (target_ulong)e3 << 32;
1812 14ce26e7 bellard
        } else
1813 14ce26e7 bellard
#endif
1814 14ce26e7 bellard
        {
1815 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1816 14ce26e7 bellard
        }
1817 2c0262af bellard
    }
1818 2c0262af bellard
    env->ldt.selector = selector;
1819 2c0262af bellard
}
1820 2c0262af bellard
1821 2c0262af bellard
void helper_ltr_T0(void)
1822 2c0262af bellard
{
1823 2c0262af bellard
    int selector;
1824 2c0262af bellard
    SegmentCache *dt;
1825 2c0262af bellard
    uint32_t e1, e2;
1826 14ce26e7 bellard
    int index, type, entry_limit;
1827 14ce26e7 bellard
    target_ulong ptr;
1828 2c0262af bellard
    
1829 2c0262af bellard
    selector = T0 & 0xffff;
1830 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1831 14ce26e7 bellard
        /* NULL selector case: invalid TR */
1832 14ce26e7 bellard
        env->tr.base = 0;
1833 2c0262af bellard
        env->tr.limit = 0;
1834 2c0262af bellard
        env->tr.flags = 0;
1835 2c0262af bellard
    } else {
1836 2c0262af bellard
        if (selector & 0x4)
1837 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1838 2c0262af bellard
        dt = &env->gdt;
1839 2c0262af bellard
        index = selector & ~7;
1840 14ce26e7 bellard
#ifdef TARGET_X86_64
1841 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1842 14ce26e7 bellard
            entry_limit = 15;
1843 14ce26e7 bellard
        else
1844 14ce26e7 bellard
#endif            
1845 14ce26e7 bellard
            entry_limit = 7;
1846 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1847 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1848 2c0262af bellard
        ptr = dt->base + index;
1849 61382a50 bellard
        e1 = ldl_kernel(ptr);
1850 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1851 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1852 2c0262af bellard
        if ((e2 & DESC_S_MASK) || 
1853 7e84c249 bellard
            (type != 1 && type != 9))
1854 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1855 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1856 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1857 14ce26e7 bellard
#ifdef TARGET_X86_64
1858 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1859 b0ee3ff0 ths
            uint32_t e3, e4;
1860 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1861 b0ee3ff0 ths
            e4 = ldl_kernel(ptr + 12);
1862 b0ee3ff0 ths
            if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
1863 b0ee3ff0 ths
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1864 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1865 14ce26e7 bellard
            env->tr.base |= (target_ulong)e3 << 32;
1866 14ce26e7 bellard
        } else 
1867 14ce26e7 bellard
#endif
1868 14ce26e7 bellard
        {
1869 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1870 14ce26e7 bellard
        }
1871 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1872 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1873 2c0262af bellard
    }
1874 2c0262af bellard
    env->tr.selector = selector;
1875 2c0262af bellard
}
1876 2c0262af bellard
1877 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1878 8e682019 bellard
void load_seg(int seg_reg, int selector)
1879 2c0262af bellard
{
1880 2c0262af bellard
    uint32_t e1, e2;
1881 3ab493de bellard
    int cpl, dpl, rpl;
1882 3ab493de bellard
    SegmentCache *dt;
1883 3ab493de bellard
    int index;
1884 14ce26e7 bellard
    target_ulong ptr;
1885 3ab493de bellard
1886 8e682019 bellard
    selector &= 0xffff;
1887 b359d4e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1888 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1889 2c0262af bellard
        /* null selector case */
1890 4d6b6c0a bellard
        if (seg_reg == R_SS
1891 4d6b6c0a bellard
#ifdef TARGET_X86_64
1892 b359d4e7 bellard
            && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
1893 4d6b6c0a bellard
#endif
1894 4d6b6c0a bellard
            )
1895 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1896 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
1897 2c0262af bellard
    } else {
1898 3ab493de bellard
        
1899 3ab493de bellard
        if (selector & 0x4)
1900 3ab493de bellard
            dt = &env->ldt;
1901 3ab493de bellard
        else
1902 3ab493de bellard
            dt = &env->gdt;
1903 3ab493de bellard
        index = selector & ~7;
1904 8e682019 bellard
        if ((index + 7) > dt->limit)
1905 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1906 3ab493de bellard
        ptr = dt->base + index;
1907 3ab493de bellard
        e1 = ldl_kernel(ptr);
1908 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1909 14ce26e7 bellard
        
1910 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1911 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1912 3ab493de bellard
        rpl = selector & 3;
1913 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1914 2c0262af bellard
        if (seg_reg == R_SS) {
1915 3ab493de bellard
            /* must be writable segment */
1916 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1917 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1918 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1919 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1920 2c0262af bellard
        } else {
1921 3ab493de bellard
            /* must be readable segment */
1922 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1923 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1924 3ab493de bellard
            
1925 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1926 3ab493de bellard
                /* if not conforming code, test rights */
1927 89984cd2 bellard
                if (dpl < cpl || dpl < rpl) 
1928 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1929 3ab493de bellard
            }
1930 2c0262af bellard
        }
1931 2c0262af bellard
1932 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1933 2c0262af bellard
            if (seg_reg == R_SS)
1934 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1935 2c0262af bellard
            else
1936 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1937 2c0262af bellard
        }
1938 3ab493de bellard
1939 3ab493de bellard
        /* set the access bit if not already set */
1940 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1941 3ab493de bellard
            e2 |= DESC_A_MASK;
1942 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1943 3ab493de bellard
        }
1944 3ab493de bellard
1945 2c0262af bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
1946 2c0262af bellard
                       get_seg_base(e1, e2),
1947 2c0262af bellard
                       get_seg_limit(e1, e2),
1948 2c0262af bellard
                       e2);
1949 2c0262af bellard
#if 0
1950 2c0262af bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
1951 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1952 2c0262af bellard
#endif
1953 2c0262af bellard
    }
1954 2c0262af bellard
}
1955 2c0262af bellard
1956 2c0262af bellard
/* protected mode jump */
1957 f419b321 bellard
void helper_ljmp_protected_T0_T1(int next_eip_addend)
1958 2c0262af bellard
{
1959 14ce26e7 bellard
    int new_cs, gate_cs, type;
1960 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
1961 f419b321 bellard
    target_ulong new_eip, next_eip;
1962 14ce26e7 bellard
    
1963 2c0262af bellard
    new_cs = T0;
1964 2c0262af bellard
    new_eip = T1;
1965 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
1966 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
1967 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
1968 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1969 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1970 2c0262af bellard
    if (e2 & DESC_S_MASK) {
1971 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
1972 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1973 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1974 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
1975 2c0262af bellard
            /* conforming code segment */
1976 2c0262af bellard
            if (dpl > cpl)
1977 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1978 2c0262af bellard
        } else {
1979 2c0262af bellard
            /* non conforming code segment */
1980 2c0262af bellard
            rpl = new_cs & 3;
1981 2c0262af bellard
            if (rpl > cpl)
1982 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1983 2c0262af bellard
            if (dpl != cpl)
1984 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1985 2c0262af bellard
        }
1986 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1987 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1988 2c0262af bellard
        limit = get_seg_limit(e1, e2);
1989 ca954f6d bellard
        if (new_eip > limit && 
1990 ca954f6d bellard
            !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
1991 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1992 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1993 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
1994 2c0262af bellard
        EIP = new_eip;
1995 2c0262af bellard
    } else {
1996 7e84c249 bellard
        /* jump to call or task gate */
1997 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1998 7e84c249 bellard
        rpl = new_cs & 3;
1999 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
2000 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2001 7e84c249 bellard
        switch(type) {
2002 7e84c249 bellard
        case 1: /* 286 TSS */
2003 7e84c249 bellard
        case 9: /* 386 TSS */
2004 7e84c249 bellard
        case 5: /* task gate */
2005 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
2006 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2007 f419b321 bellard
            next_eip = env->eip + next_eip_addend;
2008 08cea4ee bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2009 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
2010 7e84c249 bellard
            break;
2011 7e84c249 bellard
        case 4: /* 286 call gate */
2012 7e84c249 bellard
        case 12: /* 386 call gate */
2013 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
2014 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2015 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
2016 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2017 7e84c249 bellard
            gate_cs = e1 >> 16;
2018 516633dc bellard
            new_eip = (e1 & 0xffff);
2019 516633dc bellard
            if (type == 12)
2020 516633dc bellard
                new_eip |= (e2 & 0xffff0000);
2021 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
2022 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2023 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2024 7e84c249 bellard
            /* must be code segment */
2025 7e84c249 bellard
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
2026 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
2027 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2028 14ce26e7 bellard
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) || 
2029 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2030 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2031 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
2032 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2033 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
2034 7e84c249 bellard
            if (new_eip > limit)
2035 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
2036 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2037 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
2038 7e84c249 bellard
            EIP = new_eip;
2039 7e84c249 bellard
            break;
2040 7e84c249 bellard
        default:
2041 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2042 7e84c249 bellard
            break;
2043 7e84c249 bellard
        }
2044 2c0262af bellard
    }
2045 2c0262af bellard
}
2046 2c0262af bellard
2047 2c0262af bellard
/* real mode call */
2048 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
2049 2c0262af bellard
{
2050 2c0262af bellard
    int new_cs, new_eip;
2051 2c0262af bellard
    uint32_t esp, esp_mask;
2052 14ce26e7 bellard
    target_ulong ssp;
2053 2c0262af bellard
2054 2c0262af bellard
    new_cs = T0;
2055 2c0262af bellard
    new_eip = T1;
2056 2c0262af bellard
    esp = ESP;
2057 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
2058 2c0262af bellard
    ssp = env->segs[R_SS].base;
2059 2c0262af bellard
    if (shift) {
2060 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2061 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
2062 2c0262af bellard
    } else {
2063 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2064 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
2065 2c0262af bellard
    }
2066 2c0262af bellard
2067 8d7b0fbb bellard
    SET_ESP(esp, esp_mask);
2068 2c0262af bellard
    env->eip = new_eip;
2069 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
2070 14ce26e7 bellard
    env->segs[R_CS].base = (new_cs << 4);
2071 2c0262af bellard
}
2072 2c0262af bellard
2073 2c0262af bellard
/* protected mode call */
2074 f419b321 bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
2075 2c0262af bellard
{
2076 649ea05a bellard
    int new_cs, new_stack, i;
2077 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2078 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2079 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
2080 649ea05a bellard
    target_ulong ssp, old_ssp, next_eip, new_eip;
2081 2c0262af bellard
    
2082 2c0262af bellard
    new_cs = T0;
2083 2c0262af bellard
    new_eip = T1;
2084 f419b321 bellard
    next_eip = env->eip + next_eip_addend;
2085 f3f2d9be bellard
#ifdef DEBUG_PCALL
2086 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2087 e19e89a5 bellard
        fprintf(logfile, "lcall %04x:%08x s=%d\n",
2088 649ea05a bellard
                new_cs, (uint32_t)new_eip, shift);
2089 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2090 f3f2d9be bellard
    }
2091 f3f2d9be bellard
#endif
2092 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2093 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
2094 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2095 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2096 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2097 f3f2d9be bellard
#ifdef DEBUG_PCALL
2098 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2099 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2100 f3f2d9be bellard
    }
2101 f3f2d9be bellard
#endif
2102 2c0262af bellard
    if (e2 & DESC_S_MASK) {
2103 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
2104 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2105 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2106 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
2107 2c0262af bellard
            /* conforming code segment */
2108 2c0262af bellard
            if (dpl > cpl)
2109 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2110 2c0262af bellard
        } else {
2111 2c0262af bellard
            /* non conforming code segment */
2112 2c0262af bellard
            rpl = new_cs & 3;
2113 2c0262af bellard
            if (rpl > cpl)
2114 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2115 2c0262af bellard
            if (dpl != cpl)
2116 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2117 2c0262af bellard
        }
2118 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2119 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2120 2c0262af bellard
2121 f419b321 bellard
#ifdef TARGET_X86_64
2122 f419b321 bellard
        /* XXX: check 16/32 bit cases in long mode */
2123 f419b321 bellard
        if (shift == 2) {
2124 f419b321 bellard
            target_ulong rsp;
2125 f419b321 bellard
            /* 64 bit case */
2126 f419b321 bellard
            rsp = ESP;
2127 f419b321 bellard
            PUSHQ(rsp, env->segs[R_CS].selector);
2128 f419b321 bellard
            PUSHQ(rsp, next_eip);
2129 f419b321 bellard
            /* from this point, not restartable */
2130 f419b321 bellard
            ESP = rsp;
2131 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2132 f419b321 bellard
                                   get_seg_base(e1, e2), 
2133 f419b321 bellard
                                   get_seg_limit(e1, e2), e2);
2134 f419b321 bellard
            EIP = new_eip;
2135 f419b321 bellard
        } else 
2136 f419b321 bellard
#endif
2137 f419b321 bellard
        {
2138 f419b321 bellard
            sp = ESP;
2139 f419b321 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
2140 f419b321 bellard
            ssp = env->segs[R_SS].base;
2141 f419b321 bellard
            if (shift) {
2142 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2143 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, next_eip);
2144 f419b321 bellard
            } else {
2145 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2146 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, next_eip);
2147 f419b321 bellard
            }
2148 f419b321 bellard
            
2149 f419b321 bellard
            limit = get_seg_limit(e1, e2);
2150 f419b321 bellard
            if (new_eip > limit)
2151 f419b321 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2152 f419b321 bellard
            /* from this point, not restartable */
2153 8d7b0fbb bellard
            SET_ESP(sp, sp_mask);
2154 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2155 f419b321 bellard
                                   get_seg_base(e1, e2), limit, e2);
2156 f419b321 bellard
            EIP = new_eip;
2157 2c0262af bellard
        }
2158 2c0262af bellard
    } else {
2159 2c0262af bellard
        /* check gate type */
2160 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2161 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2162 7e84c249 bellard
        rpl = new_cs & 3;
2163 2c0262af bellard
        switch(type) {
2164 2c0262af bellard
        case 1: /* available 286 TSS */
2165 2c0262af bellard
        case 9: /* available 386 TSS */
2166 2c0262af bellard
        case 5: /* task gate */
2167 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
2168 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2169 883da8e2 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2170 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
2171 8145122b bellard
            return;
2172 2c0262af bellard
        case 4: /* 286 call gate */
2173 2c0262af bellard
        case 12: /* 386 call gate */
2174 2c0262af bellard
            break;
2175 2c0262af bellard
        default:
2176 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2177 2c0262af bellard
            break;
2178 2c0262af bellard
        }
2179 2c0262af bellard
        shift = type >> 3;
2180 2c0262af bellard
2181 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
2182 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2183 2c0262af bellard
        /* check valid bit */
2184 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2185 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
2186 2c0262af bellard
        selector = e1 >> 16;
2187 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2188 f3f2d9be bellard
        param_count = e2 & 0x1f;
2189 2c0262af bellard
        if ((selector & 0xfffc) == 0)
2190 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
2191 2c0262af bellard
2192 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
2193 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2194 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2195 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2196 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2197 2c0262af bellard
        if (dpl > cpl)
2198 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2199 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2200 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2201 2c0262af bellard
2202 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2203 7f75ffd3 blueswir1
            /* to inner privilege */
2204 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
2205 f3f2d9be bellard
#ifdef DEBUG_PCALL
2206 e19e89a5 bellard
            if (loglevel & CPU_LOG_PCALL)
2207 14ce26e7 bellard
                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", 
2208 f3f2d9be bellard
                        ss, sp, param_count, ESP);
2209 f3f2d9be bellard
#endif
2210 2c0262af bellard
            if ((ss & 0xfffc) == 0)
2211 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2212 2c0262af bellard
            if ((ss & 3) != dpl)
2213 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2214 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2215 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2216 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2217 2c0262af bellard
            if (ss_dpl != dpl)
2218 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2219 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
2220 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
2221 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
2222 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2223 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
2224 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2225 2c0262af bellard
            
2226 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
2227 2c0262af bellard
2228 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2229 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
2230 2c0262af bellard
            
2231 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
2232 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
2233 2c0262af bellard
            if (shift) {
2234 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2235 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
2236 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
2237 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2238 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
2239 2c0262af bellard
                }
2240 2c0262af bellard
            } else {
2241 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2242 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
2243 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
2244 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2245 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
2246 2c0262af bellard
                }
2247 2c0262af bellard
            }
2248 891b38e4 bellard
            new_stack = 1;
2249 2c0262af bellard
        } else {
2250 7f75ffd3 blueswir1
            /* to same privilege */
2251 891b38e4 bellard
            sp = ESP;
2252 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
2253 891b38e4 bellard
            ssp = env->segs[R_SS].base;
2254 891b38e4 bellard
            //            push_size = (4 << shift);
2255 891b38e4 bellard
            new_stack = 0;
2256 2c0262af bellard
        }
2257 2c0262af bellard
2258 2c0262af bellard
        if (shift) {
2259 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2260 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
2261 2c0262af bellard
        } else {
2262 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2263 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
2264 891b38e4 bellard
        }
2265 891b38e4 bellard
2266 891b38e4 bellard
        /* from this point, not restartable */
2267 891b38e4 bellard
2268 891b38e4 bellard
        if (new_stack) {
2269 891b38e4 bellard
            ss = (ss & ~3) | dpl;
2270 891b38e4 bellard
            cpu_x86_load_seg_cache(env, R_SS, ss, 
2271 891b38e4 bellard
                                   ssp,
2272 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
2273 891b38e4 bellard
                                   ss_e2);
2274 2c0262af bellard
        }
2275 2c0262af bellard
2276 2c0262af bellard
        selector = (selector & ~3) | dpl;
2277 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, selector, 
2278 2c0262af bellard
                       get_seg_base(e1, e2),
2279 2c0262af bellard
                       get_seg_limit(e1, e2),
2280 2c0262af bellard
                       e2);
2281 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
2282 8d7b0fbb bellard
        SET_ESP(sp, sp_mask);
2283 2c0262af bellard
        EIP = offset;
2284 2c0262af bellard
    }
2285 9df217a3 bellard
#ifdef USE_KQEMU
2286 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2287 9df217a3 bellard
        env->exception_index = -1;
2288 9df217a3 bellard
        cpu_loop_exit();
2289 9df217a3 bellard
    }
2290 9df217a3 bellard
#endif
2291 2c0262af bellard
}
2292 2c0262af bellard
2293 7e84c249 bellard
/* real and vm86 mode iret */
2294 2c0262af bellard
void helper_iret_real(int shift)
2295 2c0262af bellard
{
2296 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2297 14ce26e7 bellard
    target_ulong ssp;
2298 2c0262af bellard
    int eflags_mask;
2299 7e84c249 bellard
2300 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2301 891b38e4 bellard
    sp = ESP;
2302 891b38e4 bellard
    ssp = env->segs[R_SS].base;
2303 2c0262af bellard
    if (shift == 1) {
2304 2c0262af bellard
        /* 32 bits */
2305 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
2306 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
2307 891b38e4 bellard
        new_cs &= 0xffff;
2308 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
2309 2c0262af bellard
    } else {
2310 2c0262af bellard
        /* 16 bits */
2311 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
2312 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
2313 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
2314 2c0262af bellard
    }
2315 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2316 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
2317 2c0262af bellard
    env->eip = new_eip;
2318 7e84c249 bellard
    if (env->eflags & VM_MASK)
2319 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2320 7e84c249 bellard
    else
2321 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2322 2c0262af bellard
    if (shift == 0)
2323 2c0262af bellard
        eflags_mask &= 0xffff;
2324 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
2325 2c0262af bellard
}
2326 2c0262af bellard
2327 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
2328 8e682019 bellard
{
2329 8e682019 bellard
    int dpl;
2330 8e682019 bellard
    uint32_t e2;
2331 cd072e01 bellard
2332 cd072e01 bellard
    /* XXX: on x86_64, we do not want to nullify FS and GS because
2333 cd072e01 bellard
       they may still contain a valid base. I would be interested to
2334 cd072e01 bellard
       know how a real x86_64 CPU behaves */
2335 cd072e01 bellard
    if ((seg_reg == R_FS || seg_reg == R_GS) && 
2336 cd072e01 bellard
        (env->segs[seg_reg].selector & 0xfffc) == 0)
2337 cd072e01 bellard
        return;
2338 cd072e01 bellard
2339 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
2340 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2341 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2342 8e682019 bellard
        /* data or non conforming code segment */
2343 8e682019 bellard
        if (dpl < cpl) {
2344 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2345 8e682019 bellard
        }
2346 8e682019 bellard
    }
2347 8e682019 bellard
}
2348 8e682019 bellard
2349 2c0262af bellard
/* protected mode iret */
2350 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
2351 2c0262af bellard
{
2352 14ce26e7 bellard
    uint32_t new_cs, new_eflags, new_ss;
2353 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
2354 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
2355 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
2356 14ce26e7 bellard
    target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2357 2c0262af bellard
    
2358 14ce26e7 bellard
#ifdef TARGET_X86_64
2359 14ce26e7 bellard
    if (shift == 2)
2360 14ce26e7 bellard
        sp_mask = -1;
2361 14ce26e7 bellard
    else
2362 14ce26e7 bellard
#endif
2363 14ce26e7 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
2364 2c0262af bellard
    sp = ESP;
2365 891b38e4 bellard
    ssp = env->segs[R_SS].base;
2366 354ff226 bellard
    new_eflags = 0; /* avoid warning */
2367 14ce26e7 bellard
#ifdef TARGET_X86_64
2368 14ce26e7 bellard
    if (shift == 2) {
2369 14ce26e7 bellard
        POPQ(sp, new_eip);
2370 14ce26e7 bellard
        POPQ(sp, new_cs);
2371 14ce26e7 bellard
        new_cs &= 0xffff;
2372 14ce26e7 bellard
        if (is_iret) {
2373 14ce26e7 bellard
            POPQ(sp, new_eflags);
2374 14ce26e7 bellard
        }
2375 14ce26e7 bellard
    } else
2376 14ce26e7 bellard
#endif
2377 2c0262af bellard
    if (shift == 1) {
2378 2c0262af bellard
        /* 32 bits */
2379 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
2380 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
2381 891b38e4 bellard
        new_cs &= 0xffff;
2382 891b38e4 bellard
        if (is_iret) {
2383 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
2384 891b38e4 bellard
            if (new_eflags & VM_MASK)
2385 891b38e4 bellard
                goto return_to_vm86;
2386 891b38e4 bellard
        }
2387 2c0262af bellard
    } else {
2388 2c0262af bellard
        /* 16 bits */
2389 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
2390 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
2391 2c0262af bellard
        if (is_iret)
2392 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
2393 2c0262af bellard
    }
2394 891b38e4 bellard
#ifdef DEBUG_PCALL
2395 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2396 14ce26e7 bellard
        fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2397 e19e89a5 bellard
                new_cs, new_eip, shift, addend);
2398 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2399 891b38e4 bellard
    }
2400 891b38e4 bellard
#endif
2401 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2402 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2403 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2404 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2405 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
2406 2c0262af bellard
        !(e2 & DESC_CS_MASK))
2407 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2408 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2409 2c0262af bellard
    rpl = new_cs & 3; 
2410 2c0262af bellard
    if (rpl < cpl)
2411 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2412 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2413 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
2414 2c0262af bellard
        if (dpl > rpl)
2415 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2416 2c0262af bellard
    } else {
2417 2c0262af bellard
        if (dpl != rpl)
2418 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2419 2c0262af bellard
    }
2420 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
2421 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2422 2c0262af bellard
    
2423 891b38e4 bellard
    sp += addend;
2424 ca954f6d bellard
    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || 
2425 ca954f6d bellard
                       ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2426 2c0262af bellard
        /* return to same priledge level */
2427 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
2428 2c0262af bellard
                       get_seg_base(e1, e2),
2429 2c0262af bellard
                       get_seg_limit(e1, e2),
2430 2c0262af bellard
                       e2);
2431 2c0262af bellard
    } else {
2432 7f75ffd3 blueswir1
        /* return to different privilege level */
2433 14ce26e7 bellard
#ifdef TARGET_X86_64
2434 14ce26e7 bellard
        if (shift == 2) {
2435 14ce26e7 bellard
            POPQ(sp, new_esp);
2436 14ce26e7 bellard
            POPQ(sp, new_ss);
2437 14ce26e7 bellard
            new_ss &= 0xffff;
2438 14ce26e7 bellard
        } else
2439 14ce26e7 bellard
#endif
2440 2c0262af bellard
        if (shift == 1) {
2441 2c0262af bellard
            /* 32 bits */
2442 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
2443 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
2444 891b38e4 bellard
            new_ss &= 0xffff;
2445 2c0262af bellard
        } else {
2446 2c0262af bellard
            /* 16 bits */
2447 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
2448 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
2449 2c0262af bellard
        }
2450 e19e89a5 bellard
#ifdef DEBUG_PCALL
2451 e19e89a5 bellard
        if (loglevel & CPU_LOG_PCALL) {
2452 14ce26e7 bellard
            fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2453 e19e89a5 bellard
                    new_ss, new_esp);
2454 e19e89a5 bellard
        }
2455 e19e89a5 bellard
#endif
2456 b359d4e7 bellard
        if ((new_ss & 0xfffc) == 0) {
2457 b359d4e7 bellard
#ifdef TARGET_X86_64
2458 b359d4e7 bellard
            /* NULL ss is allowed in long mode if cpl != 3*/
2459 d80c7d1c bellard
            /* XXX: test CS64 ? */
2460 b359d4e7 bellard
            if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2461 b359d4e7 bellard
                cpu_x86_load_seg_cache(env, R_SS, new_ss, 
2462 b359d4e7 bellard
                                       0, 0xffffffff,
2463 b359d4e7 bellard
                                       DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2464 b359d4e7 bellard
                                       DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2465 b359d4e7 bellard
                                       DESC_W_MASK | DESC_A_MASK);
2466 d80c7d1c bellard
                ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2467 b359d4e7 bellard
            } else 
2468 b359d4e7 bellard
#endif
2469 b359d4e7 bellard
            {
2470 b359d4e7 bellard
                raise_exception_err(EXCP0D_GPF, 0);
2471 b359d4e7 bellard
            }
2472 14ce26e7 bellard
        } else {
2473 14ce26e7 bellard
            if ((new_ss & 3) != rpl)
2474 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2475 14ce26e7 bellard
            if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2476 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2477 14ce26e7 bellard
            if (!(ss_e2 & DESC_S_MASK) ||
2478 14ce26e7 bellard
                (ss_e2 & DESC_CS_MASK) ||
2479 14ce26e7 bellard
                !(ss_e2 & DESC_W_MASK))
2480 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2481 14ce26e7 bellard
            dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2482 14ce26e7 bellard
            if (dpl != rpl)
2483 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2484 14ce26e7 bellard
            if (!(ss_e2 & DESC_P_MASK))
2485 14ce26e7 bellard
                raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2486 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_SS, new_ss, 
2487 14ce26e7 bellard
                                   get_seg_base(ss_e1, ss_e2),
2488 14ce26e7 bellard
                                   get_seg_limit(ss_e1, ss_e2),
2489 14ce26e7 bellard
                                   ss_e2);
2490 14ce26e7 bellard
        }
2491 2c0262af bellard
2492 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
2493 2c0262af bellard
                       get_seg_base(e1, e2),
2494 2c0262af bellard
                       get_seg_limit(e1, e2),
2495 2c0262af bellard
                       e2);
2496 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
2497 891b38e4 bellard
        sp = new_esp;
2498 14ce26e7 bellard
#ifdef TARGET_X86_64
2499 2c8e0301 bellard
        if (env->hflags & HF_CS64_MASK)
2500 14ce26e7 bellard
            sp_mask = -1;
2501 14ce26e7 bellard
        else
2502 14ce26e7 bellard
#endif
2503 14ce26e7 bellard
            sp_mask = get_sp_mask(ss_e2);
2504 8e682019 bellard
2505 8e682019 bellard
        /* validate data segments */
2506 89984cd2 bellard
        validate_seg(R_ES, rpl);
2507 89984cd2 bellard
        validate_seg(R_DS, rpl);
2508 89984cd2 bellard
        validate_seg(R_FS, rpl);
2509 89984cd2 bellard
        validate_seg(R_GS, rpl);
2510 4afa6482 bellard
2511 4afa6482 bellard
        sp += addend;
2512 2c0262af bellard
    }
2513 8d7b0fbb bellard
    SET_ESP(sp, sp_mask);
2514 2c0262af bellard
    env->eip = new_eip;
2515 2c0262af bellard
    if (is_iret) {
2516 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
2517 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2518 2c0262af bellard
        if (cpl == 0)
2519 4136f33c bellard
            eflags_mask |= IOPL_MASK;
2520 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
2521 4136f33c bellard
        if (cpl <= iopl)
2522 4136f33c bellard
            eflags_mask |= IF_MASK;
2523 2c0262af bellard
        if (shift == 0)
2524 2c0262af bellard
            eflags_mask &= 0xffff;
2525 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
2526 2c0262af bellard
    }
2527 2c0262af bellard
    return;
2528 2c0262af bellard
2529 2c0262af bellard
 return_to_vm86:
2530 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
2531 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
2532 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
2533 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
2534 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
2535 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
2536 2c0262af bellard
    
2537 2c0262af bellard
    /* modify processor state */
2538 4136f33c bellard
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
2539 8145122b bellard
                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2540 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
2541 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
2542 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
2543 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
2544 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
2545 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
2546 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
2547 2c0262af bellard
2548 fd836909 bellard
    env->eip = new_eip & 0xffff;
2549 2c0262af bellard
    ESP = new_esp;
2550 2c0262af bellard
}
2551 2c0262af bellard
2552 08cea4ee bellard
void helper_iret_protected(int shift, int next_eip)
2553 2c0262af bellard
{
2554 7e84c249 bellard
    int tss_selector, type;
2555 7e84c249 bellard
    uint32_t e1, e2;
2556 7e84c249 bellard
    
2557 7e84c249 bellard
    /* specific case for TSS */
2558 7e84c249 bellard
    if (env->eflags & NT_MASK) {
2559 14ce26e7 bellard
#ifdef TARGET_X86_64
2560 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
2561 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, 0);
2562 14ce26e7 bellard
#endif
2563 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
2564 7e84c249 bellard
        if (tss_selector & 4)
2565 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2566 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
2567 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2568 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2569 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
2570 7e84c249 bellard
        if (type != 3)
2571 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2572 08cea4ee bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2573 7e84c249 bellard
    } else {
2574 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
2575 7e84c249 bellard
    }
2576 9df217a3 bellard
#ifdef USE_KQEMU
2577 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2578 9df217a3 bellard
        CC_OP = CC_OP_EFLAGS;
2579 9df217a3 bellard
        env->exception_index = -1;
2580 9df217a3 bellard
        cpu_loop_exit();
2581 9df217a3 bellard
    }
2582 9df217a3 bellard
#endif
2583 2c0262af bellard
}
2584 2c0262af bellard
2585 2c0262af bellard
void helper_lret_protected(int shift, int addend)
2586 2c0262af bellard
{
2587 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
2588 9df217a3 bellard
#ifdef USE_KQEMU
2589 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2590 9df217a3 bellard
        env->exception_index = -1;
2591 9df217a3 bellard
        cpu_loop_exit();
2592 9df217a3 bellard
    }
2593 9df217a3 bellard
#endif
2594 2c0262af bellard
}
2595 2c0262af bellard
2596 023fe10d bellard
void helper_sysenter(void)
2597 023fe10d bellard
{
2598 023fe10d bellard
    if (env->sysenter_cs == 0) {
2599 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2600 023fe10d bellard
    }
2601 023fe10d bellard
    env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2602 023fe10d bellard
    cpu_x86_set_cpl(env, 0);
2603 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, 
2604 14ce26e7 bellard
                           0, 0xffffffff, 
2605 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2606 023fe10d bellard
                           DESC_S_MASK |
2607 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2608 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, 
2609 14ce26e7 bellard
                           0, 0xffffffff,
2610 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2611 023fe10d bellard
                           DESC_S_MASK |
2612 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2613 023fe10d bellard
    ESP = env->sysenter_esp;
2614 023fe10d bellard
    EIP = env->sysenter_eip;
2615 023fe10d bellard
}
2616 023fe10d bellard
2617 023fe10d bellard
void helper_sysexit(void)
2618 023fe10d bellard
{
2619 023fe10d bellard
    int cpl;
2620 023fe10d bellard
2621 023fe10d bellard
    cpl = env->hflags & HF_CPL_MASK;
2622 023fe10d bellard
    if (env->sysenter_cs == 0 || cpl != 0) {
2623 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2624 023fe10d bellard
    }
2625 023fe10d bellard
    cpu_x86_set_cpl(env, 3);
2626 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, 
2627 14ce26e7 bellard
                           0, 0xffffffff, 
2628 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2629 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2630 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2631 023fe10d bellard
    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, 
2632 14ce26e7 bellard
                           0, 0xffffffff,
2633 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2634 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2635 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2636 023fe10d bellard
    ESP = ECX;
2637 023fe10d bellard
    EIP = EDX;
2638 9df217a3 bellard
#ifdef USE_KQEMU
2639 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2640 9df217a3 bellard
        env->exception_index = -1;
2641 9df217a3 bellard
        cpu_loop_exit();
2642 9df217a3 bellard
    }
2643 9df217a3 bellard
#endif
2644 023fe10d bellard
}
2645 023fe10d bellard
2646 2c0262af bellard
void helper_movl_crN_T0(int reg)
2647 2c0262af bellard
{
2648 4d6b6c0a bellard
#if !defined(CONFIG_USER_ONLY) 
2649 2c0262af bellard
    switch(reg) {
2650 2c0262af bellard
    case 0:
2651 1ac157da bellard
        cpu_x86_update_cr0(env, T0);
2652 2c0262af bellard
        break;
2653 2c0262af bellard
    case 3:
2654 1ac157da bellard
        cpu_x86_update_cr3(env, T0);
2655 1ac157da bellard
        break;
2656 1ac157da bellard
    case 4:
2657 1ac157da bellard
        cpu_x86_update_cr4(env, T0);
2658 1ac157da bellard
        break;
2659 4d6b6c0a bellard
    case 8:
2660 4d6b6c0a bellard
        cpu_set_apic_tpr(env, T0);
2661 4d6b6c0a bellard
        break;
2662 1ac157da bellard
    default:
2663 1ac157da bellard
        env->cr[reg] = T0;
2664 2c0262af bellard
        break;
2665 2c0262af bellard
    }
2666 4d6b6c0a bellard
#endif
2667 2c0262af bellard
}
2668 2c0262af bellard
2669 2c0262af bellard
/* XXX: do more */
2670 2c0262af bellard
void helper_movl_drN_T0(int reg)
2671 2c0262af bellard
{
2672 2c0262af bellard
    env->dr[reg] = T0;
2673 2c0262af bellard
}
2674 2c0262af bellard
2675 8f091a59 bellard
void helper_invlpg(target_ulong addr)
2676 2c0262af bellard
{
2677 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
2678 2c0262af bellard
}
2679 2c0262af bellard
2680 2c0262af bellard
void helper_rdtsc(void)
2681 2c0262af bellard
{
2682 2c0262af bellard
    uint64_t val;
2683 ecada8a2 bellard
2684 ecada8a2 bellard
    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2685 ecada8a2 bellard
        raise_exception(EXCP0D_GPF);
2686 ecada8a2 bellard
    }
2687 28ab0e2e bellard
    val = cpu_get_tsc(env);
2688 14ce26e7 bellard
    EAX = (uint32_t)(val);
2689 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2690 14ce26e7 bellard
}
2691 14ce26e7 bellard
2692 14ce26e7 bellard
#if defined(CONFIG_USER_ONLY) 
2693 14ce26e7 bellard
void helper_wrmsr(void)
2694 14ce26e7 bellard
{
2695 2c0262af bellard
}
2696 2c0262af bellard
2697 14ce26e7 bellard
void helper_rdmsr(void)
2698 14ce26e7 bellard
{
2699 14ce26e7 bellard
}
2700 14ce26e7 bellard
#else
2701 2c0262af bellard
void helper_wrmsr(void)
2702 2c0262af bellard
{
2703 14ce26e7 bellard
    uint64_t val;
2704 14ce26e7 bellard
2705 14ce26e7 bellard
    val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2706 14ce26e7 bellard
2707 14ce26e7 bellard
    switch((uint32_t)ECX) {
2708 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2709 14ce26e7 bellard
        env->sysenter_cs = val & 0xffff;
2710 2c0262af bellard
        break;
2711 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2712 14ce26e7 bellard
        env->sysenter_esp = val;
2713 2c0262af bellard
        break;
2714 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2715 14ce26e7 bellard
        env->sysenter_eip = val;
2716 14ce26e7 bellard
        break;
2717 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2718 14ce26e7 bellard
        cpu_set_apic_base(env, val);
2719 14ce26e7 bellard
        break;
2720 14ce26e7 bellard
    case MSR_EFER:
2721 f419b321 bellard
        {
2722 f419b321 bellard
            uint64_t update_mask;
2723 f419b321 bellard
            update_mask = 0;
2724 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
2725 f419b321 bellard
                update_mask |= MSR_EFER_SCE;
2726 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_LM)
2727 f419b321 bellard
                update_mask |= MSR_EFER_LME;
2728 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
2729 f419b321 bellard
                update_mask |= MSR_EFER_FFXSR;
2730 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_NX)
2731 f419b321 bellard
                update_mask |= MSR_EFER_NXE;
2732 f419b321 bellard
            env->efer = (env->efer & ~update_mask) | 
2733 f419b321 bellard
            (val & update_mask);
2734 f419b321 bellard
        }
2735 2c0262af bellard
        break;
2736 14ce26e7 bellard
    case MSR_STAR:
2737 14ce26e7 bellard
        env->star = val;
2738 14ce26e7 bellard
        break;
2739 8f091a59 bellard
    case MSR_PAT:
2740 8f091a59 bellard
        env->pat = val;
2741 8f091a59 bellard
        break;
2742 f419b321 bellard
#ifdef TARGET_X86_64
2743 14ce26e7 bellard
    case MSR_LSTAR:
2744 14ce26e7 bellard
        env->lstar = val;
2745 14ce26e7 bellard
        break;
2746 14ce26e7 bellard
    case MSR_CSTAR:
2747 14ce26e7 bellard
        env->cstar = val;
2748 14ce26e7 bellard
        break;
2749 14ce26e7 bellard
    case MSR_FMASK:
2750 14ce26e7 bellard
        env->fmask = val;
2751 14ce26e7 bellard
        break;
2752 14ce26e7 bellard
    case MSR_FSBASE:
2753 14ce26e7 bellard
        env->segs[R_FS].base = val;
2754 14ce26e7 bellard
        break;
2755 14ce26e7 bellard
    case MSR_GSBASE:
2756 14ce26e7 bellard
        env->segs[R_GS].base = val;
2757 14ce26e7 bellard
        break;
2758 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2759 14ce26e7 bellard
        env->kernelgsbase = val;
2760 14ce26e7 bellard
        break;
2761 14ce26e7 bellard
#endif
2762 2c0262af bellard
    default:
2763 2c0262af bellard
        /* XXX: exception ? */
2764 2c0262af bellard
        break; 
2765 2c0262af bellard
    }
2766 2c0262af bellard
}
2767 2c0262af bellard
2768 2c0262af bellard
void helper_rdmsr(void)
2769 2c0262af bellard
{
2770 14ce26e7 bellard
    uint64_t val;
2771 14ce26e7 bellard
    switch((uint32_t)ECX) {
2772 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2773 14ce26e7 bellard
        val = env->sysenter_cs;
2774 2c0262af bellard
        break;
2775 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2776 14ce26e7 bellard
        val = env->sysenter_esp;
2777 2c0262af bellard
        break;
2778 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2779 14ce26e7 bellard
        val = env->sysenter_eip;
2780 14ce26e7 bellard
        break;
2781 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2782 14ce26e7 bellard
        val = cpu_get_apic_base(env);
2783 14ce26e7 bellard
        break;
2784 14ce26e7 bellard
    case MSR_EFER:
2785 14ce26e7 bellard
        val = env->efer;
2786 14ce26e7 bellard
        break;
2787 14ce26e7 bellard
    case MSR_STAR:
2788 14ce26e7 bellard
        val = env->star;
2789 14ce26e7 bellard
        break;
2790 8f091a59 bellard
    case MSR_PAT:
2791 8f091a59 bellard
        val = env->pat;
2792 8f091a59 bellard
        break;
2793 f419b321 bellard
#ifdef TARGET_X86_64
2794 14ce26e7 bellard
    case MSR_LSTAR:
2795 14ce26e7 bellard
        val = env->lstar;
2796 14ce26e7 bellard
        break;
2797 14ce26e7 bellard
    case MSR_CSTAR:
2798 14ce26e7 bellard
        val = env->cstar;
2799 14ce26e7 bellard
        break;
2800 14ce26e7 bellard
    case MSR_FMASK:
2801 14ce26e7 bellard
        val = env->fmask;
2802 14ce26e7 bellard
        break;
2803 14ce26e7 bellard
    case MSR_FSBASE:
2804 14ce26e7 bellard
        val = env->segs[R_FS].base;
2805 14ce26e7 bellard
        break;
2806 14ce26e7 bellard
    case MSR_GSBASE:
2807 14ce26e7 bellard
        val = env->segs[R_GS].base;
2808 2c0262af bellard
        break;
2809 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2810 14ce26e7 bellard
        val = env->kernelgsbase;
2811 14ce26e7 bellard
        break;
2812 14ce26e7 bellard
#endif
2813 2c0262af bellard
    default:
2814 2c0262af bellard
        /* XXX: exception ? */
2815 14ce26e7 bellard
        val = 0;
2816 2c0262af bellard
        break; 
2817 2c0262af bellard
    }
2818 14ce26e7 bellard
    EAX = (uint32_t)(val);
2819 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2820 2c0262af bellard
}
2821 14ce26e7 bellard
#endif
2822 2c0262af bellard
2823 2c0262af bellard
void helper_lsl(void)
2824 2c0262af bellard
{
2825 2c0262af bellard
    unsigned int selector, limit;
2826 5516d670 bellard
    uint32_t e1, e2, eflags;
2827 3ab493de bellard
    int rpl, dpl, cpl, type;
2828 2c0262af bellard
2829 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2830 2c0262af bellard
    selector = T0 & 0xffff;
2831 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
2832 5516d670 bellard
        goto fail;
2833 3ab493de bellard
    rpl = selector & 3;
2834 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2835 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2836 3ab493de bellard
    if (e2 & DESC_S_MASK) {
2837 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2838 3ab493de bellard
            /* conforming */
2839 3ab493de bellard
        } else {
2840 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2841 5516d670 bellard
                goto fail;
2842 3ab493de bellard
        }
2843 3ab493de bellard
    } else {
2844 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2845 3ab493de bellard
        switch(type) {
2846 3ab493de bellard
        case 1:
2847 3ab493de bellard
        case 2:
2848 3ab493de bellard
        case 3:
2849 3ab493de bellard
        case 9:
2850 3ab493de bellard
        case 11:
2851 3ab493de bellard
            break;
2852 3ab493de bellard
        default:
2853 5516d670 bellard
            goto fail;
2854 3ab493de bellard
        }
2855 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2856 5516d670 bellard
        fail:
2857 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2858 3ab493de bellard
            return;
2859 5516d670 bellard
        }
2860 3ab493de bellard
    }
2861 3ab493de bellard
    limit = get_seg_limit(e1, e2);
2862 2c0262af bellard
    T1 = limit;
2863 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2864 2c0262af bellard
}
2865 2c0262af bellard
2866 2c0262af bellard
void helper_lar(void)
2867 2c0262af bellard
{
2868 2c0262af bellard
    unsigned int selector;
2869 5516d670 bellard
    uint32_t e1, e2, eflags;
2870 3ab493de bellard
    int rpl, dpl, cpl, type;
2871 2c0262af bellard
2872 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2873 2c0262af bellard
    selector = T0 & 0xffff;
2874 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2875 5516d670 bellard
        goto fail;
2876 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
2877 5516d670 bellard
        goto fail;
2878 3ab493de bellard
    rpl = selector & 3;
2879 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2880 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2881 3ab493de bellard
    if (e2 & DESC_S_MASK) {
2882 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2883 3ab493de bellard
            /* conforming */
2884 3ab493de bellard
        } else {
2885 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2886 5516d670 bellard
                goto fail;
2887 3ab493de bellard
        }
2888 3ab493de bellard
    } else {
2889 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2890 3ab493de bellard
        switch(type) {
2891 3ab493de bellard
        case 1:
2892 3ab493de bellard
        case 2:
2893 3ab493de bellard
        case 3:
2894 3ab493de bellard
        case 4:
2895 3ab493de bellard
        case 5:
2896 3ab493de bellard
        case 9:
2897 3ab493de bellard
        case 11:
2898 3ab493de bellard
        case 12:
2899 3ab493de bellard
            break;
2900 3ab493de bellard
        default:
2901 5516d670 bellard
            goto fail;
2902 3ab493de bellard
        }
2903 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2904 5516d670 bellard
        fail:
2905 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2906 3ab493de bellard
            return;
2907 5516d670 bellard
        }
2908 3ab493de bellard
    }
2909 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
2910 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2911 2c0262af bellard
}
2912 2c0262af bellard
2913 3ab493de bellard
void helper_verr(void)
2914 3ab493de bellard
{
2915 3ab493de bellard
    unsigned int selector;
2916 5516d670 bellard
    uint32_t e1, e2, eflags;
2917 3ab493de bellard
    int rpl, dpl, cpl;
2918 3ab493de bellard
2919 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2920 3ab493de bellard
    selector = T0 & 0xffff;
2921 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2922 5516d670 bellard
        goto fail;
2923 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
2924 5516d670 bellard
        goto fail;
2925 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
2926 5516d670 bellard
        goto fail;
2927 3ab493de bellard
    rpl = selector & 3;
2928 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2929 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2930 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
2931 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
2932 5516d670 bellard
            goto fail;
2933 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
2934 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2935 5516d670 bellard
                goto fail;
2936 3ab493de bellard
        }
2937 3ab493de bellard
    } else {
2938 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2939 5516d670 bellard
        fail:
2940 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2941 3ab493de bellard
            return;
2942 5516d670 bellard
        }
2943 3ab493de bellard
    }
2944 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2945 3ab493de bellard
}
2946 3ab493de bellard
2947 3ab493de bellard
void helper_verw(void)
2948 3ab493de bellard
{
2949 3ab493de bellard
    unsigned int selector;
2950 5516d670 bellard
    uint32_t e1, e2, eflags;
2951 3ab493de bellard
    int rpl, dpl, cpl;
2952 3ab493de bellard
2953 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2954 3ab493de bellard
    selector = T0 & 0xffff;
2955 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2956 5516d670 bellard
        goto fail;
2957 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
2958 5516d670 bellard
        goto fail;
2959 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
2960 5516d670 bellard
        goto fail;
2961 3ab493de bellard
    rpl = selector & 3;
2962 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2963 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2964 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
2965 5516d670 bellard
        goto fail;
2966 3ab493de bellard
    } else {
2967 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
2968 5516d670 bellard
            goto fail;
2969 5516d670 bellard
        if (!(e2 & DESC_W_MASK)) {
2970 5516d670 bellard
        fail:
2971 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2972 3ab493de bellard
            return;
2973 5516d670 bellard
        }
2974 3ab493de bellard
    }
2975 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2976 3ab493de bellard
}
2977 3ab493de bellard
2978 2c0262af bellard
/* FPU helpers */
2979 2c0262af bellard
2980 2c0262af bellard
void helper_fldt_ST0_A0(void)
2981 2c0262af bellard
{
2982 2c0262af bellard
    int new_fpstt;
2983 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
2984 664e0f19 bellard
    env->fpregs[new_fpstt].d = helper_fldt(A0);
2985 2c0262af bellard
    env->fpstt = new_fpstt;
2986 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
2987 2c0262af bellard
}
2988 2c0262af bellard
2989 2c0262af bellard
void helper_fstt_ST0_A0(void)
2990 2c0262af bellard
{
2991 14ce26e7 bellard
    helper_fstt(ST0, A0);
2992 2c0262af bellard
}
2993 2c0262af bellard
2994 2ee73ac3 bellard
void fpu_set_exception(int mask)
2995 2ee73ac3 bellard
{
2996 2ee73ac3 bellard
    env->fpus |= mask;
2997 2ee73ac3 bellard
    if (env->fpus & (~env->fpuc & FPUC_EM))
2998 2ee73ac3 bellard
        env->fpus |= FPUS_SE | FPUS_B;
2999 2ee73ac3 bellard
}
3000 2ee73ac3 bellard
3001 2ee73ac3 bellard
CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3002 2ee73ac3 bellard
{
3003 2ee73ac3 bellard
    if (b == 0.0) 
3004 2ee73ac3 bellard
        fpu_set_exception(FPUS_ZE);
3005 2ee73ac3 bellard
    return a / b;
3006 2ee73ac3 bellard
}
3007 2ee73ac3 bellard
3008 2ee73ac3 bellard
void fpu_raise_exception(void)
3009 2ee73ac3 bellard
{
3010 2ee73ac3 bellard
    if (env->cr[0] & CR0_NE_MASK) {
3011 2ee73ac3 bellard
        raise_exception(EXCP10_COPR);
3012 2ee73ac3 bellard
    } 
3013 2ee73ac3 bellard
#if !defined(CONFIG_USER_ONLY) 
3014 2ee73ac3 bellard
    else {
3015 2ee73ac3 bellard
        cpu_set_ferr(env);
3016 2ee73ac3 bellard
    }
3017 2ee73ac3 bellard
#endif
3018 2ee73ac3 bellard
}
3019 2ee73ac3 bellard
3020 2c0262af bellard
/* BCD ops */
3021 2c0262af bellard
3022 2c0262af bellard
void helper_fbld_ST0_A0(void)
3023 2c0262af bellard
{
3024 2c0262af bellard
    CPU86_LDouble tmp;
3025 2c0262af bellard
    uint64_t val;
3026 2c0262af bellard
    unsigned int v;
3027 2c0262af bellard
    int i;
3028 2c0262af bellard
3029 2c0262af bellard
    val = 0;
3030 2c0262af bellard
    for(i = 8; i >= 0; i--) {
3031 14ce26e7 bellard
        v = ldub(A0 + i);
3032 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3033 2c0262af bellard
    }
3034 2c0262af bellard
    tmp = val;
3035 14ce26e7 bellard
    if (ldub(A0 + 9) & 0x80)
3036 2c0262af bellard
        tmp = -tmp;
3037 2c0262af bellard
    fpush();
3038 2c0262af bellard
    ST0 = tmp;
3039 2c0262af bellard
}
3040 2c0262af bellard
3041 2c0262af bellard
void helper_fbst_ST0_A0(void)
3042 2c0262af bellard
{
3043 2c0262af bellard
    int v;
3044 14ce26e7 bellard
    target_ulong mem_ref, mem_end;
3045 2c0262af bellard
    int64_t val;
3046 2c0262af bellard
3047 7a0e1f41 bellard
    val = floatx_to_int64(ST0, &env->fp_status);
3048 14ce26e7 bellard
    mem_ref = A0;
3049 2c0262af bellard
    mem_end = mem_ref + 9;
3050 2c0262af bellard
    if (val < 0) {
3051 2c0262af bellard
        stb(mem_end, 0x80);
3052 2c0262af bellard
        val = -val;
3053 2c0262af bellard
    } else {
3054 2c0262af bellard
        stb(mem_end, 0x00);
3055 2c0262af bellard
    }
3056 2c0262af bellard
    while (mem_ref < mem_end) {
3057 2c0262af bellard
        if (val == 0)
3058 2c0262af bellard
            break;
3059 2c0262af bellard
        v = val % 100;
3060 2c0262af bellard
        val = val / 100;
3061 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
3062 2c0262af bellard
        stb(mem_ref++, v);
3063 2c0262af bellard
    }
3064 2c0262af bellard
    while (mem_ref < mem_end) {
3065 2c0262af bellard
        stb(mem_ref++, 0);
3066 2c0262af bellard
    }
3067 2c0262af bellard
}
3068 2c0262af bellard
3069 2c0262af bellard
void helper_f2xm1(void)
3070 2c0262af bellard
{
3071 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
3072 2c0262af bellard
}
3073 2c0262af bellard
3074 2c0262af bellard
void helper_fyl2x(void)
3075 2c0262af bellard
{
3076 2c0262af bellard
    CPU86_LDouble fptemp;
3077 2c0262af bellard
    
3078 2c0262af bellard
    fptemp = ST0;
3079 2c0262af bellard
    if (fptemp>0.0){
3080 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
3081 2c0262af bellard
        ST1 *= fptemp;
3082 2c0262af bellard
        fpop();
3083 2c0262af bellard
    } else { 
3084 2c0262af bellard
        env->fpus &= (~0x4700);
3085 2c0262af bellard
        env->fpus |= 0x400;
3086 2c0262af bellard
    }
3087 2c0262af bellard
}
3088 2c0262af bellard
3089 2c0262af bellard
void helper_fptan(void)
3090 2c0262af bellard
{
3091 2c0262af bellard
    CPU86_LDouble fptemp;
3092 2c0262af bellard
3093 2c0262af bellard
    fptemp = ST0;
3094 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3095 2c0262af bellard
        env->fpus |= 0x400;
3096 2c0262af bellard
    } else {
3097 2c0262af bellard
        ST0 = tan(fptemp);
3098 2c0262af bellard
        fpush();
3099 2c0262af bellard
        ST0 = 1.0;
3100 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3101 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
3102 2c0262af bellard
    }
3103 2c0262af bellard
}
3104 2c0262af bellard
3105 2c0262af bellard
void helper_fpatan(void)
3106 2c0262af bellard
{
3107 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
3108 2c0262af bellard
3109 2c0262af bellard
    fpsrcop = ST1;
3110 2c0262af bellard
    fptemp = ST0;
3111 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
3112 2c0262af bellard
    fpop();
3113 2c0262af bellard
}
3114 2c0262af bellard
3115 2c0262af bellard
void helper_fxtract(void)
3116 2c0262af bellard
{
3117 2c0262af bellard
    CPU86_LDoubleU temp;
3118 2c0262af bellard
    unsigned int expdif;
3119 2c0262af bellard
3120 2c0262af bellard
    temp.d = ST0;
3121 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
3122 2c0262af bellard
    /*DP exponent bias*/
3123 2c0262af bellard
    ST0 = expdif;
3124 2c0262af bellard
    fpush();
3125 2c0262af bellard
    BIASEXPONENT(temp);
3126 2c0262af bellard
    ST0 = temp.d;
3127 2c0262af bellard
}
3128 2c0262af bellard
3129 2c0262af bellard
void helper_fprem1(void)
3130 2c0262af bellard
{
3131 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
3132 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
3133 2c0262af bellard
    int expdif;
3134 7524c84d ths
    signed long long int q;
3135 7524c84d ths
3136 7524c84d ths
    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3137 7524c84d ths
        ST0 = 0.0 / 0.0; /* NaN */
3138 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3139 7524c84d ths
        return;
3140 7524c84d ths
    }
3141 2c0262af bellard
3142 2c0262af bellard
    fpsrcop = ST0;
3143 2c0262af bellard
    fptemp = ST1;
3144 2c0262af bellard
    fpsrcop1.d = fpsrcop;
3145 2c0262af bellard
    fptemp1.d = fptemp;
3146 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3147 7524c84d ths
3148 7524c84d ths
    if (expdif < 0) {
3149 7524c84d ths
        /* optimisation? taken from the AMD docs */
3150 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3151 7524c84d ths
        /* ST0 is unchanged */
3152 7524c84d ths
        return;
3153 7524c84d ths
    }
3154 7524c84d ths
3155 2c0262af bellard
    if (expdif < 53) {
3156 2c0262af bellard
        dblq = fpsrcop / fptemp;
3157 7524c84d ths
        /* round dblq towards nearest integer */
3158 7524c84d ths
        dblq = rint(dblq);
3159 7524c84d ths
        ST0 = fpsrcop - fptemp * dblq;
3160 7524c84d ths
3161 7524c84d ths
        /* convert dblq to q by truncating towards zero */
3162 7524c84d ths
        if (dblq < 0.0)
3163 7524c84d ths
           q = (signed long long int)(-dblq);
3164 7524c84d ths
        else
3165 7524c84d ths
           q = (signed long long int)dblq;
3166 7524c84d ths
3167 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3168 7524c84d ths
                                /* (C0,C3,C1) <-- (q2,q1,q0) */
3169 7524c84d ths
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
3170 7524c84d ths
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3171 7524c84d ths
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
3172 2c0262af bellard
    } else {
3173 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
3174 7524c84d ths
        fptemp = pow(2.0, expdif - 50);
3175 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
3176 7524c84d ths
        /* fpsrcop = integer obtained by chopping */
3177 7524c84d ths
        fpsrcop = (fpsrcop < 0.0) ?
3178 7524c84d ths
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3179 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
3180 2c0262af bellard
    }
3181 2c0262af bellard
}
3182 2c0262af bellard
3183 2c0262af bellard
void helper_fprem(void)
3184 2c0262af bellard
{
3185 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
3186 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
3187 2c0262af bellard
    int expdif;
3188 7524c84d ths
    signed long long int q;
3189 7524c84d ths
3190 7524c84d ths
    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3191 7524c84d ths
       ST0 = 0.0 / 0.0; /* NaN */
3192 7524c84d ths
       env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3193 7524c84d ths
       return;
3194 7524c84d ths
    }
3195 7524c84d ths
3196 7524c84d ths
    fpsrcop = (CPU86_LDouble)ST0;
3197 7524c84d ths
    fptemp = (CPU86_LDouble)ST1;
3198 2c0262af bellard
    fpsrcop1.d = fpsrcop;
3199 2c0262af bellard
    fptemp1.d = fptemp;
3200 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3201 7524c84d ths
3202 7524c84d ths
    if (expdif < 0) {
3203 7524c84d ths
        /* optimisation? taken from the AMD docs */
3204 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3205 7524c84d ths
        /* ST0 is unchanged */
3206 7524c84d ths
        return;
3207 7524c84d ths
    }
3208 7524c84d ths
3209 2c0262af bellard
    if ( expdif < 53 ) {
3210 7524c84d ths
        dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
3211 7524c84d ths
        /* round dblq towards zero */
3212 7524c84d ths
        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
3213 7524c84d ths
        ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
3214 7524c84d ths
3215 7524c84d ths
        /* convert dblq to q by truncating towards zero */
3216 7524c84d ths
        if (dblq < 0.0)
3217 7524c84d ths
           q = (signed long long int)(-dblq);
3218 7524c84d ths
        else
3219 7524c84d ths
           q = (signed long long int)dblq;
3220 7524c84d ths
3221 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3222 7524c84d ths
                                /* (C0,C3,C1) <-- (q2,q1,q0) */
3223 7524c84d ths
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
3224 7524c84d ths
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3225 7524c84d ths
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
3226 2c0262af bellard
    } else {
3227 7524c84d ths
        int N = 32 + (expdif % 32); /* as per AMD docs */
3228 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
3229 7524c84d ths
        fptemp = pow(2.0, (double)(expdif - N));
3230 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
3231 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
3232 7524c84d ths
        fpsrcop = (fpsrcop < 0.0) ?
3233 7524c84d ths
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3234 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
3235 2c0262af bellard
    }
3236 2c0262af bellard
}
3237 2c0262af bellard
3238 2c0262af bellard
void helper_fyl2xp1(void)
3239 2c0262af bellard
{
3240 2c0262af bellard
    CPU86_LDouble fptemp;
3241 2c0262af bellard
3242 2c0262af bellard
    fptemp = ST0;
3243 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
3244 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
3245 2c0262af bellard
        ST1 *= fptemp;
3246 2c0262af bellard
        fpop();
3247 2c0262af bellard
    } else { 
3248 2c0262af bellard
        env->fpus &= (~0x4700);
3249 2c0262af bellard
        env->fpus |= 0x400;
3250 2c0262af bellard
    }
3251 2c0262af bellard
}
3252 2c0262af bellard
3253 2c0262af bellard
void helper_fsqrt(void)
3254 2c0262af bellard
{
3255 2c0262af bellard
    CPU86_LDouble fptemp;
3256 2c0262af bellard
3257 2c0262af bellard
    fptemp = ST0;
3258 2c0262af bellard
    if (fptemp<0.0) { 
3259 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
3260 2c0262af bellard
        env->fpus |= 0x400;
3261 2c0262af bellard
    }
3262 2c0262af bellard
    ST0 = sqrt(fptemp);
3263 2c0262af bellard
}
3264 2c0262af bellard
3265 2c0262af bellard
void helper_fsincos(void)
3266 2c0262af bellard
{
3267 2c0262af bellard
    CPU86_LDouble fptemp;
3268 2c0262af bellard
3269 2c0262af bellard
    fptemp = ST0;
3270 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3271 2c0262af bellard
        env->fpus |= 0x400;
3272 2c0262af bellard
    } else {
3273 2c0262af bellard
        ST0 = sin(fptemp);
3274 2c0262af bellard
        fpush();
3275 2c0262af bellard
        ST0 = cos(fptemp);
3276 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3277 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
3278 2c0262af bellard
    }
3279 2c0262af bellard
}
3280 2c0262af bellard
3281 2c0262af bellard
void helper_frndint(void)
3282 2c0262af bellard
{
3283 7a0e1f41 bellard
    ST0 = floatx_round_to_int(ST0, &env->fp_status);
3284 2c0262af bellard
}
3285 2c0262af bellard
3286 2c0262af bellard
void helper_fscale(void)
3287 2c0262af bellard
{
3288 57e4c06e bellard
    ST0 = ldexp (ST0, (int)(ST1)); 
3289 2c0262af bellard
}
3290 2c0262af bellard
3291 2c0262af bellard
void helper_fsin(void)
3292 2c0262af bellard
{
3293 2c0262af bellard
    CPU86_LDouble fptemp;
3294 2c0262af bellard
3295 2c0262af bellard
    fptemp = ST0;
3296 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3297 2c0262af bellard
        env->fpus |= 0x400;
3298 2c0262af bellard
    } else {
3299 2c0262af bellard
        ST0 = sin(fptemp);
3300 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3301 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
3302 2c0262af bellard
    }
3303 2c0262af bellard
}
3304 2c0262af bellard
3305 2c0262af bellard
void helper_fcos(void)
3306 2c0262af bellard
{
3307 2c0262af bellard
    CPU86_LDouble fptemp;
3308 2c0262af bellard
3309 2c0262af bellard
    fptemp = ST0;
3310 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3311 2c0262af bellard
        env->fpus |= 0x400;
3312 2c0262af bellard
    } else {
3313 2c0262af bellard
        ST0 = cos(fptemp);
3314 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3315 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
3316 2c0262af bellard
    }
3317 2c0262af bellard
}
3318 2c0262af bellard
3319 2c0262af bellard
void helper_fxam_ST0(void)
3320 2c0262af bellard
{
3321 2c0262af bellard
    CPU86_LDoubleU temp;
3322 2c0262af bellard
    int expdif;
3323 2c0262af bellard
3324 2c0262af bellard
    temp.d = ST0;
3325 2c0262af bellard
3326 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
3327 2c0262af bellard
    if (SIGND(temp))
3328 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
3329 2c0262af bellard
3330 a891c7a1 bellard
    /* XXX: test fptags too */
3331 2c0262af bellard
    expdif = EXPD(temp);
3332 2c0262af bellard
    if (expdif == MAXEXPD) {
3333 a891c7a1 bellard
#ifdef USE_X86LDOUBLE
3334 a891c7a1 bellard
        if (MANTD(temp) == 0x8000000000000000ULL)
3335 a891c7a1 bellard
#else
3336 2c0262af bellard
        if (MANTD(temp) == 0)
3337 a891c7a1 bellard
#endif
3338 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
3339 2c0262af bellard
        else
3340 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
3341 2c0262af bellard
    } else if (expdif == 0) {
3342 2c0262af bellard
        if (MANTD(temp) == 0)
3343 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
3344 2c0262af bellard
        else
3345 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
3346 2c0262af bellard
    } else {
3347 2c0262af bellard
        env->fpus |= 0x400;
3348 2c0262af bellard
    }
3349 2c0262af bellard
}
3350 2c0262af bellard
3351 14ce26e7 bellard
void helper_fstenv(target_ulong ptr, int data32)
3352 2c0262af bellard
{
3353 2c0262af bellard
    int fpus, fptag, exp, i;
3354 2c0262af bellard
    uint64_t mant;
3355 2c0262af bellard
    CPU86_LDoubleU tmp;
3356 2c0262af bellard
3357 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3358 2c0262af bellard
    fptag = 0;
3359 2c0262af bellard
    for (i=7; i>=0; i--) {
3360 2c0262af bellard
        fptag <<= 2;
3361 2c0262af bellard
        if (env->fptags[i]) {
3362 2c0262af bellard
            fptag |= 3;
3363 2c0262af bellard
        } else {
3364 664e0f19 bellard
            tmp.d = env->fpregs[i].d;
3365 2c0262af bellard
            exp = EXPD(tmp);
3366 2c0262af bellard
            mant = MANTD(tmp);
3367 2c0262af bellard
            if (exp == 0 && mant == 0) {
3368 2c0262af bellard
                /* zero */
3369 2c0262af bellard
                fptag |= 1;
3370 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
3371 2c0262af bellard
#ifdef USE_X86LDOUBLE
3372 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
3373 2c0262af bellard
#endif
3374 2c0262af bellard
                       ) {
3375 2c0262af bellard
                /* NaNs, infinity, denormal */
3376 2c0262af bellard
                fptag |= 2;
3377 2c0262af bellard
            }
3378 2c0262af bellard
        }
3379 2c0262af bellard
    }
3380 2c0262af bellard
    if (data32) {
3381 2c0262af bellard
        /* 32 bit */
3382 2c0262af bellard
        stl(ptr, env->fpuc);
3383 2c0262af bellard
        stl(ptr + 4, fpus);
3384 2c0262af bellard
        stl(ptr + 8, fptag);
3385 2edcdce3 bellard
        stl(ptr + 12, 0); /* fpip */
3386 2edcdce3 bellard
        stl(ptr + 16, 0); /* fpcs */
3387 2edcdce3 bellard
        stl(ptr + 20, 0); /* fpoo */
3388 2edcdce3 bellard
        stl(ptr + 24, 0); /* fpos */
3389 2c0262af bellard
    } else {
3390 2c0262af bellard
        /* 16 bit */
3391 2c0262af bellard
        stw(ptr, env->fpuc);
3392 2c0262af bellard
        stw(ptr + 2, fpus);
3393 2c0262af bellard
        stw(ptr + 4, fptag);
3394 2c0262af bellard
        stw(ptr + 6, 0);
3395 2c0262af bellard
        stw(ptr + 8, 0);
3396 2c0262af bellard
        stw(ptr + 10, 0);
3397 2c0262af bellard
        stw(ptr + 12, 0);
3398 2c0262af bellard
    }
3399 2c0262af bellard
}
3400 2c0262af bellard
3401 14ce26e7 bellard
void helper_fldenv(target_ulong ptr, int data32)
3402 2c0262af bellard
{
3403 2c0262af bellard
    int i, fpus, fptag;
3404 2c0262af bellard
3405 2c0262af bellard
    if (data32) {
3406 2c0262af bellard
        env->fpuc = lduw(ptr);
3407 2c0262af bellard
        fpus = lduw(ptr + 4);
3408 2c0262af bellard
        fptag = lduw(ptr + 8);
3409 2c0262af bellard
    }
3410 2c0262af bellard
    else {
3411 2c0262af bellard
        env->fpuc = lduw(ptr);
3412 2c0262af bellard
        fpus = lduw(ptr + 2);
3413 2c0262af bellard
        fptag = lduw(ptr + 4);
3414 2c0262af bellard
    }
3415 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
3416 2c0262af bellard
    env->fpus = fpus & ~0x3800;
3417 2edcdce3 bellard
    for(i = 0;i < 8; i++) {
3418 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
3419 2c0262af bellard
        fptag >>= 2;
3420 2c0262af bellard
    }
3421 2c0262af bellard
}
3422 2c0262af bellard
3423 14ce26e7 bellard
void helper_fsave(target_ulong ptr, int data32)
3424 2c0262af bellard
{
3425 2c0262af bellard
    CPU86_LDouble tmp;
3426 2c0262af bellard
    int i;
3427 2c0262af bellard
3428 2c0262af bellard
    helper_fstenv(ptr, data32);
3429 2c0262af bellard
3430 2c0262af bellard
    ptr += (14 << data32);
3431 2c0262af bellard
    for(i = 0;i < 8; i++) {
3432 2c0262af bellard
        tmp = ST(i);
3433 2c0262af bellard
        helper_fstt(tmp, ptr);
3434 2c0262af bellard
        ptr += 10;
3435 2c0262af bellard
    }
3436 2c0262af bellard
3437 2c0262af bellard
    /* fninit */
3438 2c0262af bellard
    env->fpus = 0;
3439 2c0262af bellard
    env->fpstt = 0;
3440 2c0262af bellard
    env->fpuc = 0x37f;
3441 2c0262af bellard
    env->fptags[0] = 1;
3442 2c0262af bellard
    env->fptags[1] = 1;
3443 2c0262af bellard
    env->fptags[2] = 1;
3444 2c0262af bellard
    env->fptags[3] = 1;
3445 2c0262af bellard
    env->fptags[4] = 1;
3446 2c0262af bellard
    env->fptags[5] = 1;
3447 2c0262af bellard
    env->fptags[6] = 1;
3448 2c0262af bellard
    env->fptags[7] = 1;
3449 2c0262af bellard
}
3450 2c0262af bellard
3451 14ce26e7 bellard
void helper_frstor(target_ulong ptr, int data32)
3452 2c0262af bellard
{
3453 2c0262af bellard
    CPU86_LDouble tmp;
3454 2c0262af bellard
    int i;
3455 2c0262af bellard
3456 2c0262af bellard
    helper_fldenv(ptr, data32);
3457 2c0262af bellard
    ptr += (14 << data32);
3458 2c0262af bellard
3459 2c0262af bellard
    for(i = 0;i < 8; i++) {
3460 2c0262af bellard
        tmp = helper_fldt(ptr);
3461 2c0262af bellard
        ST(i) = tmp;
3462 2c0262af bellard
        ptr += 10;
3463 2c0262af bellard
    }
3464 2c0262af bellard
}
3465 2c0262af bellard
3466 14ce26e7 bellard
void helper_fxsave(target_ulong ptr, int data64)
3467 14ce26e7 bellard
{
3468 14ce26e7 bellard
    int fpus, fptag, i, nb_xmm_regs;
3469 14ce26e7 bellard
    CPU86_LDouble tmp;
3470 14ce26e7 bellard
    target_ulong addr;
3471 14ce26e7 bellard
3472 14ce26e7 bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3473 14ce26e7 bellard
    fptag = 0;
3474 14ce26e7 bellard
    for(i = 0; i < 8; i++) {
3475 d3c61721 bellard
        fptag |= (env->fptags[i] << i);
3476 14ce26e7 bellard
    }
3477 14ce26e7 bellard
    stw(ptr, env->fpuc);
3478 14ce26e7 bellard
    stw(ptr + 2, fpus);
3479 d3c61721 bellard
    stw(ptr + 4, fptag ^ 0xff);
3480 14ce26e7 bellard
3481 14ce26e7 bellard
    addr = ptr + 0x20;
3482 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3483 14ce26e7 bellard
        tmp = ST(i);
3484 14ce26e7 bellard
        helper_fstt(tmp, addr);
3485 14ce26e7 bellard
        addr += 16;
3486 14ce26e7 bellard
    }
3487 14ce26e7 bellard
    
3488 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3489 a8ede8ba bellard
        /* XXX: finish it */
3490 664e0f19 bellard
        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3491 d3c61721 bellard
        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3492 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3493 14ce26e7 bellard
        addr = ptr + 0xa0;
3494 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3495 a8ede8ba bellard
            stq(addr, env->xmm_regs[i].XMM_Q(0));
3496 a8ede8ba bellard
            stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3497 14ce26e7 bellard
            addr += 16;
3498 14ce26e7 bellard
        }
3499 14ce26e7 bellard
    }
3500 14ce26e7 bellard
}
3501 14ce26e7 bellard
3502 14ce26e7 bellard
void helper_fxrstor(target_ulong ptr, int data64)
3503 14ce26e7 bellard
{
3504 14ce26e7 bellard
    int i, fpus, fptag, nb_xmm_regs;
3505 14ce26e7 bellard
    CPU86_LDouble tmp;
3506 14ce26e7 bellard
    target_ulong addr;
3507 14ce26e7 bellard
3508 14ce26e7 bellard
    env->fpuc = lduw(ptr);
3509 14ce26e7 bellard
    fpus = lduw(ptr + 2);
3510 d3c61721 bellard
    fptag = lduw(ptr + 4);
3511 14ce26e7 bellard
    env->fpstt = (fpus >> 11) & 7;
3512 14ce26e7 bellard
    env->fpus = fpus & ~0x3800;
3513 14ce26e7 bellard
    fptag ^= 0xff;
3514 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3515 d3c61721 bellard
        env->fptags[i] = ((fptag >> i) & 1);
3516 14ce26e7 bellard
    }
3517 14ce26e7 bellard
3518 14ce26e7 bellard
    addr = ptr + 0x20;
3519 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3520 14ce26e7 bellard
        tmp = helper_fldt(addr);
3521 14ce26e7 bellard
        ST(i) = tmp;
3522 14ce26e7 bellard
        addr += 16;
3523 14ce26e7 bellard
    }
3524 14ce26e7 bellard
3525 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3526 31313213 bellard
        /* XXX: finish it */
3527 664e0f19 bellard
        env->mxcsr = ldl(ptr + 0x18);
3528 14ce26e7 bellard
        //ldl(ptr + 0x1c);
3529 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3530 14ce26e7 bellard
        addr = ptr + 0xa0;
3531 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3532 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3533 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3534 14ce26e7 bellard
            addr += 16;
3535 14ce26e7 bellard
        }
3536 14ce26e7 bellard
    }
3537 14ce26e7 bellard
}
3538 1f1af9fd bellard
3539 1f1af9fd bellard
#ifndef USE_X86LDOUBLE
3540 1f1af9fd bellard
3541 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3542 1f1af9fd bellard
{
3543 1f1af9fd bellard
    CPU86_LDoubleU temp;
3544 1f1af9fd bellard
    int e;
3545 1f1af9fd bellard
3546 1f1af9fd bellard
    temp.d = f;
3547 1f1af9fd bellard
    /* mantissa */
3548 1f1af9fd bellard
    *pmant = (MANTD(temp) << 11) | (1LL << 63);
3549 1f1af9fd bellard
    /* exponent + sign */
3550 1f1af9fd bellard
    e = EXPD(temp) - EXPBIAS + 16383;
3551 1f1af9fd bellard
    e |= SIGND(temp) >> 16;
3552 1f1af9fd bellard
    *pexp = e;
3553 1f1af9fd bellard
}
3554 1f1af9fd bellard
3555 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3556 1f1af9fd bellard
{
3557 1f1af9fd bellard
    CPU86_LDoubleU temp;
3558 1f1af9fd bellard
    int e;
3559 1f1af9fd bellard
    uint64_t ll;
3560 1f1af9fd bellard
3561 1f1af9fd bellard
    /* XXX: handle overflow ? */
3562 1f1af9fd bellard
    e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3563 1f1af9fd bellard
    e |= (upper >> 4) & 0x800; /* sign */
3564 1f1af9fd bellard
    ll = (mant >> 11) & ((1LL << 52) - 1);
3565 1f1af9fd bellard
#ifdef __arm__
3566 1f1af9fd bellard
    temp.l.upper = (e << 20) | (ll >> 32);
3567 1f1af9fd bellard
    temp.l.lower = ll;
3568 1f1af9fd bellard
#else
3569 1f1af9fd bellard
    temp.ll = ll | ((uint64_t)e << 52);
3570 1f1af9fd bellard
#endif
3571 1f1af9fd bellard
    return temp.d;
3572 1f1af9fd bellard
}
3573 1f1af9fd bellard
3574 1f1af9fd bellard
#else
3575 1f1af9fd bellard
3576 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3577 1f1af9fd bellard
{
3578 1f1af9fd bellard
    CPU86_LDoubleU temp;
3579 1f1af9fd bellard
3580 1f1af9fd bellard
    temp.d = f;
3581 1f1af9fd bellard
    *pmant = temp.l.lower;
3582 1f1af9fd bellard
    *pexp = temp.l.upper;
3583 1f1af9fd bellard
}
3584 1f1af9fd bellard
3585 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3586 1f1af9fd bellard
{
3587 1f1af9fd bellard
    CPU86_LDoubleU temp;
3588 1f1af9fd bellard
3589 1f1af9fd bellard
    temp.l.upper = upper;
3590 1f1af9fd bellard
    temp.l.lower = mant;
3591 1f1af9fd bellard
    return temp.d;
3592 1f1af9fd bellard
}
3593 1f1af9fd bellard
#endif
3594 1f1af9fd bellard
3595 14ce26e7 bellard
#ifdef TARGET_X86_64
3596 14ce26e7 bellard
3597 14ce26e7 bellard
//#define DEBUG_MULDIV
3598 14ce26e7 bellard
3599 14ce26e7 bellard
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3600 14ce26e7 bellard
{
3601 14ce26e7 bellard
    *plow += a;
3602 14ce26e7 bellard
    /* carry test */
3603 14ce26e7 bellard
    if (*plow < a)
3604 14ce26e7 bellard
        (*phigh)++;
3605 14ce26e7 bellard
    *phigh += b;
3606 14ce26e7 bellard
}
3607 14ce26e7 bellard
3608 14ce26e7 bellard
static void neg128(uint64_t *plow, uint64_t *phigh)
3609 14ce26e7 bellard
{
3610 14ce26e7 bellard
    *plow = ~ *plow;
3611 14ce26e7 bellard
    *phigh = ~ *phigh;
3612 14ce26e7 bellard
    add128(plow, phigh, 1, 0);
3613 14ce26e7 bellard
}
3614 14ce26e7 bellard
3615 45bbbb46 bellard
/* return TRUE if overflow */
3616 45bbbb46 bellard
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3617 14ce26e7 bellard
{
3618 14ce26e7 bellard
    uint64_t q, r, a1, a0;
3619 c0b24a1d bellard
    int i, qb, ab;
3620 14ce26e7 bellard
3621 14ce26e7 bellard
    a0 = *plow;
3622 14ce26e7 bellard
    a1 = *phigh;
3623 14ce26e7 bellard
    if (a1 == 0) {
3624 14ce26e7 bellard
        q = a0 / b;
3625 14ce26e7 bellard
        r = a0 % b;
3626 14ce26e7 bellard
        *plow = q;
3627 14ce26e7 bellard
        *phigh = r;
3628 14ce26e7 bellard
    } else {
3629 45bbbb46 bellard
        if (a1 >= b)
3630 45bbbb46 bellard
            return 1;
3631 14ce26e7 bellard
        /* XXX: use a better algorithm */
3632 14ce26e7 bellard
        for(i = 0; i < 64; i++) {
3633 c0b24a1d bellard
            ab = a1 >> 63;
3634 a8ede8ba bellard
            a1 = (a1 << 1) | (a0 >> 63);
3635 c0b24a1d bellard
            if (ab || a1 >= b) {
3636 14ce26e7 bellard
                a1 -= b;
3637 14ce26e7 bellard
                qb = 1;
3638 14ce26e7 bellard
            } else {
3639 14ce26e7 bellard
                qb = 0;
3640 14ce26e7 bellard
            }
3641 14ce26e7 bellard
            a0 = (a0 << 1) | qb;
3642 14ce26e7 bellard
        }
3643 a8ede8ba bellard
#if defined(DEBUG_MULDIV)
3644 26a76461 bellard
        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
3645 14ce26e7 bellard
               *phigh, *plow, b, a0, a1);
3646 14ce26e7 bellard
#endif
3647 14ce26e7 bellard
        *plow = a0;
3648 14ce26e7 bellard
        *phigh = a1;
3649 14ce26e7 bellard
    }
3650 45bbbb46 bellard
    return 0;
3651 14ce26e7 bellard
}
3652 14ce26e7 bellard
3653 45bbbb46 bellard
/* return TRUE if overflow */
3654 45bbbb46 bellard
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3655 14ce26e7 bellard
{
3656 14ce26e7 bellard
    int sa, sb;
3657 14ce26e7 bellard
    sa = ((int64_t)*phigh < 0);
3658 14ce26e7 bellard
    if (sa)
3659 14ce26e7 bellard
        neg128(plow, phigh);
3660 14ce26e7 bellard
    sb = (b < 0);
3661 14ce26e7 bellard
    if (sb)
3662 14ce26e7 bellard
        b = -b;
3663 45bbbb46 bellard
    if (div64(plow, phigh, b) != 0)
3664 45bbbb46 bellard
        return 1;
3665 45bbbb46 bellard
    if (sa ^ sb) {
3666 45bbbb46 bellard
        if (*plow > (1ULL << 63))
3667 45bbbb46 bellard
            return 1;
3668 14ce26e7 bellard
        *plow = - *plow;
3669 45bbbb46 bellard
    } else {
3670 45bbbb46 bellard
        if (*plow >= (1ULL << 63))
3671 45bbbb46 bellard
            return 1;
3672 45bbbb46 bellard
    }
3673 31313213 bellard
    if (sa)
3674 14ce26e7 bellard
        *phigh = - *phigh;
3675 45bbbb46 bellard
    return 0;
3676 14ce26e7 bellard
}
3677 14ce26e7 bellard
3678 14ce26e7 bellard
void helper_mulq_EAX_T0(void)
3679 14ce26e7 bellard
{
3680 14ce26e7 bellard
    uint64_t r0, r1;
3681 14ce26e7 bellard
3682 69d35728 ths
    mulu64(&r1, &r0, EAX, T0);
3683 14ce26e7 bellard
    EAX = r0;
3684 14ce26e7 bellard
    EDX = r1;
3685 14ce26e7 bellard
    CC_DST = r0;
3686 14ce26e7 bellard
    CC_SRC = r1;
3687 14ce26e7 bellard
}
3688 14ce26e7 bellard
3689 14ce26e7 bellard
void helper_imulq_EAX_T0(void)
3690 14ce26e7 bellard
{
3691 14ce26e7 bellard
    uint64_t r0, r1;
3692 14ce26e7 bellard
3693 69d35728 ths
    muls64(&r1, &r0, EAX, T0);
3694 14ce26e7 bellard
    EAX = r0;
3695 14ce26e7 bellard
    EDX = r1;
3696 14ce26e7 bellard
    CC_DST = r0;
3697 a8ede8ba bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3698 14ce26e7 bellard
}
3699 14ce26e7 bellard
3700 14ce26e7 bellard
void helper_imulq_T0_T1(void)
3701 14ce26e7 bellard
{
3702 14ce26e7 bellard
    uint64_t r0, r1;
3703 14ce26e7 bellard
3704 69d35728 ths
    muls64(&r1, &r0, T0, T1);
3705 14ce26e7 bellard
    T0 = r0;
3706 14ce26e7 bellard
    CC_DST = r0;
3707 14ce26e7 bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3708 14ce26e7 bellard
}
3709 14ce26e7 bellard
3710 14ce26e7 bellard
void helper_divq_EAX_T0(void)
3711 14ce26e7 bellard
{
3712 14ce26e7 bellard
    uint64_t r0, r1;
3713 14ce26e7 bellard
    if (T0 == 0) {
3714 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3715 14ce26e7 bellard
    }
3716 14ce26e7 bellard
    r0 = EAX;
3717 14ce26e7 bellard
    r1 = EDX;
3718 45bbbb46 bellard
    if (div64(&r0, &r1, T0))
3719 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3720 14ce26e7 bellard
    EAX = r0;
3721 14ce26e7 bellard
    EDX = r1;
3722 14ce26e7 bellard
}
3723 14ce26e7 bellard
3724 14ce26e7 bellard
void helper_idivq_EAX_T0(void)
3725 14ce26e7 bellard
{
3726 14ce26e7 bellard
    uint64_t r0, r1;
3727 14ce26e7 bellard
    if (T0 == 0) {
3728 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3729 14ce26e7 bellard
    }
3730 14ce26e7 bellard
    r0 = EAX;
3731 14ce26e7 bellard
    r1 = EDX;
3732 45bbbb46 bellard
    if (idiv64(&r0, &r1, T0))
3733 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3734 14ce26e7 bellard
    EAX = r0;
3735 14ce26e7 bellard
    EDX = r1;
3736 14ce26e7 bellard
}
3737 14ce26e7 bellard
3738 68cae3d8 bellard
void helper_bswapq_T0(void)
3739 68cae3d8 bellard
{
3740 68cae3d8 bellard
    T0 = bswap64(T0);
3741 68cae3d8 bellard
}
3742 14ce26e7 bellard
#endif
3743 14ce26e7 bellard
3744 3d7374c5 bellard
void helper_hlt(void)
3745 3d7374c5 bellard
{
3746 3d7374c5 bellard
    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
3747 3d7374c5 bellard
    env->hflags |= HF_HALTED_MASK;
3748 3d7374c5 bellard
    env->exception_index = EXCP_HLT;
3749 3d7374c5 bellard
    cpu_loop_exit();
3750 3d7374c5 bellard
}
3751 3d7374c5 bellard
3752 3d7374c5 bellard
void helper_monitor(void)
3753 3d7374c5 bellard
{
3754 d80c7d1c bellard
    if ((uint32_t)ECX != 0)
3755 3d7374c5 bellard
        raise_exception(EXCP0D_GPF);
3756 3d7374c5 bellard
    /* XXX: store address ? */
3757 3d7374c5 bellard
}
3758 3d7374c5 bellard
3759 3d7374c5 bellard
void helper_mwait(void)
3760 3d7374c5 bellard
{
3761 d80c7d1c bellard
    if ((uint32_t)ECX != 0)
3762 3d7374c5 bellard
        raise_exception(EXCP0D_GPF);
3763 3d7374c5 bellard
    /* XXX: not complete but not completely erroneous */
3764 3d7374c5 bellard
    if (env->cpu_index != 0 || env->next_cpu != NULL) {
3765 3d7374c5 bellard
        /* more than one CPU: do not sleep because another CPU may
3766 3d7374c5 bellard
           wake this one */
3767 3d7374c5 bellard
    } else {
3768 3d7374c5 bellard
        helper_hlt();
3769 3d7374c5 bellard
    }
3770 3d7374c5 bellard
}
3771 3d7374c5 bellard
3772 664e0f19 bellard
float approx_rsqrt(float a)
3773 664e0f19 bellard
{
3774 664e0f19 bellard
    return 1.0 / sqrt(a);
3775 664e0f19 bellard
}
3776 664e0f19 bellard
3777 664e0f19 bellard
float approx_rcp(float a)
3778 664e0f19 bellard
{
3779 664e0f19 bellard
    return 1.0 / a;
3780 664e0f19 bellard
}
3781 664e0f19 bellard
3782 7a0e1f41 bellard
void update_fp_status(void)
3783 4d6b6c0a bellard
{
3784 7a0e1f41 bellard
    int rnd_type;
3785 4d6b6c0a bellard
3786 7a0e1f41 bellard
    /* set rounding mode */
3787 7a0e1f41 bellard
    switch(env->fpuc & RC_MASK) {
3788 7a0e1f41 bellard
    default:
3789 7a0e1f41 bellard
    case RC_NEAR:
3790 7a0e1f41 bellard
        rnd_type = float_round_nearest_even;
3791 7a0e1f41 bellard
        break;
3792 7a0e1f41 bellard
    case RC_DOWN:
3793 7a0e1f41 bellard
        rnd_type = float_round_down;
3794 7a0e1f41 bellard
        break;
3795 7a0e1f41 bellard
    case RC_UP:
3796 7a0e1f41 bellard
        rnd_type = float_round_up;
3797 7a0e1f41 bellard
        break;
3798 7a0e1f41 bellard
    case RC_CHOP:
3799 7a0e1f41 bellard
        rnd_type = float_round_to_zero;
3800 7a0e1f41 bellard
        break;
3801 7a0e1f41 bellard
    }
3802 7a0e1f41 bellard
    set_float_rounding_mode(rnd_type, &env->fp_status);
3803 7a0e1f41 bellard
#ifdef FLOATX80
3804 7a0e1f41 bellard
    switch((env->fpuc >> 8) & 3) {
3805 7a0e1f41 bellard
    case 0:
3806 7a0e1f41 bellard
        rnd_type = 32;
3807 7a0e1f41 bellard
        break;
3808 7a0e1f41 bellard
    case 2:
3809 7a0e1f41 bellard
        rnd_type = 64;
3810 7a0e1f41 bellard
        break;
3811 7a0e1f41 bellard
    case 3:
3812 7a0e1f41 bellard
    default:
3813 7a0e1f41 bellard
        rnd_type = 80;
3814 7a0e1f41 bellard
        break;
3815 7a0e1f41 bellard
    }
3816 7a0e1f41 bellard
    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3817 4d6b6c0a bellard
#endif
3818 7a0e1f41 bellard
}
3819 664e0f19 bellard
3820 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
3821 61382a50 bellard
3822 61382a50 bellard
#define MMUSUFFIX _mmu
3823 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
3824 61382a50 bellard
3825 2c0262af bellard
#define SHIFT 0
3826 2c0262af bellard
#include "softmmu_template.h"
3827 2c0262af bellard
3828 2c0262af bellard
#define SHIFT 1
3829 2c0262af bellard
#include "softmmu_template.h"
3830 2c0262af bellard
3831 2c0262af bellard
#define SHIFT 2
3832 2c0262af bellard
#include "softmmu_template.h"
3833 2c0262af bellard
3834 2c0262af bellard
#define SHIFT 3
3835 2c0262af bellard
#include "softmmu_template.h"
3836 2c0262af bellard
3837 61382a50 bellard
#endif
3838 61382a50 bellard
3839 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
3840 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
3841 61382a50 bellard
   from generated code or from helper.c) */
3842 61382a50 bellard
/* XXX: fix it to restore all registers */
3843 14ce26e7 bellard
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
3844 2c0262af bellard
{
3845 2c0262af bellard
    TranslationBlock *tb;
3846 2c0262af bellard
    int ret;
3847 2c0262af bellard
    unsigned long pc;
3848 61382a50 bellard
    CPUX86State *saved_env;
3849 61382a50 bellard
3850 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
3851 61382a50 bellard
       generated code */
3852 61382a50 bellard
    saved_env = env;
3853 61382a50 bellard
    env = cpu_single_env;
3854 61382a50 bellard
3855 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
3856 2c0262af bellard
    if (ret) {
3857 61382a50 bellard
        if (retaddr) {
3858 61382a50 bellard
            /* now we have a real cpu fault */
3859 61382a50 bellard
            pc = (unsigned long)retaddr;
3860 61382a50 bellard
            tb = tb_find_pc(pc);
3861 61382a50 bellard
            if (tb) {
3862 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
3863 61382a50 bellard
                   a virtual CPU fault */
3864 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
3865 61382a50 bellard
            }
3866 2c0262af bellard
        }
3867 0d1a29f9 bellard
        if (retaddr)
3868 54ca9095 bellard
            raise_exception_err(env->exception_index, env->error_code);
3869 0d1a29f9 bellard
        else
3870 54ca9095 bellard
            raise_exception_err_norestore(env->exception_index, env->error_code);
3871 2c0262af bellard
    }
3872 61382a50 bellard
    env = saved_env;
3873 2c0262af bellard
}