]> Git Repo - qemu.git/blame - target-i386/helper2.c
statfs fix
[qemu.git] / target-i386 / helper2.c
CommitLineData
2c0262af
FB
1/*
2 * i386 helpers (without register variable usage)
3 *
4 * 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
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25#include <signal.h>
26#include <assert.h>
2c0262af
FB
27
28#include "cpu.h"
29#include "exec-all.h"
30
31//#define DEBUG_MMU
32
0e4b179d
FB
33#ifdef USE_CODE_COPY
34#include <asm/ldt.h>
35#include <linux/unistd.h>
73bdea19 36#include <linux/version.h>
0e4b179d
FB
37
38_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
73bdea19
FB
39
40#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
41#define modify_ldt_ldt_s user_desc
0e4b179d 42#endif
73bdea19 43#endif /* USE_CODE_COPY */
0e4b179d 44
2c0262af
FB
45CPUX86State *cpu_x86_init(void)
46{
47 CPUX86State *env;
2c0262af
FB
48 static int inited;
49
173d6cfe 50 env = qemu_mallocz(sizeof(CPUX86State));
2c0262af
FB
51 if (!env)
52 return NULL;
173d6cfe
FB
53 cpu_exec_init(env);
54
ffddfee3
FB
55 /* init various static tables */
56 if (!inited) {
57 inited = 1;
58 optimize_flags_init();
59 }
60#ifdef USE_CODE_COPY
61 /* testing code for code copy case */
62 {
63 struct modify_ldt_ldt_s ldt;
2c0262af 64
ffddfee3
FB
65 ldt.entry_number = 1;
66 ldt.base_addr = (unsigned long)env;
67 ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
68 ldt.seg_32bit = 1;
69 ldt.contents = MODIFY_LDT_CONTENTS_DATA;
70 ldt.read_exec_only = 0;
71 ldt.limit_in_pages = 1;
72 ldt.seg_not_present = 0;
73 ldt.useable = 1;
74 modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
75
76 asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
ffddfee3
FB
77 }
78#endif
14ce26e7
FB
79 {
80 int family, model, stepping;
81#ifdef TARGET_X86_64
82 env->cpuid_vendor1 = 0x68747541; /* "Auth" */
83 env->cpuid_vendor2 = 0x69746e65; /* "enti" */
84 env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */
85 family = 6;
86 model = 2;
87 stepping = 3;
88#else
89 env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
90 env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
91 env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
92#if 0
93 /* pentium 75-200 */
94 family = 5;
95 model = 2;
96 stepping = 11;
97#else
98 /* pentium pro */
99 family = 6;
bf079a1e 100 model = 3;
14ce26e7
FB
101 stepping = 3;
102#endif
103#endif
a6f37988 104 env->cpuid_level = 2;
14ce26e7
FB
105 env->cpuid_version = (family << 8) | (model << 4) | stepping;
106 env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
107 CPUID_TSC | CPUID_MSR | CPUID_MCE |
8f091a59
FB
108 CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
109 CPUID_PAT);
110 env->pat = 0x0007040600070406ULL;
bf079a1e
FB
111 env->cpuid_ext_features = 0;
112 env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
a6f37988
FB
113 env->cpuid_xlevel = 0;
114 {
115 const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
116 int c, len, i;
117 len = strlen(model_id);
118 for(i = 0; i < 48; i++) {
119 if (i >= len)
120 c = '\0';
121 else
122 c = model_id[i];
123 env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
124 }
125 }
14ce26e7
FB
126#ifdef TARGET_X86_64
127 /* currently not enabled for std i386 because not fully tested */
bf079a1e 128 env->cpuid_features |= CPUID_APIC;
a6f37988 129 env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
4b4f782c 130 env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
a6f37988 131 env->cpuid_xlevel = 0x80000008;
8f091a59
FB
132
133 /* these features are needed for Win64 and aren't fully implemented */
134 env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
14ce26e7
FB
135#endif
136 }
ffddfee3 137 cpu_reset(env);
bf079a1e
FB
138#ifdef USE_KQEMU
139 kqemu_init(env);
140#endif
ffddfee3
FB
141 return env;
142}
143
144/* NOTE: must be called outside the CPU execute loop */
145void cpu_reset(CPUX86State *env)
146{
147 int i;
148
149 memset(env, 0, offsetof(CPUX86State, breakpoints));
1ac157da
FB
150
151 tlb_flush(env, 1);
ffddfee3
FB
152
153 /* init to reset state */
154
2c0262af
FB
155#ifdef CONFIG_SOFTMMU
156 env->hflags |= HF_SOFTMMU_MASK;
157#endif
1ac157da
FB
158
159 cpu_x86_update_cr0(env, 0x60000010);
160 env->a20_mask = 0xffffffff;
161
162 env->idt.limit = 0xffff;
163 env->gdt.limit = 0xffff;
164 env->ldt.limit = 0xffff;
165 env->ldt.flags = DESC_P_MASK;
166 env->tr.limit = 0xffff;
167 env->tr.flags = DESC_P_MASK;
168
14ce26e7
FB
169 cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0);
170 cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0);
171 cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0);
172 cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0);
173 cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0);
174 cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);
1ac157da
FB
175
176 env->eip = 0xfff0;
177 env->regs[R_EDX] = 0x600; /* indicate P6 processor */
178
179 env->eflags = 0x2;
180
181 /* FPU init */
182 for(i = 0;i < 8; i++)
183 env->fptags[i] = 1;
184 env->fpuc = 0x37f;
664e0f19
FB
185
186 env->mxcsr = 0x1f80;
2c0262af
FB
187}
188
189void cpu_x86_close(CPUX86State *env)
190{
191 free(env);
192}
193
194/***********************************************************/
195/* x86 debug */
196
197static const char *cc_op_str[] = {
198 "DYNAMIC",
199 "EFLAGS",
14ce26e7 200
b7f0f463
FB
201 "MULB",
202 "MULW",
203 "MULL",
14ce26e7
FB
204 "MULQ",
205
2c0262af
FB
206 "ADDB",
207 "ADDW",
208 "ADDL",
14ce26e7
FB
209 "ADDQ",
210
2c0262af
FB
211 "ADCB",
212 "ADCW",
213 "ADCL",
14ce26e7
FB
214 "ADCQ",
215
2c0262af
FB
216 "SUBB",
217 "SUBW",
218 "SUBL",
14ce26e7
FB
219 "SUBQ",
220
2c0262af
FB
221 "SBBB",
222 "SBBW",
223 "SBBL",
14ce26e7
FB
224 "SBBQ",
225
2c0262af
FB
226 "LOGICB",
227 "LOGICW",
228 "LOGICL",
14ce26e7
FB
229 "LOGICQ",
230
2c0262af
FB
231 "INCB",
232 "INCW",
233 "INCL",
14ce26e7
FB
234 "INCQ",
235
2c0262af
FB
236 "DECB",
237 "DECW",
238 "DECL",
14ce26e7
FB
239 "DECQ",
240
2c0262af
FB
241 "SHLB",
242 "SHLW",
243 "SHLL",
14ce26e7
FB
244 "SHLQ",
245
2c0262af
FB
246 "SARB",
247 "SARW",
248 "SARL",
14ce26e7 249 "SARQ",
2c0262af
FB
250};
251
7fe48483
FB
252void cpu_dump_state(CPUState *env, FILE *f,
253 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
254 int flags)
2c0262af 255{
2157fa06 256 int eflags, i, nb;
2c0262af 257 char cc_op_name[32];
246d897f 258 static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
2c0262af
FB
259
260 eflags = env->eflags;
14ce26e7
FB
261#ifdef TARGET_X86_64
262 if (env->hflags & HF_CS64_MASK) {
263 cpu_fprintf(f,
264 "RAX=%016llx RBX=%016llx RCX=%016llx RDX=%016llx\n"
265 "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n"
266 "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n"
267 "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n"
d2ac63e0 268 "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
14ce26e7
FB
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,
d2ac63e0
FB
295 (env->a20_mask >> 20) & 1,
296 (env->hflags >> HF_HALTED_SHIFT) & 1);
14ce26e7
FB
297 } else
298#endif
299 {
300 cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
301 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
d2ac63e0 302 "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
14ce26e7
FB
303 (uint32_t)env->regs[R_EAX],
304 (uint32_t)env->regs[R_EBX],
305 (uint32_t)env->regs[R_ECX],
306 (uint32_t)env->regs[R_EDX],
307 (uint32_t)env->regs[R_ESI],
308 (uint32_t)env->regs[R_EDI],
309 (uint32_t)env->regs[R_EBP],
310 (uint32_t)env->regs[R_ESP],
311 (uint32_t)env->eip, eflags,
312 eflags & DF_MASK ? 'D' : '-',
313 eflags & CC_O ? 'O' : '-',
314 eflags & CC_S ? 'S' : '-',
315 eflags & CC_Z ? 'Z' : '-',
316 eflags & CC_A ? 'A' : '-',
317 eflags & CC_P ? 'P' : '-',
318 eflags & CC_C ? 'C' : '-',
319 env->hflags & HF_CPL_MASK,
320 (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
d2ac63e0
FB
321 (env->a20_mask >> 20) & 1,
322 (env->hflags >> HF_HALTED_SHIFT) & 1);
14ce26e7
FB
323 }
324
325#ifdef TARGET_X86_64
326 if (env->hflags & HF_LMA_MASK) {
327 for(i = 0; i < 6; i++) {
328 SegmentCache *sc = &env->segs[i];
329 cpu_fprintf(f, "%s =%04x %016llx %08x %08x\n",
330 seg_name[i],
331 sc->selector,
332 sc->base,
333 sc->limit,
334 sc->flags);
335 }
336 cpu_fprintf(f, "LDT=%04x %016llx %08x %08x\n",
337 env->ldt.selector,
338 env->ldt.base,
339 env->ldt.limit,
340 env->ldt.flags);
341 cpu_fprintf(f, "TR =%04x %016llx %08x %08x\n",
342 env->tr.selector,
343 env->tr.base,
344 env->tr.limit,
345 env->tr.flags);
346 cpu_fprintf(f, "GDT= %016llx %08x\n",
347 env->gdt.base, env->gdt.limit);
348 cpu_fprintf(f, "IDT= %016llx %08x\n",
349 env->idt.base, env->idt.limit);
350 cpu_fprintf(f, "CR0=%08x CR2=%016llx CR3=%016llx CR4=%08x\n",
351 (uint32_t)env->cr[0],
352 env->cr[2],
353 env->cr[3],
354 (uint32_t)env->cr[4]);
355 } else
356#endif
357 {
358 for(i = 0; i < 6; i++) {
359 SegmentCache *sc = &env->segs[i];
360 cpu_fprintf(f, "%s =%04x %08x %08x %08x\n",
361 seg_name[i],
362 sc->selector,
363 (uint32_t)sc->base,
364 sc->limit,
365 sc->flags);
366 }
367 cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n",
368 env->ldt.selector,
369 (uint32_t)env->ldt.base,
370 env->ldt.limit,
371 env->ldt.flags);
372 cpu_fprintf(f, "TR =%04x %08x %08x %08x\n",
373 env->tr.selector,
374 (uint32_t)env->tr.base,
375 env->tr.limit,
376 env->tr.flags);
377 cpu_fprintf(f, "GDT= %08x %08x\n",
378 (uint32_t)env->gdt.base, env->gdt.limit);
379 cpu_fprintf(f, "IDT= %08x %08x\n",
380 (uint32_t)env->idt.base, env->idt.limit);
381 cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
382 (uint32_t)env->cr[0],
383 (uint32_t)env->cr[2],
384 (uint32_t)env->cr[3],
385 (uint32_t)env->cr[4]);
246d897f 386 }
2c0262af
FB
387 if (flags & X86_DUMP_CCOP) {
388 if ((unsigned)env->cc_op < CC_OP_NB)
eba2af63 389 snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
2c0262af
FB
390 else
391 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
14ce26e7
FB
392#ifdef TARGET_X86_64
393 if (env->hflags & HF_CS64_MASK) {
394 cpu_fprintf(f, "CCS=%016llx CCD=%016llx CCO=%-8s\n",
395 env->cc_src, env->cc_dst,
396 cc_op_name);
397 } else
398#endif
399 {
400 cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
401 (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
402 cc_op_name);
403 }
2c0262af
FB
404 }
405 if (flags & X86_DUMP_FPU) {
2157fa06
FB
406 int fptag;
407 fptag = 0;
408 for(i = 0; i < 8; i++) {
409 fptag |= ((!env->fptags[i]) << i);
410 }
411 cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
412 env->fpuc,
413 (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
414 env->fpstt,
415 fptag,
416 env->mxcsr);
417 for(i=0;i<8;i++) {
418#if defined(USE_X86LDOUBLE)
419 union {
420 long double d;
421 struct {
422 uint64_t lower;
423 uint16_t upper;
424 } l;
425 } tmp;
426 tmp.d = env->fpregs[i].d;
427 cpu_fprintf(f, "FPR%d=%016llx %04x",
428 i, tmp.l.lower, tmp.l.upper);
429#else
430 cpu_fprintf(f, "FPR%d=%016llx",
431 i, env->fpregs[i].mmx.q);
432#endif
433 if ((i & 1) == 1)
434 cpu_fprintf(f, "\n");
435 else
436 cpu_fprintf(f, " ");
437 }
438 if (env->hflags & HF_CS64_MASK)
439 nb = 16;
440 else
441 nb = 8;
442 for(i=0;i<nb;i++) {
443 cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
444 i,
445 env->xmm_regs[i].XMM_L(3),
446 env->xmm_regs[i].XMM_L(2),
447 env->xmm_regs[i].XMM_L(1),
448 env->xmm_regs[i].XMM_L(0));
449 if ((i & 1) == 1)
450 cpu_fprintf(f, "\n");
451 else
452 cpu_fprintf(f, " ");
453 }
2c0262af
FB
454 }
455}
456
457/***********************************************************/
458/* x86 mmu */
459/* XXX: add PGE support */
460
461c0471
FB
461void cpu_x86_set_a20(CPUX86State *env, int a20_state)
462{
463 a20_state = (a20_state != 0);
1ac157da 464 if (a20_state != ((env->a20_mask >> 20) & 1)) {
b7f0f463
FB
465#if defined(DEBUG_MMU)
466 printf("A20 update: a20=%d\n", a20_state);
467#endif
6bb70571
FB
468 /* if the cpu is currently executing code, we must unlink it and
469 all the potentially executing TB */
0e4b179d 470 cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
6bb70571 471
461c0471
FB
472 /* when a20 is changed, all the MMU mappings are invalid, so
473 we must flush everything */
1ac157da
FB
474 tlb_flush(env, 1);
475 env->a20_mask = 0xffefffff | (a20_state << 20);
461c0471
FB
476 }
477}
478
1ac157da 479void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
2c0262af 480{
1ac157da 481 int pe_state;
2c0262af 482
b7f0f463 483#if defined(DEBUG_MMU)
1ac157da 484 printf("CR0 update: CR0=0x%08x\n", new_cr0);
2c0262af 485#endif
1ac157da
FB
486 if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
487 (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
488 tlb_flush(env, 1);
2c0262af 489 }
14ce26e7
FB
490
491#ifdef TARGET_X86_64
492 if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
493 (env->efer & MSR_EFER_LME)) {
494 /* enter in long mode */
495 /* XXX: generate an exception */
496 if (!(env->cr[4] & CR4_PAE_MASK))
497 return;
498 env->efer |= MSR_EFER_LMA;
499 env->hflags |= HF_LMA_MASK;
500 } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
501 (env->efer & MSR_EFER_LMA)) {
502 /* exit long mode */
503 env->efer &= ~MSR_EFER_LMA;
504 env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
505 env->eip &= 0xffffffff;
506 }
507#endif
28c3ee3f 508 env->cr[0] = new_cr0 | CR0_ET_MASK;
1ac157da 509
436d8b89
FB
510 /* update PE flag in hidden flags */
511 pe_state = (env->cr[0] & CR0_PE_MASK);
512 env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
513 /* ensure that ADDSEG is always set in real mode */
514 env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
9588b95a
FB
515 /* update FPU flags */
516 env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
517 ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
2c0262af
FB
518}
519
bf079a1e
FB
520/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
521 the PDPT */
14ce26e7 522void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
2c0262af 523{
1ac157da 524 env->cr[3] = new_cr3;
2c0262af
FB
525 if (env->cr[0] & CR0_PG_MASK) {
526#if defined(DEBUG_MMU)
14ce26e7 527 printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
2c0262af 528#endif
1ac157da 529 tlb_flush(env, 0);
2c0262af
FB
530 }
531}
532
1ac157da 533void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
2c0262af 534{
1ac157da 535#if defined(DEBUG_MMU)
14ce26e7 536 printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
1ac157da
FB
537#endif
538 if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
539 (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
540 tlb_flush(env, 1);
541 }
664e0f19
FB
542 /* SSE handling */
543 if (!(env->cpuid_features & CPUID_SSE))
544 new_cr4 &= ~CR4_OSFXSR_MASK;
545 if (new_cr4 & CR4_OSFXSR_MASK)
546 env->hflags |= HF_OSFXSR_MASK;
547 else
548 env->hflags &= ~HF_OSFXSR_MASK;
549
1ac157da 550 env->cr[4] = new_cr4;
2c0262af
FB
551}
552
553/* XXX: also flush 4MB pages */
8f091a59 554void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
2c0262af 555{
2c0262af 556 tlb_flush_page(env, addr);
2c0262af
FB
557}
558
8df1cd07 559#if defined(CONFIG_USER_ONLY)
14ce26e7 560
8df1cd07
FB
561int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
562 int is_write, int is_user, int is_softmmu)
14ce26e7 563{
8df1cd07
FB
564 /* user mode only emulation */
565 is_write &= 1;
566 env->cr[2] = addr;
567 env->error_code = (is_write << PG_ERROR_W_BIT);
568 env->error_code |= PG_ERROR_U_MASK;
569 return 1;
14ce26e7
FB
570}
571
8df1cd07 572target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
14ce26e7 573{
8df1cd07 574 return addr;
14ce26e7
FB
575}
576
8df1cd07
FB
577#else
578
4b4f782c
FB
579#define PHYS_ADDR_MASK 0xfffff000
580
2c0262af
FB
581/* return value:
582 -1 = cannot handle fault
583 0 = nothing more to do
584 1 = generate PF fault
585 2 = soft MMU activation required for this block
586*/
14ce26e7 587int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
4b4f782c 588 int is_write1, int is_user, int is_softmmu)
2c0262af 589{
4b4f782c 590 uint64_t ptep, pte;
14ce26e7 591 uint32_t pdpe_addr, pde_addr, pte_addr;
4b4f782c 592 int error_code, is_dirty, prot, page_size, ret, is_write;
14ce26e7
FB
593 unsigned long paddr, page_offset;
594 target_ulong vaddr, virt_addr;
2c0262af 595
436d8b89 596#if defined(DEBUG_MMU)
14ce26e7 597 printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
4b4f782c 598 addr, is_write1, is_user, env->eip);
2c0262af 599#endif
4b4f782c 600 is_write = is_write1 & 1;
b769d8fe 601
2c0262af
FB
602 if (!(env->cr[0] & CR0_PG_MASK)) {
603 pte = addr;
461c0471 604 virt_addr = addr & TARGET_PAGE_MASK;
4b4f782c 605 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
2c0262af
FB
606 page_size = 4096;
607 goto do_mapping;
608 }
609
14ce26e7 610 if (env->cr[4] & CR4_PAE_MASK) {
4b4f782c
FB
611 uint64_t pde, pdpe;
612
14ce26e7
FB
613 /* XXX: we only use 32 bit physical addresses */
614#ifdef TARGET_X86_64
615 if (env->hflags & HF_LMA_MASK) {
4b4f782c
FB
616 uint32_t pml4e_addr;
617 uint64_t pml4e;
14ce26e7
FB
618 int32_t sext;
619
14ce26e7
FB
620 /* test virtual address sign extension */
621 sext = (int64_t)addr >> 47;
622 if (sext != 0 && sext != -1) {
623 error_code = 0;
624 goto do_fault;
625 }
626
627 pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
628 env->a20_mask;
4b4f782c 629 pml4e = ldq_phys(pml4e_addr);
14ce26e7
FB
630 if (!(pml4e & PG_PRESENT_MASK)) {
631 error_code = 0;
632 goto do_fault;
633 }
4b4f782c
FB
634 if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
635 error_code = PG_ERROR_RSVD_MASK;
636 goto do_fault;
637 }
14ce26e7
FB
638 if (!(pml4e & PG_ACCESSED_MASK)) {
639 pml4e |= PG_ACCESSED_MASK;
8df1cd07 640 stl_phys_notdirty(pml4e_addr, pml4e);
14ce26e7 641 }
4b4f782c
FB
642 ptep = pml4e ^ PG_NX_MASK;
643 pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
14ce26e7 644 env->a20_mask;
4b4f782c 645 pdpe = ldq_phys(pdpe_addr);
14ce26e7
FB
646 if (!(pdpe & PG_PRESENT_MASK)) {
647 error_code = 0;
648 goto do_fault;
649 }
4b4f782c
FB
650 if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
651 error_code = PG_ERROR_RSVD_MASK;
652 goto do_fault;
653 }
654 ptep &= pdpe ^ PG_NX_MASK;
14ce26e7
FB
655 if (!(pdpe & PG_ACCESSED_MASK)) {
656 pdpe |= PG_ACCESSED_MASK;
8df1cd07 657 stl_phys_notdirty(pdpe_addr, pdpe);
14ce26e7 658 }
4b4f782c 659 } else
14ce26e7
FB
660#endif
661 {
4b4f782c 662 /* XXX: load them when cr3 is loaded ? */
14ce26e7
FB
663 pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
664 env->a20_mask;
4b4f782c 665 pdpe = ldq_phys(pdpe_addr);
14ce26e7
FB
666 if (!(pdpe & PG_PRESENT_MASK)) {
667 error_code = 0;
668 goto do_fault;
669 }
4b4f782c 670 ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
10f0e412 671 }
14ce26e7 672
4b4f782c 673 pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
14ce26e7 674 env->a20_mask;
4b4f782c 675 pde = ldq_phys(pde_addr);
14ce26e7
FB
676 if (!(pde & PG_PRESENT_MASK)) {
677 error_code = 0;
678 goto do_fault;
2c0262af 679 }
4b4f782c
FB
680 if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
681 error_code = PG_ERROR_RSVD_MASK;
682 goto do_fault;
683 }
684 ptep &= pde ^ PG_NX_MASK;
14ce26e7
FB
685 if (pde & PG_PSE_MASK) {
686 /* 2 MB page */
687 page_size = 2048 * 1024;
4b4f782c
FB
688 ptep ^= PG_NX_MASK;
689 if ((ptep & PG_NX_MASK) && is_write1 == 2)
690 goto do_fault_protect;
691 if (is_user) {
692 if (!(ptep & PG_USER_MASK))
693 goto do_fault_protect;
694 if (is_write && !(ptep & PG_RW_MASK))
695 goto do_fault_protect;
696 } else {
697 if ((env->cr[0] & CR0_WP_MASK) &&
698 is_write && !(ptep & PG_RW_MASK))
699 goto do_fault_protect;
700 }
701 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
702 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
703 pde |= PG_ACCESSED_MASK;
704 if (is_dirty)
705 pde |= PG_DIRTY_MASK;
706 stl_phys_notdirty(pde_addr, pde);
707 }
708 /* align to page_size */
709 pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
710 virt_addr = addr & ~(page_size - 1);
14ce26e7
FB
711 } else {
712 /* 4 KB page */
713 if (!(pde & PG_ACCESSED_MASK)) {
714 pde |= PG_ACCESSED_MASK;
8df1cd07 715 stl_phys_notdirty(pde_addr, pde);
14ce26e7 716 }
4b4f782c 717 pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
14ce26e7 718 env->a20_mask;
4b4f782c
FB
719 pte = ldq_phys(pte_addr);
720 if (!(pte & PG_PRESENT_MASK)) {
721 error_code = 0;
722 goto do_fault;
723 }
724 if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
725 error_code = PG_ERROR_RSVD_MASK;
726 goto do_fault;
727 }
728 /* combine pde and pte nx, user and rw protections */
729 ptep &= pte ^ PG_NX_MASK;
730 ptep ^= PG_NX_MASK;
731 if ((ptep & PG_NX_MASK) && is_write1 == 2)
732 goto do_fault_protect;
733 if (is_user) {
734 if (!(ptep & PG_USER_MASK))
735 goto do_fault_protect;
736 if (is_write && !(ptep & PG_RW_MASK))
737 goto do_fault_protect;
738 } else {
739 if ((env->cr[0] & CR0_WP_MASK) &&
740 is_write && !(ptep & PG_RW_MASK))
741 goto do_fault_protect;
742 }
743 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
744 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
745 pte |= PG_ACCESSED_MASK;
746 if (is_dirty)
747 pte |= PG_DIRTY_MASK;
748 stl_phys_notdirty(pte_addr, pte);
749 }
750 page_size = 4096;
751 virt_addr = addr & ~0xfff;
752 pte = pte & (PHYS_ADDR_MASK | 0xfff);
2c0262af 753 }
14ce26e7 754 } else {
4b4f782c
FB
755 uint32_t pde;
756
2c0262af 757 /* page directory entry */
14ce26e7
FB
758 pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &
759 env->a20_mask;
8df1cd07 760 pde = ldl_phys(pde_addr);
14ce26e7 761 if (!(pde & PG_PRESENT_MASK)) {
2c0262af
FB
762 error_code = 0;
763 goto do_fault;
764 }
14ce26e7
FB
765 /* if PSE bit is set, then we use a 4MB page */
766 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
767 page_size = 4096 * 1024;
14ce26e7
FB
768 if (is_user) {
769 if (!(pde & PG_USER_MASK))
770 goto do_fault_protect;
771 if (is_write && !(pde & PG_RW_MASK))
772 goto do_fault_protect;
773 } else {
774 if ((env->cr[0] & CR0_WP_MASK) &&
775 is_write && !(pde & PG_RW_MASK))
776 goto do_fault_protect;
777 }
778 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
779 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
780 pde |= PG_ACCESSED_MASK;
781 if (is_dirty)
782 pde |= PG_DIRTY_MASK;
8df1cd07 783 stl_phys_notdirty(pde_addr, pde);
14ce26e7
FB
784 }
785
786 pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
787 ptep = pte;
788 virt_addr = addr & ~(page_size - 1);
2c0262af 789 } else {
14ce26e7
FB
790 if (!(pde & PG_ACCESSED_MASK)) {
791 pde |= PG_ACCESSED_MASK;
8df1cd07 792 stl_phys_notdirty(pde_addr, pde);
14ce26e7
FB
793 }
794
795 /* page directory entry */
796 pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
797 env->a20_mask;
8df1cd07 798 pte = ldl_phys(pte_addr);
14ce26e7
FB
799 if (!(pte & PG_PRESENT_MASK)) {
800 error_code = 0;
801 goto do_fault;
802 }
803 /* combine pde and pte user and rw protections */
804 ptep = pte & pde;
805 if (is_user) {
806 if (!(ptep & PG_USER_MASK))
807 goto do_fault_protect;
808 if (is_write && !(ptep & PG_RW_MASK))
809 goto do_fault_protect;
810 } else {
811 if ((env->cr[0] & CR0_WP_MASK) &&
812 is_write && !(ptep & PG_RW_MASK))
813 goto do_fault_protect;
814 }
815 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
816 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
817 pte |= PG_ACCESSED_MASK;
818 if (is_dirty)
819 pte |= PG_DIRTY_MASK;
8df1cd07 820 stl_phys_notdirty(pte_addr, pte);
14ce26e7
FB
821 }
822 page_size = 4096;
823 virt_addr = addr & ~0xfff;
2c0262af 824 }
4b4f782c
FB
825 }
826 /* the page can be put in the TLB */
827 prot = PAGE_READ;
828 if (!(ptep & PG_NX_MASK))
829 prot |= PAGE_EXEC;
830 if (pte & PG_DIRTY_MASK) {
831 /* only set write access if already dirty... otherwise wait
832 for dirty access */
833 if (is_user) {
834 if (ptep & PG_RW_MASK)
835 prot |= PAGE_WRITE;
836 } else {
837 if (!(env->cr[0] & CR0_WP_MASK) ||
838 (ptep & PG_RW_MASK))
839 prot |= PAGE_WRITE;
c8135d9a 840 }
2c0262af 841 }
2c0262af 842 do_mapping:
1ac157da 843 pte = pte & env->a20_mask;
2c0262af 844
436d8b89
FB
845 /* Even if 4MB pages, we map only one 4KB page in the cache to
846 avoid filling it too fast */
847 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
848 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
849 vaddr = virt_addr + page_offset;
850
4b4f782c 851 ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
2c0262af
FB
852 return ret;
853 do_fault_protect:
854 error_code = PG_ERROR_P_MASK;
855 do_fault:
856 env->cr[2] = addr;
4b4f782c 857 error_code |= (is_write << PG_ERROR_W_BIT);
2c0262af 858 if (is_user)
4b4f782c
FB
859 error_code |= PG_ERROR_U_MASK;
860 if (is_write1 == 2 &&
861 (env->efer & MSR_EFER_NXE) &&
862 (env->cr[4] & CR4_PAE_MASK))
863 error_code |= PG_ERROR_I_D_MASK;
864 env->error_code = error_code;
2c0262af
FB
865 return 1;
866}
10f0e412 867
10f0e412
FB
868target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
869{
f51589da 870 uint32_t pde_addr, pte_addr;
10f0e412
FB
871 uint32_t pde, pte, paddr, page_offset, page_size;
872
f51589da
FB
873 if (env->cr[4] & CR4_PAE_MASK) {
874 uint32_t pdpe_addr, pde_addr, pte_addr;
875 uint32_t pdpe;
876
877 /* XXX: we only use 32 bit physical addresses */
878#ifdef TARGET_X86_64
879 if (env->hflags & HF_LMA_MASK) {
880 uint32_t pml4e_addr, pml4e;
881 int32_t sext;
882
883 /* test virtual address sign extension */
884 sext = (int64_t)addr >> 47;
885 if (sext != 0 && sext != -1)
886 return -1;
887
888 pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
889 env->a20_mask;
8df1cd07 890 pml4e = ldl_phys(pml4e_addr);
f51589da
FB
891 if (!(pml4e & PG_PRESENT_MASK))
892 return -1;
893
894 pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
895 env->a20_mask;
8df1cd07 896 pdpe = ldl_phys(pdpe_addr);
f51589da
FB
897 if (!(pdpe & PG_PRESENT_MASK))
898 return -1;
899 } else
900#endif
901 {
902 pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
903 env->a20_mask;
8df1cd07 904 pdpe = ldl_phys(pdpe_addr);
f51589da
FB
905 if (!(pdpe & PG_PRESENT_MASK))
906 return -1;
907 }
908
909 pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
910 env->a20_mask;
8df1cd07 911 pde = ldl_phys(pde_addr);
f51589da 912 if (!(pde & PG_PRESENT_MASK)) {
10f0e412 913 return -1;
f51589da
FB
914 }
915 if (pde & PG_PSE_MASK) {
916 /* 2 MB page */
917 page_size = 2048 * 1024;
918 pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
919 } else {
920 /* 4 KB page */
921 pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
922 env->a20_mask;
923 page_size = 4096;
8df1cd07 924 pte = ldl_phys(pte_addr);
f51589da
FB
925 }
926 } else {
927 if (!(env->cr[0] & CR0_PG_MASK)) {
928 pte = addr;
929 page_size = 4096;
10f0e412
FB
930 } else {
931 /* page directory entry */
f51589da 932 pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask;
8df1cd07 933 pde = ldl_phys(pde_addr);
f51589da 934 if (!(pde & PG_PRESENT_MASK))
10f0e412 935 return -1;
f51589da
FB
936 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
937 pte = pde & ~0x003ff000; /* align to 4MB */
938 page_size = 4096 * 1024;
939 } else {
940 /* page directory entry */
941 pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
8df1cd07 942 pte = ldl_phys(pte_addr);
f51589da
FB
943 if (!(pte & PG_PRESENT_MASK))
944 return -1;
945 page_size = 4096;
946 }
10f0e412 947 }
f51589da 948 pte = pte & env->a20_mask;
10f0e412 949 }
f51589da 950
10f0e412
FB
951 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
952 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
953 return paddr;
954}
8df1cd07 955#endif /* !CONFIG_USER_ONLY */
9588b95a
FB
956
957#if defined(USE_CODE_COPY)
958struct fpstate {
959 uint16_t fpuc;
960 uint16_t dummy1;
961 uint16_t fpus;
962 uint16_t dummy2;
963 uint16_t fptag;
964 uint16_t dummy3;
965
966 uint32_t fpip;
967 uint32_t fpcs;
968 uint32_t fpoo;
969 uint32_t fpos;
970 uint8_t fpregs1[8 * 10];
971};
972
973void restore_native_fp_state(CPUState *env)
974{
975 int fptag, i, j;
976 struct fpstate fp1, *fp = &fp1;
977
978 fp->fpuc = env->fpuc;
979 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
980 fptag = 0;
981 for (i=7; i>=0; i--) {
982 fptag <<= 2;
983 if (env->fptags[i]) {
984 fptag |= 3;
985 } else {
986 /* the FPU automatically computes it */
987 }
988 }
989 fp->fptag = fptag;
990 j = env->fpstt;
991 for(i = 0;i < 8; i++) {
664e0f19 992 memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
9588b95a
FB
993 j = (j + 1) & 7;
994 }
995 asm volatile ("frstor %0" : "=m" (*fp));
996 env->native_fp_regs = 1;
997}
998
999void save_native_fp_state(CPUState *env)
1000{
1001 int fptag, i, j;
1002 uint16_t fpuc;
1003 struct fpstate fp1, *fp = &fp1;
1004
1005 asm volatile ("fsave %0" : : "m" (*fp));
1006 env->fpuc = fp->fpuc;
1007 env->fpstt = (fp->fpus >> 11) & 7;
1008 env->fpus = fp->fpus & ~0x3800;
1009 fptag = fp->fptag;
1010 for(i = 0;i < 8; i++) {
1011 env->fptags[i] = ((fptag & 3) == 3);
1012 fptag >>= 2;
1013 }
1014 j = env->fpstt;
1015 for(i = 0;i < 8; i++) {
664e0f19 1016 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
9588b95a
FB
1017 j = (j + 1) & 7;
1018 }
1019 /* we must restore the default rounding state */
1020 /* XXX: we do not restore the exception state */
1021 fpuc = 0x037f | (env->fpuc & (3 << 10));
1022 asm volatile("fldcw %0" : : "m" (fpuc));
1023 env->native_fp_regs = 0;
1024}
1025#endif
This page took 0.236785 seconds and 4 git commands to generate.