Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 9596ebb7

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