combine PDE and PTE protections as in intel specs - added cpu_get_phys_page_debug()
[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 #include <sys/mman.h>
28
29 #include "cpu.h"
30 #include "exec-all.h"
31
32 //#define DEBUG_MMU
33
34 CPUX86State *cpu_x86_init(void)
35 {
36     CPUX86State *env;
37     int i;
38     static int inited;
39
40     cpu_exec_init();
41
42     env = malloc(sizeof(CPUX86State));
43     if (!env)
44         return NULL;
45     memset(env, 0, sizeof(CPUX86State));
46     /* basic FPU init */
47     for(i = 0;i < 8; i++)
48         env->fptags[i] = 1;
49     env->fpuc = 0x37f;
50     /* flags setup : we activate the IRQs by default as in user mode */
51     env->eflags = 0x2 | IF_MASK;
52
53     tlb_flush(env);
54 #ifdef CONFIG_SOFTMMU
55     env->hflags |= HF_SOFTMMU_MASK;
56 #endif
57     /* init various static tables */
58     if (!inited) {
59         inited = 1;
60         optimize_flags_init();
61     }
62     return env;
63 }
64
65 void cpu_x86_close(CPUX86State *env)
66 {
67     free(env);
68 }
69
70 /***********************************************************/
71 /* x86 debug */
72
73 static const char *cc_op_str[] = {
74     "DYNAMIC",
75     "EFLAGS",
76     "MULB",
77     "MULW",
78     "MULL",
79     "ADDB",
80     "ADDW",
81     "ADDL",
82     "ADCB",
83     "ADCW",
84     "ADCL",
85     "SUBB",
86     "SUBW",
87     "SUBL",
88     "SBBB",
89     "SBBW",
90     "SBBL",
91     "LOGICB",
92     "LOGICW",
93     "LOGICL",
94     "INCB",
95     "INCW",
96     "INCL",
97     "DECB",
98     "DECW",
99     "DECL",
100     "SHLB",
101     "SHLW",
102     "SHLL",
103     "SARB",
104     "SARW",
105     "SARL",
106 };
107
108 void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
109 {
110     int eflags, i;
111     char cc_op_name[32];
112     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
113
114     eflags = env->eflags;
115     fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
116             "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
117             "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d\n",
118             env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
119             env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
120             env->eip, eflags,
121             eflags & DF_MASK ? 'D' : '-',
122             eflags & CC_O ? 'O' : '-',
123             eflags & CC_S ? 'S' : '-',
124             eflags & CC_Z ? 'Z' : '-',
125             eflags & CC_A ? 'A' : '-',
126             eflags & CC_P ? 'P' : '-',
127             eflags & CC_C ? 'C' : '-',
128             env->hflags & HF_CPL_MASK, 
129             (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
130     for(i = 0; i < 6; i++) {
131         SegmentCache *sc = &env->segs[i];
132         fprintf(f, "%s =%04x %08x %08x %08x\n",
133                 seg_name[i],
134                 sc->selector,
135                 (int)sc->base,
136                 sc->limit,
137                 sc->flags);
138     }
139     fprintf(f, "LDT=%04x %08x %08x %08x\n",
140             env->ldt.selector,
141             (int)env->ldt.base,
142             env->ldt.limit,
143             env->ldt.flags);
144     fprintf(f, "TR =%04x %08x %08x %08x\n",
145             env->tr.selector,
146             (int)env->tr.base,
147             env->tr.limit,
148             env->tr.flags);
149     fprintf(f, "GDT=     %08x %08x\n",
150             (int)env->gdt.base, env->gdt.limit);
151     fprintf(f, "IDT=     %08x %08x\n",
152             (int)env->idt.base, env->idt.limit);
153     fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
154             env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
155     
156     if (flags & X86_DUMP_CCOP) {
157         if ((unsigned)env->cc_op < CC_OP_NB)
158             strcpy(cc_op_name, cc_op_str[env->cc_op]);
159         else
160             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
161         fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
162                 env->cc_src, env->cc_dst, cc_op_name);
163     }
164     if (flags & X86_DUMP_FPU) {
165         fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
166                 (double)env->fpregs[0], 
167                 (double)env->fpregs[1], 
168                 (double)env->fpregs[2], 
169                 (double)env->fpregs[3]);
170         fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", 
171                 (double)env->fpregs[4], 
172                 (double)env->fpregs[5], 
173                 (double)env->fpregs[7], 
174                 (double)env->fpregs[8]);
175     }
176 }
177
178 /***********************************************************/
179 /* x86 mmu */
180 /* XXX: add PGE support */
181
182 /* called when cr3 or PG bit are modified */
183 static int last_pg_state = -1;
184 static uint32_t a20_mask;
185 int a20_enabled;
186
187 void cpu_x86_set_a20(CPUX86State *env, int a20_state)
188 {
189     a20_state = (a20_state != 0);
190     if (a20_state != a20_enabled) {
191 #if defined(DEBUG_MMU)
192         printf("A20 update: a20=%d\n", a20_state);
193 #endif
194         /* if the cpu is currently executing code, we must unlink it and
195            all the potentially executing TB */
196         cpu_interrupt(env, 0);
197
198         /* when a20 is changed, all the MMU mappings are invalid, so
199            we must flush everything */
200         tlb_flush(env);
201         a20_enabled = a20_state;
202         if (a20_enabled)
203             a20_mask = 0xffffffff;
204         else
205             a20_mask = 0xffefffff;
206     }
207 }
208
209 void cpu_x86_update_cr0(CPUX86State *env)
210 {
211     int pg_state, pe_state;
212
213 #if defined(DEBUG_MMU)
214     printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
215 #endif
216     pg_state = env->cr[0] & CR0_PG_MASK;
217     if (pg_state != last_pg_state) {
218         tlb_flush(env);
219         last_pg_state = pg_state;
220     }
221     /* update PE flag in hidden flags */
222     pe_state = (env->cr[0] & CR0_PE_MASK);
223     env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
224     /* ensure that ADDSEG is always set in real mode */
225     env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
226 }
227
228 void cpu_x86_update_cr3(CPUX86State *env)
229 {
230     if (env->cr[0] & CR0_PG_MASK) {
231 #if defined(DEBUG_MMU)
232         printf("CR3 update: CR3=%08x\n", env->cr[3]);
233 #endif
234         tlb_flush(env);
235     }
236 }
237
238 void cpu_x86_init_mmu(CPUX86State *env)
239 {
240     a20_enabled = 1;
241     a20_mask = 0xffffffff;
242
243     last_pg_state = -1;
244     cpu_x86_update_cr0(env);
245 }
246
247 /* XXX: also flush 4MB pages */
248 void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
249 {
250     tlb_flush_page(env, addr);
251 }
252
253 /* return value:
254    -1 = cannot handle fault 
255    0  = nothing more to do 
256    1  = generate PF fault
257    2  = soft MMU activation required for this block
258 */
259 int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
260                              int is_write, int is_user, int is_softmmu)
261 {
262     uint8_t *pde_ptr, *pte_ptr;
263     uint32_t pde, pte, virt_addr, ptep;
264     int error_code, is_dirty, prot, page_size, ret;
265     unsigned long paddr, vaddr, page_offset;
266     
267 #if defined(DEBUG_MMU)
268     printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", 
269            addr, is_write, is_user, env->eip);
270 #endif
271
272     if (env->user_mode_only) {
273         /* user mode only emulation */
274         error_code = 0;
275         goto do_fault;
276     }
277
278     if (!(env->cr[0] & CR0_PG_MASK)) {
279         pte = addr;
280         virt_addr = addr & TARGET_PAGE_MASK;
281         prot = PROT_READ | PROT_WRITE;
282         page_size = 4096;
283         goto do_mapping;
284     }
285
286     /* page directory entry */
287     pde_ptr = phys_ram_base + 
288         (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask);
289     pde = ldl_raw(pde_ptr);
290     if (!(pde & PG_PRESENT_MASK)) {
291         error_code = 0;
292         goto do_fault;
293     }
294     /* if PSE bit is set, then we use a 4MB page */
295     if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
296         if (is_user) {
297             if (!(pde & PG_USER_MASK))
298                 goto do_fault_protect;
299             if (is_write && !(pde & PG_RW_MASK))
300                 goto do_fault_protect;
301         } else {
302             if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
303                 is_write && !(pde & PG_RW_MASK)) 
304                 goto do_fault_protect;
305         }
306         is_dirty = is_write && !(pde & PG_DIRTY_MASK);
307         if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
308             pde |= PG_ACCESSED_MASK;
309             if (is_dirty)
310                 pde |= PG_DIRTY_MASK;
311             stl_raw(pde_ptr, pde);
312         }
313         
314         pte = pde & ~0x003ff000; /* align to 4MB */
315         ptep = pte;
316         page_size = 4096 * 1024;
317         virt_addr = addr & ~0x003fffff;
318     } else {
319         if (!(pde & PG_ACCESSED_MASK)) {
320             pde |= PG_ACCESSED_MASK;
321             stl_raw(pde_ptr, pde);
322         }
323
324         /* page directory entry */
325         pte_ptr = phys_ram_base + 
326             (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask);
327         pte = ldl_raw(pte_ptr);
328         if (!(pte & PG_PRESENT_MASK)) {
329             error_code = 0;
330             goto do_fault;
331         }
332         /* combine pde and pte user and rw protections */
333         ptep = pte & pde;
334         if (is_user) {
335             if (!(ptep & PG_USER_MASK))
336                 goto do_fault_protect;
337             if (is_write && !(ptep & PG_RW_MASK))
338                 goto do_fault_protect;
339         } else {
340             if ((env->cr[0] & CR0_WP_MASK) && (ptep & PG_USER_MASK) &&
341                 is_write && !(ptep & PG_RW_MASK)) 
342                 goto do_fault_protect;
343         }
344         is_dirty = is_write && !(pte & PG_DIRTY_MASK);
345         if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
346             pte |= PG_ACCESSED_MASK;
347             if (is_dirty)
348                 pte |= PG_DIRTY_MASK;
349             stl_raw(pte_ptr, pte);
350         }
351         page_size = 4096;
352         virt_addr = addr & ~0xfff;
353     }
354
355     /* the page can be put in the TLB */
356     prot = PROT_READ;
357     if (pte & PG_DIRTY_MASK) {
358         /* only set write access if already dirty... otherwise wait
359            for dirty access */
360         if (is_user) {
361             if (ptep & PG_RW_MASK)
362                 prot |= PROT_WRITE;
363         } else {
364             if (!(env->cr[0] & CR0_WP_MASK) || !(ptep & PG_USER_MASK) ||
365                 (ptep & PG_RW_MASK))
366                 prot |= PROT_WRITE;
367         }
368     }
369
370  do_mapping:
371     pte = pte & a20_mask;
372
373     /* Even if 4MB pages, we map only one 4KB page in the cache to
374        avoid filling it too fast */
375     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
376     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
377     vaddr = virt_addr + page_offset;
378     
379     ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
380     return ret;
381  do_fault_protect:
382     error_code = PG_ERROR_P_MASK;
383  do_fault:
384     env->cr[2] = addr;
385     env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
386     if (is_user)
387         env->error_code |= PG_ERROR_U_MASK;
388     return 1;
389 }
390
391 #if defined(CONFIG_USER_ONLY) 
392 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
393 {
394     return addr;
395 }
396 #else
397 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
398 {
399     uint8_t *pde_ptr, *pte_ptr;
400     uint32_t pde, pte, paddr, page_offset, page_size;
401
402     if (!(env->cr[0] & CR0_PG_MASK)) {
403         pte = addr;
404         page_size = 4096;
405     } else {
406         /* page directory entry */
407         pde_ptr = phys_ram_base + 
408             (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask);
409         pde = ldl_raw(pde_ptr);
410         if (!(pde & PG_PRESENT_MASK)) 
411             return -1;
412         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
413             pte = pde & ~0x003ff000; /* align to 4MB */
414             page_size = 4096 * 1024;
415         } else {
416             /* page directory entry */
417             pte_ptr = phys_ram_base + 
418                 (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask);
419             pte = ldl_raw(pte_ptr);
420             if (!(pte & PG_PRESENT_MASK))
421                 return -1;
422             page_size = 4096;
423         }
424     }
425     pte = pte & a20_mask;
426     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
427     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
428     return paddr;
429 }
430 #endif