Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ 7fe48483

History | View | Annotate | Download (16 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
    static int inited;
49

    
50
    cpu_exec_init();
51

    
52
    env = malloc(sizeof(CPUX86State));
53
    if (!env)
54
        return NULL;
55
    memset(env, 0, sizeof(CPUX86State));
56
    /* init various static tables */
57
    if (!inited) {
58
        inited = 1;
59
        optimize_flags_init();
60
    }
61
#ifdef USE_CODE_COPY
62
    /* testing code for code copy case */
63
    {
64
        struct modify_ldt_ldt_s ldt;
65

    
66
        ldt.entry_number = 1;
67
        ldt.base_addr = (unsigned long)env;
68
        ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
69
        ldt.seg_32bit = 1;
70
        ldt.contents = MODIFY_LDT_CONTENTS_DATA;
71
        ldt.read_exec_only = 0;
72
        ldt.limit_in_pages = 1;
73
        ldt.seg_not_present = 0;
74
        ldt.useable = 1;
75
        modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
76
        
77
        asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
78
    }
79
#endif
80
    cpu_single_env = env;
81
    cpu_reset(env);
82
    return env;
83
}
84

    
85
/* NOTE: must be called outside the CPU execute loop */
86
void cpu_reset(CPUX86State *env)
87
{
88
    int i;
89

    
90
    memset(env, 0, offsetof(CPUX86State, breakpoints));
91

    
92
    tlb_flush(env, 1);
93

    
94
    /* init to reset state */
95

    
96
#ifdef CONFIG_SOFTMMU
97
    env->hflags |= HF_SOFTMMU_MASK;
98
#endif
99

    
100
    cpu_x86_update_cr0(env, 0x60000010);
101
    env->a20_mask = 0xffffffff;
102
    
103
    env->idt.limit = 0xffff;
104
    env->gdt.limit = 0xffff;
105
    env->ldt.limit = 0xffff;
106
    env->ldt.flags = DESC_P_MASK;
107
    env->tr.limit = 0xffff;
108
    env->tr.flags = DESC_P_MASK;
109
    
110
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0xffff0000, 0xffff, 0); 
111
    cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
112
    cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
113
    cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
114
    cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
115
    cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
116
    
117
    env->eip = 0xfff0;
118
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
119
    
120
    env->eflags = 0x2;
121
    
122
    /* FPU init */
123
    for(i = 0;i < 8; i++)
124
        env->fptags[i] = 1;
125
    env->fpuc = 0x37f;
126
}
127

    
128
void cpu_x86_close(CPUX86State *env)
129
{
130
    free(env);
131
}
132

    
133
/***********************************************************/
134
/* x86 debug */
135

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

    
171
void cpu_dump_state(CPUState *env, FILE *f, 
172
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
173
                    int flags)
174
{
175
    int eflags, i;
176
    char cc_op_name[32];
177
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
178

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

    
244
/***********************************************************/
245
/* x86 mmu */
246
/* XXX: add PGE support */
247

    
248
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
249
{
250
    a20_state = (a20_state != 0);
251
    if (a20_state != ((env->a20_mask >> 20) & 1)) {
252
#if defined(DEBUG_MMU)
253
        printf("A20 update: a20=%d\n", a20_state);
254
#endif
255
        /* if the cpu is currently executing code, we must unlink it and
256
           all the potentially executing TB */
257
        cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
258

    
259
        /* when a20 is changed, all the MMU mappings are invalid, so
260
           we must flush everything */
261
        tlb_flush(env, 1);
262
        env->a20_mask = 0xffefffff | (a20_state << 20);
263
    }
264
}
265

    
266
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
267
{
268
    int pe_state;
269

    
270
#if defined(DEBUG_MMU)
271
    printf("CR0 update: CR0=0x%08x\n", new_cr0);
272
#endif
273
    if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
274
        (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
275
        tlb_flush(env, 1);
276
    }
277
    env->cr[0] = new_cr0 | CR0_ET_MASK;
278
    
279
    /* update PE flag in hidden flags */
280
    pe_state = (env->cr[0] & CR0_PE_MASK);
281
    env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
282
    /* ensure that ADDSEG is always set in real mode */
283
    env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
284
    /* update FPU flags */
285
    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
286
        ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
287
}
288

    
289
void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3)
290
{
291
    env->cr[3] = new_cr3;
292
    if (env->cr[0] & CR0_PG_MASK) {
293
#if defined(DEBUG_MMU)
294
        printf("CR3 update: CR3=%08x\n", new_cr3);
295
#endif
296
        tlb_flush(env, 0);
297
    }
298
}
299

    
300
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
301
{
302
#if defined(DEBUG_MMU)
303
    printf("CR4 update: CR4=%08x\n", env->cr[4]);
304
#endif
305
    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
306
        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
307
        tlb_flush(env, 1);
308
    }
309
    env->cr[4] = new_cr4;
310
}
311

    
312
/* XXX: also flush 4MB pages */
313
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
314
{
315
    tlb_flush_page(env, addr);
316
}
317

    
318
/* return value:
319
   -1 = cannot handle fault 
320
   0  = nothing more to do 
321
   1  = generate PF fault
322
   2  = soft MMU activation required for this block
323
*/
324
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, 
325
                             int is_write, int is_user, int is_softmmu)
326
{
327
    uint8_t *pde_ptr, *pte_ptr;
328
    uint32_t pde, pte, virt_addr, ptep;
329
    int error_code, is_dirty, prot, page_size, ret;
330
    unsigned long paddr, vaddr, page_offset;
331
    
332
#if defined(DEBUG_MMU)
333
    printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", 
334
           addr, is_write, is_user, env->eip);
335
#endif
336
    is_write &= 1;
337
    
338
    if (env->user_mode_only) {
339
        /* user mode only emulation */
340
        error_code = 0;
341
        goto do_fault;
342
    }
343

    
344
    if (!(env->cr[0] & CR0_PG_MASK)) {
345
        pte = addr;
346
        virt_addr = addr & TARGET_PAGE_MASK;
347
        prot = PAGE_READ | PAGE_WRITE;
348
        page_size = 4096;
349
        goto do_mapping;
350
    }
351

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

    
390
        /* page directory entry */
391
        pte_ptr = phys_ram_base + 
392
            (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
393
        pte = ldl_raw(pte_ptr);
394
        if (!(pte & PG_PRESENT_MASK)) {
395
            error_code = 0;
396
            goto do_fault;
397
        }
398
        /* combine pde and pte user and rw protections */
399
        ptep = pte & pde;
400
        if (is_user) {
401
            if (!(ptep & PG_USER_MASK))
402
                goto do_fault_protect;
403
            if (is_write && !(ptep & PG_RW_MASK))
404
                goto do_fault_protect;
405
        } else {
406
            if ((env->cr[0] & CR0_WP_MASK) &&
407
                is_write && !(ptep & PG_RW_MASK)) 
408
                goto do_fault_protect;
409
        }
410
        is_dirty = is_write && !(pte & PG_DIRTY_MASK);
411
        if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
412
            pte |= PG_ACCESSED_MASK;
413
            if (is_dirty)
414
                pte |= PG_DIRTY_MASK;
415
            stl_raw(pte_ptr, pte);
416
        }
417
        page_size = 4096;
418
        virt_addr = addr & ~0xfff;
419
    }
420

    
421
    /* the page can be put in the TLB */
422
    prot = PAGE_READ;
423
    if (pte & PG_DIRTY_MASK) {
424
        /* only set write access if already dirty... otherwise wait
425
           for dirty access */
426
        if (is_user) {
427
            if (ptep & PG_RW_MASK)
428
                prot |= PAGE_WRITE;
429
        } else {
430
            if (!(env->cr[0] & CR0_WP_MASK) ||
431
                (ptep & PG_RW_MASK))
432
                prot |= PAGE_WRITE;
433
        }
434
    }
435

    
436
 do_mapping:
437
    pte = pte & env->a20_mask;
438

    
439
    /* Even if 4MB pages, we map only one 4KB page in the cache to
440
       avoid filling it too fast */
441
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
442
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
443
    vaddr = virt_addr + page_offset;
444
    
445
    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
446
    return ret;
447
 do_fault_protect:
448
    error_code = PG_ERROR_P_MASK;
449
 do_fault:
450
    env->cr[2] = addr;
451
    env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
452
    if (is_user)
453
        env->error_code |= PG_ERROR_U_MASK;
454
    return 1;
455
}
456

    
457
#if defined(CONFIG_USER_ONLY) 
458
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
459
{
460
    return addr;
461
}
462
#else
463
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
464
{
465
    uint8_t *pde_ptr, *pte_ptr;
466
    uint32_t pde, pte, paddr, page_offset, page_size;
467

    
468
    if (!(env->cr[0] & CR0_PG_MASK)) {
469
        pte = addr;
470
        page_size = 4096;
471
    } else {
472
        /* page directory entry */
473
        pde_ptr = phys_ram_base + 
474
            (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
475
        pde = ldl_raw(pde_ptr);
476
        if (!(pde & PG_PRESENT_MASK)) 
477
            return -1;
478
        if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
479
            pte = pde & ~0x003ff000; /* align to 4MB */
480
            page_size = 4096 * 1024;
481
        } else {
482
            /* page directory entry */
483
            pte_ptr = phys_ram_base + 
484
                (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
485
            pte = ldl_raw(pte_ptr);
486
            if (!(pte & PG_PRESENT_MASK))
487
                return -1;
488
            page_size = 4096;
489
        }
490
    }
491
    pte = pte & env->a20_mask;
492
    page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
493
    paddr = (pte & TARGET_PAGE_MASK) + page_offset;
494
    return paddr;
495
}
496
#endif
497

    
498
#if defined(USE_CODE_COPY)
499
struct fpstate {
500
    uint16_t fpuc;
501
    uint16_t dummy1;
502
    uint16_t fpus;
503
    uint16_t dummy2;
504
    uint16_t fptag;
505
    uint16_t dummy3;
506

    
507
    uint32_t fpip;
508
    uint32_t fpcs;
509
    uint32_t fpoo;
510
    uint32_t fpos;
511
    uint8_t fpregs1[8 * 10];
512
};
513

    
514
void restore_native_fp_state(CPUState *env)
515
{
516
    int fptag, i, j;
517
    struct fpstate fp1, *fp = &fp1;
518
    
519
    fp->fpuc = env->fpuc;
520
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
521
    fptag = 0;
522
    for (i=7; i>=0; i--) {
523
        fptag <<= 2;
524
        if (env->fptags[i]) {
525
            fptag |= 3;
526
        } else {
527
            /* the FPU automatically computes it */
528
        }
529
    }
530
    fp->fptag = fptag;
531
    j = env->fpstt;
532
    for(i = 0;i < 8; i++) {
533
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10);
534
        j = (j + 1) & 7;
535
    }
536
    asm volatile ("frstor %0" : "=m" (*fp));
537
    env->native_fp_regs = 1;
538
}
539
 
540
void save_native_fp_state(CPUState *env)
541
{
542
    int fptag, i, j;
543
    uint16_t fpuc;
544
    struct fpstate fp1, *fp = &fp1;
545

    
546
    asm volatile ("fsave %0" : : "m" (*fp));
547
    env->fpuc = fp->fpuc;
548
    env->fpstt = (fp->fpus >> 11) & 7;
549
    env->fpus = fp->fpus & ~0x3800;
550
    fptag = fp->fptag;
551
    for(i = 0;i < 8; i++) {
552
        env->fptags[i] = ((fptag & 3) == 3);
553
        fptag >>= 2;
554
    }
555
    j = env->fpstt;
556
    for(i = 0;i < 8; i++) {
557
        memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10);
558
        j = (j + 1) & 7;
559
    }
560
    /* we must restore the default rounding state */
561
    /* XXX: we do not restore the exception state */
562
    fpuc = 0x037f | (env->fpuc & (3 << 10));
563
    asm volatile("fldcw %0" : : "m" (fpuc));
564
    env->native_fp_regs = 0;
565
}
566
#endif