Statistics
| Branch: | Revision:

root / target-i386 / helper2.c @ ffddfee3

History | View | Annotate | Download (15.9 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
        cpu_single_env = env;
79
    }
80
#endif
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
    /* not correct (CS base=0xffff0000) */
111
    cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); 
112
    cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0);
113
    cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0);
114
    cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0);
115
    cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0);
116
    cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0);
117
    
118
    env->eip = 0xfff0;
119
    env->regs[R_EDX] = 0x600; /* indicate P6 processor */
120
    
121
    env->eflags = 0x2;
122
    
123
    /* FPU init */
124
    for(i = 0;i < 8; i++)
125
        env->fptags[i] = 1;
126
    env->fpuc = 0x37f;
127
}
128

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

    
134
/***********************************************************/
135
/* x86 debug */
136

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

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

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

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

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

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

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

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

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

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

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

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

    
336
    if (env->user_mode_only) {
337
        /* user mode only emulation */
338
        error_code = 0;
339
        goto do_fault;
340
    }
341

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

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

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

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

    
434
 do_mapping:
435
    pte = pte & env->a20_mask;
436

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

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

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

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

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

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

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