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

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++ ) 
B
bellard 已提交
86
        if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) {
87 88 89 90 91 92
            *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
    cpu_exec_init(env);
102
    env->cpu_model_str = cpu_model;
B
bellard 已提交
103

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

B
bellard 已提交
120
typedef struct x86_def_t {
121 122 123 124 125 126 127
    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 已提交
128
} x86_def_t;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

#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 | 
145
        /* these features are needed for Win64 and aren't fully implemented */
146
            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
147
        /* this feature is needed for Solaris and isn't fully implemented */
148 149 150 151 152 153 154
            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 已提交
155
#endif
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 198
    {
        .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 已提交
199
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
200 201
{
    unsigned int i;
B
bellard 已提交
202
    x86_def_t *def;
203 204 205 206 207 208 209

    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 已提交
210
    def = NULL;
211 212
    for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
        if (strcmp(name, x86_defs[i].name) == 0) {
B
bellard 已提交
213
            def = &x86_defs[i];
214 215
            break;
        }
B
bellard 已提交
216
    }
B
bellard 已提交
217
    if (!def)
218
        goto error;
B
bellard 已提交
219
    memcpy(x86_cpu_def, def, sizeof(*def));
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 277

    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 已提交
278 279
    free(s);
    return 0;
280 281 282

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

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 已提交
294
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
295
{
B
bellard 已提交
296 297 298 299
    x86_def_t def1, *def = &def1;

    if (cpu_x86_find_by_name(def, cpu_model) < 0)
        return -1;
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 329
    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 已提交
330 331 332 333 334 335 336 337
}

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

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

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

341 342
    env->old_exception = -1;

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

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

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

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

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

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

371
    env->eflags = 0x2;
372

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

B
bellard 已提交
772 773
#else

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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