Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ 67b915a5

History | View | Annotate | Download (15.6 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

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

    
31
//#define DEBUG_MMU
32

    
33
#ifdef USE_CODE_COPY
34
#include <asm/ldt.h>
35
#include <linux/unistd.h>
36
#include <linux/version.h>
37

    
38
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
39

    
40
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
41
#define modify_ldt_ldt_s user_desc
42
#endif
43
#endif /* USE_CODE_COPY */
44

    
45
CPUX86State *cpu_x86_init(void)
46
{
47
    CPUX86State *env;
48
    int i;
49
    static int inited;
50

    
51
    cpu_exec_init();
52

    
53
    env = malloc(sizeof(CPUX86State));
54
    if (!env)
55
        return NULL;
56
    memset(env, 0, sizeof(CPUX86State));
57

    
58
    /* init to reset state */
59

    
60
    tlb_flush(env, 1);
61
#ifdef CONFIG_SOFTMMU
62
    env->hflags |= HF_SOFTMMU_MASK;
63
#endif
64

    
65
    cpu_x86_update_cr0(env, 0x60000010);
66
    env->a20_mask = 0xffffffff;
67
    
68
    env->idt.limit = 0xffff;
69
    env->gdt.limit = 0xffff;
70
    env->ldt.limit = 0xffff;
71
    env->ldt.flags = DESC_P_MASK;
72
    env->tr.limit = 0xffff;
73
    env->tr.flags = DESC_P_MASK;
74
    
75
    /* not correct (CS base=0xffff0000) */
76
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); 
77
    cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
78
    cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
79
    cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
80
    cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
81
    cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
82
    
83
    env->eip = 0xfff0;
84
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
85
    
86
    env->eflags = 0x2;
87
    
88
    /* FPU init */
89
    for(i = 0;i < 8; i++)
90
        env->fptags[i] = 1;
91
    env->fpuc = 0x37f;
92
    
93
    /* init various static tables */
94
    if (!inited) {
95
        inited = 1;
96
        optimize_flags_init();
97
    }
98
#ifdef USE_CODE_COPY
99
    /* testing code for code copy case */
100
    {
101
        struct modify_ldt_ldt_s ldt;
102

    
103
        ldt.entry_number = 1;
104
        ldt.base_addr = (unsigned long)env;
105
        ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
106
        ldt.seg_32bit = 1;
107
        ldt.contents = MODIFY_LDT_CONTENTS_DATA;
108
        ldt.read_exec_only = 0;
109
        ldt.limit_in_pages = 1;
110
        ldt.seg_not_present = 0;
111
        ldt.useable = 1;
112
        modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
113
        
114
        asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
115
        cpu_single_env = env;
116
    }
117
#endif
118
    return env;
119
}
120

    
121
void cpu_x86_close(CPUX86State *env)
122
{
123
    free(env);
124
}
125

    
126
/***********************************************************/
127
/* x86 debug */
128

    
129
static const char *cc_op_str[] = {
130
    "DYNAMIC",
131
    "EFLAGS",
132
    "MULB",
133
    "MULW",
134
    "MULL",
135
    "ADDB",
136
    "ADDW",
137
    "ADDL",
138
    "ADCB",
139
    "ADCW",
140
    "ADCL",
141
    "SUBB",
142
    "SUBW",
143
    "SUBL",
144
    "SBBB",
145
    "SBBW",
146
    "SBBL",
147
    "LOGICB",
148
    "LOGICW",
149
    "LOGICL",
150
    "INCB",
151
    "INCW",
152
    "INCL",
153
    "DECB",
154
    "DECW",
155
    "DECL",
156
    "SHLB",
157
    "SHLW",
158
    "SHLL",
159
    "SARB",
160
    "SARW",
161
    "SARL",
162
};
163

    
164
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
165
{
166
    int eflags, i;
167
    char cc_op_name[32];
168
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
169

    
170
    eflags = env->eflags;
171
    fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
172
            "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
173
            "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d\n",
174
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
175
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
176
            env->eip, eflags,
177
            eflags & DF_MASK ? 'D' : '-',
178
            eflags & CC_O ? 'O' : '-',
179
            eflags & CC_S ? 'S' : '-',
180
            eflags & CC_Z ? 'Z' : '-',
181
            eflags & CC_A ? 'A' : '-',
182
            eflags & CC_P ? 'P' : '-',
183
            eflags & CC_C ? 'C' : '-',
184
            env->hflags & HF_CPL_MASK, 
185
            (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
186
    for(i = 0; i < 6; i++) {
187
        SegmentCache *sc = &env->segs[i];
188
        fprintf(f, "%s =%04x %08x %08x %08x\n",
189
                seg_name[i],
190
                sc->selector,
191
                (int)sc->base,
192
                sc->limit,
193
                sc->flags);
194
    }
195
    fprintf(f, "LDT=%04x %08x %08x %08x\n",
196
            env->ldt.selector,
197
            (int)env->ldt.base,
198
            env->ldt.limit,
199
            env->ldt.flags);
200
    fprintf(f, "TR =%04x %08x %08x %08x\n",
201
            env->tr.selector,
202
            (int)env->tr.base,
203
            env->tr.limit,
204
            env->tr.flags);
205
    fprintf(f, "GDT=     %08x %08x\n",
206
            (int)env->gdt.base, env->gdt.limit);
207
    fprintf(f, "IDT=     %08x %08x\n",
208
            (int)env->idt.base, env->idt.limit);
209
    fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
210
            env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
211
    
212
    if (flags & X86_DUMP_CCOP) {
213
        if ((unsigned)env->cc_op < CC_OP_NB)
214
            strcpy(cc_op_name, cc_op_str[env->cc_op]);
215
        else
216
            snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
217
        fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
218
                env->cc_src, env->cc_dst, cc_op_name);
219
    }
220
    if (flags & X86_DUMP_FPU) {
221
        fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
222
                (double)env->fpregs[0], 
223
                (double)env->fpregs[1], 
224
                (double)env->fpregs[2], 
225
                (double)env->fpregs[3]);
226
        fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", 
227
                (double)env->fpregs[4], 
228
                (double)env->fpregs[5], 
229
                (double)env->fpregs[7], 
230
                (double)env->fpregs[8]);
231
    }
232
}
233

    
234
/***********************************************************/
235
/* x86 mmu */
236
/* XXX: add PGE support */
237

    
238
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
239
{
240
    a20_state = (a20_state != 0);
241
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
242
#if defined(DEBUG_MMU)
243
        printf("A20 update: a20=%d\n", a20_state);
244
#endif
245
        /* if the cpu is currently executing code, we must unlink it and
246
           all the potentially executing TB */
247
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
248

    
249
        /* when a20 is changed, all the MMU mappings are invalid, so
250
           we must flush everything */
251
        tlb_flush(env, 1);
252
        env->a20_mask = 0xffefffff | (a20_state << 20);
253
    }
254
}
255

    
256
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
257
{
258
    int pe_state;
259

    
260
#if defined(DEBUG_MMU)
261
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
262
#endif
263
    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
264
        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
265
        tlb_flush(env, 1);
266
    }
267
    env->cr[0] = new_cr0;
268
    
269
    /* update PE flag in hidden flags */
270
    pe_state = (env->cr[0] & CR0_PE_MASK);
271
    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
272
    /* ensure that ADDSEG is always set in real mode */
273
    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
274
    /* update FPU flags */
275
    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
276
        ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
277
}
278

    
279
void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
280
{
281
    env->cr[3] = new_cr3;
282
    if (env->cr[0] & CR0_PG_MASK) {
283
#if defined(DEBUG_MMU)
284
        printf("CR3 update: CR3=%08x\n", new_cr3);
285
#endif
286
        tlb_flush(env, 0);
287
    }
288
}
289

    
290
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
291
{
292
#if defined(DEBUG_MMU)
293
    printf("CR4 update: CR4=%08x\n", env->cr[4]);
294
#endif
295
    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
296
        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
297
        tlb_flush(env, 1);
298
    }
299
    env->cr[4] = new_cr4;
300
}
301

    
302
/* XXX: also flush 4MB pages */
303
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
304
{
305
    tlb_flush_page(env, addr);
306
}
307

    
308
/* return value:
309
   -1 = cannot handle fault 
310
   0  = nothing more to do 
311
   1  = generate PF fault
312
   2  = soft MMU activation required for this block
313
*/
314
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
315
                             int is_write, int is_user, int is_softmmu)
316
{
317
    uint8_t *pde_ptr, *pte_ptr;
318
    uint32_t pde, pte, virt_addr, ptep;
319
    int error_code, is_dirty, prot, page_size, ret;
320
    unsigned long paddr, vaddr, page_offset;
321
    
322
#if defined(DEBUG_MMU)
323
    printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", 
324
           addr, is_write, is_user, env->eip);
325
#endif
326

    
327
    if (env->user_mode_only) {
328
        /* user mode only emulation */
329
        error_code = 0;
330
        goto do_fault;
331
    }
332

    
333
    if (!(env->cr[0] & CR0_PG_MASK)) {
334
        pte = addr;
335
        virt_addr = addr & TARGET_PAGE_MASK;
336
        prot = PAGE_READ | PAGE_WRITE;
337
        page_size = 4096;
338
        goto do_mapping;
339
    }
340

    
341
    /* page directory entry */
342
    pde_ptr = phys_ram_base + 
343
        (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
344
    pde = ldl_raw(pde_ptr);
345
    if (!(pde & PG_PRESENT_MASK)) {
346
        error_code = 0;
347
        goto do_fault;
348
    }
349
    /* if PSE bit is set, then we use a 4MB page */
350
    if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
351
        if (is_user) {
352
            if (!(pde & PG_USER_MASK))
353
                goto do_fault_protect;
354
            if (is_write && !(pde & PG_RW_MASK))
355
                goto do_fault_protect;
356
        } else {
357
            if ((env->cr[0] & CR0_WP_MASK) && 
358
                is_write && !(pde & PG_RW_MASK)) 
359
                goto do_fault_protect;
360
        }
361
        is_dirty = is_write && !(pde & PG_DIRTY_MASK);
362
        if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
363
            pde |= PG_ACCESSED_MASK;
364
            if (is_dirty)
365
                pde |= PG_DIRTY_MASK;
366
            stl_raw(pde_ptr, pde);
367
        }
368
        
369
        pte = pde & ~0x003ff000; /* align to 4MB */
370
        ptep = pte;
371
        page_size = 4096 * 1024;
372
        virt_addr = addr & ~0x003fffff;
373
    } else {
374
        if (!(pde & PG_ACCESSED_MASK)) {
375
            pde |= PG_ACCESSED_MASK;
376
            stl_raw(pde_ptr, pde);
377
        }
378

    
379
        /* page directory entry */
380
        pte_ptr = phys_ram_base + 
381
            (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
382
        pte = ldl_raw(pte_ptr);
383
        if (!(pte & PG_PRESENT_MASK)) {
384
            error_code = 0;
385
            goto do_fault;
386
        }
387
        /* combine pde and pte user and rw protections */
388
        ptep = pte & pde;
389
        if (is_user) {
390
            if (!(ptep & PG_USER_MASK))
391
                goto do_fault_protect;
392
            if (is_write && !(ptep & PG_RW_MASK))
393
                goto do_fault_protect;
394
        } else {
395
            if ((env->cr[0] & CR0_WP_MASK) &&
396
                is_write && !(ptep & PG_RW_MASK)) 
397
                goto do_fault_protect;
398
        }
399
        is_dirty = is_write && !(pte & PG_DIRTY_MASK);
400
        if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
401
            pte |= PG_ACCESSED_MASK;
402
            if (is_dirty)
403
                pte |= PG_DIRTY_MASK;
404
            stl_raw(pte_ptr, pte);
405
        }
406
        page_size = 4096;
407
        virt_addr = addr & ~0xfff;
408
    }
409

    
410
    /* the page can be put in the TLB */
411
    prot = PAGE_READ;
412
    if (pte & PG_DIRTY_MASK) {
413
        /* only set write access if already dirty... otherwise wait
414
           for dirty access */
415
        if (is_user) {
416
            if (ptep & PG_RW_MASK)
417
                prot |= PAGE_WRITE;
418
        } else {
419
            if (!(env->cr[0] & CR0_WP_MASK) ||
420
                (ptep & PG_RW_MASK))
421
                prot |= PAGE_WRITE;
422
        }
423
    }
424

    
425
 do_mapping:
426
    pte = pte & env->a20_mask;
427

    
428
    /* Even if 4MB pages, we map only one 4KB page in the cache to
429
       avoid filling it too fast */
430
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
431
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
432
    vaddr = virt_addr + page_offset;
433
    
434
    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
435
    return ret;
436
 do_fault_protect:
437
    error_code = PG_ERROR_P_MASK;
438
 do_fault:
439
    env->cr[2] = addr;
440
    env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
441
    if (is_user)
442
        env->error_code |= PG_ERROR_U_MASK;
443
    return 1;
444
}
445

    
446
#if defined(CONFIG_USER_ONLY) 
447
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
448
{
449
    return addr;
450
}
451
#else
452
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
453
{
454
    uint8_t *pde_ptr, *pte_ptr;
455
    uint32_t pde, pte, paddr, page_offset, page_size;
456

    
457
    if (!(env->cr[0] & CR0_PG_MASK)) {
458
        pte = addr;
459
        page_size = 4096;
460
    } else {
461
        /* page directory entry */
462
        pde_ptr = phys_ram_base + 
463
            (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
464
        pde = ldl_raw(pde_ptr);
465
        if (!(pde & PG_PRESENT_MASK)) 
466
            return -1;
467
        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
468
            pte = pde & ~0x003ff000; /* align to 4MB */
469
            page_size = 4096 * 1024;
470
        } else {
471
            /* page directory entry */
472
            pte_ptr = phys_ram_base + 
473
                (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
474
            pte = ldl_raw(pte_ptr);
475
            if (!(pte & PG_PRESENT_MASK))
476
                return -1;
477
            page_size = 4096;
478
        }
479
    }
480
    pte = pte & env->a20_mask;
481
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
482
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
483
    return paddr;
484
}
485
#endif
486

    
487
#if defined(USE_CODE_COPY)
488
struct fpstate {
489
    uint16_t fpuc;
490
    uint16_t dummy1;
491
    uint16_t fpus;
492
    uint16_t dummy2;
493
    uint16_t fptag;
494
    uint16_t dummy3;
495

    
496
    uint32_t fpip;
497
    uint32_t fpcs;
498
    uint32_t fpoo;
499
    uint32_t fpos;
500
    uint8_t fpregs1[8 * 10];
501
};
502

    
503
void restore_native_fp_state(CPUState *env)
504
{
505
    int fptag, i, j;
506
    struct fpstate fp1, *fp = &fp1;
507
    
508
    fp->fpuc = env->fpuc;
509
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
510
    fptag = 0;
511
    for (i=7; i>=0; i--) {
512
        fptag <<= 2;
513
        if (env->fptags[i]) {
514
            fptag |= 3;
515
        } else {
516
            /* the FPU automatically computes it */
517
        }
518
    }
519
    fp->fptag = fptag;
520
    j = env->fpstt;
521
    for(i = 0;i < 8; i++) {
522
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10);
523
        j = (j + 1) & 7;
524
    }
525
    asm volatile ("frstor %0" : "=m" (*fp));
526
    env->native_fp_regs = 1;
527
}
528
 
529
void save_native_fp_state(CPUState *env)
530
{
531
    int fptag, i, j;
532
    uint16_t fpuc;
533
    struct fpstate fp1, *fp = &fp1;
534

    
535
    asm volatile ("fsave %0" : : "m" (*fp));
536
    env->fpuc = fp->fpuc;
537
    env->fpstt = (fp->fpus >> 11) & 7;
538
    env->fpus = fp->fpus & ~0x3800;
539
    fptag = fp->fptag;
540
    for(i = 0;i < 8; i++) {
541
        env->fptags[i] = ((fptag & 3) == 3);
542
        fptag >>= 2;
543
    }
544
    j = env->fpstt;
545
    for(i = 0;i < 8; i++) {
546
        memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10);
547
        j = (j + 1) & 7;
548
    }
549
    /* we must restore the default rounding state */
550
    /* XXX: we do not restore the exception state */
551
    fpuc = 0x037f | (env->fpuc & (3 << 10));
552
    asm volatile("fldcw %0" : : "m" (fpuc));
553
    env->native_fp_regs = 0;
554
}
555
#endif