0d5f439d1be3a463a99bd0c323f7d9d4d17c6233
[qemu] / target-i386 / helper2.c
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>
27
28 #include "cpu.h"
29 #include "exec-all.h"
30
31 //#define DEBUG_MMU
32
33 #ifdef USE_CODE_COPY
34 #include <asm/ldt.h>
35 #include <linux/unistd.h>
36 #include <linux/version.h>
37
38 _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
39
40 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
41 #define modify_ldt_ldt_s user_desc
42 #endif
43 #endif /* USE_CODE_COPY */
44
45 CPUX86State *cpu_x86_init(void)
46 {
47     CPUX86State *env;
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));
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;
65
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));
78     }
79 #endif
80     cpu_single_env = env;
81     cpu_reset(env);
82     return env;
83 }
84
85 /* NOTE: must be called outside the CPU execute loop */
86 void cpu_reset(CPUX86State *env)
87 {
88     int i;
89
90     memset(env, 0, offsetof(CPUX86State, breakpoints));
91
92     tlb_flush(env, 1);
93
94     /* init to reset state */
95
96 #ifdef CONFIG_SOFTMMU
97     env->hflags |= HF_SOFTMMU_MASK;
98 #endif
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     
110     cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0xffff0000, 0xffff, 0); 
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;
126 }
127
128 void cpu_x86_close(CPUX86State *env)
129 {
130     free(env);
131 }
132
133 /***********************************************************/
134 /* x86 debug */
135
136 static const char *cc_op_str[] = {
137     "DYNAMIC",
138     "EFLAGS",
139     "MULB",
140     "MULW",
141     "MULL",
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
171 void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
172 {
173     int eflags, i;
174     char cc_op_name[32];
175     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
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"
180             "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d A20=%d\n",
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' : '-',
190             eflags & CC_C ? 'C' : '-',
191             env->hflags & HF_CPL_MASK, 
192             (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
193             (env->a20_mask >> 20) & 1);
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     
220     if (flags & X86_DUMP_CCOP) {
221         if ((unsigned)env->cc_op < CC_OP_NB)
222             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
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
246 void cpu_x86_set_a20(CPUX86State *env, int a20_state)
247 {
248     a20_state = (a20_state != 0);
249     if (a20_state != ((env->a20_mask >> 20) & 1)) {
250 #if defined(DEBUG_MMU)
251         printf("A20 update: a20=%d\n", a20_state);
252 #endif
253         /* if the cpu is currently executing code, we must unlink it and
254            all the potentially executing TB */
255         cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
256
257         /* when a20 is changed, all the MMU mappings are invalid, so
258            we must flush everything */
259         tlb_flush(env, 1);
260         env->a20_mask = 0xffefffff | (a20_state << 20);
261     }
262 }
263
264 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
265 {
266     int pe_state;
267
268 #if defined(DEBUG_MMU)
269     printf("CR0 update: CR0=0x%08x\n", new_cr0);
270 #endif
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);
274     }
275     env->cr[0] = new_cr0 | CR0_ET_MASK;
276     
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);
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));
285 }
286
287 void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
288 {
289     env->cr[3] = new_cr3;
290     if (env->cr[0] & CR0_PG_MASK) {
291 #if defined(DEBUG_MMU)
292         printf("CR3 update: CR3=%08x\n", new_cr3);
293 #endif
294         tlb_flush(env, 0);
295     }
296 }
297
298 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
299 {
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;
308 }
309
310 /* XXX: also flush 4MB pages */
311 void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
312 {
313     tlb_flush_page(env, addr);
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 */
322 int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
323                              int is_write, int is_user, int is_softmmu)
324 {
325     uint8_t *pde_ptr, *pte_ptr;
326     uint32_t pde, pte, virt_addr, ptep;
327     int error_code, is_dirty, prot, page_size, ret;
328     unsigned long paddr, vaddr, page_offset;
329     
330 #if defined(DEBUG_MMU)
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     is_write &= 1;
335     
336     if (env->user_mode_only) {
337         /* user mode only emulation */
338         error_code = 0;
339         goto do_fault;
340     }
341
342     if (!(env->cr[0] & CR0_PG_MASK)) {
343         pte = addr;
344         virt_addr = addr & TARGET_PAGE_MASK;
345         prot = PAGE_READ | PAGE_WRITE;
346         page_size = 4096;
347         goto do_mapping;
348     }
349
350     /* page directory entry */
351     pde_ptr = phys_ram_base + 
352         (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
353     pde = ldl_raw(pde_ptr);
354     if (!(pde & PG_PRESENT_MASK)) {
355         error_code = 0;
356         goto do_fault;
357     }
358     /* if PSE bit is set, then we use a 4MB page */
359     if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
360         if (is_user) {
361             if (!(pde & PG_USER_MASK))
362                 goto do_fault_protect;
363             if (is_write && !(pde & PG_RW_MASK))
364                 goto do_fault_protect;
365         } else {
366             if ((env->cr[0] & CR0_WP_MASK) && 
367                 is_write && !(pde & PG_RW_MASK)) 
368                 goto do_fault_protect;
369         }
370         is_dirty = is_write && !(pde & PG_DIRTY_MASK);
371         if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
372             pde |= PG_ACCESSED_MASK;
373             if (is_dirty)
374                 pde |= PG_DIRTY_MASK;
375             stl_raw(pde_ptr, pde);
376         }
377         
378         pte = pde & ~0x003ff000; /* align to 4MB */
379         ptep = pte;
380         page_size = 4096 * 1024;
381         virt_addr = addr & ~0x003fffff;
382     } else {
383         if (!(pde & PG_ACCESSED_MASK)) {
384             pde |= PG_ACCESSED_MASK;
385             stl_raw(pde_ptr, pde);
386         }
387
388         /* page directory entry */
389         pte_ptr = phys_ram_base + 
390             (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
391         pte = ldl_raw(pte_ptr);
392         if (!(pte & PG_PRESENT_MASK)) {
393             error_code = 0;
394             goto do_fault;
395         }
396         /* combine pde and pte user and rw protections */
397         ptep = pte & pde;
398         if (is_user) {
399             if (!(ptep & PG_USER_MASK))
400                 goto do_fault_protect;
401             if (is_write && !(ptep & PG_RW_MASK))
402                 goto do_fault_protect;
403         } else {
404             if ((env->cr[0] & CR0_WP_MASK) &&
405                 is_write && !(ptep & PG_RW_MASK)) 
406                 goto do_fault_protect;
407         }
408         is_dirty = is_write && !(pte & PG_DIRTY_MASK);
409         if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
410             pte |= PG_ACCESSED_MASK;
411             if (is_dirty)
412                 pte |= PG_DIRTY_MASK;
413             stl_raw(pte_ptr, pte);
414         }
415         page_size = 4096;
416         virt_addr = addr & ~0xfff;
417     }
418
419     /* the page can be put in the TLB */
420     prot = PAGE_READ;
421     if (pte & PG_DIRTY_MASK) {
422         /* only set write access if already dirty... otherwise wait
423            for dirty access */
424         if (is_user) {
425             if (ptep & PG_RW_MASK)
426                 prot |= PAGE_WRITE;
427         } else {
428             if (!(env->cr[0] & CR0_WP_MASK) ||
429                 (ptep & PG_RW_MASK))
430                 prot |= PAGE_WRITE;
431         }
432     }
433
434  do_mapping:
435     pte = pte & env->a20_mask;
436
437     /* Even if 4MB pages, we map only one 4KB page in the cache to
438        avoid filling it too fast */
439     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
440     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
441     vaddr = virt_addr + page_offset;
442     
443     ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
444     return ret;
445  do_fault_protect:
446     error_code = PG_ERROR_P_MASK;
447  do_fault:
448     env->cr[2] = addr;
449     env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
450     if (is_user)
451         env->error_code |= PG_ERROR_U_MASK;
452     return 1;
453 }
454
455 #if defined(CONFIG_USER_ONLY) 
456 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
457 {
458     return addr;
459 }
460 #else
461 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
462 {
463     uint8_t *pde_ptr, *pte_ptr;
464     uint32_t pde, pte, paddr, page_offset, page_size;
465
466     if (!(env->cr[0] & CR0_PG_MASK)) {
467         pte = addr;
468         page_size = 4096;
469     } else {
470         /* page directory entry */
471         pde_ptr = phys_ram_base + 
472             (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
473         pde = ldl_raw(pde_ptr);
474         if (!(pde & PG_PRESENT_MASK)) 
475             return -1;
476         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
477             pte = pde & ~0x003ff000; /* align to 4MB */
478             page_size = 4096 * 1024;
479         } else {
480             /* page directory entry */
481             pte_ptr = phys_ram_base + 
482                 (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
483             pte = ldl_raw(pte_ptr);
484             if (!(pte & PG_PRESENT_MASK))
485                 return -1;
486             page_size = 4096;
487         }
488     }
489     pte = pte & env->a20_mask;
490     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
491     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
492     return paddr;
493 }
494 #endif
495
496 #if defined(USE_CODE_COPY)
497 struct fpstate {
498     uint16_t fpuc;
499     uint16_t dummy1;
500     uint16_t fpus;
501     uint16_t dummy2;
502     uint16_t fptag;
503     uint16_t dummy3;
504
505     uint32_t fpip;
506     uint32_t fpcs;
507     uint32_t fpoo;
508     uint32_t fpos;
509     uint8_t fpregs1[8 * 10];
510 };
511
512 void restore_native_fp_state(CPUState *env)
513 {
514     int fptag, i, j;
515     struct fpstate fp1, *fp = &fp1;
516     
517     fp->fpuc = env->fpuc;
518     fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
519     fptag = 0;
520     for (i=7; i>=0; i--) {
521         fptag <<= 2;
522         if (env->fptags[i]) {
523             fptag |= 3;
524         } else {
525             /* the FPU automatically computes it */
526         }
527     }
528     fp->fptag = fptag;
529     j = env->fpstt;
530     for(i = 0;i < 8; i++) {
531         memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10);
532         j = (j + 1) & 7;
533     }
534     asm volatile ("frstor %0" : "=m" (*fp));
535     env->native_fp_regs = 1;
536 }
537  
538 void save_native_fp_state(CPUState *env)
539 {
540     int fptag, i, j;
541     uint16_t fpuc;
542     struct fpstate fp1, *fp = &fp1;
543
544     asm volatile ("fsave %0" : : "m" (*fp));
545     env->fpuc = fp->fpuc;
546     env->fpstt = (fp->fpus >> 11) & 7;
547     env->fpus = fp->fpus & ~0x3800;
548     fptag = fp->fptag;
549     for(i = 0;i < 8; i++) {
550         env->fptags[i] = ((fptag & 3) == 3);
551         fptag >>= 2;
552     }
553     j = env->fpstt;
554     for(i = 0;i < 8; i++) {
555         memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10);
556         j = (j + 1) & 7;
557     }
558     /* we must restore the default rounding state */
559     /* XXX: we do not restore the exception state */
560     fpuc = 0x037f | (env->fpuc & (3 << 10));
561     asm volatile("fldcw %0" : : "m" (fpuc));
562     env->native_fp_regs = 0;
563 }
564 #endif