mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
This changeset contains all differences between xen-unstable.hg and xen-unstable-hvm.hg. All information and comments for changesets unique to xen-unstable-hvm.hg are included below. Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> Signed-off-by: Keir Fraser <keir@xensource.com> > user: leendert@eserver2.watson.ibm.com > date: Tue Jan 31 04:29:51 2006 -0400 > files: xen/include/asm-ia64/mm.h > description: > Fix ia64 compile. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Tue Jan 31 02:21:49 2006 -0400 > files: xen/include/xen/domain_page.h > description: > Eliminate unused fields (pfn,va) warnings. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Fri Jan 27 04:31:44 2006 -0400 > files: tools/python/xen/xend/image.py > description: > Name cleanup. vmx refers to VT-x specific code, HVM is used for all others. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: root@xen-trw1.amd.com > date: Sun Jan 22 18:39:58 2006 -0500 > files: xen/arch/x86/hvm/platform.c > description: > support prefix 0x67 in hvm decode logic, gfxboot patch causes 0x67 prefix. > > > user: twoller@xen-trw1.amd.com > date: Sun Jan 22 18:35:59 2006 -0500 > files: xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/include/asm-x86/hvm/svm/svm.h > description: > check for valid shared_page_va/vmcb before deallocating in SVM. > > > user: leendert@eserver2.watson.ibm.com > date: Sun Jan 22 02:56:20 2006 -0400 > files: xen/include/asm-x86/hvm/svm/svm.h xen/include/asm-x86/hvm/svm/vmmcall.h > description: > Some SVM header file cleanups. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Fri Jan 20 11:50:23 2006 -0400 > files: xen/arch/x86/domain.c > description: > Need to be more diligent about when to call into the HVM abstraction layer > and when not. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Wed Jan 18 15:14:56 2006 -0400 > files: xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/x86_32/exits.S xen/arch/x86/hvm/svm/x86_64/exits.S xen/arch/x86/hvm/vmx/x86_32/exits.S xen/arch/x86/hvm/vmx/x86_64/exits.S > description: > Added missing copyright statements and updated svm.c's copyright to properly > reflect that it was derived from vmx.c. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Tue Jan 17 09:42:11 2006 -0400 > files: xen/arch/ia64/Makefile xen/arch/ia64/vmx/vlsapic.c xen/arch/ia64/vmx/vmx_init.c xen/include/asm-ia64/vmx_platform.h > description: > Make sure ia64 builds again with the new directory structure. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@localhost.localdomain > date: Tue Jan 17 08:28:51 2006 -0400 > files: xen/arch/x86/Makefile xen/arch/x86/hvm/i8259.c xen/arch/x86/hvm/vioapic.c > description: > The device models now belong in hvm. > > Signed-ff-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sun Jan 15 16:40:58 2006 -0400 > files: xen/arch/x86/Makefile xen/arch/x86/cpu/amd.c xen/arch/x86/cpu/intel.c xen/arch/x86/dm/hvm_vioapic.c xen/arch/x86/dm/i8259.c xen/arch/x86/dom0_ops.c xen/arch/x86/domain.c xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/io.c xen/arch/x86/hvm/platform.c xen/arch/x86/hvm/svm/emulate.c xen/arch/x86/hvm/svm/instrlen.c xen/arch/x86/hvm/svm/intr.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/arch/x86/hvm/svm/x86_32/exits.S xen/arch/x86/hvm/svm/x86_64/exits.S xen/arch/x86/hvm/vlapic.c xen/arch/x86/hvm/vmx/io.c xen/arch/x86/hvm/vmx/vmcs.c xen/arch/x86/hvm/vmx/vmx.c xen/arch/x86/hvm/vmx/x86_32/exits.S xen/arch/x86/hvm/vmx/x86_64/exits.S xen/arch/x86/i387.c xen/arch/x86/x86_32/entry.S xen/arch/x86/x86_32/traps.c xen/arch/x86/x86_64/entry.S xen/arch/x86/x86_64/traps.c xen/include/asm-x86/domain.h xen/include/asm-x86/hvm/domain.h xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/io.h xen/include/asm-x86/hvm/support.h xen/include/asm-x86/hvm/svm/emulate.h xen/include/asm-x86/hvm/svm/intr.h xen/include/asm-x86/hvm/svm/svm.h xen/include/asm-x86/hvm/svm/vmcb.h xen/include/asm-x86/hvm/svm/vmmcall.h xen/include/asm-x86/hvm/vcpu.h xen/include/asm-x86/hvm/vioapic.h xen/include/asm-x86/hvm/vlapic.h xen/include/asm-x86/hvm/vmx/cpu.h xen/include/asm-x86/hvm/vmx/vmcs.h xen/include/asm-x86/hvm/vmx/vmx.h xen/include/asm-x86/hvm/vpic.h xen/include/asm-x86/hvm/vpit.h xen/include/asm-x86/shadow.h > description: > As suggested by Keir, I restructured the hvm/vmx/svm tree. The new > directory structure looks like: > > xen/arch/hvm/ > xen/arch/hvm/vmx > xen/arch/hvm/vmx/x86_32 > xen/arch/hvm/vmx/x86_64 > xen/arch/hvm/svm > xen/arch/hvm/svm/x86_32 > xen/arch/hvm/svm/x86_64 > > xen/include/hvm/ > xen/include/hvm/vmx > xen/include/hvm/svm > > Many files have been renamed and had their hvm_/vmx_/svm_ suffix removed > because this is now clear from the directory where the file resides. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sat Jan 14 17:03:28 2006 -0400 > files: xen/arch/ia64/vmx/vlsapic.c xen/include/asm-ia64/vmx_platform.h > description: > Name change fix for ia64. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sat Jan 14 15:12:59 2006 -0400 > files: xen/arch/x86/dm/hvm_vioapic.c xen/arch/x86/dm/i8259.c xen/arch/x86/hvm.c xen/arch/x86/hvm_intercept.c xen/arch/x86/svm.c xen/arch/x86/svm_intr.c xen/arch/x86/svm_vmcb.c xen/arch/x86/vmx.c xen/arch/x86/vmx_io.c xen/arch/x86/vmx_vmcs.c xen/include/asm-x86/hvm_domain.h xen/include/asm-x86/hvm_vcpu.h > description: > Move VMX/SVM print buffer to hvm_domain. > > Cleanup variable names. The suffix hvm_ is redundant in hvm_domain. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: twoller@xen-trw1.site > date: Fri Jan 13 17:03:18 2006 -0500 > files: xen/arch/x86/svm.c > description: > remove unnecessary spin_unlock in asid_fetch code for svm. > > > user: twoller@xen-trw1.site > date: Wed Jan 11 20:00:36 2006 -0500 > files: xen/arch/x86/svm.c > description: > remove unneeded update_pagetables() during svm PF handling (resolved with ASID code rework). > > > user: leendert@eserver2.watson.ibm.com > date: Tue Jan 10 02:45:32 2006 -0400 > files: xen/arch/x86/hvm.c xen/arch/x86/vmx_io.c > description: > Factor out cpu_get_interrupt(). It is used by VMX and SVM. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Mon Jan 9 00:03:30 2006 -0400 > files: xen/arch/x86/hvm.c xen/arch/x86/svm.c xen/arch/x86/vmx.c xen/include/asm-x86/hvm_support.h xen/include/asm-x86/hvm_vcpu.h > description: > Introduce small print buffer per domain rather than a single global one. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sun Jan 8 23:07:12 2006 -0400 > files: xen/arch/x86/dom0_ops.c xen/include/asm-x86/hvm_support.h xen/include/public/arch-x86_32.h xen/include/public/arch-x86_64.h > description: > More cleanup. There is no point in distinguishing between SVM and VMX, > a single HVM flag bit suffices. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sun Jan 8 12:05:59 2006 -0400 > files: xen/arch/x86/svm.c xen/arch/x86/vmx.c > description: > Both VMX & SVM now print writes to the debug port (0xE9) on the console. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Sat Jan 7 13:55:27 2006 -0400 > files: xen/arch/x86/svm.c xen/arch/x86/svm_intr.c xen/arch/x86/svm_vmcb.c xen/arch/x86/vmx.c xen/arch/x86/vmx_io.c xen/arch/x86/vmx_vmcs.c xen/arch/x86/x86_32/asm-offsets.c xen/arch/x86/x86_64/asm-offsets.c xen/include/asm-x86/domain.h xen/include/asm-x86/vmx.h > description: > Introduce shorthands to improve code legibility. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Wed Jan 4 06:12:10 2006 -0400 > files: tools/examples/xmexample.hvm > description: > Minor spelling mistakes. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Wed Jan 4 03:37:55 2006 -0400 > files: xen/include/public/hvm/hvm_info_table.h xen/include/public/hvm/ioreq.h xen/include/public/hvm/vmx_assist.h > description: > Missed adding new files. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Mon Jan 2 01:23:54 2006 -0400 > files: tools/debugger/libxendebug/xendebug.c tools/libxc/xc_hvm_build.c > description: > Finalize Xin Li's patch: vmx/svm_identify is no longer necessary. > Xen debug should test for HVM instead of VMX. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: twoller@xen-trw1.site > date: Sun Jan 1 03:22:39 2006 -0500 > files: tools/ioemu/vl.c > description: > change hardcoded VTXEN to HVMXEN. > > > user: leendert@eserver2.watson.ibm.com > date: Sun Jan 1 02:22:47 2006 -0400 > files: tools/libxc/xc_hvm_build.c tools/python/xen/xend/image.py xen/arch/x86/domain.c > description: > Avoid xen crash if there is no VMX support. If a platform > doesn't support VMX, creating VMX domain will crash xen > HV. > > Signed-off-by: Xin Li <xin.b.li@intel.com> > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > [ vmx/svm_identify are still needed in hvm builder, but this may not > really be necessary. I need to check this. - lvd ] > > > user: twoller@xen-trw1.site > date: Fri Dec 30 21:38:56 2005 -0500 > files: xen/arch/x86/svm.c xen/arch/x86/svm_vmcb.c xen/arch/x86/x86_32/entry.S xen/include/asm-x86/svm.h xen/include/asm-x86/svm_vmcb.h > description: > add multi-core support for guest ASIDs for SVM partitions. > > > user: leendert@eserver2.watson.ibm.com > date: Sun Dec 25 20:44:43 2005 -0400 > files: tools/firmware/vmxassist/head.S > description: > Make sure vmxassist still works in its debug environment. > > Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Fri Dec 23 18:27:57 2005 -0400 > files: tools/libxc/xc_ia64_stubs.c > description: > Fixed libxc ia64, xend uses xc_hvm_build instead of xc_vmx_build. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: twoller@xen-trw1.site > date: Wed Dec 21 21:39:17 2005 -0500 > files: xen/arch/x86/svm_intr.c xen/arch/x86/svm_vmcb.c > description: > cleanup of svm specific code. > > > user: leendert@eserver2.watson.ibm.com > date: Wed Dec 21 17:18:25 2005 -0400 > files: tools/python/xen/xm/tests/test_create.py tools/xm-test/README > description: > Minor name cleanups. xm-test isn't VMX specific. Instead use HVM. > > > user: twoller@xen-trw1.site > date: Tue Dec 20 20:01:38 2005 -0500 > files: xen/arch/x86/svm_vmcb.c > description: > reword comments. > > > user: twoller@xen-trw1.site > date: Tue Dec 20 20:01:07 2005 -0500 > files: xen/arch/x86/svm_intr.c > description: > add additional VLAPIC delivery modes. > > > user: twoller@xen-trw1.site > date: Tue Dec 20 20:00:22 2005 -0500 > files: xen/arch/x86/svm.c > description: > reformat misaligned code. > > > user: twoller@xen-trw1.site > date: Tue Dec 20 19:59:37 2005 -0500 > files: xen/arch/x86/svm.c > description: > Add additional AMD SVM specific CPUID logic. > > > user: leendert@eserver2.watson.ibm.com > date: Thu Dec 15 03:06:15 2005 -0400 > files: tools/xm-test/tests/block-create/01_block_attach_device_pos.py tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py tools/xm-test/tests/block-create/12_block_attach_shared_domU.py tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py tools/xm-test/tests/block-list/01_block-list_pos.py tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py tools/xm-test/tests/block-list/04_block-list_nodb_pos.py tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py tools/xm-test/tests/memmax/01_memmax_badparm_neg.py tools/xm-test/tests/memset/01_memset_basic_pos.py tools/xm-test/tests/memset/02_memset_badparm_neg.py tools/xm-test/tests/memset/03_memset_random_pos.py tools/xm-test/tests/memset/04_memset_smallmem_pos.py tools/xm-test/tests/migrate/01_migrate_localhost_pos.py tools/xm-test/tests/network-attach/01_network_attach_pos.py tools/xm-test/tests/network-attach/02_network_attach_detach_pos.py tools/xm-test/tests/network-attach/03_network_attach_detach_multiple_pos.py tools/xm-test/tests/restore/01_restore_basic_pos.py tools/xm-test/tests/restore/02_restore_badparm_neg.py tools/xm-test/tests/restore/03_restore_badfilename_neg.py tools/xm-test/tests/restore/04_restore_withdevices_pos.py tools/xm-test/tests/save/01_save_basic_pos.py tools/xm-test/tests/save/02_save_badparm_neg.py tools/xm-test/tests/save/03_save_bogusfile_neg.py tools/xm-test/tests/sysrq/01_sysrq_basic_neg.py tools/xm-test/tests/sysrq/02_sysrq_sync_pos.py tools/xm-test/tests/sysrq/03_sysrq_withreboot_pos.py > description: > Adding SKIP() to tests that aren't supported for VMX domains. > > Signed-off-by: Dan Stekloff <dsteklof@us.ibm.com> > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Tue Dec 13 22:43:47 2005 -0400 > files: xen/arch/x86/svm.c xen/arch/x86/vmx.c xen/arch/x86/vmx_io.c xen/include/asm-x86/hvm_vpit.h xen/include/asm-x86/msr.h > description: > Support VMX guest accesses to IA32_TIME_STAMP_COUNTER MSR. > > Signed-off-by: Haifeng Xue <haifeng.xue@intel.com> > Signed-off-by: Leendert van Doorn <leendert@us.ibm.com> > > > user: twoller@xen-trw1.site > date: Tue Dec 13 19:49:53 2005 -0500 > files: xen/arch/x86/svm.c xen/arch/x86/svm_emulate.c xen/arch/x86/svm_instrlen.c xen/arch/x86/svm_intr.c xen/arch/x86/svm_vmcb.c xen/include/asm-x86/svm.h xen/include/asm-x86/svm_emulate.h xen/include/asm-x86/svm_intr.h xen/include/asm-x86/svm_vmcb.h xen/include/asm-x86/svm_vmmcall.h > description: > Add SVM base files to repository. > > > user: twoller@xen-trw1.site > date: Tue Dec 13 19:49:02 2005 -0500 > files: xen/arch/x86/x86_32/entry.S xen/arch/x86/x86_64/entry.S > description: > Add SVM entry points for launch/resume. > > > user: twoller@xen-trw1.site > date: Tue Dec 13 19:47:38 2005 -0500 > files: .hgignore > description: > Add hvmloader files to ignore list. > > > user: leendert@eserver2.watson.ibm.com > date: Mon Dec 12 22:58:54 2005 -0400 > files: docs/src/user.tex tools/firmware/README xen/include/asm-x86/hvm.h > description: > Removed dirty words (by request). > > > user: leendert@eserver2.watson.ibm.com > date: Mon Dec 12 05:48:22 2005 -0400 > files: tools/firmware/hvmloader/mkhex > description: > Fix file mode. > > Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com> > > > user: leendert@eserver2.watson.ibm.com > date: Mon Dec 12 04:50:42 2005 -0400 > files: xen/Rules.mk xen/arch/x86/cpu/amd.c xen/arch/x86/cpu/intel.c xen/arch/x86/dm/hvm_vioapic.c xen/arch/x86/dm/i8259.c xen/arch/x86/dom0_ops.c xen/arch/x86/domain.c xen/arch/x86/hvm.c xen/arch/x86/hvm_intercept.c xen/arch/x86/hvm_io.c xen/arch/x86/hvm_platform.c xen/arch/x86/hvm_vlapic.c xen/arch/x86/mpparse.c xen/arch/x86/shadow.c xen/arch/x86/vmx.c xen/arch/x86/vmx_io.c xen/arch/x86/vmx_vmcs.c xen/arch/x86/x86_32/asm-offsets.c xen/arch/x86/x86_32/entry.S xen/arch/x86/x86_64/asm-offsets.c xen/arch/x86/x86_64/entry.S xen/arch/x86/x86_64/mm.c xen/include/asm-x86/config.h xen/include/asm-x86/cpufeature.h xen/include/asm-x86/domain.h xen/include/asm-x86/hvm_domain.h xen/include/asm-x86/hvm_io.h xen/include/asm-x86/hvm_support.h xen/include/asm-x86/hvm_vcpu.h xen/include/asm-x86/hvm_vioapic.h xen/include/asm-x86/hvm_vlapic.h xen/include/asm-x86/hvm_vpic.h xen/include/asm-x86/hvm_vpit.h xen/include/asm-x86/mpspec.h xen/include/asm-x86/msr.h xen/include/asm-x86/processor.h xen/include/asm-x86/vmx.h xen/include/asm-x86/vmx_cpu.h xen/include/asm-x86/vmx_vmcs.h > description: > Phase 3 of HVM integration: This patchset introduces the refactoring of > virtualization architecture independent functions from specific ones. > > > user: leendert@eserver2.watson.ibm.com > date: Sun Dec 11 07:02:51 2005 -0400 > files: xen/arch/x86/dom0_ops.c xen/arch/x86/domain.c xen/arch/x86/i387.c xen/arch/x86/shadow.c xen/arch/x86/vmx.c xen/arch/x86/x86_32/traps.c xen/arch/x86/x86_64/traps.c xen/include/asm-x86/hvm.h xen/include/asm-x86/hvm_support.h xen/include/asm-x86/regs.h xen/include/asm-x86/shadow.h xen/include/asm-x86/vmx_vmcs.h > description: > Phase 2 of HVM integration: This patchset introduces the hvm interface > to the hypervisor and modifies all the non-vmx specific files to use it. > > > user: leendert@eserver2.watson.ibm.com > date: Sun Dec 11 01:10:00 2005 -0400 > files: tools/examples/Makefile tools/examples/README tools/examples/xmexample.hvm tools/ioemu/exec-all.h tools/ioemu/hw/i8254.c tools/ioemu/hw/i8259.c tools/ioemu/monitor.c tools/ioemu/target-i386-dm/helper2.c tools/ioemu/vl.c tools/libxc/Makefile tools/libxc/xc_hvm_build.c tools/libxc/xc_ptrace.c tools/libxc/xc_ptrace_core.c tools/libxc/xenguest.h tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/image.py tools/python/xen/xm/create.py tools/xm-test/configure.ac tools/xm-test/lib/XmTestLib/XenDomain.py tools/xm-test/lib/XmTestLib/config.py.in tools/xm-test/ramdisk/Makefile.am tools/xm-test/ramdisk/bin/create_disk_image tools/xm-test/tests/block-list/04_block-list_nodb_pos.py xen/include/public/arch-x86_32.h xen/include/public/arch-x86_64.h > description: > Phase 1 of HVM integration: This patchset updates the tools. Most of the > tools are machine independent except for some detection code in the hvm > domain builder.
952 lines
29 KiB
C
952 lines
29 KiB
C
/*
|
|
* platform.c: handling x86 platform related MMIO instructions
|
|
*
|
|
* Copyright (c) 2004, Intel Corporation.
|
|
* Copyright (c) 2005, International Business Machines Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
|
*/
|
|
|
|
#include <xen/config.h>
|
|
#include <xen/types.h>
|
|
#include <xen/mm.h>
|
|
#include <asm/shadow.h>
|
|
#include <xen/domain_page.h>
|
|
#include <asm/page.h>
|
|
#include <xen/event.h>
|
|
#include <xen/trace.h>
|
|
#include <xen/sched.h>
|
|
#include <asm/regs.h>
|
|
#include <asm/hvm/hvm.h>
|
|
#include <asm/hvm/support.h>
|
|
#include <public/hvm/ioreq.h>
|
|
|
|
#include <xen/lib.h>
|
|
#include <xen/sched.h>
|
|
#include <asm/current.h>
|
|
#if CONFIG_PAGING_LEVELS >= 3
|
|
#include <asm/shadow_64.h>
|
|
#endif
|
|
|
|
#define DECODE_success 1
|
|
#define DECODE_failure 0
|
|
|
|
extern long evtchn_send(int lport);
|
|
|
|
#if defined (__x86_64__)
|
|
static inline long __get_reg_value(unsigned long reg, int size)
|
|
{
|
|
switch(size) {
|
|
case BYTE_64:
|
|
return (char)(reg & 0xFF);
|
|
case WORD:
|
|
return (short)(reg & 0xFFFF);
|
|
case LONG:
|
|
return (int)(reg & 0xFFFFFFFF);
|
|
case QUAD:
|
|
return (long)(reg);
|
|
default:
|
|
printf("Error: (__get_reg_value) Invalid reg size\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
|
|
long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
|
|
{
|
|
if (size == BYTE) {
|
|
switch (index) {
|
|
case 0: /* %al */
|
|
return (char)(regs->rax & 0xFF);
|
|
case 1: /* %cl */
|
|
return (char)(regs->rcx & 0xFF);
|
|
case 2: /* %dl */
|
|
return (char)(regs->rdx & 0xFF);
|
|
case 3: /* %bl */
|
|
return (char)(regs->rbx & 0xFF);
|
|
case 4: /* %ah */
|
|
return (char)((regs->rax & 0xFF00) >> 8);
|
|
case 5: /* %ch */
|
|
return (char)((regs->rcx & 0xFF00) >> 8);
|
|
case 6: /* %dh */
|
|
return (char)((regs->rdx & 0xFF00) >> 8);
|
|
case 7: /* %bh */
|
|
return (char)((regs->rbx & 0xFF00) >> 8);
|
|
default:
|
|
printf("Error: (get_reg_value) Invalid index value\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
switch (index) {
|
|
case 0: return __get_reg_value(regs->rax, size);
|
|
case 1: return __get_reg_value(regs->rcx, size);
|
|
case 2: return __get_reg_value(regs->rdx, size);
|
|
case 3: return __get_reg_value(regs->rbx, size);
|
|
case 4: return __get_reg_value(regs->rsp, size);
|
|
case 5: return __get_reg_value(regs->rbp, size);
|
|
case 6: return __get_reg_value(regs->rsi, size);
|
|
case 7: return __get_reg_value(regs->rdi, size);
|
|
case 8: return __get_reg_value(regs->r8, size);
|
|
case 9: return __get_reg_value(regs->r9, size);
|
|
case 10: return __get_reg_value(regs->r10, size);
|
|
case 11: return __get_reg_value(regs->r11, size);
|
|
case 12: return __get_reg_value(regs->r12, size);
|
|
case 13: return __get_reg_value(regs->r13, size);
|
|
case 14: return __get_reg_value(regs->r14, size);
|
|
case 15: return __get_reg_value(regs->r15, size);
|
|
default:
|
|
printf("Error: (get_reg_value) Invalid index value\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
#elif defined (__i386__)
|
|
static inline long __get_reg_value(unsigned long reg, int size)
|
|
{
|
|
switch(size) {
|
|
case WORD:
|
|
return (short)(reg & 0xFFFF);
|
|
case LONG:
|
|
return (int)(reg & 0xFFFFFFFF);
|
|
default:
|
|
printf("Error: (__get_reg_value) Invalid reg size\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
|
|
long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
|
|
{
|
|
if (size == BYTE) {
|
|
switch (index) {
|
|
case 0: /* %al */
|
|
return (char)(regs->eax & 0xFF);
|
|
case 1: /* %cl */
|
|
return (char)(regs->ecx & 0xFF);
|
|
case 2: /* %dl */
|
|
return (char)(regs->edx & 0xFF);
|
|
case 3: /* %bl */
|
|
return (char)(regs->ebx & 0xFF);
|
|
case 4: /* %ah */
|
|
return (char)((regs->eax & 0xFF00) >> 8);
|
|
case 5: /* %ch */
|
|
return (char)((regs->ecx & 0xFF00) >> 8);
|
|
case 6: /* %dh */
|
|
return (char)((regs->edx & 0xFF00) >> 8);
|
|
case 7: /* %bh */
|
|
return (char)((regs->ebx & 0xFF00) >> 8);
|
|
default:
|
|
printf("Error: (get_reg_value) Invalid index value\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
|
|
switch (index) {
|
|
case 0: return __get_reg_value(regs->eax, size);
|
|
case 1: return __get_reg_value(regs->ecx, size);
|
|
case 2: return __get_reg_value(regs->edx, size);
|
|
case 3: return __get_reg_value(regs->ebx, size);
|
|
case 4: return __get_reg_value(regs->esp, size);
|
|
case 5: return __get_reg_value(regs->ebp, size);
|
|
case 6: return __get_reg_value(regs->esi, size);
|
|
case 7: return __get_reg_value(regs->edi, size);
|
|
default:
|
|
printf("Error: (get_reg_value) Invalid index value\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static inline unsigned char *check_prefix(unsigned char *inst,
|
|
struct instruction *thread_inst, unsigned char *rex_p)
|
|
{
|
|
while (1) {
|
|
switch (*inst) {
|
|
/* rex prefix for em64t instructions */
|
|
case 0x40 ... 0x4e:
|
|
*rex_p = *inst;
|
|
break;
|
|
case 0xf3: /* REPZ */
|
|
thread_inst->flags = REPZ;
|
|
break;
|
|
case 0xf2: /* REPNZ */
|
|
thread_inst->flags = REPNZ;
|
|
break;
|
|
case 0xf0: /* LOCK */
|
|
break;
|
|
case 0x2e: /* CS */
|
|
case 0x36: /* SS */
|
|
case 0x3e: /* DS */
|
|
case 0x26: /* ES */
|
|
case 0x64: /* FS */
|
|
case 0x65: /* GS */
|
|
thread_inst->seg_sel = *inst;
|
|
break;
|
|
case 0x66: /* 32bit->16bit */
|
|
thread_inst->op_size = WORD;
|
|
break;
|
|
case 0x67:
|
|
break;
|
|
default:
|
|
return inst;
|
|
}
|
|
inst++;
|
|
}
|
|
}
|
|
|
|
static inline unsigned long get_immediate(int op16,const unsigned char *inst, int op_size)
|
|
{
|
|
int mod, reg, rm;
|
|
unsigned long val = 0;
|
|
int i;
|
|
|
|
mod = (*inst >> 6) & 3;
|
|
reg = (*inst >> 3) & 7;
|
|
rm = *inst & 7;
|
|
|
|
inst++; //skip ModR/M byte
|
|
if (mod != 3 && rm == 4) {
|
|
inst++; //skip SIB byte
|
|
}
|
|
|
|
switch(mod) {
|
|
case 0:
|
|
if (rm == 5 || rm == 4) {
|
|
if (op16)
|
|
inst = inst + 2; //disp16, skip 2 bytes
|
|
else
|
|
inst = inst + 4; //disp32, skip 4 bytes
|
|
}
|
|
break;
|
|
case 1:
|
|
inst++; //disp8, skip 1 byte
|
|
break;
|
|
case 2:
|
|
if (op16)
|
|
inst = inst + 2; //disp16, skip 2 bytes
|
|
else
|
|
inst = inst + 4; //disp32, skip 4 bytes
|
|
break;
|
|
}
|
|
|
|
if (op_size == QUAD)
|
|
op_size = LONG;
|
|
|
|
for (i = 0; i < op_size; i++) {
|
|
val |= (*inst++ & 0xff) << (8 * i);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline int get_index(const unsigned char *inst, unsigned char rex)
|
|
{
|
|
int mod, reg, rm;
|
|
int rex_r, rex_b;
|
|
|
|
mod = (*inst >> 6) & 3;
|
|
reg = (*inst >> 3) & 7;
|
|
rm = *inst & 7;
|
|
|
|
rex_r = (rex >> 2) & 1;
|
|
rex_b = rex & 1;
|
|
|
|
//Only one operand in the instruction is register
|
|
if (mod == 3) {
|
|
return (rm + (rex_b << 3));
|
|
} else {
|
|
return (reg + (rex_r << 3));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void init_instruction(struct instruction *mmio_inst)
|
|
{
|
|
mmio_inst->instr = 0;
|
|
mmio_inst->op_size = 0;
|
|
mmio_inst->immediate = 0;
|
|
mmio_inst->seg_sel = 0;
|
|
|
|
mmio_inst->operand[0] = 0;
|
|
mmio_inst->operand[1] = 0;
|
|
|
|
mmio_inst->flags = 0;
|
|
}
|
|
|
|
#define GET_OP_SIZE_FOR_BYTE(op_size) \
|
|
do { \
|
|
if (rex) \
|
|
op_size = BYTE_64; \
|
|
else \
|
|
op_size = BYTE; \
|
|
} while(0)
|
|
|
|
#define GET_OP_SIZE_FOR_NONEBYTE(op_size) \
|
|
do { \
|
|
if (rex & 0x8) \
|
|
op_size = QUAD; \
|
|
else if (op_size != WORD) \
|
|
op_size = LONG; \
|
|
} while(0)
|
|
|
|
|
|
/*
|
|
* Decode mem,accumulator operands (as in <opcode> m8/m16/m32, al,ax,eax)
|
|
*/
|
|
static int mem_acc(unsigned char size, struct instruction *instr)
|
|
{
|
|
instr->operand[0] = mk_operand(size, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(size, 0, 0, REGISTER);
|
|
return DECODE_success;
|
|
}
|
|
|
|
/*
|
|
* Decode accumulator,mem operands (as in <opcode> al,ax,eax, m8/m16/m32)
|
|
*/
|
|
static int acc_mem(unsigned char size, struct instruction *instr)
|
|
{
|
|
instr->operand[0] = mk_operand(size, 0, 0, REGISTER);
|
|
instr->operand[1] = mk_operand(size, 0, 0, MEMORY);
|
|
return DECODE_success;
|
|
}
|
|
|
|
/*
|
|
* Decode mem,reg operands (as in <opcode> r32/16, m32/16)
|
|
*/
|
|
static int mem_reg(unsigned char size, unsigned char *opcode,
|
|
struct instruction *instr, unsigned char rex)
|
|
{
|
|
int index = get_index(opcode + 1, rex);
|
|
|
|
instr->operand[0] = mk_operand(size, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(size, index, 0, REGISTER);
|
|
return DECODE_success;
|
|
}
|
|
|
|
/*
|
|
* Decode reg,mem operands (as in <opcode> m32/16, r32/16)
|
|
*/
|
|
static int reg_mem(unsigned char size, unsigned char *opcode,
|
|
struct instruction *instr, unsigned char rex)
|
|
{
|
|
int index = get_index(opcode + 1, rex);
|
|
|
|
instr->operand[0] = mk_operand(size, index, 0, REGISTER);
|
|
instr->operand[1] = mk_operand(size, 0, 0, MEMORY);
|
|
return DECODE_success;
|
|
}
|
|
|
|
static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *instr)
|
|
{
|
|
unsigned char size_reg = 0;
|
|
unsigned char rex = 0;
|
|
int index;
|
|
|
|
init_instruction(instr);
|
|
|
|
opcode = check_prefix(opcode, instr, &rex);
|
|
|
|
if (realmode) { /* meaning is reversed */
|
|
if (instr->op_size == WORD)
|
|
instr->op_size = LONG;
|
|
else if (instr->op_size == LONG)
|
|
instr->op_size = WORD;
|
|
else if (instr->op_size == 0)
|
|
instr->op_size = WORD;
|
|
}
|
|
|
|
switch (*opcode) {
|
|
case 0x0B: /* or m32/16, r32/16 */
|
|
instr->instr = INSTR_OR;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return mem_reg(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x20: /* and r8, m8 */
|
|
instr->instr = INSTR_AND;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return reg_mem(size_reg, opcode, instr, rex);
|
|
|
|
case 0x21: /* and r32/16, m32/16 */
|
|
instr->instr = INSTR_AND;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return reg_mem(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x23: /* and m32/16, r32/16 */
|
|
instr->instr = INSTR_AND;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return mem_reg(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x30: /* xor r8, m8 */
|
|
instr->instr = INSTR_XOR;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return reg_mem(size_reg, opcode, instr, rex);
|
|
|
|
case 0x31: /* xor r32/16, m32/16 */
|
|
instr->instr = INSTR_XOR;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return reg_mem(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x39: /* cmp r32/16, m32/16 */
|
|
instr->instr = INSTR_CMP;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return reg_mem(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x80:
|
|
case 0x81:
|
|
{
|
|
unsigned char ins_subtype = (opcode[1] >> 3) & 7;
|
|
|
|
if (opcode[0] == 0x80) {
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
instr->op_size = BYTE;
|
|
} else {
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
size_reg = instr->op_size;
|
|
}
|
|
|
|
instr->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
|
|
instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
|
|
instr->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
|
|
|
|
switch (ins_subtype) {
|
|
case 7: /* cmp $imm, m32/16 */
|
|
instr->instr = INSTR_CMP;
|
|
return DECODE_success;
|
|
|
|
case 1: /* or $imm, m32/16 */
|
|
instr->instr = INSTR_OR;
|
|
return DECODE_success;
|
|
|
|
default:
|
|
printf("%x, This opcode isn't handled yet!\n", *opcode);
|
|
return DECODE_failure;
|
|
}
|
|
}
|
|
|
|
case 0x84: /* test m8, r8 */
|
|
instr->instr = INSTR_TEST;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return mem_reg(size_reg, opcode, instr, rex);
|
|
|
|
case 0x88: /* mov r8, m8 */
|
|
instr->instr = INSTR_MOV;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return reg_mem(size_reg, opcode, instr, rex);
|
|
|
|
case 0x89: /* mov r32/16, m32/16 */
|
|
instr->instr = INSTR_MOV;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return reg_mem(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0x8A: /* mov m8, r8 */
|
|
instr->instr = INSTR_MOV;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return mem_reg(size_reg, opcode, instr, rex);
|
|
|
|
case 0x8B: /* mov m32/16, r32/16 */
|
|
instr->instr = INSTR_MOV;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return mem_reg(instr->op_size, opcode, instr, rex);
|
|
|
|
case 0xA0: /* mov <addr>, al */
|
|
instr->instr = INSTR_MOV;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return mem_acc(size_reg, instr);
|
|
|
|
case 0xA1: /* mov <addr>, ax/eax */
|
|
instr->instr = INSTR_MOV;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return mem_acc(instr->op_size, instr);
|
|
|
|
case 0xA2: /* mov al, <addr> */
|
|
instr->instr = INSTR_MOV;
|
|
instr->op_size = BYTE;
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
return acc_mem(size_reg, instr);
|
|
|
|
case 0xA3: /* mov ax/eax, <addr> */
|
|
instr->instr = INSTR_MOV;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return acc_mem(instr->op_size, instr);
|
|
|
|
case 0xA4: /* movsb */
|
|
instr->instr = INSTR_MOVS;
|
|
instr->op_size = BYTE;
|
|
return DECODE_success;
|
|
|
|
case 0xA5: /* movsw/movsl */
|
|
instr->instr = INSTR_MOVS;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return DECODE_success;
|
|
|
|
case 0xAA: /* stosb */
|
|
instr->instr = INSTR_STOS;
|
|
instr->op_size = BYTE;
|
|
return DECODE_success;
|
|
|
|
case 0xAB: /* stosw/stosl */
|
|
instr->instr = INSTR_STOS;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
return DECODE_success;
|
|
|
|
case 0xC6:
|
|
if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm8, m8 */
|
|
instr->instr = INSTR_MOV;
|
|
instr->op_size = BYTE;
|
|
|
|
instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE);
|
|
instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
|
|
instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
|
|
|
|
return DECODE_success;
|
|
} else
|
|
return DECODE_failure;
|
|
|
|
case 0xC7:
|
|
if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm16/32, m16/32 */
|
|
instr->instr = INSTR_MOV;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
|
|
instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE);
|
|
instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
|
|
instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
|
|
|
|
return DECODE_success;
|
|
} else
|
|
return DECODE_failure;
|
|
|
|
case 0xF6:
|
|
case 0xF7:
|
|
if (((opcode[1] >> 3) & 7) == 0) { /* test $imm8/16/32, m8/16/32 */
|
|
instr->instr = INSTR_TEST;
|
|
|
|
if (opcode[0] == 0xF6) {
|
|
GET_OP_SIZE_FOR_BYTE(size_reg);
|
|
instr->op_size = BYTE;
|
|
} else {
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
size_reg = instr->op_size;
|
|
}
|
|
|
|
instr->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
|
|
instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
|
|
instr->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
|
|
|
|
return DECODE_success;
|
|
} else
|
|
return DECODE_failure;
|
|
|
|
case 0x0F:
|
|
break;
|
|
|
|
default:
|
|
printf("%x, This opcode isn't handled yet!\n", *opcode);
|
|
return DECODE_failure;
|
|
}
|
|
|
|
switch (*++opcode) {
|
|
case 0xB6: /* movzx m8, r16/r32/r64 */
|
|
instr->instr = INSTR_MOVZX;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
index = get_index(opcode + 1, rex);
|
|
instr->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
|
|
return DECODE_success;
|
|
|
|
case 0xB7: /* movzx m16/m32, r32/r64 */
|
|
instr->instr = INSTR_MOVZX;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
index = get_index(opcode + 1, rex);
|
|
if (rex & 0x8)
|
|
instr->operand[0] = mk_operand(LONG, 0, 0, MEMORY);
|
|
else
|
|
instr->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
|
|
return DECODE_success;
|
|
|
|
case 0xBE: /* movsx m8, r16/r32/r64 */
|
|
instr->instr = INSTR_MOVSX;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
index = get_index(opcode + 1, rex);
|
|
instr->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
|
|
return DECODE_success;
|
|
|
|
case 0xBF: /* movsx m16, r32/r64 */
|
|
instr->instr = INSTR_MOVSX;
|
|
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
|
index = get_index(opcode + 1, rex);
|
|
instr->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
|
|
instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
|
|
return DECODE_success;
|
|
|
|
case 0xA3: /* bt r32, m32 */
|
|
instr->instr = INSTR_BT;
|
|
index = get_index(opcode + 1, rex);
|
|
instr->op_size = LONG;
|
|
instr->operand[0] = mk_operand(instr->op_size, index, 0, REGISTER);
|
|
instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
|
|
return DECODE_success;
|
|
|
|
default:
|
|
printf("0f %x, This opcode isn't handled yet\n", *opcode);
|
|
return DECODE_failure;
|
|
}
|
|
}
|
|
|
|
int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip, int inst_len)
|
|
{
|
|
if (inst_len > MAX_INST_LEN || inst_len <= 0)
|
|
return 0;
|
|
if (!hvm_copy(buf, guest_eip, inst_len, HVM_COPY_IN))
|
|
return 0;
|
|
return inst_len;
|
|
}
|
|
|
|
void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
|
|
unsigned long count, int size, long value, int dir, int pvalid)
|
|
{
|
|
struct vcpu *v = current;
|
|
vcpu_iodata_t *vio;
|
|
ioreq_t *p;
|
|
|
|
vio = get_vio(v->domain, v->vcpu_id);
|
|
if (vio == NULL) {
|
|
printk("bad shared page: %lx\n", (unsigned long) vio);
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) {
|
|
printf("HVM I/O has not yet completed\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
set_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags);
|
|
|
|
p = &vio->vp_ioreq;
|
|
p->dir = dir;
|
|
p->pdata_valid = pvalid;
|
|
|
|
p->type = IOREQ_TYPE_PIO;
|
|
p->size = size;
|
|
p->addr = port;
|
|
p->count = count;
|
|
p->df = regs->eflags & EF_DF ? 1 : 0;
|
|
|
|
if (pvalid) {
|
|
if (hvm_paging_enabled(current))
|
|
p->u.pdata = (void *) gva_to_gpa(value);
|
|
else
|
|
p->u.pdata = (void *) value; /* guest VA == guest PA */
|
|
} else
|
|
p->u.data = value;
|
|
|
|
if (hvm_portio_intercept(p)) {
|
|
p->state = STATE_IORESP_READY;
|
|
hvm_io_assist(v);
|
|
return;
|
|
}
|
|
|
|
p->state = STATE_IOREQ_READY;
|
|
|
|
evtchn_send(iopacket_port(v->domain));
|
|
hvm_wait_io();
|
|
}
|
|
|
|
void send_mmio_req(unsigned char type, unsigned long gpa,
|
|
unsigned long count, int size, long value, int dir, int pvalid)
|
|
{
|
|
struct vcpu *v = current;
|
|
vcpu_iodata_t *vio;
|
|
ioreq_t *p;
|
|
struct cpu_user_regs *regs;
|
|
extern long evtchn_send(int lport);
|
|
|
|
regs = current->arch.hvm_vcpu.mmio_op.inst_decoder_regs;
|
|
|
|
vio = get_vio(v->domain, v->vcpu_id);
|
|
if (vio == NULL) {
|
|
printf("bad shared page\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
p = &vio->vp_ioreq;
|
|
|
|
if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) {
|
|
printf("HVM I/O has not yet completed\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
set_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags);
|
|
p->dir = dir;
|
|
p->pdata_valid = pvalid;
|
|
|
|
p->type = type;
|
|
p->size = size;
|
|
p->addr = gpa;
|
|
p->count = count;
|
|
p->df = regs->eflags & EF_DF ? 1 : 0;
|
|
|
|
if (pvalid) {
|
|
if (hvm_paging_enabled(v))
|
|
p->u.pdata = (void *) gva_to_gpa(value);
|
|
else
|
|
p->u.pdata = (void *) value; /* guest VA == guest PA */
|
|
} else
|
|
p->u.data = value;
|
|
|
|
if (hvm_mmio_intercept(p)){
|
|
p->state = STATE_IORESP_READY;
|
|
hvm_io_assist(v);
|
|
return;
|
|
}
|
|
|
|
p->state = STATE_IOREQ_READY;
|
|
|
|
evtchn_send(iopacket_port(v->domain));
|
|
hvm_wait_io();
|
|
}
|
|
|
|
static void mmio_operands(int type, unsigned long gpa, struct instruction *inst,
|
|
struct mmio_op *mmio_opp, struct cpu_user_regs *regs)
|
|
{
|
|
unsigned long value = 0;
|
|
int index, size_reg;
|
|
|
|
size_reg = operand_size(inst->operand[0]);
|
|
|
|
mmio_opp->flags = inst->flags;
|
|
mmio_opp->instr = inst->instr;
|
|
mmio_opp->operand[0] = inst->operand[0]; /* source */
|
|
mmio_opp->operand[1] = inst->operand[1]; /* destination */
|
|
mmio_opp->immediate = inst->immediate;
|
|
|
|
if (inst->operand[0] & REGISTER) { /* dest is memory */
|
|
index = operand_index(inst->operand[0]);
|
|
value = get_reg_value(size_reg, index, 0, regs);
|
|
send_mmio_req(type, gpa, 1, inst->op_size, value, IOREQ_WRITE, 0);
|
|
} else if (inst->operand[0] & IMMEDIATE) { /* dest is memory */
|
|
value = inst->immediate;
|
|
send_mmio_req(type, gpa, 1, inst->op_size, value, IOREQ_WRITE, 0);
|
|
} else if (inst->operand[0] & MEMORY) { /* dest is register */
|
|
/* send the request and wait for the value */
|
|
if ( (inst->instr == INSTR_MOVZX) || (inst->instr == INSTR_MOVSX) )
|
|
send_mmio_req(type, gpa, 1, size_reg, 0, IOREQ_READ, 0);
|
|
else
|
|
send_mmio_req(type, gpa, 1, inst->op_size, 0, IOREQ_READ, 0);
|
|
} else {
|
|
printf("mmio_operands: invalid operand\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
|
|
#define GET_REPEAT_COUNT() \
|
|
(mmio_inst.flags & REPZ ? (realmode ? regs->ecx & 0xFFFF : regs->ecx) : 1)
|
|
|
|
void handle_mmio(unsigned long va, unsigned long gpa)
|
|
{
|
|
unsigned long inst_len, inst_addr;
|
|
struct mmio_op *mmio_opp;
|
|
struct cpu_user_regs *regs;
|
|
struct instruction mmio_inst;
|
|
unsigned char inst[MAX_INST_LEN];
|
|
int i, realmode, ret;
|
|
struct vcpu *v = current;
|
|
|
|
mmio_opp = &v->arch.hvm_vcpu.mmio_op;
|
|
|
|
regs = mmio_opp->inst_decoder_regs;
|
|
hvm_store_cpu_guest_regs(v, regs);
|
|
|
|
if ((inst_len = hvm_instruction_length(v)) <= 0) {
|
|
printf("handle_mmio: failed to get instruction length\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
realmode = hvm_realmode(v);
|
|
if (realmode)
|
|
inst_addr = (regs->cs << 4) + regs->eip;
|
|
else
|
|
inst_addr = regs->eip;
|
|
|
|
memset(inst, 0, MAX_INST_LEN);
|
|
ret = inst_copy_from_guest(inst, inst_addr, inst_len);
|
|
if (ret != inst_len) {
|
|
printf("handle_mmio: failed to copy instruction\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
init_instruction(&mmio_inst);
|
|
|
|
if (hvm_decode(realmode, inst, &mmio_inst) == DECODE_failure) {
|
|
printf("handle_mmio: failed to decode instruction\n");
|
|
printf("mmio opcode: va 0x%lx, gpa 0x%lx, len %ld:",
|
|
va, gpa, inst_len);
|
|
for (i = 0; i < inst_len; i++)
|
|
printf(" %02x", inst[i] & 0xFF);
|
|
printf("\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
|
|
regs->eip += inst_len; /* advance %eip */
|
|
|
|
switch (mmio_inst.instr) {
|
|
case INSTR_MOV:
|
|
mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mmio_opp, regs);
|
|
break;
|
|
|
|
case INSTR_MOVS:
|
|
{
|
|
unsigned long count = GET_REPEAT_COUNT();
|
|
unsigned long size = mmio_inst.op_size;
|
|
int sign = regs->eflags & EF_DF ? -1 : 1;
|
|
unsigned long addr = 0;
|
|
int dir;
|
|
|
|
/* determine non-MMIO address */
|
|
if (realmode) {
|
|
if (((regs->es << 4) + (regs->edi & 0xFFFF)) == va) {
|
|
dir = IOREQ_WRITE;
|
|
addr = (regs->ds << 4) + (regs->esi & 0xFFFF);
|
|
} else {
|
|
dir = IOREQ_READ;
|
|
addr = (regs->es << 4) + (regs->edi & 0xFFFF);
|
|
}
|
|
} else {
|
|
if (va == regs->edi) {
|
|
dir = IOREQ_WRITE;
|
|
addr = regs->esi;
|
|
} else {
|
|
dir = IOREQ_READ;
|
|
addr = regs->edi;
|
|
}
|
|
}
|
|
|
|
mmio_opp->flags = mmio_inst.flags;
|
|
mmio_opp->instr = mmio_inst.instr;
|
|
|
|
/*
|
|
* In case of a movs spanning multiple pages, we break the accesses
|
|
* up into multiple pages (the device model works with non-continguous
|
|
* physical guest pages). To copy just one page, we adjust %ecx and
|
|
* do not advance %eip so that the next "rep movs" copies the next page.
|
|
* Unaligned accesses, for example movsl starting at PGSZ-2, are
|
|
* turned into a single copy where we handle the overlapping memory
|
|
* copy ourself. After this copy succeeds, "rep movs" is executed
|
|
* again.
|
|
*/
|
|
if ((addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK)) {
|
|
unsigned long value = 0;
|
|
|
|
mmio_opp->flags |= OVERLAP;
|
|
|
|
regs->eip -= inst_len; /* do not advance %eip */
|
|
|
|
if (dir == IOREQ_WRITE)
|
|
hvm_copy(&value, addr, size, HVM_COPY_IN);
|
|
send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, size, value, dir, 0);
|
|
} else {
|
|
if ((addr & PAGE_MASK) != ((addr + count * size - 1) & PAGE_MASK)) {
|
|
regs->eip -= inst_len; /* do not advance %eip */
|
|
|
|
if (sign > 0)
|
|
count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
|
|
else
|
|
count = (addr & ~PAGE_MASK) / size;
|
|
}
|
|
|
|
send_mmio_req(IOREQ_TYPE_COPY, gpa, count, size, addr, dir, 1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case INSTR_MOVZX:
|
|
case INSTR_MOVSX:
|
|
mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mmio_opp, regs);
|
|
break;
|
|
|
|
case INSTR_STOS:
|
|
/*
|
|
* Since the destination is always in (contiguous) mmio space we don't
|
|
* need to break it up into pages.
|
|
*/
|
|
mmio_opp->flags = mmio_inst.flags;
|
|
mmio_opp->instr = mmio_inst.instr;
|
|
send_mmio_req(IOREQ_TYPE_COPY, gpa,
|
|
GET_REPEAT_COUNT(), mmio_inst.op_size, regs->eax, IOREQ_WRITE, 0);
|
|
break;
|
|
|
|
case INSTR_OR:
|
|
mmio_operands(IOREQ_TYPE_OR, gpa, &mmio_inst, mmio_opp, regs);
|
|
break;
|
|
|
|
case INSTR_AND:
|
|
mmio_operands(IOREQ_TYPE_AND, gpa, &mmio_inst, mmio_opp, regs);
|
|
break;
|
|
|
|
case INSTR_XOR:
|
|
mmio_operands(IOREQ_TYPE_XOR, gpa, &mmio_inst, mmio_opp, regs);
|
|
break;
|
|
|
|
case INSTR_CMP: /* Pass through */
|
|
case INSTR_TEST:
|
|
mmio_opp->flags = mmio_inst.flags;
|
|
mmio_opp->instr = mmio_inst.instr;
|
|
mmio_opp->operand[0] = mmio_inst.operand[0]; /* source */
|
|
mmio_opp->operand[1] = mmio_inst.operand[1]; /* destination */
|
|
mmio_opp->immediate = mmio_inst.immediate;
|
|
|
|
/* send the request and wait for the value */
|
|
send_mmio_req(IOREQ_TYPE_COPY, gpa, 1,
|
|
mmio_inst.op_size, 0, IOREQ_READ, 0);
|
|
break;
|
|
|
|
case INSTR_BT:
|
|
{
|
|
unsigned long value = 0;
|
|
int index, size;
|
|
|
|
mmio_opp->instr = mmio_inst.instr;
|
|
mmio_opp->operand[0] = mmio_inst.operand[0]; /* bit offset */
|
|
mmio_opp->operand[1] = mmio_inst.operand[1]; /* bit base */
|
|
|
|
index = operand_index(mmio_inst.operand[0]);
|
|
size = operand_size(mmio_inst.operand[0]);
|
|
value = get_reg_value(size, index, 0, regs);
|
|
|
|
send_mmio_req(IOREQ_TYPE_COPY, gpa + (value >> 5), 1,
|
|
mmio_inst.op_size, 0, IOREQ_READ, 0);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
printf("Unhandled MMIO instruction\n");
|
|
domain_crash_synchronous();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-set-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|