windows support for kqemu (Filip Navara)
[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 #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 #ifdef _WIN32
49 #define KQEMU_DEVICE "\\\\.\\kqemu"
50 #else
51 #define KQEMU_DEVICE "/dev/kqemu"
52 #endif
53
54 #ifdef _WIN32
55 #define KQEMU_INVALID_FD INVALID_HANDLE_VALUE
56 HANDLE kqemu_fd = KQEMU_INVALID_FD;
57 #define kqemu_closefd(x) CloseHandle(x)
58 #else
59 #define KQEMU_INVALID_FD -1
60 int kqemu_fd = KQEMU_INVALID_FD;
61 #define kqemu_closefd(x) close(x)
62 #endif
63
64 int kqemu_allowed = 1;
65 unsigned long *pages_to_flush;
66 unsigned int nb_pages_to_flush;
67 extern uint32_t **l1_phys_map;
68
69 #define cpuid(index, eax, ebx, ecx, edx) \
70   asm volatile ("cpuid" \
71                 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
72                 : "0" (index))
73
74 static int is_cpuid_supported(void)
75 {
76     int v0, v1;
77     asm volatile ("pushf\n"
78                   "popl %0\n"
79                   "movl %0, %1\n"
80                   "xorl $0x00200000, %0\n"
81                   "pushl %0\n"
82                   "popf\n"
83                   "pushf\n"
84                   "popl %0\n"
85                   : "=a" (v0), "=d" (v1)
86                   :
87                   : "cc");
88     return (v0 != v1);
89 }
90
91 static void kqemu_update_cpuid(CPUState *env)
92 {
93     int critical_features_mask, features;
94     uint32_t eax, ebx, ecx, edx;
95
96     /* the following features are kept identical on the host and
97        target cpus because they are important for user code. Strictly
98        speaking, only SSE really matters because the OS must support
99        it if the user code uses it. */
100     critical_features_mask = 
101         CPUID_CMOV | CPUID_CX8 | 
102         CPUID_FXSR | CPUID_MMX | CPUID_SSE | 
103         CPUID_SSE2;
104     if (!is_cpuid_supported()) {
105         features = 0;
106     } else {
107         cpuid(1, eax, ebx, ecx, edx);
108         features = edx;
109     }
110     env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
111         (features & critical_features_mask);
112     /* XXX: we could update more of the target CPUID state so that the
113        non accelerated code sees exactly the same CPU features as the
114        accelerated code */
115 }
116
117 int kqemu_init(CPUState *env)
118 {
119     struct kqemu_init init;
120     int ret, version;
121 #ifdef _WIN32
122     DWORD temp;
123 #endif
124
125     if (!kqemu_allowed)
126         return -1;
127
128 #ifdef _WIN32
129     kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ,
130                           FILE_SHARE_READ | FILE_SHARE_WRITE,
131                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
132                           NULL);
133 #else
134     kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
135 #endif
136     if (kqemu_fd == KQEMU_INVALID_FD) {
137         fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
138         return -1;
139     }
140     version = 0;
141 #ifdef _WIN32
142     DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
143                     &version, sizeof(version), &temp, NULL);
144 #else
145     ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
146 #endif
147     if (version != KQEMU_VERSION) {
148         fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
149                 version, KQEMU_VERSION);
150         goto fail;
151     }
152
153     pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * 
154                                   sizeof(unsigned long));
155     if (!pages_to_flush)
156         goto fail;
157
158     init.ram_base = phys_ram_base;
159     init.ram_size = phys_ram_size;
160     init.ram_dirty = phys_ram_dirty;
161     init.phys_to_ram_map = l1_phys_map;
162     init.pages_to_flush = pages_to_flush;
163 #ifdef _WIN32
164     ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
165                           NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
166 #else
167     ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
168 #endif
169     if (ret < 0) {
170         fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
171     fail:
172         kqemu_closefd(kqemu_fd);
173         kqemu_fd = KQEMU_INVALID_FD;
174         return -1;
175     }
176     kqemu_update_cpuid(env);
177     env->kqemu_enabled = 1;
178     nb_pages_to_flush = 0;
179     return 0;
180 }
181
182 void kqemu_flush_page(CPUState *env, target_ulong addr)
183 {
184 #ifdef DEBUG
185     if (loglevel & CPU_LOG_INT) {
186         fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
187     }
188 #endif
189     if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
190         nb_pages_to_flush = KQEMU_FLUSH_ALL;
191     else
192         pages_to_flush[nb_pages_to_flush++] = addr;
193 }
194
195 void kqemu_flush(CPUState *env, int global)
196 {
197 #ifdef DEBUG
198     if (loglevel & CPU_LOG_INT) {
199         fprintf(logfile, "kqemu_flush:\n");
200     }
201 #endif
202     nb_pages_to_flush = KQEMU_FLUSH_ALL;
203 }
204
205 struct fpstate {
206     uint16_t fpuc;
207     uint16_t dummy1;
208     uint16_t fpus;
209     uint16_t dummy2;
210     uint16_t fptag;
211     uint16_t dummy3;
212
213     uint32_t fpip;
214     uint32_t fpcs;
215     uint32_t fpoo;
216     uint32_t fpos;
217     uint8_t fpregs1[8 * 10];
218 };
219
220 struct fpxstate {
221     uint16_t fpuc;
222     uint16_t fpus;
223     uint16_t fptag;
224     uint16_t fop;
225     uint32_t fpuip;
226     uint16_t cs_sel;
227     uint16_t dummy0;
228     uint32_t fpudp;
229     uint16_t ds_sel;
230     uint16_t dummy1;
231     uint32_t mxcsr;
232     uint32_t mxcsr_mask;
233     uint8_t fpregs1[8 * 16];
234     uint8_t xmm_regs[8 * 16];
235     uint8_t dummy2[224];
236 };
237
238 static struct fpxstate fpx1 __attribute__((aligned(16)));
239
240 static void restore_native_fp_frstor(CPUState *env)
241 {
242     int fptag, i, j;
243     struct fpstate fp1, *fp = &fp1;
244     
245     fp->fpuc = env->fpuc;
246     fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
247     fptag = 0;
248     for (i=7; i>=0; i--) {
249         fptag <<= 2;
250         if (env->fptags[i]) {
251             fptag |= 3;
252         } else {
253             /* the FPU automatically computes it */
254         }
255     }
256     fp->fptag = fptag;
257     j = env->fpstt;
258     for(i = 0;i < 8; i++) {
259         memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
260         j = (j + 1) & 7;
261     }
262     asm volatile ("frstor %0" : "=m" (*fp));
263 }
264  
265 static void save_native_fp_fsave(CPUState *env)
266 {
267     int fptag, i, j;
268     uint16_t fpuc;
269     struct fpstate fp1, *fp = &fp1;
270
271     asm volatile ("fsave %0" : : "m" (*fp));
272     env->fpuc = fp->fpuc;
273     env->fpstt = (fp->fpus >> 11) & 7;
274     env->fpus = fp->fpus & ~0x3800;
275     fptag = fp->fptag;
276     for(i = 0;i < 8; i++) {
277         env->fptags[i] = ((fptag & 3) == 3);
278         fptag >>= 2;
279     }
280     j = env->fpstt;
281     for(i = 0;i < 8; i++) {
282         memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
283         j = (j + 1) & 7;
284     }
285     /* we must restore the default rounding state */
286     fpuc = 0x037f | (env->fpuc & (3 << 10));
287     asm volatile("fldcw %0" : : "m" (fpuc));
288 }
289
290 static void restore_native_fp_fxrstor(CPUState *env)
291 {
292     struct fpxstate *fp = &fpx1;
293     int i, j, fptag;
294
295     fp->fpuc = env->fpuc;
296     fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
297     fptag = 0;
298     for(i = 0; i < 8; i++)
299         fptag |= (env->fptags[i] << i);
300     fp->fptag = fptag ^ 0xff;
301
302     j = env->fpstt;
303     for(i = 0;i < 8; i++) {
304         memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
305         j = (j + 1) & 7;
306     }
307     if (env->cpuid_features & CPUID_SSE) {
308         fp->mxcsr = env->mxcsr;
309         /* XXX: check if DAZ is not available */
310         fp->mxcsr_mask = 0xffff;
311         memcpy(fp->xmm_regs, env->xmm_regs, 8 * 16);
312     }
313     asm volatile ("fxrstor %0" : "=m" (*fp));
314 }
315
316 static void save_native_fp_fxsave(CPUState *env)
317 {
318     struct fpxstate *fp = &fpx1;
319     int fptag, i, j;
320     uint16_t fpuc;
321
322     asm volatile ("fxsave %0" : : "m" (*fp));
323     env->fpuc = fp->fpuc;
324     env->fpstt = (fp->fpus >> 11) & 7;
325     env->fpus = fp->fpus & ~0x3800;
326     fptag = fp->fptag ^ 0xff;
327     for(i = 0;i < 8; i++) {
328         env->fptags[i] = (fptag >> i) & 1;
329     }
330     j = env->fpstt;
331     for(i = 0;i < 8; i++) {
332         memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
333         j = (j + 1) & 7;
334     }
335     if (env->cpuid_features & CPUID_SSE) {
336         env->mxcsr = fp->mxcsr;
337         memcpy(env->xmm_regs, fp->xmm_regs, 8 * 16);
338     }
339
340     /* we must restore the default rounding state */
341     asm volatile ("fninit");
342     fpuc = 0x037f | (env->fpuc & (3 << 10));
343     asm volatile("fldcw %0" : : "m" (fpuc));
344 }
345
346 int kqemu_cpu_exec(CPUState *env)
347 {
348     struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
349     int ret;
350 #ifdef _WIN32
351     DWORD temp;
352 #endif
353
354 #ifdef DEBUG
355     if (loglevel & CPU_LOG_INT) {
356         fprintf(logfile, "kqemu: cpu_exec: enter\n");
357         cpu_dump_state(env, logfile, fprintf, 0);
358     }
359 #endif
360     memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
361     kenv->eip = env->eip;
362     kenv->eflags = env->eflags;
363     memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
364     memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
365     memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
366     memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
367     memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
368     kenv->cr0 = env->cr[0];
369     kenv->cr2 = env->cr[2];
370     kenv->cr3 = env->cr[3];
371     kenv->cr4 = env->cr[4];
372     kenv->a20_mask = env->a20_mask;
373     if (env->dr[7] & 0xff) {
374         kenv->dr7 = env->dr[7];
375         kenv->dr0 = env->dr[0];
376         kenv->dr1 = env->dr[1];
377         kenv->dr2 = env->dr[2];
378         kenv->dr3 = env->dr[3];
379     } else {
380         kenv->dr7 = 0;
381     }
382     kenv->dr6 = env->dr[6];
383     kenv->cpl = 3;
384     kenv->nb_pages_to_flush = nb_pages_to_flush;
385     nb_pages_to_flush = 0;
386     
387     if (!(kenv->cr0 & CR0_TS_MASK)) {
388         if (env->cpuid_features & CPUID_FXSR)
389             restore_native_fp_fxrstor(env);
390         else
391             restore_native_fp_frstor(env);
392     }
393
394 #ifdef _WIN32
395     DeviceIoControl(kqemu_fd, KQEMU_EXEC,
396                     kenv, sizeof(struct kqemu_cpu_state),
397                     kenv, sizeof(struct kqemu_cpu_state),
398                     &temp, NULL);
399     ret = kenv->retval;
400 #else
401 #if KQEMU_VERSION >= 0x010100
402     ioctl(kqemu_fd, KQEMU_EXEC, kenv);
403     ret = kenv->retval;
404 #else
405     ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
406 #endif
407 #endif
408     if (!(kenv->cr0 & CR0_TS_MASK)) {
409         if (env->cpuid_features & CPUID_FXSR)
410             save_native_fp_fxsave(env);
411         else
412             save_native_fp_fsave(env);
413     }
414
415     memcpy(env->regs, kenv->regs, sizeof(env->regs));
416     env->eip = kenv->eip;
417     env->eflags = kenv->eflags;
418     memcpy(env->segs, kenv->segs, sizeof(env->segs));
419 #if 0
420     /* no need to restore that */
421     memcpy(env->ldt, kenv->ldt, sizeof(env->ldt));
422     memcpy(env->tr, kenv->tr, sizeof(env->tr));
423     memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
424     memcpy(env->idt, kenv->idt, sizeof(env->idt));
425     env->cr[0] = kenv->cr0;
426     env->cr[3] = kenv->cr3;
427     env->cr[4] = kenv->cr4;
428     env->a20_mask = kenv->a20_mask;
429 #endif
430     env->cr[2] = kenv->cr2;
431     env->dr[6] = kenv->dr6;
432
433 #ifdef DEBUG
434     if (loglevel & CPU_LOG_INT) {
435         fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
436     }
437 #endif
438     if ((ret & 0xff00) == KQEMU_RET_INT) {
439         env->exception_index = ret & 0xff;
440         env->error_code = 0;
441         env->exception_is_int = 1;
442         env->exception_next_eip = kenv->next_eip;
443 #ifdef DEBUG
444     if (loglevel & CPU_LOG_INT) {
445         fprintf(logfile, "kqemu: interrupt v=%02x:\n", 
446                 env->exception_index);
447         cpu_dump_state(env, logfile, fprintf, 0);
448     }
449 #endif
450         return 1;
451     } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
452         env->exception_index = ret & 0xff;
453         env->error_code = kenv->error_code;
454         env->exception_is_int = 0;
455         env->exception_next_eip = 0;
456 #ifdef DEBUG
457         if (loglevel & CPU_LOG_INT) {
458             fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
459                     env->exception_index, env->error_code);
460             cpu_dump_state(env, logfile, fprintf, 0);
461         }
462 #endif
463         return 1;
464     } else if (ret == KQEMU_RET_INTR) {
465         return 0;
466     } else if (ret == KQEMU_RET_SOFTMMU) { 
467         return 2;
468     } else {
469         cpu_dump_state(env, stderr, fprintf, 0);
470         fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
471         exit(1);
472     }
473     return 0;
474 }
475
476 #endif