Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ ffddfee3

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
        cpu_single_env = env;
79 ffddfee3 bellard
    }
80 ffddfee3 bellard
#endif
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 1ac157da bellard
    /* not correct (CS base=0xffff0000) */
111 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); 
112 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
113 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
114 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
115 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
116 1ac157da bellard
    cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
117 1ac157da bellard
    
118 1ac157da bellard
    env->eip = 0xfff0;
119 1ac157da bellard
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
120 1ac157da bellard
    
121 1ac157da bellard
    env->eflags = 0x2;
122 1ac157da bellard
    
123 1ac157da bellard
    /* FPU init */
124 1ac157da bellard
    for(i = 0;i < 8; i++)
125 1ac157da bellard
        env->fptags[i] = 1;
126 1ac157da bellard
    env->fpuc = 0x37f;
127 2c0262af bellard
}
128 2c0262af bellard
129 2c0262af bellard
void cpu_x86_close(CPUX86State *env)
130 2c0262af bellard
{
131 2c0262af bellard
    free(env);
132 2c0262af bellard
}
133 2c0262af bellard
134 2c0262af bellard
/***********************************************************/
135 2c0262af bellard
/* x86 debug */
136 2c0262af bellard
137 2c0262af bellard
static const char *cc_op_str[] = {
138 2c0262af bellard
    "DYNAMIC",
139 2c0262af bellard
    "EFLAGS",
140 b7f0f463 bellard
    "MULB",
141 b7f0f463 bellard
    "MULW",
142 b7f0f463 bellard
    "MULL",
143 2c0262af bellard
    "ADDB",
144 2c0262af bellard
    "ADDW",
145 2c0262af bellard
    "ADDL",
146 2c0262af bellard
    "ADCB",
147 2c0262af bellard
    "ADCW",
148 2c0262af bellard
    "ADCL",
149 2c0262af bellard
    "SUBB",
150 2c0262af bellard
    "SUBW",
151 2c0262af bellard
    "SUBL",
152 2c0262af bellard
    "SBBB",
153 2c0262af bellard
    "SBBW",
154 2c0262af bellard
    "SBBL",
155 2c0262af bellard
    "LOGICB",
156 2c0262af bellard
    "LOGICW",
157 2c0262af bellard
    "LOGICL",
158 2c0262af bellard
    "INCB",
159 2c0262af bellard
    "INCW",
160 2c0262af bellard
    "INCL",
161 2c0262af bellard
    "DECB",
162 2c0262af bellard
    "DECW",
163 2c0262af bellard
    "DECL",
164 2c0262af bellard
    "SHLB",
165 2c0262af bellard
    "SHLW",
166 2c0262af bellard
    "SHLL",
167 2c0262af bellard
    "SARB",
168 2c0262af bellard
    "SARW",
169 2c0262af bellard
    "SARL",
170 2c0262af bellard
};
171 2c0262af bellard
172 2c0262af bellard
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
173 2c0262af bellard
{
174 246d897f bellard
    int eflags, i;
175 2c0262af bellard
    char cc_op_name[32];
176 246d897f bellard
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
177 2c0262af bellard
178 2c0262af bellard
    eflags = env->eflags;
179 2c0262af bellard
    fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
180 2c0262af bellard
            "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
181 eeab3a55 bellard
            "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d A20=%d\n",
182 2c0262af bellard
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
183 2c0262af bellard
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
184 2c0262af bellard
            env->eip, eflags,
185 2c0262af bellard
            eflags & DF_MASK ? 'D' : '-',
186 2c0262af bellard
            eflags & CC_O ? 'O' : '-',
187 2c0262af bellard
            eflags & CC_S ? 'S' : '-',
188 2c0262af bellard
            eflags & CC_Z ? 'Z' : '-',
189 2c0262af bellard
            eflags & CC_A ? 'A' : '-',
190 2c0262af bellard
            eflags & CC_P ? 'P' : '-',
191 246d897f bellard
            eflags & CC_C ? 'C' : '-',
192 5e809a80 bellard
            env->hflags & HF_CPL_MASK, 
193 eeab3a55 bellard
            (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
194 eeab3a55 bellard
            (env->a20_mask >> 20) & 1);
195 246d897f bellard
    for(i = 0; i < 6; i++) {
196 246d897f bellard
        SegmentCache *sc = &env->segs[i];
197 246d897f bellard
        fprintf(f, "%s =%04x %08x %08x %08x\n",
198 246d897f bellard
                seg_name[i],
199 246d897f bellard
                sc->selector,
200 246d897f bellard
                (int)sc->base,
201 246d897f bellard
                sc->limit,
202 246d897f bellard
                sc->flags);
203 246d897f bellard
    }
204 246d897f bellard
    fprintf(f, "LDT=%04x %08x %08x %08x\n",
205 246d897f bellard
            env->ldt.selector,
206 246d897f bellard
            (int)env->ldt.base,
207 246d897f bellard
            env->ldt.limit,
208 246d897f bellard
            env->ldt.flags);
209 246d897f bellard
    fprintf(f, "TR =%04x %08x %08x %08x\n",
210 246d897f bellard
            env->tr.selector,
211 246d897f bellard
            (int)env->tr.base,
212 246d897f bellard
            env->tr.limit,
213 246d897f bellard
            env->tr.flags);
214 246d897f bellard
    fprintf(f, "GDT=     %08x %08x\n",
215 246d897f bellard
            (int)env->gdt.base, env->gdt.limit);
216 246d897f bellard
    fprintf(f, "IDT=     %08x %08x\n",
217 246d897f bellard
            (int)env->idt.base, env->idt.limit);
218 246d897f bellard
    fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
219 246d897f bellard
            env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
220 246d897f bellard
    
221 2c0262af bellard
    if (flags & X86_DUMP_CCOP) {
222 2c0262af bellard
        if ((unsigned)env->cc_op < CC_OP_NB)
223 eba2af63 bellard
            snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
224 2c0262af bellard
        else
225 2c0262af bellard
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
226 2c0262af bellard
        fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
227 2c0262af bellard
                env->cc_src, env->cc_dst, cc_op_name);
228 2c0262af bellard
    }
229 2c0262af bellard
    if (flags & X86_DUMP_FPU) {
230 2c0262af bellard
        fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
231 2c0262af bellard
                (double)env->fpregs[0], 
232 2c0262af bellard
                (double)env->fpregs[1], 
233 2c0262af bellard
                (double)env->fpregs[2], 
234 2c0262af bellard
                (double)env->fpregs[3]);
235 2c0262af bellard
        fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", 
236 2c0262af bellard
                (double)env->fpregs[4], 
237 2c0262af bellard
                (double)env->fpregs[5], 
238 2c0262af bellard
                (double)env->fpregs[7], 
239 2c0262af bellard
                (double)env->fpregs[8]);
240 2c0262af bellard
    }
241 2c0262af bellard
}
242 2c0262af bellard
243 2c0262af bellard
/***********************************************************/
244 2c0262af bellard
/* x86 mmu */
245 2c0262af bellard
/* XXX: add PGE support */
246 2c0262af bellard
247 461c0471 bellard
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
248 461c0471 bellard
{
249 461c0471 bellard
    a20_state = (a20_state != 0);
250 1ac157da bellard
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
251 b7f0f463 bellard
#if defined(DEBUG_MMU)
252 b7f0f463 bellard
        printf("A20 update: a20=%d\n", a20_state);
253 b7f0f463 bellard
#endif
254 6bb70571 bellard
        /* if the cpu is currently executing code, we must unlink it and
255 6bb70571 bellard
           all the potentially executing TB */
256 0e4b179d bellard
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
257 6bb70571 bellard
258 461c0471 bellard
        /* when a20 is changed, all the MMU mappings are invalid, so
259 461c0471 bellard
           we must flush everything */
260 1ac157da bellard
        tlb_flush(env, 1);
261 1ac157da bellard
        env->a20_mask = 0xffefffff | (a20_state << 20);
262 461c0471 bellard
    }
263 461c0471 bellard
}
264 461c0471 bellard
265 1ac157da bellard
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
266 2c0262af bellard
{
267 1ac157da bellard
    int pe_state;
268 2c0262af bellard
269 b7f0f463 bellard
#if defined(DEBUG_MMU)
270 1ac157da bellard
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
271 2c0262af bellard
#endif
272 1ac157da bellard
    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
273 1ac157da bellard
        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
274 1ac157da bellard
        tlb_flush(env, 1);
275 2c0262af bellard
    }
276 28c3ee3f bellard
    env->cr[0] = new_cr0 | CR0_ET_MASK;
277 1ac157da bellard
    
278 436d8b89 bellard
    /* update PE flag in hidden flags */
279 436d8b89 bellard
    pe_state = (env->cr[0] & CR0_PE_MASK);
280 436d8b89 bellard
    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
281 436d8b89 bellard
    /* ensure that ADDSEG is always set in real mode */
282 436d8b89 bellard
    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
283 9588b95a bellard
    /* update FPU flags */
284 9588b95a bellard
    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
285 9588b95a bellard
        ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
286 2c0262af bellard
}
287 2c0262af bellard
288 1ac157da bellard
void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
289 2c0262af bellard
{
290 1ac157da bellard
    env->cr[3] = new_cr3;
291 2c0262af bellard
    if (env->cr[0] & CR0_PG_MASK) {
292 2c0262af bellard
#if defined(DEBUG_MMU)
293 1ac157da bellard
        printf("CR3 update: CR3=%08x\n", new_cr3);
294 2c0262af bellard
#endif
295 1ac157da bellard
        tlb_flush(env, 0);
296 2c0262af bellard
    }
297 2c0262af bellard
}
298 2c0262af bellard
299 1ac157da bellard
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
300 2c0262af bellard
{
301 1ac157da bellard
#if defined(DEBUG_MMU)
302 1ac157da bellard
    printf("CR4 update: CR4=%08x\n", env->cr[4]);
303 1ac157da bellard
#endif
304 1ac157da bellard
    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
305 1ac157da bellard
        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
306 1ac157da bellard
        tlb_flush(env, 1);
307 1ac157da bellard
    }
308 1ac157da bellard
    env->cr[4] = new_cr4;
309 2c0262af bellard
}
310 2c0262af bellard
311 2c0262af bellard
/* XXX: also flush 4MB pages */
312 2c0262af bellard
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
313 2c0262af bellard
{
314 2c0262af bellard
    tlb_flush_page(env, addr);
315 2c0262af bellard
}
316 2c0262af bellard
317 2c0262af bellard
/* return value:
318 2c0262af bellard
   -1 = cannot handle fault 
319 2c0262af bellard
   0  = nothing more to do 
320 2c0262af bellard
   1  = generate PF fault
321 2c0262af bellard
   2  = soft MMU activation required for this block
322 2c0262af bellard
*/
323 61382a50 bellard
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
324 61382a50 bellard
                             int is_write, int is_user, int is_softmmu)
325 2c0262af bellard
{
326 2c0262af bellard
    uint8_t *pde_ptr, *pte_ptr;
327 10f0e412 bellard
    uint32_t pde, pte, virt_addr, ptep;
328 61382a50 bellard
    int error_code, is_dirty, prot, page_size, ret;
329 436d8b89 bellard
    unsigned long paddr, vaddr, page_offset;
330 2c0262af bellard
    
331 436d8b89 bellard
#if defined(DEBUG_MMU)
332 2c0262af bellard
    printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", 
333 2c0262af bellard
           addr, is_write, is_user, env->eip);
334 2c0262af bellard
#endif
335 2c0262af 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