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