Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ d1d9f421

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 2c0262af bellard
335 2c0262af bellard
    if (env->user_mode_only) {
336 2c0262af bellard
        /* user mode only emulation */
337 2c0262af bellard
        error_code = 0;
338 2c0262af bellard
        goto do_fault;
339 2c0262af bellard
    }
340 2c0262af bellard
341 2c0262af bellard
    if (!(env->cr[0] & CR0_PG_MASK)) {
342 2c0262af bellard
        pte = addr;
343 461c0471 bellard
        virt_addr = addr & TARGET_PAGE_MASK;
344 67b915a5 bellard
        prot = PAGE_READ | PAGE_WRITE;
345 2c0262af bellard
        page_size = 4096;
346 2c0262af bellard
        goto do_mapping;
347 2c0262af bellard
    }
348 2c0262af bellard
349 2c0262af bellard
    /* page directory entry */
350 461c0471 bellard
    pde_ptr = phys_ram_base + 
351 1ac157da bellard
        (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
352 61382a50 bellard
    pde = ldl_raw(pde_ptr);
353 2c0262af bellard
    if (!(pde & PG_PRESENT_MASK)) {
354 2c0262af bellard
        error_code = 0;
355 2c0262af bellard
        goto do_fault;
356 2c0262af bellard
    }
357 2c0262af bellard
    /* if PSE bit is set, then we use a 4MB page */
358 2c0262af bellard
    if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
359 10f0e412 bellard
        if (is_user) {
360 10f0e412 bellard
            if (!(pde & PG_USER_MASK))
361 10f0e412 bellard
                goto do_fault_protect;
362 10f0e412 bellard
            if (is_write && !(pde & PG_RW_MASK))
363 10f0e412 bellard
                goto do_fault_protect;
364 10f0e412 bellard
        } else {
365 34f715e7 bellard
            if ((env->cr[0] & CR0_WP_MASK) && 
366 10f0e412 bellard
                is_write && !(pde & PG_RW_MASK)) 
367 10f0e412 bellard
                goto do_fault_protect;
368 10f0e412 bellard
        }
369 2c0262af bellard
        is_dirty = is_write && !(pde & PG_DIRTY_MASK);
370 777aca2f bellard
        if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
371 2c0262af bellard
            pde |= PG_ACCESSED_MASK;
372 2c0262af bellard
            if (is_dirty)
373 2c0262af bellard
                pde |= PG_DIRTY_MASK;
374 61382a50 bellard
            stl_raw(pde_ptr, pde);
375 2c0262af bellard
        }
376 2c0262af bellard
        
377 2c0262af bellard
        pte = pde & ~0x003ff000; /* align to 4MB */
378 10f0e412 bellard
        ptep = pte;
379 2c0262af bellard
        page_size = 4096 * 1024;
380 2c0262af bellard
        virt_addr = addr & ~0x003fffff;
381 2c0262af bellard
    } else {
382 2c0262af bellard
        if (!(pde & PG_ACCESSED_MASK)) {
383 2c0262af bellard
            pde |= PG_ACCESSED_MASK;
384 61382a50 bellard
            stl_raw(pde_ptr, pde);
385 2c0262af bellard
        }
386 2c0262af bellard
387 2c0262af bellard
        /* page directory entry */
388 461c0471 bellard
        pte_ptr = phys_ram_base + 
389 1ac157da bellard
            (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
390 61382a50 bellard
        pte = ldl_raw(pte_ptr);
391 2c0262af bellard
        if (!(pte & PG_PRESENT_MASK)) {
392 2c0262af bellard
            error_code = 0;
393 2c0262af bellard
            goto do_fault;
394 2c0262af bellard
        }
395 10f0e412 bellard
        /* combine pde and pte user and rw protections */
396 10f0e412 bellard
        ptep = pte & pde;
397 2c0262af bellard
        if (is_user) {
398 10f0e412 bellard
            if (!(ptep & PG_USER_MASK))
399 2c0262af bellard
                goto do_fault_protect;
400 10f0e412 bellard
            if (is_write && !(ptep & PG_RW_MASK))
401 2c0262af bellard
                goto do_fault_protect;
402 2c0262af bellard
        } else {
403 34f715e7 bellard
            if ((env->cr[0] & CR0_WP_MASK) &&
404 10f0e412 bellard
                is_write && !(ptep & PG_RW_MASK)) 
405 2c0262af bellard
                goto do_fault_protect;
406 2c0262af bellard
        }
407 2c0262af bellard
        is_dirty = is_write && !(pte & PG_DIRTY_MASK);
408 2c0262af bellard
        if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
409 2c0262af bellard
            pte |= PG_ACCESSED_MASK;
410 2c0262af bellard
            if (is_dirty)
411 2c0262af bellard
                pte |= PG_DIRTY_MASK;
412 61382a50 bellard
            stl_raw(pte_ptr, pte);
413 2c0262af bellard
        }
414 2c0262af bellard
        page_size = 4096;
415 2c0262af bellard
        virt_addr = addr & ~0xfff;
416 2c0262af bellard
    }
417 c8135d9a bellard
418 2c0262af bellard
    /* the page can be put in the TLB */
419 67b915a5 bellard
    prot = PAGE_READ;
420 c8135d9a bellard
    if (pte & PG_DIRTY_MASK) {
421 c8135d9a bellard
        /* only set write access if already dirty... otherwise wait
422 c8135d9a bellard
           for dirty access */
423 c8135d9a bellard
        if (is_user) {
424 10f0e412 bellard
            if (ptep & PG_RW_MASK)
425 67b915a5 bellard
                prot |= PAGE_WRITE;
426 c8135d9a bellard
        } else {
427 34f715e7 bellard
            if (!(env->cr[0] & CR0_WP_MASK) ||
428 10f0e412 bellard
                (ptep & PG_RW_MASK))
429 67b915a5 bellard
                prot |= PAGE_WRITE;
430 c8135d9a bellard
        }
431 2c0262af bellard
    }
432 777aca2f bellard
433 2c0262af bellard
 do_mapping:
434 1ac157da bellard
    pte = pte & env->a20_mask;
435 2c0262af bellard
436 436d8b89 bellard
    /* Even if 4MB pages, we map only one 4KB page in the cache to
437 436d8b89 bellard
       avoid filling it too fast */
438 436d8b89 bellard
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
439 436d8b89 bellard
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
440 436d8b89 bellard
    vaddr = virt_addr + page_offset;
441 436d8b89 bellard
    
442 436d8b89 bellard
    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
443 2c0262af bellard
    return ret;
444 2c0262af bellard
 do_fault_protect:
445 2c0262af bellard
    error_code = PG_ERROR_P_MASK;
446 2c0262af bellard
 do_fault:
447 2c0262af bellard
    env->cr[2] = addr;
448 2c0262af bellard
    env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
449 2c0262af bellard
    if (is_user)
450 2c0262af bellard
        env->error_code |= PG_ERROR_U_MASK;
451 2c0262af bellard
    return 1;
452 2c0262af bellard
}
453 10f0e412 bellard
454 10f0e412 bellard
#if defined(CONFIG_USER_ONLY) 
455 10f0e412 bellard
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
456 10f0e412 bellard
{
457 10f0e412 bellard
    return addr;
458 10f0e412 bellard
}
459 10f0e412 bellard
#else
460 10f0e412 bellard
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
461 10f0e412 bellard
{
462 10f0e412 bellard
    uint8_t *pde_ptr, *pte_ptr;
463 10f0e412 bellard
    uint32_t pde, pte, paddr, page_offset, page_size;
464 10f0e412 bellard
465 10f0e412 bellard
    if (!(env->cr[0] & CR0_PG_MASK)) {
466 10f0e412 bellard
        pte = addr;
467 10f0e412 bellard
        page_size = 4096;
468 10f0e412 bellard
    } else {
469 10f0e412 bellard
        /* page directory entry */
470 10f0e412 bellard
        pde_ptr = phys_ram_base + 
471 1ac157da bellard
            (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
472 10f0e412 bellard
        pde = ldl_raw(pde_ptr);
473 10f0e412 bellard
        if (!(pde & PG_PRESENT_MASK)) 
474 10f0e412 bellard
            return -1;
475 10f0e412 bellard
        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
476 10f0e412 bellard
            pte = pde & ~0x003ff000; /* align to 4MB */
477 10f0e412 bellard
            page_size = 4096 * 1024;
478 10f0e412 bellard
        } else {
479 10f0e412 bellard
            /* page directory entry */
480 10f0e412 bellard
            pte_ptr = phys_ram_base + 
481 1ac157da bellard
                (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
482 10f0e412 bellard
            pte = ldl_raw(pte_ptr);
483 10f0e412 bellard
            if (!(pte & PG_PRESENT_MASK))
484 10f0e412 bellard
                return -1;
485 10f0e412 bellard
            page_size = 4096;
486 10f0e412 bellard
        }
487 10f0e412 bellard
    }
488 1ac157da bellard
    pte = pte & env->a20_mask;
489 10f0e412 bellard
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
490 10f0e412 bellard
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
491 10f0e412 bellard
    return paddr;
492 10f0e412 bellard
}
493 10f0e412 bellard
#endif
494 9588b95a bellard
495 9588b95a bellard
#if defined(USE_CODE_COPY)
496 9588b95a bellard
struct fpstate {
497 9588b95a bellard
    uint16_t fpuc;
498 9588b95a bellard
    uint16_t dummy1;
499 9588b95a bellard
    uint16_t fpus;
500 9588b95a bellard
    uint16_t dummy2;
501 9588b95a bellard
    uint16_t fptag;
502 9588b95a bellard
    uint16_t dummy3;
503 9588b95a bellard
504 9588b95a bellard
    uint32_t fpip;
505 9588b95a bellard
    uint32_t fpcs;
506 9588b95a bellard
    uint32_t fpoo;
507 9588b95a bellard
    uint32_t fpos;
508 9588b95a bellard
    uint8_t fpregs1[8 * 10];
509 9588b95a bellard
};
510 9588b95a bellard
511 9588b95a bellard
void restore_native_fp_state(CPUState *env)
512 9588b95a bellard
{
513 9588b95a bellard
    int fptag, i, j;
514 9588b95a bellard
    struct fpstate fp1, *fp = &fp1;
515 9588b95a bellard
    
516 9588b95a bellard
    fp->fpuc = env->fpuc;
517 9588b95a bellard
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
518 9588b95a bellard
    fptag = 0;
519 9588b95a bellard
    for (i=7; i>=0; i--) {
520 9588b95a bellard
        fptag <<= 2;
521 9588b95a bellard
        if (env->fptags[i]) {
522 9588b95a bellard
            fptag |= 3;
523 9588b95a bellard
        } else {
524 9588b95a bellard
            /* the FPU automatically computes it */
525 9588b95a bellard
        }
526 9588b95a bellard
    }
527 9588b95a bellard
    fp->fptag = fptag;
528 9588b95a bellard
    j = env->fpstt;
529 9588b95a bellard
    for(i = 0;i < 8; i++) {
530 9588b95a bellard
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10);
531 9588b95a bellard
        j = (j + 1) & 7;
532 9588b95a bellard
    }
533 9588b95a bellard
    asm volatile ("frstor %0" : "=m" (*fp));
534 9588b95a bellard
    env->native_fp_regs = 1;
535 9588b95a bellard
}
536 9588b95a bellard
 
537 9588b95a bellard
void save_native_fp_state(CPUState *env)
538 9588b95a bellard
{
539 9588b95a bellard
    int fptag, i, j;
540 9588b95a bellard
    uint16_t fpuc;
541 9588b95a bellard
    struct fpstate fp1, *fp = &fp1;
542 9588b95a bellard
543 9588b95a bellard
    asm volatile ("fsave %0" : : "m" (*fp));
544 9588b95a bellard
    env->fpuc = fp->fpuc;
545 9588b95a bellard
    env->fpstt = (fp->fpus >> 11) & 7;
546 9588b95a bellard
    env->fpus = fp->fpus & ~0x3800;
547 9588b95a bellard
    fptag = fp->fptag;
548 9588b95a bellard
    for(i = 0;i < 8; i++) {
549 9588b95a bellard
        env->fptags[i] = ((fptag & 3) == 3);
550 9588b95a bellard
        fptag >>= 2;
551 9588b95a bellard
    }
552 9588b95a bellard
    j = env->fpstt;
553 9588b95a bellard
    for(i = 0;i < 8; i++) {
554 9588b95a bellard
        memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10);
555 9588b95a bellard
        j = (j + 1) & 7;
556 9588b95a bellard
    }
557 9588b95a bellard
    /* we must restore the default rounding state */
558 9588b95a bellard
    /* XXX: we do not restore the exception state */
559 9588b95a bellard
    fpuc = 0x037f | (env->fpuc & (3 << 10));
560 9588b95a bellard
    asm volatile("fldcw %0" : : "m" (fpuc));
561 9588b95a bellard
    env->native_fp_regs = 0;
562 9588b95a bellard
}
563 9588b95a bellard
#endif