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; | ... | ... |