raw CDROM access for windows (Filip Navara)
[qemu/qemu_0_9_1_stable.git] / kqemu.c
blob4d152502e7f8cbe3de44896e45f2c7f3c565376d
1 /*
2 * KQEMU support
3 *
4 * Copyright (c) 2005 Fabrice Bellard
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.
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.
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
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>
37 #include "cpu.h"
38 #include "exec-all.h"
40 #ifdef USE_KQEMU
42 #define DEBUG
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include "kqemu/kqemu.h"
48 /* compatibility stuff */
49 #ifndef KQEMU_RET_SYSCALL
50 #define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */
51 #endif
53 #ifdef _WIN32
54 #define KQEMU_DEVICE "\\\\.\\kqemu"
55 #else
56 #define KQEMU_DEVICE "/dev/kqemu"
57 #endif
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
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;
74 #define cpuid(index, eax, ebx, ecx, edx) \
75 asm volatile ("cpuid" \
76 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
77 : "0" (index))
79 #ifdef __x86_64__
80 static int is_cpuid_supported(void)
82 return 1;
84 #else
85 static int is_cpuid_supported(void)
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)
98 : "cc");
99 return (v0 != v1);
101 #endif
103 static void kqemu_update_cpuid(CPUState *env)
105 int critical_features_mask, features;
106 uint32_t eax, ebx, ecx, edx;
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;
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 */
129 int kqemu_init(CPUState *env)
131 struct kqemu_init init;
132 int ret, version;
133 #ifdef _WIN32
134 DWORD temp;
135 #endif
137 if (!kqemu_allowed)
138 return -1;
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;
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;
165 pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH *
166 sizeof(unsigned long));
167 if (!pages_to_flush)
168 goto fail;
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;
188 kqemu_update_cpuid(env);
189 env->kqemu_enabled = 1;
190 nb_pages_to_flush = 0;
191 return 0;
194 void kqemu_flush_page(CPUState *env, target_ulong addr)
196 #ifdef DEBUG
197 if (loglevel & CPU_LOG_INT) {
198 fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
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;
207 void kqemu_flush(CPUState *env, int global)
209 #ifdef DEBUG
210 if (loglevel & CPU_LOG_INT) {
211 fprintf(logfile, "kqemu_flush:\n");
213 #endif
214 nb_pages_to_flush = KQEMU_FLUSH_ALL;
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;
225 uint32_t fpip;
226 uint32_t fpcs;
227 uint32_t fpoo;
228 uint32_t fpos;
229 uint8_t fpregs1[8 * 10];
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];
250 static struct fpxstate fpx1 __attribute__((aligned(16)));
252 static void restore_native_fp_frstor(CPUState *env)
254 int fptag, i, j;
255 struct fpstate fp1, *fp = &fp1;
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 */
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;
274 asm volatile ("frstor %0" : "=m" (*fp));
277 static void save_native_fp_fsave(CPUState *env)
279 int fptag, i, j;
280 uint16_t fpuc;
281 struct fpstate fp1, *fp = &fp1;
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;
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;
297 /* we must restore the default rounding state */
298 fpuc = 0x037f | (env->fpuc & (3 << 10));
299 asm volatile("fldcw %0" : : "m" (fpuc));
302 static void restore_native_fp_fxrstor(CPUState *env)
304 struct fpxstate *fp = &fpx1;
305 int i, j, fptag;
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;
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;
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);
325 asm volatile ("fxrstor %0" : "=m" (*fp));
328 static void save_native_fp_fxsave(CPUState *env)
330 struct fpxstate *fp = &fpx1;
331 int fptag, i, j;
332 uint16_t fpuc;
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;
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;
347 if (env->cpuid_features & CPUID_SSE) {
348 env->mxcsr = fp->mxcsr;
349 memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
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));
358 static int do_syscall(CPUState *env,
359 struct kqemu_cpu_state *kenv)
361 int selector;
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;
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
388 env->regs[R_ECX] = (uint32_t)kenv->next_eip;
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;
404 return 2;
407 int kqemu_cpu_exec(CPUState *env)
409 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
410 int ret;
411 #ifdef _WIN32
412 DWORD temp;
413 #endif
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);
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;
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;
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);
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);
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;
497 #ifdef DEBUG
498 if (loglevel & CPU_LOG_INT) {
499 fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
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);
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);
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);
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);
546 return 0;
549 #endif