Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ 0e4b179d

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