]> git.proxmox.com Git - mirror_qemu.git/blame - kqemu.c
update
[mirror_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
aa062973 43//#define PROFILE
9df217a3
FB
44
45#include <unistd.h>
46#include <fcntl.h>
b88a3832 47#include "kqemu.h"
9df217a3 48
c28e951f
FB
49/* compatibility stuff */
50#ifndef KQEMU_RET_SYSCALL
51#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */
52#endif
aa062973
FB
53#ifndef KQEMU_MAX_RAM_PAGES_TO_UPDATE
54#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512
55#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1)
56#endif
f32fc648
FB
57#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES
58#define KQEMU_MAX_MODIFIED_RAM_PAGES 512
59#endif
c28e951f 60
6e4255f6
FB
61#ifdef _WIN32
62#define KQEMU_DEVICE "\\\\.\\kqemu"
63#else
9df217a3 64#define KQEMU_DEVICE "/dev/kqemu"
6e4255f6
FB
65#endif
66
67#ifdef _WIN32
68#define KQEMU_INVALID_FD INVALID_HANDLE_VALUE
69HANDLE kqemu_fd = KQEMU_INVALID_FD;
70#define kqemu_closefd(x) CloseHandle(x)
71#else
72#define KQEMU_INVALID_FD -1
73int kqemu_fd = KQEMU_INVALID_FD;
74#define kqemu_closefd(x) close(x)
75#endif
9df217a3 76
f32fc648
FB
77/* 0 = not allowed
78 1 = user kqemu
79 2 = kernel kqemu
80*/
9df217a3 81int kqemu_allowed = 1;
9df217a3
FB
82unsigned long *pages_to_flush;
83unsigned int nb_pages_to_flush;
aa062973
FB
84unsigned long *ram_pages_to_update;
85unsigned int nb_ram_pages_to_update;
f32fc648
FB
86unsigned long *modified_ram_pages;
87unsigned int nb_modified_ram_pages;
88uint8_t *modified_ram_pages_table;
9df217a3
FB
89extern uint32_t **l1_phys_map;
90
91#define cpuid(index, eax, ebx, ecx, edx) \
92 asm volatile ("cpuid" \
93 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
94 : "0" (index))
95
c28e951f
FB
96#ifdef __x86_64__
97static int is_cpuid_supported(void)
98{
99 return 1;
100}
101#else
9df217a3
FB
102static int is_cpuid_supported(void)
103{
104 int v0, v1;
105 asm volatile ("pushf\n"
106 "popl %0\n"
107 "movl %0, %1\n"
108 "xorl $0x00200000, %0\n"
109 "pushl %0\n"
110 "popf\n"
111 "pushf\n"
112 "popl %0\n"
113 : "=a" (v0), "=d" (v1)
114 :
115 : "cc");
116 return (v0 != v1);
117}
c28e951f 118#endif
9df217a3
FB
119
120static void kqemu_update_cpuid(CPUState *env)
121{
0de6bb73 122 int critical_features_mask, features, ext_features, ext_features_mask;
9df217a3
FB
123 uint32_t eax, ebx, ecx, edx;
124
125 /* the following features are kept identical on the host and
126 target cpus because they are important for user code. Strictly
127 speaking, only SSE really matters because the OS must support
128 it if the user code uses it. */
129 critical_features_mask =
130 CPUID_CMOV | CPUID_CX8 |
131 CPUID_FXSR | CPUID_MMX | CPUID_SSE |
ca0d1734 132 CPUID_SSE2 | CPUID_SEP;
0de6bb73 133 ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR;
9df217a3
FB
134 if (!is_cpuid_supported()) {
135 features = 0;
0de6bb73 136 ext_features = 0;
9df217a3
FB
137 } else {
138 cpuid(1, eax, ebx, ecx, edx);
139 features = edx;
0de6bb73 140 ext_features = ecx;
9df217a3 141 }
ca0d1734
FB
142#ifdef __x86_64__
143 /* NOTE: on x86_64 CPUs, SYSENTER is not supported in
144 compatibility mode, so in order to have the best performances
145 it is better not to use it */
146 features &= ~CPUID_SEP;
147#endif
9df217a3
FB
148 env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
149 (features & critical_features_mask);
0de6bb73
FB
150 env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) |
151 (ext_features & ext_features_mask);
9df217a3
FB
152 /* XXX: we could update more of the target CPUID state so that the
153 non accelerated code sees exactly the same CPU features as the
154 accelerated code */
155}
156
157int kqemu_init(CPUState *env)
158{
159 struct kqemu_init init;
160 int ret, version;
6e4255f6
FB
161#ifdef _WIN32
162 DWORD temp;
163#endif
9df217a3
FB
164
165 if (!kqemu_allowed)
166 return -1;
167
6e4255f6
FB
168#ifdef _WIN32
169 kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ,
170 FILE_SHARE_READ | FILE_SHARE_WRITE,
171 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
172 NULL);
173#else
9df217a3 174 kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
6e4255f6
FB
175#endif
176 if (kqemu_fd == KQEMU_INVALID_FD) {
9df217a3
FB
177 fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
178 return -1;
179 }
180 version = 0;
6e4255f6
FB
181#ifdef _WIN32
182 DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
183 &version, sizeof(version), &temp, NULL);
184#else
9df217a3 185 ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
6e4255f6 186#endif
9df217a3
FB
187 if (version != KQEMU_VERSION) {
188 fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
189 version, KQEMU_VERSION);
190 goto fail;
191 }
192
193 pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH *
194 sizeof(unsigned long));
195 if (!pages_to_flush)
196 goto fail;
197
aa062973
FB
198 ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE *
199 sizeof(unsigned long));
200 if (!ram_pages_to_update)
201 goto fail;
202
f32fc648
FB
203 modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES *
204 sizeof(unsigned long));
205 if (!modified_ram_pages)
206 goto fail;
207 modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS);
208 if (!modified_ram_pages_table)
209 goto fail;
210
9df217a3
FB
211 init.ram_base = phys_ram_base;
212 init.ram_size = phys_ram_size;
213 init.ram_dirty = phys_ram_dirty;
214 init.phys_to_ram_map = l1_phys_map;
215 init.pages_to_flush = pages_to_flush;
aa062973
FB
216#if KQEMU_VERSION >= 0x010200
217 init.ram_pages_to_update = ram_pages_to_update;
218#endif
f32fc648
FB
219#if KQEMU_VERSION >= 0x010300
220 init.modified_ram_pages = modified_ram_pages;
221#endif
6e4255f6
FB
222#ifdef _WIN32
223 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
224 NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
225#else
9df217a3 226 ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
6e4255f6 227#endif
9df217a3
FB
228 if (ret < 0) {
229 fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
230 fail:
6e4255f6
FB
231 kqemu_closefd(kqemu_fd);
232 kqemu_fd = KQEMU_INVALID_FD;
9df217a3
FB
233 return -1;
234 }
235 kqemu_update_cpuid(env);
f32fc648 236 env->kqemu_enabled = kqemu_allowed;
9df217a3 237 nb_pages_to_flush = 0;
aa062973 238 nb_ram_pages_to_update = 0;
9df217a3
FB
239 return 0;
240}
241
242void kqemu_flush_page(CPUState *env, target_ulong addr)
243{
f32fc648 244#if defined(DEBUG)
9df217a3
FB
245 if (loglevel & CPU_LOG_INT) {
246 fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
247 }
248#endif
249 if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
250 nb_pages_to_flush = KQEMU_FLUSH_ALL;
251 else
252 pages_to_flush[nb_pages_to_flush++] = addr;
253}
254
255void kqemu_flush(CPUState *env, int global)
256{
257#ifdef DEBUG
258 if (loglevel & CPU_LOG_INT) {
259 fprintf(logfile, "kqemu_flush:\n");
260 }
261#endif
262 nb_pages_to_flush = KQEMU_FLUSH_ALL;
263}
264
aa062973
FB
265void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
266{
267#ifdef DEBUG
268 if (loglevel & CPU_LOG_INT) {
269 fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr);
270 }
271#endif
fc8dc060
FB
272 /* we only track transitions to dirty state */
273 if (phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] != 0xff)
274 return;
aa062973
FB
275 if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE)
276 nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL;
277 else
278 ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr;
279}
280
f32fc648
FB
281static void kqemu_reset_modified_ram_pages(void)
282{
283 int i;
284 unsigned long page_index;
285
286 for(i = 0; i < nb_modified_ram_pages; i++) {
287 page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS;
288 modified_ram_pages_table[page_index] = 0;
289 }
290 nb_modified_ram_pages = 0;
291}
292
293void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr)
294{
295 unsigned long page_index;
296 int ret;
297#ifdef _WIN32
298 DWORD temp;
299#endif
300
301 page_index = ram_addr >> TARGET_PAGE_BITS;
302 if (!modified_ram_pages_table[page_index]) {
303#if 0
304 printf("%d: modify_page=%08lx\n", nb_modified_ram_pages, ram_addr);
305#endif
306 modified_ram_pages_table[page_index] = 1;
307 modified_ram_pages[nb_modified_ram_pages++] = ram_addr;
308 if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) {
309 /* flush */
310#ifdef _WIN32
311 ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
312 &nb_modified_ram_pages,
313 sizeof(nb_modified_ram_pages),
314 NULL, 0, &temp, NULL);
315#else
316 ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
317 &nb_modified_ram_pages);
318#endif
319 kqemu_reset_modified_ram_pages();
320 }
321 }
322}
323
9df217a3
FB
324struct fpstate {
325 uint16_t fpuc;
326 uint16_t dummy1;
327 uint16_t fpus;
328 uint16_t dummy2;
329 uint16_t fptag;
330 uint16_t dummy3;
331
332 uint32_t fpip;
333 uint32_t fpcs;
334 uint32_t fpoo;
335 uint32_t fpos;
336 uint8_t fpregs1[8 * 10];
337};
338
339struct fpxstate {
340 uint16_t fpuc;
341 uint16_t fpus;
342 uint16_t fptag;
343 uint16_t fop;
344 uint32_t fpuip;
345 uint16_t cs_sel;
346 uint16_t dummy0;
347 uint32_t fpudp;
348 uint16_t ds_sel;
349 uint16_t dummy1;
350 uint32_t mxcsr;
351 uint32_t mxcsr_mask;
352 uint8_t fpregs1[8 * 16];
c28e951f
FB
353 uint8_t xmm_regs[16 * 16];
354 uint8_t dummy2[96];
9df217a3
FB
355};
356
357static struct fpxstate fpx1 __attribute__((aligned(16)));
358
359static void restore_native_fp_frstor(CPUState *env)
360{
361 int fptag, i, j;
362 struct fpstate fp1, *fp = &fp1;
363
364 fp->fpuc = env->fpuc;
365 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
366 fptag = 0;
367 for (i=7; i>=0; i--) {
368 fptag <<= 2;
369 if (env->fptags[i]) {
370 fptag |= 3;
371 } else {
372 /* the FPU automatically computes it */
373 }
374 }
375 fp->fptag = fptag;
376 j = env->fpstt;
377 for(i = 0;i < 8; i++) {
378 memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
379 j = (j + 1) & 7;
380 }
381 asm volatile ("frstor %0" : "=m" (*fp));
382}
383
384static void save_native_fp_fsave(CPUState *env)
385{
386 int fptag, i, j;
387 uint16_t fpuc;
388 struct fpstate fp1, *fp = &fp1;
389
390 asm volatile ("fsave %0" : : "m" (*fp));
391 env->fpuc = fp->fpuc;
392 env->fpstt = (fp->fpus >> 11) & 7;
393 env->fpus = fp->fpus & ~0x3800;
394 fptag = fp->fptag;
395 for(i = 0;i < 8; i++) {
396 env->fptags[i] = ((fptag & 3) == 3);
397 fptag >>= 2;
398 }
399 j = env->fpstt;
400 for(i = 0;i < 8; i++) {
401 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
402 j = (j + 1) & 7;
403 }
404 /* we must restore the default rounding state */
405 fpuc = 0x037f | (env->fpuc & (3 << 10));
406 asm volatile("fldcw %0" : : "m" (fpuc));
407}
408
409static void restore_native_fp_fxrstor(CPUState *env)
410{
411 struct fpxstate *fp = &fpx1;
412 int i, j, fptag;
413
414 fp->fpuc = env->fpuc;
415 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
416 fptag = 0;
417 for(i = 0; i < 8; i++)
418 fptag |= (env->fptags[i] << i);
419 fp->fptag = fptag ^ 0xff;
420
421 j = env->fpstt;
422 for(i = 0;i < 8; i++) {
423 memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
424 j = (j + 1) & 7;
425 }
426 if (env->cpuid_features & CPUID_SSE) {
427 fp->mxcsr = env->mxcsr;
428 /* XXX: check if DAZ is not available */
429 fp->mxcsr_mask = 0xffff;
c28e951f 430 memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16);
9df217a3
FB
431 }
432 asm volatile ("fxrstor %0" : "=m" (*fp));
433}
434
435static void save_native_fp_fxsave(CPUState *env)
436{
437 struct fpxstate *fp = &fpx1;
438 int fptag, i, j;
439 uint16_t fpuc;
440
441 asm volatile ("fxsave %0" : : "m" (*fp));
442 env->fpuc = fp->fpuc;
443 env->fpstt = (fp->fpus >> 11) & 7;
444 env->fpus = fp->fpus & ~0x3800;
445 fptag = fp->fptag ^ 0xff;
446 for(i = 0;i < 8; i++) {
447 env->fptags[i] = (fptag >> i) & 1;
448 }
449 j = env->fpstt;
450 for(i = 0;i < 8; i++) {
451 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
452 j = (j + 1) & 7;
453 }
454 if (env->cpuid_features & CPUID_SSE) {
455 env->mxcsr = fp->mxcsr;
c28e951f 456 memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
9df217a3
FB
457 }
458
459 /* we must restore the default rounding state */
460 asm volatile ("fninit");
461 fpuc = 0x037f | (env->fpuc & (3 << 10));
462 asm volatile("fldcw %0" : : "m" (fpuc));
463}
464
c28e951f
FB
465static int do_syscall(CPUState *env,
466 struct kqemu_cpu_state *kenv)
467{
468 int selector;
469
470 selector = (env->star >> 32) & 0xffff;
471#ifdef __x86_64__
472 if (env->hflags & HF_LMA_MASK) {
473 env->regs[R_ECX] = kenv->next_eip;
474 env->regs[11] = env->eflags;
475
476 cpu_x86_set_cpl(env, 0);
477 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
478 0, 0xffffffff,
479 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
480 DESC_S_MASK |
481 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
482 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
483 0, 0xffffffff,
484 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
485 DESC_S_MASK |
486 DESC_W_MASK | DESC_A_MASK);
487 env->eflags &= ~env->fmask;
488 if (env->hflags & HF_CS64_MASK)
489 env->eip = env->lstar;
490 else
491 env->eip = env->cstar;
492 } else
493#endif
494 {
495 env->regs[R_ECX] = (uint32_t)kenv->next_eip;
496
497 cpu_x86_set_cpl(env, 0);
498 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
499 0, 0xffffffff,
500 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
501 DESC_S_MASK |
502 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
503 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
504 0, 0xffffffff,
505 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
506 DESC_S_MASK |
507 DESC_W_MASK | DESC_A_MASK);
508 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
509 env->eip = (uint32_t)env->star;
510 }
511 return 2;
512}
513
f32fc648 514#ifdef CONFIG_PROFILER
aa062973
FB
515
516#define PC_REC_SIZE 1
517#define PC_REC_HASH_BITS 16
518#define PC_REC_HASH_SIZE (1 << PC_REC_HASH_BITS)
519
520typedef struct PCRecord {
521 unsigned long pc;
522 int64_t count;
523 struct PCRecord *next;
524} PCRecord;
525
f32fc648
FB
526static PCRecord *pc_rec_hash[PC_REC_HASH_SIZE];
527static int nb_pc_records;
aa062973 528
f32fc648 529static void kqemu_record_pc(unsigned long pc)
aa062973
FB
530{
531 unsigned long h;
532 PCRecord **pr, *r;
533
534 h = pc / PC_REC_SIZE;
535 h = h ^ (h >> PC_REC_HASH_BITS);
536 h &= (PC_REC_HASH_SIZE - 1);
537 pr = &pc_rec_hash[h];
538 for(;;) {
539 r = *pr;
540 if (r == NULL)
541 break;
542 if (r->pc == pc) {
543 r->count++;
544 return;
545 }
546 pr = &r->next;
547 }
548 r = malloc(sizeof(PCRecord));
549 r->count = 1;
550 r->pc = pc;
551 r->next = NULL;
552 *pr = r;
553 nb_pc_records++;
554}
555
f32fc648 556static int pc_rec_cmp(const void *p1, const void *p2)
aa062973
FB
557{
558 PCRecord *r1 = *(PCRecord **)p1;
559 PCRecord *r2 = *(PCRecord **)p2;
560 if (r1->count < r2->count)
561 return 1;
562 else if (r1->count == r2->count)
563 return 0;
564 else
565 return -1;
566}
567
f32fc648
FB
568static void kqemu_record_flush(void)
569{
570 PCRecord *r, *r_next;
571 int h;
572
573 for(h = 0; h < PC_REC_HASH_SIZE; h++) {
574 for(r = pc_rec_hash[h]; r != NULL; r = r_next) {
575 r_next = r->next;
576 free(r);
577 }
578 pc_rec_hash[h] = NULL;
579 }
580 nb_pc_records = 0;
581}
582
aa062973
FB
583void kqemu_record_dump(void)
584{
585 PCRecord **pr, *r;
586 int i, h;
587 FILE *f;
588 int64_t total, sum;
589
590 pr = malloc(sizeof(PCRecord *) * nb_pc_records);
591 i = 0;
592 total = 0;
593 for(h = 0; h < PC_REC_HASH_SIZE; h++) {
594 for(r = pc_rec_hash[h]; r != NULL; r = r->next) {
595 pr[i++] = r;
596 total += r->count;
597 }
598 }
599 qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp);
600
601 f = fopen("/tmp/kqemu.stats", "w");
602 if (!f) {
603 perror("/tmp/kqemu.stats");
604 exit(1);
605 }
26a76461 606 fprintf(f, "total: %" PRId64 "\n", total);
aa062973
FB
607 sum = 0;
608 for(i = 0; i < nb_pc_records; i++) {
609 r = pr[i];
610 sum += r->count;
26a76461 611 fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n",
aa062973
FB
612 r->pc,
613 r->count,
614 (double)r->count / (double)total * 100.0,
615 (double)sum / (double)total * 100.0);
616 }
617 fclose(f);
618 free(pr);
f32fc648
FB
619
620 kqemu_record_flush();
aa062973
FB
621}
622#endif
623
9df217a3
FB
624int kqemu_cpu_exec(CPUState *env)
625{
626 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
f32fc648
FB
627 int ret, cpl, i;
628#ifdef CONFIG_PROFILER
629 int64_t ti;
630#endif
631
6e4255f6
FB
632#ifdef _WIN32
633 DWORD temp;
634#endif
9df217a3 635
f32fc648
FB
636#ifdef CONFIG_PROFILER
637 ti = profile_getclock();
638#endif
9df217a3
FB
639#ifdef DEBUG
640 if (loglevel & CPU_LOG_INT) {
641 fprintf(logfile, "kqemu: cpu_exec: enter\n");
642 cpu_dump_state(env, logfile, fprintf, 0);
643 }
644#endif
645 memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
646 kenv->eip = env->eip;
647 kenv->eflags = env->eflags;
648 memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
649 memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
650 memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
651 memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
652 memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
653 kenv->cr0 = env->cr[0];
654 kenv->cr2 = env->cr[2];
655 kenv->cr3 = env->cr[3];
656 kenv->cr4 = env->cr[4];
657 kenv->a20_mask = env->a20_mask;
c45b3c0e 658#if KQEMU_VERSION >= 0x010100
c28e951f 659 kenv->efer = env->efer;
f32fc648
FB
660#endif
661#if KQEMU_VERSION >= 0x010300
662 kenv->tsc_offset = 0;
663 kenv->star = env->star;
664 kenv->sysenter_cs = env->sysenter_cs;
665 kenv->sysenter_esp = env->sysenter_esp;
666 kenv->sysenter_eip = env->sysenter_eip;
667#ifdef __x86_64__
668 kenv->lstar = env->lstar;
669 kenv->cstar = env->cstar;
670 kenv->fmask = env->fmask;
671 kenv->kernelgsbase = env->kernelgsbase;
672#endif
c28e951f 673#endif
9df217a3
FB
674 if (env->dr[7] & 0xff) {
675 kenv->dr7 = env->dr[7];
676 kenv->dr0 = env->dr[0];
677 kenv->dr1 = env->dr[1];
678 kenv->dr2 = env->dr[2];
679 kenv->dr3 = env->dr[3];
680 } else {
681 kenv->dr7 = 0;
682 }
683 kenv->dr6 = env->dr[6];
f32fc648
FB
684 cpl = (env->hflags & HF_CPL_MASK);
685 kenv->cpl = cpl;
9df217a3 686 kenv->nb_pages_to_flush = nb_pages_to_flush;
aa062973 687#if KQEMU_VERSION >= 0x010200
f32fc648 688 kenv->user_only = (env->kqemu_enabled == 1);
aa062973
FB
689 kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
690#endif
691 nb_ram_pages_to_update = 0;
9df217a3 692
f32fc648
FB
693#if KQEMU_VERSION >= 0x010300
694 kenv->nb_modified_ram_pages = nb_modified_ram_pages;
695#endif
696 kqemu_reset_modified_ram_pages();
697
698 if (env->cpuid_features & CPUID_FXSR)
699 restore_native_fp_fxrstor(env);
700 else
701 restore_native_fp_frstor(env);
9df217a3 702
6e4255f6 703#ifdef _WIN32
a332e112
FB
704 if (DeviceIoControl(kqemu_fd, KQEMU_EXEC,
705 kenv, sizeof(struct kqemu_cpu_state),
706 kenv, sizeof(struct kqemu_cpu_state),
707 &temp, NULL)) {
708 ret = kenv->retval;
709 } else {
710 ret = -1;
711 }
6e4255f6
FB
712#else
713#if KQEMU_VERSION >= 0x010100
714 ioctl(kqemu_fd, KQEMU_EXEC, kenv);
715 ret = kenv->retval;
716#else
9df217a3 717 ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
6e4255f6
FB
718#endif
719#endif
f32fc648
FB
720 if (env->cpuid_features & CPUID_FXSR)
721 save_native_fp_fxsave(env);
722 else
723 save_native_fp_fsave(env);
9df217a3
FB
724
725 memcpy(env->regs, kenv->regs, sizeof(env->regs));
726 env->eip = kenv->eip;
727 env->eflags = kenv->eflags;
728 memcpy(env->segs, kenv->segs, sizeof(env->segs));
f32fc648
FB
729 cpu_x86_set_cpl(env, kenv->cpl);
730 memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt));
9df217a3
FB
731#if 0
732 /* no need to restore that */
9df217a3
FB
733 memcpy(env->tr, kenv->tr, sizeof(env->tr));
734 memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
735 memcpy(env->idt, kenv->idt, sizeof(env->idt));
9df217a3
FB
736 env->a20_mask = kenv->a20_mask;
737#endif
f32fc648
FB
738 env->cr[0] = kenv->cr0;
739 env->cr[4] = kenv->cr4;
740 env->cr[3] = kenv->cr3;
9df217a3
FB
741 env->cr[2] = kenv->cr2;
742 env->dr[6] = kenv->dr6;
f32fc648
FB
743#if KQEMU_VERSION >= 0x010300
744#ifdef __x86_64__
745 env->kernelgsbase = kenv->kernelgsbase;
746#endif
747#endif
748
749 /* flush pages as indicated by kqemu */
750 if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) {
751 tlb_flush(env, 1);
752 } else {
753 for(i = 0; i < kenv->nb_pages_to_flush; i++) {
754 tlb_flush_page(env, pages_to_flush[i]);
755 }
756 }
757 nb_pages_to_flush = 0;
758
759#ifdef CONFIG_PROFILER
760 kqemu_time += profile_getclock() - ti;
761 kqemu_exec_count++;
762#endif
9df217a3 763
aa062973
FB
764#if KQEMU_VERSION >= 0x010200
765 if (kenv->nb_ram_pages_to_update > 0) {
766 cpu_tlb_update_dirty(env);
767 }
768#endif
769
f32fc648
FB
770#if KQEMU_VERSION >= 0x010300
771 if (kenv->nb_modified_ram_pages > 0) {
772 for(i = 0; i < kenv->nb_modified_ram_pages; i++) {
773 unsigned long addr;
774 addr = modified_ram_pages[i];
775 tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0);
776 }
777 }
778#endif
779
aa062973
FB
780 /* restore the hidden flags */
781 {
782 unsigned int new_hflags;
783#ifdef TARGET_X86_64
784 if ((env->hflags & HF_LMA_MASK) &&
785 (env->segs[R_CS].flags & DESC_L_MASK)) {
786 /* long mode */
787 new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
788 } else
789#endif
790 {
791 /* legacy / compatibility case */
792 new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
793 >> (DESC_B_SHIFT - HF_CS32_SHIFT);
794 new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
795 >> (DESC_B_SHIFT - HF_SS32_SHIFT);
796 if (!(env->cr[0] & CR0_PE_MASK) ||
797 (env->eflags & VM_MASK) ||
798 !(env->hflags & HF_CS32_MASK)) {
799 /* XXX: try to avoid this test. The problem comes from the
800 fact that is real mode or vm86 mode we only modify the
801 'base' and 'selector' fields of the segment cache to go
802 faster. A solution may be to force addseg to one in
803 translate-i386.c. */
804 new_hflags |= HF_ADDSEG_MASK;
805 } else {
806 new_hflags |= ((env->segs[R_DS].base |
807 env->segs[R_ES].base |
808 env->segs[R_SS].base) != 0) <<
809 HF_ADDSEG_SHIFT;
810 }
811 }
812 env->hflags = (env->hflags &
813 ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |
814 new_hflags;
815 }
f32fc648
FB
816 /* update FPU flags */
817 env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
818 ((env->cr[0] << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
819 if (env->cr[4] & CR4_OSFXSR_MASK)
820 env->hflags |= HF_OSFXSR_MASK;
821 else
822 env->hflags &= ~HF_OSFXSR_MASK;
823
9df217a3
FB
824#ifdef DEBUG
825 if (loglevel & CPU_LOG_INT) {
826 fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
827 }
828#endif
c28e951f
FB
829 if (ret == KQEMU_RET_SYSCALL) {
830 /* syscall instruction */
831 return do_syscall(env, kenv);
832 } else
9df217a3
FB
833 if ((ret & 0xff00) == KQEMU_RET_INT) {
834 env->exception_index = ret & 0xff;
835 env->error_code = 0;
836 env->exception_is_int = 1;
837 env->exception_next_eip = kenv->next_eip;
f32fc648
FB
838#ifdef CONFIG_PROFILER
839 kqemu_ret_int_count++;
840#endif
9df217a3 841#ifdef DEBUG
c28e951f
FB
842 if (loglevel & CPU_LOG_INT) {
843 fprintf(logfile, "kqemu: interrupt v=%02x:\n",
844 env->exception_index);
845 cpu_dump_state(env, logfile, fprintf, 0);
846 }
9df217a3
FB
847#endif
848 return 1;
849 } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
850 env->exception_index = ret & 0xff;
851 env->error_code = kenv->error_code;
852 env->exception_is_int = 0;
853 env->exception_next_eip = 0;
f32fc648
FB
854#ifdef CONFIG_PROFILER
855 kqemu_ret_excp_count++;
856#endif
9df217a3
FB
857#ifdef DEBUG
858 if (loglevel & CPU_LOG_INT) {
859 fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
860 env->exception_index, env->error_code);
861 cpu_dump_state(env, logfile, fprintf, 0);
862 }
863#endif
864 return 1;
865 } else if (ret == KQEMU_RET_INTR) {
f32fc648
FB
866#ifdef CONFIG_PROFILER
867 kqemu_ret_intr_count++;
868#endif
c45b3c0e
FB
869#ifdef DEBUG
870 if (loglevel & CPU_LOG_INT) {
871 cpu_dump_state(env, logfile, fprintf, 0);
872 }
873#endif
9df217a3
FB
874 return 0;
875 } else if (ret == KQEMU_RET_SOFTMMU) {
f32fc648
FB
876#ifdef CONFIG_PROFILER
877 {
878 unsigned long pc = env->eip + env->segs[R_CS].base;
879 kqemu_record_pc(pc);
880 }
aa062973
FB
881#endif
882#ifdef DEBUG
883 if (loglevel & CPU_LOG_INT) {
884 cpu_dump_state(env, logfile, fprintf, 0);
885 }
886#endif
9df217a3
FB
887 return 2;
888 } else {
889 cpu_dump_state(env, stderr, fprintf, 0);
890 fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
891 exit(1);
892 }
893 return 0;
894}
895
a332e112
FB
896void kqemu_cpu_interrupt(CPUState *env)
897{
898#if defined(_WIN32) && KQEMU_VERSION >= 0x010101
899 /* cancelling the I/O request causes KQEMU to finish executing the
900 current block and successfully returning. */
901 CancelIo(kqemu_fd);
902#endif
903}
904
9df217a3 905#endif