Commit aa0629734011106231e02fca3c19e9e0e24c02be
1 parent
3a7d929e
kqemu fixes - new API support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1545 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
182 additions
and
0 deletions
kqemu.c
@@ -40,6 +40,7 @@ | @@ -40,6 +40,7 @@ | ||
40 | #ifdef USE_KQEMU | 40 | #ifdef USE_KQEMU |
41 | 41 | ||
42 | #define DEBUG | 42 | #define DEBUG |
43 | +//#define PROFILE | ||
43 | 44 | ||
44 | #include <unistd.h> | 45 | #include <unistd.h> |
45 | #include <fcntl.h> | 46 | #include <fcntl.h> |
@@ -49,6 +50,10 @@ | @@ -49,6 +50,10 @@ | ||
49 | #ifndef KQEMU_RET_SYSCALL | 50 | #ifndef KQEMU_RET_SYSCALL |
50 | #define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ | 51 | #define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ |
51 | #endif | 52 | #endif |
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 | ||
52 | 57 | ||
53 | #ifdef _WIN32 | 58 | #ifdef _WIN32 |
54 | #define KQEMU_DEVICE "\\\\.\\kqemu" | 59 | #define KQEMU_DEVICE "\\\\.\\kqemu" |
@@ -69,6 +74,8 @@ int kqemu_fd = KQEMU_INVALID_FD; | @@ -69,6 +74,8 @@ int kqemu_fd = KQEMU_INVALID_FD; | ||
69 | int kqemu_allowed = 1; | 74 | int kqemu_allowed = 1; |
70 | unsigned long *pages_to_flush; | 75 | unsigned long *pages_to_flush; |
71 | unsigned int nb_pages_to_flush; | 76 | unsigned int nb_pages_to_flush; |
77 | +unsigned long *ram_pages_to_update; | ||
78 | +unsigned int nb_ram_pages_to_update; | ||
72 | extern uint32_t **l1_phys_map; | 79 | extern uint32_t **l1_phys_map; |
73 | 80 | ||
74 | #define cpuid(index, eax, ebx, ecx, edx) \ | 81 | #define cpuid(index, eax, ebx, ecx, edx) \ |
@@ -167,11 +174,19 @@ int kqemu_init(CPUState *env) | @@ -167,11 +174,19 @@ int kqemu_init(CPUState *env) | ||
167 | if (!pages_to_flush) | 174 | if (!pages_to_flush) |
168 | goto fail; | 175 | goto fail; |
169 | 176 | ||
177 | + ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * | ||
178 | + sizeof(unsigned long)); | ||
179 | + if (!ram_pages_to_update) | ||
180 | + goto fail; | ||
181 | + | ||
170 | init.ram_base = phys_ram_base; | 182 | init.ram_base = phys_ram_base; |
171 | init.ram_size = phys_ram_size; | 183 | init.ram_size = phys_ram_size; |
172 | init.ram_dirty = phys_ram_dirty; | 184 | init.ram_dirty = phys_ram_dirty; |
173 | init.phys_to_ram_map = l1_phys_map; | 185 | init.phys_to_ram_map = l1_phys_map; |
174 | init.pages_to_flush = pages_to_flush; | 186 | init.pages_to_flush = pages_to_flush; |
187 | +#if KQEMU_VERSION >= 0x010200 | ||
188 | + init.ram_pages_to_update = ram_pages_to_update; | ||
189 | +#endif | ||
175 | #ifdef _WIN32 | 190 | #ifdef _WIN32 |
176 | ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), | 191 | ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), |
177 | NULL, 0, &temp, NULL) == TRUE ? 0 : -1; | 192 | NULL, 0, &temp, NULL) == TRUE ? 0 : -1; |
@@ -188,6 +203,7 @@ int kqemu_init(CPUState *env) | @@ -188,6 +203,7 @@ int kqemu_init(CPUState *env) | ||
188 | kqemu_update_cpuid(env); | 203 | kqemu_update_cpuid(env); |
189 | env->kqemu_enabled = 1; | 204 | env->kqemu_enabled = 1; |
190 | nb_pages_to_flush = 0; | 205 | nb_pages_to_flush = 0; |
206 | + nb_ram_pages_to_update = 0; | ||
191 | return 0; | 207 | return 0; |
192 | } | 208 | } |
193 | 209 | ||
@@ -214,6 +230,19 @@ void kqemu_flush(CPUState *env, int global) | @@ -214,6 +230,19 @@ void kqemu_flush(CPUState *env, int global) | ||
214 | nb_pages_to_flush = KQEMU_FLUSH_ALL; | 230 | nb_pages_to_flush = KQEMU_FLUSH_ALL; |
215 | } | 231 | } |
216 | 232 | ||
233 | +void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr) | ||
234 | +{ | ||
235 | +#ifdef DEBUG | ||
236 | + if (loglevel & CPU_LOG_INT) { | ||
237 | + fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr); | ||
238 | + } | ||
239 | +#endif | ||
240 | + if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE) | ||
241 | + nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL; | ||
242 | + else | ||
243 | + ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr; | ||
244 | +} | ||
245 | + | ||
217 | struct fpstate { | 246 | struct fpstate { |
218 | uint16_t fpuc; | 247 | uint16_t fpuc; |
219 | uint16_t dummy1; | 248 | uint16_t dummy1; |
@@ -404,6 +433,103 @@ static int do_syscall(CPUState *env, | @@ -404,6 +433,103 @@ static int do_syscall(CPUState *env, | ||
404 | return 2; | 433 | return 2; |
405 | } | 434 | } |
406 | 435 | ||
436 | +#ifdef PROFILE | ||
437 | + | ||
438 | +#define PC_REC_SIZE 1 | ||
439 | +#define PC_REC_HASH_BITS 16 | ||
440 | +#define PC_REC_HASH_SIZE (1 << PC_REC_HASH_BITS) | ||
441 | + | ||
442 | +typedef struct PCRecord { | ||
443 | + unsigned long pc; | ||
444 | + int64_t count; | ||
445 | + struct PCRecord *next; | ||
446 | +} PCRecord; | ||
447 | + | ||
448 | +PCRecord *pc_rec_hash[PC_REC_HASH_SIZE]; | ||
449 | +int nb_pc_records; | ||
450 | + | ||
451 | +void kqemu_record_pc(unsigned long pc) | ||
452 | +{ | ||
453 | + unsigned long h; | ||
454 | + PCRecord **pr, *r; | ||
455 | + | ||
456 | + h = pc / PC_REC_SIZE; | ||
457 | + h = h ^ (h >> PC_REC_HASH_BITS); | ||
458 | + h &= (PC_REC_HASH_SIZE - 1); | ||
459 | + pr = &pc_rec_hash[h]; | ||
460 | + for(;;) { | ||
461 | + r = *pr; | ||
462 | + if (r == NULL) | ||
463 | + break; | ||
464 | + if (r->pc == pc) { | ||
465 | + r->count++; | ||
466 | + return; | ||
467 | + } | ||
468 | + pr = &r->next; | ||
469 | + } | ||
470 | + r = malloc(sizeof(PCRecord)); | ||
471 | + r->count = 1; | ||
472 | + r->pc = pc; | ||
473 | + r->next = NULL; | ||
474 | + *pr = r; | ||
475 | + nb_pc_records++; | ||
476 | +} | ||
477 | + | ||
478 | +int pc_rec_cmp(const void *p1, const void *p2) | ||
479 | +{ | ||
480 | + PCRecord *r1 = *(PCRecord **)p1; | ||
481 | + PCRecord *r2 = *(PCRecord **)p2; | ||
482 | + if (r1->count < r2->count) | ||
483 | + return 1; | ||
484 | + else if (r1->count == r2->count) | ||
485 | + return 0; | ||
486 | + else | ||
487 | + return -1; | ||
488 | +} | ||
489 | + | ||
490 | +void kqemu_record_dump(void) | ||
491 | +{ | ||
492 | + PCRecord **pr, *r; | ||
493 | + int i, h; | ||
494 | + FILE *f; | ||
495 | + int64_t total, sum; | ||
496 | + | ||
497 | + pr = malloc(sizeof(PCRecord *) * nb_pc_records); | ||
498 | + i = 0; | ||
499 | + total = 0; | ||
500 | + for(h = 0; h < PC_REC_HASH_SIZE; h++) { | ||
501 | + for(r = pc_rec_hash[h]; r != NULL; r = r->next) { | ||
502 | + pr[i++] = r; | ||
503 | + total += r->count; | ||
504 | + } | ||
505 | + } | ||
506 | + qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp); | ||
507 | + | ||
508 | + f = fopen("/tmp/kqemu.stats", "w"); | ||
509 | + if (!f) { | ||
510 | + perror("/tmp/kqemu.stats"); | ||
511 | + exit(1); | ||
512 | + } | ||
513 | + fprintf(f, "total: %lld\n", total); | ||
514 | + sum = 0; | ||
515 | + for(i = 0; i < nb_pc_records; i++) { | ||
516 | + r = pr[i]; | ||
517 | + sum += r->count; | ||
518 | + fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n", | ||
519 | + r->pc, | ||
520 | + r->count, | ||
521 | + (double)r->count / (double)total * 100.0, | ||
522 | + (double)sum / (double)total * 100.0); | ||
523 | + } | ||
524 | + fclose(f); | ||
525 | + free(pr); | ||
526 | +} | ||
527 | +#else | ||
528 | +void kqemu_record_dump(void) | ||
529 | +{ | ||
530 | +} | ||
531 | +#endif | ||
532 | + | ||
407 | int kqemu_cpu_exec(CPUState *env) | 533 | int kqemu_cpu_exec(CPUState *env) |
408 | { | 534 | { |
409 | struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; | 535 | struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; |
@@ -447,6 +573,11 @@ int kqemu_cpu_exec(CPUState *env) | @@ -447,6 +573,11 @@ int kqemu_cpu_exec(CPUState *env) | ||
447 | kenv->cpl = 3; | 573 | kenv->cpl = 3; |
448 | kenv->nb_pages_to_flush = nb_pages_to_flush; | 574 | kenv->nb_pages_to_flush = nb_pages_to_flush; |
449 | nb_pages_to_flush = 0; | 575 | nb_pages_to_flush = 0; |
576 | +#if KQEMU_VERSION >= 0x010200 | ||
577 | + kenv->user_only = 1; | ||
578 | + kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; | ||
579 | +#endif | ||
580 | + nb_ram_pages_to_update = 0; | ||
450 | 581 | ||
451 | if (!(kenv->cr0 & CR0_TS_MASK)) { | 582 | if (!(kenv->cr0 & CR0_TS_MASK)) { |
452 | if (env->cpuid_features & CPUID_FXSR) | 583 | if (env->cpuid_features & CPUID_FXSR) |
@@ -494,6 +625,49 @@ int kqemu_cpu_exec(CPUState *env) | @@ -494,6 +625,49 @@ int kqemu_cpu_exec(CPUState *env) | ||
494 | env->cr[2] = kenv->cr2; | 625 | env->cr[2] = kenv->cr2; |
495 | env->dr[6] = kenv->dr6; | 626 | env->dr[6] = kenv->dr6; |
496 | 627 | ||
628 | +#if KQEMU_VERSION >= 0x010200 | ||
629 | + if (kenv->nb_ram_pages_to_update > 0) { | ||
630 | + cpu_tlb_update_dirty(env); | ||
631 | + } | ||
632 | +#endif | ||
633 | + | ||
634 | + /* restore the hidden flags */ | ||
635 | + { | ||
636 | + unsigned int new_hflags; | ||
637 | +#ifdef TARGET_X86_64 | ||
638 | + if ((env->hflags & HF_LMA_MASK) && | ||
639 | + (env->segs[R_CS].flags & DESC_L_MASK)) { | ||
640 | + /* long mode */ | ||
641 | + new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; | ||
642 | + } else | ||
643 | +#endif | ||
644 | + { | ||
645 | + /* legacy / compatibility case */ | ||
646 | + new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) | ||
647 | + >> (DESC_B_SHIFT - HF_CS32_SHIFT); | ||
648 | + new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) | ||
649 | + >> (DESC_B_SHIFT - HF_SS32_SHIFT); | ||
650 | + if (!(env->cr[0] & CR0_PE_MASK) || | ||
651 | + (env->eflags & VM_MASK) || | ||
652 | + !(env->hflags & HF_CS32_MASK)) { | ||
653 | + /* XXX: try to avoid this test. The problem comes from the | ||
654 | + fact that is real mode or vm86 mode we only modify the | ||
655 | + 'base' and 'selector' fields of the segment cache to go | ||
656 | + faster. A solution may be to force addseg to one in | ||
657 | + translate-i386.c. */ | ||
658 | + new_hflags |= HF_ADDSEG_MASK; | ||
659 | + } else { | ||
660 | + new_hflags |= ((env->segs[R_DS].base | | ||
661 | + env->segs[R_ES].base | | ||
662 | + env->segs[R_SS].base) != 0) << | ||
663 | + HF_ADDSEG_SHIFT; | ||
664 | + } | ||
665 | + } | ||
666 | + env->hflags = (env->hflags & | ||
667 | + ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) | | ||
668 | + new_hflags; | ||
669 | + } | ||
670 | + | ||
497 | #ifdef DEBUG | 671 | #ifdef DEBUG |
498 | if (loglevel & CPU_LOG_INT) { | 672 | if (loglevel & CPU_LOG_INT) { |
499 | fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); | 673 | fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); |
@@ -537,6 +711,14 @@ int kqemu_cpu_exec(CPUState *env) | @@ -537,6 +711,14 @@ int kqemu_cpu_exec(CPUState *env) | ||
537 | #endif | 711 | #endif |
538 | return 0; | 712 | return 0; |
539 | } else if (ret == KQEMU_RET_SOFTMMU) { | 713 | } else if (ret == KQEMU_RET_SOFTMMU) { |
714 | +#ifdef PROFILE | ||
715 | + kqemu_record_pc(env->eip + env->segs[R_CS].base); | ||
716 | +#endif | ||
717 | +#ifdef DEBUG | ||
718 | + if (loglevel & CPU_LOG_INT) { | ||
719 | + cpu_dump_state(env, logfile, fprintf, 0); | ||
720 | + } | ||
721 | +#endif | ||
540 | return 2; | 722 | return 2; |
541 | } else { | 723 | } else { |
542 | cpu_dump_state(env, stderr, fprintf, 0); | 724 | cpu_dump_state(env, stderr, fprintf, 0); |