Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ b769d8fe

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