Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ 07ce05ea

History | View | Annotate | Download (13 kB)

1
/*
2
 *  i386 helpers (without register variable usage)
3
 * 
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include <stdarg.h>
21
#include <stdlib.h>
22
#include <stdio.h>
23
#include <string.h>
24
#include <inttypes.h>
25
#include <signal.h>
26
#include <assert.h>
27
#include <sys/mman.h>
28

    
29
#include "cpu.h"
30
#include "exec-all.h"
31

    
32
//#define DEBUG_MMU
33

    
34
CPUX86State *cpu_x86_init(void)
35
{
36
    CPUX86State *env;
37
    int i;
38
    static int inited;
39

    
40
    cpu_exec_init();
41

    
42
    env = malloc(sizeof(CPUX86State));
43
    if (!env)
44
        return NULL;
45
    memset(env, 0, sizeof(CPUX86State));
46

    
47
    /* init to reset state */
48

    
49
    tlb_flush(env, 1);
50
#ifdef CONFIG_SOFTMMU
51
    env->hflags |= HF_SOFTMMU_MASK;
52
#endif
53

    
54
    cpu_x86_update_cr0(env, 0x60000010);
55
    env->a20_mask = 0xffffffff;
56
    
57
    env->idt.limit = 0xffff;
58
    env->gdt.limit = 0xffff;
59
    env->ldt.limit = 0xffff;
60
    env->ldt.flags = DESC_P_MASK;
61
    env->tr.limit = 0xffff;
62
    env->tr.flags = DESC_P_MASK;
63
    
64
    /* not correct (CS base=0xffff0000) */
65
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); 
66
    cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
67
    cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
68
    cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
69
    cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
70
    cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
71
    
72
    env->eip = 0xfff0;
73
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
74
    
75
    env->eflags = 0x2;
76
    
77
    /* FPU init */
78
    for(i = 0;i < 8; i++)
79
        env->fptags[i] = 1;
80
    env->fpuc = 0x37f;
81
    
82
    /* init various static tables */
83
    if (!inited) {
84
        inited = 1;
85
        optimize_flags_init();
86
    }
87
    return env;
88
}
89

    
90
void cpu_x86_close(CPUX86State *env)
91
{
92
    free(env);
93
}
94

    
95
/***********************************************************/
96
/* x86 debug */
97

    
98
static const char *cc_op_str[] = {
99
    "DYNAMIC",
100
    "EFLAGS",
101
    "MULB",
102
    "MULW",
103
    "MULL",
104
    "ADDB",
105
    "ADDW",
106
    "ADDL",
107
    "ADCB",
108
    "ADCW",
109
    "ADCL",
110
    "SUBB",
111
    "SUBW",
112
    "SUBL",
113
    "SBBB",
114
    "SBBW",
115
    "SBBL",
116
    "LOGICB",
117
    "LOGICW",
118
    "LOGICL",
119
    "INCB",
120
    "INCW",
121
    "INCL",
122
    "DECB",
123
    "DECW",
124
    "DECL",
125
    "SHLB",
126
    "SHLW",
127
    "SHLL",
128
    "SARB",
129
    "SARW",
130
    "SARL",
131
};
132

    
133
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
134
{
135
    int eflags, i;
136
    char cc_op_name[32];
137
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
138

    
139
    eflags = env->eflags;
140
    fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
141
            "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
142
            "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d\n",
143
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
144
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
145
            env->eip, eflags,
146
            eflags & DF_MASK ? 'D' : '-',
147
            eflags & CC_O ? 'O' : '-',
148
            eflags & CC_S ? 'S' : '-',
149
            eflags & CC_Z ? 'Z' : '-',
150
            eflags & CC_A ? 'A' : '-',
151
            eflags & CC_P ? 'P' : '-',
152
            eflags & CC_C ? 'C' : '-',
153
            env->hflags & HF_CPL_MASK, 
154
            (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
155
    for(i = 0; i < 6; i++) {
156
        SegmentCache *sc = &env->segs[i];
157
        fprintf(f, "%s =%04x %08x %08x %08x\n",
158
                seg_name[i],
159
                sc->selector,
160
                (int)sc->base,
161
                sc->limit,
162
                sc->flags);
163
    }
164
    fprintf(f, "LDT=%04x %08x %08x %08x\n",
165
            env->ldt.selector,
166
            (int)env->ldt.base,
167
            env->ldt.limit,
168
            env->ldt.flags);
169
    fprintf(f, "TR =%04x %08x %08x %08x\n",
170
            env->tr.selector,
171
            (int)env->tr.base,
172
            env->tr.limit,
173
            env->tr.flags);
174
    fprintf(f, "GDT=     %08x %08x\n",
175
            (int)env->gdt.base, env->gdt.limit);
176
    fprintf(f, "IDT=     %08x %08x\n",
177
            (int)env->idt.base, env->idt.limit);
178
    fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
179
            env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
180
    
181
    if (flags & X86_DUMP_CCOP) {
182
        if ((unsigned)env->cc_op < CC_OP_NB)
183
            strcpy(cc_op_name, cc_op_str[env->cc_op]);
184
        else
185
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
186
        fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
187
                env->cc_src, env->cc_dst, cc_op_name);
188
    }
189
    if (flags & X86_DUMP_FPU) {
190
        fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
191
                (double)env->fpregs[0], 
192
                (double)env->fpregs[1], 
193
                (double)env->fpregs[2], 
194
                (double)env->fpregs[3]);
195
        fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", 
196
                (double)env->fpregs[4], 
197
                (double)env->fpregs[5], 
198
                (double)env->fpregs[7], 
199
                (double)env->fpregs[8]);
200
    }
201
}
202

    
203
/***********************************************************/
204
/* x86 mmu */
205
/* XXX: add PGE support */
206

    
207
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
208
{
209
    a20_state = (a20_state != 0);
210
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
211
#if defined(DEBUG_MMU)
212
        printf("A20 update: a20=%d\n", a20_state);
213
#endif
214
        /* if the cpu is currently executing code, we must unlink it and
215
           all the potentially executing TB */
216
        cpu_interrupt(env, 0);
217

    
218
        /* when a20 is changed, all the MMU mappings are invalid, so
219
           we must flush everything */
220
        tlb_flush(env, 1);
221
        env->a20_mask = 0xffefffff | (a20_state << 20);
222
    }
223
}
224

    
225
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
226
{
227
    int pe_state;
228

    
229
#if defined(DEBUG_MMU)
230
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
231
#endif
232
    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
233
        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
234
        tlb_flush(env, 1);
235
    }
236
    env->cr[0] = new_cr0;
237
    
238
    /* update PE flag in hidden flags */
239
    pe_state = (env->cr[0] & CR0_PE_MASK);
240
    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
241
    /* ensure that ADDSEG is always set in real mode */
242
    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
243
}
244

    
245
void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
246
{
247
    env->cr[3] = new_cr3;
248
    if (env->cr[0] & CR0_PG_MASK) {
249
#if defined(DEBUG_MMU)
250
        printf("CR3 update: CR3=%08x\n", new_cr3);
251
#endif
252
        tlb_flush(env, 0);
253
    }
254
}
255

    
256
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
257
{
258
#if defined(DEBUG_MMU)
259
    printf("CR4 update: CR4=%08x\n", env->cr[4]);
260
#endif
261
    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
262
        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
263
        tlb_flush(env, 1);
264
    }
265
    env->cr[4] = new_cr4;
266
}
267

    
268
/* XXX: also flush 4MB pages */
269
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
270
{
271
    tlb_flush_page(env, addr);
272
}
273

    
274
/* return value:
275
   -1 = cannot handle fault 
276
   0  = nothing more to do 
277
   1  = generate PF fault
278
   2  = soft MMU activation required for this block
279
*/
280
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
281
                             int is_write, int is_user, int is_softmmu)
282
{
283
    uint8_t *pde_ptr, *pte_ptr;
284
    uint32_t pde, pte, virt_addr, ptep;
285
    int error_code, is_dirty, prot, page_size, ret;
286
    unsigned long paddr, vaddr, page_offset;
287
    
288
#if defined(DEBUG_MMU)
289
    printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", 
290
           addr, is_write, is_user, env->eip);
291
#endif
292

    
293
    if (env->user_mode_only) {
294
        /* user mode only emulation */
295
        error_code = 0;
296
        goto do_fault;
297
    }
298

    
299
    if (!(env->cr[0] & CR0_PG_MASK)) {
300
        pte = addr;
301
        virt_addr = addr & TARGET_PAGE_MASK;
302
        prot = PROT_READ | PROT_WRITE;
303
        page_size = 4096;
304
        goto do_mapping;
305
    }
306

    
307
    /* page directory entry */
308
    pde_ptr = phys_ram_base + 
309
        (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
310
    pde = ldl_raw(pde_ptr);
311
    if (!(pde & PG_PRESENT_MASK)) {
312
        error_code = 0;
313
        goto do_fault;
314
    }
315
    /* if PSE bit is set, then we use a 4MB page */
316
    if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
317
        if (is_user) {
318
            if (!(pde & PG_USER_MASK))
319
                goto do_fault_protect;
320
            if (is_write && !(pde & PG_RW_MASK))
321
                goto do_fault_protect;
322
        } else {
323
            if ((env->cr[0] & CR0_WP_MASK) && 
324
                is_write && !(pde & PG_RW_MASK)) 
325
                goto do_fault_protect;
326
        }
327
        is_dirty = is_write && !(pde & PG_DIRTY_MASK);
328
        if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
329
            pde |= PG_ACCESSED_MASK;
330
            if (is_dirty)
331
                pde |= PG_DIRTY_MASK;
332
            stl_raw(pde_ptr, pde);
333
        }
334
        
335
        pte = pde & ~0x003ff000; /* align to 4MB */
336
        ptep = pte;
337
        page_size = 4096 * 1024;
338
        virt_addr = addr & ~0x003fffff;
339
    } else {
340
        if (!(pde & PG_ACCESSED_MASK)) {
341
            pde |= PG_ACCESSED_MASK;
342
            stl_raw(pde_ptr, pde);
343
        }
344

    
345
        /* page directory entry */
346
        pte_ptr = phys_ram_base + 
347
            (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
348
        pte = ldl_raw(pte_ptr);
349
        if (!(pte & PG_PRESENT_MASK)) {
350
            error_code = 0;
351
            goto do_fault;
352
        }
353
        /* combine pde and pte user and rw protections */
354
        ptep = pte & pde;
355
        if (is_user) {
356
            if (!(ptep & PG_USER_MASK))
357
                goto do_fault_protect;
358
            if (is_write && !(ptep & PG_RW_MASK))
359
                goto do_fault_protect;
360
        } else {
361
            if ((env->cr[0] & CR0_WP_MASK) &&
362
                is_write && !(ptep & PG_RW_MASK)) 
363
                goto do_fault_protect;
364
        }
365
        is_dirty = is_write && !(pte & PG_DIRTY_MASK);
366
        if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
367
            pte |= PG_ACCESSED_MASK;
368
            if (is_dirty)
369
                pte |= PG_DIRTY_MASK;
370
            stl_raw(pte_ptr, pte);
371
        }
372
        page_size = 4096;
373
        virt_addr = addr & ~0xfff;
374
    }
375

    
376
    /* the page can be put in the TLB */
377
    prot = PROT_READ;
378
    if (pte & PG_DIRTY_MASK) {
379
        /* only set write access if already dirty... otherwise wait
380
           for dirty access */
381
        if (is_user) {
382
            if (ptep & PG_RW_MASK)
383
                prot |= PROT_WRITE;
384
        } else {
385
            if (!(env->cr[0] & CR0_WP_MASK) ||
386
                (ptep & PG_RW_MASK))
387
                prot |= PROT_WRITE;
388
        }
389
    }
390

    
391
 do_mapping:
392
    pte = pte & env->a20_mask;
393

    
394
    /* Even if 4MB pages, we map only one 4KB page in the cache to
395
       avoid filling it too fast */
396
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
397
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
398
    vaddr = virt_addr + page_offset;
399
    
400
    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
401
    return ret;
402
 do_fault_protect:
403
    error_code = PG_ERROR_P_MASK;
404
 do_fault:
405
    env->cr[2] = addr;
406
    env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
407
    if (is_user)
408
        env->error_code |= PG_ERROR_U_MASK;
409
    return 1;
410
}
411

    
412
#if defined(CONFIG_USER_ONLY) 
413
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
414
{
415
    return addr;
416
}
417
#else
418
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
419
{
420
    uint8_t *pde_ptr, *pte_ptr;
421
    uint32_t pde, pte, paddr, page_offset, page_size;
422

    
423
    if (!(env->cr[0] & CR0_PG_MASK)) {
424
        pte = addr;
425
        page_size = 4096;
426
    } else {
427
        /* page directory entry */
428
        pde_ptr = phys_ram_base + 
429
            (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
430
        pde = ldl_raw(pde_ptr);
431
        if (!(pde & PG_PRESENT_MASK)) 
432
            return -1;
433
        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
434
            pte = pde & ~0x003ff000; /* align to 4MB */
435
            page_size = 4096 * 1024;
436
        } else {
437
            /* page directory entry */
438
            pte_ptr = phys_ram_base + 
439
                (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
440
            pte = ldl_raw(pte_ptr);
441
            if (!(pte & PG_PRESENT_MASK))
442
                return -1;
443
            page_size = 4096;
444
        }
445
    }
446
    pte = pte & env->a20_mask;
447
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
448
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
449
    return paddr;
450
}
451
#endif