blob: 83122bf617e6218da5dda6c0758ecdc88e5ed73c [file] [log] [blame]
bellard2c0262a2003-09-30 20:34:21 +00001/*
bellardeaa728e2008-05-28 12:51:20 +00002 * i386 helpers (without register variable usage)
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard2c0262a2003-09-30 20:34:21 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard2c0262a2003-09-30 20:34:21 +000018 */
bellard2c0262a2003-09-30 20:34:21 +000019
bellardeaa728e2008-05-28 12:51:20 +000020#include "cpu.h"
aliguori7ba1e612008-11-05 16:04:33 +000021#include "kvm.h"
Jan Kiszka2fa11da2011-03-02 08:56:08 +010022#ifndef CONFIG_USER_ONLY
23#include "sysemu.h"
Jan Kiszka316378e2011-03-02 08:56:09 +010024#include "monitor.h"
Jan Kiszka2fa11da2011-03-02 08:56:08 +010025#endif
bellardf3f2d9b2003-11-13 23:15:36 +000026
bellardeaa728e2008-05-28 12:51:20 +000027//#define DEBUG_MMU
john cooperb5ec5ce2010-02-20 11:14:59 -060028
bellardeaa728e2008-05-28 12:51:20 +000029/* NOTE: must be called outside the CPU execute loop */
Andreas Färber317ac622012-03-14 01:38:21 +010030void cpu_state_reset(CPUX86State *env)
bellard14ce26e2005-01-03 23:50:08 +000031{
bellardeaa728e2008-05-28 12:51:20 +000032 int i;
bellard14ce26e2005-01-03 23:50:08 +000033
aliguorieca1bdf2009-01-26 19:54:31 +000034 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
35 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
36 log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
37 }
38
bellardeaa728e2008-05-28 12:51:20 +000039 memset(env, 0, offsetof(CPUX86State, breakpoints));
bellard14ce26e2005-01-03 23:50:08 +000040
bellardeaa728e2008-05-28 12:51:20 +000041 tlb_flush(env, 1);
ths0573fbf2007-09-23 15:28:04 +000042
ths0573fbf2007-09-23 15:28:04 +000043 env->old_exception = -1;
44
bellardeaa728e2008-05-28 12:51:20 +000045 /* init to reset state */
ths0573fbf2007-09-23 15:28:04 +000046
bellardeaa728e2008-05-28 12:51:20 +000047#ifdef CONFIG_SOFTMMU
48 env->hflags |= HF_SOFTMMU_MASK;
ths0573fbf2007-09-23 15:28:04 +000049#endif
bellarddb620f42008-06-04 17:02:19 +000050 env->hflags2 |= HF2_GIF_MASK;
bellard5af45182008-05-12 16:47:36 +000051
bellardeaa728e2008-05-28 12:51:20 +000052 cpu_x86_update_cr0(env, 0x60000010);
53 env->a20_mask = ~0x0;
54 env->smbase = 0x30000;
55
56 env->idt.limit = 0xffff;
57 env->gdt.limit = 0xffff;
58 env->ldt.limit = 0xffff;
bellard262ffda2008-06-06 12:08:46 +000059 env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
bellardeaa728e2008-05-28 12:51:20 +000060 env->tr.limit = 0xffff;
aliguori23e6c392008-07-23 13:29:23 +000061 env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
bellardeaa728e2008-05-28 12:51:20 +000062
bellard262ffda2008-06-06 12:08:46 +000063 cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070064 DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
65 DESC_R_MASK | DESC_A_MASK);
bellard262ffda2008-06-06 12:08:46 +000066 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070067 DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
68 DESC_A_MASK);
bellard262ffda2008-06-06 12:08:46 +000069 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070070 DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
71 DESC_A_MASK);
bellard262ffda2008-06-06 12:08:46 +000072 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070073 DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
74 DESC_A_MASK);
bellard262ffda2008-06-06 12:08:46 +000075 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070076 DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
77 DESC_A_MASK);
bellard262ffda2008-06-06 12:08:46 +000078 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff,
Nitin A Kamble538f3682009-06-04 14:29:50 -070079 DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
80 DESC_A_MASK);
bellardeaa728e2008-05-28 12:51:20 +000081
82 env->eip = 0xfff0;
83 env->regs[R_EDX] = env->cpuid_version;
84
85 env->eflags = 0x2;
86
87 /* FPU init */
88 for(i = 0;i < 8; i++)
89 env->fptags[i] = 1;
90 env->fpuc = 0x37f;
91
92 env->mxcsr = 0x1f80;
aliguori01df0402008-11-18 21:08:15 +000093
Jan Kiszkaebda3772011-03-15 12:26:21 +010094 env->pat = 0x0007040600070406ULL;
Avi Kivity21e87c42011-10-04 16:26:35 +020095 env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
Jan Kiszkaebda3772011-03-15 12:26:21 +010096
aliguori01df0402008-11-18 21:08:15 +000097 memset(env->dr, 0, sizeof(env->dr));
98 env->dr[6] = DR6_FIXED_1;
99 env->dr[7] = DR7_FIXED_1;
100 cpu_breakpoint_remove_all(env, BP_CPU);
101 cpu_watchpoint_remove_all(env, BP_CPU);
bellard5af45182008-05-12 16:47:36 +0000102}
103
bellardeaa728e2008-05-28 12:51:20 +0000104void cpu_x86_close(CPUX86State *env)
bellard5af45182008-05-12 16:47:36 +0000105{
Anthony Liguori7267c092011-08-20 22:09:37 -0500106 g_free(env);
bellard5af45182008-05-12 16:47:36 +0000107}
108
Andreas Färber317ac622012-03-14 01:38:21 +0100109static void cpu_x86_version(CPUX86State *env, int *family, int *model)
Jin Dongming2bd3e042010-12-10 17:21:14 +0900110{
111 int cpuver = env->cpuid_version;
112
113 if (family == NULL || model == NULL) {
114 return;
115 }
116
117 *family = (cpuver >> 8) & 0x0f;
118 *model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
119}
120
121/* Broadcast MCA signal for processor version 06H_EH and above */
Andreas Färber317ac622012-03-14 01:38:21 +0100122int cpu_x86_support_mca_broadcast(CPUX86State *env)
Jin Dongming2bd3e042010-12-10 17:21:14 +0900123{
124 int family = 0;
125 int model = 0;
126
127 cpu_x86_version(env, &family, &model);
128 if ((family == 6 && model >= 14) || family > 6) {
129 return 1;
130 }
131
132 return 0;
133}
134
bellardeaa728e2008-05-28 12:51:20 +0000135/***********************************************************/
136/* x86 debug */
bellard5af45182008-05-12 16:47:36 +0000137
bellardeaa728e2008-05-28 12:51:20 +0000138static const char *cc_op_str[] = {
139 "DYNAMIC",
140 "EFLAGS",
bellard5af45182008-05-12 16:47:36 +0000141
bellardeaa728e2008-05-28 12:51:20 +0000142 "MULB",
143 "MULW",
144 "MULL",
145 "MULQ",
bellard5af45182008-05-12 16:47:36 +0000146
bellardeaa728e2008-05-28 12:51:20 +0000147 "ADDB",
148 "ADDW",
149 "ADDL",
150 "ADDQ",
bellardb6abf972008-05-17 12:44:31 +0000151
bellardeaa728e2008-05-28 12:51:20 +0000152 "ADCB",
153 "ADCW",
154 "ADCL",
155 "ADCQ",
bellardb6abf972008-05-17 12:44:31 +0000156
bellardeaa728e2008-05-28 12:51:20 +0000157 "SUBB",
158 "SUBW",
159 "SUBL",
160 "SUBQ",
bellardb6abf972008-05-17 12:44:31 +0000161
bellardeaa728e2008-05-28 12:51:20 +0000162 "SBBB",
163 "SBBW",
164 "SBBL",
165 "SBBQ",
bellardb6abf972008-05-17 12:44:31 +0000166
bellardeaa728e2008-05-28 12:51:20 +0000167 "LOGICB",
168 "LOGICW",
169 "LOGICL",
170 "LOGICQ",
bellardb6abf972008-05-17 12:44:31 +0000171
bellardeaa728e2008-05-28 12:51:20 +0000172 "INCB",
173 "INCW",
174 "INCL",
175 "INCQ",
bellard07d2c592008-05-17 13:57:33 +0000176
bellardeaa728e2008-05-28 12:51:20 +0000177 "DECB",
178 "DECW",
179 "DECL",
180 "DECQ",
bellard6191b052008-05-17 18:44:58 +0000181
bellardeaa728e2008-05-28 12:51:20 +0000182 "SHLB",
183 "SHLW",
184 "SHLL",
185 "SHLQ",
bellard6191b052008-05-17 18:44:58 +0000186
bellardeaa728e2008-05-28 12:51:20 +0000187 "SARB",
188 "SARW",
189 "SARL",
190 "SARQ",
bellard07d2c592008-05-17 13:57:33 +0000191};
192
aliguoria3867ed2009-04-18 15:36:11 +0000193static void
Andreas Färber317ac622012-03-14 01:38:21 +0100194cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
aliguoria3867ed2009-04-18 15:36:11 +0000195 const char *name, struct SegmentCache *sc)
196{
197#ifdef TARGET_X86_64
198 if (env->hflags & HF_CS64_MASK) {
199 cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
Jan Kiszka4058fd92010-12-27 15:52:24 +0100200 sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00);
aliguoria3867ed2009-04-18 15:36:11 +0000201 } else
202#endif
203 {
204 cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
Jan Kiszka4058fd92010-12-27 15:52:24 +0100205 (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00);
aliguoria3867ed2009-04-18 15:36:11 +0000206 }
207
208 if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
209 goto done;
210
211 cpu_fprintf(f, " DPL=%d ", (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
212 if (sc->flags & DESC_S_MASK) {
213 if (sc->flags & DESC_CS_MASK) {
214 cpu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
215 ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
216 cpu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
217 (sc->flags & DESC_R_MASK) ? 'R' : '-');
218 } else {
219 cpu_fprintf(f, (sc->flags & DESC_B_MASK) ? "DS " : "DS16");
220 cpu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
221 (sc->flags & DESC_W_MASK) ? 'W' : '-');
222 }
223 cpu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
224 } else {
225 static const char *sys_type_name[2][16] = {
226 { /* 32 bit mode */
227 "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
228 "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
229 "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
230 "CallGate32", "Reserved", "IntGate32", "TrapGate32"
231 },
232 { /* 64 bit mode */
233 "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
234 "Reserved", "Reserved", "Reserved", "Reserved",
235 "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
236 "Reserved", "IntGate64", "TrapGate64"
237 }
238 };
Stefan Weile5c15ef2010-04-01 20:03:30 +0200239 cpu_fprintf(f, "%s",
240 sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
241 [(sc->flags & DESC_TYPE_MASK)
242 >> DESC_TYPE_SHIFT]);
aliguoria3867ed2009-04-18 15:36:11 +0000243 }
244done:
245 cpu_fprintf(f, "\n");
246}
247
Jan Kiszkaf5c848e2011-01-21 21:48:08 +0100248#define DUMP_CODE_BYTES_TOTAL 50
249#define DUMP_CODE_BYTES_BACKWARD 20
250
Andreas Färber317ac622012-03-14 01:38:21 +0100251void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
bellardeaa728e2008-05-28 12:51:20 +0000252 int flags)
253{
254 int eflags, i, nb;
255 char cc_op_name[32];
256 static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
257
Jan Kiszka23054112009-09-12 16:50:07 +0200258 cpu_synchronize_state(env);
balrogff3c01c2009-03-04 21:00:07 +0000259
bellardeaa728e2008-05-28 12:51:20 +0000260 eflags = env->eflags;
261#ifdef TARGET_X86_64
262 if (env->hflags & HF_CS64_MASK) {
263 cpu_fprintf(f,
264 "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
265 "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
266 "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
267 "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
268 "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
269 env->regs[R_EAX],
270 env->regs[R_EBX],
271 env->regs[R_ECX],
272 env->regs[R_EDX],
273 env->regs[R_ESI],
274 env->regs[R_EDI],
275 env->regs[R_EBP],
276 env->regs[R_ESP],
277 env->regs[8],
278 env->regs[9],
279 env->regs[10],
280 env->regs[11],
281 env->regs[12],
282 env->regs[13],
283 env->regs[14],
284 env->regs[15],
285 env->eip, eflags,
286 eflags & DF_MASK ? 'D' : '-',
287 eflags & CC_O ? 'O' : '-',
288 eflags & CC_S ? 'S' : '-',
289 eflags & CC_Z ? 'Z' : '-',
290 eflags & CC_A ? 'A' : '-',
291 eflags & CC_P ? 'P' : '-',
292 eflags & CC_C ? 'C' : '-',
293 env->hflags & HF_CPL_MASK,
294 (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
Juan Quintela5ee0ffa2009-09-29 22:48:49 +0200295 (env->a20_mask >> 20) & 1,
bellardeaa728e2008-05-28 12:51:20 +0000296 (env->hflags >> HF_SMM_SHIFT) & 1,
bellardce5232c2008-05-28 17:14:10 +0000297 env->halted);
bellardeaa728e2008-05-28 12:51:20 +0000298 } else
299#endif
300 {
301 cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
302 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
303 "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
304 (uint32_t)env->regs[R_EAX],
305 (uint32_t)env->regs[R_EBX],
306 (uint32_t)env->regs[R_ECX],
307 (uint32_t)env->regs[R_EDX],
308 (uint32_t)env->regs[R_ESI],
309 (uint32_t)env->regs[R_EDI],
310 (uint32_t)env->regs[R_EBP],
311 (uint32_t)env->regs[R_ESP],
312 (uint32_t)env->eip, eflags,
313 eflags & DF_MASK ? 'D' : '-',
314 eflags & CC_O ? 'O' : '-',
315 eflags & CC_S ? 'S' : '-',
316 eflags & CC_Z ? 'Z' : '-',
317 eflags & CC_A ? 'A' : '-',
318 eflags & CC_P ? 'P' : '-',
319 eflags & CC_C ? 'C' : '-',
320 env->hflags & HF_CPL_MASK,
321 (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
Juan Quintela5ee0ffa2009-09-29 22:48:49 +0200322 (env->a20_mask >> 20) & 1,
bellardeaa728e2008-05-28 12:51:20 +0000323 (env->hflags >> HF_SMM_SHIFT) & 1,
bellardce5232c2008-05-28 17:14:10 +0000324 env->halted);
bellardeaa728e2008-05-28 12:51:20 +0000325 }
326
aliguoria3867ed2009-04-18 15:36:11 +0000327 for(i = 0; i < 6; i++) {
328 cpu_x86_dump_seg_cache(env, f, cpu_fprintf, seg_name[i],
329 &env->segs[i]);
330 }
331 cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "LDT", &env->ldt);
332 cpu_x86_dump_seg_cache(env, f, cpu_fprintf, "TR", &env->tr);
333
bellardeaa728e2008-05-28 12:51:20 +0000334#ifdef TARGET_X86_64
335 if (env->hflags & HF_LMA_MASK) {
bellardeaa728e2008-05-28 12:51:20 +0000336 cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n",
337 env->gdt.base, env->gdt.limit);
338 cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n",
339 env->idt.base, env->idt.limit);
340 cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
341 (uint32_t)env->cr[0],
342 env->cr[2],
343 env->cr[3],
344 (uint32_t)env->cr[4]);
aliguoria59cb4e2008-11-18 21:09:47 +0000345 for(i = 0; i < 4; i++)
346 cpu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
347 cpu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
aliguorid4b55be2008-12-02 19:40:26 +0000348 env->dr[6], env->dr[7]);
bellardeaa728e2008-05-28 12:51:20 +0000349 } else
350#endif
351 {
bellardeaa728e2008-05-28 12:51:20 +0000352 cpu_fprintf(f, "GDT= %08x %08x\n",
353 (uint32_t)env->gdt.base, env->gdt.limit);
354 cpu_fprintf(f, "IDT= %08x %08x\n",
355 (uint32_t)env->idt.base, env->idt.limit);
356 cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
357 (uint32_t)env->cr[0],
358 (uint32_t)env->cr[2],
359 (uint32_t)env->cr[3],
360 (uint32_t)env->cr[4]);
Stefan Weil9a78eea2010-10-22 23:03:33 +0200361 for(i = 0; i < 4; i++) {
362 cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
363 }
364 cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
365 env->dr[6], env->dr[7]);
bellardeaa728e2008-05-28 12:51:20 +0000366 }
367 if (flags & X86_DUMP_CCOP) {
368 if ((unsigned)env->cc_op < CC_OP_NB)
369 snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
370 else
371 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
372#ifdef TARGET_X86_64
373 if (env->hflags & HF_CS64_MASK) {
374 cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
375 env->cc_src, env->cc_dst,
376 cc_op_name);
377 } else
378#endif
379 {
380 cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
381 (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
382 cc_op_name);
383 }
384 }
Marcelo Tosattib5e5a932010-03-23 13:37:10 -0300385 cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
bellardeaa728e2008-05-28 12:51:20 +0000386 if (flags & X86_DUMP_FPU) {
387 int fptag;
388 fptag = 0;
389 for(i = 0; i < 8; i++) {
390 fptag |= ((!env->fptags[i]) << i);
391 }
392 cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
393 env->fpuc,
394 (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
395 env->fpstt,
396 fptag,
397 env->mxcsr);
398 for(i=0;i<8;i++) {
Aurelien Jarno1ffd41e2011-04-14 00:49:29 +0200399 CPU_LDoubleU u;
400 u.d = env->fpregs[i].d;
bellardeaa728e2008-05-28 12:51:20 +0000401 cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
Aurelien Jarno1ffd41e2011-04-14 00:49:29 +0200402 i, u.l.lower, u.l.upper);
bellardeaa728e2008-05-28 12:51:20 +0000403 if ((i & 1) == 1)
404 cpu_fprintf(f, "\n");
405 else
406 cpu_fprintf(f, " ");
407 }
408 if (env->hflags & HF_CS64_MASK)
409 nb = 16;
410 else
411 nb = 8;
412 for(i=0;i<nb;i++) {
413 cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
414 i,
415 env->xmm_regs[i].XMM_L(3),
416 env->xmm_regs[i].XMM_L(2),
417 env->xmm_regs[i].XMM_L(1),
418 env->xmm_regs[i].XMM_L(0));
419 if ((i & 1) == 1)
420 cpu_fprintf(f, "\n");
421 else
422 cpu_fprintf(f, " ");
423 }
424 }
Jan Kiszkaf5c848e2011-01-21 21:48:08 +0100425 if (flags & CPU_DUMP_CODE) {
426 target_ulong base = env->segs[R_CS].base + env->eip;
427 target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
428 uint8_t code;
429 char codestr[3];
430
431 cpu_fprintf(f, "Code=");
432 for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
433 if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
434 snprintf(codestr, sizeof(codestr), "%02x", code);
435 } else {
436 snprintf(codestr, sizeof(codestr), "??");
437 }
438 cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
439 i == offs ? "<" : "", codestr, i == offs ? ">" : "");
440 }
441 cpu_fprintf(f, "\n");
442 }
bellardeaa728e2008-05-28 12:51:20 +0000443}
444
445/***********************************************************/
446/* x86 mmu */
447/* XXX: add PGE support */
448
449void cpu_x86_set_a20(CPUX86State *env, int a20_state)
450{
451 a20_state = (a20_state != 0);
452 if (a20_state != ((env->a20_mask >> 20) & 1)) {
453#if defined(DEBUG_MMU)
454 printf("A20 update: a20=%d\n", a20_state);
455#endif
456 /* if the cpu is currently executing code, we must unlink it and
457 all the potentially executing TB */
458 cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
459
460 /* when a20 is changed, all the MMU mappings are invalid, so
461 we must flush everything */
462 tlb_flush(env, 1);
Juan Quintela5ee0ffa2009-09-29 22:48:49 +0200463 env->a20_mask = ~(1 << 20) | (a20_state << 20);
bellardeaa728e2008-05-28 12:51:20 +0000464 }
465}
466
467void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
468{
469 int pe_state;
470
471#if defined(DEBUG_MMU)
472 printf("CR0 update: CR0=0x%08x\n", new_cr0);
473#endif
474 if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
475 (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
476 tlb_flush(env, 1);
477 }
478
479#ifdef TARGET_X86_64
480 if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
481 (env->efer & MSR_EFER_LME)) {
482 /* enter in long mode */
483 /* XXX: generate an exception */
484 if (!(env->cr[4] & CR4_PAE_MASK))
485 return;
486 env->efer |= MSR_EFER_LMA;
487 env->hflags |= HF_LMA_MASK;
488 } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
489 (env->efer & MSR_EFER_LMA)) {
490 /* exit long mode */
491 env->efer &= ~MSR_EFER_LMA;
492 env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
493 env->eip &= 0xffffffff;
494 }
495#endif
496 env->cr[0] = new_cr0 | CR0_ET_MASK;
497
498 /* update PE flag in hidden flags */
499 pe_state = (env->cr[0] & CR0_PE_MASK);
500 env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
501 /* ensure that ADDSEG is always set in real mode */
502 env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
503 /* update FPU flags */
504 env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
505 ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
506}
507
508/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
509 the PDPT */
510void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
511{
512 env->cr[3] = new_cr3;
513 if (env->cr[0] & CR0_PG_MASK) {
514#if defined(DEBUG_MMU)
515 printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
516#endif
517 tlb_flush(env, 0);
518 }
519}
520
521void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
522{
523#if defined(DEBUG_MMU)
524 printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
525#endif
526 if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
527 (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
528 tlb_flush(env, 1);
529 }
530 /* SSE handling */
531 if (!(env->cpuid_features & CPUID_SSE))
532 new_cr4 &= ~CR4_OSFXSR_MASK;
533 if (new_cr4 & CR4_OSFXSR_MASK)
534 env->hflags |= HF_OSFXSR_MASK;
535 else
536 env->hflags &= ~HF_OSFXSR_MASK;
537
538 env->cr[4] = new_cr4;
539}
540
bellardeaa728e2008-05-28 12:51:20 +0000541#if defined(CONFIG_USER_ONLY)
542
543int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
Blue Swirl97b348e2011-08-01 16:12:17 +0000544 int is_write, int mmu_idx)
bellardeaa728e2008-05-28 12:51:20 +0000545{
546 /* user mode only emulation */
547 is_write &= 1;
548 env->cr[2] = addr;
549 env->error_code = (is_write << PG_ERROR_W_BIT);
550 env->error_code |= PG_ERROR_U_MASK;
551 env->exception_index = EXCP0E_PAGE;
552 return 1;
553}
554
bellardeaa728e2008-05-28 12:51:20 +0000555#else
556
557/* XXX: This value should match the one returned by CPUID
558 * and in exec.c */
bellardeaa728e2008-05-28 12:51:20 +0000559# if defined(TARGET_X86_64)
ths2c90d792008-07-03 04:13:24 +0000560# define PHYS_ADDR_MASK 0xfffffff000LL
bellardeaa728e2008-05-28 12:51:20 +0000561# else
ths2c90d792008-07-03 04:13:24 +0000562# define PHYS_ADDR_MASK 0xffffff000LL
bellardeaa728e2008-05-28 12:51:20 +0000563# endif
bellardeaa728e2008-05-28 12:51:20 +0000564
565/* return value:
566 -1 = cannot handle fault
567 0 = nothing more to do
568 1 = generate PF fault
bellardeaa728e2008-05-28 12:51:20 +0000569*/
570int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
Blue Swirl97b348e2011-08-01 16:12:17 +0000571 int is_write1, int mmu_idx)
bellardeaa728e2008-05-28 12:51:20 +0000572{
573 uint64_t ptep, pte;
574 target_ulong pde_addr, pte_addr;
Paul Brookd4c430a2010-03-17 02:14:28 +0000575 int error_code, is_dirty, prot, page_size, is_write, is_user;
Anthony Liguoric227f092009-10-01 16:12:16 -0500576 target_phys_addr_t paddr;
bellardeaa728e2008-05-28 12:51:20 +0000577 uint32_t page_offset;
578 target_ulong vaddr, virt_addr;
579
580 is_user = mmu_idx == MMU_USER_IDX;
581#if defined(DEBUG_MMU)
582 printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
583 addr, is_write1, is_user, env->eip);
584#endif
585 is_write = is_write1 & 1;
586
587 if (!(env->cr[0] & CR0_PG_MASK)) {
588 pte = addr;
589 virt_addr = addr & TARGET_PAGE_MASK;
590 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
591 page_size = 4096;
592 goto do_mapping;
593 }
594
595 if (env->cr[4] & CR4_PAE_MASK) {
596 uint64_t pde, pdpe;
597 target_ulong pdpe_addr;
598
599#ifdef TARGET_X86_64
600 if (env->hflags & HF_LMA_MASK) {
601 uint64_t pml4e_addr, pml4e;
602 int32_t sext;
603
604 /* test virtual address sign extension */
605 sext = (int64_t)addr >> 47;
606 if (sext != 0 && sext != -1) {
607 env->error_code = 0;
608 env->exception_index = EXCP0D_GPF;
609 return 1;
610 }
611
612 pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
613 env->a20_mask;
614 pml4e = ldq_phys(pml4e_addr);
615 if (!(pml4e & PG_PRESENT_MASK)) {
616 error_code = 0;
617 goto do_fault;
618 }
619 if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
620 error_code = PG_ERROR_RSVD_MASK;
621 goto do_fault;
622 }
623 if (!(pml4e & PG_ACCESSED_MASK)) {
624 pml4e |= PG_ACCESSED_MASK;
625 stl_phys_notdirty(pml4e_addr, pml4e);
626 }
627 ptep = pml4e ^ PG_NX_MASK;
628 pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
629 env->a20_mask;
630 pdpe = ldq_phys(pdpe_addr);
631 if (!(pdpe & PG_PRESENT_MASK)) {
632 error_code = 0;
633 goto do_fault;
634 }
635 if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
636 error_code = PG_ERROR_RSVD_MASK;
637 goto do_fault;
638 }
639 ptep &= pdpe ^ PG_NX_MASK;
640 if (!(pdpe & PG_ACCESSED_MASK)) {
641 pdpe |= PG_ACCESSED_MASK;
642 stl_phys_notdirty(pdpe_addr, pdpe);
643 }
644 } else
645#endif
646 {
647 /* XXX: load them when cr3 is loaded ? */
648 pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
649 env->a20_mask;
650 pdpe = ldq_phys(pdpe_addr);
651 if (!(pdpe & PG_PRESENT_MASK)) {
652 error_code = 0;
653 goto do_fault;
654 }
655 ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
656 }
657
658 pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
659 env->a20_mask;
660 pde = ldq_phys(pde_addr);
661 if (!(pde & PG_PRESENT_MASK)) {
662 error_code = 0;
663 goto do_fault;
664 }
665 if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
666 error_code = PG_ERROR_RSVD_MASK;
667 goto do_fault;
668 }
669 ptep &= pde ^ PG_NX_MASK;
670 if (pde & PG_PSE_MASK) {
671 /* 2 MB page */
672 page_size = 2048 * 1024;
673 ptep ^= PG_NX_MASK;
674 if ((ptep & PG_NX_MASK) && is_write1 == 2)
675 goto do_fault_protect;
676 if (is_user) {
677 if (!(ptep & PG_USER_MASK))
678 goto do_fault_protect;
679 if (is_write && !(ptep & PG_RW_MASK))
680 goto do_fault_protect;
681 } else {
682 if ((env->cr[0] & CR0_WP_MASK) &&
683 is_write && !(ptep & PG_RW_MASK))
684 goto do_fault_protect;
685 }
686 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
687 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
688 pde |= PG_ACCESSED_MASK;
689 if (is_dirty)
690 pde |= PG_DIRTY_MASK;
691 stl_phys_notdirty(pde_addr, pde);
692 }
693 /* align to page_size */
694 pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
695 virt_addr = addr & ~(page_size - 1);
696 } else {
697 /* 4 KB page */
698 if (!(pde & PG_ACCESSED_MASK)) {
699 pde |= PG_ACCESSED_MASK;
700 stl_phys_notdirty(pde_addr, pde);
701 }
702 pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
703 env->a20_mask;
704 pte = ldq_phys(pte_addr);
705 if (!(pte & PG_PRESENT_MASK)) {
706 error_code = 0;
707 goto do_fault;
708 }
709 if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
710 error_code = PG_ERROR_RSVD_MASK;
711 goto do_fault;
712 }
713 /* combine pde and pte nx, user and rw protections */
714 ptep &= pte ^ PG_NX_MASK;
715 ptep ^= PG_NX_MASK;
716 if ((ptep & PG_NX_MASK) && is_write1 == 2)
717 goto do_fault_protect;
718 if (is_user) {
719 if (!(ptep & PG_USER_MASK))
720 goto do_fault_protect;
721 if (is_write && !(ptep & PG_RW_MASK))
722 goto do_fault_protect;
723 } else {
724 if ((env->cr[0] & CR0_WP_MASK) &&
725 is_write && !(ptep & PG_RW_MASK))
726 goto do_fault_protect;
727 }
728 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
729 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
730 pte |= PG_ACCESSED_MASK;
731 if (is_dirty)
732 pte |= PG_DIRTY_MASK;
733 stl_phys_notdirty(pte_addr, pte);
734 }
735 page_size = 4096;
736 virt_addr = addr & ~0xfff;
737 pte = pte & (PHYS_ADDR_MASK | 0xfff);
738 }
739 } else {
740 uint32_t pde;
741
742 /* page directory entry */
743 pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
744 env->a20_mask;
745 pde = ldl_phys(pde_addr);
746 if (!(pde & PG_PRESENT_MASK)) {
747 error_code = 0;
748 goto do_fault;
749 }
750 /* if PSE bit is set, then we use a 4MB page */
751 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
752 page_size = 4096 * 1024;
753 if (is_user) {
754 if (!(pde & PG_USER_MASK))
755 goto do_fault_protect;
756 if (is_write && !(pde & PG_RW_MASK))
757 goto do_fault_protect;
758 } else {
759 if ((env->cr[0] & CR0_WP_MASK) &&
760 is_write && !(pde & PG_RW_MASK))
761 goto do_fault_protect;
762 }
763 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
764 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
765 pde |= PG_ACCESSED_MASK;
766 if (is_dirty)
767 pde |= PG_DIRTY_MASK;
768 stl_phys_notdirty(pde_addr, pde);
769 }
770
771 pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
772 ptep = pte;
773 virt_addr = addr & ~(page_size - 1);
774 } else {
775 if (!(pde & PG_ACCESSED_MASK)) {
776 pde |= PG_ACCESSED_MASK;
777 stl_phys_notdirty(pde_addr, pde);
778 }
779
780 /* page directory entry */
781 pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
782 env->a20_mask;
783 pte = ldl_phys(pte_addr);
784 if (!(pte & PG_PRESENT_MASK)) {
785 error_code = 0;
786 goto do_fault;
787 }
788 /* combine pde and pte user and rw protections */
789 ptep = pte & pde;
790 if (is_user) {
791 if (!(ptep & PG_USER_MASK))
792 goto do_fault_protect;
793 if (is_write && !(ptep & PG_RW_MASK))
794 goto do_fault_protect;
795 } else {
796 if ((env->cr[0] & CR0_WP_MASK) &&
797 is_write && !(ptep & PG_RW_MASK))
798 goto do_fault_protect;
799 }
800 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
801 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
802 pte |= PG_ACCESSED_MASK;
803 if (is_dirty)
804 pte |= PG_DIRTY_MASK;
805 stl_phys_notdirty(pte_addr, pte);
806 }
807 page_size = 4096;
808 virt_addr = addr & ~0xfff;
809 }
810 }
811 /* the page can be put in the TLB */
812 prot = PAGE_READ;
813 if (!(ptep & PG_NX_MASK))
814 prot |= PAGE_EXEC;
815 if (pte & PG_DIRTY_MASK) {
816 /* only set write access if already dirty... otherwise wait
817 for dirty access */
818 if (is_user) {
819 if (ptep & PG_RW_MASK)
820 prot |= PAGE_WRITE;
821 } else {
822 if (!(env->cr[0] & CR0_WP_MASK) ||
823 (ptep & PG_RW_MASK))
824 prot |= PAGE_WRITE;
825 }
826 }
827 do_mapping:
828 pte = pte & env->a20_mask;
829
830 /* Even if 4MB pages, we map only one 4KB page in the cache to
831 avoid filling it too fast */
832 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
833 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
834 vaddr = virt_addr + page_offset;
835
Paul Brookd4c430a2010-03-17 02:14:28 +0000836 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
837 return 0;
bellardeaa728e2008-05-28 12:51:20 +0000838 do_fault_protect:
839 error_code = PG_ERROR_P_MASK;
840 do_fault:
841 error_code |= (is_write << PG_ERROR_W_BIT);
842 if (is_user)
843 error_code |= PG_ERROR_U_MASK;
844 if (is_write1 == 2 &&
845 (env->efer & MSR_EFER_NXE) &&
846 (env->cr[4] & CR4_PAE_MASK))
847 error_code |= PG_ERROR_I_D_MASK;
bellard872929a2008-05-28 16:16:54 +0000848 if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
849 /* cr2 is not modified in case of exceptions */
850 stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
851 addr);
bellardeaa728e2008-05-28 12:51:20 +0000852 } else {
853 env->cr[2] = addr;
854 }
855 env->error_code = error_code;
856 env->exception_index = EXCP0E_PAGE;
bellardeaa728e2008-05-28 12:51:20 +0000857 return 1;
858}
859
Andreas Färber317ac622012-03-14 01:38:21 +0100860target_phys_addr_t cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr)
bellardeaa728e2008-05-28 12:51:20 +0000861{
862 target_ulong pde_addr, pte_addr;
863 uint64_t pte;
Anthony Liguoric227f092009-10-01 16:12:16 -0500864 target_phys_addr_t paddr;
bellardeaa728e2008-05-28 12:51:20 +0000865 uint32_t page_offset;
866 int page_size;
867
868 if (env->cr[4] & CR4_PAE_MASK) {
869 target_ulong pdpe_addr;
870 uint64_t pde, pdpe;
871
872#ifdef TARGET_X86_64
873 if (env->hflags & HF_LMA_MASK) {
874 uint64_t pml4e_addr, pml4e;
875 int32_t sext;
876
877 /* test virtual address sign extension */
878 sext = (int64_t)addr >> 47;
879 if (sext != 0 && sext != -1)
880 return -1;
881
882 pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
883 env->a20_mask;
884 pml4e = ldq_phys(pml4e_addr);
885 if (!(pml4e & PG_PRESENT_MASK))
886 return -1;
887
Jan Kiszka3f2cbf02012-03-06 15:22:02 +0100888 pdpe_addr = ((pml4e & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
889 (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask;
bellardeaa728e2008-05-28 12:51:20 +0000890 pdpe = ldq_phys(pdpe_addr);
891 if (!(pdpe & PG_PRESENT_MASK))
892 return -1;
893 } else
894#endif
895 {
896 pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
897 env->a20_mask;
898 pdpe = ldq_phys(pdpe_addr);
899 if (!(pdpe & PG_PRESENT_MASK))
900 return -1;
901 }
902
Jan Kiszka3f2cbf02012-03-06 15:22:02 +0100903 pde_addr = ((pdpe & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
904 (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask;
bellardeaa728e2008-05-28 12:51:20 +0000905 pde = ldq_phys(pde_addr);
906 if (!(pde & PG_PRESENT_MASK)) {
907 return -1;
908 }
909 if (pde & PG_PSE_MASK) {
910 /* 2 MB page */
911 page_size = 2048 * 1024;
912 pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
913 } else {
914 /* 4 KB page */
Jan Kiszka3f2cbf02012-03-06 15:22:02 +0100915 pte_addr = ((pde & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) +
916 (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask;
bellardeaa728e2008-05-28 12:51:20 +0000917 page_size = 4096;
918 pte = ldq_phys(pte_addr);
919 }
Jan Kiszka3f2cbf02012-03-06 15:22:02 +0100920 pte &= ~(PG_NX_MASK | PG_HI_USER_MASK);
aliguorica1c9e12008-08-18 18:00:31 +0000921 if (!(pte & PG_PRESENT_MASK))
922 return -1;
bellardeaa728e2008-05-28 12:51:20 +0000923 } else {
924 uint32_t pde;
925
926 if (!(env->cr[0] & CR0_PG_MASK)) {
927 pte = addr;
928 page_size = 4096;
929 } else {
930 /* page directory entry */
931 pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
932 pde = ldl_phys(pde_addr);
933 if (!(pde & PG_PRESENT_MASK))
934 return -1;
935 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
936 pte = pde & ~0x003ff000; /* align to 4MB */
937 page_size = 4096 * 1024;
938 } else {
939 /* page directory entry */
940 pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
941 pte = ldl_phys(pte_addr);
942 if (!(pte & PG_PRESENT_MASK))
943 return -1;
944 page_size = 4096;
945 }
946 }
947 pte = pte & env->a20_mask;
948 }
949
950 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
951 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
952 return paddr;
953}
aliguori01df0402008-11-18 21:08:15 +0000954
Andreas Färber317ac622012-03-14 01:38:21 +0100955void hw_breakpoint_insert(CPUX86State *env, int index)
aliguori01df0402008-11-18 21:08:15 +0000956{
957 int type, err = 0;
958
959 switch (hw_breakpoint_type(env->dr[7], index)) {
960 case 0:
961 if (hw_breakpoint_enabled(env->dr[7], index))
962 err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
963 &env->cpu_breakpoint[index]);
964 break;
965 case 1:
966 type = BP_CPU | BP_MEM_WRITE;
967 goto insert_wp;
968 case 2:
969 /* No support for I/O watchpoints yet */
970 break;
971 case 3:
972 type = BP_CPU | BP_MEM_ACCESS;
973 insert_wp:
974 err = cpu_watchpoint_insert(env, env->dr[index],
975 hw_breakpoint_len(env->dr[7], index),
976 type, &env->cpu_watchpoint[index]);
977 break;
978 }
979 if (err)
980 env->cpu_breakpoint[index] = NULL;
981}
982
Andreas Färber317ac622012-03-14 01:38:21 +0100983void hw_breakpoint_remove(CPUX86State *env, int index)
aliguori01df0402008-11-18 21:08:15 +0000984{
985 if (!env->cpu_breakpoint[index])
986 return;
987 switch (hw_breakpoint_type(env->dr[7], index)) {
988 case 0:
989 if (hw_breakpoint_enabled(env->dr[7], index))
990 cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
991 break;
992 case 1:
993 case 3:
994 cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
995 break;
996 case 2:
997 /* No support for I/O watchpoints yet */
998 break;
999 }
1000}
1001
Andreas Färber317ac622012-03-14 01:38:21 +01001002int check_hw_breakpoints(CPUX86State *env, int force_dr6_update)
aliguori01df0402008-11-18 21:08:15 +00001003{
1004 target_ulong dr6;
1005 int reg, type;
1006 int hit_enabled = 0;
1007
1008 dr6 = env->dr[6] & ~0xf;
1009 for (reg = 0; reg < 4; reg++) {
1010 type = hw_breakpoint_type(env->dr[7], reg);
1011 if ((type == 0 && env->dr[reg] == env->eip) ||
1012 ((type & 1) && env->cpu_watchpoint[reg] &&
1013 (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) {
1014 dr6 |= 1 << reg;
1015 if (hw_breakpoint_enabled(env->dr[7], reg))
1016 hit_enabled = 1;
1017 }
1018 }
1019 if (hit_enabled || force_dr6_update)
1020 env->dr[6] = dr6;
1021 return hit_enabled;
1022}
1023
1024static CPUDebugExcpHandler *prev_debug_excp_handler;
1025
Andreas Färber317ac622012-03-14 01:38:21 +01001026static void breakpoint_handler(CPUX86State *env)
aliguori01df0402008-11-18 21:08:15 +00001027{
1028 CPUBreakpoint *bp;
1029
1030 if (env->watchpoint_hit) {
1031 if (env->watchpoint_hit->flags & BP_CPU) {
1032 env->watchpoint_hit = NULL;
1033 if (check_hw_breakpoints(env, 0))
Jason Wessel63a54732010-01-26 16:29:50 -06001034 raise_exception_env(EXCP01_DB, env);
aliguori01df0402008-11-18 21:08:15 +00001035 else
1036 cpu_resume_from_signal(env, NULL);
1037 }
1038 } else {
Blue Swirl72cf2d42009-09-12 07:36:22 +00001039 QTAILQ_FOREACH(bp, &env->breakpoints, entry)
aliguori01df0402008-11-18 21:08:15 +00001040 if (bp->pc == env->eip) {
1041 if (bp->flags & BP_CPU) {
1042 check_hw_breakpoints(env, 1);
Jason Wessel63a54732010-01-26 16:29:50 -06001043 raise_exception_env(EXCP01_DB, env);
aliguori01df0402008-11-18 21:08:15 +00001044 }
1045 break;
1046 }
1047 }
1048 if (prev_debug_excp_handler)
1049 prev_debug_excp_handler(env);
1050}
Huang Ying79c4f6b2009-06-23 10:05:14 +08001051
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001052typedef struct MCEInjectionParams {
1053 Monitor *mon;
Andreas Färber317ac622012-03-14 01:38:21 +01001054 CPUX86State *env;
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001055 int bank;
1056 uint64_t status;
1057 uint64_t mcg_status;
1058 uint64_t addr;
1059 uint64_t misc;
1060 int flags;
1061} MCEInjectionParams;
1062
1063static void do_inject_x86_mce(void *data)
Huang Ying79c4f6b2009-06-23 10:05:14 +08001064{
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001065 MCEInjectionParams *params = data;
Andreas Färber317ac622012-03-14 01:38:21 +01001066 CPUX86State *cenv = params->env;
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001067 uint64_t *banks = cenv->mce_banks + 4 * params->bank;
1068
1069 cpu_synchronize_state(cenv);
Huang Ying79c4f6b2009-06-23 10:05:14 +08001070
Jan Kiszka747461c2011-03-02 08:56:10 +01001071 /*
1072 * If there is an MCE exception being processed, ignore this SRAO MCE
1073 * unless unconditional injection was requested.
1074 */
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001075 if (!(params->flags & MCE_INJECT_UNCOND_AO)
1076 && !(params->status & MCI_STATUS_AR)
Jan Kiszka747461c2011-03-02 08:56:10 +01001077 && (cenv->mcg_status & MCG_STATUS_MCIP)) {
1078 return;
1079 }
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001080
1081 if (params->status & MCI_STATUS_UC) {
Jan Kiszka316378e2011-03-02 08:56:09 +01001082 /*
1083 * if MSR_MCG_CTL is not all 1s, the uncorrected error
1084 * reporting is disabled
1085 */
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001086 if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
1087 monitor_printf(params->mon,
Jan Kiszka316378e2011-03-02 08:56:09 +01001088 "CPU %d: Uncorrected error reporting disabled\n",
1089 cenv->cpu_index);
1090 return;
1091 }
1092
1093 /*
1094 * if MSR_MCi_CTL is not all 1s, the uncorrected error
1095 * reporting is disabled for the bank
1096 */
1097 if (banks[0] != ~(uint64_t)0) {
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001098 monitor_printf(params->mon,
1099 "CPU %d: Uncorrected error reporting disabled for"
1100 " bank %d\n",
1101 cenv->cpu_index, params->bank);
Jan Kiszka316378e2011-03-02 08:56:09 +01001102 return;
1103 }
1104
Huang Ying79c4f6b2009-06-23 10:05:14 +08001105 if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
1106 !(cenv->cr[4] & CR4_MCE_MASK)) {
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001107 monitor_printf(params->mon,
1108 "CPU %d: Previous MCE still in progress, raising"
1109 " triple fault\n",
1110 cenv->cpu_index);
Huang Ying79c4f6b2009-06-23 10:05:14 +08001111 qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
1112 qemu_system_reset_request();
1113 return;
1114 }
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001115 if (banks[1] & MCI_STATUS_VAL) {
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001116 params->status |= MCI_STATUS_OVER;
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001117 }
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001118 banks[2] = params->addr;
1119 banks[3] = params->misc;
1120 cenv->mcg_status = params->mcg_status;
1121 banks[1] = params->status;
Huang Ying79c4f6b2009-06-23 10:05:14 +08001122 cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
1123 } else if (!(banks[1] & MCI_STATUS_VAL)
1124 || !(banks[1] & MCI_STATUS_UC)) {
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001125 if (banks[1] & MCI_STATUS_VAL) {
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001126 params->status |= MCI_STATUS_OVER;
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001127 }
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001128 banks[2] = params->addr;
1129 banks[3] = params->misc;
1130 banks[1] = params->status;
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001131 } else {
Huang Ying79c4f6b2009-06-23 10:05:14 +08001132 banks[1] |= MCI_STATUS_OVER;
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001133 }
Huang Ying79c4f6b2009-06-23 10:05:14 +08001134}
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001135
Andreas Färber317ac622012-03-14 01:38:21 +01001136void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
Jan Kiszka316378e2011-03-02 08:56:09 +01001137 uint64_t status, uint64_t mcg_status, uint64_t addr,
Jan Kiszka747461c2011-03-02 08:56:10 +01001138 uint64_t misc, int flags)
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001139{
Jan Kiszkad5bfda32011-03-02 08:56:15 +01001140 MCEInjectionParams params = {
1141 .mon = mon,
1142 .env = cenv,
1143 .bank = bank,
1144 .status = status,
1145 .mcg_status = mcg_status,
1146 .addr = addr,
1147 .misc = misc,
1148 .flags = flags,
1149 };
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001150 unsigned bank_num = cenv->mcg_cap & 0xff;
Andreas Färber317ac622012-03-14 01:38:21 +01001151 CPUX86State *env;
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001152
Jan Kiszka316378e2011-03-02 08:56:09 +01001153 if (!cenv->mcg_cap) {
1154 monitor_printf(mon, "MCE injection not supported\n");
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001155 return;
1156 }
Jan Kiszka316378e2011-03-02 08:56:09 +01001157 if (bank >= bank_num) {
1158 monitor_printf(mon, "Invalid MCE bank number\n");
1159 return;
1160 }
1161 if (!(status & MCI_STATUS_VAL)) {
1162 monitor_printf(mon, "Invalid MCE status code\n");
1163 return;
1164 }
Jan Kiszka747461c2011-03-02 08:56:10 +01001165 if ((flags & MCE_INJECT_BROADCAST)
1166 && !cpu_x86_support_mca_broadcast(cenv)) {
Jan Kiszka316378e2011-03-02 08:56:09 +01001167 monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
1168 return;
Jin Dongming2bd3e042010-12-10 17:21:14 +09001169 }
1170
Jan Kiszkac34d4402011-03-02 08:56:16 +01001171 run_on_cpu(cenv, do_inject_x86_mce, &params);
1172 if (flags & MCE_INJECT_BROADCAST) {
1173 params.bank = 1;
1174 params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
1175 params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
1176 params.addr = 0;
1177 params.misc = 0;
1178 for (env = first_cpu; env != NULL; env = env->next_cpu) {
1179 if (cenv == env) {
1180 continue;
Jin Dongming31ce5e02010-12-10 17:21:02 +09001181 }
Jan Kiszkac34d4402011-03-02 08:56:16 +01001182 params.env = env;
1183 run_on_cpu(cenv, do_inject_x86_mce, &params);
Jin Dongming31ce5e02010-12-10 17:21:02 +09001184 }
Jin Dongmingb3cd24e2010-12-10 17:20:44 +09001185 }
1186}
Jan Kiszkad362e752012-02-17 18:31:17 +01001187
Andreas Färber317ac622012-03-14 01:38:21 +01001188void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
Jan Kiszkad362e752012-02-17 18:31:17 +01001189{
1190 TranslationBlock *tb;
1191
1192 if (kvm_enabled()) {
1193 env->tpr_access_type = access;
1194
1195 cpu_interrupt(env, CPU_INTERRUPT_TPR);
1196 } else {
1197 tb = tb_find_pc(env->mem_io_pc);
1198 cpu_restore_state(tb, env, env->mem_io_pc);
1199
1200 apic_handle_tpr_access_report(env->apic_state, env->eip, access);
1201 }
1202}
bellardeaa728e2008-05-28 12:51:20 +00001203#endif /* !CONFIG_USER_ONLY */
aliguori6fd805e2008-11-05 15:34:06 +00001204
Huang Ying79c4f6b2009-06-23 10:05:14 +08001205static void mce_init(CPUX86State *cenv)
1206{
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001207 unsigned int bank;
Huang Ying79c4f6b2009-06-23 10:05:14 +08001208
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001209 if (((cenv->cpuid_version >> 8) & 0xf) >= 6
1210 && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
1211 (CPUID_MCE | CPUID_MCA)) {
Huang Ying79c4f6b2009-06-23 10:05:14 +08001212 cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
1213 cenv->mcg_ctl = ~(uint64_t)0;
Jan Kiszka2fa11da2011-03-02 08:56:08 +01001214 for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
1215 cenv->mce_banks[bank * 4] = ~(uint64_t)0;
1216 }
Huang Ying79c4f6b2009-06-23 10:05:14 +08001217 }
1218}
1219
Jan Kiszka84273172009-06-27 09:53:51 +02001220int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
1221 target_ulong *base, unsigned int *limit,
1222 unsigned int *flags)
1223{
1224 SegmentCache *dt;
1225 target_ulong ptr;
1226 uint32_t e1, e2;
1227 int index;
1228
1229 if (selector & 0x4)
1230 dt = &env->ldt;
1231 else
1232 dt = &env->gdt;
1233 index = selector & ~7;
1234 ptr = dt->base + index;
1235 if ((index + 7) > dt->limit
1236 || cpu_memory_rw_debug(env, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
1237 || cpu_memory_rw_debug(env, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
1238 return 0;
1239
1240 *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
1241 *limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1242 if (e2 & DESC_G_MASK)
1243 *limit = (*limit << 12) | 0xfff;
1244 *flags = e2;
1245
1246 return 1;
1247}
1248
aliguori01df0402008-11-18 21:08:15 +00001249CPUX86State *cpu_x86_init(const char *cpu_model)
1250{
1251 CPUX86State *env;
1252 static int inited;
1253
Anthony Liguori7267c092011-08-20 22:09:37 -05001254 env = g_malloc0(sizeof(CPUX86State));
aliguori01df0402008-11-18 21:08:15 +00001255 cpu_exec_init(env);
1256 env->cpu_model_str = cpu_model;
1257
Jan Kiszkad5ab9712011-08-02 16:10:21 +02001258 /* init various static tables used in TCG mode */
1259 if (tcg_enabled() && !inited) {
aliguori01df0402008-11-18 21:08:15 +00001260 inited = 1;
1261 optimize_flags_init();
1262#ifndef CONFIG_USER_ONLY
1263 prev_debug_excp_handler =
1264 cpu_set_debug_excp_handler(breakpoint_handler);
1265#endif
1266 }
1267 if (cpu_x86_register(env, cpu_model) < 0) {
1268 cpu_x86_close(env);
1269 return NULL;
1270 }
Bharata B Raof2209eb2011-11-02 14:16:08 +05301271 env->cpuid_apic_id = env->cpu_index;
Huang Ying79c4f6b2009-06-23 10:05:14 +08001272 mce_init(env);
aliguori0bf46a42009-04-24 18:03:41 +00001273
1274 qemu_init_vcpu(env);
1275
aliguori01df0402008-11-18 21:08:15 +00001276 return env;
1277}
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001278
1279#if !defined(CONFIG_USER_ONLY)
Andreas Färber317ac622012-03-14 01:38:21 +01001280void do_cpu_init(CPUX86State *env)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001281{
1282 int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
Jan Kiszkaebda3772011-03-15 12:26:21 +01001283 uint64_t pat = env->pat;
1284
Andreas Färber1bba0dc2012-02-08 03:03:33 +01001285 cpu_state_reset(env);
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001286 env->interrupt_request = sipi;
Jan Kiszkaebda3772011-03-15 12:26:21 +01001287 env->pat = pat;
Blue Swirl4a942ce2010-06-19 10:42:31 +03001288 apic_init_reset(env->apic_state);
Jan Kiszka052be862010-06-23 08:19:39 +02001289 env->halted = !cpu_is_bsp(env);
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001290}
1291
Andreas Färber317ac622012-03-14 01:38:21 +01001292void do_cpu_sipi(CPUX86State *env)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001293{
Blue Swirl4a942ce2010-06-19 10:42:31 +03001294 apic_sipi(env->apic_state);
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001295}
1296#else
Andreas Färber317ac622012-03-14 01:38:21 +01001297void do_cpu_init(CPUX86State *env)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001298{
1299}
Andreas Färber317ac622012-03-14 01:38:21 +01001300void do_cpu_sipi(CPUX86State *env)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +03001301{
1302}
1303#endif