Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 1570de2d

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