source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/kqemu.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 25.1 KB
Line 
1/*
2 *  KQEMU support
3 *
4 *  Copyright (c) 2005 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 "config.h"
21#ifdef _WIN32
22#include <windows.h>
23#include <winioctl.h>
24#else
25#include <sys/types.h>
26#include <sys/mman.h>
27#include <sys/ioctl.h>
28#endif
29#include <stdlib.h>
30#include <stdio.h>
31#include <stdarg.h>
32#include <string.h>
33#include <errno.h>
34#include <unistd.h>
35#include <inttypes.h>
36
37#include "cpu.h"
38#include "exec-all.h"
39
40#ifdef USE_KQEMU
41
42#define DEBUG
43//#define PROFILE
44
45#include <unistd.h>
46#include <fcntl.h>
47#include "kqemu.h"
48
49/* compatibility stuff */
50#ifndef KQEMU_RET_SYSCALL
51#define KQEMU_RET_SYSCALL   0x0300 /* syscall insn */
52#endif
53#ifndef KQEMU_MAX_RAM_PAGES_TO_UPDATE
54#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512
55#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1)
56#endif
57#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES
58#define KQEMU_MAX_MODIFIED_RAM_PAGES 512
59#endif
60
61#ifdef _WIN32
62#define KQEMU_DEVICE "\\\\.\\kqemu"
63#else
64#define KQEMU_DEVICE "/dev/kqemu"
65#endif
66
67#ifdef _WIN32
68#define KQEMU_INVALID_FD INVALID_HANDLE_VALUE
69HANDLE kqemu_fd = KQEMU_INVALID_FD;
70#define kqemu_closefd(x) CloseHandle(x)
71#else
72#define KQEMU_INVALID_FD -1
73int kqemu_fd = KQEMU_INVALID_FD;
74#define kqemu_closefd(x) close(x)
75#endif
76
77/* 0 = not allowed
78   1 = user kqemu
79   2 = kernel kqemu
80*/
81int kqemu_allowed = 1;
82unsigned long *pages_to_flush;
83unsigned int nb_pages_to_flush;
84unsigned long *ram_pages_to_update;
85unsigned int nb_ram_pages_to_update;
86unsigned long *modified_ram_pages;
87unsigned int nb_modified_ram_pages;
88uint8_t *modified_ram_pages_table;
89extern uint32_t **l1_phys_map;
90
91#define cpuid(index, eax, ebx, ecx, edx) \
92  asm volatile ("cpuid" \
93                : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
94                : "0" (index))
95
96#ifdef __x86_64__
97static int is_cpuid_supported(void)
98{
99    return 1;
100}
101#else
102static int is_cpuid_supported(void)
103{
104    int v0, v1;
105    asm volatile ("pushf\n"
106                  "popl %0\n"
107                  "movl %0, %1\n"
108                  "xorl $0x00200000, %0\n"
109                  "pushl %0\n"
110                  "popf\n"
111                  "pushf\n"
112                  "popl %0\n"
113                  : "=a" (v0), "=d" (v1)
114                  :
115                  : "cc");
116    return (v0 != v1);
117}
118#endif
119
120static void kqemu_update_cpuid(CPUState *env)
121{
122    int critical_features_mask, features, ext_features, ext_features_mask;
123    uint32_t eax, ebx, ecx, edx;
124
125    /* the following features are kept identical on the host and
126       target cpus because they are important for user code. Strictly
127       speaking, only SSE really matters because the OS must support
128       it if the user code uses it. */
129    critical_features_mask = 
130        CPUID_CMOV | CPUID_CX8 | 
131        CPUID_FXSR | CPUID_MMX | CPUID_SSE | 
132        CPUID_SSE2 | CPUID_SEP;
133    ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR;
134    if (!is_cpuid_supported()) {
135        features = 0;
136        ext_features = 0;
137    } else {
138        cpuid(1, eax, ebx, ecx, edx);
139        features = edx;
140        ext_features = ecx;
141    }
142#ifdef __x86_64__
143    /* NOTE: on x86_64 CPUs, SYSENTER is not supported in
144       compatibility mode, so in order to have the best performances
145       it is better not to use it */
146    features &= ~CPUID_SEP;
147#endif
148    env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
149        (features & critical_features_mask);
150    env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) |
151        (ext_features & ext_features_mask);
152    /* XXX: we could update more of the target CPUID state so that the
153       non accelerated code sees exactly the same CPU features as the
154       accelerated code */
155}
156
157int kqemu_init(CPUState *env)
158{
159    struct kqemu_init init;
160    int ret, version;
161#ifdef _WIN32
162    DWORD temp;
163#endif
164
165    if (!kqemu_allowed)
166        return -1;
167
168#ifdef _WIN32
169    kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ,
170                          FILE_SHARE_READ | FILE_SHARE_WRITE,
171                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
172                          NULL);
173#else
174    kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
175#endif
176    if (kqemu_fd == KQEMU_INVALID_FD) {
177        fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
178        return -1;
179    }
180    version = 0;
181#ifdef _WIN32
182    DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
183                    &version, sizeof(version), &temp, NULL);
184#else
185    ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
186#endif
187    if (version != KQEMU_VERSION) {
188        fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
189                version, KQEMU_VERSION);
190        goto fail;
191    }
192
193    pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * 
194                                  sizeof(unsigned long));
195    if (!pages_to_flush)
196        goto fail;
197
198    ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * 
199                                       sizeof(unsigned long));
200    if (!ram_pages_to_update)
201        goto fail;
202
203    modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * 
204                                      sizeof(unsigned long));
205    if (!modified_ram_pages)
206        goto fail;
207    modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS);
208    if (!modified_ram_pages_table)
209        goto fail;
210
211    init.ram_base = phys_ram_base;
212    init.ram_size = phys_ram_size;
213    init.ram_dirty = phys_ram_dirty;
214    init.phys_to_ram_map = l1_phys_map;
215    init.pages_to_flush = pages_to_flush;
216#if KQEMU_VERSION >= 0x010200
217    init.ram_pages_to_update = ram_pages_to_update;
218#endif
219#if KQEMU_VERSION >= 0x010300
220    init.modified_ram_pages = modified_ram_pages;
221#endif
222#ifdef _WIN32
223    ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
224                          NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
225#else
226    ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
227#endif
228    if (ret < 0) {
229        fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
230    fail:
231        kqemu_closefd(kqemu_fd);
232        kqemu_fd = KQEMU_INVALID_FD;
233        return -1;
234    }
235    kqemu_update_cpuid(env);
236    env->kqemu_enabled = kqemu_allowed;
237    nb_pages_to_flush = 0;
238    nb_ram_pages_to_update = 0;
239    return 0;
240}
241
242void kqemu_flush_page(CPUState *env, target_ulong addr)
243{
244#if defined(DEBUG)
245    if (loglevel & CPU_LOG_INT) {
246        fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
247    }
248#endif
249    if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
250        nb_pages_to_flush = KQEMU_FLUSH_ALL;
251    else
252        pages_to_flush[nb_pages_to_flush++] = addr;
253}
254
255void kqemu_flush(CPUState *env, int global)
256{
257#ifdef DEBUG
258    if (loglevel & CPU_LOG_INT) {
259        fprintf(logfile, "kqemu_flush:\n");
260    }
261#endif
262    nb_pages_to_flush = KQEMU_FLUSH_ALL;
263}
264
265void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
266{
267#ifdef DEBUG
268    if (loglevel & CPU_LOG_INT) {
269        fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr);
270    }
271#endif
272    /* we only track transitions to dirty state */
273    if (phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] != 0xff)
274        return;
275    if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE)
276        nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL;
277    else
278        ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr;
279}
280
281static void kqemu_reset_modified_ram_pages(void)
282{
283    int i;
284    unsigned long page_index;
285   
286    for(i = 0; i < nb_modified_ram_pages; i++) {
287        page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS;
288        modified_ram_pages_table[page_index] = 0;
289    }
290    nb_modified_ram_pages = 0;
291}
292
293void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr)
294{
295    unsigned long page_index;
296    int ret;
297#ifdef _WIN32
298    DWORD temp;
299#endif
300
301    page_index = ram_addr >> TARGET_PAGE_BITS;
302    if (!modified_ram_pages_table[page_index]) {
303#if 0
304        printf("%d: modify_page=%08lx\n", nb_modified_ram_pages, ram_addr);
305#endif
306        modified_ram_pages_table[page_index] = 1;
307        modified_ram_pages[nb_modified_ram_pages++] = ram_addr;
308        if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) {
309            /* flush */
310#ifdef _WIN32
311            ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, 
312                                  &nb_modified_ram_pages, 
313                                  sizeof(nb_modified_ram_pages),
314                                  NULL, 0, &temp, NULL);
315#else
316            ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, 
317                        &nb_modified_ram_pages);
318#endif
319            kqemu_reset_modified_ram_pages();
320        }
321    }
322}
323
324struct fpstate {
325    uint16_t fpuc;
326    uint16_t dummy1;
327    uint16_t fpus;
328    uint16_t dummy2;
329    uint16_t fptag;
330    uint16_t dummy3;
331
332    uint32_t fpip;
333    uint32_t fpcs;
334    uint32_t fpoo;
335    uint32_t fpos;
336    uint8_t fpregs1[8 * 10];
337};
338
339struct fpxstate {
340    uint16_t fpuc;
341    uint16_t fpus;
342    uint16_t fptag;
343    uint16_t fop;
344    uint32_t fpuip;
345    uint16_t cs_sel;
346    uint16_t dummy0;
347    uint32_t fpudp;
348    uint16_t ds_sel;
349    uint16_t dummy1;
350    uint32_t mxcsr;
351    uint32_t mxcsr_mask;
352    uint8_t fpregs1[8 * 16];
353    uint8_t xmm_regs[16 * 16];
354    uint8_t dummy2[96];
355};
356
357static struct fpxstate fpx1 __attribute__((aligned(16)));
358
359static void restore_native_fp_frstor(CPUState *env)
360{
361    int fptag, i, j;
362    struct fpstate fp1, *fp = &fp1;
363   
364    fp->fpuc = env->fpuc;
365    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
366    fptag = 0;
367    for (i=7; i>=0; i--) {
368        fptag <<= 2;
369        if (env->fptags[i]) {
370            fptag |= 3;
371        } else {
372            /* the FPU automatically computes it */
373        }
374    }
375    fp->fptag = fptag;
376    j = env->fpstt;
377    for(i = 0;i < 8; i++) {
378        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
379        j = (j + 1) & 7;
380    }
381    asm volatile ("frstor %0" : "=m" (*fp));
382}
383 
384static void save_native_fp_fsave(CPUState *env)
385{
386    int fptag, i, j;
387    uint16_t fpuc;
388    struct fpstate fp1, *fp = &fp1;
389
390    asm volatile ("fsave %0" : : "m" (*fp));
391    env->fpuc = fp->fpuc;
392    env->fpstt = (fp->fpus >> 11) & 7;
393    env->fpus = fp->fpus & ~0x3800;
394    fptag = fp->fptag;
395    for(i = 0;i < 8; i++) {
396        env->fptags[i] = ((fptag & 3) == 3);
397        fptag >>= 2;
398    }
399    j = env->fpstt;
400    for(i = 0;i < 8; i++) {
401        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
402        j = (j + 1) & 7;
403    }
404    /* we must restore the default rounding state */
405    fpuc = 0x037f | (env->fpuc & (3 << 10));
406    asm volatile("fldcw %0" : : "m" (fpuc));
407}
408
409static void restore_native_fp_fxrstor(CPUState *env)
410{
411    struct fpxstate *fp = &fpx1;
412    int i, j, fptag;
413
414    fp->fpuc = env->fpuc;
415    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
416    fptag = 0;
417    for(i = 0; i < 8; i++)
418        fptag |= (env->fptags[i] << i);
419    fp->fptag = fptag ^ 0xff;
420
421    j = env->fpstt;
422    for(i = 0;i < 8; i++) {
423        memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
424        j = (j + 1) & 7;
425    }
426    if (env->cpuid_features & CPUID_SSE) {
427        fp->mxcsr = env->mxcsr;
428        /* XXX: check if DAZ is not available */
429        fp->mxcsr_mask = 0xffff;
430        memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16);
431    }
432    asm volatile ("fxrstor %0" : "=m" (*fp));
433}
434
435static void save_native_fp_fxsave(CPUState *env)
436{
437    struct fpxstate *fp = &fpx1;
438    int fptag, i, j;
439    uint16_t fpuc;
440
441    asm volatile ("fxsave %0" : : "m" (*fp));
442    env->fpuc = fp->fpuc;
443    env->fpstt = (fp->fpus >> 11) & 7;
444    env->fpus = fp->fpus & ~0x3800;
445    fptag = fp->fptag ^ 0xff;
446    for(i = 0;i < 8; i++) {
447        env->fptags[i] = (fptag >> i) & 1;
448    }
449    j = env->fpstt;
450    for(i = 0;i < 8; i++) {
451        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
452        j = (j + 1) & 7;
453    }
454    if (env->cpuid_features & CPUID_SSE) {
455        env->mxcsr = fp->mxcsr;
456        memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
457    }
458
459    /* we must restore the default rounding state */
460    asm volatile ("fninit");
461    fpuc = 0x037f | (env->fpuc & (3 << 10));
462    asm volatile("fldcw %0" : : "m" (fpuc));
463}
464
465static int do_syscall(CPUState *env,
466                      struct kqemu_cpu_state *kenv)
467{
468    int selector;
469   
470    selector = (env->star >> 32) & 0xffff;
471#ifdef __x86_64__
472    if (env->hflags & HF_LMA_MASK) {
473        env->regs[R_ECX] = kenv->next_eip;
474        env->regs[11] = env->eflags;
475
476        cpu_x86_set_cpl(env, 0);
477        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
478                               0, 0xffffffff, 
479                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
480                               DESC_S_MASK |
481                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
482        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
483                               0, 0xffffffff,
484                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
485                               DESC_S_MASK |
486                               DESC_W_MASK | DESC_A_MASK);
487        env->eflags &= ~env->fmask;
488        if (env->hflags & HF_CS64_MASK)
489            env->eip = env->lstar;
490        else
491            env->eip = env->cstar;
492    } else 
493#endif
494    {
495        env->regs[R_ECX] = (uint32_t)kenv->next_eip;
496       
497        cpu_x86_set_cpl(env, 0);
498        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
499                           0, 0xffffffff, 
500                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
501                               DESC_S_MASK |
502                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
503        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
504                               0, 0xffffffff,
505                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
506                               DESC_S_MASK |
507                               DESC_W_MASK | DESC_A_MASK);
508        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
509        env->eip = (uint32_t)env->star;
510    }
511    return 2;
512}
513
514#ifdef CONFIG_PROFILER
515
516#define PC_REC_SIZE 1
517#define PC_REC_HASH_BITS 16
518#define PC_REC_HASH_SIZE (1 << PC_REC_HASH_BITS)
519
520typedef struct PCRecord {
521    unsigned long pc;
522    int64_t count;
523    struct PCRecord *next;
524} PCRecord;
525
526static PCRecord *pc_rec_hash[PC_REC_HASH_SIZE];
527static int nb_pc_records;
528
529static void kqemu_record_pc(unsigned long pc)
530{
531    unsigned long h;
532    PCRecord **pr, *r;
533
534    h = pc / PC_REC_SIZE;
535    h = h ^ (h >> PC_REC_HASH_BITS);
536    h &= (PC_REC_HASH_SIZE - 1);
537    pr = &pc_rec_hash[h];
538    for(;;) {
539        r = *pr;
540        if (r == NULL)
541            break;
542        if (r->pc == pc) {
543            r->count++;
544            return;
545        }
546        pr = &r->next;
547    }
548    r = malloc(sizeof(PCRecord));
549    r->count = 1;
550    r->pc = pc;
551    r->next = NULL;
552    *pr = r;
553    nb_pc_records++;
554}
555
556static int pc_rec_cmp(const void *p1, const void *p2)
557{
558    PCRecord *r1 = *(PCRecord **)p1;
559    PCRecord *r2 = *(PCRecord **)p2;
560    if (r1->count < r2->count)
561        return 1;
562    else if (r1->count == r2->count)
563        return 0;
564    else
565        return -1;
566}
567
568static void kqemu_record_flush(void)
569{
570    PCRecord *r, *r_next;
571    int h;
572
573    for(h = 0; h < PC_REC_HASH_SIZE; h++) {
574        for(r = pc_rec_hash[h]; r != NULL; r = r_next) {
575            r_next = r->next;
576            free(r);
577        }
578        pc_rec_hash[h] = NULL;
579    }
580    nb_pc_records = 0;
581}
582
583void kqemu_record_dump(void)
584{
585    PCRecord **pr, *r;
586    int i, h;
587    FILE *f;
588    int64_t total, sum;
589
590    pr = malloc(sizeof(PCRecord *) * nb_pc_records);
591    i = 0;
592    total = 0;
593    for(h = 0; h < PC_REC_HASH_SIZE; h++) {
594        for(r = pc_rec_hash[h]; r != NULL; r = r->next) {
595            pr[i++] = r;
596            total += r->count;
597        }
598    }
599    qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp);
600   
601    f = fopen("/tmp/kqemu.stats", "w");
602    if (!f) {
603        perror("/tmp/kqemu.stats");
604        exit(1);
605    }
606    fprintf(f, "total: %" PRId64 "\n", total);
607    sum = 0;
608    for(i = 0; i < nb_pc_records; i++) {
609        r = pr[i];
610        sum += r->count;
611        fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", 
612                r->pc, 
613                r->count, 
614                (double)r->count / (double)total * 100.0,
615                (double)sum / (double)total * 100.0);
616    }
617    fclose(f);
618    free(pr);
619
620    kqemu_record_flush();
621}
622#endif
623
624int kqemu_cpu_exec(CPUState *env)
625{
626    struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
627    int ret, cpl, i;
628#ifdef CONFIG_PROFILER
629    int64_t ti;
630#endif
631
632#ifdef _WIN32
633    DWORD temp;
634#endif
635
636#ifdef CONFIG_PROFILER
637    ti = profile_getclock();
638#endif
639#ifdef DEBUG
640    if (loglevel & CPU_LOG_INT) {
641        fprintf(logfile, "kqemu: cpu_exec: enter\n");
642        cpu_dump_state(env, logfile, fprintf, 0);
643    }
644#endif
645    memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
646    kenv->eip = env->eip;
647    kenv->eflags = env->eflags;
648    memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
649    memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
650    memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
651    memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
652    memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
653    kenv->cr0 = env->cr[0];
654    kenv->cr2 = env->cr[2];
655    kenv->cr3 = env->cr[3];
656    kenv->cr4 = env->cr[4];
657    kenv->a20_mask = env->a20_mask;
658#if KQEMU_VERSION >= 0x010100
659    kenv->efer = env->efer;
660#endif
661#if KQEMU_VERSION >= 0x010300
662    kenv->tsc_offset = 0;
663    kenv->star = env->star;
664    kenv->sysenter_cs = env->sysenter_cs;
665    kenv->sysenter_esp = env->sysenter_esp;
666    kenv->sysenter_eip = env->sysenter_eip;
667#ifdef __x86_64__
668    kenv->lstar = env->lstar;
669    kenv->cstar = env->cstar;
670    kenv->fmask = env->fmask;
671    kenv->kernelgsbase = env->kernelgsbase;
672#endif
673#endif
674    if (env->dr[7] & 0xff) {
675        kenv->dr7 = env->dr[7];
676        kenv->dr0 = env->dr[0];
677        kenv->dr1 = env->dr[1];
678        kenv->dr2 = env->dr[2];
679        kenv->dr3 = env->dr[3];
680    } else {
681        kenv->dr7 = 0;
682    }
683    kenv->dr6 = env->dr[6];
684    cpl = (env->hflags & HF_CPL_MASK);
685    kenv->cpl = cpl;
686    kenv->nb_pages_to_flush = nb_pages_to_flush;
687#if KQEMU_VERSION >= 0x010200
688    kenv->user_only = (env->kqemu_enabled == 1);
689    kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
690#endif
691    nb_ram_pages_to_update = 0;
692   
693#if KQEMU_VERSION >= 0x010300
694    kenv->nb_modified_ram_pages = nb_modified_ram_pages;
695#endif
696    kqemu_reset_modified_ram_pages();
697
698    if (env->cpuid_features & CPUID_FXSR)
699        restore_native_fp_fxrstor(env);
700    else
701        restore_native_fp_frstor(env);
702
703#ifdef _WIN32
704    if (DeviceIoControl(kqemu_fd, KQEMU_EXEC,
705                        kenv, sizeof(struct kqemu_cpu_state),
706                        kenv, sizeof(struct kqemu_cpu_state),
707                        &temp, NULL)) {
708        ret = kenv->retval;
709    } else {
710        ret = -1;
711    }
712#else
713#if KQEMU_VERSION >= 0x010100
714    ioctl(kqemu_fd, KQEMU_EXEC, kenv);
715    ret = kenv->retval;
716#else
717    ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
718#endif
719#endif
720    if (env->cpuid_features & CPUID_FXSR)
721        save_native_fp_fxsave(env);
722    else
723        save_native_fp_fsave(env);
724
725    memcpy(env->regs, kenv->regs, sizeof(env->regs));
726    env->eip = kenv->eip;
727    env->eflags = kenv->eflags;
728    memcpy(env->segs, kenv->segs, sizeof(env->segs));
729    cpu_x86_set_cpl(env, kenv->cpl);
730    memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt));
731#if 0
732    /* no need to restore that */
733    memcpy(env->tr, kenv->tr, sizeof(env->tr));
734    memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
735    memcpy(env->idt, kenv->idt, sizeof(env->idt));
736    env->a20_mask = kenv->a20_mask;
737#endif
738    env->cr[0] = kenv->cr0;
739    env->cr[4] = kenv->cr4;
740    env->cr[3] = kenv->cr3;
741    env->cr[2] = kenv->cr2;
742    env->dr[6] = kenv->dr6;
743#if KQEMU_VERSION >= 0x010300
744#ifdef __x86_64__
745    env->kernelgsbase = kenv->kernelgsbase;
746#endif
747#endif
748
749    /* flush pages as indicated by kqemu */
750    if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) {
751        tlb_flush(env, 1);
752    } else {
753        for(i = 0; i < kenv->nb_pages_to_flush; i++) {
754            tlb_flush_page(env, pages_to_flush[i]);
755        }
756    }
757    nb_pages_to_flush = 0;
758
759#ifdef CONFIG_PROFILER
760    kqemu_time += profile_getclock() - ti;
761    kqemu_exec_count++;
762#endif
763
764#if KQEMU_VERSION >= 0x010200
765    if (kenv->nb_ram_pages_to_update > 0) {
766        cpu_tlb_update_dirty(env);
767    }
768#endif
769
770#if KQEMU_VERSION >= 0x010300
771    if (kenv->nb_modified_ram_pages > 0) {
772        for(i = 0; i < kenv->nb_modified_ram_pages; i++) {
773            unsigned long addr;
774            addr = modified_ram_pages[i];
775            tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0);
776        }
777    }
778#endif
779
780    /* restore the hidden flags */
781    {
782        unsigned int new_hflags;
783#ifdef TARGET_X86_64
784        if ((env->hflags & HF_LMA_MASK) && 
785            (env->segs[R_CS].flags & DESC_L_MASK)) {
786            /* long mode */
787            new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
788        } else
789#endif
790        {
791            /* legacy / compatibility case */
792            new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
793                >> (DESC_B_SHIFT - HF_CS32_SHIFT);
794            new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
795                >> (DESC_B_SHIFT - HF_SS32_SHIFT);
796            if (!(env->cr[0] & CR0_PE_MASK) || 
797                   (env->eflags & VM_MASK) ||
798                   !(env->hflags & HF_CS32_MASK)) {
799                /* XXX: try to avoid this test. The problem comes from the
800                   fact that is real mode or vm86 mode we only modify the
801                   'base' and 'selector' fields of the segment cache to go
802                   faster. A solution may be to force addseg to one in
803                   translate-i386.c. */
804                new_hflags |= HF_ADDSEG_MASK;
805            } else {
806                new_hflags |= ((env->segs[R_DS].base | 
807                                env->segs[R_ES].base |
808                                env->segs[R_SS].base) != 0) << 
809                    HF_ADDSEG_SHIFT;
810            }
811        }
812        env->hflags = (env->hflags & 
813           ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |
814            new_hflags;
815    }
816    /* update FPU flags */
817    env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
818        ((env->cr[0] << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
819    if (env->cr[4] & CR4_OSFXSR_MASK)
820        env->hflags |= HF_OSFXSR_MASK;
821    else
822        env->hflags &= ~HF_OSFXSR_MASK;
823       
824#ifdef DEBUG
825    if (loglevel & CPU_LOG_INT) {
826        fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
827    }
828#endif
829    if (ret == KQEMU_RET_SYSCALL) {
830        /* syscall instruction */
831        return do_syscall(env, kenv);
832    } else 
833    if ((ret & 0xff00) == KQEMU_RET_INT) {
834        env->exception_index = ret & 0xff;
835        env->error_code = 0;
836        env->exception_is_int = 1;
837        env->exception_next_eip = kenv->next_eip;
838#ifdef CONFIG_PROFILER
839        kqemu_ret_int_count++;
840#endif
841#ifdef DEBUG
842        if (loglevel & CPU_LOG_INT) {
843            fprintf(logfile, "kqemu: interrupt v=%02x:\n", 
844                    env->exception_index);
845            cpu_dump_state(env, logfile, fprintf, 0);
846        }
847#endif
848        return 1;
849    } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
850        env->exception_index = ret & 0xff;
851        env->error_code = kenv->error_code;
852        env->exception_is_int = 0;
853        env->exception_next_eip = 0;
854#ifdef CONFIG_PROFILER
855        kqemu_ret_excp_count++;
856#endif
857#ifdef DEBUG
858        if (loglevel & CPU_LOG_INT) {
859            fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
860                    env->exception_index, env->error_code);
861            cpu_dump_state(env, logfile, fprintf, 0);
862        }
863#endif
864        return 1;
865    } else if (ret == KQEMU_RET_INTR) {
866#ifdef CONFIG_PROFILER
867        kqemu_ret_intr_count++;
868#endif
869#ifdef DEBUG
870        if (loglevel & CPU_LOG_INT) {
871            cpu_dump_state(env, logfile, fprintf, 0);
872        }
873#endif
874        return 0;
875    } else if (ret == KQEMU_RET_SOFTMMU) { 
876#ifdef CONFIG_PROFILER
877        {
878            unsigned long pc = env->eip + env->segs[R_CS].base;
879            kqemu_record_pc(pc);
880        }
881#endif
882#ifdef DEBUG
883        if (loglevel & CPU_LOG_INT) {
884            cpu_dump_state(env, logfile, fprintf, 0);
885        }
886#endif
887        return 2;
888    } else {
889        cpu_dump_state(env, stderr, fprintf, 0);
890        fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
891        exit(1);
892    }
893    return 0;
894}
895
896void kqemu_cpu_interrupt(CPUState *env)
897{
898#if defined(_WIN32) && KQEMU_VERSION >= 0x010101
899    /* cancelling the I/O request causes KQEMU to finish executing the
900       current block and successfully returning. */
901    CancelIo(kqemu_fd);
902#endif
903}
904
905#endif
Note: See TracBrowser for help on using the repository browser.