VirtualBox

source: vbox/trunk/src/recompiler/new/target-i386/helper2.c@ 1

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette