Commit f32fc64851c28e2dd3976d08f93006a3eff68a3d

Authored by bellard
1 parent f1c85677

optional support for kernel code virtualization


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1753 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-exec.c
... ... @@ -627,6 +627,9 @@ int cpu_exec(CPUState *env1)
627 627 jump. */
628 628 {
629 629 if (T0 != 0 &&
  630 +#if USE_KQEMU
  631 + (env->kqemu_enabled != 2) &&
  632 +#endif
630 633 tb->page_addr[1] == -1
631 634 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
632 635 && (tb->cflags & CF_CODE_COPY) ==
... ... @@ -756,6 +759,13 @@ int cpu_exec(CPUState *env1)
756 759 T0 = 0;
757 760 }
758 761 #endif
  762 +#if defined(USE_KQEMU)
  763 +#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
  764 + if (kqemu_is_ok(env) &&
  765 + (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
  766 + cpu_loop_exit();
  767 + }
  768 +#endif
759 769 }
760 770 } else {
761 771 env_to_regs();
... ...
exec-all.h
... ... @@ -577,21 +577,27 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
577 577  
578 578  
579 579 #ifdef USE_KQEMU
  580 +#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
  581 +
580 582 int kqemu_init(CPUState *env);
581 583 int kqemu_cpu_exec(CPUState *env);
582 584 void kqemu_flush_page(CPUState *env, target_ulong addr);
583 585 void kqemu_flush(CPUState *env, int global);
584 586 void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
  587 +void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
585 588 void kqemu_cpu_interrupt(CPUState *env);
  589 +void kqemu_record_dump(void);
586 590  
587 591 static inline int kqemu_is_ok(CPUState *env)
588 592 {
589 593 return(env->kqemu_enabled &&
590   - (env->hflags & HF_CPL_MASK) == 3 &&
591   - (env->eflags & IOPL_MASK) != IOPL_MASK &&
592 594 (env->cr[0] & CR0_PE_MASK) &&
  595 + !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
593 596 (env->eflags & IF_MASK) &&
594   - !(env->eflags & VM_MASK));
  597 + !(env->eflags & VM_MASK) &&
  598 + (env->kqemu_enabled == 2 ||
  599 + ((env->hflags & HF_CPL_MASK) == 3 &&
  600 + (env->eflags & IOPL_MASK) != IOPL_MASK)));
595 601 }
596 602  
597 603 #endif
... ...
... ... @@ -1796,6 +1796,11 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t
1796 1796 #endif
1797 1797 }
1798 1798 stb_p((uint8_t *)(long)addr, val);
  1799 +#ifdef USE_KQEMU
  1800 + if (cpu_single_env->kqemu_enabled &&
  1801 + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
  1802 + kqemu_modify_page(cpu_single_env, ram_addr);
  1803 +#endif
1799 1804 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1800 1805 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1801 1806 /* we remove the notdirty callback only if the code has been
... ... @@ -1817,6 +1822,11 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t
1817 1822 #endif
1818 1823 }
1819 1824 stw_p((uint8_t *)(long)addr, val);
  1825 +#ifdef USE_KQEMU
  1826 + if (cpu_single_env->kqemu_enabled &&
  1827 + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
  1828 + kqemu_modify_page(cpu_single_env, ram_addr);
  1829 +#endif
1820 1830 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1821 1831 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1822 1832 /* we remove the notdirty callback only if the code has been
... ... @@ -1838,6 +1848,11 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t
1838 1848 #endif
1839 1849 }
1840 1850 stl_p((uint8_t *)(long)addr, val);
  1851 +#ifdef USE_KQEMU
  1852 + if (cpu_single_env->kqemu_enabled &&
  1853 + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
  1854 + kqemu_modify_page(cpu_single_env, ram_addr);
  1855 +#endif
1841 1856 dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1842 1857 phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
1843 1858 /* we remove the notdirty callback only if the code has been
... ...
... ... @@ -54,6 +54,9 @@
54 54 #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512
55 55 #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1)
56 56 #endif
  57 +#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES
  58 +#define KQEMU_MAX_MODIFIED_RAM_PAGES 512
  59 +#endif
57 60  
58 61 #ifdef _WIN32
59 62 #define KQEMU_DEVICE "\\\\.\\kqemu"
... ... @@ -71,11 +74,18 @@ int kqemu_fd = KQEMU_INVALID_FD;
71 74 #define kqemu_closefd(x) close(x)
72 75 #endif
73 76  
  77 +/* 0 = not allowed
  78 + 1 = user kqemu
  79 + 2 = kernel kqemu
  80 +*/
74 81 int kqemu_allowed = 1;
75 82 unsigned long *pages_to_flush;
76 83 unsigned int nb_pages_to_flush;
77 84 unsigned long *ram_pages_to_update;
78 85 unsigned int nb_ram_pages_to_update;
  86 +unsigned long *modified_ram_pages;
  87 +unsigned int nb_modified_ram_pages;
  88 +uint8_t *modified_ram_pages_table;
79 89 extern uint32_t **l1_phys_map;
80 90  
81 91 #define cpuid(index, eax, ebx, ecx, edx) \
... ... @@ -185,6 +195,14 @@ int kqemu_init(CPUState *env)
185 195 if (!ram_pages_to_update)
186 196 goto fail;
187 197  
  198 + 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 +
188 206 init.ram_base = phys_ram_base;
189 207 init.ram_size = phys_ram_size;
190 208 init.ram_dirty = phys_ram_dirty;
... ... @@ -193,6 +211,9 @@ int kqemu_init(CPUState *env)
193 211 #if KQEMU_VERSION >= 0x010200
194 212 init.ram_pages_to_update = ram_pages_to_update;
195 213 #endif
  214 +#if KQEMU_VERSION >= 0x010300
  215 + init.modified_ram_pages = modified_ram_pages;
  216 +#endif
196 217 #ifdef _WIN32
197 218 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init),
198 219 NULL, 0, &temp, NULL) == TRUE ? 0 : -1;
... ... @@ -207,7 +228,7 @@ int kqemu_init(CPUState *env)
207 228 return -1;
208 229 }
209 230 kqemu_update_cpuid(env);
210   - env->kqemu_enabled = 1;
  231 + env->kqemu_enabled = kqemu_allowed;
211 232 nb_pages_to_flush = 0;
212 233 nb_ram_pages_to_update = 0;
213 234 return 0;
... ... @@ -215,7 +236,7 @@ int kqemu_init(CPUState *env)
215 236  
216 237 void kqemu_flush_page(CPUState *env, target_ulong addr)
217 238 {
218   -#ifdef DEBUG
  239 +#if defined(DEBUG)
219 240 if (loglevel & CPU_LOG_INT) {
220 241 fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
221 242 }
... ... @@ -252,6 +273,49 @@ void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
252 273 ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr;
253 274 }
254 275  
  276 +static 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 +
  288 +void 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 +
255 319 struct fpstate {
256 320 uint16_t fpuc;
257 321 uint16_t dummy1;
... ... @@ -442,7 +506,7 @@ static int do_syscall(CPUState *env,
442 506 return 2;
443 507 }
444 508  
445   -#ifdef PROFILE
  509 +#ifdef CONFIG_PROFILER
446 510  
447 511 #define PC_REC_SIZE 1
448 512 #define PC_REC_HASH_BITS 16
... ... @@ -454,10 +518,10 @@ typedef struct PCRecord {
454 518 struct PCRecord *next;
455 519 } PCRecord;
456 520  
457   -PCRecord *pc_rec_hash[PC_REC_HASH_SIZE];
458   -int nb_pc_records;
  521 +static PCRecord *pc_rec_hash[PC_REC_HASH_SIZE];
  522 +static int nb_pc_records;
459 523  
460   -void kqemu_record_pc(unsigned long pc)
  524 +static void kqemu_record_pc(unsigned long pc)
461 525 {
462 526 unsigned long h;
463 527 PCRecord **pr, *r;
... ... @@ -484,7 +548,7 @@ void kqemu_record_pc(unsigned long pc)
484 548 nb_pc_records++;
485 549 }
486 550  
487   -int pc_rec_cmp(const void *p1, const void *p2)
  551 +static int pc_rec_cmp(const void *p1, const void *p2)
488 552 {
489 553 PCRecord *r1 = *(PCRecord **)p1;
490 554 PCRecord *r2 = *(PCRecord **)p2;
... ... @@ -496,6 +560,21 @@ int pc_rec_cmp(const void *p1, const void *p2)
496 560 return -1;
497 561 }
498 562  
  563 +static 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 +
499 578 void kqemu_record_dump(void)
500 579 {
501 580 PCRecord **pr, *r;
... ... @@ -532,21 +611,26 @@ void kqemu_record_dump(void)
532 611 }
533 612 fclose(f);
534 613 free(pr);
535   -}
536   -#else
537   -void kqemu_record_dump(void)
538   -{
  614 +
  615 + kqemu_record_flush();
539 616 }
540 617 #endif
541 618  
542 619 int kqemu_cpu_exec(CPUState *env)
543 620 {
544 621 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
545   - int ret;
  622 + int ret, cpl, i;
  623 +#ifdef CONFIG_PROFILER
  624 + int64_t ti;
  625 +#endif
  626 +
546 627 #ifdef _WIN32
547 628 DWORD temp;
548 629 #endif
549 630  
  631 +#ifdef CONFIG_PROFILER
  632 + ti = profile_getclock();
  633 +#endif
550 634 #ifdef DEBUG
551 635 if (loglevel & CPU_LOG_INT) {
552 636 fprintf(logfile, "kqemu: cpu_exec: enter\n");
... ... @@ -569,6 +653,19 @@ int kqemu_cpu_exec(CPUState *env)
569 653 #if KQEMU_VERSION >= 0x010100
570 654 kenv->efer = env->efer;
571 655 #endif
  656 +#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
572 669 if (env->dr[7] & 0xff) {
573 670 kenv->dr7 = env->dr[7];
574 671 kenv->dr0 = env->dr[0];
... ... @@ -579,21 +676,24 @@ int kqemu_cpu_exec(CPUState *env)
579 676 kenv->dr7 = 0;
580 677 }
581 678 kenv->dr6 = env->dr[6];
582   - kenv->cpl = 3;
  679 + cpl = (env->hflags & HF_CPL_MASK);
  680 + kenv->cpl = cpl;
583 681 kenv->nb_pages_to_flush = nb_pages_to_flush;
584   - nb_pages_to_flush = 0;
585 682 #if KQEMU_VERSION >= 0x010200
586   - kenv->user_only = 1;
  683 + kenv->user_only = (env->kqemu_enabled == 1);
587 684 kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
588 685 #endif
589 686 nb_ram_pages_to_update = 0;
590 687  
591   - if (!(kenv->cr0 & CR0_TS_MASK)) {
592   - if (env->cpuid_features & CPUID_FXSR)
593   - restore_native_fp_fxrstor(env);
594   - else
595   - restore_native_fp_frstor(env);
596   - }
  688 +#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);
597 697  
598 698 #ifdef _WIN32
599 699 if (DeviceIoControl(kqemu_fd, KQEMU_EXEC,
... ... @@ -612,30 +712,49 @@ int kqemu_cpu_exec(CPUState *env)
612 712 ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
613 713 #endif
614 714 #endif
615   - if (!(kenv->cr0 & CR0_TS_MASK)) {
616   - if (env->cpuid_features & CPUID_FXSR)
617   - save_native_fp_fxsave(env);
618   - else
619   - save_native_fp_fsave(env);
620   - }
  715 + if (env->cpuid_features & CPUID_FXSR)
  716 + save_native_fp_fxsave(env);
  717 + else
  718 + save_native_fp_fsave(env);
621 719  
622 720 memcpy(env->regs, kenv->regs, sizeof(env->regs));
623 721 env->eip = kenv->eip;
624 722 env->eflags = kenv->eflags;
625 723 memcpy(env->segs, kenv->segs, sizeof(env->segs));
  724 + cpu_x86_set_cpl(env, kenv->cpl);
  725 + memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt));
626 726 #if 0
627 727 /* no need to restore that */
628   - memcpy(env->ldt, kenv->ldt, sizeof(env->ldt));
629 728 memcpy(env->tr, kenv->tr, sizeof(env->tr));
630 729 memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
631 730 memcpy(env->idt, kenv->idt, sizeof(env->idt));
632   - env->cr[0] = kenv->cr0;
633   - env->cr[3] = kenv->cr3;
634   - env->cr[4] = kenv->cr4;
635 731 env->a20_mask = kenv->a20_mask;
636 732 #endif
  733 + env->cr[0] = kenv->cr0;
  734 + env->cr[4] = kenv->cr4;
  735 + env->cr[3] = kenv->cr3;
637 736 env->cr[2] = kenv->cr2;
638 737 env->dr[6] = kenv->dr6;
  738 +#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
639 758  
640 759 #if KQEMU_VERSION >= 0x010200
641 760 if (kenv->nb_ram_pages_to_update > 0) {
... ... @@ -643,6 +762,16 @@ int kqemu_cpu_exec(CPUState *env)
643 762 }
644 763 #endif
645 764  
  765 +#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 +
646 775 /* restore the hidden flags */
647 776 {
648 777 unsigned int new_hflags;
... ... @@ -679,7 +808,14 @@ int kqemu_cpu_exec(CPUState *env)
679 808 ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |
680 809 new_hflags;
681 810 }
682   -
  811 + /* 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 +
683 819 #ifdef DEBUG
684 820 if (loglevel & CPU_LOG_INT) {
685 821 fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
... ... @@ -694,6 +830,9 @@ int kqemu_cpu_exec(CPUState *env)
694 830 env->error_code = 0;
695 831 env->exception_is_int = 1;
696 832 env->exception_next_eip = kenv->next_eip;
  833 +#ifdef CONFIG_PROFILER
  834 + kqemu_ret_int_count++;
  835 +#endif
697 836 #ifdef DEBUG
698 837 if (loglevel & CPU_LOG_INT) {
699 838 fprintf(logfile, "kqemu: interrupt v=%02x:\n",
... ... @@ -707,6 +846,9 @@ int kqemu_cpu_exec(CPUState *env)
707 846 env->error_code = kenv->error_code;
708 847 env->exception_is_int = 0;
709 848 env->exception_next_eip = 0;
  849 +#ifdef CONFIG_PROFILER
  850 + kqemu_ret_excp_count++;
  851 +#endif
710 852 #ifdef DEBUG
711 853 if (loglevel & CPU_LOG_INT) {
712 854 fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
... ... @@ -716,6 +858,9 @@ int kqemu_cpu_exec(CPUState *env)
716 858 #endif
717 859 return 1;
718 860 } else if (ret == KQEMU_RET_INTR) {
  861 +#ifdef CONFIG_PROFILER
  862 + kqemu_ret_intr_count++;
  863 +#endif
719 864 #ifdef DEBUG
720 865 if (loglevel & CPU_LOG_INT) {
721 866 cpu_dump_state(env, logfile, fprintf, 0);
... ... @@ -723,8 +868,11 @@ int kqemu_cpu_exec(CPUState *env)
723 868 #endif
724 869 return 0;
725 870 } else if (ret == KQEMU_RET_SOFTMMU) {
726   -#ifdef PROFILE
727   - kqemu_record_pc(env->eip + env->segs[R_CS].base);
  871 +#ifdef CONFIG_PROFILER
  872 + {
  873 + unsigned long pc = env->eip + env->segs[R_CS].base;
  874 + kqemu_record_pc(pc);
  875 + }
728 876 #endif
729 877 #ifdef DEBUG
730 878 if (loglevel & CPU_LOG_INT) {
... ...