Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ 10f0e412

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