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