Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 52621688

History | View | Annotate | Download (129.7 kB)

1 2c0262af bellard
/*
2 2c0262af bellard
 *  i386 helpers
3 5fafdf24 ths
 *
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 5fafdf24 ths
    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 5fafdf24 ths
    0, 1, 2, 3, 4, 5, 6, 7,
79 2c0262af bellard
    8, 0, 1, 2, 3, 4, 5, 6,
80 5fafdf24 ths
    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 3b46e624 ths
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 3b46e624 ths
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 5fafdf24 ths
    cpu_x86_load_seg_cache(env, seg, selector,
156 14ce26e7 bellard
                           (selector << 4), 0xffff, 0);
157 7e84c249 bellard
}
158 7e84c249 bellard
159 5fafdf24 ths
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 3b46e624 ths
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 5fafdf24 ths
        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 5fafdf24 ths
        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 5fafdf24 ths
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 5fafdf24 ths
    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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 5fafdf24 ths
    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 5fafdf24 ths
        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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 3b46e624 ths
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 0573fbfc ths
    int svm_should_check = 1;
598 2c0262af bellard
599 0573fbfc ths
    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
600 0573fbfc ths
        next_eip = EIP;
601 0573fbfc ths
        svm_should_check = 0;
602 0573fbfc ths
    }
603 0573fbfc ths
604 0573fbfc ths
    if (svm_should_check
605 0573fbfc ths
        && (INTERCEPTEDl(_exceptions, 1 << intno)
606 0573fbfc ths
        && !is_int)) {
607 0573fbfc ths
        raise_interrupt(intno, is_int, error_code, 0);
608 0573fbfc ths
    }
609 7e84c249 bellard
    has_error_code = 0;
610 7e84c249 bellard
    if (!is_int && !is_hw) {
611 7e84c249 bellard
        switch(intno) {
612 7e84c249 bellard
        case 8:
613 7e84c249 bellard
        case 10:
614 7e84c249 bellard
        case 11:
615 7e84c249 bellard
        case 12:
616 7e84c249 bellard
        case 13:
617 7e84c249 bellard
        case 14:
618 7e84c249 bellard
        case 17:
619 7e84c249 bellard
            has_error_code = 1;
620 7e84c249 bellard
            break;
621 7e84c249 bellard
        }
622 7e84c249 bellard
    }
623 883da8e2 bellard
    if (is_int)
624 883da8e2 bellard
        old_eip = next_eip;
625 883da8e2 bellard
    else
626 883da8e2 bellard
        old_eip = env->eip;
627 7e84c249 bellard
628 2c0262af bellard
    dt = &env->idt;
629 2c0262af bellard
    if (intno * 8 + 7 > dt->limit)
630 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
631 2c0262af bellard
    ptr = dt->base + intno * 8;
632 61382a50 bellard
    e1 = ldl_kernel(ptr);
633 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
634 2c0262af bellard
    /* check gate type */
635 2c0262af bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
636 2c0262af bellard
    switch(type) {
637 2c0262af bellard
    case 5: /* task gate */
638 7e84c249 bellard
        /* must do that check here to return the correct error code */
639 7e84c249 bellard
        if (!(e2 & DESC_P_MASK))
640 7e84c249 bellard
            raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
641 883da8e2 bellard
        switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
642 7e84c249 bellard
        if (has_error_code) {
643 8d7b0fbb bellard
            int type;
644 8d7b0fbb bellard
            uint32_t mask;
645 7e84c249 bellard
            /* push the error code */
646 3f20e1dd bellard
            type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
647 3f20e1dd bellard
            shift = type >> 3;
648 7e84c249 bellard
            if (env->segs[R_SS].flags & DESC_B_MASK)
649 7e84c249 bellard
                mask = 0xffffffff;
650 7e84c249 bellard
            else
651 7e84c249 bellard
                mask = 0xffff;
652 0d1a29f9 bellard
            esp = (ESP - (2 << shift)) & mask;
653 7e84c249 bellard
            ssp = env->segs[R_SS].base + esp;
654 7e84c249 bellard
            if (shift)
655 7e84c249 bellard
                stl_kernel(ssp, error_code);
656 7e84c249 bellard
            else
657 7e84c249 bellard
                stw_kernel(ssp, error_code);
658 8d7b0fbb bellard
            SET_ESP(esp, mask);
659 7e84c249 bellard
        }
660 7e84c249 bellard
        return;
661 2c0262af bellard
    case 6: /* 286 interrupt gate */
662 2c0262af bellard
    case 7: /* 286 trap gate */
663 2c0262af bellard
    case 14: /* 386 interrupt gate */
664 2c0262af bellard
    case 15: /* 386 trap gate */
665 2c0262af bellard
        break;
666 2c0262af bellard
    default:
667 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
668 2c0262af bellard
        break;
669 2c0262af bellard
    }
670 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
671 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
672 2c0262af bellard
    /* check privledge if software int */
673 2c0262af bellard
    if (is_int && dpl < cpl)
674 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
675 2c0262af bellard
    /* check valid bit */
676 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
677 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
678 2c0262af bellard
    selector = e1 >> 16;
679 2c0262af bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
680 2c0262af bellard
    if ((selector & 0xfffc) == 0)
681 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
682 2c0262af bellard
683 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
684 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
685 2c0262af bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
686 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
687 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
688 2c0262af bellard
    if (dpl > cpl)
689 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
690 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
691 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
692 2c0262af bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
693 7f75ffd3 blueswir1
        /* to inner privilege */
694 2c0262af bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
695 2c0262af bellard
        if ((ss & 0xfffc) == 0)
696 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
697 2c0262af bellard
        if ((ss & 3) != dpl)
698 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
699 2c0262af bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
700 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
701 2c0262af bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
702 2c0262af bellard
        if (ss_dpl != dpl)
703 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
704 2c0262af bellard
        if (!(ss_e2 & DESC_S_MASK) ||
705 2c0262af bellard
            (ss_e2 & DESC_CS_MASK) ||
706 2c0262af bellard
            !(ss_e2 & DESC_W_MASK))
707 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
708 2c0262af bellard
        if (!(ss_e2 & DESC_P_MASK))
709 2c0262af bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
710 2c0262af bellard
        new_stack = 1;
711 891b38e4 bellard
        sp_mask = get_sp_mask(ss_e2);
712 891b38e4 bellard
        ssp = get_seg_base(ss_e1, ss_e2);
713 2c0262af bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
714 7f75ffd3 blueswir1
        /* to same privilege */
715 8e682019 bellard
        if (env->eflags & VM_MASK)
716 8e682019 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
717 2c0262af bellard
        new_stack = 0;
718 891b38e4 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
719 891b38e4 bellard
        ssp = env->segs[R_SS].base;
720 891b38e4 bellard
        esp = ESP;
721 4796f5e9 bellard
        dpl = cpl;
722 2c0262af bellard
    } else {
723 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
724 2c0262af bellard
        new_stack = 0; /* avoid warning */
725 891b38e4 bellard
        sp_mask = 0; /* avoid warning */
726 14ce26e7 bellard
        ssp = 0; /* avoid warning */
727 891b38e4 bellard
        esp = 0; /* avoid warning */
728 2c0262af bellard
    }
729 2c0262af bellard
730 2c0262af bellard
    shift = type >> 3;
731 891b38e4 bellard
732 891b38e4 bellard
#if 0
733 891b38e4 bellard
    /* XXX: check that enough room is available */
734 2c0262af bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
735 2c0262af bellard
    if (env->eflags & VM_MASK)
736 2c0262af bellard
        push_size += 8;
737 2c0262af bellard
    push_size <<= shift;
738 891b38e4 bellard
#endif
739 2c0262af bellard
    if (shift == 1) {
740 2c0262af bellard
        if (new_stack) {
741 8e682019 bellard
            if (env->eflags & VM_MASK) {
742 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
743 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
744 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
745 8e682019 bellard
                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
746 8e682019 bellard
            }
747 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
748 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, ESP);
749 2c0262af bellard
        }
750 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, compute_eflags());
751 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
752 891b38e4 bellard
        PUSHL(ssp, esp, sp_mask, old_eip);
753 2c0262af bellard
        if (has_error_code) {
754 891b38e4 bellard
            PUSHL(ssp, esp, sp_mask, error_code);
755 2c0262af bellard
        }
756 2c0262af bellard
    } else {
757 2c0262af bellard
        if (new_stack) {
758 8e682019 bellard
            if (env->eflags & VM_MASK) {
759 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
760 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
761 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
762 8e682019 bellard
                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
763 8e682019 bellard
            }
764 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
765 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, ESP);
766 2c0262af bellard
        }
767 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, compute_eflags());
768 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
769 891b38e4 bellard
        PUSHW(ssp, esp, sp_mask, old_eip);
770 2c0262af bellard
        if (has_error_code) {
771 891b38e4 bellard
            PUSHW(ssp, esp, sp_mask, error_code);
772 2c0262af bellard
        }
773 2c0262af bellard
    }
774 3b46e624 ths
775 891b38e4 bellard
    if (new_stack) {
776 8e682019 bellard
        if (env->eflags & VM_MASK) {
777 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
778 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
779 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
780 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
781 8e682019 bellard
        }
782 891b38e4 bellard
        ss = (ss & ~3) | dpl;
783 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_SS, ss,
784 891b38e4 bellard
                               ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
785 891b38e4 bellard
    }
786 8d7b0fbb bellard
    SET_ESP(esp, sp_mask);
787 891b38e4 bellard
788 891b38e4 bellard
    selector = (selector & ~3) | dpl;
789 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_CS, selector,
790 891b38e4 bellard
                   get_seg_base(e1, e2),
791 891b38e4 bellard
                   get_seg_limit(e1, e2),
792 891b38e4 bellard
                   e2);
793 891b38e4 bellard
    cpu_x86_set_cpl(env, dpl);
794 891b38e4 bellard
    env->eip = offset;
795 891b38e4 bellard
796 2c0262af bellard
    /* interrupt gate clear IF mask */
797 2c0262af bellard
    if ((type & 1) == 0) {
798 2c0262af bellard
        env->eflags &= ~IF_MASK;
799 2c0262af bellard
    }
800 2c0262af bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
801 2c0262af bellard
}
802 2c0262af bellard
803 14ce26e7 bellard
#ifdef TARGET_X86_64
804 14ce26e7 bellard
805 14ce26e7 bellard
#define PUSHQ(sp, val)\
806 14ce26e7 bellard
{\
807 14ce26e7 bellard
    sp -= 8;\
808 14ce26e7 bellard
    stq_kernel(sp, (val));\
809 14ce26e7 bellard
}
810 14ce26e7 bellard
811 14ce26e7 bellard
#define POPQ(sp, val)\
812 14ce26e7 bellard
{\
813 14ce26e7 bellard
    val = ldq_kernel(sp);\
814 14ce26e7 bellard
    sp += 8;\
815 14ce26e7 bellard
}
816 14ce26e7 bellard
817 14ce26e7 bellard
static inline target_ulong get_rsp_from_tss(int level)
818 14ce26e7 bellard
{
819 14ce26e7 bellard
    int index;
820 3b46e624 ths
821 14ce26e7 bellard
#if 0
822 5fafdf24 ths
    printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
823 14ce26e7 bellard
           env->tr.base, env->tr.limit);
824 14ce26e7 bellard
#endif
825 14ce26e7 bellard
826 14ce26e7 bellard
    if (!(env->tr.flags & DESC_P_MASK))
827 14ce26e7 bellard
        cpu_abort(env, "invalid tss");
828 14ce26e7 bellard
    index = 8 * level + 4;
829 14ce26e7 bellard
    if ((index + 7) > env->tr.limit)
830 14ce26e7 bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
831 14ce26e7 bellard
    return ldq_kernel(env->tr.base + index);
832 14ce26e7 bellard
}
833 14ce26e7 bellard
834 14ce26e7 bellard
/* 64 bit interrupt */
835 14ce26e7 bellard
static void do_interrupt64(int intno, int is_int, int error_code,
836 14ce26e7 bellard
                           target_ulong next_eip, int is_hw)
837 14ce26e7 bellard
{
838 14ce26e7 bellard
    SegmentCache *dt;
839 14ce26e7 bellard
    target_ulong ptr;
840 14ce26e7 bellard
    int type, dpl, selector, cpl, ist;
841 14ce26e7 bellard
    int has_error_code, new_stack;
842 14ce26e7 bellard
    uint32_t e1, e2, e3, ss;
843 14ce26e7 bellard
    target_ulong old_eip, esp, offset;
844 0573fbfc ths
    int svm_should_check = 1;
845 14ce26e7 bellard
846 0573fbfc ths
    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
847 0573fbfc ths
        next_eip = EIP;
848 0573fbfc ths
        svm_should_check = 0;
849 0573fbfc ths
    }
850 0573fbfc ths
    if (svm_should_check
851 0573fbfc ths
        && INTERCEPTEDl(_exceptions, 1 << intno)
852 0573fbfc ths
        && !is_int) {
853 0573fbfc ths
        raise_interrupt(intno, is_int, error_code, 0);
854 0573fbfc ths
    }
855 14ce26e7 bellard
    has_error_code = 0;
856 14ce26e7 bellard
    if (!is_int && !is_hw) {
857 14ce26e7 bellard
        switch(intno) {
858 14ce26e7 bellard
        case 8:
859 14ce26e7 bellard
        case 10:
860 14ce26e7 bellard
        case 11:
861 14ce26e7 bellard
        case 12:
862 14ce26e7 bellard
        case 13:
863 14ce26e7 bellard
        case 14:
864 14ce26e7 bellard
        case 17:
865 14ce26e7 bellard
            has_error_code = 1;
866 14ce26e7 bellard
            break;
867 14ce26e7 bellard
        }
868 14ce26e7 bellard
    }
869 14ce26e7 bellard
    if (is_int)
870 14ce26e7 bellard
        old_eip = next_eip;
871 14ce26e7 bellard
    else
872 14ce26e7 bellard
        old_eip = env->eip;
873 14ce26e7 bellard
874 14ce26e7 bellard
    dt = &env->idt;
875 14ce26e7 bellard
    if (intno * 16 + 15 > dt->limit)
876 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
877 14ce26e7 bellard
    ptr = dt->base + intno * 16;
878 14ce26e7 bellard
    e1 = ldl_kernel(ptr);
879 14ce26e7 bellard
    e2 = ldl_kernel(ptr + 4);
880 14ce26e7 bellard
    e3 = ldl_kernel(ptr + 8);
881 14ce26e7 bellard
    /* check gate type */
882 14ce26e7 bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
883 14ce26e7 bellard
    switch(type) {
884 14ce26e7 bellard
    case 14: /* 386 interrupt gate */
885 14ce26e7 bellard
    case 15: /* 386 trap gate */
886 14ce26e7 bellard
        break;
887 14ce26e7 bellard
    default:
888 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
889 14ce26e7 bellard
        break;
890 14ce26e7 bellard
    }
891 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
892 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
893 14ce26e7 bellard
    /* check privledge if software int */
894 14ce26e7 bellard
    if (is_int && dpl < cpl)
895 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
896 14ce26e7 bellard
    /* check valid bit */
897 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
898 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
899 14ce26e7 bellard
    selector = e1 >> 16;
900 14ce26e7 bellard
    offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
901 14ce26e7 bellard
    ist = e2 & 7;
902 14ce26e7 bellard
    if ((selector & 0xfffc) == 0)
903 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
904 14ce26e7 bellard
905 14ce26e7 bellard
    if (load_segment(&e1, &e2, selector) != 0)
906 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
907 14ce26e7 bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
908 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
909 14ce26e7 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
910 14ce26e7 bellard
    if (dpl > cpl)
911 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
912 14ce26e7 bellard
    if (!(e2 & DESC_P_MASK))
913 14ce26e7 bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
914 14ce26e7 bellard
    if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
915 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
916 14ce26e7 bellard
    if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
917 7f75ffd3 blueswir1
        /* to inner privilege */
918 14ce26e7 bellard
        if (ist != 0)
919 14ce26e7 bellard
            esp = get_rsp_from_tss(ist + 3);
920 14ce26e7 bellard
        else
921 14ce26e7 bellard
            esp = get_rsp_from_tss(dpl);
922 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
923 14ce26e7 bellard
        ss = 0;
924 14ce26e7 bellard
        new_stack = 1;
925 14ce26e7 bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
926 7f75ffd3 blueswir1
        /* to same privilege */
927 14ce26e7 bellard
        if (env->eflags & VM_MASK)
928 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
929 14ce26e7 bellard
        new_stack = 0;
930 9540a78b bellard
        if (ist != 0)
931 9540a78b bellard
            esp = get_rsp_from_tss(ist + 3);
932 9540a78b bellard
        else
933 9540a78b bellard
            esp = ESP;
934 9540a78b bellard
        esp &= ~0xfLL; /* align stack */
935 14ce26e7 bellard
        dpl = cpl;
936 14ce26e7 bellard
    } else {
937 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
938 14ce26e7 bellard
        new_stack = 0; /* avoid warning */
939 14ce26e7 bellard
        esp = 0; /* avoid warning */
940 14ce26e7 bellard
    }
941 14ce26e7 bellard
942 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_SS].selector);
943 14ce26e7 bellard
    PUSHQ(esp, ESP);
944 14ce26e7 bellard
    PUSHQ(esp, compute_eflags());
945 14ce26e7 bellard
    PUSHQ(esp, env->segs[R_CS].selector);
946 14ce26e7 bellard
    PUSHQ(esp, old_eip);
947 14ce26e7 bellard
    if (has_error_code) {
948 14ce26e7 bellard
        PUSHQ(esp, error_code);
949 14ce26e7 bellard
    }
950 3b46e624 ths
951 14ce26e7 bellard
    if (new_stack) {
952 14ce26e7 bellard
        ss = 0 | dpl;
953 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
954 14ce26e7 bellard
    }
955 14ce26e7 bellard
    ESP = esp;
956 14ce26e7 bellard
957 14ce26e7 bellard
    selector = (selector & ~3) | dpl;
958 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_CS, selector,
959 14ce26e7 bellard
                   get_seg_base(e1, e2),
960 14ce26e7 bellard
                   get_seg_limit(e1, e2),
961 14ce26e7 bellard
                   e2);
962 14ce26e7 bellard
    cpu_x86_set_cpl(env, dpl);
963 14ce26e7 bellard
    env->eip = offset;
964 14ce26e7 bellard
965 14ce26e7 bellard
    /* interrupt gate clear IF mask */
966 14ce26e7 bellard
    if ((type & 1) == 0) {
967 14ce26e7 bellard
        env->eflags &= ~IF_MASK;
968 14ce26e7 bellard
    }
969 14ce26e7 bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
970 14ce26e7 bellard
}
971 f419b321 bellard
#endif
972 14ce26e7 bellard
973 06c2f506 bellard
void helper_syscall(int next_eip_addend)
974 14ce26e7 bellard
{
975 14ce26e7 bellard
    int selector;
976 14ce26e7 bellard
977 14ce26e7 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
978 14ce26e7 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
979 14ce26e7 bellard
    }
980 14ce26e7 bellard
    selector = (env->star >> 32) & 0xffff;
981 f419b321 bellard
#ifdef TARGET_X86_64
982 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
983 9540a78b bellard
        int code64;
984 9540a78b bellard
985 06c2f506 bellard
        ECX = env->eip + next_eip_addend;
986 14ce26e7 bellard
        env->regs[11] = compute_eflags();
987 3b46e624 ths
988 9540a78b bellard
        code64 = env->hflags & HF_CS64_MASK;
989 14ce26e7 bellard
990 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
991 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
992 5fafdf24 ths
                           0, 0xffffffff,
993 d80c7d1c bellard
                               DESC_G_MASK | DESC_P_MASK |
994 14ce26e7 bellard
                               DESC_S_MASK |
995 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
996 5fafdf24 ths
        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 &= ~env->fmask;
1002 9540a78b bellard
        if (code64)
1003 14ce26e7 bellard
            env->eip = env->lstar;
1004 14ce26e7 bellard
        else
1005 14ce26e7 bellard
            env->eip = env->cstar;
1006 5fafdf24 ths
    } else
1007 f419b321 bellard
#endif
1008 f419b321 bellard
    {
1009 06c2f506 bellard
        ECX = (uint32_t)(env->eip + next_eip_addend);
1010 3b46e624 ths
1011 14ce26e7 bellard
        cpu_x86_set_cpl(env, 0);
1012 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
1013 5fafdf24 ths
                           0, 0xffffffff,
1014 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1015 14ce26e7 bellard
                               DESC_S_MASK |
1016 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1017 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
1018 14ce26e7 bellard
                               0, 0xffffffff,
1019 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1020 14ce26e7 bellard
                               DESC_S_MASK |
1021 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1022 14ce26e7 bellard
        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
1023 14ce26e7 bellard
        env->eip = (uint32_t)env->star;
1024 14ce26e7 bellard
    }
1025 14ce26e7 bellard
}
1026 14ce26e7 bellard
1027 14ce26e7 bellard
void helper_sysret(int dflag)
1028 14ce26e7 bellard
{
1029 14ce26e7 bellard
    int cpl, selector;
1030 14ce26e7 bellard
1031 f419b321 bellard
    if (!(env->efer & MSR_EFER_SCE)) {
1032 f419b321 bellard
        raise_exception_err(EXCP06_ILLOP, 0);
1033 f419b321 bellard
    }
1034 14ce26e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1035 14ce26e7 bellard
    if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
1036 14ce26e7 bellard
        raise_exception_err(EXCP0D_GPF, 0);
1037 14ce26e7 bellard
    }
1038 14ce26e7 bellard
    selector = (env->star >> 48) & 0xffff;
1039 f419b321 bellard
#ifdef TARGET_X86_64
1040 14ce26e7 bellard
    if (env->hflags & HF_LMA_MASK) {
1041 14ce26e7 bellard
        if (dflag == 2) {
1042 5fafdf24 ths
            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
1043 5fafdf24 ths
                                   0, 0xffffffff,
1044 d80c7d1c bellard
                                   DESC_G_MASK | DESC_P_MASK |
1045 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1046 5fafdf24 ths
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
1047 14ce26e7 bellard
                                   DESC_L_MASK);
1048 14ce26e7 bellard
            env->eip = ECX;
1049 14ce26e7 bellard
        } else {
1050 5fafdf24 ths
            cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1051 5fafdf24 ths
                                   0, 0xffffffff,
1052 14ce26e7 bellard
                                   DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1053 14ce26e7 bellard
                                   DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1054 14ce26e7 bellard
                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1055 14ce26e7 bellard
            env->eip = (uint32_t)ECX;
1056 14ce26e7 bellard
        }
1057 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1058 14ce26e7 bellard
                               0, 0xffffffff,
1059 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1060 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1061 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1062 5fafdf24 ths
        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
1063 31313213 bellard
                    IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
1064 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1065 5fafdf24 ths
    } else
1066 f419b321 bellard
#endif
1067 f419b321 bellard
    {
1068 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, selector | 3,
1069 5fafdf24 ths
                               0, 0xffffffff,
1070 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1071 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1072 14ce26e7 bellard
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
1073 14ce26e7 bellard
        env->eip = (uint32_t)ECX;
1074 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
1075 14ce26e7 bellard
                               0, 0xffffffff,
1076 14ce26e7 bellard
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
1077 14ce26e7 bellard
                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
1078 14ce26e7 bellard
                               DESC_W_MASK | DESC_A_MASK);
1079 14ce26e7 bellard
        env->eflags |= IF_MASK;
1080 14ce26e7 bellard
        cpu_x86_set_cpl(env, 3);
1081 14ce26e7 bellard
    }
1082 f419b321 bellard
#ifdef USE_KQEMU
1083 f419b321 bellard
    if (kqemu_is_ok(env)) {
1084 f419b321 bellard
        if (env->hflags & HF_LMA_MASK)
1085 f419b321 bellard
            CC_OP = CC_OP_EFLAGS;
1086 f419b321 bellard
        env->exception_index = -1;
1087 f419b321 bellard
        cpu_loop_exit();
1088 f419b321 bellard
    }
1089 14ce26e7 bellard
#endif
1090 f419b321 bellard
}
1091 14ce26e7 bellard
1092 2c0262af bellard
/* real mode interrupt */
1093 2c0262af bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
1094 4136f33c bellard
                              unsigned int next_eip)
1095 2c0262af bellard
{
1096 2c0262af bellard
    SegmentCache *dt;
1097 14ce26e7 bellard
    target_ulong ptr, ssp;
1098 2c0262af bellard
    int selector;
1099 2c0262af bellard
    uint32_t offset, esp;
1100 2c0262af bellard
    uint32_t old_cs, old_eip;
1101 0573fbfc ths
    int svm_should_check = 1;
1102 2c0262af bellard
1103 0573fbfc ths
    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
1104 0573fbfc ths
        next_eip = EIP;
1105 0573fbfc ths
        svm_should_check = 0;
1106 0573fbfc ths
    }
1107 0573fbfc ths
    if (svm_should_check
1108 0573fbfc ths
        && INTERCEPTEDl(_exceptions, 1 << intno)
1109 0573fbfc ths
        && !is_int) {
1110 0573fbfc ths
        raise_interrupt(intno, is_int, error_code, 0);
1111 0573fbfc ths
    }
1112 2c0262af bellard
    /* real mode (simpler !) */
1113 2c0262af bellard
    dt = &env->idt;
1114 2c0262af bellard
    if (intno * 4 + 3 > dt->limit)
1115 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1116 2c0262af bellard
    ptr = dt->base + intno * 4;
1117 61382a50 bellard
    offset = lduw_kernel(ptr);
1118 61382a50 bellard
    selector = lduw_kernel(ptr + 2);
1119 2c0262af bellard
    esp = ESP;
1120 2c0262af bellard
    ssp = env->segs[R_SS].base;
1121 2c0262af bellard
    if (is_int)
1122 2c0262af bellard
        old_eip = next_eip;
1123 2c0262af bellard
    else
1124 2c0262af bellard
        old_eip = env->eip;
1125 2c0262af bellard
    old_cs = env->segs[R_CS].selector;
1126 891b38e4 bellard
    /* XXX: use SS segment size ? */
1127 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, compute_eflags());
1128 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_cs);
1129 891b38e4 bellard
    PUSHW(ssp, esp, 0xffff, old_eip);
1130 3b46e624 ths
1131 2c0262af bellard
    /* update processor state */
1132 2c0262af bellard
    ESP = (ESP & ~0xffff) | (esp & 0xffff);
1133 2c0262af bellard
    env->eip = offset;
1134 2c0262af bellard
    env->segs[R_CS].selector = selector;
1135 14ce26e7 bellard
    env->segs[R_CS].base = (selector << 4);
1136 2c0262af bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
1137 2c0262af bellard
}
1138 2c0262af bellard
1139 2c0262af bellard
/* fake user mode interrupt */
1140 5fafdf24 ths
void do_interrupt_user(int intno, int is_int, int error_code,
1141 14ce26e7 bellard
                       target_ulong next_eip)
1142 2c0262af bellard
{
1143 2c0262af bellard
    SegmentCache *dt;
1144 14ce26e7 bellard
    target_ulong ptr;
1145 2c0262af bellard
    int dpl, cpl;
1146 2c0262af bellard
    uint32_t e2;
1147 2c0262af bellard
1148 2c0262af bellard
    dt = &env->idt;
1149 2c0262af bellard
    ptr = dt->base + (intno * 8);
1150 61382a50 bellard
    e2 = ldl_kernel(ptr + 4);
1151 3b46e624 ths
1152 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1153 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
1154 2c0262af bellard
    /* check privledge if software int */
1155 2c0262af bellard
    if (is_int && dpl < cpl)
1156 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
1157 2c0262af bellard
1158 2c0262af bellard
    /* Since we emulate only user space, we cannot do more than
1159 2c0262af bellard
       exiting the emulation with the suitable exception and error
1160 2c0262af bellard
       code */
1161 2c0262af bellard
    if (is_int)
1162 2c0262af bellard
        EIP = next_eip;
1163 2c0262af bellard
}
1164 2c0262af bellard
1165 2c0262af bellard
/*
1166 e19e89a5 bellard
 * Begin execution of an interruption. is_int is TRUE if coming from
1167 2c0262af bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
1168 3b46e624 ths
 * instruction. It is only relevant if is_int is TRUE.
1169 2c0262af bellard
 */
1170 5fafdf24 ths
void do_interrupt(int intno, int is_int, int error_code,
1171 14ce26e7 bellard
                  target_ulong next_eip, int is_hw)
1172 2c0262af bellard
{
1173 1247c5f7 bellard
    if (loglevel & CPU_LOG_INT) {
1174 e19e89a5 bellard
        if ((env->cr[0] & CR0_PE_MASK)) {
1175 e19e89a5 bellard
            static int count;
1176 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,
1177 dc6f57fd bellard
                    count, intno, error_code, is_int,
1178 dc6f57fd bellard
                    env->hflags & HF_CPL_MASK,
1179 dc6f57fd bellard
                    env->segs[R_CS].selector, EIP,
1180 2ee73ac3 bellard
                    (int)env->segs[R_CS].base + EIP,
1181 8145122b bellard
                    env->segs[R_SS].selector, ESP);
1182 8145122b bellard
            if (intno == 0x0e) {
1183 14ce26e7 bellard
                fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
1184 8145122b bellard
            } else {
1185 14ce26e7 bellard
                fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
1186 8145122b bellard
            }
1187 e19e89a5 bellard
            fprintf(logfile, "\n");
1188 06c2f506 bellard
            cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1189 1247c5f7 bellard
#if 0
1190 e19e89a5 bellard
            {
1191 e19e89a5 bellard
                int i;
1192 e19e89a5 bellard
                uint8_t *ptr;
1193 e19e89a5 bellard
                fprintf(logfile, "       code=");
1194 e19e89a5 bellard
                ptr = env->segs[R_CS].base + env->eip;
1195 e19e89a5 bellard
                for(i = 0; i < 16; i++) {
1196 e19e89a5 bellard
                    fprintf(logfile, " %02x", ldub(ptr + i));
1197 dc6f57fd bellard
                }
1198 e19e89a5 bellard
                fprintf(logfile, "\n");
1199 dc6f57fd bellard
            }
1200 8e682019 bellard
#endif
1201 e19e89a5 bellard
            count++;
1202 4136f33c bellard
        }
1203 4136f33c bellard
    }
1204 2c0262af bellard
    if (env->cr[0] & CR0_PE_MASK) {
1205 14ce26e7 bellard
#if TARGET_X86_64
1206 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1207 14ce26e7 bellard
            do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
1208 14ce26e7 bellard
        } else
1209 14ce26e7 bellard
#endif
1210 14ce26e7 bellard
        {
1211 14ce26e7 bellard
            do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
1212 14ce26e7 bellard
        }
1213 2c0262af bellard
    } else {
1214 2c0262af bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
1215 2c0262af bellard
    }
1216 2c0262af bellard
}
1217 2c0262af bellard
1218 2c0262af bellard
/*
1219 678dde13 ths
 * Check nested exceptions and change to double or triple fault if
1220 678dde13 ths
 * needed. It should only be called, if this is not an interrupt.
1221 678dde13 ths
 * Returns the new exception number.
1222 678dde13 ths
 */
1223 678dde13 ths
int check_exception(int intno, int *error_code)
1224 678dde13 ths
{
1225 678dde13 ths
    char first_contributory = env->old_exception == 0 ||
1226 678dde13 ths
                              (env->old_exception >= 10 &&
1227 678dde13 ths
                               env->old_exception <= 13);
1228 678dde13 ths
    char second_contributory = intno == 0 ||
1229 678dde13 ths
                               (intno >= 10 && intno <= 13);
1230 678dde13 ths
1231 678dde13 ths
    if (loglevel & CPU_LOG_INT)
1232 678dde13 ths
        fprintf(logfile, "check_exception old: %x new %x\n",
1233 678dde13 ths
                env->old_exception, intno);
1234 678dde13 ths
1235 678dde13 ths
    if (env->old_exception == EXCP08_DBLE)
1236 678dde13 ths
        cpu_abort(env, "triple fault");
1237 678dde13 ths
1238 678dde13 ths
    if ((first_contributory && second_contributory)
1239 678dde13 ths
        || (env->old_exception == EXCP0E_PAGE &&
1240 678dde13 ths
            (second_contributory || (intno == EXCP0E_PAGE)))) {
1241 678dde13 ths
        intno = EXCP08_DBLE;
1242 678dde13 ths
        *error_code = 0;
1243 678dde13 ths
    }
1244 678dde13 ths
1245 678dde13 ths
    if (second_contributory || (intno == EXCP0E_PAGE) ||
1246 678dde13 ths
        (intno == EXCP08_DBLE))
1247 678dde13 ths
        env->old_exception = intno;
1248 678dde13 ths
1249 678dde13 ths
    return intno;
1250 678dde13 ths
}
1251 678dde13 ths
1252 678dde13 ths
/*
1253 2c0262af bellard
 * Signal an interruption. It is executed in the main CPU loop.
1254 2c0262af bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
1255 2c0262af bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
1256 3b46e624 ths
 * is_int is TRUE.
1257 2c0262af bellard
 */
1258 5fafdf24 ths
void raise_interrupt(int intno, int is_int, int error_code,
1259 a8ede8ba bellard
                     int next_eip_addend)
1260 2c0262af bellard
{
1261 0573fbfc ths
    if (!is_int) {
1262 0573fbfc ths
        svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
1263 678dde13 ths
        intno = check_exception(intno, &error_code);
1264 0573fbfc ths
    }
1265 678dde13 ths
1266 2c0262af bellard
    env->exception_index = intno;
1267 2c0262af bellard
    env->error_code = error_code;
1268 2c0262af bellard
    env->exception_is_int = is_int;
1269 a8ede8ba bellard
    env->exception_next_eip = env->eip + next_eip_addend;
1270 2c0262af bellard
    cpu_loop_exit();
1271 2c0262af bellard
}
1272 2c0262af bellard
1273 0d1a29f9 bellard
/* same as raise_exception_err, but do not restore global registers */
1274 0d1a29f9 bellard
static void raise_exception_err_norestore(int exception_index, int error_code)
1275 0d1a29f9 bellard
{
1276 678dde13 ths
    exception_index = check_exception(exception_index, &error_code);
1277 678dde13 ths
1278 0d1a29f9 bellard
    env->exception_index = exception_index;
1279 0d1a29f9 bellard
    env->error_code = error_code;
1280 0d1a29f9 bellard
    env->exception_is_int = 0;
1281 0d1a29f9 bellard
    env->exception_next_eip = 0;
1282 0d1a29f9 bellard
    longjmp(env->jmp_env, 1);
1283 0d1a29f9 bellard
}
1284 0d1a29f9 bellard
1285 2c0262af bellard
/* shortcuts to generate exceptions */
1286 8145122b bellard
1287 8145122b bellard
void (raise_exception_err)(int exception_index, int error_code)
1288 2c0262af bellard
{
1289 2c0262af bellard
    raise_interrupt(exception_index, 0, error_code, 0);
1290 2c0262af bellard
}
1291 2c0262af bellard
1292 2c0262af bellard
void raise_exception(int exception_index)
1293 2c0262af bellard
{
1294 2c0262af bellard
    raise_interrupt(exception_index, 0, 0, 0);
1295 2c0262af bellard
}
1296 2c0262af bellard
1297 3b21e03e bellard
/* SMM support */
1298 3b21e03e bellard
1299 5fafdf24 ths
#if defined(CONFIG_USER_ONLY)
1300 74ce674f bellard
1301 74ce674f bellard
void do_smm_enter(void)
1302 74ce674f bellard
{
1303 74ce674f bellard
}
1304 74ce674f bellard
1305 74ce674f bellard
void helper_rsm(void)
1306 74ce674f bellard
{
1307 74ce674f bellard
}
1308 74ce674f bellard
1309 74ce674f bellard
#else
1310 74ce674f bellard
1311 3b21e03e bellard
#ifdef TARGET_X86_64
1312 3b21e03e bellard
#define SMM_REVISION_ID 0x00020064
1313 3b21e03e bellard
#else
1314 3b21e03e bellard
#define SMM_REVISION_ID 0x00020000
1315 3b21e03e bellard
#endif
1316 3b21e03e bellard
1317 3b21e03e bellard
void do_smm_enter(void)
1318 3b21e03e bellard
{
1319 3b21e03e bellard
    target_ulong sm_state;
1320 3b21e03e bellard
    SegmentCache *dt;
1321 3b21e03e bellard
    int i, offset;
1322 3b21e03e bellard
1323 3b21e03e bellard
    if (loglevel & CPU_LOG_INT) {
1324 3b21e03e bellard
        fprintf(logfile, "SMM: enter\n");
1325 3b21e03e bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1326 3b21e03e bellard
    }
1327 3b21e03e bellard
1328 3b21e03e bellard
    env->hflags |= HF_SMM_MASK;
1329 3b21e03e bellard
    cpu_smm_update(env);
1330 3b21e03e bellard
1331 3b21e03e bellard
    sm_state = env->smbase + 0x8000;
1332 3b46e624 ths
1333 3b21e03e bellard
#ifdef TARGET_X86_64
1334 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1335 3b21e03e bellard
        dt = &env->segs[i];
1336 3b21e03e bellard
        offset = 0x7e00 + i * 16;
1337 3b21e03e bellard
        stw_phys(sm_state + offset, dt->selector);
1338 3b21e03e bellard
        stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff);
1339 3b21e03e bellard
        stl_phys(sm_state + offset + 4, dt->limit);
1340 3b21e03e bellard
        stq_phys(sm_state + offset + 8, dt->base);
1341 3b21e03e bellard
    }
1342 3b21e03e bellard
1343 3b21e03e bellard
    stq_phys(sm_state + 0x7e68, env->gdt.base);
1344 3b21e03e bellard
    stl_phys(sm_state + 0x7e64, env->gdt.limit);
1345 3b21e03e bellard
1346 3b21e03e bellard
    stw_phys(sm_state + 0x7e70, env->ldt.selector);
1347 3b21e03e bellard
    stq_phys(sm_state + 0x7e78, env->ldt.base);
1348 3b21e03e bellard
    stl_phys(sm_state + 0x7e74, env->ldt.limit);
1349 3b21e03e bellard
    stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
1350 3b46e624 ths
1351 3b21e03e bellard
    stq_phys(sm_state + 0x7e88, env->idt.base);
1352 3b21e03e bellard
    stl_phys(sm_state + 0x7e84, env->idt.limit);
1353 3b21e03e bellard
1354 3b21e03e bellard
    stw_phys(sm_state + 0x7e90, env->tr.selector);
1355 3b21e03e bellard
    stq_phys(sm_state + 0x7e98, env->tr.base);
1356 3b21e03e bellard
    stl_phys(sm_state + 0x7e94, env->tr.limit);
1357 3b21e03e bellard
    stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
1358 3b46e624 ths
1359 3b21e03e bellard
    stq_phys(sm_state + 0x7ed0, env->efer);
1360 3b21e03e bellard
1361 3b21e03e bellard
    stq_phys(sm_state + 0x7ff8, EAX);
1362 3b21e03e bellard
    stq_phys(sm_state + 0x7ff0, ECX);
1363 3b21e03e bellard
    stq_phys(sm_state + 0x7fe8, EDX);
1364 3b21e03e bellard
    stq_phys(sm_state + 0x7fe0, EBX);
1365 3b21e03e bellard
    stq_phys(sm_state + 0x7fd8, ESP);
1366 3b21e03e bellard
    stq_phys(sm_state + 0x7fd0, EBP);
1367 3b21e03e bellard
    stq_phys(sm_state + 0x7fc8, ESI);
1368 3b21e03e bellard
    stq_phys(sm_state + 0x7fc0, EDI);
1369 5fafdf24 ths
    for(i = 8; i < 16; i++)
1370 3b21e03e bellard
        stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
1371 3b21e03e bellard
    stq_phys(sm_state + 0x7f78, env->eip);
1372 3b21e03e bellard
    stl_phys(sm_state + 0x7f70, compute_eflags());
1373 3b21e03e bellard
    stl_phys(sm_state + 0x7f68, env->dr[6]);
1374 3b21e03e bellard
    stl_phys(sm_state + 0x7f60, env->dr[7]);
1375 3b21e03e bellard
1376 3b21e03e bellard
    stl_phys(sm_state + 0x7f48, env->cr[4]);
1377 3b21e03e bellard
    stl_phys(sm_state + 0x7f50, env->cr[3]);
1378 3b21e03e bellard
    stl_phys(sm_state + 0x7f58, env->cr[0]);
1379 3b21e03e bellard
1380 3b21e03e bellard
    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1381 3b21e03e bellard
    stl_phys(sm_state + 0x7f00, env->smbase);
1382 3b21e03e bellard
#else
1383 3b21e03e bellard
    stl_phys(sm_state + 0x7ffc, env->cr[0]);
1384 3b21e03e bellard
    stl_phys(sm_state + 0x7ff8, env->cr[3]);
1385 3b21e03e bellard
    stl_phys(sm_state + 0x7ff4, compute_eflags());
1386 3b21e03e bellard
    stl_phys(sm_state + 0x7ff0, env->eip);
1387 3b21e03e bellard
    stl_phys(sm_state + 0x7fec, EDI);
1388 3b21e03e bellard
    stl_phys(sm_state + 0x7fe8, ESI);
1389 3b21e03e bellard
    stl_phys(sm_state + 0x7fe4, EBP);
1390 3b21e03e bellard
    stl_phys(sm_state + 0x7fe0, ESP);
1391 3b21e03e bellard
    stl_phys(sm_state + 0x7fdc, EBX);
1392 3b21e03e bellard
    stl_phys(sm_state + 0x7fd8, EDX);
1393 3b21e03e bellard
    stl_phys(sm_state + 0x7fd4, ECX);
1394 3b21e03e bellard
    stl_phys(sm_state + 0x7fd0, EAX);
1395 3b21e03e bellard
    stl_phys(sm_state + 0x7fcc, env->dr[6]);
1396 3b21e03e bellard
    stl_phys(sm_state + 0x7fc8, env->dr[7]);
1397 3b46e624 ths
1398 3b21e03e bellard
    stl_phys(sm_state + 0x7fc4, env->tr.selector);
1399 3b21e03e bellard
    stl_phys(sm_state + 0x7f64, env->tr.base);
1400 3b21e03e bellard
    stl_phys(sm_state + 0x7f60, env->tr.limit);
1401 3b21e03e bellard
    stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
1402 3b46e624 ths
1403 3b21e03e bellard
    stl_phys(sm_state + 0x7fc0, env->ldt.selector);
1404 3b21e03e bellard
    stl_phys(sm_state + 0x7f80, env->ldt.base);
1405 3b21e03e bellard
    stl_phys(sm_state + 0x7f7c, env->ldt.limit);
1406 3b21e03e bellard
    stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
1407 3b46e624 ths
1408 3b21e03e bellard
    stl_phys(sm_state + 0x7f74, env->gdt.base);
1409 3b21e03e bellard
    stl_phys(sm_state + 0x7f70, env->gdt.limit);
1410 3b21e03e bellard
1411 3b21e03e bellard
    stl_phys(sm_state + 0x7f58, env->idt.base);
1412 3b21e03e bellard
    stl_phys(sm_state + 0x7f54, env->idt.limit);
1413 3b21e03e bellard
1414 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1415 3b21e03e bellard
        dt = &env->segs[i];
1416 3b21e03e bellard
        if (i < 3)
1417 3b21e03e bellard
            offset = 0x7f84 + i * 12;
1418 3b21e03e bellard
        else
1419 3b21e03e bellard
            offset = 0x7f2c + (i - 3) * 12;
1420 3b21e03e bellard
        stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector);
1421 3b21e03e bellard
        stl_phys(sm_state + offset + 8, dt->base);
1422 3b21e03e bellard
        stl_phys(sm_state + offset + 4, dt->limit);
1423 3b21e03e bellard
        stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff);
1424 3b21e03e bellard
    }
1425 3b21e03e bellard
    stl_phys(sm_state + 0x7f14, env->cr[4]);
1426 3b21e03e bellard
1427 3b21e03e bellard
    stl_phys(sm_state + 0x7efc, SMM_REVISION_ID);
1428 3b21e03e bellard
    stl_phys(sm_state + 0x7ef8, env->smbase);
1429 3b21e03e bellard
#endif
1430 3b21e03e bellard
    /* init SMM cpu state */
1431 3b21e03e bellard
1432 8988ae89 bellard
#ifdef TARGET_X86_64
1433 8988ae89 bellard
    env->efer = 0;
1434 8988ae89 bellard
    env->hflags &= ~HF_LMA_MASK;
1435 8988ae89 bellard
#endif
1436 3b21e03e bellard
    load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1437 3b21e03e bellard
    env->eip = 0x00008000;
1438 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase,
1439 3b21e03e bellard
                           0xffffffff, 0);
1440 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0);
1441 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0);
1442 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
1443 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
1444 3b21e03e bellard
    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
1445 3b46e624 ths
1446 5fafdf24 ths
    cpu_x86_update_cr0(env,
1447 3b21e03e bellard
                       env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
1448 3b21e03e bellard
    cpu_x86_update_cr4(env, 0);
1449 3b21e03e bellard
    env->dr[7] = 0x00000400;
1450 3b21e03e bellard
    CC_OP = CC_OP_EFLAGS;
1451 3b21e03e bellard
}
1452 3b21e03e bellard
1453 3b21e03e bellard
void helper_rsm(void)
1454 3b21e03e bellard
{
1455 3b21e03e bellard
    target_ulong sm_state;
1456 3b21e03e bellard
    int i, offset;
1457 3b21e03e bellard
    uint32_t val;
1458 3b21e03e bellard
1459 3b21e03e bellard
    sm_state = env->smbase + 0x8000;
1460 3b21e03e bellard
#ifdef TARGET_X86_64
1461 8988ae89 bellard
    env->efer = ldq_phys(sm_state + 0x7ed0);
1462 8988ae89 bellard
    if (env->efer & MSR_EFER_LMA)
1463 8988ae89 bellard
        env->hflags |= HF_LMA_MASK;
1464 8988ae89 bellard
    else
1465 8988ae89 bellard
        env->hflags &= ~HF_LMA_MASK;
1466 8988ae89 bellard
1467 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1468 3b21e03e bellard
        offset = 0x7e00 + i * 16;
1469 5fafdf24 ths
        cpu_x86_load_seg_cache(env, i,
1470 3b21e03e bellard
                               lduw_phys(sm_state + offset),
1471 3b21e03e bellard
                               ldq_phys(sm_state + offset + 8),
1472 3b21e03e bellard
                               ldl_phys(sm_state + offset + 4),
1473 3b21e03e bellard
                               (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8);
1474 3b21e03e bellard
    }
1475 3b21e03e bellard
1476 3b21e03e bellard
    env->gdt.base = ldq_phys(sm_state + 0x7e68);
1477 3b21e03e bellard
    env->gdt.limit = ldl_phys(sm_state + 0x7e64);
1478 3b21e03e bellard
1479 3b21e03e bellard
    env->ldt.selector = lduw_phys(sm_state + 0x7e70);
1480 3b21e03e bellard
    env->ldt.base = ldq_phys(sm_state + 0x7e78);
1481 3b21e03e bellard
    env->ldt.limit = ldl_phys(sm_state + 0x7e74);
1482 3b21e03e bellard
    env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
1483 3b46e624 ths
1484 3b21e03e bellard
    env->idt.base = ldq_phys(sm_state + 0x7e88);
1485 3b21e03e bellard
    env->idt.limit = ldl_phys(sm_state + 0x7e84);
1486 3b21e03e bellard
1487 3b21e03e bellard
    env->tr.selector = lduw_phys(sm_state + 0x7e90);
1488 3b21e03e bellard
    env->tr.base = ldq_phys(sm_state + 0x7e98);
1489 3b21e03e bellard
    env->tr.limit = ldl_phys(sm_state + 0x7e94);
1490 3b21e03e bellard
    env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
1491 3b46e624 ths
1492 3b21e03e bellard
    EAX = ldq_phys(sm_state + 0x7ff8);
1493 3b21e03e bellard
    ECX = ldq_phys(sm_state + 0x7ff0);
1494 3b21e03e bellard
    EDX = ldq_phys(sm_state + 0x7fe8);
1495 3b21e03e bellard
    EBX = ldq_phys(sm_state + 0x7fe0);
1496 3b21e03e bellard
    ESP = ldq_phys(sm_state + 0x7fd8);
1497 3b21e03e bellard
    EBP = ldq_phys(sm_state + 0x7fd0);
1498 3b21e03e bellard
    ESI = ldq_phys(sm_state + 0x7fc8);
1499 3b21e03e bellard
    EDI = ldq_phys(sm_state + 0x7fc0);
1500 5fafdf24 ths
    for(i = 8; i < 16; i++)
1501 3b21e03e bellard
        env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
1502 3b21e03e bellard
    env->eip = ldq_phys(sm_state + 0x7f78);
1503 5fafdf24 ths
    load_eflags(ldl_phys(sm_state + 0x7f70),
1504 3b21e03e bellard
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1505 3b21e03e bellard
    env->dr[6] = ldl_phys(sm_state + 0x7f68);
1506 3b21e03e bellard
    env->dr[7] = ldl_phys(sm_state + 0x7f60);
1507 3b21e03e bellard
1508 3b21e03e bellard
    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48));
1509 3b21e03e bellard
    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50));
1510 3b21e03e bellard
    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58));
1511 3b21e03e bellard
1512 3b21e03e bellard
    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1513 3b21e03e bellard
    if (val & 0x20000) {
1514 3b21e03e bellard
        env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff;
1515 3b21e03e bellard
    }
1516 3b21e03e bellard
#else
1517 3b21e03e bellard
    cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
1518 3b21e03e bellard
    cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
1519 5fafdf24 ths
    load_eflags(ldl_phys(sm_state + 0x7ff4),
1520 3b21e03e bellard
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
1521 3b21e03e bellard
    env->eip = ldl_phys(sm_state + 0x7ff0);
1522 3b21e03e bellard
    EDI = ldl_phys(sm_state + 0x7fec);
1523 3b21e03e bellard
    ESI = ldl_phys(sm_state + 0x7fe8);
1524 3b21e03e bellard
    EBP = ldl_phys(sm_state + 0x7fe4);
1525 3b21e03e bellard
    ESP = ldl_phys(sm_state + 0x7fe0);
1526 3b21e03e bellard
    EBX = ldl_phys(sm_state + 0x7fdc);
1527 3b21e03e bellard
    EDX = ldl_phys(sm_state + 0x7fd8);
1528 3b21e03e bellard
    ECX = ldl_phys(sm_state + 0x7fd4);
1529 3b21e03e bellard
    EAX = ldl_phys(sm_state + 0x7fd0);
1530 3b21e03e bellard
    env->dr[6] = ldl_phys(sm_state + 0x7fcc);
1531 3b21e03e bellard
    env->dr[7] = ldl_phys(sm_state + 0x7fc8);
1532 3b46e624 ths
1533 3b21e03e bellard
    env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
1534 3b21e03e bellard
    env->tr.base = ldl_phys(sm_state + 0x7f64);
1535 3b21e03e bellard
    env->tr.limit = ldl_phys(sm_state + 0x7f60);
1536 3b21e03e bellard
    env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
1537 3b46e624 ths
1538 3b21e03e bellard
    env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
1539 3b21e03e bellard
    env->ldt.base = ldl_phys(sm_state + 0x7f80);
1540 3b21e03e bellard
    env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
1541 3b21e03e bellard
    env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
1542 3b46e624 ths
1543 3b21e03e bellard
    env->gdt.base = ldl_phys(sm_state + 0x7f74);
1544 3b21e03e bellard
    env->gdt.limit = ldl_phys(sm_state + 0x7f70);
1545 3b21e03e bellard
1546 3b21e03e bellard
    env->idt.base = ldl_phys(sm_state + 0x7f58);
1547 3b21e03e bellard
    env->idt.limit = ldl_phys(sm_state + 0x7f54);
1548 3b21e03e bellard
1549 3b21e03e bellard
    for(i = 0; i < 6; i++) {
1550 3b21e03e bellard
        if (i < 3)
1551 3b21e03e bellard
            offset = 0x7f84 + i * 12;
1552 3b21e03e bellard
        else
1553 3b21e03e bellard
            offset = 0x7f2c + (i - 3) * 12;
1554 5fafdf24 ths
        cpu_x86_load_seg_cache(env, i,
1555 3b21e03e bellard
                               ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
1556 3b21e03e bellard
                               ldl_phys(sm_state + offset + 8),
1557 3b21e03e bellard
                               ldl_phys(sm_state + offset + 4),
1558 3b21e03e bellard
                               (ldl_phys(sm_state + offset) & 0xf0ff) << 8);
1559 3b21e03e bellard
    }
1560 3b21e03e bellard
    cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14));
1561 3b21e03e bellard
1562 3b21e03e bellard
    val = ldl_phys(sm_state + 0x7efc); /* revision ID */
1563 3b21e03e bellard
    if (val & 0x20000) {
1564 3b21e03e bellard
        env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff;
1565 3b21e03e bellard
    }
1566 3b21e03e bellard
#endif
1567 3b21e03e bellard
    CC_OP = CC_OP_EFLAGS;
1568 3b21e03e bellard
    env->hflags &= ~HF_SMM_MASK;
1569 3b21e03e bellard
    cpu_smm_update(env);
1570 3b21e03e bellard
1571 3b21e03e bellard
    if (loglevel & CPU_LOG_INT) {
1572 3b21e03e bellard
        fprintf(logfile, "SMM: after RSM\n");
1573 3b21e03e bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
1574 3b21e03e bellard
    }
1575 3b21e03e bellard
}
1576 3b21e03e bellard
1577 74ce674f bellard
#endif /* !CONFIG_USER_ONLY */
1578 74ce674f bellard
1579 74ce674f bellard
1580 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1581 2c0262af bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
1582 2c0262af bellard
   call it from another function */
1583 45bbbb46 bellard
uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
1584 2c0262af bellard
{
1585 2c0262af bellard
    *q_ptr = num / den;
1586 2c0262af bellard
    return num % den;
1587 2c0262af bellard
}
1588 2c0262af bellard
1589 45bbbb46 bellard
int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
1590 2c0262af bellard
{
1591 2c0262af bellard
    *q_ptr = num / den;
1592 2c0262af bellard
    return num % den;
1593 2c0262af bellard
}
1594 2c0262af bellard
#endif
1595 2c0262af bellard
1596 14ce26e7 bellard
void helper_divl_EAX_T0(void)
1597 2c0262af bellard
{
1598 45bbbb46 bellard
    unsigned int den, r;
1599 45bbbb46 bellard
    uint64_t num, q;
1600 3b46e624 ths
1601 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1602 2c0262af bellard
    den = T0;
1603 2c0262af bellard
    if (den == 0) {
1604 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1605 2c0262af bellard
    }
1606 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1607 14ce26e7 bellard
    r = div32(&q, num, den);
1608 2c0262af bellard
#else
1609 2c0262af bellard
    q = (num / den);
1610 2c0262af bellard
    r = (num % den);
1611 2c0262af bellard
#endif
1612 45bbbb46 bellard
    if (q > 0xffffffff)
1613 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1614 14ce26e7 bellard
    EAX = (uint32_t)q;
1615 14ce26e7 bellard
    EDX = (uint32_t)r;
1616 2c0262af bellard
}
1617 2c0262af bellard
1618 14ce26e7 bellard
void helper_idivl_EAX_T0(void)
1619 2c0262af bellard
{
1620 45bbbb46 bellard
    int den, r;
1621 45bbbb46 bellard
    int64_t num, q;
1622 3b46e624 ths
1623 31313213 bellard
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
1624 2c0262af bellard
    den = T0;
1625 2c0262af bellard
    if (den == 0) {
1626 2c0262af bellard
        raise_exception(EXCP00_DIVZ);
1627 2c0262af bellard
    }
1628 2c0262af bellard
#ifdef BUGGY_GCC_DIV64
1629 14ce26e7 bellard
    r = idiv32(&q, num, den);
1630 2c0262af bellard
#else
1631 2c0262af bellard
    q = (num / den);
1632 2c0262af bellard
    r = (num % den);
1633 2c0262af bellard
#endif
1634 45bbbb46 bellard
    if (q != (int32_t)q)
1635 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
1636 14ce26e7 bellard
    EAX = (uint32_t)q;
1637 14ce26e7 bellard
    EDX = (uint32_t)r;
1638 2c0262af bellard
}
1639 2c0262af bellard
1640 2c0262af bellard
void helper_cmpxchg8b(void)
1641 2c0262af bellard
{
1642 2c0262af bellard
    uint64_t d;
1643 2c0262af bellard
    int eflags;
1644 2c0262af bellard
1645 2c0262af bellard
    eflags = cc_table[CC_OP].compute_all();
1646 14ce26e7 bellard
    d = ldq(A0);
1647 2c0262af bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
1648 14ce26e7 bellard
        stq(A0, ((uint64_t)ECX << 32) | EBX);
1649 2c0262af bellard
        eflags |= CC_Z;
1650 2c0262af bellard
    } else {
1651 2c0262af bellard
        EDX = d >> 32;
1652 2c0262af bellard
        EAX = d;
1653 2c0262af bellard
        eflags &= ~CC_Z;
1654 2c0262af bellard
    }
1655 2c0262af bellard
    CC_SRC = eflags;
1656 2c0262af bellard
}
1657 2c0262af bellard
1658 88fe8a41 ths
void helper_single_step()
1659 88fe8a41 ths
{
1660 88fe8a41 ths
    env->dr[6] |= 0x4000;
1661 88fe8a41 ths
    raise_exception(EXCP01_SSTP);
1662 88fe8a41 ths
}
1663 88fe8a41 ths
1664 2c0262af bellard
void helper_cpuid(void)
1665 2c0262af bellard
{
1666 f419b321 bellard
    uint32_t index;
1667 f419b321 bellard
    index = (uint32_t)EAX;
1668 3b46e624 ths
1669 f419b321 bellard
    /* test if maximum index reached */
1670 f419b321 bellard
    if (index & 0x80000000) {
1671 5fafdf24 ths
        if (index > env->cpuid_xlevel)
1672 f419b321 bellard
            index = env->cpuid_level;
1673 f419b321 bellard
    } else {
1674 5fafdf24 ths
        if (index > env->cpuid_level)
1675 f419b321 bellard
            index = env->cpuid_level;
1676 f419b321 bellard
    }
1677 3b46e624 ths
1678 f419b321 bellard
    switch(index) {
1679 8e682019 bellard
    case 0:
1680 f419b321 bellard
        EAX = env->cpuid_level;
1681 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1682 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1683 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1684 8e682019 bellard
        break;
1685 8e682019 bellard
    case 1:
1686 14ce26e7 bellard
        EAX = env->cpuid_version;
1687 eae7629b ths
        EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
1688 9df217a3 bellard
        ECX = env->cpuid_ext_features;
1689 14ce26e7 bellard
        EDX = env->cpuid_features;
1690 8e682019 bellard
        break;
1691 f419b321 bellard
    case 2:
1692 8e682019 bellard
        /* cache info: needed for Pentium Pro compatibility */
1693 d8134d91 ths
        EAX = 1;
1694 2c0262af bellard
        EBX = 0;
1695 2c0262af bellard
        ECX = 0;
1696 d8134d91 ths
        EDX = 0x2c307d;
1697 8e682019 bellard
        break;
1698 14ce26e7 bellard
    case 0x80000000:
1699 f419b321 bellard
        EAX = env->cpuid_xlevel;
1700 14ce26e7 bellard
        EBX = env->cpuid_vendor1;
1701 14ce26e7 bellard
        EDX = env->cpuid_vendor2;
1702 14ce26e7 bellard
        ECX = env->cpuid_vendor3;
1703 14ce26e7 bellard
        break;
1704 14ce26e7 bellard
    case 0x80000001:
1705 14ce26e7 bellard
        EAX = env->cpuid_features;
1706 14ce26e7 bellard
        EBX = 0;
1707 0573fbfc ths
        ECX = env->cpuid_ext3_features;
1708 f419b321 bellard
        EDX = env->cpuid_ext2_features;
1709 f419b321 bellard
        break;
1710 f419b321 bellard
    case 0x80000002:
1711 f419b321 bellard
    case 0x80000003:
1712 f419b321 bellard
    case 0x80000004:
1713 f419b321 bellard
        EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
1714 f419b321 bellard
        EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
1715 f419b321 bellard
        ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
1716 f419b321 bellard
        EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
1717 14ce26e7 bellard
        break;
1718 8f091a59 bellard
    case 0x80000005:
1719 8f091a59 bellard
        /* cache info (L1 cache) */
1720 8f091a59 bellard
        EAX = 0x01ff01ff;
1721 8f091a59 bellard
        EBX = 0x01ff01ff;
1722 8f091a59 bellard
        ECX = 0x40020140;
1723 8f091a59 bellard
        EDX = 0x40020140;
1724 8f091a59 bellard
        break;
1725 8f091a59 bellard
    case 0x80000006:
1726 8f091a59 bellard
        /* cache info (L2 cache) */
1727 8f091a59 bellard
        EAX = 0;
1728 8f091a59 bellard
        EBX = 0x42004200;
1729 8f091a59 bellard
        ECX = 0x02008140;
1730 8f091a59 bellard
        EDX = 0;
1731 8f091a59 bellard
        break;
1732 14ce26e7 bellard
    case 0x80000008:
1733 14ce26e7 bellard
        /* virtual & phys address size in low 2 bytes. */
1734 14ce26e7 bellard
        EAX = 0x00003028;
1735 14ce26e7 bellard
        EBX = 0;
1736 14ce26e7 bellard
        ECX = 0;
1737 14ce26e7 bellard
        EDX = 0;
1738 14ce26e7 bellard
        break;
1739 f419b321 bellard
    default:
1740 f419b321 bellard
        /* reserved values: zero */
1741 f419b321 bellard
        EAX = 0;
1742 f419b321 bellard
        EBX = 0;
1743 f419b321 bellard
        ECX = 0;
1744 f419b321 bellard
        EDX = 0;
1745 f419b321 bellard
        break;
1746 2c0262af bellard
    }
1747 2c0262af bellard
}
1748 2c0262af bellard
1749 61a8c4ec bellard
void helper_enter_level(int level, int data32)
1750 61a8c4ec bellard
{
1751 14ce26e7 bellard
    target_ulong ssp;
1752 61a8c4ec bellard
    uint32_t esp_mask, esp, ebp;
1753 61a8c4ec bellard
1754 61a8c4ec bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
1755 61a8c4ec bellard
    ssp = env->segs[R_SS].base;
1756 61a8c4ec bellard
    ebp = EBP;
1757 61a8c4ec bellard
    esp = ESP;
1758 61a8c4ec bellard
    if (data32) {
1759 61a8c4ec bellard
        /* 32 bit */
1760 61a8c4ec bellard
        esp -= 4;
1761 61a8c4ec bellard
        while (--level) {
1762 61a8c4ec bellard
            esp -= 4;
1763 61a8c4ec bellard
            ebp -= 4;
1764 61a8c4ec bellard
            stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
1765 61a8c4ec bellard
        }
1766 61a8c4ec bellard
        esp -= 4;
1767 61a8c4ec bellard
        stl(ssp + (esp & esp_mask), T1);
1768 61a8c4ec bellard
    } else {
1769 61a8c4ec bellard
        /* 16 bit */
1770 61a8c4ec bellard
        esp -= 2;
1771 61a8c4ec bellard
        while (--level) {
1772 61a8c4ec bellard
            esp -= 2;
1773 61a8c4ec bellard
            ebp -= 2;
1774 61a8c4ec bellard
            stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
1775 61a8c4ec bellard
        }
1776 61a8c4ec bellard
        esp -= 2;
1777 61a8c4ec bellard
        stw(ssp + (esp & esp_mask), T1);
1778 61a8c4ec bellard
    }
1779 61a8c4ec bellard
}
1780 61a8c4ec bellard
1781 8f091a59 bellard
#ifdef TARGET_X86_64
1782 8f091a59 bellard
void helper_enter64_level(int level, int data64)
1783 8f091a59 bellard
{
1784 8f091a59 bellard
    target_ulong esp, ebp;
1785 8f091a59 bellard
    ebp = EBP;
1786 8f091a59 bellard
    esp = ESP;
1787 8f091a59 bellard
1788 8f091a59 bellard
    if (data64) {
1789 8f091a59 bellard
        /* 64 bit */
1790 8f091a59 bellard
        esp -= 8;
1791 8f091a59 bellard
        while (--level) {
1792 8f091a59 bellard
            esp -= 8;
1793 8f091a59 bellard
            ebp -= 8;
1794 8f091a59 bellard
            stq(esp, ldq(ebp));
1795 8f091a59 bellard
        }
1796 8f091a59 bellard
        esp -= 8;
1797 8f091a59 bellard
        stq(esp, T1);
1798 8f091a59 bellard
    } else {
1799 8f091a59 bellard
        /* 16 bit */
1800 8f091a59 bellard
        esp -= 2;
1801 8f091a59 bellard
        while (--level) {
1802 8f091a59 bellard
            esp -= 2;
1803 8f091a59 bellard
            ebp -= 2;
1804 8f091a59 bellard
            stw(esp, lduw(ebp));
1805 8f091a59 bellard
        }
1806 8f091a59 bellard
        esp -= 2;
1807 8f091a59 bellard
        stw(esp, T1);
1808 8f091a59 bellard
    }
1809 8f091a59 bellard
}
1810 8f091a59 bellard
#endif
1811 8f091a59 bellard
1812 2c0262af bellard
void helper_lldt_T0(void)
1813 2c0262af bellard
{
1814 2c0262af bellard
    int selector;
1815 2c0262af bellard
    SegmentCache *dt;
1816 2c0262af bellard
    uint32_t e1, e2;
1817 14ce26e7 bellard
    int index, entry_limit;
1818 14ce26e7 bellard
    target_ulong ptr;
1819 3b46e624 ths
1820 2c0262af bellard
    selector = T0 & 0xffff;
1821 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1822 2c0262af bellard
        /* XXX: NULL selector case: invalid LDT */
1823 14ce26e7 bellard
        env->ldt.base = 0;
1824 2c0262af bellard
        env->ldt.limit = 0;
1825 2c0262af bellard
    } else {
1826 2c0262af bellard
        if (selector & 0x4)
1827 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1828 2c0262af bellard
        dt = &env->gdt;
1829 2c0262af bellard
        index = selector & ~7;
1830 14ce26e7 bellard
#ifdef TARGET_X86_64
1831 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1832 14ce26e7 bellard
            entry_limit = 15;
1833 14ce26e7 bellard
        else
1834 3b46e624 ths
#endif
1835 14ce26e7 bellard
            entry_limit = 7;
1836 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1837 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1838 2c0262af bellard
        ptr = dt->base + index;
1839 61382a50 bellard
        e1 = ldl_kernel(ptr);
1840 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1841 2c0262af bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
1842 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1843 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1844 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1845 14ce26e7 bellard
#ifdef TARGET_X86_64
1846 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1847 14ce26e7 bellard
            uint32_t e3;
1848 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1849 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1850 14ce26e7 bellard
            env->ldt.base |= (target_ulong)e3 << 32;
1851 14ce26e7 bellard
        } else
1852 14ce26e7 bellard
#endif
1853 14ce26e7 bellard
        {
1854 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->ldt, e1, e2);
1855 14ce26e7 bellard
        }
1856 2c0262af bellard
    }
1857 2c0262af bellard
    env->ldt.selector = selector;
1858 2c0262af bellard
}
1859 2c0262af bellard
1860 2c0262af bellard
void helper_ltr_T0(void)
1861 2c0262af bellard
{
1862 2c0262af bellard
    int selector;
1863 2c0262af bellard
    SegmentCache *dt;
1864 2c0262af bellard
    uint32_t e1, e2;
1865 14ce26e7 bellard
    int index, type, entry_limit;
1866 14ce26e7 bellard
    target_ulong ptr;
1867 3b46e624 ths
1868 2c0262af bellard
    selector = T0 & 0xffff;
1869 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1870 14ce26e7 bellard
        /* NULL selector case: invalid TR */
1871 14ce26e7 bellard
        env->tr.base = 0;
1872 2c0262af bellard
        env->tr.limit = 0;
1873 2c0262af bellard
        env->tr.flags = 0;
1874 2c0262af bellard
    } else {
1875 2c0262af bellard
        if (selector & 0x4)
1876 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1877 2c0262af bellard
        dt = &env->gdt;
1878 2c0262af bellard
        index = selector & ~7;
1879 14ce26e7 bellard
#ifdef TARGET_X86_64
1880 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
1881 14ce26e7 bellard
            entry_limit = 15;
1882 14ce26e7 bellard
        else
1883 3b46e624 ths
#endif
1884 14ce26e7 bellard
            entry_limit = 7;
1885 14ce26e7 bellard
        if ((index + entry_limit) > dt->limit)
1886 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1887 2c0262af bellard
        ptr = dt->base + index;
1888 61382a50 bellard
        e1 = ldl_kernel(ptr);
1889 61382a50 bellard
        e2 = ldl_kernel(ptr + 4);
1890 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
1891 5fafdf24 ths
        if ((e2 & DESC_S_MASK) ||
1892 7e84c249 bellard
            (type != 1 && type != 9))
1893 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1894 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
1895 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1896 14ce26e7 bellard
#ifdef TARGET_X86_64
1897 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK) {
1898 b0ee3ff0 ths
            uint32_t e3, e4;
1899 14ce26e7 bellard
            e3 = ldl_kernel(ptr + 8);
1900 b0ee3ff0 ths
            e4 = ldl_kernel(ptr + 12);
1901 b0ee3ff0 ths
            if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
1902 b0ee3ff0 ths
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1903 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1904 14ce26e7 bellard
            env->tr.base |= (target_ulong)e3 << 32;
1905 5fafdf24 ths
        } else
1906 14ce26e7 bellard
#endif
1907 14ce26e7 bellard
        {
1908 14ce26e7 bellard
            load_seg_cache_raw_dt(&env->tr, e1, e2);
1909 14ce26e7 bellard
        }
1910 8e682019 bellard
        e2 |= DESC_TSS_BUSY_MASK;
1911 61382a50 bellard
        stl_kernel(ptr + 4, e2);
1912 2c0262af bellard
    }
1913 2c0262af bellard
    env->tr.selector = selector;
1914 2c0262af bellard
}
1915 2c0262af bellard
1916 3ab493de bellard
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
1917 8e682019 bellard
void load_seg(int seg_reg, int selector)
1918 2c0262af bellard
{
1919 2c0262af bellard
    uint32_t e1, e2;
1920 3ab493de bellard
    int cpl, dpl, rpl;
1921 3ab493de bellard
    SegmentCache *dt;
1922 3ab493de bellard
    int index;
1923 14ce26e7 bellard
    target_ulong ptr;
1924 3ab493de bellard
1925 8e682019 bellard
    selector &= 0xffff;
1926 b359d4e7 bellard
    cpl = env->hflags & HF_CPL_MASK;
1927 2c0262af bellard
    if ((selector & 0xfffc) == 0) {
1928 2c0262af bellard
        /* null selector case */
1929 4d6b6c0a bellard
        if (seg_reg == R_SS
1930 4d6b6c0a bellard
#ifdef TARGET_X86_64
1931 b359d4e7 bellard
            && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
1932 4d6b6c0a bellard
#endif
1933 4d6b6c0a bellard
            )
1934 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
1935 14ce26e7 bellard
        cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
1936 2c0262af bellard
    } else {
1937 3b46e624 ths
1938 3ab493de bellard
        if (selector & 0x4)
1939 3ab493de bellard
            dt = &env->ldt;
1940 3ab493de bellard
        else
1941 3ab493de bellard
            dt = &env->gdt;
1942 3ab493de bellard
        index = selector & ~7;
1943 8e682019 bellard
        if ((index + 7) > dt->limit)
1944 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1945 3ab493de bellard
        ptr = dt->base + index;
1946 3ab493de bellard
        e1 = ldl_kernel(ptr);
1947 3ab493de bellard
        e2 = ldl_kernel(ptr + 4);
1948 3b46e624 ths
1949 8e682019 bellard
        if (!(e2 & DESC_S_MASK))
1950 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1951 3ab493de bellard
        rpl = selector & 3;
1952 3ab493de bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1953 2c0262af bellard
        if (seg_reg == R_SS) {
1954 3ab493de bellard
            /* must be writable segment */
1955 8e682019 bellard
            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
1956 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1957 8e682019 bellard
            if (rpl != cpl || dpl != cpl)
1958 3ab493de bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1959 2c0262af bellard
        } else {
1960 3ab493de bellard
            /* must be readable segment */
1961 8e682019 bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
1962 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1963 3b46e624 ths
1964 3ab493de bellard
            if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
1965 3ab493de bellard
                /* if not conforming code, test rights */
1966 5fafdf24 ths
                if (dpl < cpl || dpl < rpl)
1967 3ab493de bellard
                    raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1968 3ab493de bellard
            }
1969 2c0262af bellard
        }
1970 2c0262af bellard
1971 2c0262af bellard
        if (!(e2 & DESC_P_MASK)) {
1972 2c0262af bellard
            if (seg_reg == R_SS)
1973 2c0262af bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1974 2c0262af bellard
            else
1975 2c0262af bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1976 2c0262af bellard
        }
1977 3ab493de bellard
1978 3ab493de bellard
        /* set the access bit if not already set */
1979 3ab493de bellard
        if (!(e2 & DESC_A_MASK)) {
1980 3ab493de bellard
            e2 |= DESC_A_MASK;
1981 3ab493de bellard
            stl_kernel(ptr + 4, e2);
1982 3ab493de bellard
        }
1983 3ab493de bellard
1984 5fafdf24 ths
        cpu_x86_load_seg_cache(env, seg_reg, selector,
1985 2c0262af bellard
                       get_seg_base(e1, e2),
1986 2c0262af bellard
                       get_seg_limit(e1, e2),
1987 2c0262af bellard
                       e2);
1988 2c0262af bellard
#if 0
1989 5fafdf24 ths
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
1990 2c0262af bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
1991 2c0262af bellard
#endif
1992 2c0262af bellard
    }
1993 2c0262af bellard
}
1994 2c0262af bellard
1995 2c0262af bellard
/* protected mode jump */
1996 f419b321 bellard
void helper_ljmp_protected_T0_T1(int next_eip_addend)
1997 2c0262af bellard
{
1998 14ce26e7 bellard
    int new_cs, gate_cs, type;
1999 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, limit;
2000 f419b321 bellard
    target_ulong new_eip, next_eip;
2001 3b46e624 ths
2002 2c0262af bellard
    new_cs = T0;
2003 2c0262af bellard
    new_eip = T1;
2004 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2005 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
2006 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2007 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2008 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2009 2c0262af bellard
    if (e2 & DESC_S_MASK) {
2010 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
2011 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2012 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2013 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
2014 2c0262af bellard
            /* conforming code segment */
2015 2c0262af bellard
            if (dpl > cpl)
2016 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2017 2c0262af bellard
        } else {
2018 2c0262af bellard
            /* non conforming code segment */
2019 2c0262af bellard
            rpl = new_cs & 3;
2020 2c0262af bellard
            if (rpl > cpl)
2021 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2022 2c0262af bellard
            if (dpl != cpl)
2023 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2024 2c0262af bellard
        }
2025 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2026 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2027 2c0262af bellard
        limit = get_seg_limit(e1, e2);
2028 5fafdf24 ths
        if (new_eip > limit &&
2029 ca954f6d bellard
            !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
2030 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2031 2c0262af bellard
        cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2032 2c0262af bellard
                       get_seg_base(e1, e2), limit, e2);
2033 2c0262af bellard
        EIP = new_eip;
2034 2c0262af bellard
    } else {
2035 7e84c249 bellard
        /* jump to call or task gate */
2036 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2037 7e84c249 bellard
        rpl = new_cs & 3;
2038 7e84c249 bellard
        cpl = env->hflags & HF_CPL_MASK;
2039 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2040 7e84c249 bellard
        switch(type) {
2041 7e84c249 bellard
        case 1: /* 286 TSS */
2042 7e84c249 bellard
        case 9: /* 386 TSS */
2043 7e84c249 bellard
        case 5: /* task gate */
2044 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
2045 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2046 f419b321 bellard
            next_eip = env->eip + next_eip_addend;
2047 08cea4ee bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
2048 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
2049 7e84c249 bellard
            break;
2050 7e84c249 bellard
        case 4: /* 286 call gate */
2051 7e84c249 bellard
        case 12: /* 386 call gate */
2052 7e84c249 bellard
            if ((dpl < cpl) || (dpl < rpl))
2053 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2054 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
2055 7e84c249 bellard
                raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2056 7e84c249 bellard
            gate_cs = e1 >> 16;
2057 516633dc bellard
            new_eip = (e1 & 0xffff);
2058 516633dc bellard
            if (type == 12)
2059 516633dc bellard
                new_eip |= (e2 & 0xffff0000);
2060 7e84c249 bellard
            if (load_segment(&e1, &e2, gate_cs) != 0)
2061 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2062 7e84c249 bellard
            dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2063 7e84c249 bellard
            /* must be code segment */
2064 5fafdf24 ths
            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
2065 7e84c249 bellard
                 (DESC_S_MASK | DESC_CS_MASK)))
2066 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2067 5fafdf24 ths
            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
2068 7e84c249 bellard
                (!(e2 & DESC_C_MASK) && (dpl != cpl)))
2069 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2070 7e84c249 bellard
            if (!(e2 & DESC_P_MASK))
2071 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
2072 7e84c249 bellard
            limit = get_seg_limit(e1, e2);
2073 7e84c249 bellard
            if (new_eip > limit)
2074 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, 0);
2075 7e84c249 bellard
            cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
2076 7e84c249 bellard
                                   get_seg_base(e1, e2), limit, e2);
2077 7e84c249 bellard
            EIP = new_eip;
2078 7e84c249 bellard
            break;
2079 7e84c249 bellard
        default:
2080 7e84c249 bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2081 7e84c249 bellard
            break;
2082 7e84c249 bellard
        }
2083 2c0262af bellard
    }
2084 2c0262af bellard
}
2085 2c0262af bellard
2086 2c0262af bellard
/* real mode call */
2087 2c0262af bellard
void helper_lcall_real_T0_T1(int shift, int next_eip)
2088 2c0262af bellard
{
2089 2c0262af bellard
    int new_cs, new_eip;
2090 2c0262af bellard
    uint32_t esp, esp_mask;
2091 14ce26e7 bellard
    target_ulong ssp;
2092 2c0262af bellard
2093 2c0262af bellard
    new_cs = T0;
2094 2c0262af bellard
    new_eip = T1;
2095 2c0262af bellard
    esp = ESP;
2096 891b38e4 bellard
    esp_mask = get_sp_mask(env->segs[R_SS].flags);
2097 2c0262af bellard
    ssp = env->segs[R_SS].base;
2098 2c0262af bellard
    if (shift) {
2099 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
2100 891b38e4 bellard
        PUSHL(ssp, esp, esp_mask, next_eip);
2101 2c0262af bellard
    } else {
2102 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
2103 891b38e4 bellard
        PUSHW(ssp, esp, esp_mask, next_eip);
2104 2c0262af bellard
    }
2105 2c0262af bellard
2106 8d7b0fbb bellard
    SET_ESP(esp, esp_mask);
2107 2c0262af bellard
    env->eip = new_eip;
2108 2c0262af bellard
    env->segs[R_CS].selector = new_cs;
2109 14ce26e7 bellard
    env->segs[R_CS].base = (new_cs << 4);
2110 2c0262af bellard
}
2111 2c0262af bellard
2112 2c0262af bellard
/* protected mode call */
2113 f419b321 bellard
void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
2114 2c0262af bellard
{
2115 649ea05a bellard
    int new_cs, new_stack, i;
2116 2c0262af bellard
    uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
2117 891b38e4 bellard
    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
2118 891b38e4 bellard
    uint32_t val, limit, old_sp_mask;
2119 649ea05a bellard
    target_ulong ssp, old_ssp, next_eip, new_eip;
2120 3b46e624 ths
2121 2c0262af bellard
    new_cs = T0;
2122 2c0262af bellard
    new_eip = T1;
2123 f419b321 bellard
    next_eip = env->eip + next_eip_addend;
2124 f3f2d9be bellard
#ifdef DEBUG_PCALL
2125 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2126 e19e89a5 bellard
        fprintf(logfile, "lcall %04x:%08x s=%d\n",
2127 649ea05a bellard
                new_cs, (uint32_t)new_eip, shift);
2128 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2129 f3f2d9be bellard
    }
2130 f3f2d9be bellard
#endif
2131 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2132 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, 0);
2133 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2134 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2135 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2136 f3f2d9be bellard
#ifdef DEBUG_PCALL
2137 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2138 f3f2d9be bellard
        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
2139 f3f2d9be bellard
    }
2140 f3f2d9be bellard
#endif
2141 2c0262af bellard
    if (e2 & DESC_S_MASK) {
2142 2c0262af bellard
        if (!(e2 & DESC_CS_MASK))
2143 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2144 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2145 7e84c249 bellard
        if (e2 & DESC_C_MASK) {
2146 2c0262af bellard
            /* conforming code segment */
2147 2c0262af bellard
            if (dpl > cpl)
2148 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2149 2c0262af bellard
        } else {
2150 2c0262af bellard
            /* non conforming code segment */
2151 2c0262af bellard
            rpl = new_cs & 3;
2152 2c0262af bellard
            if (rpl > cpl)
2153 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2154 2c0262af bellard
            if (dpl != cpl)
2155 2c0262af bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2156 2c0262af bellard
        }
2157 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2158 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2159 2c0262af bellard
2160 f419b321 bellard
#ifdef TARGET_X86_64
2161 f419b321 bellard
        /* XXX: check 16/32 bit cases in long mode */
2162 f419b321 bellard
        if (shift == 2) {
2163 f419b321 bellard
            target_ulong rsp;
2164 f419b321 bellard
            /* 64 bit case */
2165 f419b321 bellard
            rsp = ESP;
2166 f419b321 bellard
            PUSHQ(rsp, env->segs[R_CS].selector);
2167 f419b321 bellard
            PUSHQ(rsp, next_eip);
2168 f419b321 bellard
            /* from this point, not restartable */
2169 f419b321 bellard
            ESP = rsp;
2170 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2171 5fafdf24 ths
                                   get_seg_base(e1, e2),
2172 f419b321 bellard
                                   get_seg_limit(e1, e2), e2);
2173 f419b321 bellard
            EIP = new_eip;
2174 5fafdf24 ths
        } else
2175 f419b321 bellard
#endif
2176 f419b321 bellard
        {
2177 f419b321 bellard
            sp = ESP;
2178 f419b321 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
2179 f419b321 bellard
            ssp = env->segs[R_SS].base;
2180 f419b321 bellard
            if (shift) {
2181 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2182 f419b321 bellard
                PUSHL(ssp, sp, sp_mask, next_eip);
2183 f419b321 bellard
            } else {
2184 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2185 f419b321 bellard
                PUSHW(ssp, sp, sp_mask, next_eip);
2186 f419b321 bellard
            }
2187 3b46e624 ths
2188 f419b321 bellard
            limit = get_seg_limit(e1, e2);
2189 f419b321 bellard
            if (new_eip > limit)
2190 f419b321 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2191 f419b321 bellard
            /* from this point, not restartable */
2192 8d7b0fbb bellard
            SET_ESP(sp, sp_mask);
2193 f419b321 bellard
            cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2194 f419b321 bellard
                                   get_seg_base(e1, e2), limit, e2);
2195 f419b321 bellard
            EIP = new_eip;
2196 2c0262af bellard
        }
2197 2c0262af bellard
    } else {
2198 2c0262af bellard
        /* check gate type */
2199 2c0262af bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
2200 7e84c249 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2201 7e84c249 bellard
        rpl = new_cs & 3;
2202 2c0262af bellard
        switch(type) {
2203 2c0262af bellard
        case 1: /* available 286 TSS */
2204 2c0262af bellard
        case 9: /* available 386 TSS */
2205 2c0262af bellard
        case 5: /* task gate */
2206 7e84c249 bellard
            if (dpl < cpl || dpl < rpl)
2207 7e84c249 bellard
                raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2208 883da8e2 bellard
            switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
2209 447c2cef bellard
            CC_OP = CC_OP_EFLAGS;
2210 8145122b bellard
            return;
2211 2c0262af bellard
        case 4: /* 286 call gate */
2212 2c0262af bellard
        case 12: /* 386 call gate */
2213 2c0262af bellard
            break;
2214 2c0262af bellard
        default:
2215 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2216 2c0262af bellard
            break;
2217 2c0262af bellard
        }
2218 2c0262af bellard
        shift = type >> 3;
2219 2c0262af bellard
2220 2c0262af bellard
        if (dpl < cpl || dpl < rpl)
2221 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2222 2c0262af bellard
        /* check valid bit */
2223 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2224 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
2225 2c0262af bellard
        selector = e1 >> 16;
2226 2c0262af bellard
        offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
2227 f3f2d9be bellard
        param_count = e2 & 0x1f;
2228 2c0262af bellard
        if ((selector & 0xfffc) == 0)
2229 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, 0);
2230 2c0262af bellard
2231 2c0262af bellard
        if (load_segment(&e1, &e2, selector) != 0)
2232 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2233 2c0262af bellard
        if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
2234 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2235 2c0262af bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2236 2c0262af bellard
        if (dpl > cpl)
2237 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
2238 2c0262af bellard
        if (!(e2 & DESC_P_MASK))
2239 2c0262af bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
2240 2c0262af bellard
2241 2c0262af bellard
        if (!(e2 & DESC_C_MASK) && dpl < cpl) {
2242 7f75ffd3 blueswir1
            /* to inner privilege */
2243 2c0262af bellard
            get_ss_esp_from_tss(&ss, &sp, dpl);
2244 f3f2d9be bellard
#ifdef DEBUG_PCALL
2245 e19e89a5 bellard
            if (loglevel & CPU_LOG_PCALL)
2246 5fafdf24 ths
                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
2247 f3f2d9be bellard
                        ss, sp, param_count, ESP);
2248 f3f2d9be bellard
#endif
2249 2c0262af bellard
            if ((ss & 0xfffc) == 0)
2250 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2251 2c0262af bellard
            if ((ss & 3) != dpl)
2252 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2253 2c0262af bellard
            if (load_segment(&ss_e1, &ss_e2, ss) != 0)
2254 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2255 2c0262af bellard
            ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2256 2c0262af bellard
            if (ss_dpl != dpl)
2257 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2258 2c0262af bellard
            if (!(ss_e2 & DESC_S_MASK) ||
2259 2c0262af bellard
                (ss_e2 & DESC_CS_MASK) ||
2260 2c0262af bellard
                !(ss_e2 & DESC_W_MASK))
2261 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2262 2c0262af bellard
            if (!(ss_e2 & DESC_P_MASK))
2263 2c0262af bellard
                raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
2264 3b46e624 ths
2265 891b38e4 bellard
            //            push_size = ((param_count * 2) + 8) << shift;
2266 2c0262af bellard
2267 891b38e4 bellard
            old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
2268 891b38e4 bellard
            old_ssp = env->segs[R_SS].base;
2269 3b46e624 ths
2270 891b38e4 bellard
            sp_mask = get_sp_mask(ss_e2);
2271 891b38e4 bellard
            ssp = get_seg_base(ss_e1, ss_e2);
2272 2c0262af bellard
            if (shift) {
2273 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
2274 891b38e4 bellard
                PUSHL(ssp, sp, sp_mask, ESP);
2275 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
2276 891b38e4 bellard
                    val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
2277 891b38e4 bellard
                    PUSHL(ssp, sp, sp_mask, val);
2278 2c0262af bellard
                }
2279 2c0262af bellard
            } else {
2280 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
2281 891b38e4 bellard
                PUSHW(ssp, sp, sp_mask, ESP);
2282 891b38e4 bellard
                for(i = param_count - 1; i >= 0; i--) {
2283 891b38e4 bellard
                    val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
2284 891b38e4 bellard
                    PUSHW(ssp, sp, sp_mask, val);
2285 2c0262af bellard
                }
2286 2c0262af bellard
            }
2287 891b38e4 bellard
            new_stack = 1;
2288 2c0262af bellard
        } else {
2289 7f75ffd3 blueswir1
            /* to same privilege */
2290 891b38e4 bellard
            sp = ESP;
2291 891b38e4 bellard
            sp_mask = get_sp_mask(env->segs[R_SS].flags);
2292 891b38e4 bellard
            ssp = env->segs[R_SS].base;
2293 891b38e4 bellard
            //            push_size = (4 << shift);
2294 891b38e4 bellard
            new_stack = 0;
2295 2c0262af bellard
        }
2296 2c0262af bellard
2297 2c0262af bellard
        if (shift) {
2298 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
2299 891b38e4 bellard
            PUSHL(ssp, sp, sp_mask, next_eip);
2300 2c0262af bellard
        } else {
2301 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
2302 891b38e4 bellard
            PUSHW(ssp, sp, sp_mask, next_eip);
2303 891b38e4 bellard
        }
2304 891b38e4 bellard
2305 891b38e4 bellard
        /* from this point, not restartable */
2306 891b38e4 bellard
2307 891b38e4 bellard
        if (new_stack) {
2308 891b38e4 bellard
            ss = (ss & ~3) | dpl;
2309 5fafdf24 ths
            cpu_x86_load_seg_cache(env, R_SS, ss,
2310 891b38e4 bellard
                                   ssp,
2311 891b38e4 bellard
                                   get_seg_limit(ss_e1, ss_e2),
2312 891b38e4 bellard
                                   ss_e2);
2313 2c0262af bellard
        }
2314 2c0262af bellard
2315 2c0262af bellard
        selector = (selector & ~3) | dpl;
2316 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, selector,
2317 2c0262af bellard
                       get_seg_base(e1, e2),
2318 2c0262af bellard
                       get_seg_limit(e1, e2),
2319 2c0262af bellard
                       e2);
2320 2c0262af bellard
        cpu_x86_set_cpl(env, dpl);
2321 8d7b0fbb bellard
        SET_ESP(sp, sp_mask);
2322 2c0262af bellard
        EIP = offset;
2323 2c0262af bellard
    }
2324 9df217a3 bellard
#ifdef USE_KQEMU
2325 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2326 9df217a3 bellard
        env->exception_index = -1;
2327 9df217a3 bellard
        cpu_loop_exit();
2328 9df217a3 bellard
    }
2329 9df217a3 bellard
#endif
2330 2c0262af bellard
}
2331 2c0262af bellard
2332 7e84c249 bellard
/* real and vm86 mode iret */
2333 2c0262af bellard
void helper_iret_real(int shift)
2334 2c0262af bellard
{
2335 891b38e4 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
2336 14ce26e7 bellard
    target_ulong ssp;
2337 2c0262af bellard
    int eflags_mask;
2338 7e84c249 bellard
2339 891b38e4 bellard
    sp_mask = 0xffff; /* XXXX: use SS segment size ? */
2340 891b38e4 bellard
    sp = ESP;
2341 891b38e4 bellard
    ssp = env->segs[R_SS].base;
2342 2c0262af bellard
    if (shift == 1) {
2343 2c0262af bellard
        /* 32 bits */
2344 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
2345 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
2346 891b38e4 bellard
        new_cs &= 0xffff;
2347 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eflags);
2348 2c0262af bellard
    } else {
2349 2c0262af bellard
        /* 16 bits */
2350 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
2351 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
2352 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eflags);
2353 2c0262af bellard
    }
2354 4136f33c bellard
    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
2355 2c0262af bellard
    load_seg_vm(R_CS, new_cs);
2356 2c0262af bellard
    env->eip = new_eip;
2357 7e84c249 bellard
    if (env->eflags & VM_MASK)
2358 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
2359 7e84c249 bellard
    else
2360 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
2361 2c0262af bellard
    if (shift == 0)
2362 2c0262af bellard
        eflags_mask &= 0xffff;
2363 2c0262af bellard
    load_eflags(new_eflags, eflags_mask);
2364 2c0262af bellard
}
2365 2c0262af bellard
2366 8e682019 bellard
static inline void validate_seg(int seg_reg, int cpl)
2367 8e682019 bellard
{
2368 8e682019 bellard
    int dpl;
2369 8e682019 bellard
    uint32_t e2;
2370 cd072e01 bellard
2371 cd072e01 bellard
    /* XXX: on x86_64, we do not want to nullify FS and GS because
2372 cd072e01 bellard
       they may still contain a valid base. I would be interested to
2373 cd072e01 bellard
       know how a real x86_64 CPU behaves */
2374 5fafdf24 ths
    if ((seg_reg == R_FS || seg_reg == R_GS) &&
2375 cd072e01 bellard
        (env->segs[seg_reg].selector & 0xfffc) == 0)
2376 cd072e01 bellard
        return;
2377 cd072e01 bellard
2378 8e682019 bellard
    e2 = env->segs[seg_reg].flags;
2379 8e682019 bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2380 8e682019 bellard
    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
2381 8e682019 bellard
        /* data or non conforming code segment */
2382 8e682019 bellard
        if (dpl < cpl) {
2383 14ce26e7 bellard
            cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
2384 8e682019 bellard
        }
2385 8e682019 bellard
    }
2386 8e682019 bellard
}
2387 8e682019 bellard
2388 2c0262af bellard
/* protected mode iret */
2389 2c0262af bellard
static inline void helper_ret_protected(int shift, int is_iret, int addend)
2390 2c0262af bellard
{
2391 14ce26e7 bellard
    uint32_t new_cs, new_eflags, new_ss;
2392 2c0262af bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
2393 2c0262af bellard
    uint32_t e1, e2, ss_e1, ss_e2;
2394 4136f33c bellard
    int cpl, dpl, rpl, eflags_mask, iopl;
2395 14ce26e7 bellard
    target_ulong ssp, sp, new_eip, new_esp, sp_mask;
2396 3b46e624 ths
2397 14ce26e7 bellard
#ifdef TARGET_X86_64
2398 14ce26e7 bellard
    if (shift == 2)
2399 14ce26e7 bellard
        sp_mask = -1;
2400 14ce26e7 bellard
    else
2401 14ce26e7 bellard
#endif
2402 14ce26e7 bellard
        sp_mask = get_sp_mask(env->segs[R_SS].flags);
2403 2c0262af bellard
    sp = ESP;
2404 891b38e4 bellard
    ssp = env->segs[R_SS].base;
2405 354ff226 bellard
    new_eflags = 0; /* avoid warning */
2406 14ce26e7 bellard
#ifdef TARGET_X86_64
2407 14ce26e7 bellard
    if (shift == 2) {
2408 14ce26e7 bellard
        POPQ(sp, new_eip);
2409 14ce26e7 bellard
        POPQ(sp, new_cs);
2410 14ce26e7 bellard
        new_cs &= 0xffff;
2411 14ce26e7 bellard
        if (is_iret) {
2412 14ce26e7 bellard
            POPQ(sp, new_eflags);
2413 14ce26e7 bellard
        }
2414 14ce26e7 bellard
    } else
2415 14ce26e7 bellard
#endif
2416 2c0262af bellard
    if (shift == 1) {
2417 2c0262af bellard
        /* 32 bits */
2418 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_eip);
2419 891b38e4 bellard
        POPL(ssp, sp, sp_mask, new_cs);
2420 891b38e4 bellard
        new_cs &= 0xffff;
2421 891b38e4 bellard
        if (is_iret) {
2422 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_eflags);
2423 891b38e4 bellard
            if (new_eflags & VM_MASK)
2424 891b38e4 bellard
                goto return_to_vm86;
2425 891b38e4 bellard
        }
2426 2c0262af bellard
    } else {
2427 2c0262af bellard
        /* 16 bits */
2428 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_eip);
2429 891b38e4 bellard
        POPW(ssp, sp, sp_mask, new_cs);
2430 2c0262af bellard
        if (is_iret)
2431 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_eflags);
2432 2c0262af bellard
    }
2433 891b38e4 bellard
#ifdef DEBUG_PCALL
2434 e19e89a5 bellard
    if (loglevel & CPU_LOG_PCALL) {
2435 14ce26e7 bellard
        fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
2436 e19e89a5 bellard
                new_cs, new_eip, shift, addend);
2437 7fe48483 bellard
        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
2438 891b38e4 bellard
    }
2439 891b38e4 bellard
#endif
2440 2c0262af bellard
    if ((new_cs & 0xfffc) == 0)
2441 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2442 2c0262af bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
2443 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2444 2c0262af bellard
    if (!(e2 & DESC_S_MASK) ||
2445 2c0262af bellard
        !(e2 & DESC_CS_MASK))
2446 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2447 2c0262af bellard
    cpl = env->hflags & HF_CPL_MASK;
2448 5fafdf24 ths
    rpl = new_cs & 3;
2449 2c0262af bellard
    if (rpl < cpl)
2450 2c0262af bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2451 2c0262af bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2452 7e84c249 bellard
    if (e2 & DESC_C_MASK) {
2453 2c0262af bellard
        if (dpl > rpl)
2454 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2455 2c0262af bellard
    } else {
2456 2c0262af bellard
        if (dpl != rpl)
2457 2c0262af bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2458 2c0262af bellard
    }
2459 2c0262af bellard
    if (!(e2 & DESC_P_MASK))
2460 2c0262af bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
2461 3b46e624 ths
2462 891b38e4 bellard
    sp += addend;
2463 5fafdf24 ths
    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
2464 ca954f6d bellard
                       ((env->hflags & HF_CS64_MASK) && !is_iret))) {
2465 2c0262af bellard
        /* return to same priledge level */
2466 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, new_cs,
2467 2c0262af bellard
                       get_seg_base(e1, e2),
2468 2c0262af bellard
                       get_seg_limit(e1, e2),
2469 2c0262af bellard
                       e2);
2470 2c0262af bellard
    } else {
2471 7f75ffd3 blueswir1
        /* return to different privilege level */
2472 14ce26e7 bellard
#ifdef TARGET_X86_64
2473 14ce26e7 bellard
        if (shift == 2) {
2474 14ce26e7 bellard
            POPQ(sp, new_esp);
2475 14ce26e7 bellard
            POPQ(sp, new_ss);
2476 14ce26e7 bellard
            new_ss &= 0xffff;
2477 14ce26e7 bellard
        } else
2478 14ce26e7 bellard
#endif
2479 2c0262af bellard
        if (shift == 1) {
2480 2c0262af bellard
            /* 32 bits */
2481 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_esp);
2482 891b38e4 bellard
            POPL(ssp, sp, sp_mask, new_ss);
2483 891b38e4 bellard
            new_ss &= 0xffff;
2484 2c0262af bellard
        } else {
2485 2c0262af bellard
            /* 16 bits */
2486 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_esp);
2487 891b38e4 bellard
            POPW(ssp, sp, sp_mask, new_ss);
2488 2c0262af bellard
        }
2489 e19e89a5 bellard
#ifdef DEBUG_PCALL
2490 e19e89a5 bellard
        if (loglevel & CPU_LOG_PCALL) {
2491 14ce26e7 bellard
            fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
2492 e19e89a5 bellard
                    new_ss, new_esp);
2493 e19e89a5 bellard
        }
2494 e19e89a5 bellard
#endif
2495 b359d4e7 bellard
        if ((new_ss & 0xfffc) == 0) {
2496 b359d4e7 bellard
#ifdef TARGET_X86_64
2497 b359d4e7 bellard
            /* NULL ss is allowed in long mode if cpl != 3*/
2498 d80c7d1c bellard
            /* XXX: test CS64 ? */
2499 b359d4e7 bellard
            if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
2500 5fafdf24 ths
                cpu_x86_load_seg_cache(env, R_SS, new_ss,
2501 b359d4e7 bellard
                                       0, 0xffffffff,
2502 b359d4e7 bellard
                                       DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2503 b359d4e7 bellard
                                       DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
2504 b359d4e7 bellard
                                       DESC_W_MASK | DESC_A_MASK);
2505 d80c7d1c bellard
                ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
2506 5fafdf24 ths
            } else
2507 b359d4e7 bellard
#endif
2508 b359d4e7 bellard
            {
2509 b359d4e7 bellard
                raise_exception_err(EXCP0D_GPF, 0);
2510 b359d4e7 bellard
            }
2511 14ce26e7 bellard
        } else {
2512 14ce26e7 bellard
            if ((new_ss & 3) != rpl)
2513 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2514 14ce26e7 bellard
            if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
2515 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2516 14ce26e7 bellard
            if (!(ss_e2 & DESC_S_MASK) ||
2517 14ce26e7 bellard
                (ss_e2 & DESC_CS_MASK) ||
2518 14ce26e7 bellard
                !(ss_e2 & DESC_W_MASK))
2519 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2520 14ce26e7 bellard
            dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
2521 14ce26e7 bellard
            if (dpl != rpl)
2522 14ce26e7 bellard
                raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
2523 14ce26e7 bellard
            if (!(ss_e2 & DESC_P_MASK))
2524 14ce26e7 bellard
                raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
2525 5fafdf24 ths
            cpu_x86_load_seg_cache(env, R_SS, new_ss,
2526 14ce26e7 bellard
                                   get_seg_base(ss_e1, ss_e2),
2527 14ce26e7 bellard
                                   get_seg_limit(ss_e1, ss_e2),
2528 14ce26e7 bellard
                                   ss_e2);
2529 14ce26e7 bellard
        }
2530 2c0262af bellard
2531 5fafdf24 ths
        cpu_x86_load_seg_cache(env, R_CS, new_cs,
2532 2c0262af bellard
                       get_seg_base(e1, e2),
2533 2c0262af bellard
                       get_seg_limit(e1, e2),
2534 2c0262af bellard
                       e2);
2535 2c0262af bellard
        cpu_x86_set_cpl(env, rpl);
2536 891b38e4 bellard
        sp = new_esp;
2537 14ce26e7 bellard
#ifdef TARGET_X86_64
2538 2c8e0301 bellard
        if (env->hflags & HF_CS64_MASK)
2539 14ce26e7 bellard
            sp_mask = -1;
2540 14ce26e7 bellard
        else
2541 14ce26e7 bellard
#endif
2542 14ce26e7 bellard
            sp_mask = get_sp_mask(ss_e2);
2543 8e682019 bellard
2544 8e682019 bellard
        /* validate data segments */
2545 89984cd2 bellard
        validate_seg(R_ES, rpl);
2546 89984cd2 bellard
        validate_seg(R_DS, rpl);
2547 89984cd2 bellard
        validate_seg(R_FS, rpl);
2548 89984cd2 bellard
        validate_seg(R_GS, rpl);
2549 4afa6482 bellard
2550 4afa6482 bellard
        sp += addend;
2551 2c0262af bellard
    }
2552 8d7b0fbb bellard
    SET_ESP(sp, sp_mask);
2553 2c0262af bellard
    env->eip = new_eip;
2554 2c0262af bellard
    if (is_iret) {
2555 4136f33c bellard
        /* NOTE: 'cpl' is the _old_ CPL */
2556 8145122b bellard
        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
2557 2c0262af bellard
        if (cpl == 0)
2558 4136f33c bellard
            eflags_mask |= IOPL_MASK;
2559 4136f33c bellard
        iopl = (env->eflags >> IOPL_SHIFT) & 3;
2560 4136f33c bellard
        if (cpl <= iopl)
2561 4136f33c bellard
            eflags_mask |= IF_MASK;
2562 2c0262af bellard
        if (shift == 0)
2563 2c0262af bellard
            eflags_mask &= 0xffff;
2564 2c0262af bellard
        load_eflags(new_eflags, eflags_mask);
2565 2c0262af bellard
    }
2566 2c0262af bellard
    return;
2567 2c0262af bellard
2568 2c0262af bellard
 return_to_vm86:
2569 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_esp);
2570 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ss);
2571 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_es);
2572 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_ds);
2573 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_fs);
2574 891b38e4 bellard
    POPL(ssp, sp, sp_mask, new_gs);
2575 3b46e624 ths
2576 2c0262af bellard
    /* modify processor state */
2577 5fafdf24 ths
    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
2578 8145122b bellard
                IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
2579 891b38e4 bellard
    load_seg_vm(R_CS, new_cs & 0xffff);
2580 2c0262af bellard
    cpu_x86_set_cpl(env, 3);
2581 891b38e4 bellard
    load_seg_vm(R_SS, new_ss & 0xffff);
2582 891b38e4 bellard
    load_seg_vm(R_ES, new_es & 0xffff);
2583 891b38e4 bellard
    load_seg_vm(R_DS, new_ds & 0xffff);
2584 891b38e4 bellard
    load_seg_vm(R_FS, new_fs & 0xffff);
2585 891b38e4 bellard
    load_seg_vm(R_GS, new_gs & 0xffff);
2586 2c0262af bellard
2587 fd836909 bellard
    env->eip = new_eip & 0xffff;
2588 2c0262af bellard
    ESP = new_esp;
2589 2c0262af bellard
}
2590 2c0262af bellard
2591 08cea4ee bellard
void helper_iret_protected(int shift, int next_eip)
2592 2c0262af bellard
{
2593 7e84c249 bellard
    int tss_selector, type;
2594 7e84c249 bellard
    uint32_t e1, e2;
2595 3b46e624 ths
2596 7e84c249 bellard
    /* specific case for TSS */
2597 7e84c249 bellard
    if (env->eflags & NT_MASK) {
2598 14ce26e7 bellard
#ifdef TARGET_X86_64
2599 14ce26e7 bellard
        if (env->hflags & HF_LMA_MASK)
2600 14ce26e7 bellard
            raise_exception_err(EXCP0D_GPF, 0);
2601 14ce26e7 bellard
#endif
2602 7e84c249 bellard
        tss_selector = lduw_kernel(env->tr.base + 0);
2603 7e84c249 bellard
        if (tss_selector & 4)
2604 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2605 7e84c249 bellard
        if (load_segment(&e1, &e2, tss_selector) != 0)
2606 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2607 7e84c249 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
2608 7e84c249 bellard
        /* NOTE: we check both segment and busy TSS */
2609 7e84c249 bellard
        if (type != 3)
2610 7e84c249 bellard
            raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
2611 08cea4ee bellard
        switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
2612 7e84c249 bellard
    } else {
2613 7e84c249 bellard
        helper_ret_protected(shift, 1, 0);
2614 7e84c249 bellard
    }
2615 9df217a3 bellard
#ifdef USE_KQEMU
2616 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2617 9df217a3 bellard
        CC_OP = CC_OP_EFLAGS;
2618 9df217a3 bellard
        env->exception_index = -1;
2619 9df217a3 bellard
        cpu_loop_exit();
2620 9df217a3 bellard
    }
2621 9df217a3 bellard
#endif
2622 2c0262af bellard
}
2623 2c0262af bellard
2624 2c0262af bellard
void helper_lret_protected(int shift, int addend)
2625 2c0262af bellard
{
2626 2c0262af bellard
    helper_ret_protected(shift, 0, addend);
2627 9df217a3 bellard
#ifdef USE_KQEMU
2628 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2629 9df217a3 bellard
        env->exception_index = -1;
2630 9df217a3 bellard
        cpu_loop_exit();
2631 9df217a3 bellard
    }
2632 9df217a3 bellard
#endif
2633 2c0262af bellard
}
2634 2c0262af bellard
2635 023fe10d bellard
void helper_sysenter(void)
2636 023fe10d bellard
{
2637 023fe10d bellard
    if (env->sysenter_cs == 0) {
2638 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2639 023fe10d bellard
    }
2640 023fe10d bellard
    env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
2641 023fe10d bellard
    cpu_x86_set_cpl(env, 0);
2642 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
2643 5fafdf24 ths
                           0, 0xffffffff,
2644 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2645 023fe10d bellard
                           DESC_S_MASK |
2646 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2647 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
2648 14ce26e7 bellard
                           0, 0xffffffff,
2649 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2650 023fe10d bellard
                           DESC_S_MASK |
2651 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2652 023fe10d bellard
    ESP = env->sysenter_esp;
2653 023fe10d bellard
    EIP = env->sysenter_eip;
2654 023fe10d bellard
}
2655 023fe10d bellard
2656 023fe10d bellard
void helper_sysexit(void)
2657 023fe10d bellard
{
2658 023fe10d bellard
    int cpl;
2659 023fe10d bellard
2660 023fe10d bellard
    cpl = env->hflags & HF_CPL_MASK;
2661 023fe10d bellard
    if (env->sysenter_cs == 0 || cpl != 0) {
2662 023fe10d bellard
        raise_exception_err(EXCP0D_GPF, 0);
2663 023fe10d bellard
    }
2664 023fe10d bellard
    cpu_x86_set_cpl(env, 3);
2665 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
2666 5fafdf24 ths
                           0, 0xffffffff,
2667 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2668 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2669 023fe10d bellard
                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
2670 5fafdf24 ths
    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
2671 14ce26e7 bellard
                           0, 0xffffffff,
2672 023fe10d bellard
                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
2673 023fe10d bellard
                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
2674 023fe10d bellard
                           DESC_W_MASK | DESC_A_MASK);
2675 023fe10d bellard
    ESP = ECX;
2676 023fe10d bellard
    EIP = EDX;
2677 9df217a3 bellard
#ifdef USE_KQEMU
2678 9df217a3 bellard
    if (kqemu_is_ok(env)) {
2679 9df217a3 bellard
        env->exception_index = -1;
2680 9df217a3 bellard
        cpu_loop_exit();
2681 9df217a3 bellard
    }
2682 9df217a3 bellard
#endif
2683 023fe10d bellard
}
2684 023fe10d bellard
2685 2c0262af bellard
void helper_movl_crN_T0(int reg)
2686 2c0262af bellard
{
2687 5fafdf24 ths
#if !defined(CONFIG_USER_ONLY)
2688 2c0262af bellard
    switch(reg) {
2689 2c0262af bellard
    case 0:
2690 1ac157da bellard
        cpu_x86_update_cr0(env, T0);
2691 2c0262af bellard
        break;
2692 2c0262af bellard
    case 3:
2693 1ac157da bellard
        cpu_x86_update_cr3(env, T0);
2694 1ac157da bellard
        break;
2695 1ac157da bellard
    case 4:
2696 1ac157da bellard
        cpu_x86_update_cr4(env, T0);
2697 1ac157da bellard
        break;
2698 4d6b6c0a bellard
    case 8:
2699 4d6b6c0a bellard
        cpu_set_apic_tpr(env, T0);
2700 4d6b6c0a bellard
        break;
2701 1ac157da bellard
    default:
2702 1ac157da bellard
        env->cr[reg] = T0;
2703 2c0262af bellard
        break;
2704 2c0262af bellard
    }
2705 4d6b6c0a bellard
#endif
2706 2c0262af bellard
}
2707 2c0262af bellard
2708 2c0262af bellard
/* XXX: do more */
2709 2c0262af bellard
void helper_movl_drN_T0(int reg)
2710 2c0262af bellard
{
2711 2c0262af bellard
    env->dr[reg] = T0;
2712 2c0262af bellard
}
2713 2c0262af bellard
2714 8f091a59 bellard
void helper_invlpg(target_ulong addr)
2715 2c0262af bellard
{
2716 2c0262af bellard
    cpu_x86_flush_tlb(env, addr);
2717 2c0262af bellard
}
2718 2c0262af bellard
2719 2c0262af bellard
void helper_rdtsc(void)
2720 2c0262af bellard
{
2721 2c0262af bellard
    uint64_t val;
2722 ecada8a2 bellard
2723 ecada8a2 bellard
    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2724 ecada8a2 bellard
        raise_exception(EXCP0D_GPF);
2725 ecada8a2 bellard
    }
2726 28ab0e2e bellard
    val = cpu_get_tsc(env);
2727 14ce26e7 bellard
    EAX = (uint32_t)(val);
2728 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2729 14ce26e7 bellard
}
2730 14ce26e7 bellard
2731 5fafdf24 ths
#if defined(CONFIG_USER_ONLY)
2732 14ce26e7 bellard
void helper_wrmsr(void)
2733 14ce26e7 bellard
{
2734 2c0262af bellard
}
2735 2c0262af bellard
2736 14ce26e7 bellard
void helper_rdmsr(void)
2737 14ce26e7 bellard
{
2738 14ce26e7 bellard
}
2739 14ce26e7 bellard
#else
2740 2c0262af bellard
void helper_wrmsr(void)
2741 2c0262af bellard
{
2742 14ce26e7 bellard
    uint64_t val;
2743 14ce26e7 bellard
2744 14ce26e7 bellard
    val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
2745 14ce26e7 bellard
2746 14ce26e7 bellard
    switch((uint32_t)ECX) {
2747 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2748 14ce26e7 bellard
        env->sysenter_cs = val & 0xffff;
2749 2c0262af bellard
        break;
2750 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2751 14ce26e7 bellard
        env->sysenter_esp = val;
2752 2c0262af bellard
        break;
2753 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2754 14ce26e7 bellard
        env->sysenter_eip = val;
2755 14ce26e7 bellard
        break;
2756 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2757 14ce26e7 bellard
        cpu_set_apic_base(env, val);
2758 14ce26e7 bellard
        break;
2759 14ce26e7 bellard
    case MSR_EFER:
2760 f419b321 bellard
        {
2761 f419b321 bellard
            uint64_t update_mask;
2762 f419b321 bellard
            update_mask = 0;
2763 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
2764 f419b321 bellard
                update_mask |= MSR_EFER_SCE;
2765 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_LM)
2766 f419b321 bellard
                update_mask |= MSR_EFER_LME;
2767 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
2768 f419b321 bellard
                update_mask |= MSR_EFER_FFXSR;
2769 f419b321 bellard
            if (env->cpuid_ext2_features & CPUID_EXT2_NX)
2770 f419b321 bellard
                update_mask |= MSR_EFER_NXE;
2771 5fafdf24 ths
            env->efer = (env->efer & ~update_mask) |
2772 f419b321 bellard
            (val & update_mask);
2773 f419b321 bellard
        }
2774 2c0262af bellard
        break;
2775 14ce26e7 bellard
    case MSR_STAR:
2776 14ce26e7 bellard
        env->star = val;
2777 14ce26e7 bellard
        break;
2778 8f091a59 bellard
    case MSR_PAT:
2779 8f091a59 bellard
        env->pat = val;
2780 8f091a59 bellard
        break;
2781 0573fbfc ths
    case MSR_VM_HSAVE_PA:
2782 0573fbfc ths
        env->vm_hsave = val;
2783 0573fbfc ths
        break;
2784 f419b321 bellard
#ifdef TARGET_X86_64
2785 14ce26e7 bellard
    case MSR_LSTAR:
2786 14ce26e7 bellard
        env->lstar = val;
2787 14ce26e7 bellard
        break;
2788 14ce26e7 bellard
    case MSR_CSTAR:
2789 14ce26e7 bellard
        env->cstar = val;
2790 14ce26e7 bellard
        break;
2791 14ce26e7 bellard
    case MSR_FMASK:
2792 14ce26e7 bellard
        env->fmask = val;
2793 14ce26e7 bellard
        break;
2794 14ce26e7 bellard
    case MSR_FSBASE:
2795 14ce26e7 bellard
        env->segs[R_FS].base = val;
2796 14ce26e7 bellard
        break;
2797 14ce26e7 bellard
    case MSR_GSBASE:
2798 14ce26e7 bellard
        env->segs[R_GS].base = val;
2799 14ce26e7 bellard
        break;
2800 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2801 14ce26e7 bellard
        env->kernelgsbase = val;
2802 14ce26e7 bellard
        break;
2803 14ce26e7 bellard
#endif
2804 2c0262af bellard
    default:
2805 2c0262af bellard
        /* XXX: exception ? */
2806 5fafdf24 ths
        break;
2807 2c0262af bellard
    }
2808 2c0262af bellard
}
2809 2c0262af bellard
2810 2c0262af bellard
void helper_rdmsr(void)
2811 2c0262af bellard
{
2812 14ce26e7 bellard
    uint64_t val;
2813 14ce26e7 bellard
    switch((uint32_t)ECX) {
2814 2c0262af bellard
    case MSR_IA32_SYSENTER_CS:
2815 14ce26e7 bellard
        val = env->sysenter_cs;
2816 2c0262af bellard
        break;
2817 2c0262af bellard
    case MSR_IA32_SYSENTER_ESP:
2818 14ce26e7 bellard
        val = env->sysenter_esp;
2819 2c0262af bellard
        break;
2820 2c0262af bellard
    case MSR_IA32_SYSENTER_EIP:
2821 14ce26e7 bellard
        val = env->sysenter_eip;
2822 14ce26e7 bellard
        break;
2823 14ce26e7 bellard
    case MSR_IA32_APICBASE:
2824 14ce26e7 bellard
        val = cpu_get_apic_base(env);
2825 14ce26e7 bellard
        break;
2826 14ce26e7 bellard
    case MSR_EFER:
2827 14ce26e7 bellard
        val = env->efer;
2828 14ce26e7 bellard
        break;
2829 14ce26e7 bellard
    case MSR_STAR:
2830 14ce26e7 bellard
        val = env->star;
2831 14ce26e7 bellard
        break;
2832 8f091a59 bellard
    case MSR_PAT:
2833 8f091a59 bellard
        val = env->pat;
2834 8f091a59 bellard
        break;
2835 0573fbfc ths
    case MSR_VM_HSAVE_PA:
2836 0573fbfc ths
        val = env->vm_hsave;
2837 0573fbfc ths
        break;
2838 f419b321 bellard
#ifdef TARGET_X86_64
2839 14ce26e7 bellard
    case MSR_LSTAR:
2840 14ce26e7 bellard
        val = env->lstar;
2841 14ce26e7 bellard
        break;
2842 14ce26e7 bellard
    case MSR_CSTAR:
2843 14ce26e7 bellard
        val = env->cstar;
2844 14ce26e7 bellard
        break;
2845 14ce26e7 bellard
    case MSR_FMASK:
2846 14ce26e7 bellard
        val = env->fmask;
2847 14ce26e7 bellard
        break;
2848 14ce26e7 bellard
    case MSR_FSBASE:
2849 14ce26e7 bellard
        val = env->segs[R_FS].base;
2850 14ce26e7 bellard
        break;
2851 14ce26e7 bellard
    case MSR_GSBASE:
2852 14ce26e7 bellard
        val = env->segs[R_GS].base;
2853 2c0262af bellard
        break;
2854 14ce26e7 bellard
    case MSR_KERNELGSBASE:
2855 14ce26e7 bellard
        val = env->kernelgsbase;
2856 14ce26e7 bellard
        break;
2857 14ce26e7 bellard
#endif
2858 2c0262af bellard
    default:
2859 2c0262af bellard
        /* XXX: exception ? */
2860 14ce26e7 bellard
        val = 0;
2861 5fafdf24 ths
        break;
2862 2c0262af bellard
    }
2863 14ce26e7 bellard
    EAX = (uint32_t)(val);
2864 14ce26e7 bellard
    EDX = (uint32_t)(val >> 32);
2865 2c0262af bellard
}
2866 14ce26e7 bellard
#endif
2867 2c0262af bellard
2868 2c0262af bellard
void helper_lsl(void)
2869 2c0262af bellard
{
2870 2c0262af bellard
    unsigned int selector, limit;
2871 5516d670 bellard
    uint32_t e1, e2, eflags;
2872 3ab493de bellard
    int rpl, dpl, cpl, type;
2873 2c0262af bellard
2874 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2875 2c0262af bellard
    selector = T0 & 0xffff;
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 9:
2895 3ab493de bellard
        case 11:
2896 3ab493de bellard
            break;
2897 3ab493de bellard
        default:
2898 5516d670 bellard
            goto fail;
2899 3ab493de bellard
        }
2900 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2901 5516d670 bellard
        fail:
2902 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2903 3ab493de bellard
            return;
2904 5516d670 bellard
        }
2905 3ab493de bellard
    }
2906 3ab493de bellard
    limit = get_seg_limit(e1, e2);
2907 2c0262af bellard
    T1 = limit;
2908 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2909 2c0262af bellard
}
2910 2c0262af bellard
2911 2c0262af bellard
void helper_lar(void)
2912 2c0262af bellard
{
2913 2c0262af bellard
    unsigned int selector;
2914 5516d670 bellard
    uint32_t e1, e2, eflags;
2915 3ab493de bellard
    int rpl, dpl, cpl, type;
2916 2c0262af bellard
2917 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2918 2c0262af bellard
    selector = T0 & 0xffff;
2919 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2920 5516d670 bellard
        goto fail;
2921 2c0262af bellard
    if (load_segment(&e1, &e2, selector) != 0)
2922 5516d670 bellard
        goto fail;
2923 3ab493de bellard
    rpl = selector & 3;
2924 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2925 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2926 3ab493de bellard
    if (e2 & DESC_S_MASK) {
2927 3ab493de bellard
        if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
2928 3ab493de bellard
            /* conforming */
2929 3ab493de bellard
        } else {
2930 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2931 5516d670 bellard
                goto fail;
2932 3ab493de bellard
        }
2933 3ab493de bellard
    } else {
2934 3ab493de bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
2935 3ab493de bellard
        switch(type) {
2936 3ab493de bellard
        case 1:
2937 3ab493de bellard
        case 2:
2938 3ab493de bellard
        case 3:
2939 3ab493de bellard
        case 4:
2940 3ab493de bellard
        case 5:
2941 3ab493de bellard
        case 9:
2942 3ab493de bellard
        case 11:
2943 3ab493de bellard
        case 12:
2944 3ab493de bellard
            break;
2945 3ab493de bellard
        default:
2946 5516d670 bellard
            goto fail;
2947 3ab493de bellard
        }
2948 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2949 5516d670 bellard
        fail:
2950 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2951 3ab493de bellard
            return;
2952 5516d670 bellard
        }
2953 3ab493de bellard
    }
2954 2c0262af bellard
    T1 = e2 & 0x00f0ff00;
2955 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2956 2c0262af bellard
}
2957 2c0262af bellard
2958 3ab493de bellard
void helper_verr(void)
2959 3ab493de bellard
{
2960 3ab493de bellard
    unsigned int selector;
2961 5516d670 bellard
    uint32_t e1, e2, eflags;
2962 3ab493de bellard
    int rpl, dpl, cpl;
2963 3ab493de bellard
2964 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2965 3ab493de bellard
    selector = T0 & 0xffff;
2966 3ab493de bellard
    if ((selector & 0xfffc) == 0)
2967 5516d670 bellard
        goto fail;
2968 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
2969 5516d670 bellard
        goto fail;
2970 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
2971 5516d670 bellard
        goto fail;
2972 3ab493de bellard
    rpl = selector & 3;
2973 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
2974 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
2975 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
2976 3ab493de bellard
        if (!(e2 & DESC_R_MASK))
2977 5516d670 bellard
            goto fail;
2978 3ab493de bellard
        if (!(e2 & DESC_C_MASK)) {
2979 3ab493de bellard
            if (dpl < cpl || dpl < rpl)
2980 5516d670 bellard
                goto fail;
2981 3ab493de bellard
        }
2982 3ab493de bellard
    } else {
2983 5516d670 bellard
        if (dpl < cpl || dpl < rpl) {
2984 5516d670 bellard
        fail:
2985 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
2986 3ab493de bellard
            return;
2987 5516d670 bellard
        }
2988 3ab493de bellard
    }
2989 5516d670 bellard
    CC_SRC = eflags | CC_Z;
2990 3ab493de bellard
}
2991 3ab493de bellard
2992 3ab493de bellard
void helper_verw(void)
2993 3ab493de bellard
{
2994 3ab493de bellard
    unsigned int selector;
2995 5516d670 bellard
    uint32_t e1, e2, eflags;
2996 3ab493de bellard
    int rpl, dpl, cpl;
2997 3ab493de bellard
2998 5516d670 bellard
    eflags = cc_table[CC_OP].compute_all();
2999 3ab493de bellard
    selector = T0 & 0xffff;
3000 3ab493de bellard
    if ((selector & 0xfffc) == 0)
3001 5516d670 bellard
        goto fail;
3002 3ab493de bellard
    if (load_segment(&e1, &e2, selector) != 0)
3003 5516d670 bellard
        goto fail;
3004 3ab493de bellard
    if (!(e2 & DESC_S_MASK))
3005 5516d670 bellard
        goto fail;
3006 3ab493de bellard
    rpl = selector & 3;
3007 3ab493de bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
3008 3ab493de bellard
    cpl = env->hflags & HF_CPL_MASK;
3009 3ab493de bellard
    if (e2 & DESC_CS_MASK) {
3010 5516d670 bellard
        goto fail;
3011 3ab493de bellard
    } else {
3012 3ab493de bellard
        if (dpl < cpl || dpl < rpl)
3013 5516d670 bellard
            goto fail;
3014 5516d670 bellard
        if (!(e2 & DESC_W_MASK)) {
3015 5516d670 bellard
        fail:
3016 5516d670 bellard
            CC_SRC = eflags & ~CC_Z;
3017 3ab493de bellard
            return;
3018 5516d670 bellard
        }
3019 3ab493de bellard
    }
3020 5516d670 bellard
    CC_SRC = eflags | CC_Z;
3021 3ab493de bellard
}
3022 3ab493de bellard
3023 2c0262af bellard
/* FPU helpers */
3024 2c0262af bellard
3025 2c0262af bellard
void helper_fldt_ST0_A0(void)
3026 2c0262af bellard
{
3027 2c0262af bellard
    int new_fpstt;
3028 2c0262af bellard
    new_fpstt = (env->fpstt - 1) & 7;
3029 664e0f19 bellard
    env->fpregs[new_fpstt].d = helper_fldt(A0);
3030 2c0262af bellard
    env->fpstt = new_fpstt;
3031 2c0262af bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3032 2c0262af bellard
}
3033 2c0262af bellard
3034 2c0262af bellard
void helper_fstt_ST0_A0(void)
3035 2c0262af bellard
{
3036 14ce26e7 bellard
    helper_fstt(ST0, A0);
3037 2c0262af bellard
}
3038 2c0262af bellard
3039 2ee73ac3 bellard
void fpu_set_exception(int mask)
3040 2ee73ac3 bellard
{
3041 2ee73ac3 bellard
    env->fpus |= mask;
3042 2ee73ac3 bellard
    if (env->fpus & (~env->fpuc & FPUC_EM))
3043 2ee73ac3 bellard
        env->fpus |= FPUS_SE | FPUS_B;
3044 2ee73ac3 bellard
}
3045 2ee73ac3 bellard
3046 2ee73ac3 bellard
CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
3047 2ee73ac3 bellard
{
3048 5fafdf24 ths
    if (b == 0.0)
3049 2ee73ac3 bellard
        fpu_set_exception(FPUS_ZE);
3050 2ee73ac3 bellard
    return a / b;
3051 2ee73ac3 bellard
}
3052 2ee73ac3 bellard
3053 2ee73ac3 bellard
void fpu_raise_exception(void)
3054 2ee73ac3 bellard
{
3055 2ee73ac3 bellard
    if (env->cr[0] & CR0_NE_MASK) {
3056 2ee73ac3 bellard
        raise_exception(EXCP10_COPR);
3057 5fafdf24 ths
    }
3058 5fafdf24 ths
#if !defined(CONFIG_USER_ONLY)
3059 2ee73ac3 bellard
    else {
3060 2ee73ac3 bellard
        cpu_set_ferr(env);
3061 2ee73ac3 bellard
    }
3062 2ee73ac3 bellard
#endif
3063 2ee73ac3 bellard
}
3064 2ee73ac3 bellard
3065 2c0262af bellard
/* BCD ops */
3066 2c0262af bellard
3067 2c0262af bellard
void helper_fbld_ST0_A0(void)
3068 2c0262af bellard
{
3069 2c0262af bellard
    CPU86_LDouble tmp;
3070 2c0262af bellard
    uint64_t val;
3071 2c0262af bellard
    unsigned int v;
3072 2c0262af bellard
    int i;
3073 2c0262af bellard
3074 2c0262af bellard
    val = 0;
3075 2c0262af bellard
    for(i = 8; i >= 0; i--) {
3076 14ce26e7 bellard
        v = ldub(A0 + i);
3077 2c0262af bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
3078 2c0262af bellard
    }
3079 2c0262af bellard
    tmp = val;
3080 14ce26e7 bellard
    if (ldub(A0 + 9) & 0x80)
3081 2c0262af bellard
        tmp = -tmp;
3082 2c0262af bellard
    fpush();
3083 2c0262af bellard
    ST0 = tmp;
3084 2c0262af bellard
}
3085 2c0262af bellard
3086 2c0262af bellard
void helper_fbst_ST0_A0(void)
3087 2c0262af bellard
{
3088 2c0262af bellard
    int v;
3089 14ce26e7 bellard
    target_ulong mem_ref, mem_end;
3090 2c0262af bellard
    int64_t val;
3091 2c0262af bellard
3092 7a0e1f41 bellard
    val = floatx_to_int64(ST0, &env->fp_status);
3093 14ce26e7 bellard
    mem_ref = A0;
3094 2c0262af bellard
    mem_end = mem_ref + 9;
3095 2c0262af bellard
    if (val < 0) {
3096 2c0262af bellard
        stb(mem_end, 0x80);
3097 2c0262af bellard
        val = -val;
3098 2c0262af bellard
    } else {
3099 2c0262af bellard
        stb(mem_end, 0x00);
3100 2c0262af bellard
    }
3101 2c0262af bellard
    while (mem_ref < mem_end) {
3102 2c0262af bellard
        if (val == 0)
3103 2c0262af bellard
            break;
3104 2c0262af bellard
        v = val % 100;
3105 2c0262af bellard
        val = val / 100;
3106 2c0262af bellard
        v = ((v / 10) << 4) | (v % 10);
3107 2c0262af bellard
        stb(mem_ref++, v);
3108 2c0262af bellard
    }
3109 2c0262af bellard
    while (mem_ref < mem_end) {
3110 2c0262af bellard
        stb(mem_ref++, 0);
3111 2c0262af bellard
    }
3112 2c0262af bellard
}
3113 2c0262af bellard
3114 2c0262af bellard
void helper_f2xm1(void)
3115 2c0262af bellard
{
3116 2c0262af bellard
    ST0 = pow(2.0,ST0) - 1.0;
3117 2c0262af bellard
}
3118 2c0262af bellard
3119 2c0262af bellard
void helper_fyl2x(void)
3120 2c0262af bellard
{
3121 2c0262af bellard
    CPU86_LDouble fptemp;
3122 3b46e624 ths
3123 2c0262af bellard
    fptemp = ST0;
3124 2c0262af bellard
    if (fptemp>0.0){
3125 2c0262af bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
3126 2c0262af bellard
        ST1 *= fptemp;
3127 2c0262af bellard
        fpop();
3128 5fafdf24 ths
    } else {
3129 2c0262af bellard
        env->fpus &= (~0x4700);
3130 2c0262af bellard
        env->fpus |= 0x400;
3131 2c0262af bellard
    }
3132 2c0262af bellard
}
3133 2c0262af bellard
3134 2c0262af bellard
void helper_fptan(void)
3135 2c0262af bellard
{
3136 2c0262af bellard
    CPU86_LDouble fptemp;
3137 2c0262af bellard
3138 2c0262af bellard
    fptemp = ST0;
3139 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3140 2c0262af bellard
        env->fpus |= 0x400;
3141 2c0262af bellard
    } else {
3142 2c0262af bellard
        ST0 = tan(fptemp);
3143 2c0262af bellard
        fpush();
3144 2c0262af bellard
        ST0 = 1.0;
3145 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3146 2c0262af bellard
        /* the above code is for  |arg| < 2**52 only */
3147 2c0262af bellard
    }
3148 2c0262af bellard
}
3149 2c0262af bellard
3150 2c0262af bellard
void helper_fpatan(void)
3151 2c0262af bellard
{
3152 2c0262af bellard
    CPU86_LDouble fptemp, fpsrcop;
3153 2c0262af bellard
3154 2c0262af bellard
    fpsrcop = ST1;
3155 2c0262af bellard
    fptemp = ST0;
3156 2c0262af bellard
    ST1 = atan2(fpsrcop,fptemp);
3157 2c0262af bellard
    fpop();
3158 2c0262af bellard
}
3159 2c0262af bellard
3160 2c0262af bellard
void helper_fxtract(void)
3161 2c0262af bellard
{
3162 2c0262af bellard
    CPU86_LDoubleU temp;
3163 2c0262af bellard
    unsigned int expdif;
3164 2c0262af bellard
3165 2c0262af bellard
    temp.d = ST0;
3166 2c0262af bellard
    expdif = EXPD(temp) - EXPBIAS;
3167 2c0262af bellard
    /*DP exponent bias*/
3168 2c0262af bellard
    ST0 = expdif;
3169 2c0262af bellard
    fpush();
3170 2c0262af bellard
    BIASEXPONENT(temp);
3171 2c0262af bellard
    ST0 = temp.d;
3172 2c0262af bellard
}
3173 2c0262af bellard
3174 2c0262af bellard
void helper_fprem1(void)
3175 2c0262af bellard
{
3176 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
3177 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
3178 2c0262af bellard
    int expdif;
3179 7524c84d ths
    signed long long int q;
3180 7524c84d ths
3181 7524c84d ths
    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3182 7524c84d ths
        ST0 = 0.0 / 0.0; /* NaN */
3183 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3184 7524c84d ths
        return;
3185 7524c84d ths
    }
3186 2c0262af bellard
3187 2c0262af bellard
    fpsrcop = ST0;
3188 2c0262af bellard
    fptemp = ST1;
3189 2c0262af bellard
    fpsrcop1.d = fpsrcop;
3190 2c0262af bellard
    fptemp1.d = fptemp;
3191 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3192 7524c84d ths
3193 7524c84d ths
    if (expdif < 0) {
3194 7524c84d ths
        /* optimisation? taken from the AMD docs */
3195 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3196 7524c84d ths
        /* ST0 is unchanged */
3197 7524c84d ths
        return;
3198 7524c84d ths
    }
3199 7524c84d ths
3200 2c0262af bellard
    if (expdif < 53) {
3201 2c0262af bellard
        dblq = fpsrcop / fptemp;
3202 7524c84d ths
        /* round dblq towards nearest integer */
3203 7524c84d ths
        dblq = rint(dblq);
3204 7524c84d ths
        ST0 = fpsrcop - fptemp * dblq;
3205 7524c84d ths
3206 7524c84d ths
        /* convert dblq to q by truncating towards zero */
3207 7524c84d ths
        if (dblq < 0.0)
3208 7524c84d ths
           q = (signed long long int)(-dblq);
3209 7524c84d ths
        else
3210 7524c84d ths
           q = (signed long long int)dblq;
3211 7524c84d ths
3212 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3213 7524c84d ths
                                /* (C0,C3,C1) <-- (q2,q1,q0) */
3214 7524c84d ths
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
3215 7524c84d ths
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3216 7524c84d ths
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
3217 2c0262af bellard
    } else {
3218 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
3219 7524c84d ths
        fptemp = pow(2.0, expdif - 50);
3220 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
3221 7524c84d ths
        /* fpsrcop = integer obtained by chopping */
3222 7524c84d ths
        fpsrcop = (fpsrcop < 0.0) ?
3223 7524c84d ths
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3224 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
3225 2c0262af bellard
    }
3226 2c0262af bellard
}
3227 2c0262af bellard
3228 2c0262af bellard
void helper_fprem(void)
3229 2c0262af bellard
{
3230 2c0262af bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
3231 2c0262af bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
3232 2c0262af bellard
    int expdif;
3233 7524c84d ths
    signed long long int q;
3234 7524c84d ths
3235 7524c84d ths
    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
3236 7524c84d ths
       ST0 = 0.0 / 0.0; /* NaN */
3237 7524c84d ths
       env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3238 7524c84d ths
       return;
3239 7524c84d ths
    }
3240 7524c84d ths
3241 7524c84d ths
    fpsrcop = (CPU86_LDouble)ST0;
3242 7524c84d ths
    fptemp = (CPU86_LDouble)ST1;
3243 2c0262af bellard
    fpsrcop1.d = fpsrcop;
3244 2c0262af bellard
    fptemp1.d = fptemp;
3245 2c0262af bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
3246 7524c84d ths
3247 7524c84d ths
    if (expdif < 0) {
3248 7524c84d ths
        /* optimisation? taken from the AMD docs */
3249 7524c84d ths
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3250 7524c84d ths
        /* ST0 is unchanged */
3251 7524c84d ths
        return;
3252 7524c84d ths
    }
3253 7524c84d ths
3254 2c0262af bellard
    if ( expdif < 53 ) {
3255 7524c84d ths
        dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
3256 7524c84d ths
        /* round dblq towards zero */
3257 7524c84d ths
        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
3258 7524c84d ths
        ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
3259 7524c84d ths
3260 7524c84d ths
        /* convert dblq to q by truncating towards zero */
3261 7524c84d ths
        if (dblq < 0.0)
3262 7524c84d ths
           q = (signed long long int)(-dblq);
3263 7524c84d ths
        else
3264 7524c84d ths
           q = (signed long long int)dblq;
3265 7524c84d ths
3266 2c0262af bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
3267 7524c84d ths
                                /* (C0,C3,C1) <-- (q2,q1,q0) */
3268 7524c84d ths
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
3269 7524c84d ths
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
3270 7524c84d ths
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
3271 2c0262af bellard
    } else {
3272 7524c84d ths
        int N = 32 + (expdif % 32); /* as per AMD docs */
3273 2c0262af bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
3274 7524c84d ths
        fptemp = pow(2.0, (double)(expdif - N));
3275 2c0262af bellard
        fpsrcop = (ST0 / ST1) / fptemp;
3276 2c0262af bellard
        /* fpsrcop = integer obtained by chopping */
3277 7524c84d ths
        fpsrcop = (fpsrcop < 0.0) ?
3278 7524c84d ths
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
3279 2c0262af bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
3280 2c0262af bellard
    }
3281 2c0262af bellard
}
3282 2c0262af bellard
3283 2c0262af bellard
void helper_fyl2xp1(void)
3284 2c0262af bellard
{
3285 2c0262af bellard
    CPU86_LDouble fptemp;
3286 2c0262af bellard
3287 2c0262af bellard
    fptemp = ST0;
3288 2c0262af bellard
    if ((fptemp+1.0)>0.0) {
3289 2c0262af bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
3290 2c0262af bellard
        ST1 *= fptemp;
3291 2c0262af bellard
        fpop();
3292 5fafdf24 ths
    } else {
3293 2c0262af bellard
        env->fpus &= (~0x4700);
3294 2c0262af bellard
        env->fpus |= 0x400;
3295 2c0262af bellard
    }
3296 2c0262af bellard
}
3297 2c0262af bellard
3298 2c0262af bellard
void helper_fsqrt(void)
3299 2c0262af bellard
{
3300 2c0262af bellard
    CPU86_LDouble fptemp;
3301 2c0262af bellard
3302 2c0262af bellard
    fptemp = ST0;
3303 5fafdf24 ths
    if (fptemp<0.0) {
3304 2c0262af bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
3305 2c0262af bellard
        env->fpus |= 0x400;
3306 2c0262af bellard
    }
3307 2c0262af bellard
    ST0 = sqrt(fptemp);
3308 2c0262af bellard
}
3309 2c0262af bellard
3310 2c0262af bellard
void helper_fsincos(void)
3311 2c0262af bellard
{
3312 2c0262af bellard
    CPU86_LDouble fptemp;
3313 2c0262af bellard
3314 2c0262af bellard
    fptemp = ST0;
3315 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3316 2c0262af bellard
        env->fpus |= 0x400;
3317 2c0262af bellard
    } else {
3318 2c0262af bellard
        ST0 = sin(fptemp);
3319 2c0262af bellard
        fpush();
3320 2c0262af bellard
        ST0 = cos(fptemp);
3321 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3322 2c0262af bellard
        /* the above code is for  |arg| < 2**63 only */
3323 2c0262af bellard
    }
3324 2c0262af bellard
}
3325 2c0262af bellard
3326 2c0262af bellard
void helper_frndint(void)
3327 2c0262af bellard
{
3328 7a0e1f41 bellard
    ST0 = floatx_round_to_int(ST0, &env->fp_status);
3329 2c0262af bellard
}
3330 2c0262af bellard
3331 2c0262af bellard
void helper_fscale(void)
3332 2c0262af bellard
{
3333 5fafdf24 ths
    ST0 = ldexp (ST0, (int)(ST1));
3334 2c0262af bellard
}
3335 2c0262af bellard
3336 2c0262af bellard
void helper_fsin(void)
3337 2c0262af bellard
{
3338 2c0262af bellard
    CPU86_LDouble fptemp;
3339 2c0262af bellard
3340 2c0262af bellard
    fptemp = ST0;
3341 2c0262af bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3342 2c0262af bellard
        env->fpus |= 0x400;
3343 2c0262af bellard
    } else {
3344 2c0262af bellard
        ST0 = sin(fptemp);
3345 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3346 2c0262af bellard
        /* the above code is for  |arg| < 2**53 only */
3347 2c0262af bellard
    }
3348 2c0262af bellard
}
3349 2c0262af bellard
3350 2c0262af bellard
void helper_fcos(void)
3351 2c0262af bellard
{
3352 2c0262af bellard
    CPU86_LDouble fptemp;
3353 2c0262af bellard
3354 2c0262af bellard
    fptemp = ST0;
3355 2c0262af bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
3356 2c0262af bellard
        env->fpus |= 0x400;
3357 2c0262af bellard
    } else {
3358 2c0262af bellard
        ST0 = cos(fptemp);
3359 2c0262af bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
3360 2c0262af bellard
        /* the above code is for  |arg5 < 2**63 only */
3361 2c0262af bellard
    }
3362 2c0262af bellard
}
3363 2c0262af bellard
3364 2c0262af bellard
void helper_fxam_ST0(void)
3365 2c0262af bellard
{
3366 2c0262af bellard
    CPU86_LDoubleU temp;
3367 2c0262af bellard
    int expdif;
3368 2c0262af bellard
3369 2c0262af bellard
    temp.d = ST0;
3370 2c0262af bellard
3371 2c0262af bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
3372 2c0262af bellard
    if (SIGND(temp))
3373 2c0262af bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
3374 2c0262af bellard
3375 a891c7a1 bellard
    /* XXX: test fptags too */
3376 2c0262af bellard
    expdif = EXPD(temp);
3377 2c0262af bellard
    if (expdif == MAXEXPD) {
3378 a891c7a1 bellard
#ifdef USE_X86LDOUBLE
3379 a891c7a1 bellard
        if (MANTD(temp) == 0x8000000000000000ULL)
3380 a891c7a1 bellard
#else
3381 2c0262af bellard
        if (MANTD(temp) == 0)
3382 a891c7a1 bellard
#endif
3383 2c0262af bellard
            env->fpus |=  0x500 /*Infinity*/;
3384 2c0262af bellard
        else
3385 2c0262af bellard
            env->fpus |=  0x100 /*NaN*/;
3386 2c0262af bellard
    } else if (expdif == 0) {
3387 2c0262af bellard
        if (MANTD(temp) == 0)
3388 2c0262af bellard
            env->fpus |=  0x4000 /*Zero*/;
3389 2c0262af bellard
        else
3390 2c0262af bellard
            env->fpus |= 0x4400 /*Denormal*/;
3391 2c0262af bellard
    } else {
3392 2c0262af bellard
        env->fpus |= 0x400;
3393 2c0262af bellard
    }
3394 2c0262af bellard
}
3395 2c0262af bellard
3396 14ce26e7 bellard
void helper_fstenv(target_ulong ptr, int data32)
3397 2c0262af bellard
{
3398 2c0262af bellard
    int fpus, fptag, exp, i;
3399 2c0262af bellard
    uint64_t mant;
3400 2c0262af bellard
    CPU86_LDoubleU tmp;
3401 2c0262af bellard
3402 2c0262af bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3403 2c0262af bellard
    fptag = 0;
3404 2c0262af bellard
    for (i=7; i>=0; i--) {
3405 2c0262af bellard
        fptag <<= 2;
3406 2c0262af bellard
        if (env->fptags[i]) {
3407 2c0262af bellard
            fptag |= 3;
3408 2c0262af bellard
        } else {
3409 664e0f19 bellard
            tmp.d = env->fpregs[i].d;
3410 2c0262af bellard
            exp = EXPD(tmp);
3411 2c0262af bellard
            mant = MANTD(tmp);
3412 2c0262af bellard
            if (exp == 0 && mant == 0) {
3413 2c0262af bellard
                /* zero */
3414 2c0262af bellard
                fptag |= 1;
3415 2c0262af bellard
            } else if (exp == 0 || exp == MAXEXPD
3416 2c0262af bellard
#ifdef USE_X86LDOUBLE
3417 2c0262af bellard
                       || (mant & (1LL << 63)) == 0
3418 2c0262af bellard
#endif
3419 2c0262af bellard
                       ) {
3420 2c0262af bellard
                /* NaNs, infinity, denormal */
3421 2c0262af bellard
                fptag |= 2;
3422 2c0262af bellard
            }
3423 2c0262af bellard
        }
3424 2c0262af bellard
    }
3425 2c0262af bellard
    if (data32) {
3426 2c0262af bellard
        /* 32 bit */
3427 2c0262af bellard
        stl(ptr, env->fpuc);
3428 2c0262af bellard
        stl(ptr + 4, fpus);
3429 2c0262af bellard
        stl(ptr + 8, fptag);
3430 2edcdce3 bellard
        stl(ptr + 12, 0); /* fpip */
3431 2edcdce3 bellard
        stl(ptr + 16, 0); /* fpcs */
3432 2edcdce3 bellard
        stl(ptr + 20, 0); /* fpoo */
3433 2edcdce3 bellard
        stl(ptr + 24, 0); /* fpos */
3434 2c0262af bellard
    } else {
3435 2c0262af bellard
        /* 16 bit */
3436 2c0262af bellard
        stw(ptr, env->fpuc);
3437 2c0262af bellard
        stw(ptr + 2, fpus);
3438 2c0262af bellard
        stw(ptr + 4, fptag);
3439 2c0262af bellard
        stw(ptr + 6, 0);
3440 2c0262af bellard
        stw(ptr + 8, 0);
3441 2c0262af bellard
        stw(ptr + 10, 0);
3442 2c0262af bellard
        stw(ptr + 12, 0);
3443 2c0262af bellard
    }
3444 2c0262af bellard
}
3445 2c0262af bellard
3446 14ce26e7 bellard
void helper_fldenv(target_ulong ptr, int data32)
3447 2c0262af bellard
{
3448 2c0262af bellard
    int i, fpus, fptag;
3449 2c0262af bellard
3450 2c0262af bellard
    if (data32) {
3451 2c0262af bellard
        env->fpuc = lduw(ptr);
3452 2c0262af bellard
        fpus = lduw(ptr + 4);
3453 2c0262af bellard
        fptag = lduw(ptr + 8);
3454 2c0262af bellard
    }
3455 2c0262af bellard
    else {
3456 2c0262af bellard
        env->fpuc = lduw(ptr);
3457 2c0262af bellard
        fpus = lduw(ptr + 2);
3458 2c0262af bellard
        fptag = lduw(ptr + 4);
3459 2c0262af bellard
    }
3460 2c0262af bellard
    env->fpstt = (fpus >> 11) & 7;
3461 2c0262af bellard
    env->fpus = fpus & ~0x3800;
3462 2edcdce3 bellard
    for(i = 0;i < 8; i++) {
3463 2c0262af bellard
        env->fptags[i] = ((fptag & 3) == 3);
3464 2c0262af bellard
        fptag >>= 2;
3465 2c0262af bellard
    }
3466 2c0262af bellard
}
3467 2c0262af bellard
3468 14ce26e7 bellard
void helper_fsave(target_ulong ptr, int data32)
3469 2c0262af bellard
{
3470 2c0262af bellard
    CPU86_LDouble tmp;
3471 2c0262af bellard
    int i;
3472 2c0262af bellard
3473 2c0262af bellard
    helper_fstenv(ptr, data32);
3474 2c0262af bellard
3475 2c0262af bellard
    ptr += (14 << data32);
3476 2c0262af bellard
    for(i = 0;i < 8; i++) {
3477 2c0262af bellard
        tmp = ST(i);
3478 2c0262af bellard
        helper_fstt(tmp, ptr);
3479 2c0262af bellard
        ptr += 10;
3480 2c0262af bellard
    }
3481 2c0262af bellard
3482 2c0262af bellard
    /* fninit */
3483 2c0262af bellard
    env->fpus = 0;
3484 2c0262af bellard
    env->fpstt = 0;
3485 2c0262af bellard
    env->fpuc = 0x37f;
3486 2c0262af bellard
    env->fptags[0] = 1;
3487 2c0262af bellard
    env->fptags[1] = 1;
3488 2c0262af bellard
    env->fptags[2] = 1;
3489 2c0262af bellard
    env->fptags[3] = 1;
3490 2c0262af bellard
    env->fptags[4] = 1;
3491 2c0262af bellard
    env->fptags[5] = 1;
3492 2c0262af bellard
    env->fptags[6] = 1;
3493 2c0262af bellard
    env->fptags[7] = 1;
3494 2c0262af bellard
}
3495 2c0262af bellard
3496 14ce26e7 bellard
void helper_frstor(target_ulong ptr, int data32)
3497 2c0262af bellard
{
3498 2c0262af bellard
    CPU86_LDouble tmp;
3499 2c0262af bellard
    int i;
3500 2c0262af bellard
3501 2c0262af bellard
    helper_fldenv(ptr, data32);
3502 2c0262af bellard
    ptr += (14 << data32);
3503 2c0262af bellard
3504 2c0262af bellard
    for(i = 0;i < 8; i++) {
3505 2c0262af bellard
        tmp = helper_fldt(ptr);
3506 2c0262af bellard
        ST(i) = tmp;
3507 2c0262af bellard
        ptr += 10;
3508 2c0262af bellard
    }
3509 2c0262af bellard
}
3510 2c0262af bellard
3511 14ce26e7 bellard
void helper_fxsave(target_ulong ptr, int data64)
3512 14ce26e7 bellard
{
3513 14ce26e7 bellard
    int fpus, fptag, i, nb_xmm_regs;
3514 14ce26e7 bellard
    CPU86_LDouble tmp;
3515 14ce26e7 bellard
    target_ulong addr;
3516 14ce26e7 bellard
3517 14ce26e7 bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
3518 14ce26e7 bellard
    fptag = 0;
3519 14ce26e7 bellard
    for(i = 0; i < 8; i++) {
3520 d3c61721 bellard
        fptag |= (env->fptags[i] << i);
3521 14ce26e7 bellard
    }
3522 14ce26e7 bellard
    stw(ptr, env->fpuc);
3523 14ce26e7 bellard
    stw(ptr + 2, fpus);
3524 d3c61721 bellard
    stw(ptr + 4, fptag ^ 0xff);
3525 14ce26e7 bellard
3526 14ce26e7 bellard
    addr = ptr + 0x20;
3527 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3528 14ce26e7 bellard
        tmp = ST(i);
3529 14ce26e7 bellard
        helper_fstt(tmp, addr);
3530 14ce26e7 bellard
        addr += 16;
3531 14ce26e7 bellard
    }
3532 3b46e624 ths
3533 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3534 a8ede8ba bellard
        /* XXX: finish it */
3535 664e0f19 bellard
        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
3536 d3c61721 bellard
        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
3537 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3538 14ce26e7 bellard
        addr = ptr + 0xa0;
3539 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3540 a8ede8ba bellard
            stq(addr, env->xmm_regs[i].XMM_Q(0));
3541 a8ede8ba bellard
            stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
3542 14ce26e7 bellard
            addr += 16;
3543 14ce26e7 bellard
        }
3544 14ce26e7 bellard
    }
3545 14ce26e7 bellard
}
3546 14ce26e7 bellard
3547 14ce26e7 bellard
void helper_fxrstor(target_ulong ptr, int data64)
3548 14ce26e7 bellard
{
3549 14ce26e7 bellard
    int i, fpus, fptag, nb_xmm_regs;
3550 14ce26e7 bellard
    CPU86_LDouble tmp;
3551 14ce26e7 bellard
    target_ulong addr;
3552 14ce26e7 bellard
3553 14ce26e7 bellard
    env->fpuc = lduw(ptr);
3554 14ce26e7 bellard
    fpus = lduw(ptr + 2);
3555 d3c61721 bellard
    fptag = lduw(ptr + 4);
3556 14ce26e7 bellard
    env->fpstt = (fpus >> 11) & 7;
3557 14ce26e7 bellard
    env->fpus = fpus & ~0x3800;
3558 14ce26e7 bellard
    fptag ^= 0xff;
3559 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3560 d3c61721 bellard
        env->fptags[i] = ((fptag >> i) & 1);
3561 14ce26e7 bellard
    }
3562 14ce26e7 bellard
3563 14ce26e7 bellard
    addr = ptr + 0x20;
3564 14ce26e7 bellard
    for(i = 0;i < 8; i++) {
3565 14ce26e7 bellard
        tmp = helper_fldt(addr);
3566 14ce26e7 bellard
        ST(i) = tmp;
3567 14ce26e7 bellard
        addr += 16;
3568 14ce26e7 bellard
    }
3569 14ce26e7 bellard
3570 14ce26e7 bellard
    if (env->cr[4] & CR4_OSFXSR_MASK) {
3571 31313213 bellard
        /* XXX: finish it */
3572 664e0f19 bellard
        env->mxcsr = ldl(ptr + 0x18);
3573 14ce26e7 bellard
        //ldl(ptr + 0x1c);
3574 14ce26e7 bellard
        nb_xmm_regs = 8 << data64;
3575 14ce26e7 bellard
        addr = ptr + 0xa0;
3576 14ce26e7 bellard
        for(i = 0; i < nb_xmm_regs; i++) {
3577 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
3578 a8ede8ba bellard
            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
3579 14ce26e7 bellard
            addr += 16;
3580 14ce26e7 bellard
        }
3581 14ce26e7 bellard
    }
3582 14ce26e7 bellard
}
3583 1f1af9fd bellard
3584 1f1af9fd bellard
#ifndef USE_X86LDOUBLE
3585 1f1af9fd bellard
3586 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3587 1f1af9fd bellard
{
3588 1f1af9fd bellard
    CPU86_LDoubleU temp;
3589 1f1af9fd bellard
    int e;
3590 1f1af9fd bellard
3591 1f1af9fd bellard
    temp.d = f;
3592 1f1af9fd bellard
    /* mantissa */
3593 1f1af9fd bellard
    *pmant = (MANTD(temp) << 11) | (1LL << 63);
3594 1f1af9fd bellard
    /* exponent + sign */
3595 1f1af9fd bellard
    e = EXPD(temp) - EXPBIAS + 16383;
3596 1f1af9fd bellard
    e |= SIGND(temp) >> 16;
3597 1f1af9fd bellard
    *pexp = e;
3598 1f1af9fd bellard
}
3599 1f1af9fd bellard
3600 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3601 1f1af9fd bellard
{
3602 1f1af9fd bellard
    CPU86_LDoubleU temp;
3603 1f1af9fd bellard
    int e;
3604 1f1af9fd bellard
    uint64_t ll;
3605 1f1af9fd bellard
3606 1f1af9fd bellard
    /* XXX: handle overflow ? */
3607 1f1af9fd bellard
    e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
3608 1f1af9fd bellard
    e |= (upper >> 4) & 0x800; /* sign */
3609 1f1af9fd bellard
    ll = (mant >> 11) & ((1LL << 52) - 1);
3610 1f1af9fd bellard
#ifdef __arm__
3611 1f1af9fd bellard
    temp.l.upper = (e << 20) | (ll >> 32);
3612 1f1af9fd bellard
    temp.l.lower = ll;
3613 1f1af9fd bellard
#else
3614 1f1af9fd bellard
    temp.ll = ll | ((uint64_t)e << 52);
3615 1f1af9fd bellard
#endif
3616 1f1af9fd bellard
    return temp.d;
3617 1f1af9fd bellard
}
3618 1f1af9fd bellard
3619 1f1af9fd bellard
#else
3620 1f1af9fd bellard
3621 1f1af9fd bellard
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
3622 1f1af9fd bellard
{
3623 1f1af9fd bellard
    CPU86_LDoubleU temp;
3624 1f1af9fd bellard
3625 1f1af9fd bellard
    temp.d = f;
3626 1f1af9fd bellard
    *pmant = temp.l.lower;
3627 1f1af9fd bellard
    *pexp = temp.l.upper;
3628 1f1af9fd bellard
}
3629 1f1af9fd bellard
3630 1f1af9fd bellard
CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
3631 1f1af9fd bellard
{
3632 1f1af9fd bellard
    CPU86_LDoubleU temp;
3633 1f1af9fd bellard
3634 1f1af9fd bellard
    temp.l.upper = upper;
3635 1f1af9fd bellard
    temp.l.lower = mant;
3636 1f1af9fd bellard
    return temp.d;
3637 1f1af9fd bellard
}
3638 1f1af9fd bellard
#endif
3639 1f1af9fd bellard
3640 14ce26e7 bellard
#ifdef TARGET_X86_64
3641 14ce26e7 bellard
3642 14ce26e7 bellard
//#define DEBUG_MULDIV
3643 14ce26e7 bellard
3644 14ce26e7 bellard
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3645 14ce26e7 bellard
{
3646 14ce26e7 bellard
    *plow += a;
3647 14ce26e7 bellard
    /* carry test */
3648 14ce26e7 bellard
    if (*plow < a)
3649 14ce26e7 bellard
        (*phigh)++;
3650 14ce26e7 bellard
    *phigh += b;
3651 14ce26e7 bellard
}
3652 14ce26e7 bellard
3653 14ce26e7 bellard
static void neg128(uint64_t *plow, uint64_t *phigh)
3654 14ce26e7 bellard
{
3655 14ce26e7 bellard
    *plow = ~ *plow;
3656 14ce26e7 bellard
    *phigh = ~ *phigh;
3657 14ce26e7 bellard
    add128(plow, phigh, 1, 0);
3658 14ce26e7 bellard
}
3659 14ce26e7 bellard
3660 45bbbb46 bellard
/* return TRUE if overflow */
3661 45bbbb46 bellard
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3662 14ce26e7 bellard
{
3663 14ce26e7 bellard
    uint64_t q, r, a1, a0;
3664 c0b24a1d bellard
    int i, qb, ab;
3665 14ce26e7 bellard
3666 14ce26e7 bellard
    a0 = *plow;
3667 14ce26e7 bellard
    a1 = *phigh;
3668 14ce26e7 bellard
    if (a1 == 0) {
3669 14ce26e7 bellard
        q = a0 / b;
3670 14ce26e7 bellard
        r = a0 % b;
3671 14ce26e7 bellard
        *plow = q;
3672 14ce26e7 bellard
        *phigh = r;
3673 14ce26e7 bellard
    } else {
3674 45bbbb46 bellard
        if (a1 >= b)
3675 45bbbb46 bellard
            return 1;
3676 14ce26e7 bellard
        /* XXX: use a better algorithm */
3677 14ce26e7 bellard
        for(i = 0; i < 64; i++) {
3678 c0b24a1d bellard
            ab = a1 >> 63;
3679 a8ede8ba bellard
            a1 = (a1 << 1) | (a0 >> 63);
3680 c0b24a1d bellard
            if (ab || a1 >= b) {
3681 14ce26e7 bellard
                a1 -= b;
3682 14ce26e7 bellard
                qb = 1;
3683 14ce26e7 bellard
            } else {
3684 14ce26e7 bellard
                qb = 0;
3685 14ce26e7 bellard
            }
3686 14ce26e7 bellard
            a0 = (a0 << 1) | qb;
3687 14ce26e7 bellard
        }
3688 a8ede8ba bellard
#if defined(DEBUG_MULDIV)
3689 26a76461 bellard
        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
3690 14ce26e7 bellard
               *phigh, *plow, b, a0, a1);
3691 14ce26e7 bellard
#endif
3692 14ce26e7 bellard
        *plow = a0;
3693 14ce26e7 bellard
        *phigh = a1;
3694 14ce26e7 bellard
    }
3695 45bbbb46 bellard
    return 0;
3696 14ce26e7 bellard
}
3697 14ce26e7 bellard
3698 45bbbb46 bellard
/* return TRUE if overflow */
3699 45bbbb46 bellard
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3700 14ce26e7 bellard
{
3701 14ce26e7 bellard
    int sa, sb;
3702 14ce26e7 bellard
    sa = ((int64_t)*phigh < 0);
3703 14ce26e7 bellard
    if (sa)
3704 14ce26e7 bellard
        neg128(plow, phigh);
3705 14ce26e7 bellard
    sb = (b < 0);
3706 14ce26e7 bellard
    if (sb)
3707 14ce26e7 bellard
        b = -b;
3708 45bbbb46 bellard
    if (div64(plow, phigh, b) != 0)
3709 45bbbb46 bellard
        return 1;
3710 45bbbb46 bellard
    if (sa ^ sb) {
3711 45bbbb46 bellard
        if (*plow > (1ULL << 63))
3712 45bbbb46 bellard
            return 1;
3713 14ce26e7 bellard
        *plow = - *plow;
3714 45bbbb46 bellard
    } else {
3715 45bbbb46 bellard
        if (*plow >= (1ULL << 63))
3716 45bbbb46 bellard
            return 1;
3717 45bbbb46 bellard
    }
3718 31313213 bellard
    if (sa)
3719 14ce26e7 bellard
        *phigh = - *phigh;
3720 45bbbb46 bellard
    return 0;
3721 14ce26e7 bellard
}
3722 14ce26e7 bellard
3723 14ce26e7 bellard
void helper_mulq_EAX_T0(void)
3724 14ce26e7 bellard
{
3725 14ce26e7 bellard
    uint64_t r0, r1;
3726 14ce26e7 bellard
3727 69d35728 ths
    mulu64(&r1, &r0, EAX, T0);
3728 14ce26e7 bellard
    EAX = r0;
3729 14ce26e7 bellard
    EDX = r1;
3730 14ce26e7 bellard
    CC_DST = r0;
3731 14ce26e7 bellard
    CC_SRC = r1;
3732 14ce26e7 bellard
}
3733 14ce26e7 bellard
3734 14ce26e7 bellard
void helper_imulq_EAX_T0(void)
3735 14ce26e7 bellard
{
3736 14ce26e7 bellard
    uint64_t r0, r1;
3737 14ce26e7 bellard
3738 69d35728 ths
    muls64(&r1, &r0, EAX, T0);
3739 14ce26e7 bellard
    EAX = r0;
3740 14ce26e7 bellard
    EDX = r1;
3741 14ce26e7 bellard
    CC_DST = r0;
3742 a8ede8ba bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3743 14ce26e7 bellard
}
3744 14ce26e7 bellard
3745 14ce26e7 bellard
void helper_imulq_T0_T1(void)
3746 14ce26e7 bellard
{
3747 14ce26e7 bellard
    uint64_t r0, r1;
3748 14ce26e7 bellard
3749 69d35728 ths
    muls64(&r1, &r0, T0, T1);
3750 14ce26e7 bellard
    T0 = r0;
3751 14ce26e7 bellard
    CC_DST = r0;
3752 14ce26e7 bellard
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3753 14ce26e7 bellard
}
3754 14ce26e7 bellard
3755 14ce26e7 bellard
void helper_divq_EAX_T0(void)
3756 14ce26e7 bellard
{
3757 14ce26e7 bellard
    uint64_t r0, r1;
3758 14ce26e7 bellard
    if (T0 == 0) {
3759 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3760 14ce26e7 bellard
    }
3761 14ce26e7 bellard
    r0 = EAX;
3762 14ce26e7 bellard
    r1 = EDX;
3763 45bbbb46 bellard
    if (div64(&r0, &r1, T0))
3764 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3765 14ce26e7 bellard
    EAX = r0;
3766 14ce26e7 bellard
    EDX = r1;
3767 14ce26e7 bellard
}
3768 14ce26e7 bellard
3769 14ce26e7 bellard
void helper_idivq_EAX_T0(void)
3770 14ce26e7 bellard
{
3771 14ce26e7 bellard
    uint64_t r0, r1;
3772 14ce26e7 bellard
    if (T0 == 0) {
3773 14ce26e7 bellard
        raise_exception(EXCP00_DIVZ);
3774 14ce26e7 bellard
    }
3775 14ce26e7 bellard
    r0 = EAX;
3776 14ce26e7 bellard
    r1 = EDX;
3777 45bbbb46 bellard
    if (idiv64(&r0, &r1, T0))
3778 45bbbb46 bellard
        raise_exception(EXCP00_DIVZ);
3779 14ce26e7 bellard
    EAX = r0;
3780 14ce26e7 bellard
    EDX = r1;
3781 14ce26e7 bellard
}
3782 14ce26e7 bellard
3783 68cae3d8 bellard
void helper_bswapq_T0(void)
3784 68cae3d8 bellard
{
3785 68cae3d8 bellard
    T0 = bswap64(T0);
3786 68cae3d8 bellard
}
3787 14ce26e7 bellard
#endif
3788 14ce26e7 bellard
3789 3d7374c5 bellard
void helper_hlt(void)
3790 3d7374c5 bellard
{
3791 3d7374c5 bellard
    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
3792 3d7374c5 bellard
    env->hflags |= HF_HALTED_MASK;
3793 3d7374c5 bellard
    env->exception_index = EXCP_HLT;
3794 3d7374c5 bellard
    cpu_loop_exit();
3795 3d7374c5 bellard
}
3796 3d7374c5 bellard
3797 3d7374c5 bellard
void helper_monitor(void)
3798 3d7374c5 bellard
{
3799 d80c7d1c bellard
    if ((uint32_t)ECX != 0)
3800 3d7374c5 bellard
        raise_exception(EXCP0D_GPF);
3801 3d7374c5 bellard
    /* XXX: store address ? */
3802 3d7374c5 bellard
}
3803 3d7374c5 bellard
3804 3d7374c5 bellard
void helper_mwait(void)
3805 3d7374c5 bellard
{
3806 d80c7d1c bellard
    if ((uint32_t)ECX != 0)
3807 3d7374c5 bellard
        raise_exception(EXCP0D_GPF);
3808 3d7374c5 bellard
    /* XXX: not complete but not completely erroneous */
3809 3d7374c5 bellard
    if (env->cpu_index != 0 || env->next_cpu != NULL) {
3810 3d7374c5 bellard
        /* more than one CPU: do not sleep because another CPU may
3811 3d7374c5 bellard
           wake this one */
3812 3d7374c5 bellard
    } else {
3813 3d7374c5 bellard
        helper_hlt();
3814 3d7374c5 bellard
    }
3815 3d7374c5 bellard
}
3816 3d7374c5 bellard
3817 664e0f19 bellard
float approx_rsqrt(float a)
3818 664e0f19 bellard
{
3819 664e0f19 bellard
    return 1.0 / sqrt(a);
3820 664e0f19 bellard
}
3821 664e0f19 bellard
3822 664e0f19 bellard
float approx_rcp(float a)
3823 664e0f19 bellard
{
3824 664e0f19 bellard
    return 1.0 / a;
3825 664e0f19 bellard
}
3826 664e0f19 bellard
3827 7a0e1f41 bellard
void update_fp_status(void)
3828 4d6b6c0a bellard
{
3829 7a0e1f41 bellard
    int rnd_type;
3830 4d6b6c0a bellard
3831 7a0e1f41 bellard
    /* set rounding mode */
3832 7a0e1f41 bellard
    switch(env->fpuc & RC_MASK) {
3833 7a0e1f41 bellard
    default:
3834 7a0e1f41 bellard
    case RC_NEAR:
3835 7a0e1f41 bellard
        rnd_type = float_round_nearest_even;
3836 7a0e1f41 bellard
        break;
3837 7a0e1f41 bellard
    case RC_DOWN:
3838 7a0e1f41 bellard
        rnd_type = float_round_down;
3839 7a0e1f41 bellard
        break;
3840 7a0e1f41 bellard
    case RC_UP:
3841 7a0e1f41 bellard
        rnd_type = float_round_up;
3842 7a0e1f41 bellard
        break;
3843 7a0e1f41 bellard
    case RC_CHOP:
3844 7a0e1f41 bellard
        rnd_type = float_round_to_zero;
3845 7a0e1f41 bellard
        break;
3846 7a0e1f41 bellard
    }
3847 7a0e1f41 bellard
    set_float_rounding_mode(rnd_type, &env->fp_status);
3848 7a0e1f41 bellard
#ifdef FLOATX80
3849 7a0e1f41 bellard
    switch((env->fpuc >> 8) & 3) {
3850 7a0e1f41 bellard
    case 0:
3851 7a0e1f41 bellard
        rnd_type = 32;
3852 7a0e1f41 bellard
        break;
3853 7a0e1f41 bellard
    case 2:
3854 7a0e1f41 bellard
        rnd_type = 64;
3855 7a0e1f41 bellard
        break;
3856 7a0e1f41 bellard
    case 3:
3857 7a0e1f41 bellard
    default:
3858 7a0e1f41 bellard
        rnd_type = 80;
3859 7a0e1f41 bellard
        break;
3860 7a0e1f41 bellard
    }
3861 7a0e1f41 bellard
    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
3862 4d6b6c0a bellard
#endif
3863 7a0e1f41 bellard
}
3864 664e0f19 bellard
3865 5fafdf24 ths
#if !defined(CONFIG_USER_ONLY)
3866 61382a50 bellard
3867 61382a50 bellard
#define MMUSUFFIX _mmu
3868 61382a50 bellard
#define GETPC() (__builtin_return_address(0))
3869 61382a50 bellard
3870 2c0262af bellard
#define SHIFT 0
3871 2c0262af bellard
#include "softmmu_template.h"
3872 2c0262af bellard
3873 2c0262af bellard
#define SHIFT 1
3874 2c0262af bellard
#include "softmmu_template.h"
3875 2c0262af bellard
3876 2c0262af bellard
#define SHIFT 2
3877 2c0262af bellard
#include "softmmu_template.h"
3878 2c0262af bellard
3879 2c0262af bellard
#define SHIFT 3
3880 2c0262af bellard
#include "softmmu_template.h"
3881 2c0262af bellard
3882 61382a50 bellard
#endif
3883 61382a50 bellard
3884 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
3885 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
3886 61382a50 bellard
   from generated code or from helper.c) */
3887 61382a50 bellard
/* XXX: fix it to restore all registers */
3888 14ce26e7 bellard
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
3889 2c0262af bellard
{
3890 2c0262af bellard
    TranslationBlock *tb;
3891 2c0262af bellard
    int ret;
3892 2c0262af bellard
    unsigned long pc;
3893 61382a50 bellard
    CPUX86State *saved_env;
3894 61382a50 bellard
3895 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
3896 61382a50 bellard
       generated code */
3897 61382a50 bellard
    saved_env = env;
3898 61382a50 bellard
    env = cpu_single_env;
3899 61382a50 bellard
3900 61382a50 bellard
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
3901 2c0262af bellard
    if (ret) {
3902 61382a50 bellard
        if (retaddr) {
3903 61382a50 bellard
            /* now we have a real cpu fault */
3904 61382a50 bellard
            pc = (unsigned long)retaddr;
3905 61382a50 bellard
            tb = tb_find_pc(pc);
3906 61382a50 bellard
            if (tb) {
3907 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
3908 61382a50 bellard
                   a virtual CPU fault */
3909 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
3910 61382a50 bellard
            }
3911 2c0262af bellard
        }
3912 0d1a29f9 bellard
        if (retaddr)
3913 54ca9095 bellard
            raise_exception_err(env->exception_index, env->error_code);
3914 0d1a29f9 bellard
        else
3915 54ca9095 bellard
            raise_exception_err_norestore(env->exception_index, env->error_code);
3916 2c0262af bellard
    }
3917 61382a50 bellard
    env = saved_env;
3918 2c0262af bellard
}
3919 0573fbfc ths
3920 0573fbfc ths
3921 0573fbfc ths
/* Secure Virtual Machine helpers */
3922 0573fbfc ths
3923 0573fbfc ths
void helper_stgi(void)
3924 0573fbfc ths
{
3925 0573fbfc ths
    env->hflags |= HF_GIF_MASK;
3926 0573fbfc ths
}
3927 0573fbfc ths
3928 0573fbfc ths
void helper_clgi(void)
3929 0573fbfc ths
{
3930 0573fbfc ths
    env->hflags &= ~HF_GIF_MASK;
3931 0573fbfc ths
}
3932 0573fbfc ths
3933 0573fbfc ths
#if defined(CONFIG_USER_ONLY)
3934 0573fbfc ths
3935 0573fbfc ths
void helper_vmrun(target_ulong addr) { }
3936 0573fbfc ths
void helper_vmmcall(void) { }
3937 0573fbfc ths
void helper_vmload(target_ulong addr) { }
3938 0573fbfc ths
void helper_vmsave(target_ulong addr) { }
3939 0573fbfc ths
void helper_skinit(void) { }
3940 0573fbfc ths
void helper_invlpga(void) { }
3941 0573fbfc ths
void vmexit(uint64_t exit_code, uint64_t exit_info_1) { }
3942 0573fbfc ths
int svm_check_intercept_param(uint32_t type, uint64_t param)
3943 0573fbfc ths
{
3944 0573fbfc ths
    return 0;
3945 0573fbfc ths
}
3946 0573fbfc ths
3947 0573fbfc ths
#else
3948 0573fbfc ths
3949 0573fbfc ths
static inline uint32_t
3950 0573fbfc ths
vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit)
3951 0573fbfc ths
{
3952 0573fbfc ths
    return    ((vmcb_attrib & 0x00ff) << 8)          /* Type, S, DPL, P */
3953 0573fbfc ths
            | ((vmcb_attrib & 0x0f00) << 12)         /* AVL, L, DB, G */
3954 0573fbfc ths
            | ((vmcb_base >> 16) & 0xff)             /* Base 23-16 */
3955 0573fbfc ths
            | (vmcb_base & 0xff000000)               /* Base 31-24 */
3956 0573fbfc ths
            | (vmcb_limit & 0xf0000);                /* Limit 19-16 */
3957 0573fbfc ths
}
3958 0573fbfc ths
3959 0573fbfc ths
static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib)
3960 0573fbfc ths
{
3961 0573fbfc ths
    return    ((cpu_attrib >> 8) & 0xff)             /* Type, S, DPL, P */
3962 0573fbfc ths
            | ((cpu_attrib & 0xf00000) >> 12);       /* AVL, L, DB, G */
3963 0573fbfc ths
}
3964 0573fbfc ths
3965 0573fbfc ths
extern uint8_t *phys_ram_base;
3966 0573fbfc ths
void helper_vmrun(target_ulong addr)
3967 0573fbfc ths
{
3968 0573fbfc ths
    uint32_t event_inj;
3969 0573fbfc ths
    uint32_t int_ctl;
3970 0573fbfc ths
3971 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
3972 0573fbfc ths
        fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
3973 0573fbfc ths
3974 0573fbfc ths
    env->vm_vmcb = addr;
3975 0573fbfc ths
    regs_to_env();
3976 0573fbfc ths
3977 0573fbfc ths
    /* save the current CPU state in the hsave page */
3978 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
3979 0573fbfc ths
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
3980 0573fbfc ths
3981 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
3982 0573fbfc ths
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
3983 0573fbfc ths
3984 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
3985 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
3986 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
3987 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
3988 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]);
3989 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
3990 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
3991 0573fbfc ths
3992 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
3993 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
3994 0573fbfc ths
3995 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es);
3996 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs);
3997 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss);
3998 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds);
3999 0573fbfc ths
4000 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP);
4001 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4002 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4003 0573fbfc ths
4004 0573fbfc ths
    /* load the interception bitmaps so we do not need to access the
4005 0573fbfc ths
       vmcb in svm mode */
4006 0573fbfc ths
    /* We shift all the intercept bits so we can OR them with the TB
4007 0573fbfc ths
       flags later on */
4008 0573fbfc ths
    env->intercept            = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK;
4009 0573fbfc ths
    env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4010 0573fbfc ths
    env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4011 0573fbfc ths
    env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4012 0573fbfc ths
    env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4013 0573fbfc ths
    env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4014 0573fbfc ths
4015 0573fbfc ths
    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4016 0573fbfc ths
    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4017 0573fbfc ths
4018 0573fbfc ths
    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4019 0573fbfc ths
    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4020 0573fbfc ths
4021 0573fbfc ths
    /* clear exit_info_2 so we behave like the real hardware */
4022 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4023 0573fbfc ths
4024 0573fbfc ths
    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4025 0573fbfc ths
    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4026 0573fbfc ths
    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4027 0573fbfc ths
    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4028 0573fbfc ths
    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
4029 0573fbfc ths
    if (int_ctl & V_INTR_MASKING_MASK) {
4030 0573fbfc ths
        env->cr[8] = int_ctl & V_TPR_MASK;
4031 0573fbfc ths
        if (env->eflags & IF_MASK)
4032 0573fbfc ths
            env->hflags |= HF_HIF_MASK;
4033 0573fbfc ths
    }
4034 0573fbfc ths
4035 0573fbfc ths
#ifdef TARGET_X86_64
4036 0573fbfc ths
    env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer));
4037 0573fbfc ths
    env->hflags &= ~HF_LMA_MASK;
4038 0573fbfc ths
    if (env->efer & MSR_EFER_LMA)
4039 0573fbfc ths
       env->hflags |= HF_LMA_MASK;
4040 0573fbfc ths
#endif
4041 0573fbfc ths
    env->eflags = 0;
4042 0573fbfc ths
    load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
4043 0573fbfc ths
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4044 0573fbfc ths
    CC_OP = CC_OP_EFLAGS;
4045 0573fbfc ths
    CC_DST = 0xffffffff;
4046 0573fbfc ths
4047 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, ES, es);
4048 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, CS, cs);
4049 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, SS, ss);
4050 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, DS, ds);
4051 0573fbfc ths
4052 0573fbfc ths
    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
4053 0573fbfc ths
    env->eip = EIP;
4054 0573fbfc ths
    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
4055 0573fbfc ths
    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
4056 0573fbfc ths
    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
4057 0573fbfc ths
    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
4058 0573fbfc ths
    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
4059 0573fbfc ths
4060 0573fbfc ths
    /* FIXME: guest state consistency checks */
4061 0573fbfc ths
4062 0573fbfc ths
    switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
4063 0573fbfc ths
        case TLB_CONTROL_DO_NOTHING:
4064 0573fbfc ths
            break;
4065 0573fbfc ths
        case TLB_CONTROL_FLUSH_ALL_ASID:
4066 0573fbfc ths
            /* FIXME: this is not 100% correct but should work for now */
4067 0573fbfc ths
            tlb_flush(env, 1);
4068 0573fbfc ths
        break;
4069 0573fbfc ths
    }
4070 0573fbfc ths
4071 0573fbfc ths
    helper_stgi();
4072 0573fbfc ths
4073 0573fbfc ths
    regs_to_env();
4074 0573fbfc ths
4075 0573fbfc ths
    /* maybe we need to inject an event */
4076 0573fbfc ths
    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
4077 0573fbfc ths
    if (event_inj & SVM_EVTINJ_VALID) {
4078 0573fbfc ths
        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4079 0573fbfc ths
        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
4080 0573fbfc ths
        uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
4081 0573fbfc ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
4082 0573fbfc ths
4083 0573fbfc ths
        if (loglevel & CPU_LOG_TB_IN_ASM)
4084 0573fbfc ths
            fprintf(logfile, "Injecting(%#hx): ", valid_err);
4085 0573fbfc ths
        /* FIXME: need to implement valid_err */
4086 0573fbfc ths
        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4087 0573fbfc ths
        case SVM_EVTINJ_TYPE_INTR:
4088 0573fbfc ths
                env->exception_index = vector;
4089 0573fbfc ths
                env->error_code = event_inj_err;
4090 0573fbfc ths
                env->exception_is_int = 1;
4091 0573fbfc ths
                env->exception_next_eip = -1;
4092 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4093 0573fbfc ths
                    fprintf(logfile, "INTR");
4094 0573fbfc ths
                break;
4095 0573fbfc ths
        case SVM_EVTINJ_TYPE_NMI:
4096 0573fbfc ths
                env->exception_index = vector;
4097 0573fbfc ths
                env->error_code = event_inj_err;
4098 0573fbfc ths
                env->exception_is_int = 1;
4099 0573fbfc ths
                env->exception_next_eip = EIP;
4100 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4101 0573fbfc ths
                    fprintf(logfile, "NMI");
4102 0573fbfc ths
                break;
4103 0573fbfc ths
        case SVM_EVTINJ_TYPE_EXEPT:
4104 0573fbfc ths
                env->exception_index = vector;
4105 0573fbfc ths
                env->error_code = event_inj_err;
4106 0573fbfc ths
                env->exception_is_int = 0;
4107 0573fbfc ths
                env->exception_next_eip = -1;
4108 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4109 0573fbfc ths
                    fprintf(logfile, "EXEPT");
4110 0573fbfc ths
                break;
4111 0573fbfc ths
        case SVM_EVTINJ_TYPE_SOFT:
4112 0573fbfc ths
                env->exception_index = vector;
4113 0573fbfc ths
                env->error_code = event_inj_err;
4114 0573fbfc ths
                env->exception_is_int = 1;
4115 0573fbfc ths
                env->exception_next_eip = EIP;
4116 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4117 0573fbfc ths
                    fprintf(logfile, "SOFT");
4118 0573fbfc ths
                break;
4119 0573fbfc ths
        }
4120 0573fbfc ths
        if (loglevel & CPU_LOG_TB_IN_ASM)
4121 0573fbfc ths
            fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
4122 0573fbfc ths
    }
4123 52621688 ths
    if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) {
4124 0573fbfc ths
        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
4125 52621688 ths
    }
4126 0573fbfc ths
4127 0573fbfc ths
    cpu_loop_exit();
4128 0573fbfc ths
}
4129 0573fbfc ths
4130 0573fbfc ths
void helper_vmmcall(void)
4131 0573fbfc ths
{
4132 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4133 0573fbfc ths
        fprintf(logfile,"vmmcall!\n");
4134 0573fbfc ths
}
4135 0573fbfc ths
4136 0573fbfc ths
void helper_vmload(target_ulong addr)
4137 0573fbfc ths
{
4138 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4139 0573fbfc ths
        fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4140 0573fbfc ths
                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4141 0573fbfc ths
                env->segs[R_FS].base);
4142 0573fbfc ths
4143 0573fbfc ths
    SVM_LOAD_SEG2(addr, segs[R_FS], fs);
4144 0573fbfc ths
    SVM_LOAD_SEG2(addr, segs[R_GS], gs);
4145 0573fbfc ths
    SVM_LOAD_SEG2(addr, tr, tr);
4146 0573fbfc ths
    SVM_LOAD_SEG2(addr, ldt, ldtr);
4147 0573fbfc ths
4148 0573fbfc ths
#ifdef TARGET_X86_64
4149 0573fbfc ths
    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
4150 0573fbfc ths
    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
4151 0573fbfc ths
    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
4152 0573fbfc ths
    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
4153 0573fbfc ths
#endif
4154 0573fbfc ths
    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
4155 0573fbfc ths
    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
4156 0573fbfc ths
    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
4157 0573fbfc ths
    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
4158 0573fbfc ths
}
4159 0573fbfc ths
4160 0573fbfc ths
void helper_vmsave(target_ulong addr)
4161 0573fbfc ths
{
4162 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4163 0573fbfc ths
        fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4164 0573fbfc ths
                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4165 0573fbfc ths
                env->segs[R_FS].base);
4166 0573fbfc ths
4167 0573fbfc ths
    SVM_SAVE_SEG(addr, segs[R_FS], fs);
4168 0573fbfc ths
    SVM_SAVE_SEG(addr, segs[R_GS], gs);
4169 0573fbfc ths
    SVM_SAVE_SEG(addr, tr, tr);
4170 0573fbfc ths
    SVM_SAVE_SEG(addr, ldt, ldtr);
4171 0573fbfc ths
4172 0573fbfc ths
#ifdef TARGET_X86_64
4173 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
4174 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
4175 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
4176 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
4177 0573fbfc ths
#endif
4178 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
4179 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
4180 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
4181 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
4182 0573fbfc ths
}
4183 0573fbfc ths
4184 0573fbfc ths
void helper_skinit(void)
4185 0573fbfc ths
{
4186 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4187 0573fbfc ths
        fprintf(logfile,"skinit!\n");
4188 0573fbfc ths
}
4189 0573fbfc ths
4190 0573fbfc ths
void helper_invlpga(void)
4191 0573fbfc ths
{
4192 0573fbfc ths
    tlb_flush(env, 0);
4193 0573fbfc ths
}
4194 0573fbfc ths
4195 0573fbfc ths
int svm_check_intercept_param(uint32_t type, uint64_t param)
4196 0573fbfc ths
{
4197 0573fbfc ths
    switch(type) {
4198 0573fbfc ths
    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
4199 0573fbfc ths
        if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) {
4200 0573fbfc ths
            vmexit(type, param);
4201 0573fbfc ths
            return 1;
4202 0573fbfc ths
        }
4203 0573fbfc ths
        break;
4204 0573fbfc ths
    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8:
4205 0573fbfc ths
        if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) {
4206 0573fbfc ths
            vmexit(type, param);
4207 0573fbfc ths
            return 1;
4208 0573fbfc ths
        }
4209 0573fbfc ths
        break;
4210 0573fbfc ths
    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
4211 0573fbfc ths
        if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) {
4212 0573fbfc ths
            vmexit(type, param);
4213 0573fbfc ths
            return 1;
4214 0573fbfc ths
        }
4215 0573fbfc ths
        break;
4216 0573fbfc ths
    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8:
4217 0573fbfc ths
        if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) {
4218 0573fbfc ths
            vmexit(type, param);
4219 0573fbfc ths
            return 1;
4220 0573fbfc ths
        }
4221 0573fbfc ths
        break;
4222 0573fbfc ths
    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16:
4223 0573fbfc ths
        if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) {
4224 0573fbfc ths
            vmexit(type, param);
4225 0573fbfc ths
            return 1;
4226 0573fbfc ths
        }
4227 0573fbfc ths
        break;
4228 0573fbfc ths
    case SVM_EXIT_IOIO:
4229 0573fbfc ths
        if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) {
4230 0573fbfc ths
            /* FIXME: this should be read in at vmrun (faster this way?) */
4231 0573fbfc ths
            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
4232 0573fbfc ths
            uint16_t port = (uint16_t) (param >> 16);
4233 0573fbfc ths
4234 0573fbfc ths
            if(ldub_phys(addr + port / 8) & (1 << (port % 8)))
4235 0573fbfc ths
                vmexit(type, param);
4236 0573fbfc ths
        }
4237 0573fbfc ths
        break;
4238 0573fbfc ths
4239 0573fbfc ths
    case SVM_EXIT_MSR:
4240 0573fbfc ths
        if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) {
4241 0573fbfc ths
            /* FIXME: this should be read in at vmrun (faster this way?) */
4242 0573fbfc ths
            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
4243 0573fbfc ths
            switch((uint32_t)ECX) {
4244 0573fbfc ths
            case 0 ... 0x1fff:
4245 0573fbfc ths
                T0 = (ECX * 2) % 8;
4246 0573fbfc ths
                T1 = ECX / 8;
4247 0573fbfc ths
                break;
4248 0573fbfc ths
            case 0xc0000000 ... 0xc0001fff:
4249 0573fbfc ths
                T0 = (8192 + ECX - 0xc0000000) * 2;
4250 0573fbfc ths
                T1 = (T0 / 8);
4251 0573fbfc ths
                T0 %= 8;
4252 0573fbfc ths
                break;
4253 0573fbfc ths
            case 0xc0010000 ... 0xc0011fff:
4254 0573fbfc ths
                T0 = (16384 + ECX - 0xc0010000) * 2;
4255 0573fbfc ths
                T1 = (T0 / 8);
4256 0573fbfc ths
                T0 %= 8;
4257 0573fbfc ths
                break;
4258 0573fbfc ths
            default:
4259 0573fbfc ths
                vmexit(type, param);
4260 0573fbfc ths
                return 1;
4261 0573fbfc ths
            }
4262 0573fbfc ths
            if (ldub_phys(addr + T1) & ((1 << param) << T0))
4263 0573fbfc ths
                vmexit(type, param);
4264 0573fbfc ths
            return 1;
4265 0573fbfc ths
        }
4266 0573fbfc ths
        break;
4267 0573fbfc ths
    default:
4268 0573fbfc ths
        if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) {
4269 0573fbfc ths
            vmexit(type, param);
4270 0573fbfc ths
            return 1;
4271 0573fbfc ths
        }
4272 0573fbfc ths
        break;
4273 0573fbfc ths
    }
4274 0573fbfc ths
    return 0;
4275 0573fbfc ths
}
4276 0573fbfc ths
4277 0573fbfc ths
void vmexit(uint64_t exit_code, uint64_t exit_info_1)
4278 0573fbfc ths
{
4279 0573fbfc ths
    uint32_t int_ctl;
4280 0573fbfc ths
4281 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4282 0573fbfc ths
        fprintf(logfile,"vmexit(%016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
4283 0573fbfc ths
                exit_code, exit_info_1,
4284 0573fbfc ths
                ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
4285 0573fbfc ths
                EIP);
4286 0573fbfc ths
4287 52621688 ths
    if(env->hflags & HF_INHIBIT_IRQ_MASK) {
4288 52621688 ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
4289 52621688 ths
        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4290 52621688 ths
    } else {
4291 52621688 ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
4292 52621688 ths
    }
4293 52621688 ths
4294 0573fbfc ths
    /* Save the VM state in the vmcb */
4295 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es);
4296 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs);
4297 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss);
4298 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds);
4299 0573fbfc ths
4300 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4301 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4302 0573fbfc ths
4303 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4304 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4305 0573fbfc ths
4306 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
4307 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
4308 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
4309 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
4310 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
4311 0573fbfc ths
4312 0573fbfc ths
    if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) {
4313 0573fbfc ths
        int_ctl &= ~V_TPR_MASK;
4314 0573fbfc ths
        int_ctl |= env->cr[8] & V_TPR_MASK;
4315 0573fbfc ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
4316 0573fbfc ths
    }
4317 0573fbfc ths
4318 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
4319 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
4320 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
4321 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
4322 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
4323 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
4324 0573fbfc ths
    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
4325 0573fbfc ths
4326 0573fbfc ths
    /* Reload the host state from vm_hsave */
4327 0573fbfc ths
    env->hflags &= ~HF_HIF_MASK;
4328 0573fbfc ths
    env->intercept = 0;
4329 0573fbfc ths
    env->intercept_exceptions = 0;
4330 0573fbfc ths
    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
4331 0573fbfc ths
4332 0573fbfc ths
    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
4333 0573fbfc ths
    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
4334 0573fbfc ths
4335 0573fbfc ths
    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
4336 0573fbfc ths
    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
4337 0573fbfc ths
4338 0573fbfc ths
    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
4339 0573fbfc ths
    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
4340 0573fbfc ths
    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
4341 0573fbfc ths
    if (int_ctl & V_INTR_MASKING_MASK)
4342 0573fbfc ths
        env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8));
4343 0573fbfc ths
    /* we need to set the efer after the crs so the hidden flags get set properly */
4344 0573fbfc ths
#ifdef TARGET_X86_64
4345 0573fbfc ths
    env->efer  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer));
4346 0573fbfc ths
    env->hflags &= ~HF_LMA_MASK;
4347 0573fbfc ths
    if (env->efer & MSR_EFER_LMA)
4348 0573fbfc ths
       env->hflags |= HF_LMA_MASK;
4349 0573fbfc ths
#endif
4350 0573fbfc ths
4351 0573fbfc ths
    env->eflags = 0;
4352 0573fbfc ths
    load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
4353 0573fbfc ths
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4354 0573fbfc ths
    CC_OP = CC_OP_EFLAGS;
4355 0573fbfc ths
4356 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, ES, es);
4357 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, CS, cs);
4358 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, SS, ss);
4359 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, DS, ds);
4360 0573fbfc ths
4361 0573fbfc ths
    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
4362 0573fbfc ths
    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
4363 0573fbfc ths
    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
4364 0573fbfc ths
4365 0573fbfc ths
    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
4366 0573fbfc ths
    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
4367 0573fbfc ths
4368 0573fbfc ths
    /* other setups */
4369 0573fbfc ths
    cpu_x86_set_cpl(env, 0);
4370 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32));
4371 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
4372 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
4373 0573fbfc ths
4374 0573fbfc ths
    helper_clgi();
4375 0573fbfc ths
    /* FIXME: Resets the current ASID register to zero (host ASID). */
4376 0573fbfc ths
4377 0573fbfc ths
    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
4378 0573fbfc ths
4379 0573fbfc ths
    /* Clears the TSC_OFFSET inside the processor. */
4380 0573fbfc ths
4381 0573fbfc ths
    /* If the host is in PAE mode, the processor reloads the host's PDPEs
4382 0573fbfc ths
       from the page table indicated the host's CR3. If the PDPEs contain
4383 0573fbfc ths
       illegal state, the processor causes a shutdown. */
4384 0573fbfc ths
4385 0573fbfc ths
    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
4386 0573fbfc ths
    env->cr[0] |= CR0_PE_MASK;
4387 0573fbfc ths
    env->eflags &= ~VM_MASK;
4388 0573fbfc ths
4389 0573fbfc ths
    /* Disables all breakpoints in the host DR7 register. */
4390 0573fbfc ths
4391 0573fbfc ths
    /* Checks the reloaded host state for consistency. */
4392 0573fbfc ths
4393 0573fbfc ths
    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
4394 0573fbfc ths
       host's code segment or non-canonical (in the case of long mode), a
4395 0573fbfc ths
       #GP fault is delivered inside the host.) */
4396 0573fbfc ths
4397 0573fbfc ths
    /* remove any pending exception */
4398 0573fbfc ths
    env->exception_index = -1;
4399 0573fbfc ths
    env->error_code = 0;
4400 0573fbfc ths
    env->old_exception = -1;
4401 0573fbfc ths
4402 0573fbfc ths
    regs_to_env();
4403 0573fbfc ths
    cpu_loop_exit();
4404 0573fbfc ths
}
4405 0573fbfc ths
4406 0573fbfc ths
#endif