Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 19e6c4b8

History | View | Annotate | Download (138.5 kB)

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