]> git.proxmox.com Git - qemu.git/blame - kqemu.c
64 bit virtual addressing fix
[qemu.git] / kqemu.c
CommitLineData
9df217a3
FB
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>
6e4255f6 23#include <winioctl.h>
9df217a3
FB
24#else
25#include <sys/types.h>
26#include <sys/mman.h>
6e4255f6 27#include <sys/ioctl.h>
9df217a3
FB
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>
9df217a3
FB
46#include "kqemu/kqemu.h"
47
c28e951f
FB
48/* compatibility stuff */
49#ifndef KQEMU_RET_SYSCALL
50#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */
51#endif
52
6e4255f6
FB
53#ifdef _WIN32
54#define KQEMU_DEVICE "\\\\.\\kqemu"
55#else
9df217a3 56#define KQEMU_DEVICE "/dev/kqemu"
6e4255f6
FB
57#endif
58
59#ifdef _WIN32
60#define KQEMU_INVALID_FD INVALID_HANDLE_VALUE
61HANDLE kqemu_fd = KQEMU_INVALID_FD;
62#define kqemu_closefd(x) CloseHandle(x)
63#else
64#define KQEMU_INVALID_FD -1
65int kqemu_fd = KQEMU_INVALID_FD;
66#define kqemu_closefd(x) close(x)
67#endif
9df217a3
FB
68
69int kqemu_allowed = 1;
9df217a3
FB
70unsigned long *pages_to_flush;
71unsigned int nb_pages_to_flush;
72extern 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
c28e951f
FB
79#ifdef __x86_64__
80static int is_cpuid_supported(void)
81{
82 return 1;
83}
84#else
9df217a3
FB
85static 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}
c28e951f 101#endif
9df217a3
FB
102
103static 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
129int kqemu_init(CPUState *env)
130{
131 struct kqemu_init init;
132 int ret, version;
6e4255f6
FB
133#ifdef _WIN32
134 DWORD temp;
135#endif
9df217a3
FB
136
137 if (!kqemu_allowed)
138 return -1;
139
6e4255f6
FB
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
9df217a3 146 kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
6e4255f6
FB
147#endif
148 if (kqemu_fd == KQEMU_INVALID_FD) {
9df217a3
FB
149 fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
150 return -1;
151 }
152 version = 0;
6e4255f6
FB
153#ifdef _WIN32
154 DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
155 &version, sizeof(version), &temp, NULL);
156#else
9df217a3 157 ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
6e4255f6 158#endif
9df217a3
FB
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;
6e4255f6
FB
175#ifdef _WIN32
176 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
177 NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
178#else
9df217a3 179 ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
6e4255f6 180#endif
9df217a3
FB
181 if (ret < 0) {
182 fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
183 fail:
6e4255f6
FB
184 kqemu_closefd(kqemu_fd);
185 kqemu_fd = KQEMU_INVALID_FD;
9df217a3
FB
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
194void 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
207void 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
217struct 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
232struct 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];
c28e951f
FB
246 uint8_t xmm_regs[16 * 16];
247 uint8_t dummy2[96];
9df217a3
FB
248};
249
250static struct fpxstate fpx1 __attribute__((aligned(16)));
251
252static 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
277static 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
302static 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;
c28e951f 323 memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16);
9df217a3
FB
324 }
325 asm volatile ("fxrstor %0" : "=m" (*fp));
326}
327
328static 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;
c28e951f 349 memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
9df217a3
FB
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
c28e951f
FB
358static 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
9df217a3
FB
407int kqemu_cpu_exec(CPUState *env)
408{
409 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
410 int ret;
6e4255f6
FB
411#ifdef _WIN32
412 DWORD temp;
413#endif
9df217a3
FB
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;
c45b3c0e 434#if KQEMU_VERSION >= 0x010100
c28e951f
FB
435 kenv->efer = env->efer;
436#endif
9df217a3
FB
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
6e4255f6
FB
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
9df217a3 469 ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
6e4255f6
FB
470#endif
471#endif
9df217a3
FB
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
c28e951f
FB
502 if (ret == KQEMU_RET_SYSCALL) {
503 /* syscall instruction */
504 return do_syscall(env, kenv);
505 } else
9df217a3
FB
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
c28e951f
FB
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 }
9df217a3
FB
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) {
c45b3c0e
FB
533#ifdef DEBUG
534 if (loglevel & CPU_LOG_INT) {
535 cpu_dump_state(env, logfile, fprintf, 0);
536 }
537#endif
9df217a3
FB
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