Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ eeab3a55

History | View | Annotate | Download (15.7 kB)

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