helper.c 41.0 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
 *  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
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
18 19
 */

20
#include "cpu.h"
A
aliguori 已提交
21
#include "kvm.h"
J
Jan Kiszka 已提交
22 23
#ifndef CONFIG_USER_ONLY
#include "sysemu.h"
24
#include "monitor.h"
J
Jan Kiszka 已提交
25
#endif
B
bellard 已提交
26

27
//#define DEBUG_MMU
28

29
/* NOTE: must be called outside the CPU execute loop */
30
void cpu_state_reset(CPUX86State *env)
31
{
32
    int i;
33

A
aliguori 已提交
34 35 36 37 38
    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
        log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
    }

39
    memset(env, 0, offsetof(CPUX86State, breakpoints));
40

41
    tlb_flush(env, 1);
42

43
    env->old_exception = -1;
44

45
    /* init to reset state */
46

47 48
#ifdef CONFIG_SOFTMMU
    env->hflags |= HF_SOFTMMU_MASK;
B
bellard 已提交
49
#endif
50
    env->hflags2 |= HF2_GIF_MASK;
B
bellard 已提交
51

52 53 54
    cpu_x86_update_cr0(env, 0x60000010);
    env->a20_mask = ~0x0;
    env->smbase = 0x30000;
55

56 57 58
    env->idt.limit = 0xffff;
    env->gdt.limit = 0xffff;
    env->ldt.limit = 0xffff;
59
    env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
60
    env->tr.limit = 0xffff;
61
    env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
62 63

    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
64 65
                           DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
                           DESC_R_MASK | DESC_A_MASK);
66
    cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
67 68
                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
                           DESC_A_MASK);
69
    cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
70 71
                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
                           DESC_A_MASK);
72
    cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
73 74
                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
                           DESC_A_MASK);
75
    cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
76 77
                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
                           DESC_A_MASK);
78
    cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
79 80
                           DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
                           DESC_A_MASK);
81

82 83
    env->eip = 0xfff0;
    env->regs[R_EDX] = env->cpuid_version;
B
bellard 已提交
84

85
    env->eflags = 0x2;
86

87 88 89 90
    /* FPU init */
    for(i = 0;i < 8; i++)
        env->fptags[i] = 1;
    env->fpuc = 0x37f;
91

92
    env->mxcsr = 0x1f80;
93

J
Jan Kiszka 已提交
94
    env->pat = 0x0007040600070406ULL;
A
Avi Kivity 已提交
95
    env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
J
Jan Kiszka 已提交
96

97 98 99 100 101
    memset(env->dr, 0, sizeof(env->dr));
    env->dr[6] = DR6_FIXED_1;
    env->dr[7] = DR7_FIXED_1;
    cpu_breakpoint_remove_all(env, BP_CPU);
    cpu_watchpoint_remove_all(env, BP_CPU);
102
}
103

104
static void cpu_x86_version(CPUX86State *env, int *family, int *model)
105 106 107 108 109 110 111 112 113 114 115 116
{
    int cpuver = env->cpuid_version;

    if (family == NULL || model == NULL) {
        return;
    }

    *family = (cpuver >> 8) & 0x0f;
    *model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
}

/* Broadcast MCA signal for processor version 06H_EH and above */
117
int cpu_x86_support_mca_broadcast(CPUX86State *env)
118 119 120 121 122 123 124 125 126 127 128 129
{
    int family = 0;
    int model = 0;

    cpu_x86_version(env, &family, &model);
    if ((family == 6 && model >= 14) || family > 6) {
        return 1;
    }

    return 0;
}

130 131
/***********************************************************/
/* x86 debug */
132

133 134 135
static const char *cc_op_str[] = {
    "DYNAMIC",
    "EFLAGS",
136

137 138 139 140
    "MULB",
    "MULW",
    "MULL",
    "MULQ",
141

142 143 144 145
    "ADDB",
    "ADDW",
    "ADDL",
    "ADDQ",
146

147 148 149 150
    "ADCB",
    "ADCW",
    "ADCL",
    "ADCQ",
151

152 153 154 155
    "SUBB",
    "SUBW",
    "SUBL",
    "SUBQ",
156

157 158 159 160
    "SBBB",
    "SBBW",
    "SBBL",
    "SBBQ",
161

162 163 164 165
    "LOGICB",
    "LOGICW",
    "LOGICL",
    "LOGICQ",
166

167 168 169 170
    "INCB",
    "INCW",
    "INCL",
    "INCQ",
171

172 173 174 175
    "DECB",
    "DECW",
    "DECL",
    "DECQ",
176

177 178 179 180
    "SHLB",
    "SHLW",
    "SHLL",
    "SHLQ",
181

182 183 184 185 186
    "SARB",
    "SARW",
    "SARL",
    "SARQ",
};
187

188
static void
189
cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
190 191 192 193 194
                       const char *name, struct SegmentCache *sc)
{
#ifdef TARGET_X86_64
    if (env->hflags & HF_CS64_MASK) {
        cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
195
                    sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00);
196 197 198 199
    } else
#endif
    {
        cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
200
                    (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00);
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    }

    if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
        goto done;

    cpu_fprintf(f, " DPL=%d ", (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
    if (sc->flags & DESC_S_MASK) {
        if (sc->flags & DESC_CS_MASK) {
            cpu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
                           ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
            cpu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
                        (sc->flags & DESC_R_MASK) ? 'R' : '-');
        } else {
            cpu_fprintf(f, (sc->flags & DESC_B_MASK) ? "DS  " : "DS16");
            cpu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
                        (sc->flags & DESC_W_MASK) ? 'W' : '-');
        }
        cpu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
    } else {
        static const char *sys_type_name[2][16] = {
            { /* 32 bit mode */
                "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
                "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
                "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
                "CallGate32", "Reserved", "IntGate32", "TrapGate32"
            },
            { /* 64 bit mode */
                "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
                "Reserved", "Reserved", "Reserved", "Reserved",
                "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
                "Reserved", "IntGate64", "TrapGate64"
            }
        };
S
Stefan Weil 已提交
234 235 236 237
        cpu_fprintf(f, "%s",
                    sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
                                 [(sc->flags & DESC_TYPE_MASK)
                                  >> DESC_TYPE_SHIFT]);
238 239 240 241 242
    }
done:
    cpu_fprintf(f, "\n");
}

243 244 245
#define DUMP_CODE_BYTES_TOTAL    50
#define DUMP_CODE_BYTES_BACKWARD 20

246
void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
247 248 249 250 251
                    int flags)
{
    int eflags, i, nb;
    char cc_op_name[32];
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
252

253
    cpu_synchronize_state(env);
B
balrog 已提交
254

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    eflags = env->eflags;
#ifdef TARGET_X86_64
    if (env->hflags & HF_CS64_MASK) {
        cpu_fprintf(f,
                    "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"
                    "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
                    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],
                    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' : '-',
                    env->hflags & HF_CPL_MASK,
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
J
Juan Quintela 已提交
290
                    (env->a20_mask >> 20) & 1,
291
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
292
                    env->halted);
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
    } else
#endif
    {
        cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
                    "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
                    "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
                    (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],
                    (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' : '-',
                    env->hflags & HF_CPL_MASK,
                    (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
J
Juan Quintela 已提交
317
                    (env->a20_mask >> 20) & 1,
318
                    (env->hflags >> HF_SMM_SHIFT) & 1,
B
bellard 已提交
319
                    env->halted);
320
    }
321

322 323 324 325 326 327 328
    for(i = 0; i < 6; i++) {
        cpu_x86_dump_seg_cache(env, f, cpu_fprintf, seg_name[i],
                               &env->segs[i]);
    }
    cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "LDT", &env->ldt);
    cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "TR", &env->tr);

329 330 331 332 333 334 335 336 337 338 339
#ifdef TARGET_X86_64
    if (env->hflags & HF_LMA_MASK) {
        cpu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
                    env->gdt.base, env->gdt.limit);
        cpu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
                    env->idt.base, env->idt.limit);
        cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
                    (uint32_t)env->cr[0],
                    env->cr[2],
                    env->cr[3],
                    (uint32_t)env->cr[4]);
A
aliguori 已提交
340 341 342
        for(i = 0; i < 4; i++)
            cpu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
        cpu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
343
                    env->dr[6], env->dr[7]);
344 345 346 347 348 349 350 351 352 353 354 355
    } else
#endif
    {
        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",
                    (uint32_t)env->cr[0],
                    (uint32_t)env->cr[2],
                    (uint32_t)env->cr[3],
                    (uint32_t)env->cr[4]);
356 357 358 359 360
        for(i = 0; i < 4; i++) {
            cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
        }
        cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
                    env->dr[6], env->dr[7]);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    }
    if (flags & X86_DUMP_CCOP) {
        if ((unsigned)env->cc_op < CC_OP_NB)
            snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
        else
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
#ifdef TARGET_X86_64
        if (env->hflags & HF_CS64_MASK) {
            cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
                        env->cc_src, env->cc_dst,
                        cc_op_name);
        } else
#endif
        {
            cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
                        cc_op_name);
        }
379
    }
380
    cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
381 382 383 384 385 386 387 388 389 390 391 392 393
    if (flags & X86_DUMP_FPU) {
        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++) {
394 395
            CPU_LDoubleU u;
            u.d = env->fpregs[i].d;
396
            cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
397
                        i, u.l.lower, u.l.upper);
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
            if ((i & 1) == 1)
                cpu_fprintf(f, "\n");
            else
                cpu_fprintf(f, " ");
        }
        if (env->hflags & HF_CS64_MASK)
            nb = 16;
        else
            nb = 8;
        for(i=0;i<nb;i++) {
            cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
                        i,
                        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, " ");
        }
419
    }
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
    if (flags & CPU_DUMP_CODE) {
        target_ulong base = env->segs[R_CS].base + env->eip;
        target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
        uint8_t code;
        char codestr[3];

        cpu_fprintf(f, "Code=");
        for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
            if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
                snprintf(codestr, sizeof(codestr), "%02x", code);
            } else {
                snprintf(codestr, sizeof(codestr), "??");
            }
            cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
                        i == offs ? "<" : "", codestr, i == offs ? ">" : "");
        }
        cpu_fprintf(f, "\n");
    }
B
bellard 已提交
438
}
439

440 441 442 443 444
/***********************************************************/
/* x86 mmu */
/* XXX: add PGE support */

void cpu_x86_set_a20(CPUX86State *env, int a20_state)
B
bellard 已提交
445
{
446 447 448 449 450 451 452 453
    a20_state = (a20_state != 0);
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
#if defined(DEBUG_MMU)
        printf("A20 update: a20=%d\n", a20_state);
#endif
        /* if the cpu is currently executing code, we must unlink it and
           all the potentially executing TB */
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
454

455 456 457
        /* when a20 is changed, all the MMU mappings are invalid, so
           we must flush everything */
        tlb_flush(env, 1);
J
Juan Quintela 已提交
458
        env->a20_mask = ~(1 << 20) | (a20_state << 20);
459
    }
B
bellard 已提交
460 461
}

462
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
B
bellard 已提交
463
{
464
    int pe_state;
B
bellard 已提交
465

466 467 468 469 470 471 472
#if defined(DEBUG_MMU)
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
#endif
    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 已提交
473

474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
#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
    env->cr[0] = new_cr0 | CR0_ET_MASK;
492

493 494 495 496 497 498 499 500
    /* 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);
    /* 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));
501 502
}

503 504 505
/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
   the PDPT */
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
506
{
507 508 509 510 511 512 513
    env->cr[3] = new_cr3;
    if (env->cr[0] & CR0_PG_MASK) {
#if defined(DEBUG_MMU)
        printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
#endif
        tlb_flush(env, 0);
    }
514 515
}

516
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
517
{
518 519 520 521 522 523 524 525 526 527 528 529 530 531
#if defined(DEBUG_MMU)
    printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
#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);
    }
    /* 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;
532

533
    env->cr[4] = new_cr4;
534 535
}

536 537 538
#if defined(CONFIG_USER_ONLY)

int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
539
                             int is_write, int mmu_idx)
540
{
541 542 543 544 545 546 547
    /* 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;
    env->exception_index = EXCP0E_PAGE;
    return 1;
B
bellard 已提交
548 549
}

550
#else
551

552 553 554
/* XXX: This value should match the one returned by CPUID
 * and in exec.c */
# if defined(TARGET_X86_64)
555
# define PHYS_ADDR_MASK 0xfffffff000LL
556
# else
557
# define PHYS_ADDR_MASK 0xffffff000LL
558 559 560 561 562 563 564 565
# endif

/* return value:
   -1 = cannot handle fault
   0  = nothing more to do
   1  = generate PF fault
*/
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
566
                             int is_write1, int mmu_idx)
567 568 569
{
    uint64_t ptep, pte;
    target_ulong pde_addr, pte_addr;
P
Paul Brook 已提交
570
    int error_code, is_dirty, prot, page_size, is_write, is_user;
A
Anthony Liguori 已提交
571
    target_phys_addr_t paddr;
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    uint32_t page_offset;
    target_ulong vaddr, virt_addr;

    is_user = mmu_idx == MMU_USER_IDX;
#if defined(DEBUG_MMU)
    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
           addr, is_write1, is_user, env->eip);
#endif
    is_write = is_write1 & 1;

    if (!(env->cr[0] & CR0_PG_MASK)) {
        pte = addr;
        virt_addr = addr & TARGET_PAGE_MASK;
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
        page_size = 4096;
        goto do_mapping;
    }

    if (env->cr[4] & CR4_PAE_MASK) {
        uint64_t pde, pdpe;
        target_ulong pdpe_addr;
B
bellard 已提交
593

594 595 596 597 598 599 600 601 602 603 604 605
#ifdef TARGET_X86_64
        if (env->hflags & HF_LMA_MASK) {
            uint64_t pml4e_addr, pml4e;
            int32_t sext;

            /* test virtual address sign extension */
            sext = (int64_t)addr >> 47;
            if (sext != 0 && sext != -1) {
                env->error_code = 0;
                env->exception_index = EXCP0D_GPF;
                return 1;
            }
T
ths 已提交
606

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
                env->a20_mask;
            pml4e = ldq_phys(pml4e_addr);
            if (!(pml4e & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
            if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
            if (!(pml4e & PG_ACCESSED_MASK)) {
                pml4e |= PG_ACCESSED_MASK;
                stl_phys_notdirty(pml4e_addr, pml4e);
            }
            ptep = pml4e ^ PG_NX_MASK;
            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
                env->a20_mask;
            pdpe = ldq_phys(pdpe_addr);
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
            if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
                error_code = PG_ERROR_RSVD_MASK;
                goto do_fault;
            }
            ptep &= pdpe ^ PG_NX_MASK;
            if (!(pdpe & PG_ACCESSED_MASK)) {
                pdpe |= PG_ACCESSED_MASK;
                stl_phys_notdirty(pdpe_addr, pdpe);
            }
        } else
#endif
        {
            /* XXX: load them when cr3 is loaded ? */
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
                env->a20_mask;
            pdpe = ldq_phys(pdpe_addr);
            if (!(pdpe & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
            }
            ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
651 652
        }

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
        pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
            env->a20_mask;
        pde = ldq_phys(pde_addr);
        if (!(pde & PG_PRESENT_MASK)) {
            error_code = 0;
            goto do_fault;
        }
        if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
            error_code = PG_ERROR_RSVD_MASK;
            goto do_fault;
        }
        ptep &= pde ^ PG_NX_MASK;
        if (pde & PG_PSE_MASK) {
            /* 2 MB page */
            page_size = 2048 * 1024;
            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 {
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(ptep & PG_RW_MASK))
                    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 */
            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
            virt_addr = addr & ~(page_size - 1);
        } else {
            /* 4 KB page */
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
                stl_phys_notdirty(pde_addr, pde);
            }
            pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
                env->a20_mask;
            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)
                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 {
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(ptep & PG_RW_MASK))
                    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);
733
        }
B
bellard 已提交
734
    } else {
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
        uint32_t pde;

        /* page directory entry */
        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
            env->a20_mask;
        pde = ldl_phys(pde_addr);
        if (!(pde & PG_PRESENT_MASK)) {
            error_code = 0;
            goto do_fault;
        }
        /* 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 {
                if ((env->cr[0] & CR0_WP_MASK) &&
                    is_write && !(pde & PG_RW_MASK))
                    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);
            }
B
bellard 已提交
765

766 767 768 769 770 771 772 773
            pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
            ptep = pte;
            virt_addr = addr & ~(page_size - 1);
        } else {
            if (!(pde & PG_ACCESSED_MASK)) {
                pde |= PG_ACCESSED_MASK;
                stl_phys_notdirty(pde_addr, pde);
            }
774

775 776 777 778 779 780 781
            /* page directory entry */
            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
                env->a20_mask;
            pte = ldl_phys(pte_addr);
            if (!(pte & PG_PRESENT_MASK)) {
                error_code = 0;
                goto do_fault;
782
            }
783 784 785 786 787 788 789 790 791 792 793
            /* 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) &&
                    is_write && !(ptep & PG_RW_MASK))
                    goto do_fault_protect;
794
            }
795 796 797 798 799 800 801 802 803
            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;
B
bellard 已提交
804 805
        }
    }
806 807 808 809 810 811 812 813 814 815 816 817 818 819
    /* 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;
820
        }
821
    }
822 823 824 825 826 827 828 829 830
 do_mapping:
    pte = pte & env->a20_mask;

    /* 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;

P
Paul Brook 已提交
831 832
    tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
    return 0;
833 834 835 836 837 838 839 840 841 842
 do_fault_protect:
    error_code = PG_ERROR_P_MASK;
 do_fault:
    error_code |= (is_write << PG_ERROR_W_BIT);
    if (is_user)
        error_code |= PG_ERROR_U_MASK;
    if (is_write1 == 2 &&
        (env->efer & MSR_EFER_NXE) &&
        (env->cr[4] & CR4_PAE_MASK))
        error_code |= PG_ERROR_I_D_MASK;
B
bellard 已提交
843 844 845 846
    if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
        /* cr2 is not modified in case of exceptions */
        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 
                 addr);
847 848
    } else {
        env->cr[2] = addr;
B
bellard 已提交
849
    }
850 851 852
    env->error_code = error_code;
    env->exception_index = EXCP0E_PAGE;
    return 1;
B
bellard 已提交
853 854
}

855
target_phys_addr_t cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr)
B
bellard 已提交
856
{
857 858
    target_ulong pde_addr, pte_addr;
    uint64_t pte;
A
Anthony Liguori 已提交
859
    target_phys_addr_t paddr;
860 861
    uint32_t page_offset;
    int page_size;
B
bellard 已提交
862

863 864 865
    if (env->cr[4] & CR4_PAE_MASK) {
        target_ulong pdpe_addr;
        uint64_t pde, pdpe;
B
bellard 已提交
866

867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
#ifdef TARGET_X86_64
        if (env->hflags & HF_LMA_MASK) {
            uint64_t pml4e_addr, pml4e;
            int32_t sext;

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

            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
                env->a20_mask;
            pml4e = ldq_phys(pml4e_addr);
            if (!(pml4e & PG_PRESENT_MASK))
                return -1;

883 884
            pdpe_addr = ((pml4e & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
                         (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask;
885 886 887 888 889 890 891 892 893 894 895
            pdpe = ldq_phys(pdpe_addr);
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
        } else
#endif
        {
            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
                env->a20_mask;
            pdpe = ldq_phys(pdpe_addr);
            if (!(pdpe & PG_PRESENT_MASK))
                return -1;
B
bellard 已提交
896 897
        }

898 899
        pde_addr = ((pdpe & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
                    (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask;
900 901 902 903 904 905 906 907 908 909
        pde = ldq_phys(pde_addr);
        if (!(pde & PG_PRESENT_MASK)) {
            return -1;
        }
        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 */
910 911
            pte_addr = ((pde & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
                        (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask;
912 913 914
            page_size = 4096;
            pte = ldq_phys(pte_addr);
        }
915
        pte &= ~(PG_NX_MASK | PG_HI_USER_MASK);
916 917
        if (!(pte & PG_PRESENT_MASK))
            return -1;
B
bellard 已提交
918
    } else {
919
        uint32_t pde;
920

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
        if (!(env->cr[0] & CR0_PG_MASK)) {
            pte = addr;
            page_size = 4096;
        } else {
            /* page directory entry */
            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
            pde = ldl_phys(pde_addr);
            if (!(pde & PG_PRESENT_MASK))
                return -1;
            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;
                pte = ldl_phys(pte_addr);
                if (!(pte & PG_PRESENT_MASK))
                    return -1;
                page_size = 4096;
            }
        }
        pte = pte & env->a20_mask;
B
bellard 已提交
943 944
    }

945 946 947
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
    return paddr;
B
bellard 已提交
948
}
949

950
void hw_breakpoint_insert(CPUX86State *env, int index)
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
{
    int type, err = 0;

    switch (hw_breakpoint_type(env->dr[7], index)) {
    case 0:
        if (hw_breakpoint_enabled(env->dr[7], index))
            err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
                                        &env->cpu_breakpoint[index]);
        break;
    case 1:
        type = BP_CPU | BP_MEM_WRITE;
        goto insert_wp;
    case 2:
         /* No support for I/O watchpoints yet */
        break;
    case 3:
        type = BP_CPU | BP_MEM_ACCESS;
    insert_wp:
        err = cpu_watchpoint_insert(env, env->dr[index],
                                    hw_breakpoint_len(env->dr[7], index),
                                    type, &env->cpu_watchpoint[index]);
        break;
    }
    if (err)
        env->cpu_breakpoint[index] = NULL;
}

978
void hw_breakpoint_remove(CPUX86State *env, int index)
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
{
    if (!env->cpu_breakpoint[index])
        return;
    switch (hw_breakpoint_type(env->dr[7], index)) {
    case 0:
        if (hw_breakpoint_enabled(env->dr[7], index))
            cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
        break;
    case 1:
    case 3:
        cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
        break;
    case 2:
        /* No support for I/O watchpoints yet */
        break;
    }
}

997
int check_hw_breakpoints(CPUX86State *env, int force_dr6_update)
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
{
    target_ulong dr6;
    int reg, type;
    int hit_enabled = 0;

    dr6 = env->dr[6] & ~0xf;
    for (reg = 0; reg < 4; reg++) {
        type = hw_breakpoint_type(env->dr[7], reg);
        if ((type == 0 && env->dr[reg] == env->eip) ||
            ((type & 1) && env->cpu_watchpoint[reg] &&
             (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) {
            dr6 |= 1 << reg;
            if (hw_breakpoint_enabled(env->dr[7], reg))
                hit_enabled = 1;
        }
    }
    if (hit_enabled || force_dr6_update)
        env->dr[6] = dr6;
    return hit_enabled;
}

static CPUDebugExcpHandler *prev_debug_excp_handler;

1021
static void breakpoint_handler(CPUX86State *env)
1022 1023 1024 1025 1026 1027 1028
{
    CPUBreakpoint *bp;

    if (env->watchpoint_hit) {
        if (env->watchpoint_hit->flags & BP_CPU) {
            env->watchpoint_hit = NULL;
            if (check_hw_breakpoints(env, 0))
1029
                raise_exception_env(EXCP01_DB, env);
1030 1031 1032 1033
            else
                cpu_resume_from_signal(env, NULL);
        }
    } else {
B
Blue Swirl 已提交
1034
        QTAILQ_FOREACH(bp, &env->breakpoints, entry)
1035 1036 1037
            if (bp->pc == env->eip) {
                if (bp->flags & BP_CPU) {
                    check_hw_breakpoints(env, 1);
1038
                    raise_exception_env(EXCP01_DB, env);
1039 1040 1041 1042 1043 1044 1045
                }
                break;
            }
    }
    if (prev_debug_excp_handler)
        prev_debug_excp_handler(env);
}
1046

1047 1048
typedef struct MCEInjectionParams {
    Monitor *mon;
1049
    CPUX86State *env;
1050 1051 1052 1053 1054 1055 1056 1057 1058
    int bank;
    uint64_t status;
    uint64_t mcg_status;
    uint64_t addr;
    uint64_t misc;
    int flags;
} MCEInjectionParams;

static void do_inject_x86_mce(void *data)
1059
{
1060
    MCEInjectionParams *params = data;
1061
    CPUX86State *cenv = params->env;
1062 1063 1064
    uint64_t *banks = cenv->mce_banks + 4 * params->bank;

    cpu_synchronize_state(cenv);
1065

1066 1067 1068 1069
    /*
     * If there is an MCE exception being processed, ignore this SRAO MCE
     * unless unconditional injection was requested.
     */
1070 1071
    if (!(params->flags & MCE_INJECT_UNCOND_AO)
        && !(params->status & MCI_STATUS_AR)
1072 1073 1074
        && (cenv->mcg_status & MCG_STATUS_MCIP)) {
        return;
    }
1075 1076

    if (params->status & MCI_STATUS_UC) {
1077 1078 1079 1080
        /*
         * if MSR_MCG_CTL is not all 1s, the uncorrected error
         * reporting is disabled
         */
1081 1082
        if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
            monitor_printf(params->mon,
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
                           "CPU %d: Uncorrected error reporting disabled\n",
                           cenv->cpu_index);
            return;
        }

        /*
         * if MSR_MCi_CTL is not all 1s, the uncorrected error
         * reporting is disabled for the bank
         */
        if (banks[0] != ~(uint64_t)0) {
1093 1094 1095 1096
            monitor_printf(params->mon,
                           "CPU %d: Uncorrected error reporting disabled for"
                           " bank %d\n",
                           cenv->cpu_index, params->bank);
1097 1098 1099
            return;
        }

1100 1101
        if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
            !(cenv->cr[4] & CR4_MCE_MASK)) {
1102 1103 1104 1105
            monitor_printf(params->mon,
                           "CPU %d: Previous MCE still in progress, raising"
                           " triple fault\n",
                           cenv->cpu_index);
1106 1107 1108 1109
            qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
            qemu_system_reset_request();
            return;
        }
J
Jan Kiszka 已提交
1110
        if (banks[1] & MCI_STATUS_VAL) {
1111
            params->status |= MCI_STATUS_OVER;
J
Jan Kiszka 已提交
1112
        }
1113 1114 1115 1116
        banks[2] = params->addr;
        banks[3] = params->misc;
        cenv->mcg_status = params->mcg_status;
        banks[1] = params->status;
1117 1118 1119
        cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
    } else if (!(banks[1] & MCI_STATUS_VAL)
               || !(banks[1] & MCI_STATUS_UC)) {
J
Jan Kiszka 已提交
1120
        if (banks[1] & MCI_STATUS_VAL) {
1121
            params->status |= MCI_STATUS_OVER;
J
Jan Kiszka 已提交
1122
        }
1123 1124 1125
        banks[2] = params->addr;
        banks[3] = params->misc;
        banks[1] = params->status;
J
Jan Kiszka 已提交
1126
    } else {
1127
        banks[1] |= MCI_STATUS_OVER;
J
Jan Kiszka 已提交
1128
    }
1129
}
J
Jin Dongming 已提交
1130

1131
void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
1132
                        uint64_t status, uint64_t mcg_status, uint64_t addr,
1133
                        uint64_t misc, int flags)
J
Jin Dongming 已提交
1134
{
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
    MCEInjectionParams params = {
        .mon = mon,
        .env = cenv,
        .bank = bank,
        .status = status,
        .mcg_status = mcg_status,
        .addr = addr,
        .misc = misc,
        .flags = flags,
    };
J
Jin Dongming 已提交
1145
    unsigned bank_num = cenv->mcg_cap & 0xff;
1146
    CPUX86State *env;
J
Jin Dongming 已提交
1147

1148 1149
    if (!cenv->mcg_cap) {
        monitor_printf(mon, "MCE injection not supported\n");
J
Jin Dongming 已提交
1150 1151
        return;
    }
1152 1153 1154 1155 1156 1157 1158 1159
    if (bank >= bank_num) {
        monitor_printf(mon, "Invalid MCE bank number\n");
        return;
    }
    if (!(status & MCI_STATUS_VAL)) {
        monitor_printf(mon, "Invalid MCE status code\n");
        return;
    }
1160 1161
    if ((flags & MCE_INJECT_BROADCAST)
        && !cpu_x86_support_mca_broadcast(cenv)) {
1162 1163
        monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
        return;
1164 1165
    }

1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    run_on_cpu(cenv, do_inject_x86_mce, &params);
    if (flags & MCE_INJECT_BROADCAST) {
        params.bank = 1;
        params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
        params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
        params.addr = 0;
        params.misc = 0;
        for (env = first_cpu; env != NULL; env = env->next_cpu) {
            if (cenv == env) {
                continue;
1176
            }
1177 1178
            params.env = env;
            run_on_cpu(cenv, do_inject_x86_mce, &params);
1179
        }
J
Jin Dongming 已提交
1180 1181
    }
}
1182

1183
void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
{
    TranslationBlock *tb;

    if (kvm_enabled()) {
        env->tpr_access_type = access;

        cpu_interrupt(env, CPU_INTERRUPT_TPR);
    } else {
        tb = tb_find_pc(env->mem_io_pc);
        cpu_restore_state(tb, env, env->mem_io_pc);

        apic_handle_tpr_access_report(env->apic_state, env->eip, access);
    }
}
B
bellard 已提交
1198
#endif /* !CONFIG_USER_ONLY */
A
aliguori 已提交
1199

1200 1201
static void mce_init(CPUX86State *cenv)
{
J
Jan Kiszka 已提交
1202
    unsigned int bank;
1203

J
Jan Kiszka 已提交
1204 1205 1206
    if (((cenv->cpuid_version >> 8) & 0xf) >= 6
        && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
            (CPUID_MCE | CPUID_MCA)) {
1207 1208
        cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
        cenv->mcg_ctl = ~(uint64_t)0;
J
Jan Kiszka 已提交
1209 1210 1211
        for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
            cenv->mce_banks[bank * 4] = ~(uint64_t)0;
        }
1212 1213 1214
    }
}

1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
                            target_ulong *base, unsigned int *limit,
                            unsigned int *flags)
{
    SegmentCache *dt;
    target_ulong ptr;
    uint32_t e1, e2;
    int index;

    if (selector & 0x4)
        dt = &env->ldt;
    else
        dt = &env->gdt;
    index = selector & ~7;
    ptr = dt->base + index;
    if ((index + 7) > dt->limit
        || cpu_memory_rw_debug(env, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
        || cpu_memory_rw_debug(env, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
        return 0;

    *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
    *limit = (e1 & 0xffff) | (e2 & 0x000f0000);
    if (e2 & DESC_G_MASK)
        *limit = (*limit << 12) | 0xfff;
    *flags = e2;

    return 1;
}

1244 1245
CPUX86State *cpu_x86_init(const char *cpu_model)
{
A
Andreas Färber 已提交
1246
    X86CPU *cpu;
1247 1248 1249
    CPUX86State *env;
    static int inited;

A
Andreas Färber 已提交
1250 1251
    cpu = X86_CPU(object_new(TYPE_X86_CPU));
    env = &cpu->env;
1252 1253 1254
    cpu_exec_init(env);
    env->cpu_model_str = cpu_model;

1255 1256
    /* init various static tables used in TCG mode */
    if (tcg_enabled() && !inited) {
1257 1258 1259 1260 1261 1262 1263 1264
        inited = 1;
        optimize_flags_init();
#ifndef CONFIG_USER_ONLY
        prev_debug_excp_handler =
            cpu_set_debug_excp_handler(breakpoint_handler);
#endif
    }
    if (cpu_x86_register(env, cpu_model) < 0) {
A
Andreas Färber 已提交
1265
        object_delete(OBJECT(cpu));
1266 1267
        return NULL;
    }
B
Bharata B Rao 已提交
1268
    env->cpuid_apic_id = env->cpu_index;
1269
    mce_init(env);
1270 1271 1272

    qemu_init_vcpu(env);

1273 1274
    return env;
}
1275 1276

#if !defined(CONFIG_USER_ONLY)
1277
void do_cpu_init(CPUX86State *env)
1278 1279
{
    int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
J
Jan Kiszka 已提交
1280 1281
    uint64_t pat = env->pat;

1282
    cpu_state_reset(env);
1283
    env->interrupt_request = sipi;
J
Jan Kiszka 已提交
1284
    env->pat = pat;
1285
    apic_init_reset(env->apic_state);
J
Jan Kiszka 已提交
1286
    env->halted = !cpu_is_bsp(env);
1287 1288
}

1289
void do_cpu_sipi(CPUX86State *env)
1290
{
1291
    apic_sipi(env->apic_state);
1292 1293
}
#else
1294
void do_cpu_init(CPUX86State *env)
1295 1296
{
}
1297
void do_cpu_sipi(CPUX86State *env)
1298 1299 1300
{
}
#endif