Commit da260249a4109b1ac82016b27973c50f0a74311a
1 parent
da94d263
kqemu API change - allow use of kqemu with 32 bit QEMU on a 64 bit host
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4628 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
285 additions
and
135 deletions
configure
| ... | ... | @@ -1222,7 +1222,7 @@ case "$target_cpu" in |
| 1222 | 1222 | echo "TARGET_ARCH=i386" >> $config_mak |
| 1223 | 1223 | echo "#define TARGET_ARCH \"i386\"" >> $config_h |
| 1224 | 1224 | echo "#define TARGET_I386 1" >> $config_h |
| 1225 | - if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "i386" | |
| 1225 | + if test $kqemu = "yes" -a "$target_softmmu" = "yes" | |
| 1226 | 1226 | then |
| 1227 | 1227 | echo "#define USE_KQEMU 1" >> $config_h |
| 1228 | 1228 | fi | ... | ... |
exec-all.h
| ... | ... | @@ -563,15 +563,21 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) |
| 563 | 563 | #ifdef USE_KQEMU |
| 564 | 564 | #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) |
| 565 | 565 | |
| 566 | +#define MSR_QPI_COMMBASE 0xfabe0010 | |
| 567 | + | |
| 566 | 568 | int kqemu_init(CPUState *env); |
| 567 | 569 | int kqemu_cpu_exec(CPUState *env); |
| 568 | 570 | void kqemu_flush_page(CPUState *env, target_ulong addr); |
| 569 | 571 | void kqemu_flush(CPUState *env, int global); |
| 570 | 572 | void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); |
| 571 | 573 | void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr); |
| 574 | +void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, | |
| 575 | + ram_addr_t phys_offset); | |
| 572 | 576 | void kqemu_cpu_interrupt(CPUState *env); |
| 573 | 577 | void kqemu_record_dump(void); |
| 574 | 578 | |
| 579 | +extern uint32_t kqemu_comm_base; | |
| 580 | + | |
| 575 | 581 | static inline int kqemu_is_ok(CPUState *env) |
| 576 | 582 | { |
| 577 | 583 | return(env->kqemu_enabled && | ... | ... |
exec.c
| ... | ... | @@ -2139,6 +2139,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, |
| 2139 | 2139 | ram_addr_t orig_size = size; |
| 2140 | 2140 | void *subpage; |
| 2141 | 2141 | |
| 2142 | +#ifdef USE_KQEMU | |
| 2143 | + /* XXX: should not depend on cpu context */ | |
| 2144 | + env = first_cpu; | |
| 2145 | + if (env->kqemu_enabled) { | |
| 2146 | + kqemu_set_phys_mem(start_addr, size, phys_offset); | |
| 2147 | + } | |
| 2148 | +#endif | |
| 2142 | 2149 | size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; |
| 2143 | 2150 | end_addr = start_addr + (target_phys_addr_t)size; |
| 2144 | 2151 | for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { | ... | ... |
kqemu.c
| 1 | 1 | /* |
| 2 | 2 | * KQEMU support |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2005 Fabrice Bellard | |
| 4 | + * Copyright (c) 2005-2008 Fabrice Bellard | |
| 5 | 5 | * |
| 6 | 6 | * This library is free software; you can redistribute it and/or |
| 7 | 7 | * modify it under the terms of the GNU Lesser General Public |
| ... | ... | @@ -51,24 +51,14 @@ |
| 51 | 51 | #include <fcntl.h> |
| 52 | 52 | #include "kqemu.h" |
| 53 | 53 | |
| 54 | -/* compatibility stuff */ | |
| 55 | -#ifndef KQEMU_RET_SYSCALL | |
| 56 | -#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ | |
| 57 | -#endif | |
| 58 | -#ifndef KQEMU_MAX_RAM_PAGES_TO_UPDATE | |
| 59 | -#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 | |
| 60 | -#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) | |
| 61 | -#endif | |
| 62 | -#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES | |
| 63 | -#define KQEMU_MAX_MODIFIED_RAM_PAGES 512 | |
| 64 | -#endif | |
| 65 | - | |
| 66 | 54 | #ifdef _WIN32 |
| 67 | 55 | #define KQEMU_DEVICE "\\\\.\\kqemu" |
| 68 | 56 | #else |
| 69 | 57 | #define KQEMU_DEVICE "/dev/kqemu" |
| 70 | 58 | #endif |
| 71 | 59 | |
| 60 | +static void qpi_init(void); | |
| 61 | + | |
| 72 | 62 | #ifdef _WIN32 |
| 73 | 63 | #define KQEMU_INVALID_FD INVALID_HANDLE_VALUE |
| 74 | 64 | HANDLE kqemu_fd = KQEMU_INVALID_FD; |
| ... | ... | @@ -84,14 +74,15 @@ int kqemu_fd = KQEMU_INVALID_FD; |
| 84 | 74 | 2 = kernel kqemu |
| 85 | 75 | */ |
| 86 | 76 | int kqemu_allowed = 1; |
| 87 | -unsigned long *pages_to_flush; | |
| 77 | +uint64_t *pages_to_flush; | |
| 88 | 78 | unsigned int nb_pages_to_flush; |
| 89 | -unsigned long *ram_pages_to_update; | |
| 79 | +uint64_t *ram_pages_to_update; | |
| 90 | 80 | unsigned int nb_ram_pages_to_update; |
| 91 | -unsigned long *modified_ram_pages; | |
| 81 | +uint64_t *modified_ram_pages; | |
| 92 | 82 | unsigned int nb_modified_ram_pages; |
| 93 | 83 | uint8_t *modified_ram_pages_table; |
| 94 | -extern uint32_t **l1_phys_map; | |
| 84 | +int qpi_io_memory; | |
| 85 | +uint32_t kqemu_comm_base; /* physical address of the QPI communication page */ | |
| 95 | 86 | |
| 96 | 87 | #define cpuid(index, eax, ebx, ecx, edx) \ |
| 97 | 88 | asm volatile ("cpuid" \ |
| ... | ... | @@ -161,7 +152,7 @@ static void kqemu_update_cpuid(CPUState *env) |
| 161 | 152 | |
| 162 | 153 | int kqemu_init(CPUState *env) |
| 163 | 154 | { |
| 164 | - struct kqemu_init init; | |
| 155 | + struct kqemu_init kinit; | |
| 165 | 156 | int ret, version; |
| 166 | 157 | #ifdef _WIN32 |
| 167 | 158 | DWORD temp; |
| ... | ... | @@ -197,39 +188,35 @@ int kqemu_init(CPUState *env) |
| 197 | 188 | } |
| 198 | 189 | |
| 199 | 190 | pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * |
| 200 | - sizeof(unsigned long)); | |
| 191 | + sizeof(uint64_t)); | |
| 201 | 192 | if (!pages_to_flush) |
| 202 | 193 | goto fail; |
| 203 | 194 | |
| 204 | 195 | ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * |
| 205 | - sizeof(unsigned long)); | |
| 196 | + sizeof(uint64_t)); | |
| 206 | 197 | if (!ram_pages_to_update) |
| 207 | 198 | goto fail; |
| 208 | 199 | |
| 209 | 200 | modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * |
| 210 | - sizeof(unsigned long)); | |
| 201 | + sizeof(uint64_t)); | |
| 211 | 202 | if (!modified_ram_pages) |
| 212 | 203 | goto fail; |
| 213 | 204 | modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS); |
| 214 | 205 | if (!modified_ram_pages_table) |
| 215 | 206 | goto fail; |
| 216 | 207 | |
| 217 | - init.ram_base = phys_ram_base; | |
| 218 | - init.ram_size = phys_ram_size; | |
| 219 | - init.ram_dirty = phys_ram_dirty; | |
| 220 | - init.phys_to_ram_map = l1_phys_map; | |
| 221 | - init.pages_to_flush = pages_to_flush; | |
| 222 | -#if KQEMU_VERSION >= 0x010200 | |
| 223 | - init.ram_pages_to_update = ram_pages_to_update; | |
| 224 | -#endif | |
| 225 | -#if KQEMU_VERSION >= 0x010300 | |
| 226 | - init.modified_ram_pages = modified_ram_pages; | |
| 227 | -#endif | |
| 208 | + memset(&kinit, 0, sizeof(kinit)); /* set the paddings to zero */ | |
| 209 | + kinit.ram_base = phys_ram_base; | |
| 210 | + kinit.ram_size = phys_ram_size; | |
| 211 | + kinit.ram_dirty = phys_ram_dirty; | |
| 212 | + kinit.pages_to_flush = pages_to_flush; | |
| 213 | + kinit.ram_pages_to_update = ram_pages_to_update; | |
| 214 | + kinit.modified_ram_pages = modified_ram_pages; | |
| 228 | 215 | #ifdef _WIN32 |
| 229 | - ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), | |
| 216 | + ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &kinit, sizeof(kinit), | |
| 230 | 217 | NULL, 0, &temp, NULL) == TRUE ? 0 : -1; |
| 231 | 218 | #else |
| 232 | - ret = ioctl(kqemu_fd, KQEMU_INIT, &init); | |
| 219 | + ret = ioctl(kqemu_fd, KQEMU_INIT, &kinit); | |
| 233 | 220 | #endif |
| 234 | 221 | if (ret < 0) { |
| 235 | 222 | fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret); |
| ... | ... | @@ -242,6 +229,8 @@ int kqemu_init(CPUState *env) |
| 242 | 229 | env->kqemu_enabled = kqemu_allowed; |
| 243 | 230 | nb_pages_to_flush = 0; |
| 244 | 231 | nb_ram_pages_to_update = 0; |
| 232 | + | |
| 233 | + qpi_init(); | |
| 245 | 234 | return 0; |
| 246 | 235 | } |
| 247 | 236 | |
| ... | ... | @@ -272,7 +261,8 @@ void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr) |
| 272 | 261 | { |
| 273 | 262 | #ifdef DEBUG |
| 274 | 263 | if (loglevel & CPU_LOG_INT) { |
| 275 | - fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr); | |
| 264 | + fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", | |
| 265 | + (unsigned long)ram_addr); | |
| 276 | 266 | } |
| 277 | 267 | #endif |
| 278 | 268 | /* we only track transitions to dirty state */ |
| ... | ... | @@ -327,6 +317,51 @@ void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr) |
| 327 | 317 | } |
| 328 | 318 | } |
| 329 | 319 | |
| 320 | +void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, | |
| 321 | + ram_addr_t phys_offset) | |
| 322 | +{ | |
| 323 | + struct kqemu_phys_mem kphys_mem1, *kphys_mem = &kphys_mem1; | |
| 324 | + uint64_t end; | |
| 325 | + int ret, io_index; | |
| 326 | + | |
| 327 | + end = (start_addr + size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; | |
| 328 | + start_addr &= TARGET_PAGE_MASK; | |
| 329 | + kphys_mem->phys_addr = start_addr; | |
| 330 | + kphys_mem->size = end - start_addr; | |
| 331 | + kphys_mem->ram_addr = phys_offset & TARGET_PAGE_MASK; | |
| 332 | + io_index = phys_offset & ~TARGET_PAGE_MASK; | |
| 333 | + switch(io_index) { | |
| 334 | + case IO_MEM_RAM: | |
| 335 | + kphys_mem->io_index = KQEMU_IO_MEM_RAM; | |
| 336 | + break; | |
| 337 | + case IO_MEM_ROM: | |
| 338 | + kphys_mem->io_index = KQEMU_IO_MEM_ROM; | |
| 339 | + break; | |
| 340 | + default: | |
| 341 | + if (qpi_io_memory == io_index) { | |
| 342 | + kphys_mem->io_index = KQEMU_IO_MEM_COMM; | |
| 343 | + } else { | |
| 344 | + kphys_mem->io_index = KQEMU_IO_MEM_UNASSIGNED; | |
| 345 | + } | |
| 346 | + break; | |
| 347 | + } | |
| 348 | +#ifdef _WIN32 | |
| 349 | + { | |
| 350 | + DWORD temp; | |
| 351 | + ret = DeviceIoControl(kqemu_fd, KQEMU_SET_PHYS_MEM, | |
| 352 | + kphys_mem, sizeof(*kphys_mem), | |
| 353 | + NULL, 0, &temp, NULL) == TRUE ? 0 : -1; | |
| 354 | + } | |
| 355 | +#else | |
| 356 | + ret = ioctl(kqemu_fd, KQEMU_SET_PHYS_MEM, kphys_mem); | |
| 357 | +#endif | |
| 358 | + if (ret < 0) { | |
| 359 | + fprintf(stderr, "kqemu: KQEMU_SET_PHYS_PAGE error=%d: start_addr=0x%016" PRIx64 " size=0x%08lx phys_offset=0x%08lx\n", | |
| 360 | + ret, start_addr, | |
| 361 | + (unsigned long)size, (unsigned long)phys_offset); | |
| 362 | + } | |
| 363 | +} | |
| 364 | + | |
| 330 | 365 | struct fpstate { |
| 331 | 366 | uint16_t fpuc; |
| 332 | 367 | uint16_t dummy1; |
| ... | ... | @@ -474,7 +509,7 @@ static int do_syscall(CPUState *env, |
| 474 | 509 | int selector; |
| 475 | 510 | |
| 476 | 511 | selector = (env->star >> 32) & 0xffff; |
| 477 | -#ifdef __x86_64__ | |
| 512 | +#ifdef TARGET_X86_64 | |
| 478 | 513 | if (env->hflags & HF_LMA_MASK) { |
| 479 | 514 | int code64; |
| 480 | 515 | |
| ... | ... | @@ -631,6 +666,24 @@ void kqemu_record_dump(void) |
| 631 | 666 | } |
| 632 | 667 | #endif |
| 633 | 668 | |
| 669 | +static inline void kqemu_load_seg(struct kqemu_segment_cache *ksc, | |
| 670 | + const SegmentCache *sc) | |
| 671 | +{ | |
| 672 | + ksc->selector = sc->selector; | |
| 673 | + ksc->flags = sc->flags; | |
| 674 | + ksc->limit = sc->limit; | |
| 675 | + ksc->base = sc->base; | |
| 676 | +} | |
| 677 | + | |
| 678 | +static inline void kqemu_save_seg(SegmentCache *sc, | |
| 679 | + const struct kqemu_segment_cache *ksc) | |
| 680 | +{ | |
| 681 | + sc->selector = ksc->selector; | |
| 682 | + sc->flags = ksc->flags; | |
| 683 | + sc->limit = ksc->limit; | |
| 684 | + sc->base = ksc->base; | |
| 685 | +} | |
| 686 | + | |
| 634 | 687 | int kqemu_cpu_exec(CPUState *env) |
| 635 | 688 | { |
| 636 | 689 | struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; |
| ... | ... | @@ -638,7 +691,6 @@ int kqemu_cpu_exec(CPUState *env) |
| 638 | 691 | #ifdef CONFIG_PROFILER |
| 639 | 692 | int64_t ti; |
| 640 | 693 | #endif |
| 641 | - | |
| 642 | 694 | #ifdef _WIN32 |
| 643 | 695 | DWORD temp; |
| 644 | 696 | #endif |
| ... | ... | @@ -652,35 +704,33 @@ int kqemu_cpu_exec(CPUState *env) |
| 652 | 704 | cpu_dump_state(env, logfile, fprintf, 0); |
| 653 | 705 | } |
| 654 | 706 | #endif |
| 655 | - memcpy(kenv->regs, env->regs, sizeof(kenv->regs)); | |
| 707 | + for(i = 0; i < CPU_NB_REGS; i++) | |
| 708 | + kenv->regs[i] = env->regs[i]; | |
| 656 | 709 | kenv->eip = env->eip; |
| 657 | 710 | kenv->eflags = env->eflags; |
| 658 | - memcpy(&kenv->segs, &env->segs, sizeof(env->segs)); | |
| 659 | - memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt)); | |
| 660 | - memcpy(&kenv->tr, &env->tr, sizeof(env->tr)); | |
| 661 | - memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt)); | |
| 662 | - memcpy(&kenv->idt, &env->idt, sizeof(env->idt)); | |
| 711 | + for(i = 0; i < 6; i++) | |
| 712 | + kqemu_load_seg(&kenv->segs[i], &env->segs[i]); | |
| 713 | + kqemu_load_seg(&kenv->ldt, &env->ldt); | |
| 714 | + kqemu_load_seg(&kenv->tr, &env->tr); | |
| 715 | + kqemu_load_seg(&kenv->gdt, &env->gdt); | |
| 716 | + kqemu_load_seg(&kenv->idt, &env->idt); | |
| 663 | 717 | kenv->cr0 = env->cr[0]; |
| 664 | 718 | kenv->cr2 = env->cr[2]; |
| 665 | 719 | kenv->cr3 = env->cr[3]; |
| 666 | 720 | kenv->cr4 = env->cr[4]; |
| 667 | 721 | kenv->a20_mask = env->a20_mask; |
| 668 | -#if KQEMU_VERSION >= 0x010100 | |
| 669 | 722 | kenv->efer = env->efer; |
| 670 | -#endif | |
| 671 | -#if KQEMU_VERSION >= 0x010300 | |
| 672 | 723 | kenv->tsc_offset = 0; |
| 673 | 724 | kenv->star = env->star; |
| 674 | 725 | kenv->sysenter_cs = env->sysenter_cs; |
| 675 | 726 | kenv->sysenter_esp = env->sysenter_esp; |
| 676 | 727 | kenv->sysenter_eip = env->sysenter_eip; |
| 677 | -#ifdef __x86_64__ | |
| 728 | +#ifdef TARGET_X86_64 | |
| 678 | 729 | kenv->lstar = env->lstar; |
| 679 | 730 | kenv->cstar = env->cstar; |
| 680 | 731 | kenv->fmask = env->fmask; |
| 681 | 732 | kenv->kernelgsbase = env->kernelgsbase; |
| 682 | 733 | #endif |
| 683 | -#endif | |
| 684 | 734 | if (env->dr[7] & 0xff) { |
| 685 | 735 | kenv->dr7 = env->dr[7]; |
| 686 | 736 | kenv->dr0 = env->dr[0]; |
| ... | ... | @@ -694,15 +744,11 @@ int kqemu_cpu_exec(CPUState *env) |
| 694 | 744 | cpl = (env->hflags & HF_CPL_MASK); |
| 695 | 745 | kenv->cpl = cpl; |
| 696 | 746 | kenv->nb_pages_to_flush = nb_pages_to_flush; |
| 697 | -#if KQEMU_VERSION >= 0x010200 | |
| 698 | 747 | kenv->user_only = (env->kqemu_enabled == 1); |
| 699 | 748 | kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; |
| 700 | -#endif | |
| 701 | 749 | nb_ram_pages_to_update = 0; |
| 702 | - | |
| 703 | -#if KQEMU_VERSION >= 0x010300 | |
| 704 | 750 | kenv->nb_modified_ram_pages = nb_modified_ram_pages; |
| 705 | -#endif | |
| 751 | + | |
| 706 | 752 | kqemu_reset_modified_ram_pages(); |
| 707 | 753 | |
| 708 | 754 | if (env->cpuid_features & CPUID_FXSR) |
| ... | ... | @@ -720,41 +766,30 @@ int kqemu_cpu_exec(CPUState *env) |
| 720 | 766 | ret = -1; |
| 721 | 767 | } |
| 722 | 768 | #else |
| 723 | -#if KQEMU_VERSION >= 0x010100 | |
| 724 | 769 | ioctl(kqemu_fd, KQEMU_EXEC, kenv); |
| 725 | 770 | ret = kenv->retval; |
| 726 | -#else | |
| 727 | - ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv); | |
| 728 | -#endif | |
| 729 | 771 | #endif |
| 730 | 772 | if (env->cpuid_features & CPUID_FXSR) |
| 731 | 773 | save_native_fp_fxsave(env); |
| 732 | 774 | else |
| 733 | 775 | save_native_fp_fsave(env); |
| 734 | 776 | |
| 735 | - memcpy(env->regs, kenv->regs, sizeof(env->regs)); | |
| 777 | + for(i = 0; i < CPU_NB_REGS; i++) | |
| 778 | + env->regs[i] = kenv->regs[i]; | |
| 736 | 779 | env->eip = kenv->eip; |
| 737 | 780 | env->eflags = kenv->eflags; |
| 738 | - memcpy(env->segs, kenv->segs, sizeof(env->segs)); | |
| 781 | + for(i = 0; i < 6; i++) | |
| 782 | + kqemu_save_seg(&env->segs[i], &kenv->segs[i]); | |
| 739 | 783 | cpu_x86_set_cpl(env, kenv->cpl); |
| 740 | - memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt)); | |
| 741 | -#if 0 | |
| 742 | - /* no need to restore that */ | |
| 743 | - memcpy(env->tr, kenv->tr, sizeof(env->tr)); | |
| 744 | - memcpy(env->gdt, kenv->gdt, sizeof(env->gdt)); | |
| 745 | - memcpy(env->idt, kenv->idt, sizeof(env->idt)); | |
| 746 | - env->a20_mask = kenv->a20_mask; | |
| 747 | -#endif | |
| 784 | + kqemu_save_seg(&env->ldt, &kenv->ldt); | |
| 748 | 785 | env->cr[0] = kenv->cr0; |
| 749 | 786 | env->cr[4] = kenv->cr4; |
| 750 | 787 | env->cr[3] = kenv->cr3; |
| 751 | 788 | env->cr[2] = kenv->cr2; |
| 752 | 789 | env->dr[6] = kenv->dr6; |
| 753 | -#if KQEMU_VERSION >= 0x010300 | |
| 754 | -#ifdef __x86_64__ | |
| 790 | +#ifdef TARGET_X86_64 | |
| 755 | 791 | env->kernelgsbase = kenv->kernelgsbase; |
| 756 | 792 | #endif |
| 757 | -#endif | |
| 758 | 793 | |
| 759 | 794 | /* flush pages as indicated by kqemu */ |
| 760 | 795 | if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) { |
| ... | ... | @@ -771,13 +806,10 @@ int kqemu_cpu_exec(CPUState *env) |
| 771 | 806 | kqemu_exec_count++; |
| 772 | 807 | #endif |
| 773 | 808 | |
| 774 | -#if KQEMU_VERSION >= 0x010200 | |
| 775 | 809 | if (kenv->nb_ram_pages_to_update > 0) { |
| 776 | 810 | cpu_tlb_update_dirty(env); |
| 777 | 811 | } |
| 778 | -#endif | |
| 779 | 812 | |
| 780 | -#if KQEMU_VERSION >= 0x010300 | |
| 781 | 813 | if (kenv->nb_modified_ram_pages > 0) { |
| 782 | 814 | for(i = 0; i < kenv->nb_modified_ram_pages; i++) { |
| 783 | 815 | unsigned long addr; |
| ... | ... | @@ -785,7 +817,6 @@ int kqemu_cpu_exec(CPUState *env) |
| 785 | 817 | tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0); |
| 786 | 818 | } |
| 787 | 819 | } |
| 788 | -#endif | |
| 789 | 820 | |
| 790 | 821 | /* restore the hidden flags */ |
| 791 | 822 | { |
| ... | ... | @@ -905,11 +936,85 @@ int kqemu_cpu_exec(CPUState *env) |
| 905 | 936 | |
| 906 | 937 | void kqemu_cpu_interrupt(CPUState *env) |
| 907 | 938 | { |
| 908 | -#if defined(_WIN32) && KQEMU_VERSION >= 0x010101 | |
| 939 | +#if defined(_WIN32) | |
| 909 | 940 | /* cancelling the I/O request causes KQEMU to finish executing the |
| 910 | 941 | current block and successfully returning. */ |
| 911 | 942 | CancelIo(kqemu_fd); |
| 912 | 943 | #endif |
| 913 | 944 | } |
| 914 | 945 | |
| 946 | +/* | |
| 947 | + QEMU paravirtualization interface. The current interface only | |
| 948 | + allows to modify the IF and IOPL flags when running in | |
| 949 | + kqemu. | |
| 950 | + | |
| 951 | + At this point it is not very satisfactory. I leave it for reference | |
| 952 | + as it adds little complexity. | |
| 953 | +*/ | |
| 954 | + | |
| 955 | +#define QPI_COMM_PAGE_PHYS_ADDR 0xff000000 | |
| 956 | + | |
| 957 | +static uint32_t qpi_mem_readb(void *opaque, target_phys_addr_t addr) | |
| 958 | +{ | |
| 959 | + return 0; | |
| 960 | +} | |
| 961 | + | |
| 962 | +static uint32_t qpi_mem_readw(void *opaque, target_phys_addr_t addr) | |
| 963 | +{ | |
| 964 | + return 0; | |
| 965 | +} | |
| 966 | + | |
| 967 | +static void qpi_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 968 | +{ | |
| 969 | +} | |
| 970 | + | |
| 971 | +static void qpi_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 972 | +{ | |
| 973 | +} | |
| 974 | + | |
| 975 | +static uint32_t qpi_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 976 | +{ | |
| 977 | + CPUState *env; | |
| 978 | + | |
| 979 | + env = cpu_single_env; | |
| 980 | + if (!env) | |
| 981 | + return 0; | |
| 982 | + return env->eflags & (IF_MASK | IOPL_MASK); | |
| 983 | +} | |
| 984 | + | |
| 985 | +/* Note: after writing to this address, the guest code must make sure | |
| 986 | + it is exiting the current TB. pushf/popf can be used for that | |
| 987 | + purpose. */ | |
| 988 | +static void qpi_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
| 989 | +{ | |
| 990 | + CPUState *env; | |
| 991 | + | |
| 992 | + env = cpu_single_env; | |
| 993 | + if (!env) | |
| 994 | + return; | |
| 995 | + env->eflags = (env->eflags & ~(IF_MASK | IOPL_MASK)) | | |
| 996 | + (val & (IF_MASK | IOPL_MASK)); | |
| 997 | +} | |
| 998 | + | |
| 999 | +static CPUReadMemoryFunc *qpi_mem_read[3] = { | |
| 1000 | + qpi_mem_readb, | |
| 1001 | + qpi_mem_readw, | |
| 1002 | + qpi_mem_readl, | |
| 1003 | +}; | |
| 1004 | + | |
| 1005 | +static CPUWriteMemoryFunc *qpi_mem_write[3] = { | |
| 1006 | + qpi_mem_writeb, | |
| 1007 | + qpi_mem_writew, | |
| 1008 | + qpi_mem_writel, | |
| 1009 | +}; | |
| 1010 | + | |
| 1011 | +static void qpi_init(void) | |
| 1012 | +{ | |
| 1013 | + kqemu_comm_base = 0xff000000 | 1; | |
| 1014 | + qpi_io_memory = cpu_register_io_memory(0, | |
| 1015 | + qpi_mem_read, | |
| 1016 | + qpi_mem_write, NULL); | |
| 1017 | + cpu_register_physical_memory(kqemu_comm_base & ~0xfff, | |
| 1018 | + 0x1000, qpi_io_memory); | |
| 1019 | +} | |
| 915 | 1020 | #endif | ... | ... |
kqemu.h
| 1 | 1 | /* |
| 2 | 2 | * KQEMU header |
| 3 | - * | |
| 4 | - * Copyright (c) 2004-2006 Fabrice Bellard | |
| 5 | - * | |
| 3 | + * | |
| 4 | + * Copyright (c) 2004-2008 Fabrice Bellard | |
| 5 | + * | |
| 6 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | 8 | * in the Software without restriction, including without limitation the rights |
| ... | ... | @@ -24,25 +24,27 @@ |
| 24 | 24 | #ifndef KQEMU_H |
| 25 | 25 | #define KQEMU_H |
| 26 | 26 | |
| 27 | -#define KQEMU_VERSION 0x010300 | |
| 27 | +#if defined(__i386__) | |
| 28 | +#define KQEMU_PAD32(x) x | |
| 29 | +#else | |
| 30 | +#define KQEMU_PAD32(x) | |
| 31 | +#endif | |
| 32 | + | |
| 33 | +#define KQEMU_VERSION 0x010400 | |
| 28 | 34 | |
| 29 | 35 | struct kqemu_segment_cache { |
| 30 | - uint32_t selector; | |
| 31 | - unsigned long base; | |
| 32 | - uint32_t limit; | |
| 36 | + uint16_t selector; | |
| 37 | + uint16_t padding1; | |
| 33 | 38 | uint32_t flags; |
| 39 | + uint64_t base; | |
| 40 | + uint32_t limit; | |
| 41 | + uint32_t padding2; | |
| 34 | 42 | }; |
| 35 | 43 | |
| 36 | 44 | struct kqemu_cpu_state { |
| 37 | -#ifdef __x86_64__ | |
| 38 | - unsigned long regs[16]; | |
| 39 | -#else | |
| 40 | - unsigned long regs[8]; | |
| 41 | -#endif | |
| 42 | - unsigned long eip; | |
| 43 | - unsigned long eflags; | |
| 44 | - | |
| 45 | - uint32_t dummy0, dummy1, dumm2, dummy3, dummy4; | |
| 45 | + uint64_t regs[16]; | |
| 46 | + uint64_t eip; | |
| 47 | + uint64_t eflags; | |
| 46 | 48 | |
| 47 | 49 | struct kqemu_segment_cache segs[6]; /* selector values */ |
| 48 | 50 | struct kqemu_segment_cache ldt; |
| ... | ... | @@ -50,63 +52,81 @@ struct kqemu_cpu_state { |
| 50 | 52 | struct kqemu_segment_cache gdt; /* only base and limit are used */ |
| 51 | 53 | struct kqemu_segment_cache idt; /* only base and limit are used */ |
| 52 | 54 | |
| 53 | - unsigned long cr0; | |
| 54 | - unsigned long dummy5; | |
| 55 | - unsigned long cr2; | |
| 56 | - unsigned long cr3; | |
| 57 | - unsigned long cr4; | |
| 58 | - uint32_t a20_mask; | |
| 55 | + uint64_t cr0; | |
| 56 | + uint64_t cr2; | |
| 57 | + uint64_t cr3; | |
| 58 | + uint64_t cr4; | |
| 59 | + uint64_t a20_mask; | |
| 59 | 60 | |
| 60 | 61 | /* sysenter registers */ |
| 61 | - uint32_t sysenter_cs; | |
| 62 | - uint32_t sysenter_esp; | |
| 63 | - uint32_t sysenter_eip; | |
| 64 | - uint64_t efer __attribute__((aligned(8))); | |
| 62 | + uint64_t sysenter_cs; | |
| 63 | + uint64_t sysenter_esp; | |
| 64 | + uint64_t sysenter_eip; | |
| 65 | + uint64_t efer; | |
| 65 | 66 | uint64_t star; |
| 66 | -#ifdef __x86_64__ | |
| 67 | - unsigned long lstar; | |
| 68 | - unsigned long cstar; | |
| 69 | - unsigned long fmask; | |
| 70 | - unsigned long kernelgsbase; | |
| 71 | -#endif | |
| 67 | + | |
| 68 | + uint64_t lstar; | |
| 69 | + uint64_t cstar; | |
| 70 | + uint64_t fmask; | |
| 71 | + uint64_t kernelgsbase; | |
| 72 | + | |
| 72 | 73 | uint64_t tsc_offset; |
| 73 | 74 | |
| 74 | - unsigned long dr0; | |
| 75 | - unsigned long dr1; | |
| 76 | - unsigned long dr2; | |
| 77 | - unsigned long dr3; | |
| 78 | - unsigned long dr6; | |
| 79 | - unsigned long dr7; | |
| 75 | + uint64_t dr0; | |
| 76 | + uint64_t dr1; | |
| 77 | + uint64_t dr2; | |
| 78 | + uint64_t dr3; | |
| 79 | + uint64_t dr6; | |
| 80 | + uint64_t dr7; | |
| 80 | 81 | |
| 81 | 82 | uint8_t cpl; |
| 82 | 83 | uint8_t user_only; |
| 84 | + uint16_t padding1; | |
| 83 | 85 | |
| 84 | 86 | uint32_t error_code; /* error_code when exiting with an exception */ |
| 85 | - unsigned long next_eip; /* next eip value when exiting with an interrupt */ | |
| 86 | - unsigned int nb_pages_to_flush; /* number of pages to flush, | |
| 87 | + uint64_t next_eip; /* next eip value when exiting with an interrupt */ | |
| 88 | + uint32_t nb_pages_to_flush; /* number of pages to flush, | |
| 87 | 89 | KQEMU_FLUSH_ALL means full flush */ |
| 88 | 90 | #define KQEMU_MAX_PAGES_TO_FLUSH 512 |
| 89 | 91 | #define KQEMU_FLUSH_ALL (KQEMU_MAX_PAGES_TO_FLUSH + 1) |
| 90 | 92 | |
| 91 | - long retval; | |
| 93 | + int32_t retval; | |
| 92 | 94 | |
| 93 | 95 | /* number of ram_dirty entries to update */ |
| 94 | - unsigned int nb_ram_pages_to_update; | |
| 96 | + uint32_t nb_ram_pages_to_update; | |
| 95 | 97 | #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 |
| 96 | 98 | #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) |
| 97 | 99 | |
| 98 | 100 | #define KQEMU_MAX_MODIFIED_RAM_PAGES 512 |
| 99 | - unsigned int nb_modified_ram_pages; | |
| 101 | + uint32_t nb_modified_ram_pages; | |
| 100 | 102 | }; |
| 101 | 103 | |
| 102 | 104 | struct kqemu_init { |
| 103 | 105 | uint8_t *ram_base; /* must be page aligned */ |
| 104 | - unsigned long ram_size; /* must be multiple of 4 KB */ | |
| 106 | + KQEMU_PAD32(uint32_t padding1;) | |
| 107 | + uint64_t ram_size; /* must be multiple of 4 KB */ | |
| 105 | 108 | uint8_t *ram_dirty; /* must be page aligned */ |
| 106 | - uint32_t **phys_to_ram_map; /* must be page aligned */ | |
| 107 | - unsigned long *pages_to_flush; /* must be page aligned */ | |
| 108 | - unsigned long *ram_pages_to_update; /* must be page aligned */ | |
| 109 | - unsigned long *modified_ram_pages; /* must be page aligned */ | |
| 109 | + KQEMU_PAD32(uint32_t padding2;) | |
| 110 | + uint64_t *pages_to_flush; /* must be page aligned */ | |
| 111 | + KQEMU_PAD32(uint32_t padding4;) | |
| 112 | + uint64_t *ram_pages_to_update; /* must be page aligned */ | |
| 113 | + KQEMU_PAD32(uint32_t padding5;) | |
| 114 | + uint64_t *modified_ram_pages; /* must be page aligned */ | |
| 115 | + KQEMU_PAD32(uint32_t padding6;) | |
| 116 | +}; | |
| 117 | + | |
| 118 | +#define KQEMU_IO_MEM_RAM 0 | |
| 119 | +#define KQEMU_IO_MEM_ROM 1 | |
| 120 | +#define KQEMU_IO_MEM_COMM 2 /* kqemu communication page */ | |
| 121 | +#define KQEMU_IO_MEM_UNASSIGNED 3 /* any device: return to application */ | |
| 122 | + | |
| 123 | +struct kqemu_phys_mem { | |
| 124 | + uint64_t phys_addr; /* physical address range: phys_addr, | |
| 125 | + phys_addr + size */ | |
| 126 | + uint64_t size; | |
| 127 | + uint64_t ram_addr; /* corresponding ram address */ | |
| 128 | + uint32_t io_index; /* memory type: see KQEMU_IO_MEM_xxx */ | |
| 129 | + uint32_t padding1; | |
| 110 | 130 | }; |
| 111 | 131 | |
| 112 | 132 | #define KQEMU_RET_ABORT (-1) |
| ... | ... | @@ -122,11 +142,13 @@ struct kqemu_init { |
| 122 | 142 | #define KQEMU_INIT CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_WRITE_ACCESS) |
| 123 | 143 | #define KQEMU_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_READ_ACCESS) |
| 124 | 144 | #define KQEMU_MODIFY_RAM_PAGES CTL_CODE(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS) |
| 145 | +#define KQEMU_SET_PHYS_MEM CTL_CODE(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_WRITE_ACCESS) | |
| 125 | 146 | #else |
| 126 | 147 | #define KQEMU_EXEC _IOWR('q', 1, struct kqemu_cpu_state) |
| 127 | 148 | #define KQEMU_INIT _IOW('q', 2, struct kqemu_init) |
| 128 | 149 | #define KQEMU_GET_VERSION _IOR('q', 3, int) |
| 129 | 150 | #define KQEMU_MODIFY_RAM_PAGES _IOW('q', 4, int) |
| 151 | +#define KQEMU_SET_PHYS_MEM _IOW('q', 5, struct kqemu_phys_mem) | |
| 130 | 152 | #endif |
| 131 | 153 | |
| 132 | 154 | #endif /* KQEMU_H */ | ... | ... |
target-i386/op_helper.c
| ... | ... | @@ -1950,20 +1950,21 @@ void helper_cpuid(void) |
| 1950 | 1950 | case 0x80000008: |
| 1951 | 1951 | /* virtual & phys address size in low 2 bytes. */ |
| 1952 | 1952 | /* XXX: This value must match the one used in the MMU code. */ |
| 1953 | -#if defined(TARGET_X86_64) | |
| 1954 | -# if defined(USE_KQEMU) | |
| 1955 | - EAX = 0x00003020; /* 48 bits virtual, 32 bits physical */ | |
| 1956 | -# else | |
| 1953 | + if (env->cpuid_ext2_features & CPUID_EXT2_LM) { | |
| 1954 | + /* 64 bit processor */ | |
| 1955 | +#if defined(USE_KQEMU) | |
| 1956 | + EAX = 0x00003020; /* 48 bits virtual, 32 bits physical */ | |
| 1957 | +#else | |
| 1957 | 1958 | /* XXX: The physical address space is limited to 42 bits in exec.c. */ |
| 1958 | - EAX = 0x00003028; /* 48 bits virtual, 40 bits physical */ | |
| 1959 | -# endif | |
| 1959 | + EAX = 0x00003028; /* 48 bits virtual, 40 bits physical */ | |
| 1960 | +#endif | |
| 1961 | + } else { | |
| 1962 | +#if defined(USE_KQEMU) | |
| 1963 | + EAX = 0x00000020; /* 32 bits physical */ | |
| 1960 | 1964 | #else |
| 1961 | -# if defined(USE_KQEMU) | |
| 1962 | - EAX = 0x00000020; /* 32 bits physical */ | |
| 1963 | -# else | |
| 1964 | - EAX = 0x00000024; /* 36 bits physical */ | |
| 1965 | -# endif | |
| 1965 | + EAX = 0x00000024; /* 36 bits physical */ | |
| 1966 | 1966 | #endif |
| 1967 | + } | |
| 1967 | 1968 | EBX = 0; |
| 1968 | 1969 | ECX = 0; |
| 1969 | 1970 | EDX = 0; |
| ... | ... | @@ -3158,6 +3159,15 @@ void helper_rdmsr(void) |
| 3158 | 3159 | val = env->kernelgsbase; |
| 3159 | 3160 | break; |
| 3160 | 3161 | #endif |
| 3162 | +#ifdef USE_KQEMU | |
| 3163 | + case MSR_QPI_COMMBASE: | |
| 3164 | + if (env->kqemu_enabled) { | |
| 3165 | + val = kqemu_comm_base; | |
| 3166 | + } else { | |
| 3167 | + val = 0; | |
| 3168 | + } | |
| 3169 | + break; | |
| 3170 | +#endif | |
| 3161 | 3171 | default: |
| 3162 | 3172 | /* XXX: exception ? */ |
| 3163 | 3173 | val = 0; | ... | ... |