Statistics
| Branch: | Revision:

root / target-i386 / helper.c @ 1b9d9ebb

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

4611 b5b38f61 bellard
void helper_sti_vm(void)
4612 b5b38f61 bellard
{
4613 b5b38f61 bellard
    env->eflags |= VIF_MASK;
4614 b5b38f61 bellard
    if (env->eflags & VIP_MASK) {
4615 b5b38f61 bellard
        raise_exception(EXCP0D_GPF);
4616 7a0e1f41 bellard
    }
4617 b5b38f61 bellard
}
4618 4d6b6c0a bellard
#endif
4619 b5b38f61 bellard
4620 b5b38f61 bellard
void helper_set_inhibit_irq(void)
4621 b5b38f61 bellard
{
4622 b5b38f61 bellard
    env->hflags |= HF_INHIBIT_IRQ_MASK;
4623 b5b38f61 bellard
}
4624 b5b38f61 bellard
4625 b5b38f61 bellard
void helper_reset_inhibit_irq(void)
4626 b5b38f61 bellard
{
4627 b5b38f61 bellard
    env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4628 b5b38f61 bellard
}
4629 b5b38f61 bellard
4630 b8b6a50b bellard
void helper_boundw(target_ulong a0, int v)
4631 b5b38f61 bellard
{
4632 b8b6a50b bellard
    int low, high;
4633 b8b6a50b bellard
    low = ldsw(a0);
4634 b8b6a50b bellard
    high = ldsw(a0 + 2);
4635 b8b6a50b bellard
    v = (int16_t)v;
4636 b5b38f61 bellard
    if (v < low || v > high) {
4637 b5b38f61 bellard
        raise_exception(EXCP05_BOUND);
4638 b5b38f61 bellard
    }
4639 b5b38f61 bellard
    FORCE_RET();
4640 b5b38f61 bellard
}
4641 b5b38f61 bellard
4642 b8b6a50b bellard
void helper_boundl(target_ulong a0, int v)
4643 b5b38f61 bellard
{
4644 b8b6a50b bellard
    int low, high;
4645 b8b6a50b bellard
    low = ldl(a0);
4646 b8b6a50b bellard
    high = ldl(a0 + 4);
4647 b5b38f61 bellard
    if (v < low || v > high) {
4648 b5b38f61 bellard
        raise_exception(EXCP05_BOUND);
4649 b5b38f61 bellard
    }
4650 b5b38f61 bellard
    FORCE_RET();
4651 b5b38f61 bellard
}
4652 b5b38f61 bellard
4653 b5b38f61 bellard
static float approx_rsqrt(float a)
4654 b5b38f61 bellard
{
4655 b5b38f61 bellard
    return 1.0 / sqrt(a);
4656 b5b38f61 bellard
}
4657 b5b38f61 bellard
4658 b5b38f61 bellard
static float approx_rcp(float a)
4659 b5b38f61 bellard
{
4660 b5b38f61 bellard
    return 1.0 / a;
4661 7a0e1f41 bellard
}
4662 664e0f19 bellard
4663 5fafdf24 ths
#if !defined(CONFIG_USER_ONLY)
4664 61382a50 bellard
4665 61382a50 bellard
#define MMUSUFFIX _mmu
4666 273af660 ths
#ifdef __s390__
4667 273af660 ths
# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
4668 273af660 ths
#else
4669 273af660 ths
# define GETPC() (__builtin_return_address(0))
4670 273af660 ths
#endif
4671 61382a50 bellard
4672 2c0262af bellard
#define SHIFT 0
4673 2c0262af bellard
#include "softmmu_template.h"
4674 2c0262af bellard
4675 2c0262af bellard
#define SHIFT 1
4676 2c0262af bellard
#include "softmmu_template.h"
4677 2c0262af bellard
4678 2c0262af bellard
#define SHIFT 2
4679 2c0262af bellard
#include "softmmu_template.h"
4680 2c0262af bellard
4681 2c0262af bellard
#define SHIFT 3
4682 2c0262af bellard
#include "softmmu_template.h"
4683 2c0262af bellard
4684 61382a50 bellard
#endif
4685 61382a50 bellard
4686 61382a50 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
4687 61382a50 bellard
   NULL, it means that the function was called in C code (i.e. not
4688 61382a50 bellard
   from generated code or from helper.c) */
4689 61382a50 bellard
/* XXX: fix it to restore all registers */
4690 6ebbf390 j_mayer
void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
4691 2c0262af bellard
{
4692 2c0262af bellard
    TranslationBlock *tb;
4693 2c0262af bellard
    int ret;
4694 2c0262af bellard
    unsigned long pc;
4695 61382a50 bellard
    CPUX86State *saved_env;
4696 61382a50 bellard
4697 61382a50 bellard
    /* XXX: hack to restore env in all cases, even if not called from
4698 61382a50 bellard
       generated code */
4699 61382a50 bellard
    saved_env = env;
4700 61382a50 bellard
    env = cpu_single_env;
4701 61382a50 bellard
4702 6ebbf390 j_mayer
    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
4703 2c0262af bellard
    if (ret) {
4704 61382a50 bellard
        if (retaddr) {
4705 61382a50 bellard
            /* now we have a real cpu fault */
4706 61382a50 bellard
            pc = (unsigned long)retaddr;
4707 61382a50 bellard
            tb = tb_find_pc(pc);
4708 61382a50 bellard
            if (tb) {
4709 61382a50 bellard
                /* the PC is inside the translated code. It means that we have
4710 61382a50 bellard
                   a virtual CPU fault */
4711 58fe2f10 bellard
                cpu_restore_state(tb, env, pc, NULL);
4712 61382a50 bellard
            }
4713 2c0262af bellard
        }
4714 0d1a29f9 bellard
        if (retaddr)
4715 54ca9095 bellard
            raise_exception_err(env->exception_index, env->error_code);
4716 0d1a29f9 bellard
        else
4717 54ca9095 bellard
            raise_exception_err_norestore(env->exception_index, env->error_code);
4718 2c0262af bellard
    }
4719 61382a50 bellard
    env = saved_env;
4720 2c0262af bellard
}
4721 0573fbfc ths
4722 0573fbfc ths
4723 0573fbfc ths
/* Secure Virtual Machine helpers */
4724 0573fbfc ths
4725 0573fbfc ths
void helper_stgi(void)
4726 0573fbfc ths
{
4727 0573fbfc ths
    env->hflags |= HF_GIF_MASK;
4728 0573fbfc ths
}
4729 0573fbfc ths
4730 0573fbfc ths
void helper_clgi(void)
4731 0573fbfc ths
{
4732 0573fbfc ths
    env->hflags &= ~HF_GIF_MASK;
4733 0573fbfc ths
}
4734 0573fbfc ths
4735 0573fbfc ths
#if defined(CONFIG_USER_ONLY)
4736 0573fbfc ths
4737 b8b6a50b bellard
void helper_vmrun(void) 
4738 b8b6a50b bellard
{ 
4739 b8b6a50b bellard
}
4740 b8b6a50b bellard
void helper_vmmcall(void) 
4741 b8b6a50b bellard
{ 
4742 b8b6a50b bellard
}
4743 b8b6a50b bellard
void helper_vmload(void) 
4744 b8b6a50b bellard
{ 
4745 b8b6a50b bellard
}
4746 b8b6a50b bellard
void helper_vmsave(void) 
4747 b8b6a50b bellard
{ 
4748 b8b6a50b bellard
}
4749 b8b6a50b bellard
void helper_skinit(void) 
4750 b8b6a50b bellard
{ 
4751 b8b6a50b bellard
}
4752 b8b6a50b bellard
void helper_invlpga(void) 
4753 b8b6a50b bellard
{ 
4754 b8b6a50b bellard
}
4755 b8b6a50b bellard
void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 
4756 b8b6a50b bellard
{ 
4757 b8b6a50b bellard
}
4758 b8b6a50b bellard
void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
4759 0573fbfc ths
{
4760 0573fbfc ths
}
4761 0573fbfc ths
4762 b8b6a50b bellard
void helper_svm_check_io(uint32_t port, uint32_t param, 
4763 b8b6a50b bellard
                         uint32_t next_eip_addend)
4764 b8b6a50b bellard
{
4765 b8b6a50b bellard
}
4766 0573fbfc ths
#else
4767 0573fbfc ths
4768 0573fbfc ths
static inline uint32_t
4769 0573fbfc ths
vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit)
4770 0573fbfc ths
{
4771 0573fbfc ths
    return    ((vmcb_attrib & 0x00ff) << 8)          /* Type, S, DPL, P */
4772 0573fbfc ths
            | ((vmcb_attrib & 0x0f00) << 12)         /* AVL, L, DB, G */
4773 0573fbfc ths
            | ((vmcb_base >> 16) & 0xff)             /* Base 23-16 */
4774 0573fbfc ths
            | (vmcb_base & 0xff000000)               /* Base 31-24 */
4775 0573fbfc ths
            | (vmcb_limit & 0xf0000);                /* Limit 19-16 */
4776 0573fbfc ths
}
4777 0573fbfc ths
4778 0573fbfc ths
static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib)
4779 0573fbfc ths
{
4780 0573fbfc ths
    return    ((cpu_attrib >> 8) & 0xff)             /* Type, S, DPL, P */
4781 0573fbfc ths
            | ((cpu_attrib & 0xf00000) >> 12);       /* AVL, L, DB, G */
4782 0573fbfc ths
}
4783 0573fbfc ths
4784 b5b38f61 bellard
void helper_vmrun(void)
4785 0573fbfc ths
{
4786 b5b38f61 bellard
    target_ulong addr;
4787 0573fbfc ths
    uint32_t event_inj;
4788 0573fbfc ths
    uint32_t int_ctl;
4789 0573fbfc ths
4790 b5b38f61 bellard
    addr = EAX;
4791 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4792 0573fbfc ths
        fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
4793 0573fbfc ths
4794 0573fbfc ths
    env->vm_vmcb = addr;
4795 0573fbfc ths
4796 0573fbfc ths
    /* save the current CPU state in the hsave page */
4797 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
4798 0573fbfc ths
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
4799 0573fbfc ths
4800 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
4801 0573fbfc ths
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
4802 0573fbfc ths
4803 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
4804 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
4805 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
4806 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
4807 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]);
4808 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
4809 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
4810 0573fbfc ths
4811 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
4812 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
4813 0573fbfc ths
4814 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es);
4815 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs);
4816 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss);
4817 0573fbfc ths
    SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds);
4818 0573fbfc ths
4819 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP);
4820 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
4821 0573fbfc ths
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
4822 0573fbfc ths
4823 0573fbfc ths
    /* load the interception bitmaps so we do not need to access the
4824 0573fbfc ths
       vmcb in svm mode */
4825 0573fbfc ths
    /* We shift all the intercept bits so we can OR them with the TB
4826 0573fbfc ths
       flags later on */
4827 0573fbfc ths
    env->intercept            = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK;
4828 0573fbfc ths
    env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
4829 0573fbfc ths
    env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
4830 0573fbfc ths
    env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
4831 0573fbfc ths
    env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
4832 0573fbfc ths
    env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
4833 0573fbfc ths
4834 0573fbfc ths
    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
4835 0573fbfc ths
    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
4836 0573fbfc ths
4837 0573fbfc ths
    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
4838 0573fbfc ths
    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
4839 0573fbfc ths
4840 0573fbfc ths
    /* clear exit_info_2 so we behave like the real hardware */
4841 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
4842 0573fbfc ths
4843 0573fbfc ths
    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
4844 0573fbfc ths
    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
4845 0573fbfc ths
    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
4846 0573fbfc ths
    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
4847 0573fbfc ths
    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
4848 0573fbfc ths
    if (int_ctl & V_INTR_MASKING_MASK) {
4849 0573fbfc ths
        env->cr[8] = int_ctl & V_TPR_MASK;
4850 3d575329 balrog
        cpu_set_apic_tpr(env, env->cr[8]);
4851 0573fbfc ths
        if (env->eflags & IF_MASK)
4852 0573fbfc ths
            env->hflags |= HF_HIF_MASK;
4853 0573fbfc ths
    }
4854 0573fbfc ths
4855 0573fbfc ths
#ifdef TARGET_X86_64
4856 0573fbfc ths
    env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer));
4857 0573fbfc ths
    env->hflags &= ~HF_LMA_MASK;
4858 0573fbfc ths
    if (env->efer & MSR_EFER_LMA)
4859 0573fbfc ths
       env->hflags |= HF_LMA_MASK;
4860 0573fbfc ths
#endif
4861 0573fbfc ths
    env->eflags = 0;
4862 0573fbfc ths
    load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
4863 0573fbfc ths
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
4864 0573fbfc ths
    CC_OP = CC_OP_EFLAGS;
4865 0573fbfc ths
    CC_DST = 0xffffffff;
4866 0573fbfc ths
4867 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, ES, es);
4868 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, CS, cs);
4869 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, SS, ss);
4870 0573fbfc ths
    SVM_LOAD_SEG(env->vm_vmcb, DS, ds);
4871 0573fbfc ths
4872 0573fbfc ths
    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
4873 0573fbfc ths
    env->eip = EIP;
4874 0573fbfc ths
    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
4875 0573fbfc ths
    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
4876 0573fbfc ths
    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
4877 0573fbfc ths
    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
4878 0573fbfc ths
    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
4879 0573fbfc ths
4880 0573fbfc ths
    /* FIXME: guest state consistency checks */
4881 0573fbfc ths
4882 0573fbfc ths
    switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
4883 0573fbfc ths
        case TLB_CONTROL_DO_NOTHING:
4884 0573fbfc ths
            break;
4885 0573fbfc ths
        case TLB_CONTROL_FLUSH_ALL_ASID:
4886 0573fbfc ths
            /* FIXME: this is not 100% correct but should work for now */
4887 0573fbfc ths
            tlb_flush(env, 1);
4888 0573fbfc ths
        break;
4889 0573fbfc ths
    }
4890 0573fbfc ths
4891 0573fbfc ths
    helper_stgi();
4892 0573fbfc ths
4893 0573fbfc ths
    /* maybe we need to inject an event */
4894 0573fbfc ths
    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
4895 0573fbfc ths
    if (event_inj & SVM_EVTINJ_VALID) {
4896 0573fbfc ths
        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
4897 0573fbfc ths
        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
4898 0573fbfc ths
        uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
4899 0573fbfc ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
4900 0573fbfc ths
4901 0573fbfc ths
        if (loglevel & CPU_LOG_TB_IN_ASM)
4902 0573fbfc ths
            fprintf(logfile, "Injecting(%#hx): ", valid_err);
4903 0573fbfc ths
        /* FIXME: need to implement valid_err */
4904 0573fbfc ths
        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
4905 0573fbfc ths
        case SVM_EVTINJ_TYPE_INTR:
4906 0573fbfc ths
                env->exception_index = vector;
4907 0573fbfc ths
                env->error_code = event_inj_err;
4908 7241f532 balrog
                env->exception_is_int = 0;
4909 0573fbfc ths
                env->exception_next_eip = -1;
4910 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4911 0573fbfc ths
                    fprintf(logfile, "INTR");
4912 0573fbfc ths
                break;
4913 0573fbfc ths
        case SVM_EVTINJ_TYPE_NMI:
4914 0573fbfc ths
                env->exception_index = vector;
4915 0573fbfc ths
                env->error_code = event_inj_err;
4916 7241f532 balrog
                env->exception_is_int = 0;
4917 0573fbfc ths
                env->exception_next_eip = EIP;
4918 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4919 0573fbfc ths
                    fprintf(logfile, "NMI");
4920 0573fbfc ths
                break;
4921 0573fbfc ths
        case SVM_EVTINJ_TYPE_EXEPT:
4922 0573fbfc ths
                env->exception_index = vector;
4923 0573fbfc ths
                env->error_code = event_inj_err;
4924 0573fbfc ths
                env->exception_is_int = 0;
4925 0573fbfc ths
                env->exception_next_eip = -1;
4926 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4927 0573fbfc ths
                    fprintf(logfile, "EXEPT");
4928 0573fbfc ths
                break;
4929 0573fbfc ths
        case SVM_EVTINJ_TYPE_SOFT:
4930 0573fbfc ths
                env->exception_index = vector;
4931 0573fbfc ths
                env->error_code = event_inj_err;
4932 0573fbfc ths
                env->exception_is_int = 1;
4933 0573fbfc ths
                env->exception_next_eip = EIP;
4934 0573fbfc ths
                if (loglevel & CPU_LOG_TB_IN_ASM)
4935 0573fbfc ths
                    fprintf(logfile, "SOFT");
4936 0573fbfc ths
                break;
4937 0573fbfc ths
        }
4938 0573fbfc ths
        if (loglevel & CPU_LOG_TB_IN_ASM)
4939 0573fbfc ths
            fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
4940 0573fbfc ths
    }
4941 52621688 ths
    if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) {
4942 0573fbfc ths
        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
4943 52621688 ths
    }
4944 0573fbfc ths
4945 0573fbfc ths
    cpu_loop_exit();
4946 0573fbfc ths
}
4947 0573fbfc ths
4948 0573fbfc ths
void helper_vmmcall(void)
4949 0573fbfc ths
{
4950 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4951 0573fbfc ths
        fprintf(logfile,"vmmcall!\n");
4952 0573fbfc ths
}
4953 0573fbfc ths
4954 b5b38f61 bellard
void helper_vmload(void)
4955 0573fbfc ths
{
4956 b5b38f61 bellard
    target_ulong addr;
4957 b5b38f61 bellard
    addr = EAX;
4958 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4959 0573fbfc ths
        fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4960 0573fbfc ths
                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4961 0573fbfc ths
                env->segs[R_FS].base);
4962 0573fbfc ths
4963 0573fbfc ths
    SVM_LOAD_SEG2(addr, segs[R_FS], fs);
4964 0573fbfc ths
    SVM_LOAD_SEG2(addr, segs[R_GS], gs);
4965 0573fbfc ths
    SVM_LOAD_SEG2(addr, tr, tr);
4966 0573fbfc ths
    SVM_LOAD_SEG2(addr, ldt, ldtr);
4967 0573fbfc ths
4968 0573fbfc ths
#ifdef TARGET_X86_64
4969 0573fbfc ths
    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
4970 0573fbfc ths
    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
4971 0573fbfc ths
    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
4972 0573fbfc ths
    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
4973 0573fbfc ths
#endif
4974 0573fbfc ths
    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
4975 0573fbfc ths
    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
4976 0573fbfc ths
    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
4977 0573fbfc ths
    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
4978 0573fbfc ths
}
4979 0573fbfc ths
4980 b5b38f61 bellard
void helper_vmsave(void)
4981 0573fbfc ths
{
4982 b5b38f61 bellard
    target_ulong addr;
4983 b5b38f61 bellard
    addr = EAX;
4984 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
4985 0573fbfc ths
        fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
4986 0573fbfc ths
                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
4987 0573fbfc ths
                env->segs[R_FS].base);
4988 0573fbfc ths
4989 0573fbfc ths
    SVM_SAVE_SEG(addr, segs[R_FS], fs);
4990 0573fbfc ths
    SVM_SAVE_SEG(addr, segs[R_GS], gs);
4991 0573fbfc ths
    SVM_SAVE_SEG(addr, tr, tr);
4992 0573fbfc ths
    SVM_SAVE_SEG(addr, ldt, ldtr);
4993 0573fbfc ths
4994 0573fbfc ths
#ifdef TARGET_X86_64
4995 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
4996 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
4997 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
4998 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
4999 0573fbfc ths
#endif
5000 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
5001 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
5002 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
5003 0573fbfc ths
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
5004 0573fbfc ths
}
5005 0573fbfc ths
5006 0573fbfc ths
void helper_skinit(void)
5007 0573fbfc ths
{
5008 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
5009 0573fbfc ths
        fprintf(logfile,"skinit!\n");
5010 0573fbfc ths
}
5011 0573fbfc ths
5012 0573fbfc ths
void helper_invlpga(void)
5013 0573fbfc ths
{
5014 0573fbfc ths
    tlb_flush(env, 0);
5015 0573fbfc ths
}
5016 0573fbfc ths
5017 b8b6a50b bellard
void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
5018 0573fbfc ths
{
5019 0573fbfc ths
    switch(type) {
5020 0573fbfc ths
    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
5021 0573fbfc ths
        if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) {
5022 b8b6a50b bellard
            helper_vmexit(type, param);
5023 0573fbfc ths
        }
5024 0573fbfc ths
        break;
5025 0573fbfc ths
    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8:
5026 0573fbfc ths
        if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) {
5027 b8b6a50b bellard
            helper_vmexit(type, param);
5028 0573fbfc ths
        }
5029 0573fbfc ths
        break;
5030 0573fbfc ths
    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
5031 0573fbfc ths
        if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) {
5032 b8b6a50b bellard
            helper_vmexit(type, param);
5033 0573fbfc ths
        }
5034 0573fbfc ths
        break;
5035 0573fbfc ths
    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8:
5036 0573fbfc ths
        if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) {
5037 b8b6a50b bellard
            helper_vmexit(type, param);
5038 0573fbfc ths
        }
5039 0573fbfc ths
        break;
5040 0573fbfc ths
    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16:
5041 0573fbfc ths
        if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) {
5042 b8b6a50b bellard
            helper_vmexit(type, param);
5043 0573fbfc ths
        }
5044 0573fbfc ths
        break;
5045 0573fbfc ths
    case SVM_EXIT_IOIO:
5046 0573fbfc ths
        break;
5047 0573fbfc ths
5048 0573fbfc ths
    case SVM_EXIT_MSR:
5049 0573fbfc ths
        if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) {
5050 0573fbfc ths
            /* FIXME: this should be read in at vmrun (faster this way?) */
5051 0573fbfc ths
            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
5052 b8b6a50b bellard
            uint32_t t0, t1;
5053 0573fbfc ths
            switch((uint32_t)ECX) {
5054 0573fbfc ths
            case 0 ... 0x1fff:
5055 b8b6a50b bellard
                t0 = (ECX * 2) % 8;
5056 b8b6a50b bellard
                t1 = ECX / 8;
5057 0573fbfc ths
                break;
5058 0573fbfc ths
            case 0xc0000000 ... 0xc0001fff:
5059 b8b6a50b bellard
                t0 = (8192 + ECX - 0xc0000000) * 2;
5060 b8b6a50b bellard
                t1 = (t0 / 8);
5061 b8b6a50b bellard
                t0 %= 8;
5062 0573fbfc ths
                break;
5063 0573fbfc ths
            case 0xc0010000 ... 0xc0011fff:
5064 b8b6a50b bellard
                t0 = (16384 + ECX - 0xc0010000) * 2;
5065 b8b6a50b bellard
                t1 = (t0 / 8);
5066 b8b6a50b bellard
                t0 %= 8;
5067 0573fbfc ths
                break;
5068 0573fbfc ths
            default:
5069 b8b6a50b bellard
                helper_vmexit(type, param);
5070 b8b6a50b bellard
                t0 = 0;
5071 b8b6a50b bellard
                t1 = 0;
5072 b8b6a50b bellard
                break;
5073 0573fbfc ths
            }
5074 b8b6a50b bellard
            if (ldub_phys(addr + t1) & ((1 << param) << t0))
5075 b8b6a50b bellard
                helper_vmexit(type, param);
5076 0573fbfc ths
        }
5077 0573fbfc ths
        break;
5078 0573fbfc ths
    default:
5079 0573fbfc ths
        if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) {
5080 b8b6a50b bellard
            helper_vmexit(type, param);
5081 0573fbfc ths
        }
5082 0573fbfc ths
        break;
5083 0573fbfc ths
    }
5084 0573fbfc ths
}
5085 0573fbfc ths
5086 b8b6a50b bellard
void helper_svm_check_io(uint32_t port, uint32_t param, 
5087 b8b6a50b bellard
                         uint32_t next_eip_addend)
5088 b8b6a50b bellard
{
5089 b8b6a50b bellard
    if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) {
5090 b8b6a50b bellard
        /* FIXME: this should be read in at vmrun (faster this way?) */
5091 b8b6a50b bellard
        uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
5092 b8b6a50b bellard
        uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
5093 b8b6a50b bellard
        if(lduw_phys(addr + port / 8) & (mask << (port & 7))) {
5094 b8b6a50b bellard
            /* next EIP */
5095 b8b6a50b bellard
            stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 
5096 b8b6a50b bellard
                     env->eip + next_eip_addend);
5097 b8b6a50b bellard
            helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
5098 b8b6a50b bellard
        }
5099 b8b6a50b bellard
    }
5100 b8b6a50b bellard
}
5101 b8b6a50b bellard
5102 b8b6a50b bellard
/* Note: currently only 32 bits of exit_code are used */
5103 b8b6a50b bellard
void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
5104 0573fbfc ths
{
5105 0573fbfc ths
    uint32_t int_ctl;
5106 0573fbfc ths
5107 0573fbfc ths
    if (loglevel & CPU_LOG_TB_IN_ASM)
5108 b8b6a50b bellard
        fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
5109 0573fbfc ths
                exit_code, exit_info_1,
5110 0573fbfc ths
                ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
5111 0573fbfc ths
                EIP);
5112 0573fbfc ths
5113 52621688 ths
    if(env->hflags & HF_INHIBIT_IRQ_MASK) {
5114 52621688 ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
5115 52621688 ths
        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
5116 52621688 ths
    } else {
5117 52621688 ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
5118 52621688 ths
    }
5119 52621688 ths
5120 0573fbfc ths
    /* Save the VM state in the vmcb */
5121 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es);
5122 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs);
5123 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss);
5124 0573fbfc ths
    SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds);
5125 0573fbfc ths
5126 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
5127 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
5128 0573fbfc ths
5129 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
5130 0573fbfc ths
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
5131 0573fbfc ths
5132 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
5133 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
5134 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
5135 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
5136 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
5137 0573fbfc ths
5138 0573fbfc ths
    if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) {
5139 0573fbfc ths
        int_ctl &= ~V_TPR_MASK;
5140 0573fbfc ths
        int_ctl |= env->cr[8] & V_TPR_MASK;
5141 0573fbfc ths
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
5142 0573fbfc ths
    }
5143 0573fbfc ths
5144 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
5145 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
5146 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
5147 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
5148 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
5149 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
5150 0573fbfc ths
    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
5151 0573fbfc ths
5152 0573fbfc ths
    /* Reload the host state from vm_hsave */
5153 0573fbfc ths
    env->hflags &= ~HF_HIF_MASK;
5154 0573fbfc ths
    env->intercept = 0;
5155 0573fbfc ths
    env->intercept_exceptions = 0;
5156 0573fbfc ths
    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
5157 0573fbfc ths
5158 0573fbfc ths
    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
5159 0573fbfc ths
    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
5160 0573fbfc ths
5161 0573fbfc ths
    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
5162 0573fbfc ths
    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
5163 0573fbfc ths
5164 0573fbfc ths
    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
5165 0573fbfc ths
    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
5166 0573fbfc ths
    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
5167 3d575329 balrog
    if (int_ctl & V_INTR_MASKING_MASK) {
5168 0573fbfc ths
        env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8));
5169 3d575329 balrog
        cpu_set_apic_tpr(env, env->cr[8]);
5170 3d575329 balrog
    }
5171 0573fbfc ths
    /* we need to set the efer after the crs so the hidden flags get set properly */
5172 0573fbfc ths
#ifdef TARGET_X86_64
5173 0573fbfc ths
    env->efer  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer));
5174 0573fbfc ths
    env->hflags &= ~HF_LMA_MASK;
5175 0573fbfc ths
    if (env->efer & MSR_EFER_LMA)
5176 0573fbfc ths
       env->hflags |= HF_LMA_MASK;
5177 0573fbfc ths
#endif
5178 0573fbfc ths
5179 0573fbfc ths
    env->eflags = 0;
5180 0573fbfc ths
    load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
5181 0573fbfc ths
                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
5182 0573fbfc ths
    CC_OP = CC_OP_EFLAGS;
5183 0573fbfc ths
5184 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, ES, es);
5185 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, CS, cs);
5186 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, SS, ss);
5187 0573fbfc ths
    SVM_LOAD_SEG(env->vm_hsave, DS, ds);
5188 0573fbfc ths
5189 0573fbfc ths
    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
5190 0573fbfc ths
    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
5191 0573fbfc ths
    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
5192 0573fbfc ths
5193 0573fbfc ths
    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
5194 0573fbfc ths
    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
5195 0573fbfc ths
5196 0573fbfc ths
    /* other setups */
5197 0573fbfc ths
    cpu_x86_set_cpl(env, 0);
5198 b8b6a50b bellard
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
5199 0573fbfc ths
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
5200 0573fbfc ths
5201 0573fbfc ths
    helper_clgi();
5202 0573fbfc ths
    /* FIXME: Resets the current ASID register to zero (host ASID). */
5203 0573fbfc ths
5204 0573fbfc ths
    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
5205 0573fbfc ths
5206 0573fbfc ths
    /* Clears the TSC_OFFSET inside the processor. */
5207 0573fbfc ths
5208 0573fbfc ths
    /* If the host is in PAE mode, the processor reloads the host's PDPEs
5209 0573fbfc ths
       from the page table indicated the host's CR3. If the PDPEs contain
5210 0573fbfc ths
       illegal state, the processor causes a shutdown. */
5211 0573fbfc ths
5212 0573fbfc ths
    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
5213 0573fbfc ths
    env->cr[0] |= CR0_PE_MASK;
5214 0573fbfc ths
    env->eflags &= ~VM_MASK;
5215 0573fbfc ths
5216 0573fbfc ths
    /* Disables all breakpoints in the host DR7 register. */
5217 0573fbfc ths
5218 0573fbfc ths
    /* Checks the reloaded host state for consistency. */
5219 0573fbfc ths
5220 0573fbfc ths
    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
5221 0573fbfc ths
       host's code segment or non-canonical (in the case of long mode), a
5222 0573fbfc ths
       #GP fault is delivered inside the host.) */
5223 0573fbfc ths
5224 0573fbfc ths
    /* remove any pending exception */
5225 0573fbfc ths
    env->exception_index = -1;
5226 0573fbfc ths
    env->error_code = 0;
5227 0573fbfc ths
    env->old_exception = -1;
5228 0573fbfc ths
5229 0573fbfc ths
    cpu_loop_exit();
5230 0573fbfc ths
}
5231 0573fbfc ths
5232 0573fbfc ths
#endif
5233 5af45186 bellard
5234 5af45186 bellard
/* MMX/SSE */
5235 5af45186 bellard
/* XXX: optimize by storing fptt and fptags in the static cpu state */
5236 5af45186 bellard
void helper_enter_mmx(void)
5237 5af45186 bellard
{
5238 5af45186 bellard
    env->fpstt = 0;
5239 5af45186 bellard
    *(uint32_t *)(env->fptags) = 0;
5240 5af45186 bellard
    *(uint32_t *)(env->fptags + 4) = 0;
5241 5af45186 bellard
}
5242 5af45186 bellard
5243 5af45186 bellard
void helper_emms(void)
5244 5af45186 bellard
{
5245 5af45186 bellard
    /* set to empty state */
5246 5af45186 bellard
    *(uint32_t *)(env->fptags) = 0x01010101;
5247 5af45186 bellard
    *(uint32_t *)(env->fptags + 4) = 0x01010101;
5248 5af45186 bellard
}
5249 5af45186 bellard
5250 5af45186 bellard
/* XXX: suppress */
5251 5af45186 bellard
void helper_movq(uint64_t *d, uint64_t *s)
5252 5af45186 bellard
{
5253 5af45186 bellard
    *d = *s;
5254 5af45186 bellard
}
5255 5af45186 bellard
5256 5af45186 bellard
#define SHIFT 0
5257 5af45186 bellard
#include "ops_sse.h"
5258 5af45186 bellard
5259 5af45186 bellard
#define SHIFT 1
5260 5af45186 bellard
#include "ops_sse.h"
5261 5af45186 bellard
5262 b6abf97d bellard
#define SHIFT 0
5263 b6abf97d bellard
#include "helper_template.h"
5264 b6abf97d bellard
#undef SHIFT
5265 b6abf97d bellard
5266 b6abf97d bellard
#define SHIFT 1
5267 b6abf97d bellard
#include "helper_template.h"
5268 b6abf97d bellard
#undef SHIFT
5269 b6abf97d bellard
5270 b6abf97d bellard
#define SHIFT 2
5271 b6abf97d bellard
#include "helper_template.h"
5272 b6abf97d bellard
#undef SHIFT
5273 b6abf97d bellard
5274 b6abf97d bellard
#ifdef TARGET_X86_64
5275 b6abf97d bellard
5276 b6abf97d bellard
#define SHIFT 3
5277 b6abf97d bellard
#include "helper_template.h"
5278 b6abf97d bellard
#undef SHIFT
5279 b6abf97d bellard
5280 b6abf97d bellard
#endif
5281 07d2c595 bellard
5282 6191b059 bellard
/* bit operations */
5283 6191b059 bellard
target_ulong helper_bsf(target_ulong t0)
5284 6191b059 bellard
{
5285 6191b059 bellard
    int count;
5286 6191b059 bellard
    target_ulong res;
5287 6191b059 bellard
5288 6191b059 bellard
    res = t0;
5289 6191b059 bellard
    count = 0;
5290 6191b059 bellard
    while ((res & 1) == 0) {
5291 6191b059 bellard
        count++;
5292 6191b059 bellard
        res >>= 1;
5293 6191b059 bellard
    }
5294 6191b059 bellard
    return count;
5295 6191b059 bellard
}
5296 6191b059 bellard
5297 6191b059 bellard
target_ulong helper_bsr(target_ulong t0)
5298 6191b059 bellard
{
5299 6191b059 bellard
    int count;
5300 6191b059 bellard
    target_ulong res, mask;
5301 6191b059 bellard
    
5302 6191b059 bellard
    res = t0;
5303 6191b059 bellard
    count = TARGET_LONG_BITS - 1;
5304 6191b059 bellard
    mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
5305 6191b059 bellard
    while ((res & mask) == 0) {
5306 6191b059 bellard
        count--;
5307 6191b059 bellard
        res <<= 1;
5308 6191b059 bellard
    }
5309 6191b059 bellard
    return count;
5310 6191b059 bellard
}
5311 6191b059 bellard
5312 6191b059 bellard
5313 07d2c595 bellard
static int compute_all_eflags(void)
5314 07d2c595 bellard
{
5315 07d2c595 bellard
    return CC_SRC;
5316 07d2c595 bellard
}
5317 07d2c595 bellard
5318 07d2c595 bellard
static int compute_c_eflags(void)
5319 07d2c595 bellard
{
5320 07d2c595 bellard
    return CC_SRC & CC_C;
5321 07d2c595 bellard
}
5322 07d2c595 bellard
5323 07d2c595 bellard
CCTable cc_table[CC_OP_NB] = {
5324 07d2c595 bellard
    [CC_OP_DYNAMIC] = { /* should never happen */ },
5325 07d2c595 bellard
5326 07d2c595 bellard
    [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
5327 07d2c595 bellard
5328 07d2c595 bellard
    [CC_OP_MULB] = { compute_all_mulb, compute_c_mull },
5329 07d2c595 bellard
    [CC_OP_MULW] = { compute_all_mulw, compute_c_mull },
5330 07d2c595 bellard
    [CC_OP_MULL] = { compute_all_mull, compute_c_mull },
5331 07d2c595 bellard
5332 07d2c595 bellard
    [CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
5333 07d2c595 bellard
    [CC_OP_ADDW] = { compute_all_addw, compute_c_addw  },
5334 07d2c595 bellard
    [CC_OP_ADDL] = { compute_all_addl, compute_c_addl  },
5335 07d2c595 bellard
5336 07d2c595 bellard
    [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb },
5337 07d2c595 bellard
    [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw  },
5338 07d2c595 bellard
    [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl  },
5339 07d2c595 bellard
5340 07d2c595 bellard
    [CC_OP_SUBB] = { compute_all_subb, compute_c_subb  },
5341 07d2c595 bellard
    [CC_OP_SUBW] = { compute_all_subw, compute_c_subw  },
5342 07d2c595 bellard
    [CC_OP_SUBL] = { compute_all_subl, compute_c_subl  },
5343 07d2c595 bellard
5344 07d2c595 bellard
    [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb  },
5345 07d2c595 bellard
    [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw  },
5346 07d2c595 bellard
    [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl  },
5347 07d2c595 bellard
5348 07d2c595 bellard
    [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
5349 07d2c595 bellard
    [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
5350 07d2c595 bellard
    [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
5351 07d2c595 bellard
5352 07d2c595 bellard
    [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
5353 07d2c595 bellard
    [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
5354 07d2c595 bellard
    [CC_OP_INCL] = { compute_all_incl, compute_c_incl },
5355 07d2c595 bellard
5356 07d2c595 bellard
    [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
5357 07d2c595 bellard
    [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
5358 07d2c595 bellard
    [CC_OP_DECL] = { compute_all_decl, compute_c_incl },
5359 07d2c595 bellard
5360 07d2c595 bellard
    [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
5361 07d2c595 bellard
    [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
5362 07d2c595 bellard
    [CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
5363 07d2c595 bellard
5364 07d2c595 bellard
    [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
5365 07d2c595 bellard
    [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
5366 07d2c595 bellard
    [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
5367 07d2c595 bellard
5368 07d2c595 bellard
#ifdef TARGET_X86_64
5369 07d2c595 bellard
    [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull },
5370 07d2c595 bellard
5371 07d2c595 bellard
    [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq  },
5372 07d2c595 bellard
5373 07d2c595 bellard
    [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq  },
5374 07d2c595 bellard
5375 07d2c595 bellard
    [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq  },
5376 07d2c595 bellard
5377 07d2c595 bellard
    [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq  },
5378 07d2c595 bellard
5379 07d2c595 bellard
    [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq },
5380 07d2c595 bellard
5381 07d2c595 bellard
    [CC_OP_INCQ] = { compute_all_incq, compute_c_incl },
5382 07d2c595 bellard
5383 07d2c595 bellard
    [CC_OP_DECQ] = { compute_all_decq, compute_c_incl },
5384 07d2c595 bellard
5385 07d2c595 bellard
    [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq },
5386 07d2c595 bellard
5387 07d2c595 bellard
    [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl },
5388 07d2c595 bellard
#endif
5389 07d2c595 bellard
};