helper2.c 37.8 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

B
bellard 已提交
34
static int cpu_x86_register (CPUX86State *env, const char *cpu_model);
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, 
                                    uint32_t *ext_features, 
                                    uint32_t *ext2_features, 
                                    uint32_t *ext3_features)
{
    int i;
    /* feature flags taken from "Intel Processor Identification and the CPUID
     * Instruction" and AMD's "CPUID Specification". In cases of disagreement 
     * about feature names, the Linux name is used. */
    const char *feature_name[] = {
        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
        "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
        "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
    };
    const char *ext_feature_name[] = {
       "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
       "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
       NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    };
    const char *ext2_feature_name[] = {
       "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
       "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov",
       "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
       "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
    };
    const char *ext3_feature_name[] = {
       "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
       "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    };

    for ( i = 0 ; i < 32 ; i++ ) 
        if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
            *features |= 1 << i;
            return;
        }
    for ( i = 0 ; i < 32 ; i++ ) 
        if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
            *ext_features |= 1 << i;
            return;
        }
    for ( i = 0 ; i < 32 ; i++ ) 
        if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
            *ext2_features |= 1 << i;
            return;
        }
    for ( i = 0 ; i < 32 ; i++ ) 
        if (ext3_features[i] && !strcmp (flagname, ext3_feature_name[i])) {
            *ext3_features |= 1 << i;
            return;
        }
    fprintf(stderr, "CPU feature %s not found\n", flagname);
}

B
bellard 已提交
93
CPUX86State *cpu_x86_init(const char *cpu_model)
B
bellard 已提交
94 95 96 97
{
    CPUX86State *env;
    static int inited;

B
bellard 已提交
98
    env = qemu_mallocz(sizeof(CPUX86State));
B
bellard 已提交
99 100
    if (!env)
        return NULL;
B
bellard 已提交
101 102
    cpu_exec_init(env);

B
bellard 已提交
103 104 105 106 107
    /* init various static tables */
    if (!inited) {
        inited = 1;
        optimize_flags_init();
    }
B
bellard 已提交
108 109 110 111
    if (cpu_x86_register(env, cpu_model) < 0) {
        cpu_x86_close(env);
        return NULL;
    }
112 113 114
    cpu_reset(env);
#ifdef USE_KQEMU
    kqemu_init(env);
B
bellard 已提交
115
#endif
116 117
    return env;
}
118

B
bellard 已提交
119
typedef struct x86_def_t {
120 121 122 123 124 125 126
    const char *name;
    uint32_t vendor1, vendor2, vendor3;
    int family;
    int model;
    int stepping;
    uint32_t features, ext_features, ext2_features, ext3_features;
    uint32_t xlevel;
B
bellard 已提交
127
} x86_def_t;
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
          CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
          CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
          CPUID_PAE | CPUID_SEP | CPUID_APIC)
static x86_def_t x86_defs[] = {
#ifdef TARGET_X86_64
    {
        .name = "qemu64",
        .vendor1 = 0x68747541, /* "Auth" */
        .vendor2 = 0x69746e65, /* "enti" */
        .vendor3 = 0x444d4163, /* "cAMD" */
        .family = 6,
        .model = 2,
        .stepping = 3,
        .features = PPRO_FEATURES | 
144
        /* these features are needed for Win64 and aren't fully implemented */
145
            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
146
        /* this feature is needed for Solaris and isn't fully implemented */
147 148 149 150 151 152 153
            CPUID_PSE36,
        .ext_features = CPUID_EXT_SSE3,
        .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | 
            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
        .ext3_features = CPUID_EXT3_SVM,
        .xlevel = 0x80000008,
    },
B
bellard 已提交
154
#endif
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    {
        .name = "qemu32",
        .family = 6,
        .model = 3,
        .stepping = 3,
        .features = PPRO_FEATURES,
        .ext_features = CPUID_EXT_SSE3,
        .xlevel = 0,
    },
    {
        .name = "486",
        .family = 4,
        .model = 0,
        .stepping = 0,
        .features = 0x0000000B,
        .xlevel = 0,
    },
    {
        .name = "pentium",
        .family = 5,
        .model = 4,
        .stepping = 3,
        .features = 0x008001BF,
        .xlevel = 0,
    },
    {
        .name = "pentium2",
        .family = 6,
        .model = 5,
        .stepping = 2,
        .features = 0x0183F9FF,
        .xlevel = 0,
    },
    {
        .name = "pentium3",
        .family = 6,
        .model = 7,
        .stepping = 3,
        .features = 0x0383F9FF,
        .xlevel = 0,
    },
};

B
bellard 已提交
198
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
199 200
{
    unsigned int i;
B
bellard 已提交
201
    x86_def_t *def;
202 203 204 205 206 207 208

    char *s = strdup(cpu_model);
    char *featurestr, *name = strtok(s, ",");
    uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0;
    uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0;
    int family = -1, model = -1, stepping = -1;

B
bellard 已提交
209
    def = NULL;
210 211
    for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
        if (strcmp(name, x86_defs[i].name) == 0) {
B
bellard 已提交
212
            def = &x86_defs[i];
213 214
            break;
        }
B
bellard 已提交
215
    }
B
bellard 已提交
216
    if (!def)
217
        goto error;
B
bellard 已提交
218
    memcpy(x86_cpu_def, def, sizeof(*def));
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276

    featurestr = strtok(NULL, ",");

    while (featurestr) {
        char *val;
        if (featurestr[0] == '+') {
            add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features);
        } else if (featurestr[0] == '-') {
            add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features);
        } else if ((val = strchr(featurestr, '='))) {
            *val = 0; val++;
            if (!strcmp(featurestr, "family")) {
                char *err;
                family = strtol(val, &err, 10);
                if (!*val || *err || family < 0) {
                    fprintf(stderr, "bad numerical value %s\n", val);
                    x86_cpu_def = 0;
                    goto error;
                }
                x86_cpu_def->family = family;
            } else if (!strcmp(featurestr, "model")) {
                char *err;
                model = strtol(val, &err, 10);
                if (!*val || *err || model < 0 || model > 0xf) {
                    fprintf(stderr, "bad numerical value %s\n", val);
                    x86_cpu_def = 0;
                    goto error;
                }
                x86_cpu_def->model = model;
            } else if (!strcmp(featurestr, "stepping")) {
                char *err;
                stepping = strtol(val, &err, 10);
                if (!*val || *err || stepping < 0 || stepping > 0xf) {
                    fprintf(stderr, "bad numerical value %s\n", val);
                    x86_cpu_def = 0;
                    goto error;
                }
                x86_cpu_def->stepping = stepping;
            } else {
                fprintf(stderr, "unregnized feature %s\n", featurestr);
                x86_cpu_def = 0;
                goto error;
            }
        } else {
            fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
            x86_cpu_def = 0;
            goto error;
        }
        featurestr = strtok(NULL, ",");
    }
    x86_cpu_def->features |= plus_features;
    x86_cpu_def->ext_features |= plus_ext_features;
    x86_cpu_def->ext2_features |= plus_ext2_features;
    x86_cpu_def->ext3_features |= plus_ext3_features;
    x86_cpu_def->features &= ~minus_features;
    x86_cpu_def->ext_features &= ~minus_ext_features;
    x86_cpu_def->ext2_features &= ~minus_ext2_features;
    x86_cpu_def->ext3_features &= ~minus_ext3_features;
B
bellard 已提交
277 278
    free(s);
    return 0;
279 280 281

error:
    free(s);
B
bellard 已提交
282
    return -1;
283 284 285 286 287 288 289 290 291 292
}

void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
    unsigned int i;

    for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++)
        (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
}

B
bellard 已提交
293
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
294
{
B
bellard 已提交
295 296 297 298
    x86_def_t def1, *def = &def1;

    if (cpu_x86_find_by_name(def, cpu_model) < 0)
        return -1;
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    if (def->vendor1) {
        env->cpuid_vendor1 = def->vendor1;
        env->cpuid_vendor2 = def->vendor2;
        env->cpuid_vendor3 = def->vendor3;
    } else {
        env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
        env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
        env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
    }
    env->cpuid_level = 2;
    env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping;
    env->cpuid_features = def->features;
    env->pat = 0x0007040600070406ULL;
    env->cpuid_ext_features = def->ext_features;
    env->cpuid_ext2_features = def->ext2_features;
    env->cpuid_xlevel = def->xlevel;
    env->cpuid_ext3_features = def->ext3_features;
    {
        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));
        }
    }
    return 0;
B
bellard 已提交
329 330 331 332 333 334 335 336
}

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

    memset(env, 0, offsetof(CPUX86State, breakpoints));
337 338

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

340 341
    env->old_exception = -1;

B
bellard 已提交
342 343
    /* init to reset state */

B
bellard 已提交
344 345 346
#ifdef CONFIG_SOFTMMU
    env->hflags |= HF_SOFTMMU_MASK;
#endif
T
ths 已提交
347
    env->hflags |= HF_GIF_MASK;
348 349 350

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

353 354 355 356 357 358
    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;
359

360
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0);
B
bellard 已提交
361 362 363 364 365
    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);
366

367
    env->eip = 0xfff0;
368
    env->regs[R_EDX] = env->cpuid_version;
369

370
    env->eflags = 0x2;
371

372 373 374 375
    /* FPU init */
    for(i = 0;i < 8; i++)
        env->fptags[i] = 1;
    env->fpuc = 0x37f;
B
bellard 已提交
376 377

    env->mxcsr = 0x1f80;
B
bellard 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390
}

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

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

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

392 393 394
    "MULB",
    "MULW",
    "MULL",
B
bellard 已提交
395 396
    "MULQ",

B
bellard 已提交
397 398 399
    "ADDB",
    "ADDW",
    "ADDL",
B
bellard 已提交
400 401
    "ADDQ",

B
bellard 已提交
402 403 404
    "ADCB",
    "ADCW",
    "ADCL",
B
bellard 已提交
405 406
    "ADCQ",

B
bellard 已提交
407 408 409
    "SUBB",
    "SUBW",
    "SUBL",
B
bellard 已提交
410 411
    "SUBQ",

B
bellard 已提交
412 413 414
    "SBBB",
    "SBBW",
    "SBBL",
B
bellard 已提交
415 416
    "SBBQ",

B
bellard 已提交
417 418 419
    "LOGICB",
    "LOGICW",
    "LOGICL",
B
bellard 已提交
420 421
    "LOGICQ",

B
bellard 已提交
422 423 424
    "INCB",
    "INCW",
    "INCL",
B
bellard 已提交
425 426
    "INCQ",

B
bellard 已提交
427 428 429
    "DECB",
    "DECW",
    "DECL",
B
bellard 已提交
430 431
    "DECQ",

B
bellard 已提交
432 433 434
    "SHLB",
    "SHLW",
    "SHLL",
B
bellard 已提交
435 436
    "SHLQ",

B
bellard 已提交
437 438 439
    "SARB",
    "SARW",
    "SARL",
B
bellard 已提交
440
    "SARQ",
B
bellard 已提交
441 442
};

443
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
444 445
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
446
{
B
bellard 已提交
447
    int eflags, i, nb;
B
bellard 已提交
448
    char cc_op_name[32];
B
bellard 已提交
449
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
B
bellard 已提交
450 451

    eflags = env->eflags;
B
bellard 已提交
452 453
#ifdef TARGET_X86_64
    if (env->hflags & HF_CS64_MASK) {
454
        cpu_fprintf(f,
B
bellard 已提交
455 456 457 458
                    "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 已提交
459
                    "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
                    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 已提交
476 477 478 479 480 481 482 483
                    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' : '-',
484
                    env->hflags & HF_CPL_MASK,
B
bellard 已提交
485
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
B
bellard 已提交
486
                    (env->a20_mask >> 20) & 1,
B
bellard 已提交
487
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
488
                    (env->hflags >> HF_HALTED_SHIFT) & 1);
489
    } else
B
bellard 已提交
490 491 492 493
#endif
    {
        cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
                    "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
B
bellard 已提交
494
                    "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
495 496 497 498 499 500 501 502
                    (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 已提交
503 504 505 506 507 508 509 510
                    (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' : '-',
511
                    env->hflags & HF_CPL_MASK,
B
bellard 已提交
512
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
B
bellard 已提交
513
                    (env->a20_mask >> 20) & 1,
B
bellard 已提交
514
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
515
                    (env->hflags >> HF_HALTED_SHIFT) & 1);
B
bellard 已提交
516 517 518 519 520 521
    }

#ifdef TARGET_X86_64
    if (env->hflags & HF_LMA_MASK) {
        for(i = 0; i < 6; i++) {
            SegmentCache *sc = &env->segs[i];
B
bellard 已提交
522
            cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
523 524 525 526 527 528
                        seg_name[i],
                        sc->selector,
                        sc->base,
                        sc->limit,
                        sc->flags);
        }
B
bellard 已提交
529
        cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
530 531 532 533
                    env->ldt.selector,
                    env->ldt.base,
                    env->ldt.limit,
                    env->ldt.flags);
B
bellard 已提交
534
        cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n",
B
bellard 已提交
535 536 537 538
                    env->tr.selector,
                    env->tr.base,
                    env->tr.limit,
                    env->tr.flags);
B
bellard 已提交
539
        cpu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
B
bellard 已提交
540
                    env->gdt.base, env->gdt.limit);
B
bellard 已提交
541
        cpu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
B
bellard 已提交
542
                    env->idt.base, env->idt.limit);
B
bellard 已提交
543
        cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
544 545 546
                    (uint32_t)env->cr[0],
                    env->cr[2],
                    env->cr[3],
B
bellard 已提交
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
                    (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",
575 576 577
                    (uint32_t)env->cr[0],
                    (uint32_t)env->cr[2],
                    (uint32_t)env->cr[3],
B
bellard 已提交
578
                    (uint32_t)env->cr[4]);
B
bellard 已提交
579
    }
B
bellard 已提交
580 581
    if (flags & X86_DUMP_CCOP) {
        if ((unsigned)env->cc_op < CC_OP_NB)
B
bellard 已提交
582
            snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
B
bellard 已提交
583 584
        else
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
B
bellard 已提交
585 586
#ifdef TARGET_X86_64
        if (env->hflags & HF_CS64_MASK) {
B
bellard 已提交
587
            cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
588
                        env->cc_src, env->cc_dst,
B
bellard 已提交
589
                        cc_op_name);
590
        } else
B
bellard 已提交
591 592 593
#endif
        {
            cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
594
                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
B
bellard 已提交
595 596
                        cc_op_name);
        }
B
bellard 已提交
597 598
    }
    if (flags & X86_DUMP_FPU) {
B
bellard 已提交
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
        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 已提交
620
            cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
B
bellard 已提交
621 622
                        i, tmp.l.lower, tmp.l.upper);
#else
B
bellard 已提交
623
            cpu_fprintf(f, "FPR%d=%016" PRIx64,
B
bellard 已提交
624 625 626 627 628 629 630
                        i, env->fpregs[i].mmx.q);
#endif
            if ((i & 1) == 1)
                cpu_fprintf(f, "\n");
            else
                cpu_fprintf(f, " ");
        }
631
        if (env->hflags & HF_CS64_MASK)
B
bellard 已提交
632 633 634 635 636
            nb = 16;
        else
            nb = 8;
        for(i=0;i<nb;i++) {
            cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
637
                        i,
B
bellard 已提交
638 639 640 641 642 643 644 645 646
                        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 已提交
647 648 649 650 651 652 653
    }
}

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

B
bellard 已提交
654 655 656
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
{
    a20_state = (a20_state != 0);
657
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
658 659 660
#if defined(DEBUG_MMU)
        printf("A20 update: a20=%d\n", a20_state);
#endif
B
a20 fix  
bellard 已提交
661 662
        /* if the cpu is currently executing code, we must unlink it and
           all the potentially executing TB */
663
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
B
a20 fix  
bellard 已提交
664

B
bellard 已提交
665 666
        /* when a20 is changed, all the MMU mappings are invalid, so
           we must flush everything */
667 668
        tlb_flush(env, 1);
        env->a20_mask = 0xffefffff | (a20_state << 20);
B
bellard 已提交
669 670 671
    }
}

672
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
B
bellard 已提交
673
{
674
    int pe_state;
B
bellard 已提交
675

676
#if defined(DEBUG_MMU)
677
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
B
bellard 已提交
678
#endif
679 680 681
    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 已提交
682
    }
B
bellard 已提交
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700

#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 已提交
701
    env->cr[0] = new_cr0 | CR0_ET_MASK;
702

703 704 705 706 707
    /* 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);
708 709 710
    /* 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 已提交
711 712
}

B
bellard 已提交
713 714
/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
   the PDPT */
B
bellard 已提交
715
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
B
bellard 已提交
716
{
717
    env->cr[3] = new_cr3;
B
bellard 已提交
718 719
    if (env->cr[0] & CR0_PG_MASK) {
#if defined(DEBUG_MMU)
B
bellard 已提交
720
        printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
B
bellard 已提交
721
#endif
722
        tlb_flush(env, 0);
B
bellard 已提交
723 724 725
    }
}

726
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
B
bellard 已提交
727
{
728
#if defined(DEBUG_MMU)
B
bellard 已提交
729
    printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
730 731 732 733 734
#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 已提交
735 736 737 738 739 740 741 742
    /* 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;

743
    env->cr[4] = new_cr4;
B
bellard 已提交
744 745 746
}

/* XXX: also flush 4MB pages */
747
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
B
bellard 已提交
748 749 750 751
{
    tlb_flush_page(env, addr);
}

752
#if defined(CONFIG_USER_ONLY)
B
bellard 已提交
753

754
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
755
                             int is_write, int mmu_idx, int is_softmmu)
B
bellard 已提交
756
{
B
bellard 已提交
757 758 759 760 761
    /* 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 已提交
762
    env->exception_index = EXCP0E_PAGE;
B
bellard 已提交
763
    return 1;
B
bellard 已提交
764 765
}

766
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
B
bellard 已提交
767
{
B
bellard 已提交
768
    return addr;
B
bellard 已提交
769 770
}

B
bellard 已提交
771 772
#else

B
bellard 已提交
773 774
#define PHYS_ADDR_MASK 0xfffff000

B
bellard 已提交
775
/* return value:
776 777
   -1 = cannot handle fault
   0  = nothing more to do
B
bellard 已提交
778 779 780
   1  = generate PF fault
   2  = soft MMU activation required for this block
*/
781
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
782
                             int is_write1, int mmu_idx, int is_softmmu)
B
bellard 已提交
783
{
B
bellard 已提交
784
    uint64_t ptep, pte;
B
bellard 已提交
785
    uint32_t pdpe_addr, pde_addr, pte_addr;
786
    int error_code, is_dirty, prot, page_size, ret, is_write, is_user;
B
bellard 已提交
787 788
    unsigned long paddr, page_offset;
    target_ulong vaddr, virt_addr;
789

790
    is_user = mmu_idx == MMU_USER_IDX;
791
#if defined(DEBUG_MMU)
792
    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
B
bellard 已提交
793
           addr, is_write1, is_user, env->eip);
B
bellard 已提交
794
#endif
B
bellard 已提交
795
    is_write = is_write1 & 1;
796

B
bellard 已提交
797 798
    if (!(env->cr[0] & CR0_PG_MASK)) {
        pte = addr;
B
bellard 已提交
799
        virt_addr = addr & TARGET_PAGE_MASK;
B
bellard 已提交
800
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
B
bellard 已提交
801 802 803 804
        page_size = 4096;
        goto do_mapping;
    }

B
bellard 已提交
805
    if (env->cr[4] & CR4_PAE_MASK) {
B
bellard 已提交
806 807
        uint64_t pde, pdpe;

B
bellard 已提交
808 809 810
        /* XXX: we only use 32 bit physical addresses */
#ifdef TARGET_X86_64
        if (env->hflags & HF_LMA_MASK) {
B
bellard 已提交
811 812
            uint32_t pml4e_addr;
            uint64_t pml4e;
B
bellard 已提交
813 814 815 816 817
            int32_t sext;

            /* test virtual address sign extension */
            sext = (int64_t)addr >> 47;
            if (sext != 0 && sext != -1) {
B
bellard 已提交
818 819 820
                env->error_code = 0;
                env->exception_index = EXCP0D_GPF;
                return 1;
B
bellard 已提交
821
            }
822

823
            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
B
bellard 已提交
824
                env->a20_mask;
B
bellard 已提交
825
            pml4e = ldq_phys(pml4e_addr);
B
bellard 已提交
826 827 828 829
            if (!(pml4e & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
830 831 832 833
            if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
B
bellard 已提交
834 835
            if (!(pml4e & PG_ACCESSED_MASK)) {
                pml4e |= PG_ACCESSED_MASK;
B
bellard 已提交
836
                stl_phys_notdirty(pml4e_addr, pml4e);
B
bellard 已提交
837
            }
B
bellard 已提交
838
            ptep = pml4e ^ PG_NX_MASK;
839
            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
B
bellard 已提交
840
                env->a20_mask;
B
bellard 已提交
841
            pdpe = ldq_phys(pdpe_addr);
B
bellard 已提交
842 843 844 845
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
846 847 848 849 850
            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 已提交
851 852
            if (!(pdpe & PG_ACCESSED_MASK)) {
                pdpe |= PG_ACCESSED_MASK;
B
bellard 已提交
853
                stl_phys_notdirty(pdpe_addr, pdpe);
B
bellard 已提交
854
            }
B
bellard 已提交
855
        } else
B
bellard 已提交
856 857
#endif
        {
B
bellard 已提交
858
            /* XXX: load them when cr3 is loaded ? */
859
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
B
bellard 已提交
860
                env->a20_mask;
B
bellard 已提交
861
            pdpe = ldq_phys(pdpe_addr);
B
bellard 已提交
862 863 864 865
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
B
bellard 已提交
866
            ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
867
        }
B
bellard 已提交
868

B
bellard 已提交
869
        pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
B
bellard 已提交
870
            env->a20_mask;
B
bellard 已提交
871
        pde = ldq_phys(pde_addr);
B
bellard 已提交
872 873 874
        if (!(pde & PG_PRESENT_MASK)) {
            error_code = 0;
            goto do_fault;
B
bellard 已提交
875
        }
B
bellard 已提交
876 877 878 879 880
        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 已提交
881 882 883
        if (pde & PG_PSE_MASK) {
            /* 2 MB page */
            page_size = 2048 * 1024;
B
bellard 已提交
884 885 886 887 888 889 890 891 892
            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 {
893 894
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
895 896 897 898 899 900 901 902 903 904
                    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 */
905
            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
B
bellard 已提交
906
            virt_addr = addr & ~(page_size - 1);
B
bellard 已提交
907 908 909 910
        } else {
            /* 4 KB page */
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
B
bellard 已提交
911
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
912
            }
B
bellard 已提交
913
            pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
B
bellard 已提交
914
                env->a20_mask;
B
bellard 已提交
915 916 917 918 919 920 921 922 923 924 925 926 927
            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)
928
                goto do_fault_protect;
B
bellard 已提交
929 930 931 932 933 934 935
            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) &&
936
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
937 938 939 940 941 942 943 944 945 946 947 948
                    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 已提交
949
        }
B
bellard 已提交
950
    } else {
B
bellard 已提交
951 952
        uint32_t pde;

B
bellard 已提交
953
        /* page directory entry */
954
        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
B
bellard 已提交
955
            env->a20_mask;
B
bellard 已提交
956
        pde = ldl_phys(pde_addr);
B
bellard 已提交
957
        if (!(pde & PG_PRESENT_MASK)) {
B
bellard 已提交
958 959 960
            error_code = 0;
            goto do_fault;
        }
B
bellard 已提交
961 962 963 964 965 966 967 968 969
        /* 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 {
970 971
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(pde & PG_RW_MASK))
B
bellard 已提交
972 973 974 975 976 977 978
                    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 已提交
979
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
980
            }
981

B
bellard 已提交
982 983 984
            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
            ptep = pte;
            virt_addr = addr & ~(page_size - 1);
B
bellard 已提交
985
        } else {
B
bellard 已提交
986 987
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
B
bellard 已提交
988
                stl_phys_notdirty(pde_addr, pde);
B
bellard 已提交
989 990 991
            }

            /* page directory entry */
992
            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
B
bellard 已提交
993
                env->a20_mask;
B
bellard 已提交
994
            pte = ldl_phys(pte_addr);
B
bellard 已提交
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
            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) &&
1008
                    is_write && !(ptep & PG_RW_MASK))
B
bellard 已提交
1009 1010 1011 1012 1013 1014 1015
                    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 已提交
1016
                stl_phys_notdirty(pte_addr, pte);
B
bellard 已提交
1017 1018 1019
            }
            page_size = 4096;
            virt_addr = addr & ~0xfff;
B
bellard 已提交
1020
        }
B
bellard 已提交
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
    }
    /* 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;
1036
        }
B
bellard 已提交
1037 1038
    }
 do_mapping:
1039
    pte = pte & env->a20_mask;
B
bellard 已提交
1040

1041 1042 1043 1044 1045
    /* 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;
1046

1047
    ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
B
bellard 已提交
1048 1049 1050 1051
    return ret;
 do_fault_protect:
    error_code = PG_ERROR_P_MASK;
 do_fault:
B
bellard 已提交
1052
    error_code |= (is_write << PG_ERROR_W_BIT);
B
bellard 已提交
1053
    if (is_user)
B
bellard 已提交
1054
        error_code |= PG_ERROR_U_MASK;
1055 1056
    if (is_write1 == 2 &&
        (env->efer & MSR_EFER_NXE) &&
B
bellard 已提交
1057 1058
        (env->cr[4] & CR4_PAE_MASK))
        error_code |= PG_ERROR_I_D_MASK;
T
ths 已提交
1059 1060 1061 1062 1063
    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 已提交
1064
    env->error_code = error_code;
B
bellard 已提交
1065
    env->exception_index = EXCP0E_PAGE;
T
ths 已提交
1066 1067 1068
    /* the VMM will handle this */
    if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE))
        return 2;
B
bellard 已提交
1069 1070
    return 1;
}
1071

1072
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
1073
{
1074
    uint32_t pde_addr, pte_addr;
1075 1076
    uint32_t pde, pte, paddr, page_offset, page_size;

1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
    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;
1091

1092
            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
1093
                env->a20_mask;
B
bellard 已提交
1094
            pml4e = ldl_phys(pml4e_addr);
1095 1096
            if (!(pml4e & PG_PRESENT_MASK))
                return -1;
1097

1098
            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
1099
                env->a20_mask;
B
bellard 已提交
1100
            pdpe = ldl_phys(pdpe_addr);
1101 1102
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
1103
        } else
1104 1105
#endif
        {
1106
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
1107
                env->a20_mask;
B
bellard 已提交
1108
            pdpe = ldl_phys(pdpe_addr);
1109 1110 1111 1112 1113 1114
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
        }

        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
            env->a20_mask;
B
bellard 已提交
1115
        pde = ldl_phys(pde_addr);
1116
        if (!(pde & PG_PRESENT_MASK)) {
1117
            return -1;
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
        }
        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 已提交
1128
            pte = ldl_phys(pte_addr);
1129 1130 1131 1132 1133
        }
    } else {
        if (!(env->cr[0] & CR0_PG_MASK)) {
            pte = addr;
            page_size = 4096;
1134 1135
        } else {
            /* page directory entry */
1136
            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
B
bellard 已提交
1137
            pde = ldl_phys(pde_addr);
1138
            if (!(pde & PG_PRESENT_MASK))
1139
                return -1;
1140 1141 1142 1143 1144 1145
            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 已提交
1146
                pte = ldl_phys(pte_addr);
1147 1148 1149 1150
                if (!(pte & PG_PRESENT_MASK))
                    return -1;
                page_size = 4096;
            }
1151
        }
1152
        pte = pte & env->a20_mask;
1153
    }
1154

1155 1156 1157 1158
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
    return paddr;
}
B
bellard 已提交
1159
#endif /* !CONFIG_USER_ONLY */