kqemu support
[qemu] / kqemu.c
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