Statistics
| Branch: | Revision:

root / kqemu.c @ c45b3c0e

History | View | Annotate | Download (15.2 kB)

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

    
44
#include <unistd.h>
45
#include <fcntl.h>
46
#include "kqemu/kqemu.h"
47

    
48
/* compatibility stuff */
49
#ifndef KQEMU_RET_SYSCALL
50
#define KQEMU_RET_SYSCALL   0x0300 /* syscall insn */
51
#endif
52

    
53
#ifdef _WIN32
54
#define KQEMU_DEVICE "\\\\.\\kqemu"
55
#else
56
#define KQEMU_DEVICE "/dev/kqemu"
57
#endif
58

    
59
#ifdef _WIN32
60
#define KQEMU_INVALID_FD INVALID_HANDLE_VALUE
61
HANDLE kqemu_fd = KQEMU_INVALID_FD;
62
#define kqemu_closefd(x) CloseHandle(x)
63
#else
64
#define KQEMU_INVALID_FD -1
65
int kqemu_fd = KQEMU_INVALID_FD;
66
#define kqemu_closefd(x) close(x)
67
#endif
68

    
69
int kqemu_allowed = 1;
70
unsigned long *pages_to_flush;
71
unsigned int nb_pages_to_flush;
72
extern uint32_t **l1_phys_map;
73

    
74
#define cpuid(index, eax, ebx, ecx, edx) \
75
  asm volatile ("cpuid" \
76
                : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
77
                : "0" (index))
78

    
79
#ifdef __x86_64__
80
static int is_cpuid_supported(void)
81
{
82
    return 1;
83
}
84
#else
85
static int is_cpuid_supported(void)
86
{
87
    int v0, v1;
88
    asm volatile ("pushf\n"
89
                  "popl %0\n"
90
                  "movl %0, %1\n"
91
                  "xorl $0x00200000, %0\n"
92
                  "pushl %0\n"
93
                  "popf\n"
94
                  "pushf\n"
95
                  "popl %0\n"
96
                  : "=a" (v0), "=d" (v1)
97
                  :
98
                  : "cc");
99
    return (v0 != v1);
100
}
101
#endif
102

    
103
static void kqemu_update_cpuid(CPUState *env)
104
{
105
    int critical_features_mask, features;
106
    uint32_t eax, ebx, ecx, edx;
107

    
108
    /* the following features are kept identical on the host and
109
       target cpus because they are important for user code. Strictly
110
       speaking, only SSE really matters because the OS must support
111
       it if the user code uses it. */
112
    critical_features_mask = 
113
        CPUID_CMOV | CPUID_CX8 | 
114
        CPUID_FXSR | CPUID_MMX | CPUID_SSE | 
115
        CPUID_SSE2;
116
    if (!is_cpuid_supported()) {
117
        features = 0;
118
    } else {
119
        cpuid(1, eax, ebx, ecx, edx);
120
        features = edx;
121
    }
122
    env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
123
        (features & critical_features_mask);
124
    /* XXX: we could update more of the target CPUID state so that the
125
       non accelerated code sees exactly the same CPU features as the
126
       accelerated code */
127
}
128

    
129
int kqemu_init(CPUState *env)
130
{
131
    struct kqemu_init init;
132
    int ret, version;
133
#ifdef _WIN32
134
    DWORD temp;
135
#endif
136

    
137
    if (!kqemu_allowed)
138
        return -1;
139

    
140
#ifdef _WIN32
141
    kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ,
142
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
143
                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
144
                          NULL);
145
#else
146
    kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
147
#endif
148
    if (kqemu_fd == KQEMU_INVALID_FD) {
149
        fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
150
        return -1;
151
    }
152
    version = 0;
153
#ifdef _WIN32
154
    DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
155
                    &version, sizeof(version), &temp, NULL);
156
#else
157
    ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
158
#endif
159
    if (version != KQEMU_VERSION) {
160
        fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
161
                version, KQEMU_VERSION);
162
        goto fail;
163
    }
164

    
165
    pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * 
166
                                  sizeof(unsigned long));
167
    if (!pages_to_flush)
168
        goto fail;
169

    
170
    init.ram_base = phys_ram_base;
171
    init.ram_size = phys_ram_size;
172
    init.ram_dirty = phys_ram_dirty;
173
    init.phys_to_ram_map = l1_phys_map;
174
    init.pages_to_flush = pages_to_flush;
175
#ifdef _WIN32
176
    ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
177
                          NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
178
#else
179
    ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
180
#endif
181
    if (ret < 0) {
182
        fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
183
    fail:
184
        kqemu_closefd(kqemu_fd);
185
        kqemu_fd = KQEMU_INVALID_FD;
186
        return -1;
187
    }
188
    kqemu_update_cpuid(env);
189
    env->kqemu_enabled = 1;
190
    nb_pages_to_flush = 0;
191
    return 0;
192
}
193

    
194
void kqemu_flush_page(CPUState *env, target_ulong addr)
195
{
196
#ifdef DEBUG
197
    if (loglevel & CPU_LOG_INT) {
198
        fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
199
    }
200
#endif
201
    if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
202
        nb_pages_to_flush = KQEMU_FLUSH_ALL;
203
    else
204
        pages_to_flush[nb_pages_to_flush++] = addr;
205
}
206

    
207
void kqemu_flush(CPUState *env, int global)
208
{
209
#ifdef DEBUG
210
    if (loglevel & CPU_LOG_INT) {
211
        fprintf(logfile, "kqemu_flush:\n");
212
    }
213
#endif
214
    nb_pages_to_flush = KQEMU_FLUSH_ALL;
215
}
216

    
217
struct fpstate {
218
    uint16_t fpuc;
219
    uint16_t dummy1;
220
    uint16_t fpus;
221
    uint16_t dummy2;
222
    uint16_t fptag;
223
    uint16_t dummy3;
224

    
225
    uint32_t fpip;
226
    uint32_t fpcs;
227
    uint32_t fpoo;
228
    uint32_t fpos;
229
    uint8_t fpregs1[8 * 10];
230
};
231

    
232
struct fpxstate {
233
    uint16_t fpuc;
234
    uint16_t fpus;
235
    uint16_t fptag;
236
    uint16_t fop;
237
    uint32_t fpuip;
238
    uint16_t cs_sel;
239
    uint16_t dummy0;
240
    uint32_t fpudp;
241
    uint16_t ds_sel;
242
    uint16_t dummy1;
243
    uint32_t mxcsr;
244
    uint32_t mxcsr_mask;
245
    uint8_t fpregs1[8 * 16];
246
    uint8_t xmm_regs[16 * 16];
247
    uint8_t dummy2[96];
248
};
249

    
250
static struct fpxstate fpx1 __attribute__((aligned(16)));
251

    
252
static void restore_native_fp_frstor(CPUState *env)
253
{
254
    int fptag, i, j;
255
    struct fpstate fp1, *fp = &fp1;
256
    
257
    fp->fpuc = env->fpuc;
258
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
259
    fptag = 0;
260
    for (i=7; i>=0; i--) {
261
        fptag <<= 2;
262
        if (env->fptags[i]) {
263
            fptag |= 3;
264
        } else {
265
            /* the FPU automatically computes it */
266
        }
267
    }
268
    fp->fptag = fptag;
269
    j = env->fpstt;
270
    for(i = 0;i < 8; i++) {
271
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
272
        j = (j + 1) & 7;
273
    }
274
    asm volatile ("frstor %0" : "=m" (*fp));
275
}
276
 
277
static void save_native_fp_fsave(CPUState *env)
278
{
279
    int fptag, i, j;
280
    uint16_t fpuc;
281
    struct fpstate fp1, *fp = &fp1;
282

    
283
    asm volatile ("fsave %0" : : "m" (*fp));
284
    env->fpuc = fp->fpuc;
285
    env->fpstt = (fp->fpus >> 11) & 7;
286
    env->fpus = fp->fpus & ~0x3800;
287
    fptag = fp->fptag;
288
    for(i = 0;i < 8; i++) {
289
        env->fptags[i] = ((fptag & 3) == 3);
290
        fptag >>= 2;
291
    }
292
    j = env->fpstt;
293
    for(i = 0;i < 8; i++) {
294
        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
295
        j = (j + 1) & 7;
296
    }
297
    /* we must restore the default rounding state */
298
    fpuc = 0x037f | (env->fpuc & (3 << 10));
299
    asm volatile("fldcw %0" : : "m" (fpuc));
300
}
301

    
302
static void restore_native_fp_fxrstor(CPUState *env)
303
{
304
    struct fpxstate *fp = &fpx1;
305
    int i, j, fptag;
306

    
307
    fp->fpuc = env->fpuc;
308
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
309
    fptag = 0;
310
    for(i = 0; i < 8; i++)
311
        fptag |= (env->fptags[i] << i);
312
    fp->fptag = fptag ^ 0xff;
313

    
314
    j = env->fpstt;
315
    for(i = 0;i < 8; i++) {
316
        memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
317
        j = (j + 1) & 7;
318
    }
319
    if (env->cpuid_features & CPUID_SSE) {
320
        fp->mxcsr = env->mxcsr;
321
        /* XXX: check if DAZ is not available */
322
        fp->mxcsr_mask = 0xffff;
323
        memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16);
324
    }
325
    asm volatile ("fxrstor %0" : "=m" (*fp));
326
}
327

    
328
static void save_native_fp_fxsave(CPUState *env)
329
{
330
    struct fpxstate *fp = &fpx1;
331
    int fptag, i, j;
332
    uint16_t fpuc;
333

    
334
    asm volatile ("fxsave %0" : : "m" (*fp));
335
    env->fpuc = fp->fpuc;
336
    env->fpstt = (fp->fpus >> 11) & 7;
337
    env->fpus = fp->fpus & ~0x3800;
338
    fptag = fp->fptag ^ 0xff;
339
    for(i = 0;i < 8; i++) {
340
        env->fptags[i] = (fptag >> i) & 1;
341
    }
342
    j = env->fpstt;
343
    for(i = 0;i < 8; i++) {
344
        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
345
        j = (j + 1) & 7;
346
    }
347
    if (env->cpuid_features & CPUID_SSE) {
348
        env->mxcsr = fp->mxcsr;
349
        memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
350
    }
351

    
352
    /* we must restore the default rounding state */
353
    asm volatile ("fninit");
354
    fpuc = 0x037f | (env->fpuc & (3 << 10));
355
    asm volatile("fldcw %0" : : "m" (fpuc));
356
}
357

    
358
static int do_syscall(CPUState *env,
359
                      struct kqemu_cpu_state *kenv)
360
{
361
    int selector;
362
    
363
    selector = (env->star >> 32) & 0xffff;
364
#ifdef __x86_64__
365
    if (env->hflags & HF_LMA_MASK) {
366
        env->regs[R_ECX] = kenv->next_eip;
367
        env->regs[11] = env->eflags;
368

    
369
        cpu_x86_set_cpl(env, 0);
370
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
371
                               0, 0xffffffff, 
372
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
373
                               DESC_S_MASK |
374
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
375
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
376
                               0, 0xffffffff,
377
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
378
                               DESC_S_MASK |
379
                               DESC_W_MASK | DESC_A_MASK);
380
        env->eflags &= ~env->fmask;
381
        if (env->hflags & HF_CS64_MASK)
382
            env->eip = env->lstar;
383
        else
384
            env->eip = env->cstar;
385
    } else 
386
#endif
387
    {
388
        env->regs[R_ECX] = (uint32_t)kenv->next_eip;
389
        
390
        cpu_x86_set_cpl(env, 0);
391
        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
392
                           0, 0xffffffff, 
393
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
394
                               DESC_S_MASK |
395
                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
396
        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
397
                               0, 0xffffffff,
398
                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
399
                               DESC_S_MASK |
400
                               DESC_W_MASK | DESC_A_MASK);
401
        env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
402
        env->eip = (uint32_t)env->star;
403
    }
404
    return 2;
405
}
406

    
407
int kqemu_cpu_exec(CPUState *env)
408
{
409
    struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
410
    int ret;
411
#ifdef _WIN32
412
    DWORD temp;
413
#endif
414

    
415
#ifdef DEBUG
416
    if (loglevel & CPU_LOG_INT) {
417
        fprintf(logfile, "kqemu: cpu_exec: enter\n");
418
        cpu_dump_state(env, logfile, fprintf, 0);
419
    }
420
#endif
421
    memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
422
    kenv->eip = env->eip;
423
    kenv->eflags = env->eflags;
424
    memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
425
    memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
426
    memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
427
    memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
428
    memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
429
    kenv->cr0 = env->cr[0];
430
    kenv->cr2 = env->cr[2];
431
    kenv->cr3 = env->cr[3];
432
    kenv->cr4 = env->cr[4];
433
    kenv->a20_mask = env->a20_mask;
434
#if KQEMU_VERSION >= 0x010100
435
    kenv->efer = env->efer;
436
#endif
437
    if (env->dr[7] & 0xff) {
438
        kenv->dr7 = env->dr[7];
439
        kenv->dr0 = env->dr[0];
440
        kenv->dr1 = env->dr[1];
441
        kenv->dr2 = env->dr[2];
442
        kenv->dr3 = env->dr[3];
443
    } else {
444
        kenv->dr7 = 0;
445
    }
446
    kenv->dr6 = env->dr[6];
447
    kenv->cpl = 3;
448
    kenv->nb_pages_to_flush = nb_pages_to_flush;
449
    nb_pages_to_flush = 0;
450
    
451
    if (!(kenv->cr0 & CR0_TS_MASK)) {
452
        if (env->cpuid_features & CPUID_FXSR)
453
            restore_native_fp_fxrstor(env);
454
        else
455
            restore_native_fp_frstor(env);
456
    }
457

    
458
#ifdef _WIN32
459
    DeviceIoControl(kqemu_fd, KQEMU_EXEC,
460
                    kenv, sizeof(struct kqemu_cpu_state),
461
                    kenv, sizeof(struct kqemu_cpu_state),
462
                    &temp, NULL);
463
    ret = kenv->retval;
464
#else
465
#if KQEMU_VERSION >= 0x010100
466
    ioctl(kqemu_fd, KQEMU_EXEC, kenv);
467
    ret = kenv->retval;
468
#else
469
    ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
470
#endif
471
#endif
472
    if (!(kenv->cr0 & CR0_TS_MASK)) {
473
        if (env->cpuid_features & CPUID_FXSR)
474
            save_native_fp_fxsave(env);
475
        else
476
            save_native_fp_fsave(env);
477
    }
478

    
479
    memcpy(env->regs, kenv->regs, sizeof(env->regs));
480
    env->eip = kenv->eip;
481
    env->eflags = kenv->eflags;
482
    memcpy(env->segs, kenv->segs, sizeof(env->segs));
483
#if 0
484
    /* no need to restore that */
485
    memcpy(env->ldt, kenv->ldt, sizeof(env->ldt));
486
    memcpy(env->tr, kenv->tr, sizeof(env->tr));
487
    memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
488
    memcpy(env->idt, kenv->idt, sizeof(env->idt));
489
    env->cr[0] = kenv->cr0;
490
    env->cr[3] = kenv->cr3;
491
    env->cr[4] = kenv->cr4;
492
    env->a20_mask = kenv->a20_mask;
493
#endif
494
    env->cr[2] = kenv->cr2;
495
    env->dr[6] = kenv->dr6;
496

    
497
#ifdef DEBUG
498
    if (loglevel & CPU_LOG_INT) {
499
        fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
500
    }
501
#endif
502
    if (ret == KQEMU_RET_SYSCALL) {
503
        /* syscall instruction */
504
        return do_syscall(env, kenv);
505
    } else 
506
    if ((ret & 0xff00) == KQEMU_RET_INT) {
507
        env->exception_index = ret & 0xff;
508
        env->error_code = 0;
509
        env->exception_is_int = 1;
510
        env->exception_next_eip = kenv->next_eip;
511
#ifdef DEBUG
512
        if (loglevel & CPU_LOG_INT) {
513
            fprintf(logfile, "kqemu: interrupt v=%02x:\n", 
514
                    env->exception_index);
515
            cpu_dump_state(env, logfile, fprintf, 0);
516
        }
517
#endif
518
        return 1;
519
    } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
520
        env->exception_index = ret & 0xff;
521
        env->error_code = kenv->error_code;
522
        env->exception_is_int = 0;
523
        env->exception_next_eip = 0;
524
#ifdef DEBUG
525
        if (loglevel & CPU_LOG_INT) {
526
            fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
527
                    env->exception_index, env->error_code);
528
            cpu_dump_state(env, logfile, fprintf, 0);
529
        }
530
#endif
531
        return 1;
532
    } else if (ret == KQEMU_RET_INTR) {
533
#ifdef DEBUG
534
        if (loglevel & CPU_LOG_INT) {
535
            cpu_dump_state(env, logfile, fprintf, 0);
536
        }
537
#endif
538
        return 0;
539
    } else if (ret == KQEMU_RET_SOFTMMU) { 
540
        return 2;
541
    } else {
542
        cpu_dump_state(env, stderr, fprintf, 0);
543
        fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
544
        exit(1);
545
    }
546
    return 0;
547
}
548

    
549
#endif