]> git.proxmox.com Git - mirror_qemu.git/blame - target-i386/helper2.c
win32 port (initial patch by kazu)
[mirror_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;
48 int i;
49 static int inited;
50
51 cpu_exec_init();
52
53 env = malloc(sizeof(CPUX86State));
54 if (!env)
55 return NULL;
56 memset(env, 0, sizeof(CPUX86State));
2c0262af 57
1ac157da
FB
58 /* init to reset state */
59
60 tlb_flush(env, 1);
2c0262af
FB
61#ifdef CONFIG_SOFTMMU
62 env->hflags |= HF_SOFTMMU_MASK;
63#endif
1ac157da
FB
64
65 cpu_x86_update_cr0(env, 0x60000010);
66 env->a20_mask = 0xffffffff;
67
68 env->idt.limit = 0xffff;
69 env->gdt.limit = 0xffff;
70 env->ldt.limit = 0xffff;
71 env->ldt.flags = DESC_P_MASK;
72 env->tr.limit = 0xffff;
73 env->tr.flags = DESC_P_MASK;
74
75 /* not correct (CS base=0xffff0000) */
76 cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0);
77 cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
78 cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
79 cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
80 cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
81 cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
82
83 env->eip = 0xfff0;
84 env->regs[R_EDX] = 0x600; /* indicate P6 processor */
85
86 env->eflags = 0x2;
87
88 /* FPU init */
89 for(i = 0;i < 8; i++)
90 env->fptags[i] = 1;
91 env->fpuc = 0x37f;
92
2c0262af
FB
93 /* init various static tables */
94 if (!inited) {
95 inited = 1;
96 optimize_flags_init();
97 }
0e4b179d
FB
98#ifdef USE_CODE_COPY
99 /* testing code for code copy case */
100 {
101 struct modify_ldt_ldt_s ldt;
102
103 ldt.entry_number = 1;
104 ldt.base_addr = (unsigned long)env;
105 ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
106 ldt.seg_32bit = 1;
107 ldt.contents = MODIFY_LDT_CONTENTS_DATA;
108 ldt.read_exec_only = 0;
109 ldt.limit_in_pages = 1;
110 ldt.seg_not_present = 0;
111 ldt.useable = 1;
112 modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
113
114 asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
115 cpu_single_env = env;
116 }
117#endif
2c0262af
FB
118 return env;
119}
120
121void cpu_x86_close(CPUX86State *env)
122{
123 free(env);
124}
125
126/***********************************************************/
127/* x86 debug */
128
129static const char *cc_op_str[] = {
130 "DYNAMIC",
131 "EFLAGS",
b7f0f463
FB
132 "MULB",
133 "MULW",
134 "MULL",
2c0262af
FB
135 "ADDB",
136 "ADDW",
137 "ADDL",
138 "ADCB",
139 "ADCW",
140 "ADCL",
141 "SUBB",
142 "SUBW",
143 "SUBL",
144 "SBBB",
145 "SBBW",
146 "SBBL",
147 "LOGICB",
148 "LOGICW",
149 "LOGICL",
150 "INCB",
151 "INCW",
152 "INCL",
153 "DECB",
154 "DECW",
155 "DECL",
156 "SHLB",
157 "SHLW",
158 "SHLL",
159 "SARB",
160 "SARW",
161 "SARL",
162};
163
164void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
165{
246d897f 166 int eflags, i;
2c0262af 167 char cc_op_name[32];
246d897f 168 static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
2c0262af
FB
169
170 eflags = env->eflags;
171 fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
172 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
5e809a80 173 "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d\n",
2c0262af
FB
174 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
175 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
176 env->eip, eflags,
177 eflags & DF_MASK ? 'D' : '-',
178 eflags & CC_O ? 'O' : '-',
179 eflags & CC_S ? 'S' : '-',
180 eflags & CC_Z ? 'Z' : '-',
181 eflags & CC_A ? 'A' : '-',
182 eflags & CC_P ? 'P' : '-',
246d897f 183 eflags & CC_C ? 'C' : '-',
5e809a80
FB
184 env->hflags & HF_CPL_MASK,
185 (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
246d897f
FB
186 for(i = 0; i < 6; i++) {
187 SegmentCache *sc = &env->segs[i];
188 fprintf(f, "%s =%04x %08x %08x %08x\n",
189 seg_name[i],
190 sc->selector,
191 (int)sc->base,
192 sc->limit,
193 sc->flags);
194 }
195 fprintf(f, "LDT=%04x %08x %08x %08x\n",
196 env->ldt.selector,
197 (int)env->ldt.base,
198 env->ldt.limit,
199 env->ldt.flags);
200 fprintf(f, "TR =%04x %08x %08x %08x\n",
201 env->tr.selector,
202 (int)env->tr.base,
203 env->tr.limit,
204 env->tr.flags);
205 fprintf(f, "GDT= %08x %08x\n",
206 (int)env->gdt.base, env->gdt.limit);
207 fprintf(f, "IDT= %08x %08x\n",
208 (int)env->idt.base, env->idt.limit);
209 fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
210 env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
211
2c0262af
FB
212 if (flags & X86_DUMP_CCOP) {
213 if ((unsigned)env->cc_op < CC_OP_NB)
214 strcpy(cc_op_name, cc_op_str[env->cc_op]);
215 else
216 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
217 fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
218 env->cc_src, env->cc_dst, cc_op_name);
219 }
220 if (flags & X86_DUMP_FPU) {
221 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
222 (double)env->fpregs[0],
223 (double)env->fpregs[1],
224 (double)env->fpregs[2],
225 (double)env->fpregs[3]);
226 fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
227 (double)env->fpregs[4],
228 (double)env->fpregs[5],
229 (double)env->fpregs[7],
230 (double)env->fpregs[8]);
231 }
232}
233
234/***********************************************************/
235/* x86 mmu */
236/* XXX: add PGE support */
237
461c0471
FB
238void cpu_x86_set_a20(CPUX86State *env, int a20_state)
239{
240 a20_state = (a20_state != 0);
1ac157da 241 if (a20_state != ((env->a20_mask >> 20) & 1)) {
b7f0f463
FB
242#if defined(DEBUG_MMU)
243 printf("A20 update: a20=%d\n", a20_state);
244#endif
6bb70571
FB
245 /* if the cpu is currently executing code, we must unlink it and
246 all the potentially executing TB */
0e4b179d 247 cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
6bb70571 248
461c0471
FB
249 /* when a20 is changed, all the MMU mappings are invalid, so
250 we must flush everything */
1ac157da
FB
251 tlb_flush(env, 1);
252 env->a20_mask = 0xffefffff | (a20_state << 20);
461c0471
FB
253 }
254}
255
1ac157da 256void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
2c0262af 257{
1ac157da 258 int pe_state;
2c0262af 259
b7f0f463 260#if defined(DEBUG_MMU)
1ac157da 261 printf("CR0 update: CR0=0x%08x\n", new_cr0);
2c0262af 262#endif
1ac157da
FB
263 if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
264 (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
265 tlb_flush(env, 1);
2c0262af 266 }
1ac157da
FB
267 env->cr[0] = new_cr0;
268
436d8b89
FB
269 /* update PE flag in hidden flags */
270 pe_state = (env->cr[0] & CR0_PE_MASK);
271 env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
272 /* ensure that ADDSEG is always set in real mode */
273 env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
9588b95a
FB
274 /* update FPU flags */
275 env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
276 ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
2c0262af
FB
277}
278
1ac157da 279void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
2c0262af 280{
1ac157da 281 env->cr[3] = new_cr3;
2c0262af
FB
282 if (env->cr[0] & CR0_PG_MASK) {
283#if defined(DEBUG_MMU)
1ac157da 284 printf("CR3 update: CR3=%08x\n", new_cr3);
2c0262af 285#endif
1ac157da 286 tlb_flush(env, 0);
2c0262af
FB
287 }
288}
289
1ac157da 290void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
2c0262af 291{
1ac157da
FB
292#if defined(DEBUG_MMU)
293 printf("CR4 update: CR4=%08x\n", env->cr[4]);
294#endif
295 if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
296 (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
297 tlb_flush(env, 1);
298 }
299 env->cr[4] = new_cr4;
2c0262af
FB
300}
301
302/* XXX: also flush 4MB pages */
303void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
304{
2c0262af 305 tlb_flush_page(env, addr);
2c0262af
FB
306}
307
308/* return value:
309 -1 = cannot handle fault
310 0 = nothing more to do
311 1 = generate PF fault
312 2 = soft MMU activation required for this block
313*/
61382a50
FB
314int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
315 int is_write, int is_user, int is_softmmu)
2c0262af
FB
316{
317 uint8_t *pde_ptr, *pte_ptr;
10f0e412 318 uint32_t pde, pte, virt_addr, ptep;
61382a50 319 int error_code, is_dirty, prot, page_size, ret;
436d8b89 320 unsigned long paddr, vaddr, page_offset;
2c0262af 321
436d8b89 322#if defined(DEBUG_MMU)
2c0262af
FB
323 printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
324 addr, is_write, is_user, env->eip);
325#endif
326
327 if (env->user_mode_only) {
328 /* user mode only emulation */
329 error_code = 0;
330 goto do_fault;
331 }
332
333 if (!(env->cr[0] & CR0_PG_MASK)) {
334 pte = addr;
461c0471 335 virt_addr = addr & TARGET_PAGE_MASK;
67b915a5 336 prot = PAGE_READ | PAGE_WRITE;
2c0262af
FB
337 page_size = 4096;
338 goto do_mapping;
339 }
340
341 /* page directory entry */
461c0471 342 pde_ptr = phys_ram_base +
1ac157da 343 (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
61382a50 344 pde = ldl_raw(pde_ptr);
2c0262af
FB
345 if (!(pde & PG_PRESENT_MASK)) {
346 error_code = 0;
347 goto do_fault;
348 }
2c0262af
FB
349 /* if PSE bit is set, then we use a 4MB page */
350 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
10f0e412
FB
351 if (is_user) {
352 if (!(pde & PG_USER_MASK))
353 goto do_fault_protect;
354 if (is_write && !(pde & PG_RW_MASK))
355 goto do_fault_protect;
356 } else {
34f715e7 357 if ((env->cr[0] & CR0_WP_MASK) &&
10f0e412
FB
358 is_write && !(pde & PG_RW_MASK))
359 goto do_fault_protect;
360 }
2c0262af 361 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
777aca2f 362 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
2c0262af
FB
363 pde |= PG_ACCESSED_MASK;
364 if (is_dirty)
365 pde |= PG_DIRTY_MASK;
61382a50 366 stl_raw(pde_ptr, pde);
2c0262af
FB
367 }
368
369 pte = pde & ~0x003ff000; /* align to 4MB */
10f0e412 370 ptep = pte;
2c0262af
FB
371 page_size = 4096 * 1024;
372 virt_addr = addr & ~0x003fffff;
373 } else {
374 if (!(pde & PG_ACCESSED_MASK)) {
375 pde |= PG_ACCESSED_MASK;
61382a50 376 stl_raw(pde_ptr, pde);
2c0262af
FB
377 }
378
379 /* page directory entry */
461c0471 380 pte_ptr = phys_ram_base +
1ac157da 381 (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
61382a50 382 pte = ldl_raw(pte_ptr);
2c0262af
FB
383 if (!(pte & PG_PRESENT_MASK)) {
384 error_code = 0;
385 goto do_fault;
386 }
10f0e412
FB
387 /* combine pde and pte user and rw protections */
388 ptep = pte & pde;
2c0262af 389 if (is_user) {
10f0e412 390 if (!(ptep & PG_USER_MASK))
2c0262af 391 goto do_fault_protect;
10f0e412 392 if (is_write && !(ptep & PG_RW_MASK))
2c0262af
FB
393 goto do_fault_protect;
394 } else {
34f715e7 395 if ((env->cr[0] & CR0_WP_MASK) &&
10f0e412 396 is_write && !(ptep & PG_RW_MASK))
2c0262af
FB
397 goto do_fault_protect;
398 }
399 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
400 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
401 pte |= PG_ACCESSED_MASK;
402 if (is_dirty)
403 pte |= PG_DIRTY_MASK;
61382a50 404 stl_raw(pte_ptr, pte);
2c0262af
FB
405 }
406 page_size = 4096;
407 virt_addr = addr & ~0xfff;
408 }
c8135d9a 409
2c0262af 410 /* the page can be put in the TLB */
67b915a5 411 prot = PAGE_READ;
c8135d9a
FB
412 if (pte & PG_DIRTY_MASK) {
413 /* only set write access if already dirty... otherwise wait
414 for dirty access */
415 if (is_user) {
10f0e412 416 if (ptep & PG_RW_MASK)
67b915a5 417 prot |= PAGE_WRITE;
c8135d9a 418 } else {
34f715e7 419 if (!(env->cr[0] & CR0_WP_MASK) ||
10f0e412 420 (ptep & PG_RW_MASK))
67b915a5 421 prot |= PAGE_WRITE;
c8135d9a 422 }
2c0262af 423 }
777aca2f 424
2c0262af 425 do_mapping:
1ac157da 426 pte = pte & env->a20_mask;
2c0262af 427
436d8b89
FB
428 /* Even if 4MB pages, we map only one 4KB page in the cache to
429 avoid filling it too fast */
430 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
431 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
432 vaddr = virt_addr + page_offset;
433
434 ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
2c0262af
FB
435 return ret;
436 do_fault_protect:
437 error_code = PG_ERROR_P_MASK;
438 do_fault:
439 env->cr[2] = addr;
440 env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
441 if (is_user)
442 env->error_code |= PG_ERROR_U_MASK;
443 return 1;
444}
10f0e412
FB
445
446#if defined(CONFIG_USER_ONLY)
447target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
448{
449 return addr;
450}
451#else
452target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
453{
454 uint8_t *pde_ptr, *pte_ptr;
455 uint32_t pde, pte, paddr, page_offset, page_size;
456
457 if (!(env->cr[0] & CR0_PG_MASK)) {
458 pte = addr;
459 page_size = 4096;
460 } else {
461 /* page directory entry */
462 pde_ptr = phys_ram_base +
1ac157da 463 (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
10f0e412
FB
464 pde = ldl_raw(pde_ptr);
465 if (!(pde & PG_PRESENT_MASK))
466 return -1;
467 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
468 pte = pde & ~0x003ff000; /* align to 4MB */
469 page_size = 4096 * 1024;
470 } else {
471 /* page directory entry */
472 pte_ptr = phys_ram_base +
1ac157da 473 (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
10f0e412
FB
474 pte = ldl_raw(pte_ptr);
475 if (!(pte & PG_PRESENT_MASK))
476 return -1;
477 page_size = 4096;
478 }
479 }
1ac157da 480 pte = pte & env->a20_mask;
10f0e412
FB
481 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
482 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
483 return paddr;
484}
485#endif
9588b95a
FB
486
487#if defined(USE_CODE_COPY)
488struct fpstate {
489 uint16_t fpuc;
490 uint16_t dummy1;
491 uint16_t fpus;
492 uint16_t dummy2;
493 uint16_t fptag;
494 uint16_t dummy3;
495
496 uint32_t fpip;
497 uint32_t fpcs;
498 uint32_t fpoo;
499 uint32_t fpos;
500 uint8_t fpregs1[8 * 10];
501};
502
503void restore_native_fp_state(CPUState *env)
504{
505 int fptag, i, j;
506 struct fpstate fp1, *fp = &fp1;
507
508 fp->fpuc = env->fpuc;
509 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
510 fptag = 0;
511 for (i=7; i>=0; i--) {
512 fptag <<= 2;
513 if (env->fptags[i]) {
514 fptag |= 3;
515 } else {
516 /* the FPU automatically computes it */
517 }
518 }
519 fp->fptag = fptag;
520 j = env->fpstt;
521 for(i = 0;i < 8; i++) {
522 memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10);
523 j = (j + 1) & 7;
524 }
525 asm volatile ("frstor %0" : "=m" (*fp));
526 env->native_fp_regs = 1;
527}
528
529void save_native_fp_state(CPUState *env)
530{
531 int fptag, i, j;
532 uint16_t fpuc;
533 struct fpstate fp1, *fp = &fp1;
534
535 asm volatile ("fsave %0" : : "m" (*fp));
536 env->fpuc = fp->fpuc;
537 env->fpstt = (fp->fpus >> 11) & 7;
538 env->fpus = fp->fpus & ~0x3800;
539 fptag = fp->fptag;
540 for(i = 0;i < 8; i++) {
541 env->fptags[i] = ((fptag & 3) == 3);
542 fptag >>= 2;
543 }
544 j = env->fpstt;
545 for(i = 0;i < 8; i++) {
546 memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10);
547 j = (j + 1) & 7;
548 }
549 /* we must restore the default rounding state */
550 /* XXX: we do not restore the exception state */
551 fpuc = 0x037f | (env->fpuc & (3 << 10));
552 asm volatile("fldcw %0" : : "m" (fpuc));
553 env->native_fp_regs = 0;
554}
555#endif