Statistics
| Branch: | Revision:

root / kqemu.c @ 157777ef

History | View | Annotate | Download (11.5 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
#else
24
#include <sys/types.h>
25
#include <sys/mman.h>
26
#endif
27
#include <stdlib.h>
28
#include <stdio.h>
29
#include <stdarg.h>
30
#include <string.h>
31
#include <errno.h>
32
#include <unistd.h>
33
#include <inttypes.h>
34

    
35
#include "cpu.h"
36
#include "exec-all.h"
37

    
38
#ifdef USE_KQEMU
39

    
40
#define DEBUG
41

    
42
#include <unistd.h>
43
#include <fcntl.h>
44
#include <sys/ioctl.h>
45
#include "kqemu/kqemu.h"
46

    
47
#define KQEMU_DEVICE "/dev/kqemu"
48

    
49
int kqemu_allowed = 1;
50
int kqemu_fd = -1;
51
unsigned long *pages_to_flush;
52
unsigned int nb_pages_to_flush;
53
extern uint32_t **l1_phys_map;
54

    
55
#define cpuid(index, eax, ebx, ecx, edx) \
56
  asm volatile ("cpuid" \
57
                : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
58
                : "0" (index))
59

    
60
static int is_cpuid_supported(void)
61
{
62
    int v0, v1;
63
    asm volatile ("pushf\n"
64
                  "popl %0\n"
65
                  "movl %0, %1\n"
66
                  "xorl $0x00200000, %0\n"
67
                  "pushl %0\n"
68
                  "popf\n"
69
                  "pushf\n"
70
                  "popl %0\n"
71
                  : "=a" (v0), "=d" (v1)
72
                  :
73
                  : "cc");
74
    return (v0 != v1);
75
}
76

    
77
static void kqemu_update_cpuid(CPUState *env)
78
{
79
    int critical_features_mask, features;
80
    uint32_t eax, ebx, ecx, edx;
81

    
82
    /* the following features are kept identical on the host and
83
       target cpus because they are important for user code. Strictly
84
       speaking, only SSE really matters because the OS must support
85
       it if the user code uses it. */
86
    critical_features_mask = 
87
        CPUID_CMOV | CPUID_CX8 | 
88
        CPUID_FXSR | CPUID_MMX | CPUID_SSE | 
89
        CPUID_SSE2;
90
    if (!is_cpuid_supported()) {
91
        features = 0;
92
    } else {
93
        cpuid(1, eax, ebx, ecx, edx);
94
        features = edx;
95
    }
96
    env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
97
        (features & critical_features_mask);
98
    /* XXX: we could update more of the target CPUID state so that the
99
       non accelerated code sees exactly the same CPU features as the
100
       accelerated code */
101
}
102

    
103
int kqemu_init(CPUState *env)
104
{
105
    struct kqemu_init init;
106
    int ret, version;
107

    
108
    if (!kqemu_allowed)
109
        return -1;
110

    
111
    kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
112
    if (kqemu_fd < 0) {
113
        fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
114
        return -1;
115
    }
116
    version = 0;
117
    ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
118
    if (version != KQEMU_VERSION) {
119
        fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
120
                version, KQEMU_VERSION);
121
        goto fail;
122
    }
123

    
124
    pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * 
125
                                  sizeof(unsigned long));
126
    if (!pages_to_flush)
127
        goto fail;
128

    
129
    init.ram_base = phys_ram_base;
130
    init.ram_size = phys_ram_size;
131
    init.ram_dirty = phys_ram_dirty;
132
    init.phys_to_ram_map = l1_phys_map;
133
    init.pages_to_flush = pages_to_flush;
134
    ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
135
    if (ret < 0) {
136
        fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
137
    fail:
138
        close(kqemu_fd);
139
        kqemu_fd = -1;
140
        return -1;
141
    }
142
    kqemu_update_cpuid(env);
143
    env->kqemu_enabled = 1;
144
    nb_pages_to_flush = 0;
145
    return 0;
146
}
147

    
148
void kqemu_flush_page(CPUState *env, target_ulong addr)
149
{
150
#ifdef DEBUG
151
    if (loglevel & CPU_LOG_INT) {
152
        fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
153
    }
154
#endif
155
    if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
156
        nb_pages_to_flush = KQEMU_FLUSH_ALL;
157
    else
158
        pages_to_flush[nb_pages_to_flush++] = addr;
159
}
160

    
161
void kqemu_flush(CPUState *env, int global)
162
{
163
#ifdef DEBUG
164
    if (loglevel & CPU_LOG_INT) {
165
        fprintf(logfile, "kqemu_flush:\n");
166
    }
167
#endif
168
    nb_pages_to_flush = KQEMU_FLUSH_ALL;
169
}
170

    
171
struct fpstate {
172
    uint16_t fpuc;
173
    uint16_t dummy1;
174
    uint16_t fpus;
175
    uint16_t dummy2;
176
    uint16_t fptag;
177
    uint16_t dummy3;
178

    
179
    uint32_t fpip;
180
    uint32_t fpcs;
181
    uint32_t fpoo;
182
    uint32_t fpos;
183
    uint8_t fpregs1[8 * 10];
184
};
185

    
186
struct fpxstate {
187
    uint16_t fpuc;
188
    uint16_t fpus;
189
    uint16_t fptag;
190
    uint16_t fop;
191
    uint32_t fpuip;
192
    uint16_t cs_sel;
193
    uint16_t dummy0;
194
    uint32_t fpudp;
195
    uint16_t ds_sel;
196
    uint16_t dummy1;
197
    uint32_t mxcsr;
198
    uint32_t mxcsr_mask;
199
    uint8_t fpregs1[8 * 16];
200
    uint8_t xmm_regs[8 * 16];
201
    uint8_t dummy2[224];
202
};
203

    
204
static struct fpxstate fpx1 __attribute__((aligned(16)));
205

    
206
static void restore_native_fp_frstor(CPUState *env)
207
{
208
    int fptag, i, j;
209
    struct fpstate fp1, *fp = &fp1;
210
    
211
    fp->fpuc = env->fpuc;
212
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
213
    fptag = 0;
214
    for (i=7; i>=0; i--) {
215
        fptag <<= 2;
216
        if (env->fptags[i]) {
217
            fptag |= 3;
218
        } else {
219
            /* the FPU automatically computes it */
220
        }
221
    }
222
    fp->fptag = fptag;
223
    j = env->fpstt;
224
    for(i = 0;i < 8; i++) {
225
        memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
226
        j = (j + 1) & 7;
227
    }
228
    asm volatile ("frstor %0" : "=m" (*fp));
229
}
230
 
231
static void save_native_fp_fsave(CPUState *env)
232
{
233
    int fptag, i, j;
234
    uint16_t fpuc;
235
    struct fpstate fp1, *fp = &fp1;
236

    
237
    asm volatile ("fsave %0" : : "m" (*fp));
238
    env->fpuc = fp->fpuc;
239
    env->fpstt = (fp->fpus >> 11) & 7;
240
    env->fpus = fp->fpus & ~0x3800;
241
    fptag = fp->fptag;
242
    for(i = 0;i < 8; i++) {
243
        env->fptags[i] = ((fptag & 3) == 3);
244
        fptag >>= 2;
245
    }
246
    j = env->fpstt;
247
    for(i = 0;i < 8; i++) {
248
        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
249
        j = (j + 1) & 7;
250
    }
251
    /* we must restore the default rounding state */
252
    fpuc = 0x037f | (env->fpuc & (3 << 10));
253
    asm volatile("fldcw %0" : : "m" (fpuc));
254
}
255

    
256
static void restore_native_fp_fxrstor(CPUState *env)
257
{
258
    struct fpxstate *fp = &fpx1;
259
    int i, j, fptag;
260

    
261
    fp->fpuc = env->fpuc;
262
    fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
263
    fptag = 0;
264
    for(i = 0; i < 8; i++)
265
        fptag |= (env->fptags[i] << i);
266
    fp->fptag = fptag ^ 0xff;
267

    
268
    j = env->fpstt;
269
    for(i = 0;i < 8; i++) {
270
        memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
271
        j = (j + 1) & 7;
272
    }
273
    if (env->cpuid_features & CPUID_SSE) {
274
        fp->mxcsr = env->mxcsr;
275
        /* XXX: check if DAZ is not available */
276
        fp->mxcsr_mask = 0xffff;
277
        memcpy(fp->xmm_regs, env->xmm_regs, 8 * 16);
278
    }
279
    asm volatile ("fxrstor %0" : "=m" (*fp));
280
}
281

    
282
static void save_native_fp_fxsave(CPUState *env)
283
{
284
    struct fpxstate *fp = &fpx1;
285
    int fptag, i, j;
286
    uint16_t fpuc;
287

    
288
    asm volatile ("fxsave %0" : : "m" (*fp));
289
    env->fpuc = fp->fpuc;
290
    env->fpstt = (fp->fpus >> 11) & 7;
291
    env->fpus = fp->fpus & ~0x3800;
292
    fptag = fp->fptag ^ 0xff;
293
    for(i = 0;i < 8; i++) {
294
        env->fptags[i] = (fptag >> i) & 1;
295
    }
296
    j = env->fpstt;
297
    for(i = 0;i < 8; i++) {
298
        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
299
        j = (j + 1) & 7;
300
    }
301
    if (env->cpuid_features & CPUID_SSE) {
302
        env->mxcsr = fp->mxcsr;
303
        memcpy(env->xmm_regs, fp->xmm_regs, 8 * 16);
304
    }
305

    
306
    /* we must restore the default rounding state */
307
    asm volatile ("fninit");
308
    fpuc = 0x037f | (env->fpuc & (3 << 10));
309
    asm volatile("fldcw %0" : : "m" (fpuc));
310
}
311

    
312
int kqemu_cpu_exec(CPUState *env)
313
{
314
    struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
315
    int ret;
316

    
317
#ifdef DEBUG
318
    if (loglevel & CPU_LOG_INT) {
319
        fprintf(logfile, "kqemu: cpu_exec: enter\n");
320
        cpu_dump_state(env, logfile, fprintf, 0);
321
    }
322
#endif
323
    memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
324
    kenv->eip = env->eip;
325
    kenv->eflags = env->eflags;
326
    memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
327
    memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
328
    memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
329
    memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
330
    memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
331
    kenv->cr0 = env->cr[0];
332
    kenv->cr2 = env->cr[2];
333
    kenv->cr3 = env->cr[3];
334
    kenv->cr4 = env->cr[4];
335
    kenv->a20_mask = env->a20_mask;
336
    if (env->dr[7] & 0xff) {
337
        kenv->dr7 = env->dr[7];
338
        kenv->dr0 = env->dr[0];
339
        kenv->dr1 = env->dr[1];
340
        kenv->dr2 = env->dr[2];
341
        kenv->dr3 = env->dr[3];
342
    } else {
343
        kenv->dr7 = 0;
344
    }
345
    kenv->dr6 = env->dr[6];
346
    kenv->cpl = 3;
347
    kenv->nb_pages_to_flush = nb_pages_to_flush;
348
    nb_pages_to_flush = 0;
349
    
350
    if (!(kenv->cr0 & CR0_TS_MASK)) {
351
        if (env->cpuid_features & CPUID_FXSR)
352
            restore_native_fp_fxrstor(env);
353
        else
354
            restore_native_fp_frstor(env);
355
    }
356

    
357
    ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
358

    
359
    if (!(kenv->cr0 & CR0_TS_MASK)) {
360
        if (env->cpuid_features & CPUID_FXSR)
361
            save_native_fp_fxsave(env);
362
        else
363
            save_native_fp_fsave(env);
364
    }
365

    
366
    memcpy(env->regs, kenv->regs, sizeof(env->regs));
367
    env->eip = kenv->eip;
368
    env->eflags = kenv->eflags;
369
    memcpy(env->segs, kenv->segs, sizeof(env->segs));
370
#if 0
371
    /* no need to restore that */
372
    memcpy(env->ldt, kenv->ldt, sizeof(env->ldt));
373
    memcpy(env->tr, kenv->tr, sizeof(env->tr));
374
    memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
375
    memcpy(env->idt, kenv->idt, sizeof(env->idt));
376
    env->cr[0] = kenv->cr0;
377
    env->cr[3] = kenv->cr3;
378
    env->cr[4] = kenv->cr4;
379
    env->a20_mask = kenv->a20_mask;
380
#endif
381
    env->cr[2] = kenv->cr2;
382
    env->dr[6] = kenv->dr6;
383

    
384
#ifdef DEBUG
385
    if (loglevel & CPU_LOG_INT) {
386
        fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
387
    }
388
#endif
389
    if ((ret & 0xff00) == KQEMU_RET_INT) {
390
        env->exception_index = ret & 0xff;
391
        env->error_code = 0;
392
        env->exception_is_int = 1;
393
        env->exception_next_eip = kenv->next_eip;
394
#ifdef DEBUG
395
    if (loglevel & CPU_LOG_INT) {
396
        fprintf(logfile, "kqemu: interrupt v=%02x:\n", 
397
                env->exception_index);
398
        cpu_dump_state(env, logfile, fprintf, 0);
399
    }
400
#endif
401
        return 1;
402
    } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
403
        env->exception_index = ret & 0xff;
404
        env->error_code = kenv->error_code;
405
        env->exception_is_int = 0;
406
        env->exception_next_eip = 0;
407
#ifdef DEBUG
408
        if (loglevel & CPU_LOG_INT) {
409
            fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
410
                    env->exception_index, env->error_code);
411
            cpu_dump_state(env, logfile, fprintf, 0);
412
        }
413
#endif
414
        return 1;
415
    } else if (ret == KQEMU_RET_INTR) {
416
        return 0;
417
    } else if (ret == KQEMU_RET_SOFTMMU) { 
418
        return 2;
419
    } else {
420
        cpu_dump_state(env, stderr, fprintf, 0);
421
        fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
422
        exit(1);
423
    }
424
    return 0;
425
}
426

    
427
#endif