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.
1091 lines
25 KiB
C
1091 lines
25 KiB
C
/*
|
|
* vm86.c: A vm86 emulator. The main purpose of this emulator is to do as
|
|
* little work as possible.
|
|
*
|
|
* Leendert van Doorn, leendert@watson.ibm.com
|
|
* 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 "vm86.h"
|
|
#include "util.h"
|
|
#include "machine.h"
|
|
|
|
#define HIGHMEM (1 << 20) /* 1MB */
|
|
#define MASK16(v) ((v) & 0xFFFF)
|
|
|
|
#define DATA32 0x0001
|
|
#define ADDR32 0x0002
|
|
#define SEG_CS 0x0004
|
|
#define SEG_DS 0x0008
|
|
#define SEG_ES 0x0010
|
|
#define SEG_SS 0x0020
|
|
#define SEG_FS 0x0040
|
|
#define SEG_GS 0x0080
|
|
|
|
unsigned prev_eip = 0;
|
|
enum vm86_mode mode;
|
|
|
|
#ifdef DEBUG
|
|
int traceset = 0;
|
|
|
|
char *states[] = {
|
|
"<VM86_REAL>",
|
|
"<VM86_REAL_TO_PROTECTED>",
|
|
"<VM86_PROTECTED_TO_REAL>",
|
|
"<VM86_PROTECTED>"
|
|
};
|
|
#endif /* DEBUG */
|
|
|
|
|
|
unsigned
|
|
address(struct regs *regs, unsigned seg, unsigned off)
|
|
{
|
|
unsigned long long entry;
|
|
unsigned addr;
|
|
|
|
/* real mode: segment is part of the address */
|
|
if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED)
|
|
return ((seg & 0xFFFF) << 4) + off;
|
|
|
|
/* protected mode: use seg as index into gdt */
|
|
if (seg > oldctx.gdtr_limit) {
|
|
printf("address: Invalid segment descriptor (0x%x)\n", seg);
|
|
return 0;
|
|
}
|
|
|
|
entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3];
|
|
addr = (((entry >> (56-24)) & 0xFF000000) |
|
|
((entry >> (32-16)) & 0x00FF0000) |
|
|
((entry >> ( 16)) & 0x0000FFFF)) + off;
|
|
return addr;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
trace(struct regs *regs, int adjust, char *fmt, ...)
|
|
{
|
|
unsigned off = regs->eip - adjust;
|
|
va_list ap;
|
|
|
|
if ((traceset & (1 << mode)) &&
|
|
(mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) {
|
|
/* 16-bit, seg:off addressing */
|
|
unsigned addr = address(regs, regs->cs, off);
|
|
printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off);
|
|
printf("(%d) ", mode);
|
|
va_start(ap, fmt);
|
|
vprintf(fmt, ap);
|
|
va_end(ap);
|
|
printf("\n");
|
|
}
|
|
if ((traceset & (1 << mode)) &&
|
|
(mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) {
|
|
/* 16-bit, gdt addressing */
|
|
unsigned addr = address(regs, regs->cs, off);
|
|
printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off);
|
|
printf("(%d) ", mode);
|
|
va_start(ap, fmt);
|
|
vprintf(fmt, ap);
|
|
va_end(ap);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
static inline unsigned
|
|
read32(unsigned addr)
|
|
{
|
|
return *(unsigned long *) addr;
|
|
}
|
|
|
|
static inline unsigned
|
|
read16(unsigned addr)
|
|
{
|
|
return *(unsigned short *) addr;
|
|
}
|
|
|
|
static inline unsigned
|
|
read8(unsigned addr)
|
|
{
|
|
return *(unsigned char *) addr;
|
|
}
|
|
|
|
static inline void
|
|
write32(unsigned addr, unsigned value)
|
|
{
|
|
*(unsigned long *) addr = value;
|
|
}
|
|
|
|
static inline void
|
|
write16(unsigned addr, unsigned value)
|
|
{
|
|
*(unsigned short *) addr = value;
|
|
}
|
|
|
|
static inline void
|
|
write8(unsigned addr, unsigned value)
|
|
{
|
|
*(unsigned char *) addr = value;
|
|
}
|
|
|
|
static inline void
|
|
push32(struct regs *regs, unsigned value)
|
|
{
|
|
regs->uesp -= 4;
|
|
write32(address(regs, regs->uss, MASK16(regs->uesp)), value);
|
|
}
|
|
|
|
static inline void
|
|
push16(struct regs *regs, unsigned value)
|
|
{
|
|
regs->uesp -= 2;
|
|
write16(address(regs, regs->uss, MASK16(regs->uesp)), value);
|
|
}
|
|
|
|
static inline unsigned
|
|
pop32(struct regs *regs)
|
|
{
|
|
unsigned value = read32(address(regs, regs->uss, MASK16(regs->uesp)));
|
|
regs->uesp += 4;
|
|
return value;
|
|
}
|
|
|
|
static inline unsigned
|
|
pop16(struct regs *regs)
|
|
{
|
|
unsigned value = read16(address(regs, regs->uss, MASK16(regs->uesp)));
|
|
regs->uesp += 2;
|
|
return value;
|
|
}
|
|
|
|
static inline unsigned
|
|
fetch32(struct regs *regs)
|
|
{
|
|
unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
|
|
|
|
regs->eip += 4;
|
|
return read32(addr);
|
|
}
|
|
|
|
static inline unsigned
|
|
fetch16(struct regs *regs)
|
|
{
|
|
unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
|
|
|
|
regs->eip += 2;
|
|
return read16(addr);
|
|
}
|
|
|
|
static inline unsigned
|
|
fetch8(struct regs *regs)
|
|
{
|
|
unsigned addr = address(regs, regs->cs, MASK16(regs->eip));
|
|
|
|
regs->eip++;
|
|
return read8(addr);
|
|
}
|
|
|
|
unsigned
|
|
getreg(struct regs *regs, int r)
|
|
{
|
|
switch (r & 7) {
|
|
case 0: return regs->eax;
|
|
case 1: return regs->ecx;
|
|
case 2: return regs->edx;
|
|
case 3: return regs->ebx;
|
|
case 4: return regs->esp;
|
|
case 5: return regs->ebp;
|
|
case 6: return regs->esi;
|
|
case 7: return regs->edi;
|
|
}
|
|
return ~0;
|
|
}
|
|
|
|
void
|
|
setreg(struct regs *regs, int r, unsigned v)
|
|
{
|
|
switch (r & 7) {
|
|
case 0: regs->eax = v; break;
|
|
case 1: regs->ecx = v; break;
|
|
case 2: regs->edx = v; break;
|
|
case 3: regs->ebx = v; break;
|
|
case 4: regs->esp = v; break;
|
|
case 5: regs->ebp = v; break;
|
|
case 6: regs->esi = v; break;
|
|
case 7: regs->edi = v; break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Operand (modrm) decode
|
|
*/
|
|
unsigned
|
|
operand(unsigned prefix, struct regs *regs, unsigned modrm)
|
|
{
|
|
int mod, disp = 0, seg;
|
|
|
|
seg = regs->vds;
|
|
if (prefix & SEG_ES)
|
|
seg = regs->ves;
|
|
if (prefix & SEG_DS)
|
|
seg = regs->vds;
|
|
if (prefix & SEG_CS)
|
|
seg = regs->cs;
|
|
if (prefix & SEG_SS)
|
|
seg = regs->uss;
|
|
if (prefix & SEG_FS)
|
|
seg = regs->fs;
|
|
if (prefix & SEG_GS)
|
|
seg = regs->gs;
|
|
|
|
if (prefix & ADDR32) { /* 32-bit addressing */
|
|
switch ((mod = (modrm >> 6) & 3)) {
|
|
case 0:
|
|
switch (modrm & 7) {
|
|
case 0: return address(regs, seg, regs->eax);
|
|
case 1: return address(regs, seg, regs->ecx);
|
|
case 2: return address(regs, seg, regs->edx);
|
|
case 3: return address(regs, seg, regs->ebx);
|
|
case 4: panic("No SIB decode (yet)");
|
|
case 5: return address(regs, seg, fetch32(regs));
|
|
case 6: return address(regs, seg, regs->esi);
|
|
case 7: return address(regs, seg, regs->edi);
|
|
}
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
if ((modrm & 7) != 4) {
|
|
if (mod == 1)
|
|
disp = (char) fetch8(regs);
|
|
else
|
|
disp = (int) fetch32(regs);
|
|
}
|
|
switch (modrm & 7) {
|
|
case 0: return address(regs, seg, regs->eax + disp);
|
|
case 1: return address(regs, seg, regs->ecx + disp);
|
|
case 2: return address(regs, seg, regs->edx + disp);
|
|
case 3: return address(regs, seg, regs->ebx + disp);
|
|
case 4: panic("No SIB decode (yet)");
|
|
case 5: return address(regs, seg, regs->ebp + disp);
|
|
case 6: return address(regs, seg, regs->esi + disp);
|
|
case 7: return address(regs, seg, regs->edi + disp);
|
|
}
|
|
break;
|
|
case 3:
|
|
return getreg(regs, modrm);
|
|
}
|
|
} else { /* 16-bit addressing */
|
|
switch ((mod = (modrm >> 6) & 3)) {
|
|
case 0:
|
|
switch (modrm & 7) {
|
|
case 0: return address(regs, seg, MASK16(regs->ebx) +
|
|
MASK16(regs->esi));
|
|
case 1: return address(regs, seg, MASK16(regs->ebx) +
|
|
MASK16(regs->edi));
|
|
case 2: return address(regs, seg, MASK16(regs->ebp) +
|
|
MASK16(regs->esi));
|
|
case 3: return address(regs, seg, MASK16(regs->ebp) +
|
|
MASK16(regs->edi));
|
|
case 4: return address(regs, seg, MASK16(regs->esi));
|
|
case 5: return address(regs, seg, MASK16(regs->edi));
|
|
case 6: return address(regs, seg, fetch16(regs));
|
|
case 7: return address(regs, seg, MASK16(regs->ebx));
|
|
}
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
if (mod == 1)
|
|
disp = (char) fetch8(regs);
|
|
else
|
|
disp = (int) fetch16(regs);
|
|
switch (modrm & 7) {
|
|
case 0: return address(regs, seg, MASK16(regs->ebx) +
|
|
MASK16(regs->esi) + disp);
|
|
case 1: return address(regs, seg, MASK16(regs->ebx) +
|
|
MASK16(regs->edi) + disp);
|
|
case 2: return address(regs, seg, MASK16(regs->ebp) +
|
|
MASK16(regs->esi) + disp);
|
|
case 3: return address(regs, seg, MASK16(regs->ebp) +
|
|
MASK16(regs->edi) + disp);
|
|
case 4: return address(regs, seg,
|
|
MASK16(regs->esi) + disp);
|
|
case 5: return address(regs, seg,
|
|
MASK16(regs->edi) + disp);
|
|
case 6: return address(regs, seg,
|
|
MASK16(regs->ebp) + disp);
|
|
case 7: return address(regs, seg,
|
|
MASK16(regs->ebx) + disp);
|
|
}
|
|
break;
|
|
case 3:
|
|
return MASK16(getreg(regs, modrm));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Load new IDT
|
|
*/
|
|
int
|
|
lidt(struct regs *regs, unsigned prefix, unsigned modrm)
|
|
{
|
|
unsigned eip = regs->eip - 3;
|
|
unsigned addr = operand(prefix, regs, modrm);
|
|
|
|
oldctx.idtr_limit = ((struct dtr *) addr)->size;
|
|
if ((prefix & DATA32) == 0)
|
|
oldctx.idtr_base = ((struct dtr *) addr)->base & 0xFFFFFF;
|
|
else
|
|
oldctx.idtr_base = ((struct dtr *) addr)->base;
|
|
TRACE((regs, regs->eip - eip, "lidt 0x%x <%d, 0x%x>",
|
|
addr, oldctx.idtr_limit, oldctx.idtr_base));
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Load new GDT
|
|
*/
|
|
int
|
|
lgdt(struct regs *regs, unsigned prefix, unsigned modrm)
|
|
{
|
|
unsigned eip = regs->eip - 3;
|
|
unsigned addr = operand(prefix, regs, modrm);
|
|
|
|
oldctx.gdtr_limit = ((struct dtr *) addr)->size;
|
|
if ((prefix & DATA32) == 0)
|
|
oldctx.gdtr_base = ((struct dtr *) addr)->base & 0xFFFFFF;
|
|
else
|
|
oldctx.gdtr_base = ((struct dtr *) addr)->base;
|
|
TRACE((regs, regs->eip - eip, "lgdt 0x%x <%d, 0x%x>",
|
|
addr, oldctx.gdtr_limit, oldctx.gdtr_base));
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Modify CR0 either through an lmsw instruction.
|
|
*/
|
|
int
|
|
lmsw(struct regs *regs, unsigned prefix, unsigned modrm)
|
|
{
|
|
unsigned eip = regs->eip - 3;
|
|
unsigned ax = operand(prefix, regs, modrm) & 0xF;
|
|
unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax;
|
|
|
|
TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax));
|
|
#ifndef TEST
|
|
oldctx.cr0 = cr0 | CR0_PE | CR0_NE;
|
|
#else
|
|
oldctx.cr0 = cr0 | CR0_PE | CR0_NE | CR0_PG;
|
|
#endif
|
|
if (cr0 & CR0_PE)
|
|
set_mode(regs, VM86_REAL_TO_PROTECTED);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Move to and from a control register.
|
|
*/
|
|
int
|
|
movcr(struct regs *regs, unsigned prefix, unsigned opc)
|
|
{
|
|
unsigned eip = regs->eip - 2;
|
|
unsigned modrm = fetch8(regs);
|
|
unsigned cr = (modrm >> 3) & 7;
|
|
|
|
if ((modrm & 0xC0) != 0xC0) /* only registers */
|
|
return 0;
|
|
|
|
switch (opc) {
|
|
case 0x20: /* mov Rd, Cd */
|
|
TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr));
|
|
switch (cr) {
|
|
case 0:
|
|
#ifndef TEST
|
|
setreg(regs, modrm,
|
|
oldctx.cr0 & ~(CR0_PE | CR0_NE));
|
|
#else
|
|
setreg(regs, modrm,
|
|
oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG));
|
|
#endif
|
|
break;
|
|
case 2:
|
|
setreg(regs, modrm, get_cr2());
|
|
break;
|
|
case 3:
|
|
setreg(regs, modrm, oldctx.cr3);
|
|
break;
|
|
case 4:
|
|
setreg(regs, modrm, oldctx.cr4);
|
|
break;
|
|
}
|
|
break;
|
|
case 0x22: /* mov Cd, Rd */
|
|
TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr));
|
|
switch (cr) {
|
|
case 0:
|
|
oldctx.cr0 = getreg(regs, modrm) | (CR0_PE | CR0_NE);
|
|
#ifdef TEST
|
|
oldctx.cr0 |= CR0_PG;
|
|
#endif
|
|
if (getreg(regs, modrm) & CR0_PE)
|
|
set_mode(regs, VM86_REAL_TO_PROTECTED);
|
|
|
|
break;
|
|
case 3:
|
|
oldctx.cr3 = getreg(regs, modrm);
|
|
break;
|
|
case 4:
|
|
oldctx.cr4 = getreg(regs, modrm);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Emulate a segment load in protected mode
|
|
*/
|
|
int
|
|
load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes)
|
|
{
|
|
unsigned long long entry;
|
|
|
|
/* protected mode: use seg as index into gdt */
|
|
if (sel > oldctx.gdtr_limit)
|
|
return 0;
|
|
|
|
if (sel == 0) {
|
|
arbytes->fields.null_bit = 1;
|
|
return 1;
|
|
}
|
|
|
|
entry = ((unsigned long long *) oldctx.gdtr_base)[sel >> 3];
|
|
|
|
/* Check the P bit fisrt*/
|
|
if (!((entry >> (15+32)) & 0x1) && sel != 0) {
|
|
return 0;
|
|
}
|
|
|
|
*base = (((entry >> (56-24)) & 0xFF000000) |
|
|
((entry >> (32-16)) & 0x00FF0000) |
|
|
((entry >> ( 16)) & 0x0000FFFF));
|
|
*limit = (((entry >> (48-16)) & 0x000F0000) |
|
|
((entry ) & 0x0000FFFF));
|
|
|
|
arbytes->bytes = 0;
|
|
arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */
|
|
arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */
|
|
if (arbytes->fields.s)
|
|
arbytes->fields.seg_type |= 1; /* accessed */
|
|
arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */
|
|
arbytes->fields.p = (entry >> (15+32)) & 0x1; /* P */
|
|
arbytes->fields.avl = (entry >> (20+32)) & 0x1; /* AVL */
|
|
arbytes->fields.default_ops_size = (entry >> (22+32)) & 0x1; /* D */
|
|
|
|
if (entry & (1ULL << (23+32))) { /* G */
|
|
arbytes->fields.g = 1;
|
|
*limit = (*limit << 12) | 0xFFF;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Transition to protected mode
|
|
*/
|
|
void
|
|
protected_mode(struct regs *regs)
|
|
{
|
|
regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM);
|
|
|
|
oldctx.eip = regs->eip;
|
|
oldctx.esp = regs->uesp;
|
|
oldctx.eflags = regs->eflags;
|
|
|
|
/* reload all segment registers */
|
|
if (!load_seg(regs->cs, &oldctx.cs_base,
|
|
&oldctx.cs_limit, &oldctx.cs_arbytes))
|
|
panic("Invalid %%cs=0x%x for protected mode\n", regs->cs);
|
|
oldctx.cs_sel = regs->cs;
|
|
|
|
if (load_seg(regs->ves, &oldctx.es_base,
|
|
&oldctx.es_limit, &oldctx.es_arbytes))
|
|
oldctx.es_sel = regs->ves;
|
|
else {
|
|
load_seg(0, &oldctx.es_base,&oldctx.es_limit, &oldctx.es_arbytes);
|
|
oldctx.es_sel = 0;
|
|
}
|
|
|
|
if (load_seg(regs->uss, &oldctx.ss_base,
|
|
&oldctx.ss_limit, &oldctx.ss_arbytes))
|
|
oldctx.ss_sel = regs->uss;
|
|
else {
|
|
load_seg(0, &oldctx.ss_base, &oldctx.ss_limit, &oldctx.ss_arbytes);
|
|
oldctx.ss_sel = 0;
|
|
}
|
|
|
|
if (load_seg(regs->vds, &oldctx.ds_base,
|
|
&oldctx.ds_limit, &oldctx.ds_arbytes))
|
|
oldctx.ds_sel = regs->vds;
|
|
else {
|
|
load_seg(0, &oldctx.ds_base, &oldctx.ds_limit, &oldctx.ds_arbytes);
|
|
oldctx.ds_sel = 0;
|
|
}
|
|
|
|
if (load_seg(regs->vfs, &oldctx.fs_base,
|
|
&oldctx.fs_limit, &oldctx.fs_arbytes))
|
|
oldctx.fs_sel = regs->vfs;
|
|
else {
|
|
load_seg(0, &oldctx.fs_base, &oldctx.fs_limit, &oldctx.fs_arbytes);
|
|
oldctx.fs_sel = 0;
|
|
}
|
|
|
|
if (load_seg(regs->vgs, &oldctx.gs_base,
|
|
&oldctx.gs_limit, &oldctx.gs_arbytes))
|
|
oldctx.gs_sel = regs->vgs;
|
|
else {
|
|
load_seg(0, &oldctx.gs_base, &oldctx.gs_limit, &oldctx.gs_arbytes);
|
|
oldctx.gs_sel = 0;
|
|
}
|
|
|
|
/* initialize jump environment to warp back to protected mode */
|
|
regs->cs = CODE_SELECTOR;
|
|
regs->ds = DATA_SELECTOR;
|
|
regs->es = DATA_SELECTOR;
|
|
regs->fs = DATA_SELECTOR;
|
|
regs->gs = DATA_SELECTOR;
|
|
regs->eip = (unsigned) &switch_to_protected_mode;
|
|
|
|
/* this should get us into 32-bit mode */
|
|
}
|
|
|
|
/*
|
|
* Start real-mode emulation
|
|
*/
|
|
void
|
|
real_mode(struct regs *regs)
|
|
{
|
|
regs->eflags |= EFLAGS_VM | 0x02;
|
|
regs->ds = DATA_SELECTOR;
|
|
regs->es = DATA_SELECTOR;
|
|
regs->fs = DATA_SELECTOR;
|
|
regs->gs = DATA_SELECTOR;
|
|
|
|
/*
|
|
* When we transition from protected to real-mode and we
|
|
* have not reloaded the segment descriptors yet, they are
|
|
* interpreted as if they were in protect mode.
|
|
* We emulate this behavior by assuming that these memory
|
|
* reference are below 1MB and set %ss, %ds, %es accordingly.
|
|
*/
|
|
if (regs->uss != 0) {
|
|
if (regs->uss >= HIGHMEM)
|
|
panic("%%ss 0x%lx higher than 1MB", regs->uss);
|
|
regs->uss = address(regs, regs->uss, 0) >> 4;
|
|
}
|
|
if (regs->vds != 0) {
|
|
if (regs->vds >= HIGHMEM)
|
|
panic("%%ds 0x%lx higher than 1MB", regs->vds);
|
|
regs->vds = address(regs, regs->vds, 0) >> 4;
|
|
}
|
|
if (regs->ves != 0) {
|
|
if (regs->ves >= HIGHMEM)
|
|
panic("%%es 0x%lx higher than 1MB", regs->ves);
|
|
regs->ves = address(regs, regs->ves, 0) >> 4;
|
|
}
|
|
|
|
/* this should get us into 16-bit mode */
|
|
}
|
|
|
|
/*
|
|
* This is the smarts of the emulator and handles the mode transitions. The
|
|
* emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode, Just
|
|
* handle those instructions that are not supported under VM8086.
|
|
* 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In this
|
|
* we single step through the instructions until we reload the new %cs (some
|
|
* OSes do a lot of computations before reloading %cs). 2) VM86_PROTECTED_TO_REAL
|
|
* when we are going from protected to real mode. In this case we emulate the
|
|
* instructions by hand. Finally, 4) VM86_PROTECTED when we transitioned to
|
|
* protected mode and we should abandon the emulator. No instructions are
|
|
* emulated when in VM86_PROTECTED mode.
|
|
*/
|
|
void
|
|
set_mode(struct regs *regs, enum vm86_mode newmode)
|
|
{
|
|
switch (newmode) {
|
|
case VM86_REAL:
|
|
if (mode == VM86_PROTECTED_TO_REAL) {
|
|
real_mode(regs);
|
|
break;
|
|
} else if (mode == VM86_REAL) {
|
|
break;
|
|
} else
|
|
panic("unexpected real mode transition");
|
|
break;
|
|
|
|
case VM86_REAL_TO_PROTECTED:
|
|
if (mode == VM86_REAL) {
|
|
regs->eflags |= EFLAGS_TF;
|
|
break;
|
|
} else if (mode == VM86_REAL_TO_PROTECTED) {
|
|
break;
|
|
} else
|
|
panic("unexpected real-to-protected mode transition");
|
|
break;
|
|
|
|
case VM86_PROTECTED_TO_REAL:
|
|
if (mode == VM86_PROTECTED)
|
|
break;
|
|
else
|
|
panic("unexpected protected-to-real mode transition");
|
|
|
|
case VM86_PROTECTED:
|
|
if (mode == VM86_REAL_TO_PROTECTED) {
|
|
protected_mode(regs);
|
|
break;
|
|
} else
|
|
panic("unexpected protected mode transition");
|
|
break;
|
|
}
|
|
|
|
mode = newmode;
|
|
TRACE((regs, 0, states[mode]));
|
|
}
|
|
|
|
void
|
|
jmpl(struct regs *regs, int prefix)
|
|
{
|
|
unsigned n = regs->eip;
|
|
unsigned cs, eip;
|
|
|
|
if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */
|
|
eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs);
|
|
cs = fetch16(regs);
|
|
|
|
TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
|
|
|
|
regs->cs = cs;
|
|
regs->eip = eip;
|
|
set_mode(regs, VM86_PROTECTED);
|
|
} else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */
|
|
eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs);
|
|
cs = fetch16(regs);
|
|
|
|
TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));
|
|
|
|
regs->cs = cs;
|
|
regs->eip = eip;
|
|
set_mode(regs, VM86_REAL);
|
|
} else
|
|
panic("jmpl");
|
|
}
|
|
|
|
void
|
|
retl(struct regs *regs, int prefix)
|
|
{
|
|
unsigned cs, eip;
|
|
|
|
if (prefix & DATA32) {
|
|
eip = pop32(regs);
|
|
cs = MASK16(pop32(regs));
|
|
} else {
|
|
eip = pop16(regs);
|
|
cs = pop16(regs);
|
|
}
|
|
|
|
TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip));
|
|
|
|
if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */
|
|
regs->cs = cs;
|
|
regs->eip = eip;
|
|
set_mode(regs, VM86_PROTECTED);
|
|
} else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */
|
|
regs->cs = cs;
|
|
regs->eip = eip;
|
|
set_mode(regs, VM86_REAL);
|
|
} else
|
|
panic("retl");
|
|
}
|
|
|
|
void
|
|
interrupt(struct regs *regs, int n)
|
|
{
|
|
TRACE((regs, 0, "external interrupt %d", n));
|
|
push16(regs, regs->eflags);
|
|
push16(regs, regs->cs);
|
|
push16(regs, regs->eip);
|
|
regs->eflags &= ~EFLAGS_IF;
|
|
regs->eip = read16(address(regs, 0, n * 4));
|
|
regs->cs = read16(address(regs, 0, n * 4 + 2));
|
|
}
|
|
|
|
/*
|
|
* Most port I/O operations are passed unmodified. We do have to be
|
|
* careful and make sure the emulated program isn't remapping the
|
|
* interrupt vectors. The following simple state machine catches
|
|
* these attempts and rewrites them.
|
|
*/
|
|
int
|
|
outbyte(struct regs *regs, unsigned prefix, unsigned opc)
|
|
{
|
|
static char icw2[2] = { 0 };
|
|
int al, port;
|
|
|
|
switch (opc) {
|
|
case 0xE6: /* outb port, al */
|
|
port = fetch8(regs);
|
|
break;
|
|
case 0xEE: /* outb (%dx), al */
|
|
port = MASK16(regs->edx);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
al = regs->eax & 0xFF;
|
|
|
|
switch (port) {
|
|
case PIC_MASTER + PIC_CMD:
|
|
if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */
|
|
icw2[0] = 1;
|
|
break;
|
|
case PIC_MASTER + PIC_IMR:
|
|
if (icw2[0]) {
|
|
icw2[0] = 0;
|
|
printf("Remapping master: ICW2 0x%x -> 0x%x\n",
|
|
al, NR_EXCEPTION_HANDLER);
|
|
al = NR_EXCEPTION_HANDLER;
|
|
}
|
|
break;
|
|
|
|
case PIC_SLAVE + PIC_CMD:
|
|
if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */
|
|
icw2[1] = 1;
|
|
break;
|
|
case PIC_SLAVE + PIC_IMR:
|
|
if (icw2[1]) {
|
|
icw2[1] = 0;
|
|
printf("Remapping slave: ICW2 0x%x -> 0x%x\n",
|
|
al, NR_EXCEPTION_HANDLER+8);
|
|
al = NR_EXCEPTION_HANDLER+8;
|
|
}
|
|
break;
|
|
}
|
|
|
|
outb(port, al);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
inbyte(struct regs *regs, unsigned prefix, unsigned opc)
|
|
{
|
|
int port;
|
|
|
|
switch (opc) {
|
|
case 0xE4: /* inb al, port */
|
|
port = fetch8(regs);
|
|
break;
|
|
case 0xEC: /* inb al, (%dx) */
|
|
port = MASK16(regs->edx);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
regs->eax = (regs->eax & ~0xFF) | inb(port);
|
|
return 1;
|
|
}
|
|
|
|
enum { OPC_INVALID, OPC_EMULATED };
|
|
|
|
/*
|
|
* Emulate a single instruction, including all its prefixes. We only implement
|
|
* a small subset of the opcodes, and not all opcodes are implemented for each
|
|
* of the four modes we can operate in.
|
|
*/
|
|
int
|
|
opcode(struct regs *regs)
|
|
{
|
|
unsigned eip = regs->eip;
|
|
unsigned opc, modrm, disp;
|
|
unsigned prefix = 0;
|
|
|
|
for (;;) {
|
|
switch ((opc = fetch8(regs))) {
|
|
case 0x0F: /* two byte opcode */
|
|
if (mode == VM86_PROTECTED)
|
|
goto invalid;
|
|
switch ((opc = fetch8(regs))) {
|
|
case 0x01:
|
|
switch (((modrm = fetch8(regs)) >> 3) & 7) {
|
|
case 0: /* sgdt */
|
|
case 1: /* sidt */
|
|
goto invalid;
|
|
case 2: /* lgdt */
|
|
if (!lgdt(regs, prefix, modrm))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
case 3: /* lidt */
|
|
if (!lidt(regs, prefix, modrm))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
case 4: /* smsw */
|
|
goto invalid;
|
|
case 5:
|
|
goto invalid;
|
|
case 6: /* lmsw */
|
|
if (!lmsw(regs, prefix, modrm))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
case 7: /* invlpg */
|
|
goto invalid;
|
|
}
|
|
break;
|
|
case 0x09: /* wbinvd */
|
|
return OPC_EMULATED;
|
|
case 0x20: /* mov Rd, Cd (1h) */
|
|
case 0x22:
|
|
if (!movcr(regs, prefix, opc))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
default:
|
|
goto invalid;
|
|
}
|
|
goto invalid;
|
|
|
|
case 0x26:
|
|
TRACE((regs, regs->eip - eip, "%%es:"));
|
|
prefix |= SEG_ES;
|
|
continue;
|
|
|
|
case 0x2E:
|
|
TRACE((regs, regs->eip - eip, "%%cs:"));
|
|
prefix |= SEG_CS;
|
|
continue;
|
|
|
|
case 0x36:
|
|
TRACE((regs, regs->eip - eip, "%%ss:"));
|
|
prefix |= SEG_SS;
|
|
continue;
|
|
|
|
case 0x3E:
|
|
TRACE((regs, regs->eip - eip, "%%ds:"));
|
|
prefix |= SEG_DS;
|
|
continue;
|
|
|
|
case 0x64:
|
|
TRACE((regs, regs->eip - eip, "%%fs:"));
|
|
prefix |= SEG_FS;
|
|
continue;
|
|
|
|
case 0x65:
|
|
TRACE((regs, regs->eip - eip, "%%gs:"));
|
|
prefix |= SEG_GS;
|
|
continue;
|
|
|
|
case 0x66:
|
|
TRACE((regs, regs->eip - eip, "data32"));
|
|
prefix |= DATA32;
|
|
continue;
|
|
|
|
case 0x67:
|
|
TRACE((regs, regs->eip - eip, "addr32"));
|
|
prefix |= ADDR32;
|
|
continue;
|
|
|
|
case 0x90: /* nop */
|
|
TRACE((regs, regs->eip - eip, "nop"));
|
|
return OPC_EMULATED;
|
|
|
|
case 0x9C: /* pushf */
|
|
TRACE((regs, regs->eip - eip, "pushf"));
|
|
if (prefix & DATA32)
|
|
push32(regs, regs->eflags & ~EFLAGS_VM);
|
|
else
|
|
push16(regs, regs->eflags & ~EFLAGS_VM);
|
|
return OPC_EMULATED;
|
|
|
|
case 0x9D: /* popf */
|
|
TRACE((regs, regs->eip - eip, "popf"));
|
|
if (prefix & DATA32)
|
|
regs->eflags = pop32(regs);
|
|
else
|
|
regs->eflags = (regs->eflags & 0xFFFF0000L) |
|
|
pop16(regs);
|
|
regs->eflags |= EFLAGS_VM;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xCB: /* retl */
|
|
if ((mode == VM86_REAL_TO_PROTECTED) ||
|
|
(mode == VM86_PROTECTED_TO_REAL)) {
|
|
retl(regs, prefix);
|
|
return OPC_EMULATED;
|
|
}
|
|
goto invalid;
|
|
|
|
case 0xCD: /* int $n */
|
|
TRACE((regs, regs->eip - eip, "int"));
|
|
interrupt(regs, fetch8(regs));
|
|
return OPC_EMULATED;
|
|
|
|
case 0xCF: /* iret */
|
|
if (prefix & DATA32) {
|
|
TRACE((regs, regs->eip - eip, "data32 iretd"));
|
|
regs->eip = pop32(regs);
|
|
regs->cs = pop32(regs);
|
|
regs->eflags = pop32(regs);
|
|
} else {
|
|
TRACE((regs, regs->eip - eip, "iret"));
|
|
regs->eip = pop16(regs);
|
|
regs->cs = pop16(regs);
|
|
regs->eflags = (regs->eflags & 0xFFFF0000L) |
|
|
pop16(regs);
|
|
}
|
|
return OPC_EMULATED;
|
|
|
|
case 0xE4: /* inb al, port */
|
|
if (!inbyte(regs, prefix, opc))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xE6: /* outb port, al */
|
|
if (!outbyte(regs, prefix, opc))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xEA: /* jmpl */
|
|
if ((mode == VM86_REAL_TO_PROTECTED) ||
|
|
(mode == VM86_PROTECTED_TO_REAL)) {
|
|
jmpl(regs, prefix);
|
|
return OPC_EMULATED;
|
|
}
|
|
goto invalid;
|
|
|
|
case 0xEB: /* short jump */
|
|
if ((mode == VM86_REAL_TO_PROTECTED) ||
|
|
(mode == VM86_PROTECTED_TO_REAL)) {
|
|
disp = (char) fetch8(regs);
|
|
TRACE((regs, 2, "jmp 0x%x", regs->eip + disp));
|
|
regs->eip += disp;
|
|
return OPC_EMULATED;
|
|
}
|
|
goto invalid;
|
|
|
|
case 0xEC: /* inb al, (%dx) */
|
|
if (!inbyte(regs, prefix, opc))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xEE: /* outb (%dx), al */
|
|
if (!outbyte(regs, prefix, opc))
|
|
goto invalid;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xF0: /* lock */
|
|
TRACE((regs, regs->eip - eip, "lock"));
|
|
continue;
|
|
|
|
case 0xFA: /* cli */
|
|
TRACE((regs, regs->eip - eip, "cli"));
|
|
regs->eflags &= ~EFLAGS_IF;
|
|
return OPC_EMULATED;
|
|
|
|
case 0xFB: /* sti */
|
|
TRACE((regs, regs->eip - eip, "sti"));
|
|
regs->eflags |= EFLAGS_IF;
|
|
return OPC_EMULATED;
|
|
|
|
default:
|
|
goto invalid;
|
|
}
|
|
}
|
|
|
|
invalid:
|
|
regs->eip = eip;
|
|
return OPC_INVALID;
|
|
}
|
|
|
|
void
|
|
emulate(struct regs *regs)
|
|
{
|
|
unsigned flteip;
|
|
int nemul = 0;
|
|
|
|
/* emulate as many instructions as possible */
|
|
while (opcode(regs) != OPC_INVALID)
|
|
nemul++;
|
|
|
|
/* detect the case where we are not making progress */
|
|
if (nemul == 0 && prev_eip == regs->eip) {
|
|
flteip = address(regs, MASK16(regs->cs), regs->eip);
|
|
panic("Unknown opcode at %04x:%04x=0x%x",
|
|
MASK16(regs->cs), regs->eip, flteip);
|
|
} else
|
|
prev_eip = regs->eip;
|
|
}
|
|
|
|
void
|
|
trap(int trapno, int errno, struct regs *regs)
|
|
{
|
|
/* emulate device interrupts */
|
|
if (trapno >= NR_EXCEPTION_HANDLER) {
|
|
int irq = trapno - NR_EXCEPTION_HANDLER;
|
|
if (irq < 8)
|
|
interrupt(regs, irq + 8);
|
|
else
|
|
interrupt(regs, 0x70 + (irq - 8));
|
|
return;
|
|
}
|
|
|
|
switch (trapno) {
|
|
case 1: /* Debug */
|
|
if (regs->eflags & EFLAGS_VM) {
|
|
/* emulate any 8086 instructions */
|
|
if (mode != VM86_REAL_TO_PROTECTED)
|
|
panic("not in real-to-protected mode");
|
|
emulate(regs);
|
|
return;
|
|
}
|
|
goto invalid;
|
|
|
|
case 13: /* GPF */
|
|
if (regs->eflags & EFLAGS_VM) {
|
|
/* emulate any 8086 instructions */
|
|
if (mode == VM86_PROTECTED)
|
|
panic("unexpected protected mode");
|
|
emulate(regs);
|
|
return;
|
|
}
|
|
goto invalid;
|
|
|
|
default:
|
|
invalid:
|
|
printf("Trap (0x%x) while in %s mode\n",
|
|
trapno, regs->eflags & EFLAGS_VM ? "real" : "protected");
|
|
if (trapno == 14)
|
|
printf("Page fault address 0x%x\n", get_cr2());
|
|
dump_regs(regs);
|
|
halt();
|
|
}
|
|
}
|
|
|