blob: bd70474d69516cbd3ca0e69c02d6edc806209918 [file] [log] [blame]
bellard9df217a2005-02-10 22:05:51 +00001/*
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>
bellard6e4255f2005-04-17 18:33:47 +000023#include <winioctl.h>
bellard9df217a2005-02-10 22:05:51 +000024#else
25#include <sys/types.h>
26#include <sys/mman.h>
bellard6e4255f2005-04-17 18:33:47 +000027#include <sys/ioctl.h>
bellard9df217a2005-02-10 22:05:51 +000028#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
bellardaa062972005-08-21 09:30:12 +000043//#define PROFILE
bellard9df217a2005-02-10 22:05:51 +000044
45#include <unistd.h>
46#include <fcntl.h>
bellardb88a3832006-02-08 22:59:35 +000047#include "kqemu.h"
bellard9df217a2005-02-10 22:05:51 +000048
bellardc28e9512005-04-23 17:45:43 +000049/* compatibility stuff */
50#ifndef KQEMU_RET_SYSCALL
51#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */
52#endif
bellardaa062972005-08-21 09:30:12 +000053#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
bellardf32fc642006-02-08 22:43:39 +000057#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES
58#define KQEMU_MAX_MODIFIED_RAM_PAGES 512
59#endif
bellardc28e9512005-04-23 17:45:43 +000060
bellard6e4255f2005-04-17 18:33:47 +000061#ifdef _WIN32
62#define KQEMU_DEVICE "\\\\.\\kqemu"
63#else
bellard9df217a2005-02-10 22:05:51 +000064#define KQEMU_DEVICE "/dev/kqemu"
bellard6e4255f2005-04-17 18:33:47 +000065#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
bellard9df217a2005-02-10 22:05:51 +000076
bellardf32fc642006-02-08 22:43:39 +000077/* 0 = not allowed
78 1 = user kqemu
79 2 = kernel kqemu
80*/
bellard9df217a2005-02-10 22:05:51 +000081int kqemu_allowed = 1;
bellard9df217a2005-02-10 22:05:51 +000082unsigned long *pages_to_flush;
83unsigned int nb_pages_to_flush;
bellardaa062972005-08-21 09:30:12 +000084unsigned long *ram_pages_to_update;
85unsigned int nb_ram_pages_to_update;
bellardf32fc642006-02-08 22:43:39 +000086unsigned long *modified_ram_pages;
87unsigned int nb_modified_ram_pages;
88uint8_t *modified_ram_pages_table;
bellard9df217a2005-02-10 22:05:51 +000089extern 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
bellardc28e9512005-04-23 17:45:43 +000096#ifdef __x86_64__
97static int is_cpuid_supported(void)
98{
99 return 1;
100}
101#else
bellard9df217a2005-02-10 22:05:51 +0000102static 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}
bellardc28e9512005-04-23 17:45:43 +0000118#endif
bellard9df217a2005-02-10 22:05:51 +0000119
120static void kqemu_update_cpuid(CPUState *env)
121{
122 int critical_features_mask, features;
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 |
bellardca0d1732005-09-03 16:25:14 +0000132 CPUID_SSE2 | CPUID_SEP;
bellard9df217a2005-02-10 22:05:51 +0000133 if (!is_cpuid_supported()) {
134 features = 0;
135 } else {
136 cpuid(1, eax, ebx, ecx, edx);
137 features = edx;
138 }
bellardca0d1732005-09-03 16:25:14 +0000139#ifdef __x86_64__
140 /* NOTE: on x86_64 CPUs, SYSENTER is not supported in
141 compatibility mode, so in order to have the best performances
142 it is better not to use it */
143 features &= ~CPUID_SEP;
144#endif
bellard9df217a2005-02-10 22:05:51 +0000145 env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
146 (features & critical_features_mask);
147 /* XXX: we could update more of the target CPUID state so that the
148 non accelerated code sees exactly the same CPU features as the
149 accelerated code */
150}
151
152int kqemu_init(CPUState *env)
153{
154 struct kqemu_init init;
155 int ret, version;
bellard6e4255f2005-04-17 18:33:47 +0000156#ifdef _WIN32
157 DWORD temp;
158#endif
bellard9df217a2005-02-10 22:05:51 +0000159
160 if (!kqemu_allowed)
161 return -1;
162
bellard6e4255f2005-04-17 18:33:47 +0000163#ifdef _WIN32
164 kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ,
165 FILE_SHARE_READ | FILE_SHARE_WRITE,
166 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
167 NULL);
168#else
bellard9df217a2005-02-10 22:05:51 +0000169 kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
bellard6e4255f2005-04-17 18:33:47 +0000170#endif
171 if (kqemu_fd == KQEMU_INVALID_FD) {
bellard9df217a2005-02-10 22:05:51 +0000172 fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
173 return -1;
174 }
175 version = 0;
bellard6e4255f2005-04-17 18:33:47 +0000176#ifdef _WIN32
177 DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0,
178 &version, sizeof(version), &temp, NULL);
179#else
bellard9df217a2005-02-10 22:05:51 +0000180 ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
bellard6e4255f2005-04-17 18:33:47 +0000181#endif
bellard9df217a2005-02-10 22:05:51 +0000182 if (version != KQEMU_VERSION) {
183 fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
184 version, KQEMU_VERSION);
185 goto fail;
186 }
187
188 pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH *
189 sizeof(unsigned long));
190 if (!pages_to_flush)
191 goto fail;
192
bellardaa062972005-08-21 09:30:12 +0000193 ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE *
194 sizeof(unsigned long));
195 if (!ram_pages_to_update)
196 goto fail;
197
bellardf32fc642006-02-08 22:43:39 +0000198 modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES *
199 sizeof(unsigned long));
200 if (!modified_ram_pages)
201 goto fail;
202 modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS);
203 if (!modified_ram_pages_table)
204 goto fail;
205
bellard9df217a2005-02-10 22:05:51 +0000206 init.ram_base = phys_ram_base;
207 init.ram_size = phys_ram_size;
208 init.ram_dirty = phys_ram_dirty;
209 init.phys_to_ram_map = l1_phys_map;
210 init.pages_to_flush = pages_to_flush;
bellardaa062972005-08-21 09:30:12 +0000211#if KQEMU_VERSION >= 0x010200
212 init.ram_pages_to_update = ram_pages_to_update;
213#endif
bellardf32fc642006-02-08 22:43:39 +0000214#if KQEMU_VERSION >= 0x010300
215 init.modified_ram_pages = modified_ram_pages;
216#endif
bellard6e4255f2005-04-17 18:33:47 +0000217#ifdef _WIN32
218 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
219 NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
220#else
bellard9df217a2005-02-10 22:05:51 +0000221 ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
bellard6e4255f2005-04-17 18:33:47 +0000222#endif
bellard9df217a2005-02-10 22:05:51 +0000223 if (ret < 0) {
224 fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
225 fail:
bellard6e4255f2005-04-17 18:33:47 +0000226 kqemu_closefd(kqemu_fd);
227 kqemu_fd = KQEMU_INVALID_FD;
bellard9df217a2005-02-10 22:05:51 +0000228 return -1;
229 }
230 kqemu_update_cpuid(env);
bellardf32fc642006-02-08 22:43:39 +0000231 env->kqemu_enabled = kqemu_allowed;
bellard9df217a2005-02-10 22:05:51 +0000232 nb_pages_to_flush = 0;
bellardaa062972005-08-21 09:30:12 +0000233 nb_ram_pages_to_update = 0;
bellard9df217a2005-02-10 22:05:51 +0000234 return 0;
235}
236
237void kqemu_flush_page(CPUState *env, target_ulong addr)
238{
bellardf32fc642006-02-08 22:43:39 +0000239#if defined(DEBUG)
bellard9df217a2005-02-10 22:05:51 +0000240 if (loglevel & CPU_LOG_INT) {
241 fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
242 }
243#endif
244 if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
245 nb_pages_to_flush = KQEMU_FLUSH_ALL;
246 else
247 pages_to_flush[nb_pages_to_flush++] = addr;
248}
249
250void kqemu_flush(CPUState *env, int global)
251{
252#ifdef DEBUG
253 if (loglevel & CPU_LOG_INT) {
254 fprintf(logfile, "kqemu_flush:\n");
255 }
256#endif
257 nb_pages_to_flush = KQEMU_FLUSH_ALL;
258}
259
bellardaa062972005-08-21 09:30:12 +0000260void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
261{
262#ifdef DEBUG
263 if (loglevel & CPU_LOG_INT) {
264 fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr);
265 }
266#endif
bellardfc8dc062005-08-21 19:15:23 +0000267 /* we only track transitions to dirty state */
268 if (phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] != 0xff)
269 return;
bellardaa062972005-08-21 09:30:12 +0000270 if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE)
271 nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL;
272 else
273 ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr;
274}
275
bellardf32fc642006-02-08 22:43:39 +0000276static void kqemu_reset_modified_ram_pages(void)
277{
278 int i;
279 unsigned long page_index;
280
281 for(i = 0; i < nb_modified_ram_pages; i++) {
282 page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS;
283 modified_ram_pages_table[page_index] = 0;
284 }
285 nb_modified_ram_pages = 0;
286}
287
288void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr)
289{
290 unsigned long page_index;
291 int ret;
292#ifdef _WIN32
293 DWORD temp;
294#endif
295
296 page_index = ram_addr >> TARGET_PAGE_BITS;
297 if (!modified_ram_pages_table[page_index]) {
298#if 0
299 printf("%d: modify_page=%08lx\n", nb_modified_ram_pages, ram_addr);
300#endif
301 modified_ram_pages_table[page_index] = 1;
302 modified_ram_pages[nb_modified_ram_pages++] = ram_addr;
303 if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) {
304 /* flush */
305#ifdef _WIN32
306 ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
307 &nb_modified_ram_pages,
308 sizeof(nb_modified_ram_pages),
309 NULL, 0, &temp, NULL);
310#else
311 ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
312 &nb_modified_ram_pages);
313#endif
314 kqemu_reset_modified_ram_pages();
315 }
316 }
317}
318
bellard9df217a2005-02-10 22:05:51 +0000319struct fpstate {
320 uint16_t fpuc;
321 uint16_t dummy1;
322 uint16_t fpus;
323 uint16_t dummy2;
324 uint16_t fptag;
325 uint16_t dummy3;
326
327 uint32_t fpip;
328 uint32_t fpcs;
329 uint32_t fpoo;
330 uint32_t fpos;
331 uint8_t fpregs1[8 * 10];
332};
333
334struct fpxstate {
335 uint16_t fpuc;
336 uint16_t fpus;
337 uint16_t fptag;
338 uint16_t fop;
339 uint32_t fpuip;
340 uint16_t cs_sel;
341 uint16_t dummy0;
342 uint32_t fpudp;
343 uint16_t ds_sel;
344 uint16_t dummy1;
345 uint32_t mxcsr;
346 uint32_t mxcsr_mask;
347 uint8_t fpregs1[8 * 16];
bellardc28e9512005-04-23 17:45:43 +0000348 uint8_t xmm_regs[16 * 16];
349 uint8_t dummy2[96];
bellard9df217a2005-02-10 22:05:51 +0000350};
351
352static struct fpxstate fpx1 __attribute__((aligned(16)));
353
354static void restore_native_fp_frstor(CPUState *env)
355{
356 int fptag, i, j;
357 struct fpstate fp1, *fp = &fp1;
358
359 fp->fpuc = env->fpuc;
360 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
361 fptag = 0;
362 for (i=7; i>=0; i--) {
363 fptag <<= 2;
364 if (env->fptags[i]) {
365 fptag |= 3;
366 } else {
367 /* the FPU automatically computes it */
368 }
369 }
370 fp->fptag = fptag;
371 j = env->fpstt;
372 for(i = 0;i < 8; i++) {
373 memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
374 j = (j + 1) & 7;
375 }
376 asm volatile ("frstor %0" : "=m" (*fp));
377}
378
379static void save_native_fp_fsave(CPUState *env)
380{
381 int fptag, i, j;
382 uint16_t fpuc;
383 struct fpstate fp1, *fp = &fp1;
384
385 asm volatile ("fsave %0" : : "m" (*fp));
386 env->fpuc = fp->fpuc;
387 env->fpstt = (fp->fpus >> 11) & 7;
388 env->fpus = fp->fpus & ~0x3800;
389 fptag = fp->fptag;
390 for(i = 0;i < 8; i++) {
391 env->fptags[i] = ((fptag & 3) == 3);
392 fptag >>= 2;
393 }
394 j = env->fpstt;
395 for(i = 0;i < 8; i++) {
396 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
397 j = (j + 1) & 7;
398 }
399 /* we must restore the default rounding state */
400 fpuc = 0x037f | (env->fpuc & (3 << 10));
401 asm volatile("fldcw %0" : : "m" (fpuc));
402}
403
404static void restore_native_fp_fxrstor(CPUState *env)
405{
406 struct fpxstate *fp = &fpx1;
407 int i, j, fptag;
408
409 fp->fpuc = env->fpuc;
410 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
411 fptag = 0;
412 for(i = 0; i < 8; i++)
413 fptag |= (env->fptags[i] << i);
414 fp->fptag = fptag ^ 0xff;
415
416 j = env->fpstt;
417 for(i = 0;i < 8; i++) {
418 memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
419 j = (j + 1) & 7;
420 }
421 if (env->cpuid_features & CPUID_SSE) {
422 fp->mxcsr = env->mxcsr;
423 /* XXX: check if DAZ is not available */
424 fp->mxcsr_mask = 0xffff;
bellardc28e9512005-04-23 17:45:43 +0000425 memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16);
bellard9df217a2005-02-10 22:05:51 +0000426 }
427 asm volatile ("fxrstor %0" : "=m" (*fp));
428}
429
430static void save_native_fp_fxsave(CPUState *env)
431{
432 struct fpxstate *fp = &fpx1;
433 int fptag, i, j;
434 uint16_t fpuc;
435
436 asm volatile ("fxsave %0" : : "m" (*fp));
437 env->fpuc = fp->fpuc;
438 env->fpstt = (fp->fpus >> 11) & 7;
439 env->fpus = fp->fpus & ~0x3800;
440 fptag = fp->fptag ^ 0xff;
441 for(i = 0;i < 8; i++) {
442 env->fptags[i] = (fptag >> i) & 1;
443 }
444 j = env->fpstt;
445 for(i = 0;i < 8; i++) {
446 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
447 j = (j + 1) & 7;
448 }
449 if (env->cpuid_features & CPUID_SSE) {
450 env->mxcsr = fp->mxcsr;
bellardc28e9512005-04-23 17:45:43 +0000451 memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16);
bellard9df217a2005-02-10 22:05:51 +0000452 }
453
454 /* we must restore the default rounding state */
455 asm volatile ("fninit");
456 fpuc = 0x037f | (env->fpuc & (3 << 10));
457 asm volatile("fldcw %0" : : "m" (fpuc));
458}
459
bellardc28e9512005-04-23 17:45:43 +0000460static int do_syscall(CPUState *env,
461 struct kqemu_cpu_state *kenv)
462{
463 int selector;
464
465 selector = (env->star >> 32) & 0xffff;
466#ifdef __x86_64__
467 if (env->hflags & HF_LMA_MASK) {
468 env->regs[R_ECX] = kenv->next_eip;
469 env->regs[11] = env->eflags;
470
471 cpu_x86_set_cpl(env, 0);
472 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
473 0, 0xffffffff,
474 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
475 DESC_S_MASK |
476 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
477 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
478 0, 0xffffffff,
479 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
480 DESC_S_MASK |
481 DESC_W_MASK | DESC_A_MASK);
482 env->eflags &= ~env->fmask;
483 if (env->hflags & HF_CS64_MASK)
484 env->eip = env->lstar;
485 else
486 env->eip = env->cstar;
487 } else
488#endif
489 {
490 env->regs[R_ECX] = (uint32_t)kenv->next_eip;
491
492 cpu_x86_set_cpl(env, 0);
493 cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
494 0, 0xffffffff,
495 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
496 DESC_S_MASK |
497 DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
498 cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
499 0, 0xffffffff,
500 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
501 DESC_S_MASK |
502 DESC_W_MASK | DESC_A_MASK);
503 env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
504 env->eip = (uint32_t)env->star;
505 }
506 return 2;
507}
508
bellardf32fc642006-02-08 22:43:39 +0000509#ifdef CONFIG_PROFILER
bellardaa062972005-08-21 09:30:12 +0000510
511#define PC_REC_SIZE 1
512#define PC_REC_HASH_BITS 16
513#define PC_REC_HASH_SIZE (1 << PC_REC_HASH_BITS)
514
515typedef struct PCRecord {
516 unsigned long pc;
517 int64_t count;
518 struct PCRecord *next;
519} PCRecord;
520
bellardf32fc642006-02-08 22:43:39 +0000521static PCRecord *pc_rec_hash[PC_REC_HASH_SIZE];
522static int nb_pc_records;
bellardaa062972005-08-21 09:30:12 +0000523
bellardf32fc642006-02-08 22:43:39 +0000524static void kqemu_record_pc(unsigned long pc)
bellardaa062972005-08-21 09:30:12 +0000525{
526 unsigned long h;
527 PCRecord **pr, *r;
528
529 h = pc / PC_REC_SIZE;
530 h = h ^ (h >> PC_REC_HASH_BITS);
531 h &= (PC_REC_HASH_SIZE - 1);
532 pr = &pc_rec_hash[h];
533 for(;;) {
534 r = *pr;
535 if (r == NULL)
536 break;
537 if (r->pc == pc) {
538 r->count++;
539 return;
540 }
541 pr = &r->next;
542 }
543 r = malloc(sizeof(PCRecord));
544 r->count = 1;
545 r->pc = pc;
546 r->next = NULL;
547 *pr = r;
548 nb_pc_records++;
549}
550
bellardf32fc642006-02-08 22:43:39 +0000551static int pc_rec_cmp(const void *p1, const void *p2)
bellardaa062972005-08-21 09:30:12 +0000552{
553 PCRecord *r1 = *(PCRecord **)p1;
554 PCRecord *r2 = *(PCRecord **)p2;
555 if (r1->count < r2->count)
556 return 1;
557 else if (r1->count == r2->count)
558 return 0;
559 else
560 return -1;
561}
562
bellardf32fc642006-02-08 22:43:39 +0000563static void kqemu_record_flush(void)
564{
565 PCRecord *r, *r_next;
566 int h;
567
568 for(h = 0; h < PC_REC_HASH_SIZE; h++) {
569 for(r = pc_rec_hash[h]; r != NULL; r = r_next) {
570 r_next = r->next;
571 free(r);
572 }
573 pc_rec_hash[h] = NULL;
574 }
575 nb_pc_records = 0;
576}
577
bellardaa062972005-08-21 09:30:12 +0000578void kqemu_record_dump(void)
579{
580 PCRecord **pr, *r;
581 int i, h;
582 FILE *f;
583 int64_t total, sum;
584
585 pr = malloc(sizeof(PCRecord *) * nb_pc_records);
586 i = 0;
587 total = 0;
588 for(h = 0; h < PC_REC_HASH_SIZE; h++) {
589 for(r = pc_rec_hash[h]; r != NULL; r = r->next) {
590 pr[i++] = r;
591 total += r->count;
592 }
593 }
594 qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp);
595
596 f = fopen("/tmp/kqemu.stats", "w");
597 if (!f) {
598 perror("/tmp/kqemu.stats");
599 exit(1);
600 }
601 fprintf(f, "total: %lld\n", total);
602 sum = 0;
603 for(i = 0; i < nb_pc_records; i++) {
604 r = pr[i];
605 sum += r->count;
606 fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n",
607 r->pc,
608 r->count,
609 (double)r->count / (double)total * 100.0,
610 (double)sum / (double)total * 100.0);
611 }
612 fclose(f);
613 free(pr);
bellardf32fc642006-02-08 22:43:39 +0000614
615 kqemu_record_flush();
bellardaa062972005-08-21 09:30:12 +0000616}
617#endif
618
bellard9df217a2005-02-10 22:05:51 +0000619int kqemu_cpu_exec(CPUState *env)
620{
621 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
bellardf32fc642006-02-08 22:43:39 +0000622 int ret, cpl, i;
623#ifdef CONFIG_PROFILER
624 int64_t ti;
625#endif
626
bellard6e4255f2005-04-17 18:33:47 +0000627#ifdef _WIN32
628 DWORD temp;
629#endif
bellard9df217a2005-02-10 22:05:51 +0000630
bellardf32fc642006-02-08 22:43:39 +0000631#ifdef CONFIG_PROFILER
632 ti = profile_getclock();
633#endif
bellard9df217a2005-02-10 22:05:51 +0000634#ifdef DEBUG
635 if (loglevel & CPU_LOG_INT) {
636 fprintf(logfile, "kqemu: cpu_exec: enter\n");
637 cpu_dump_state(env, logfile, fprintf, 0);
638 }
639#endif
640 memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
641 kenv->eip = env->eip;
642 kenv->eflags = env->eflags;
643 memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
644 memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
645 memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
646 memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
647 memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
648 kenv->cr0 = env->cr[0];
649 kenv->cr2 = env->cr[2];
650 kenv->cr3 = env->cr[3];
651 kenv->cr4 = env->cr[4];
652 kenv->a20_mask = env->a20_mask;
bellardc45b3c02005-04-24 18:03:37 +0000653#if KQEMU_VERSION >= 0x010100
bellardc28e9512005-04-23 17:45:43 +0000654 kenv->efer = env->efer;
655#endif
bellardf32fc642006-02-08 22:43:39 +0000656#if KQEMU_VERSION >= 0x010300
657 kenv->tsc_offset = 0;
658 kenv->star = env->star;
659 kenv->sysenter_cs = env->sysenter_cs;
660 kenv->sysenter_esp = env->sysenter_esp;
661 kenv->sysenter_eip = env->sysenter_eip;
662#ifdef __x86_64__
663 kenv->lstar = env->lstar;
664 kenv->cstar = env->cstar;
665 kenv->fmask = env->fmask;
666 kenv->kernelgsbase = env->kernelgsbase;
667#endif
668#endif
bellard9df217a2005-02-10 22:05:51 +0000669 if (env->dr[7] & 0xff) {
670 kenv->dr7 = env->dr[7];
671 kenv->dr0 = env->dr[0];
672 kenv->dr1 = env->dr[1];
673 kenv->dr2 = env->dr[2];
674 kenv->dr3 = env->dr[3];
675 } else {
676 kenv->dr7 = 0;
677 }
678 kenv->dr6 = env->dr[6];
bellardf32fc642006-02-08 22:43:39 +0000679 cpl = (env->hflags & HF_CPL_MASK);
680 kenv->cpl = cpl;
bellard9df217a2005-02-10 22:05:51 +0000681 kenv->nb_pages_to_flush = nb_pages_to_flush;
bellardaa062972005-08-21 09:30:12 +0000682#if KQEMU_VERSION >= 0x010200
bellardf32fc642006-02-08 22:43:39 +0000683 kenv->user_only = (env->kqemu_enabled == 1);
bellardaa062972005-08-21 09:30:12 +0000684 kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
685#endif
686 nb_ram_pages_to_update = 0;
bellard9df217a2005-02-10 22:05:51 +0000687
bellardf32fc642006-02-08 22:43:39 +0000688#if KQEMU_VERSION >= 0x010300
689 kenv->nb_modified_ram_pages = nb_modified_ram_pages;
690#endif
691 kqemu_reset_modified_ram_pages();
692
693 if (env->cpuid_features & CPUID_FXSR)
694 restore_native_fp_fxrstor(env);
695 else
696 restore_native_fp_frstor(env);
bellard9df217a2005-02-10 22:05:51 +0000697
bellard6e4255f2005-04-17 18:33:47 +0000698#ifdef _WIN32
bellarda332e112005-09-03 17:55:47 +0000699 if (DeviceIoControl(kqemu_fd, KQEMU_EXEC,
700 kenv, sizeof(struct kqemu_cpu_state),
701 kenv, sizeof(struct kqemu_cpu_state),
702 &temp, NULL)) {
703 ret = kenv->retval;
704 } else {
705 ret = -1;
706 }
bellard6e4255f2005-04-17 18:33:47 +0000707#else
708#if KQEMU_VERSION >= 0x010100
709 ioctl(kqemu_fd, KQEMU_EXEC, kenv);
710 ret = kenv->retval;
711#else
bellard9df217a2005-02-10 22:05:51 +0000712 ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
bellard6e4255f2005-04-17 18:33:47 +0000713#endif
714#endif
bellardf32fc642006-02-08 22:43:39 +0000715 if (env->cpuid_features & CPUID_FXSR)
716 save_native_fp_fxsave(env);
717 else
718 save_native_fp_fsave(env);
bellard9df217a2005-02-10 22:05:51 +0000719
720 memcpy(env->regs, kenv->regs, sizeof(env->regs));
721 env->eip = kenv->eip;
722 env->eflags = kenv->eflags;
723 memcpy(env->segs, kenv->segs, sizeof(env->segs));
bellardf32fc642006-02-08 22:43:39 +0000724 cpu_x86_set_cpl(env, kenv->cpl);
725 memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt));
bellard9df217a2005-02-10 22:05:51 +0000726#if 0
727 /* no need to restore that */
bellard9df217a2005-02-10 22:05:51 +0000728 memcpy(env->tr, kenv->tr, sizeof(env->tr));
729 memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
730 memcpy(env->idt, kenv->idt, sizeof(env->idt));
bellard9df217a2005-02-10 22:05:51 +0000731 env->a20_mask = kenv->a20_mask;
732#endif
bellardf32fc642006-02-08 22:43:39 +0000733 env->cr[0] = kenv->cr0;
734 env->cr[4] = kenv->cr4;
735 env->cr[3] = kenv->cr3;
bellard9df217a2005-02-10 22:05:51 +0000736 env->cr[2] = kenv->cr2;
737 env->dr[6] = kenv->dr6;
bellardf32fc642006-02-08 22:43:39 +0000738#if KQEMU_VERSION >= 0x010300
739#ifdef __x86_64__
740 env->kernelgsbase = kenv->kernelgsbase;
741#endif
742#endif
743
744 /* flush pages as indicated by kqemu */
745 if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) {
746 tlb_flush(env, 1);
747 } else {
748 for(i = 0; i < kenv->nb_pages_to_flush; i++) {
749 tlb_flush_page(env, pages_to_flush[i]);
750 }
751 }
752 nb_pages_to_flush = 0;
753
754#ifdef CONFIG_PROFILER
755 kqemu_time += profile_getclock() - ti;
756 kqemu_exec_count++;
757#endif
bellard9df217a2005-02-10 22:05:51 +0000758
bellardaa062972005-08-21 09:30:12 +0000759#if KQEMU_VERSION >= 0x010200
760 if (kenv->nb_ram_pages_to_update > 0) {
761 cpu_tlb_update_dirty(env);
762 }
763#endif
764
bellardf32fc642006-02-08 22:43:39 +0000765#if KQEMU_VERSION >= 0x010300
766 if (kenv->nb_modified_ram_pages > 0) {
767 for(i = 0; i < kenv->nb_modified_ram_pages; i++) {
768 unsigned long addr;
769 addr = modified_ram_pages[i];
770 tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0);
771 }
772 }
773#endif
774
bellardaa062972005-08-21 09:30:12 +0000775 /* restore the hidden flags */
776 {
777 unsigned int new_hflags;
778#ifdef TARGET_X86_64
779 if ((env->hflags & HF_LMA_MASK) &&
780 (env->segs[R_CS].flags & DESC_L_MASK)) {
781 /* long mode */
782 new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
783 } else
784#endif
785 {
786 /* legacy / compatibility case */
787 new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
788 >> (DESC_B_SHIFT - HF_CS32_SHIFT);
789 new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
790 >> (DESC_B_SHIFT - HF_SS32_SHIFT);
791 if (!(env->cr[0] & CR0_PE_MASK) ||
792 (env->eflags & VM_MASK) ||
793 !(env->hflags & HF_CS32_MASK)) {
794 /* XXX: try to avoid this test. The problem comes from the
795 fact that is real mode or vm86 mode we only modify the
796 'base' and 'selector' fields of the segment cache to go
797 faster. A solution may be to force addseg to one in
798 translate-i386.c. */
799 new_hflags |= HF_ADDSEG_MASK;
800 } else {
801 new_hflags |= ((env->segs[R_DS].base |
802 env->segs[R_ES].base |
803 env->segs[R_SS].base) != 0) <<
804 HF_ADDSEG_SHIFT;
805 }
806 }
807 env->hflags = (env->hflags &
808 ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |
809 new_hflags;
810 }
bellardf32fc642006-02-08 22:43:39 +0000811 /* update FPU flags */
812 env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
813 ((env->cr[0] << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
814 if (env->cr[4] & CR4_OSFXSR_MASK)
815 env->hflags |= HF_OSFXSR_MASK;
816 else
817 env->hflags &= ~HF_OSFXSR_MASK;
818
bellard9df217a2005-02-10 22:05:51 +0000819#ifdef DEBUG
820 if (loglevel & CPU_LOG_INT) {
821 fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
822 }
823#endif
bellardc28e9512005-04-23 17:45:43 +0000824 if (ret == KQEMU_RET_SYSCALL) {
825 /* syscall instruction */
826 return do_syscall(env, kenv);
827 } else
bellard9df217a2005-02-10 22:05:51 +0000828 if ((ret & 0xff00) == KQEMU_RET_INT) {
829 env->exception_index = ret & 0xff;
830 env->error_code = 0;
831 env->exception_is_int = 1;
832 env->exception_next_eip = kenv->next_eip;
bellardf32fc642006-02-08 22:43:39 +0000833#ifdef CONFIG_PROFILER
834 kqemu_ret_int_count++;
835#endif
bellard9df217a2005-02-10 22:05:51 +0000836#ifdef DEBUG
bellardc28e9512005-04-23 17:45:43 +0000837 if (loglevel & CPU_LOG_INT) {
838 fprintf(logfile, "kqemu: interrupt v=%02x:\n",
839 env->exception_index);
840 cpu_dump_state(env, logfile, fprintf, 0);
841 }
bellard9df217a2005-02-10 22:05:51 +0000842#endif
843 return 1;
844 } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
845 env->exception_index = ret & 0xff;
846 env->error_code = kenv->error_code;
847 env->exception_is_int = 0;
848 env->exception_next_eip = 0;
bellardf32fc642006-02-08 22:43:39 +0000849#ifdef CONFIG_PROFILER
850 kqemu_ret_excp_count++;
851#endif
bellard9df217a2005-02-10 22:05:51 +0000852#ifdef DEBUG
853 if (loglevel & CPU_LOG_INT) {
854 fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
855 env->exception_index, env->error_code);
856 cpu_dump_state(env, logfile, fprintf, 0);
857 }
858#endif
859 return 1;
860 } else if (ret == KQEMU_RET_INTR) {
bellardf32fc642006-02-08 22:43:39 +0000861#ifdef CONFIG_PROFILER
862 kqemu_ret_intr_count++;
863#endif
bellardc45b3c02005-04-24 18:03:37 +0000864#ifdef DEBUG
865 if (loglevel & CPU_LOG_INT) {
866 cpu_dump_state(env, logfile, fprintf, 0);
867 }
868#endif
bellard9df217a2005-02-10 22:05:51 +0000869 return 0;
870 } else if (ret == KQEMU_RET_SOFTMMU) {
bellardf32fc642006-02-08 22:43:39 +0000871#ifdef CONFIG_PROFILER
872 {
873 unsigned long pc = env->eip + env->segs[R_CS].base;
874 kqemu_record_pc(pc);
875 }
bellardaa062972005-08-21 09:30:12 +0000876#endif
877#ifdef DEBUG
878 if (loglevel & CPU_LOG_INT) {
879 cpu_dump_state(env, logfile, fprintf, 0);
880 }
881#endif
bellard9df217a2005-02-10 22:05:51 +0000882 return 2;
883 } else {
884 cpu_dump_state(env, stderr, fprintf, 0);
885 fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
886 exit(1);
887 }
888 return 0;
889}
890
bellarda332e112005-09-03 17:55:47 +0000891void kqemu_cpu_interrupt(CPUState *env)
892{
893#if defined(_WIN32) && KQEMU_VERSION >= 0x010101
894 /* cancelling the I/O request causes KQEMU to finish executing the
895 current block and successfully returning. */
896 CancelIo(kqemu_fd);
897#endif
898}
899
bellard9df217a2005-02-10 22:05:51 +0000900#endif