helper2.c 32.9 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  i386 helpers (without register variable usage)
3
 *
B
bellard 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *  Copyright (c) 2003 Fabrice Bellard
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <assert.h>

#include "cpu.h"
#include "exec-all.h"
T
ths 已提交
30
#include "svm.h"
B
bellard 已提交
31 32 33

//#define DEBUG_MMU

34
#ifdef USE_CODE_COPY
T
ths 已提交
35
#include <unistd.h>
36 37
#include <asm/ldt.h>
#include <linux/unistd.h>
B
bellard 已提交
38
#include <linux/version.h>
39

B
bellard 已提交
40 41 42 43
int modify_ldt(int func, void *ptr, unsigned long bytecount)
{
	return syscall(__NR_modify_ldt, func, ptr, bytecount);
}
B
bellard 已提交
44 45 46

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
#define modify_ldt_ldt_s user_desc
47
#endif
B
bellard 已提交
48
#endif /* USE_CODE_COPY */
49

B
bellard 已提交
50 51 52 53 54
CPUX86State *cpu_x86_init(void)
{
    CPUX86State *env;
    static int inited;

B
bellard 已提交
55
    env = qemu_mallocz(sizeof(CPUX86State));
B
bellard 已提交
56 57
    if (!env)
        return NULL;
B
bellard 已提交
58 59
    cpu_exec_init(env);

B
bellard 已提交
60 61 62 63 64 65 66 67 68
    /* init various static tables */
    if (!inited) {
        inited = 1;
        optimize_flags_init();
    }
#ifdef USE_CODE_COPY
    /* testing code for code copy case */
    {
        struct modify_ldt_ldt_s ldt;
B
bellard 已提交
69

B
bellard 已提交
70 71 72 73 74 75 76 77 78 79
        ldt.entry_number = 1;
        ldt.base_addr = (unsigned long)env;
        ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
        ldt.seg_32bit = 1;
        ldt.contents = MODIFY_LDT_CONTENTS_DATA;
        ldt.read_exec_only = 0;
        ldt.limit_in_pages = 1;
        ldt.seg_not_present = 0;
        ldt.useable = 1;
        modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
80

B
bellard 已提交
81 82 83
        asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
    }
#endif
B
bellard 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    {
        int family, model, stepping;
#ifdef TARGET_X86_64
        env->cpuid_vendor1 = 0x68747541; /* "Auth" */
        env->cpuid_vendor2 = 0x69746e65; /* "enti" */
        env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */
        family = 6;
        model = 2;
        stepping = 3;
#else
        env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
        env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
        env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
#if 0
        /* pentium 75-200 */
        family = 5;
        model = 2;
        stepping = 11;
#else
        /* pentium pro */
        family = 6;
B
bellard 已提交
105
        model = 3;
B
bellard 已提交
106 107 108
        stepping = 3;
#endif
#endif
B
bellard 已提交
109
        env->cpuid_level = 2;
B
bellard 已提交
110 111 112
        env->cpuid_version = (family << 8) | (model << 4) | stepping;
        env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
                               CPUID_TSC | CPUID_MSR | CPUID_MCE |
113 114 115
                               CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
                               CPUID_PAT);
        env->pat = 0x0007040600070406ULL;
T
ths 已提交
116
        env->cpuid_ext3_features = CPUID_EXT3_SVM;
B
bellard 已提交
117
        env->cpuid_ext_features = CPUID_EXT_SSE3;
B
bellard 已提交
118
        env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
B
bellard 已提交
119
        env->cpuid_features |= CPUID_APIC;
T
ths 已提交
120
        env->cpuid_xlevel = 0x8000000e;
B
bellard 已提交
121 122 123 124 125 126 127 128 129 130 131 132
        {
            const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
            int c, len, i;
            len = strlen(model_id);
            for(i = 0; i < 48; i++) {
                if (i >= len)
                    c = '\0';
                else
                    c = model_id[i];
                env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
            }
        }
B
bellard 已提交
133 134
#ifdef TARGET_X86_64
        /* currently not enabled for std i386 because not fully tested */
B
bellard 已提交
135
        env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
B
bellard 已提交
136
        env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
137 138 139

        /* these features are needed for Win64 and aren't fully implemented */
        env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
140 141
        /* this feature is needed for Solaris and isn't fully implemented */
        env->cpuid_features |= CPUID_PSE36;
B
bellard 已提交
142 143
#endif
    }
B
bellard 已提交
144
    cpu_reset(env);
B
bellard 已提交
145 146 147
#ifdef USE_KQEMU
    kqemu_init(env);
#endif
B
bellard 已提交
148 149 150 151 152 153 154 155 156
    return env;
}

/* NOTE: must be called outside the CPU execute loop */
void cpu_reset(CPUX86State *env)
{
    int i;

    memset(env, 0, offsetof(CPUX86State, breakpoints));
157 158

    tlb_flush(env, 1);
B
bellard 已提交
159

160 161
    env->old_exception = -1;

B
bellard 已提交
162 163
    /* init to reset state */

B
bellard 已提交
164 165 166
#ifdef CONFIG_SOFTMMU
    env->hflags |= HF_SOFTMMU_MASK;
#endif
T
ths 已提交
167
    env->hflags |= HF_GIF_MASK;
168 169 170

    cpu_x86_update_cr0(env, 0x60000010);
    env->a20_mask = 0xffffffff;
B
bellard 已提交
171 172
    env->smbase = 0x30000;

173 174 175 176 177 178
    env->idt.limit = 0xffff;
    env->gdt.limit = 0xffff;
    env->ldt.limit = 0xffff;
    env->ldt.flags = DESC_P_MASK;
    env->tr.limit = 0xffff;
    env->tr.flags = DESC_P_MASK;
179

180
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0);
B
bellard 已提交
181 182 183 184 185
    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0);
    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0);
    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0);
    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0);
    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);
186

187 188
    env->eip = 0xfff0;
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
189

190
    env->eflags = 0x2;
191

192 193 194 195
    /* FPU init */
    for(i = 0;i < 8; i++)
        env->fptags[i] = 1;
    env->fpuc = 0x37f;
B
bellard 已提交
196 197

    env->mxcsr = 0x1f80;
B
bellard 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210
}

void cpu_x86_close(CPUX86State *env)
{
    free(env);
}

/***********************************************************/
/* x86 debug */

static const char *cc_op_str[] = {
    "DYNAMIC",
    "EFLAGS",
B
bellard 已提交
211

212 213 214
    "MULB",
    "MULW",
    "MULL",
B
bellard 已提交
215 216
    "MULQ",

B
bellard 已提交
217 218 219
    "ADDB",
    "ADDW",
    "ADDL",
B
bellard 已提交
220 221
    "ADDQ",

B
bellard 已提交
222 223 224
    "ADCB",
    "ADCW",
    "ADCL",
B
bellard 已提交
225 226
    "ADCQ",

B
bellard 已提交
227 228 229
    "SUBB",
    "SUBW",
    "SUBL",
B
bellard 已提交
230 231
    "SUBQ",

B
bellard 已提交
232 233 234
    "SBBB",
    "SBBW",
    "SBBL",
B
bellard 已提交
235 236
    "SBBQ",

B
bellard 已提交
237 238 239
    "LOGICB",
    "LOGICW",
    "LOGICL",
B
bellard 已提交
240 241
    "LOGICQ",

B
bellard 已提交
242 243 244
    "INCB",
    "INCW",
    "INCL",
B
bellard 已提交
245 246
    "INCQ",

B
bellard 已提交
247 248 249
    "DECB",
    "DECW",
    "DECL",
B
bellard 已提交
250 251
    "DECQ",

B
bellard 已提交
252 253 254
    "SHLB",
    "SHLW",
    "SHLL",
B
bellard 已提交
255 256
    "SHLQ",

B
bellard 已提交
257 258 259
    "SARB",
    "SARW",
    "SARL",
B
bellard 已提交
260
    "SARQ",
B
bellard 已提交
261 262
};

263
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
264 265
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
266
{
B
bellard 已提交
267
    int eflags, i, nb;
B
bellard 已提交
268
    char cc_op_name[32];
B
bellard 已提交
269
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
B
bellard 已提交
270 271

    eflags = env->eflags;
B
bellard 已提交
272 273
#ifdef TARGET_X86_64
    if (env->hflags & HF_CS64_MASK) {
274
        cpu_fprintf(f,
B
bellard 已提交
275 276 277 278
                    "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
                    "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
                    "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
                    "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
B
bellard 已提交
279
                    "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
                    env->regs[R_EAX],
                    env->regs[R_EBX],
                    env->regs[R_ECX],
                    env->regs[R_EDX],
                    env->regs[R_ESI],
                    env->regs[R_EDI],
                    env->regs[R_EBP],
                    env->regs[R_ESP],
                    env->regs[8],
                    env->regs[9],
                    env->regs[10],
                    env->regs[11],
                    env->regs[12],
                    env->regs[13],
                    env->regs[14],
                    env->regs[15],
B
bellard 已提交
296 297 298 299 300 301 302 303
                    env->eip, eflags,
                    eflags & DF_MASK ? 'D' : '-',
                    eflags & CC_O ? 'O' : '-',
                    eflags & CC_S ? 'S' : '-',
                    eflags & CC_Z ? 'Z' : '-',
                    eflags & CC_A ? 'A' : '-',
                    eflags & CC_P ? 'P' : '-',
                    eflags & CC_C ? 'C' : '-',
304
                    env->hflags & HF_CPL_MASK,
B
bellard 已提交
305
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
B
bellard 已提交
306
                    (env->a20_mask >> 20) & 1,
B
bellard 已提交
307
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
308
                    (env->hflags >> HF_HALTED_SHIFT) & 1);
309
    } else
B
bellard 已提交
310 311 312 313
#endif
    {
        cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
                    "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
B
bellard 已提交
314
                    "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
315 316 317 318 319 320 321 322
                    (uint32_t)env->regs[R_EAX],
                    (uint32_t)env->regs[R_EBX],
                    (uint32_t)env->regs[R_ECX],
                    (uint32_t)env->regs[R_EDX],
                    (uint32_t)env->regs[R_ESI],
                    (uint32_t)env->regs[R_EDI],
                    (uint32_t)env->regs[R_EBP],
                    (uint32_t)env->regs[R_ESP],
B
bellard 已提交
323 324 325 326 327 328 329 330
                    (uint32_t)env->eip, eflags,
                    eflags & DF_MASK ? 'D' : '-',
                    eflags & CC_O ? 'O' : '-',
                    eflags & CC_S ? 'S' : '-',
                    eflags & CC_Z ? 'Z' : '-',
                    eflags & CC_A ? 'A' : '-',
                    eflags & CC_P ? 'P' : '-',
                    eflags & CC_C ? 'C' : '-',
331
                    env->hflags & HF_CPL_MASK,
B
bellard 已提交
332
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
B
bellard 已提交
333
                    (env->a20_mask >> 20) & 1,
B
bellard 已提交
334
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
335
                    (env->hflags >> HF_HALTED_SHIFT) & 1);
B
bellard 已提交
336 337 338 339 340 341
    }

#ifdef TARGET_X86_64
    if (env->hflags & HF_LMA_MASK) {
        for(i = 0; i < 6; i++) {
            SegmentCache *sc = &env->segs[i];
B
bellard 已提交
342
            cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
343 344 345 346 347 348
                        seg_name[i],
                        sc->selector,
                        sc->base,
                        sc->limit,
                        sc->flags);
        }
B
bellard 已提交
349
        cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
350 351 352 353
                    env->ldt.selector,
                    env->ldt.base,
                    env->ldt.limit,
                    env->ldt.flags);
B
bellard 已提交
354
        cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
355 356 357 358
                    env->tr.selector,
                    env->tr.base,
                    env->tr.limit,
                    env->tr.flags);
B
bellard 已提交
359
        cpu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
B
bellard 已提交
360
                    env->gdt.base, env->gdt.limit);
B
bellard 已提交
361
        cpu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
B
bellard 已提交
362
                    env->idt.base, env->idt.limit);
B
bellard 已提交
363
        cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
364 365 366
                    (uint32_t)env->cr[0],
                    env->cr[2],
                    env->cr[3],
B
bellard 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
                    (uint32_t)env->cr[4]);
    } else
#endif
    {
        for(i = 0; i < 6; i++) {
            SegmentCache *sc = &env->segs[i];
            cpu_fprintf(f, "%s =%04x %08x %08x %08x\n",
                        seg_name[i],
                        sc->selector,
                        (uint32_t)sc->base,
                        sc->limit,
                        sc->flags);
        }
        cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n",
                    env->ldt.selector,
                    (uint32_t)env->ldt.base,
                    env->ldt.limit,
                    env->ldt.flags);
        cpu_fprintf(f, "TR =%04x %08x %08x %08x\n",
                    env->tr.selector,
                    (uint32_t)env->tr.base,
                    env->tr.limit,
                    env->tr.flags);
        cpu_fprintf(f, "GDT=     %08x %08x\n",
                    (uint32_t)env->gdt.base, env->gdt.limit);
        cpu_fprintf(f, "IDT=     %08x %08x\n",
                    (uint32_t)env->idt.base, env->idt.limit);
        cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
395 396 397
                    (uint32_t)env->cr[0],
                    (uint32_t)env->cr[2],
                    (uint32_t)env->cr[3],
B
bellard 已提交
398
                    (uint32_t)env->cr[4]);
B
bellard 已提交
399
    }
B
bellard 已提交
400 401
    if (flags & X86_DUMP_CCOP) {
        if ((unsigned)env->cc_op < CC_OP_NB)
B
bellard 已提交
402
            snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
B
bellard 已提交
403 404
        else
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
B
bellard 已提交
405 406
#ifdef TARGET_X86_64
        if (env->hflags & HF_CS64_MASK) {
B
bellard 已提交
407
            cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
408
                        env->cc_src, env->cc_dst,
B
bellard 已提交
409
                        cc_op_name);
410
        } else
B
bellard 已提交
411 412 413
#endif
        {
            cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
414
                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
B
bellard 已提交
415 416
                        cc_op_name);
        }
B
bellard 已提交
417 418
    }
    if (flags & X86_DUMP_FPU) {
B
bellard 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        int fptag;
        fptag = 0;
        for(i = 0; i < 8; i++) {
            fptag |= ((!env->fptags[i]) << i);
        }
        cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
                    env->fpuc,
                    (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
                    env->fpstt,
                    fptag,
                    env->mxcsr);
        for(i=0;i<8;i++) {
#if defined(USE_X86LDOUBLE)
            union {
                long double d;
                struct {
                    uint64_t lower;
                    uint16_t upper;
                } l;
            } tmp;
            tmp.d = env->fpregs[i].d;
B
bellard 已提交
440
            cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
B
bellard 已提交
441 442
                        i, tmp.l.lower, tmp.l.upper);
#else
B
bellard 已提交
443
            cpu_fprintf(f, "FPR%d=%016" PRIx64,
B
bellard 已提交
444 445 446 447 448 449 450
                        i, env->fpregs[i].mmx.q);
#endif
            if ((i & 1) == 1)
                cpu_fprintf(f, "\n");
            else
                cpu_fprintf(f, " ");
        }
451
        if (env->hflags & HF_CS64_MASK)
B
bellard 已提交
452 453 454 455 456
            nb = 16;
        else
            nb = 8;
        for(i=0;i<nb;i++) {
            cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
457
                        i,
B
bellard 已提交
458 459 460 461 462 463 464 465 466
                        env->xmm_regs[i].XMM_L(3),
                        env->xmm_regs[i].XMM_L(2),
                        env->xmm_regs[i].XMM_L(1),
                        env->xmm_regs[i].XMM_L(0));
            if ((i & 1) == 1)
                cpu_fprintf(f, "\n");
            else
                cpu_fprintf(f, " ");
        }
B
bellard 已提交
467 468 469 470 471 472 473
    }
}

/***********************************************************/
/* x86 mmu */
/* XXX: add PGE support */

B
bellard 已提交
474 475 476
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
{
    a20_state = (a20_state != 0);
477
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
478 479 480
#if defined(DEBUG_MMU)
        printf("A20 update: a20=%d\n", a20_state);
#endif
B
a20 fix  
bellard 已提交
481 482
        /* if the cpu is currently executing code, we must unlink it and
           all the potentially executing TB */
483
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
B
a20 fix  
bellard 已提交
484

B
bellard 已提交
485 486
        /* when a20 is changed, all the MMU mappings are invalid, so
           we must flush everything */
487 488
        tlb_flush(env, 1);
        env->a20_mask = 0xffefffff | (a20_state << 20);
B
bellard 已提交
489 490 491
    }
}

492
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
B
bellard 已提交
493
{
494
    int pe_state;
B
bellard 已提交
495

496
#if defined(DEBUG_MMU)
497
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
B
bellard 已提交
498
#endif
499 500 501
    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
        tlb_flush(env, 1);
B
bellard 已提交
502
    }
B
bellard 已提交
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520

#ifdef TARGET_X86_64
    if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
        (env->efer & MSR_EFER_LME)) {
        /* enter in long mode */
        /* XXX: generate an exception */
        if (!(env->cr[4] & CR4_PAE_MASK))
            return;
        env->efer |= MSR_EFER_LMA;
        env->hflags |= HF_LMA_MASK;
    } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
               (env->efer & MSR_EFER_LMA)) {
        /* exit long mode */
        env->efer &= ~MSR_EFER_LMA;
        env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
        env->eip &= 0xffffffff;
    }
#endif
B
bellard 已提交
521
    env->cr[0] = new_cr0 | CR0_ET_MASK;
522

523 524 525 526 527
    /* update PE flag in hidden flags */
    pe_state = (env->cr[0] & CR0_PE_MASK);
    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
    /* ensure that ADDSEG is always set in real mode */
    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
528 529 530
    /* update FPU flags */
    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
        ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
B
bellard 已提交
531 532
}

B
bellard 已提交
533 534
/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
   the PDPT */
B
bellard 已提交
535
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
B
bellard 已提交
536
{
537
    env->cr[3] = new_cr3;
B
bellard 已提交
538 539
    if (env->cr[0] & CR0_PG_MASK) {
#if defined(DEBUG_MMU)
B
bellard 已提交
540
        printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
B
bellard 已提交
541
#endif
542
        tlb_flush(env, 0);
B
bellard 已提交
543 544 545
    }
}

546
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
B
bellard 已提交
547
{
548
#if defined(DEBUG_MMU)
B
bellard 已提交
549
    printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
550 551 552 553 554
#endif
    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
        tlb_flush(env, 1);
    }
B
bellard 已提交
555 556 557 558 559 560 561 562
    /* SSE handling */
    if (!(env->cpuid_features & CPUID_SSE))
        new_cr4 &= ~CR4_OSFXSR_MASK;
    if (new_cr4 & CR4_OSFXSR_MASK)
        env->hflags |= HF_OSFXSR_MASK;
    else
        env->hflags &= ~HF_OSFXSR_MASK;

563
    env->cr[4] = new_cr4;
B
bellard 已提交
564 565 566
}

/* XXX: also flush 4MB pages */
567
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
B
bellard 已提交
568 569 570 571
{
    tlb_flush_page(env, addr);
}

572
#if defined(CONFIG_USER_ONLY)
B
bellard 已提交
573

574
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
575
                             int is_write, int mmu_idx, int is_softmmu)
B
bellard 已提交
576
{
B
bellard 已提交
577 578 579 580 581
    /* user mode only emulation */
    is_write &= 1;
    env->cr[2] = addr;
    env->error_code = (is_write << PG_ERROR_W_BIT);
    env->error_code |= PG_ERROR_U_MASK;
B
bellard 已提交
582
    env->exception_index = EXCP0E_PAGE;
B
bellard 已提交
583
    return 1;
B
bellard 已提交
584 585
}

586
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
B
bellard 已提交
587
{
B
bellard 已提交
588
    return addr;
B
bellard 已提交
589 590
}

B
bellard 已提交
591 592
#else

B
bellard 已提交
593 594
#define PHYS_ADDR_MASK 0xfffff000

B
bellard 已提交
595
/* return value:
596 597
   -1 = cannot handle fault
   0  = nothing more to do
B
bellard 已提交
598 599 600
   1  = generate PF fault
   2  = soft MMU activation required for this block
*/
601
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
602
                             int is_write1, int mmu_idx, int is_softmmu)
B
bellard 已提交
603
{
B
bellard 已提交
604
    uint64_t ptep, pte;
B
bellard 已提交
605
    uint32_t pdpe_addr, pde_addr, pte_addr;
606
    int error_code, is_dirty, prot, page_size, ret, is_write, is_user;
B
bellard 已提交
607 608
    unsigned long paddr, page_offset;
    target_ulong vaddr, virt_addr;
609

610
    is_user = mmu_idx == MMU_USER_IDX;
611
#if defined(DEBUG_MMU)
612
    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
B
bellard 已提交
613
           addr, is_write1, is_user, env->eip);
B
bellard 已提交
614
#endif
B
bellard 已提交
615
    is_write = is_write1 & 1;
616

B
bellard 已提交
617 618
    if (!(env->cr[0] & CR0_PG_MASK)) {
        pte = addr;
B
bellard 已提交
619
        virt_addr = addr & TARGET_PAGE_MASK;
B
bellard 已提交
620
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
B
bellard 已提交
621 622 623 624
        page_size = 4096;
        goto do_mapping;
    }

B
bellard 已提交
625
    if (env->cr[4] & CR4_PAE_MASK) {
B
bellard 已提交
626 627
        uint64_t pde, pdpe;

B
bellard 已提交
628 629 630
        /* XXX: we only use 32 bit physical addresses */
#ifdef TARGET_X86_64
        if (env->hflags & HF_LMA_MASK) {
B
bellard 已提交
631 632
            uint32_t pml4e_addr;
            uint64_t pml4e;
B
bellard 已提交
633 634 635 636 637
            int32_t sext;

            /* test virtual address sign extension */
            sext = (int64_t)addr >> 47;
            if (sext != 0 && sext != -1) {
B
bellard 已提交
638 639 640
                env->error_code = 0;
                env->exception_index = EXCP0D_GPF;
                return 1;
B
bellard 已提交
641
            }
642

643
            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
B
bellard 已提交
644
                env->a20_mask;
B
bellard 已提交
645
            pml4e = ldq_phys(pml4e_addr);
B
bellard 已提交
646 647 648 649
            if (!(pml4e & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
650 651 652 653
            if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
B
bellard 已提交
654 655
            if (!(pml4e & PG_ACCESSED_MASK)) {
                pml4e |= PG_ACCESSED_MASK;
B
bellard 已提交
656
                stl_phys_notdirty(pml4e_addr, pml4e);
B
bellard 已提交
657
            }
B
bellard 已提交
658
            ptep = pml4e ^ PG_NX_MASK;
659
            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
B
bellard 已提交
660
                env->a20_mask;
B
bellard 已提交
661
            pdpe = ldq_phys(pdpe_addr);
B
bellard 已提交
662 663 664 665
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
666 667 668 669 670
            if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
            ptep &= pdpe ^ PG_NX_MASK;
B
bellard 已提交
671 672
            if (!(pdpe & PG_ACCESSED_MASK)) {
                pdpe |= PG_ACCESSED_MASK;
B
bellard 已提交
673
                stl_phys_notdirty(pdpe_addr, pdpe);
B
bellard 已提交
674
            }
B
bellard 已提交
675
        } else
B
bellard 已提交
676 677
#endif
        {
B
bellard 已提交
678
            /* XXX: load them when cr3 is loaded ? */
679
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
B
bellard 已提交
680
                env->a20_mask;
B
bellard 已提交
681
            pdpe = ldq_phys(pdpe_addr);
B
bellard 已提交
682 683 684 685
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
686
            ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
687
        }
B
bellard 已提交
688

B
bellard 已提交
689
        pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
B
bellard 已提交
690
            env->a20_mask;
B
bellard 已提交
691
        pde = ldq_phys(pde_addr);
B
bellard 已提交
692 693 694
        if (!(pde & PG_PRESENT_MASK)) {
            error_code = 0;
            goto do_fault;
B
bellard 已提交
695
        }
B
bellard 已提交
696 697 698 699 700
        if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
            error_code = PG_ERROR_RSVD_MASK;
            goto do_fault;
        }
        ptep &= pde ^ PG_NX_MASK;
B
bellard 已提交
701 702 703
        if (pde & PG_PSE_MASK) {
            /* 2 MB page */
            page_size = 2048 * 1024;
B
bellard 已提交
704 705 706 707 708 709 710 711 712
            ptep ^= PG_NX_MASK;
            if ((ptep & PG_NX_MASK) && is_write1 == 2)
                goto do_fault_protect;
            if (is_user) {
                if (!(ptep & PG_USER_MASK))
                    goto do_fault_protect;
                if (is_write && !(ptep & PG_RW_MASK))
                    goto do_fault_protect;
            } else {
713 714
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
715 716 717 718 719 720 721 722 723 724
                    goto do_fault_protect;
            }
            is_dirty = is_write && !(pde & PG_DIRTY_MASK);
            if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
                pde |= PG_ACCESSED_MASK;
                if (is_dirty)
                    pde |= PG_DIRTY_MASK;
                stl_phys_notdirty(pde_addr, pde);
            }
            /* align to page_size */
725
            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
B
bellard 已提交
726
            virt_addr = addr & ~(page_size - 1);
B
bellard 已提交
727 728 729 730
        } else {
            /* 4 KB page */
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
B
bellard 已提交
731
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
732
            }
B
bellard 已提交
733
            pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
B
bellard 已提交
734
                env->a20_mask;
B
bellard 已提交
735 736 737 738 739 740 741 742 743 744 745 746 747
            pte = ldq_phys(pte_addr);
            if (!(pte & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
            if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
            /* combine pde and pte nx, user and rw protections */
            ptep &= pte ^ PG_NX_MASK;
            ptep ^= PG_NX_MASK;
            if ((ptep & PG_NX_MASK) && is_write1 == 2)
748
                goto do_fault_protect;
B
bellard 已提交
749 750 751 752 753 754 755
            if (is_user) {
                if (!(ptep & PG_USER_MASK))
                    goto do_fault_protect;
                if (is_write && !(ptep & PG_RW_MASK))
                    goto do_fault_protect;
            } else {
                if ((env->cr[0] & CR0_WP_MASK) &&
756
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
757 758 759 760 761 762 763 764 765 766 767 768
                    goto do_fault_protect;
            }
            is_dirty = is_write && !(pte & PG_DIRTY_MASK);
            if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
                pte |= PG_ACCESSED_MASK;
                if (is_dirty)
                    pte |= PG_DIRTY_MASK;
                stl_phys_notdirty(pte_addr, pte);
            }
            page_size = 4096;
            virt_addr = addr & ~0xfff;
            pte = pte & (PHYS_ADDR_MASK | 0xfff);
B
bellard 已提交
769
        }
B
bellard 已提交
770
    } else {
B
bellard 已提交
771 772
        uint32_t pde;

B
bellard 已提交
773
        /* page directory entry */
774
        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
B
bellard 已提交
775
            env->a20_mask;
B
bellard 已提交
776
        pde = ldl_phys(pde_addr);
B
bellard 已提交
777
        if (!(pde & PG_PRESENT_MASK)) {
B
bellard 已提交
778 779 780
            error_code = 0;
            goto do_fault;
        }
B
bellard 已提交
781 782 783 784 785 786 787 788 789
        /* if PSE bit is set, then we use a 4MB page */
        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
            page_size = 4096 * 1024;
            if (is_user) {
                if (!(pde & PG_USER_MASK))
                    goto do_fault_protect;
                if (is_write && !(pde & PG_RW_MASK))
                    goto do_fault_protect;
            } else {
790 791
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(pde & PG_RW_MASK))
B
bellard 已提交
792 793 794 795 796 797 798
                    goto do_fault_protect;
            }
            is_dirty = is_write && !(pde & PG_DIRTY_MASK);
            if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
                pde |= PG_ACCESSED_MASK;
                if (is_dirty)
                    pde |= PG_DIRTY_MASK;
B
bellard 已提交
799
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
800
            }
801

B
bellard 已提交
802 803 804
            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
            ptep = pte;
            virt_addr = addr & ~(page_size - 1);
B
bellard 已提交
805
        } else {
B
bellard 已提交
806 807
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
B
bellard 已提交
808
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
809 810 811
            }

            /* page directory entry */
812
            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
B
bellard 已提交
813
                env->a20_mask;
B
bellard 已提交
814
            pte = ldl_phys(pte_addr);
B
bellard 已提交
815 816 817 818 819 820 821 822 823 824 825 826 827
            if (!(pte & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
            /* combine pde and pte user and rw protections */
            ptep = pte & pde;
            if (is_user) {
                if (!(ptep & PG_USER_MASK))
                    goto do_fault_protect;
                if (is_write && !(ptep & PG_RW_MASK))
                    goto do_fault_protect;
            } else {
                if ((env->cr[0] & CR0_WP_MASK) &&
828
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
829 830 831 832 833 834 835
                    goto do_fault_protect;
            }
            is_dirty = is_write && !(pte & PG_DIRTY_MASK);
            if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
                pte |= PG_ACCESSED_MASK;
                if (is_dirty)
                    pte |= PG_DIRTY_MASK;
B
bellard 已提交
836
                stl_phys_notdirty(pte_addr, pte);
B
bellard 已提交
837 838 839
            }
            page_size = 4096;
            virt_addr = addr & ~0xfff;
B
bellard 已提交
840
        }
B
bellard 已提交
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    }
    /* the page can be put in the TLB */
    prot = PAGE_READ;
    if (!(ptep & PG_NX_MASK))
        prot |= PAGE_EXEC;
    if (pte & PG_DIRTY_MASK) {
        /* only set write access if already dirty... otherwise wait
           for dirty access */
        if (is_user) {
            if (ptep & PG_RW_MASK)
                prot |= PAGE_WRITE;
        } else {
            if (!(env->cr[0] & CR0_WP_MASK) ||
                (ptep & PG_RW_MASK))
                prot |= PAGE_WRITE;
856
        }
B
bellard 已提交
857 858
    }
 do_mapping:
859
    pte = pte & env->a20_mask;
B
bellard 已提交
860

861 862 863 864 865
    /* Even if 4MB pages, we map only one 4KB page in the cache to
       avoid filling it too fast */
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
    vaddr = virt_addr + page_offset;
866

867
    ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
B
bellard 已提交
868 869 870 871
    return ret;
 do_fault_protect:
    error_code = PG_ERROR_P_MASK;
 do_fault:
B
bellard 已提交
872
    error_code |= (is_write << PG_ERROR_W_BIT);
B
bellard 已提交
873
    if (is_user)
B
bellard 已提交
874
        error_code |= PG_ERROR_U_MASK;
875 876
    if (is_write1 == 2 &&
        (env->efer & MSR_EFER_NXE) &&
B
bellard 已提交
877 878
        (env->cr[4] & CR4_PAE_MASK))
        error_code |= PG_ERROR_I_D_MASK;
T
ths 已提交
879 880 881 882 883
    if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) {
        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr);
    } else {
        env->cr[2] = addr;
    }
B
bellard 已提交
884
    env->error_code = error_code;
B
bellard 已提交
885
    env->exception_index = EXCP0E_PAGE;
T
ths 已提交
886 887 888
    /* the VMM will handle this */
    if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE))
        return 2;
B
bellard 已提交
889 890
    return 1;
}
891

892
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
893
{
894
    uint32_t pde_addr, pte_addr;
895 896
    uint32_t pde, pte, paddr, page_offset, page_size;

897 898 899 900 901 902 903 904 905 906 907 908 909 910
    if (env->cr[4] & CR4_PAE_MASK) {
        uint32_t pdpe_addr, pde_addr, pte_addr;
        uint32_t pdpe;

        /* XXX: we only use 32 bit physical addresses */
#ifdef TARGET_X86_64
        if (env->hflags & HF_LMA_MASK) {
            uint32_t pml4e_addr, pml4e;
            int32_t sext;

            /* test virtual address sign extension */
            sext = (int64_t)addr >> 47;
            if (sext != 0 && sext != -1)
                return -1;
911

912
            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
913
                env->a20_mask;
B
bellard 已提交
914
            pml4e = ldl_phys(pml4e_addr);
915 916
            if (!(pml4e & PG_PRESENT_MASK))
                return -1;
917

918
            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
919
                env->a20_mask;
B
bellard 已提交
920
            pdpe = ldl_phys(pdpe_addr);
921 922
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
923
        } else
924 925
#endif
        {
926
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
927
                env->a20_mask;
B
bellard 已提交
928
            pdpe = ldl_phys(pdpe_addr);
929 930 931 932 933 934
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
        }

        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
            env->a20_mask;
B
bellard 已提交
935
        pde = ldl_phys(pde_addr);
936
        if (!(pde & PG_PRESENT_MASK)) {
937
            return -1;
938 939 940 941 942 943 944 945 946 947
        }
        if (pde & PG_PSE_MASK) {
            /* 2 MB page */
            page_size = 2048 * 1024;
            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
        } else {
            /* 4 KB page */
            pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
                env->a20_mask;
            page_size = 4096;
B
bellard 已提交
948
            pte = ldl_phys(pte_addr);
949 950 951 952 953
        }
    } else {
        if (!(env->cr[0] & CR0_PG_MASK)) {
            pte = addr;
            page_size = 4096;
954 955
        } else {
            /* page directory entry */
956
            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
B
bellard 已提交
957
            pde = ldl_phys(pde_addr);
958
            if (!(pde & PG_PRESENT_MASK))
959
                return -1;
960 961 962 963 964 965
            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
                pte = pde & ~0x003ff000; /* align to 4MB */
                page_size = 4096 * 1024;
            } else {
                /* page directory entry */
                pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
B
bellard 已提交
966
                pte = ldl_phys(pte_addr);
967 968 969 970
                if (!(pte & PG_PRESENT_MASK))
                    return -1;
                page_size = 4096;
            }
971
        }
972
        pte = pte & env->a20_mask;
973
    }
974

975 976 977 978
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
    return paddr;
}
B
bellard 已提交
979
#endif /* !CONFIG_USER_ONLY */
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000

#if defined(USE_CODE_COPY)
struct fpstate {
    uint16_t fpuc;
    uint16_t dummy1;
    uint16_t fpus;
    uint16_t dummy2;
    uint16_t fptag;
    uint16_t dummy3;

    uint32_t fpip;
    uint32_t fpcs;
    uint32_t fpoo;
    uint32_t fpos;
    uint8_t fpregs1[8 * 10];
};

void restore_native_fp_state(CPUState *env)
{
    int fptag, i, j;
    struct fpstate fp1, *fp = &fp1;
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    fp->fpuc = env->fpuc;
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
    fptag = 0;
    for (i=7; i>=0; i--) {
	fptag <<= 2;
	if (env->fptags[i]) {
            fptag |= 3;
        } else {
            /* the FPU automatically computes it */
        }
    }
    fp->fptag = fptag;
    j = env->fpstt;
    for(i = 0;i < 8; i++) {
B
bellard 已提交
1016
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
1017 1018 1019 1020 1021
        j = (j + 1) & 7;
    }
    asm volatile ("frstor %0" : "=m" (*fp));
    env->native_fp_regs = 1;
}
1022

1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
void save_native_fp_state(CPUState *env)
{
    int fptag, i, j;
    uint16_t fpuc;
    struct fpstate fp1, *fp = &fp1;

    asm volatile ("fsave %0" : : "m" (*fp));
    env->fpuc = fp->fpuc;
    env->fpstt = (fp->fpus >> 11) & 7;
    env->fpus = fp->fpus & ~0x3800;
    fptag = fp->fptag;
    for(i = 0;i < 8; i++) {
        env->fptags[i] = ((fptag & 3) == 3);
        fptag >>= 2;
    }
    j = env->fpstt;
    for(i = 0;i < 8; i++) {
B
bellard 已提交
1040
        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
1041 1042 1043 1044 1045 1046 1047 1048 1049
        j = (j + 1) & 7;
    }
    /* we must restore the default rounding state */
    /* XXX: we do not restore the exception state */
    fpuc = 0x037f | (env->fpuc & (3 << 10));
    asm volatile("fldcw %0" : : "m" (fpuc));
    env->native_fp_regs = 0;
}
#endif