SVM support
PATCH 1/1 SVM support
Hi,
after a lot of struggling I finally got everything working smoothly (special thanks to Fabrice and Avi), so I believe this patch is ready to be taken upstream.CC_DST was never a problem, as everything I did in the eflags area already worked. I managed to clobber the segment attributes though, so that was the real problem here.
Nevertheless there is still a lot of functionality missing, whereas none of that is used in kvm by now, so that works already.
So there are still missing parts that I will list here:
- NPT support
- Everything related to device virtualisation
- The "Secure" part of the extension (would need TPM emulation for that)
- Debugging support (maybe it does work, I actually have never tried to debug a kvm virtualised machine)
- TSC_OFFSET
- ASID support
- Sanity checks
- Task switch and Ferr_Freeze Intercepts
- VMMCALL
- SMM support
- SVM-Lock
Most of these features are optional or not used by any software I know of today, so it does not hurt (yet).
I'm really sorry that this patch is so big. I already tried to make it as small as I could, but this feature is heavy.
In case it is too big, I can try to split it up into several patches.
Thanks a lot,
Alexander Graf
target-i386/helper2.c +11 -2
@@ -27,6 +27,7 @@#include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU
@@ -111,6 +112,7 @@ CPUX86State *cpu_x86_init(void)CPUID_CX8 |CPUID_PGE |CPUID_CMOV | CPUID_PAT); env->pat =0x0007040600070406ULL ; + env->cpuid_ext3_features =CPUID_EXT3_SVM ; env->cpuid_ext_features =CPUID_EXT_SSE3 ; env->cpuid_features |=CPUID_FXSR |CPUID_MMX |CPUID_SSE |CPUID_SSE2 |CPUID_PAE |CPUID_SEP ; env->cpuid_features |=CPUID_APIC ;
@@ -131,7 +133,7 @@ CPUX86State *cpu_x86_init(void)/* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features &0x0183F3FF ); env->cpuid_ext2_features |=CPUID_EXT2_LM |CPUID_EXT2_SYSCALL |CPUID_EXT2_NX ; - env->cpuid_xlevel =0x80000008 ; + env->cpuid_xlevel =0x8000000a ;/* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |=CPUID_MTRR |CPUID_CLFLUSH |CPUID_MCA ;
@@ -160,6 +162,7 @@ void cpu_reset(CPUX86State *env)#ifdef CONFIG_SOFTMMU env->hflags |=HF_SOFTMMU_MASK ;#endif + env->hflags |=HF_GIF_MASK ;cpu_x86_update_cr0 (env,0x60000010 ); env->a20_mask =0xffffffff ;
@@ -863,7 +866,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State do_fault_protect: error_code =PG_ERROR_P_MASK ; do_fault: - env->cr[2 ] = addr; error_code |= (is_write <<PG_ERROR_W_BIT );if (is_user) error_code |=PG_ERROR_U_MASK ;
@@ -871,8 +873,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |=PG_ERROR_I_D_MASK ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + }else { + env->cr[2 ] = addr; + } env->error_code = error_code; env->exception_index =EXCP0E_PAGE ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE ))// the VMM will handle this +return 2 ;return 1 ; }
target-i386/translate.c +178 -7
433 lines not on this page · raw message
target-i386/cpu.h +21 -0
@@ -46,6 +46,8 @@#include "softfloat.h" +#include "svm.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU ) && !defined(__APPLE__)#define USE_CODE_COPY #endif
@@ -84,6 +86,7 @@#define DESC_AVL_MASK (1 << 20)#define DESC_P_MASK (1 << 15)#define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT)#define DESC_S_MASK (1 << 12)#define DESC_TYPE_SHIFT 8#define DESC_A_MASK (1 << 8)
@@ -149,6 +152,8 @@#define HF_VM_SHIFT 17/* must be same as eflags */ #define HF_HALTED_SHIFT 18/* CPU halted */ #define HF_SMM_SHIFT 19/* CPU in SMM mode */ +#define HF_GIF_SHIFT 20/* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21/* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT)#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +171,8 @@#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)#define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT)#define CR0_PE_MASK (1 << 0)#define CR0_MP_MASK (1 << 1)
@@ -249,6 +256,8 @@#define MSR_GSBASE 0xc0000101#define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 +/* cpuid_features bits */ #define CPUID_FP87 (1 << 0)#define CPUID_VME (1 << 1)
@@ -283,6 +292,8 @@#define CPUID_EXT2_FFXSR (1 << 25)#define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) +#define EXCP00_DIVZ 0#define EXCP01_SSTP 1#define EXCP02_NMI 2
@@ -489,6 +500,16 @@ typedef struct CPUX86State {uint32_t sysenter_eip;uint64_t efer;uint64_t star; + +target_phys_addr_t vm_hsave; +target_phys_addr_t vm_vmcb; +uint64_t intercept; +uint16_t intercept_cr_read; +uint16_t intercept_cr_write; +uint16_t intercept_dr_read; +uint16_t intercept_dr_write; +uint32_t intercept_exceptions; +#ifdef TARGET_X86_64 target_ulong lstar;target_ulong cstar;
target-i386/op.c +74 -0
83 lines not on this page · raw message
target-i386/helper.c +472 -2
528 lines not on this page · raw message
target-i386/svm.h new file +373 -0
373 lines not on this page · raw message
cpu-exec.c +35 -3
@@ -104,6 +104,9 @@ static TranslationBlock *tb_find_slow(taif (tb->pc == pc && tb->page_addr[0 ] == phys_page1 && tb->cs_base == cs_base && +#if defined(TARGET_I386) + tb->intercept == env->intercept && +#endif tb->flags == flags) {/* check next page if needed */ if (tb->page_addr[1 ] !=-1 ) {
@@ -132,6 +135,9 @@ static TranslationBlock *tb_find_slow(ta tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; +#if defined(TARGET_I386 ) + tb->intercept = env->intercept; +#endif tb->flags = flags;cpu_gen_code (env, tb,CODE_GEN_MAX_SIZE , &code_gen_size); code_gen_ptr = (void *)(((unsigned long )code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 ));
@@ -214,7 +220,11 @@ static inline TranslationBlock *tb_find_#endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func (pc)];if (__builtin_expect (!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags,0 )) { + tb->flags != flags +#if defined(TARGET_I386) + || tb->intercept != env->intercept +#endif + , 0)) { tb =tb_find_slow (pc, cs_base, flags);/* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */
@@ -373,7 +383,11 @@ int cpu_exec(CPUState *env1) tmp_T0 =T0 ;#endif interrupt_request = env->interrupt_request; -if (__builtin_expect (interrupt_request,0 )) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386 ) + && env->hflags & HF_GIF_MASK +#endif + ) {if (interrupt_request &CPU_INTERRUPT_DEBUG ) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG ; env->exception_index =EXCP_DEBUG ;
@@ -391,6 +405,7 @@ int cpu_exec(CPUState *env1)#if defined(TARGET_I386 )if ((interrupt_request &CPU_INTERRUPT_SMI ) && !(env->hflags &HF_SMM_MASK )) { +svm_check_intercept (SVM_EXIT_SMI ); env->interrupt_request &= ~CPU_INTERRUPT_SMI ;do_smm_enter ();#if defined(__sparc__) && !defined(HOST_SOLARIS )
@@ -399,9 +414,10 @@ int cpu_exec(CPUState *env1)T0 =0 ;#endif }else if ((interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ) && + (env->eflags &IF_MASK || env->hflags &HF_HIF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) {int intno; +svm_check_intercept (SVM_EXIT_INTR ); env->interrupt_request &= ~CPU_INTERRUPT_HARD ; intno =cpu_get_pic_interrupt (env);if (loglevel &CPU_LOG_TB_IN_ASM ) {
@@ -415,6 +431,22 @@ int cpu_exec(CPUState *env1)#else T0 =0 ;#endif + }else if ((interrupt_request &CPU_INTERRUPT_VIRQ ) && + (env->eflags &IF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) { +int intno; +// FIXME: this should respect TPR +svm_check_intercept (SVM_EXIT_VINTR ); + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); +if (loglevel &CPU_LOG_TB_IN_ASM ) +fprintf (logfile,"Servicing virtual hardware INT=0x%02x\n" , intno); +do_interrupt (intno,0 ,0 ,-1 ,1 ); +#if defined(__sparc__) && !defined(HOST_SOLARIS ) + tmp_T0 =0 ; +#else +T0 =0 ; +#endif }#elif defined(TARGET_PPC)#if 0
target-i386/exec.h +10 -0
@@ -501,6 +501,15 @@ void update_fp_status(void);void helper_hlt (void );void helper_monitor (void );void helper_mwait (void ); +void helper_vmrun (target_ulong addr); +void helper_vmmcall (void ); +void helper_vmload (target_ulong addr); +void helper_vmsave (target_ulong addr); +void helper_stgi (void ); +void helper_clgi (void ); +void helper_skinit (void ); +void helper_invlpga (void ); +void vmexit (uint64_t exit_code,uint64_t exit_info_1);extern const uint8_t parity_table[256 ];extern const uint8_t rclw_table[32 ];
@@ -588,3 +597,4 @@ static inline int cpu_halted(CPUState *e }return EXCP_HALTED ; } +
exec.c +5 -0
@@ -1281,6 +1281,11 @@ void cpu_abort(CPUState *env, const charvfprintf (stderr, fmt, ap);fprintf (stderr,"\n" );#ifdef TARGET_I386 +if (env->intercept &INTERCEPT_SVM_MASK ) { +// most probably the virtual machine should not +// be shut down but rather caught by the VMM +vmexit (SVM_EXIT_SHUTDOWN ,0 ); + }cpu_dump_state (env, stderr, fprintf,X86_DUMP_FPU |X86_DUMP_CCOP );#else cpu_dump_state (env, stderr, fprintf,0 );
exec-all.h +1 -0
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */
cpu-all.h +1 -0
@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void cpu_reset_interrupt (CPUState *env,int mask);
Quoted 11 lines · Alexander Graf
Hi,
after a lot of struggling I finally got everything working smoothly (special thanks to Fabrice and Avi), so I believe this patch is ready to be taken upstream.
CC_DSTwas never a problem, as everything I did in the eflags area already worked. I managed to clobber the segment attributes though, so that was the real problem here.
Nevertheless there is still a lot of functionality missing, whereas none of that is used in kvm by now, so that works already.
Quoted 5 lines
So there are still missing parts that I will list here:
- NPT support
- Everything related to device virtualisation
- The "Secure" part of the extension (would need TPM emulation for that)
I backported Xen's TPM emulation to Qemu for exactly that purpose. I also started to implement skinit, but did not had the time to finish that work, yet. Please note that this patch requires a two line patch to the tpm-emulator to understand the localities.
Bernhard Kauer
Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.191
Makefile.target +1 -0
@@ -429,6 +429,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmware_vga.o +VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), ppc)
Index: hw/pc.c
===================================================================
RCS file: /sources/qemu/qemu/hw/pc.c,v
retrieving revision 1.81
pc.c +3 -0
@@ -914,6 +917,9 @@if (i440fx_state) {i440fx_init_memory_mappings (i440fx_state); } + +tpm_tis_init (); +#if 0 /* ??? Need to figure out some way for the user to specify SCSI devices. */
tpm_tis.c new file +890 -0
890 lines not on this page · raw message
Just after I sent the patch I found a problem with the interrupt handling when a lot of interrupts occur. This patch fixes that and removes a small chunk of debugging code I forgot to remove.
Thanks,
Alexander Graf
target-i386/helper2.c +11 -2
@@ -27,6 +27,7 @@#include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU
@@ -111,6 +112,7 @@ CPUX86State *cpu_x86_init(void)CPUID_CX8 |CPUID_PGE |CPUID_CMOV | CPUID_PAT); env->pat =0x0007040600070406ULL ; + env->cpuid_ext3_features =CPUID_EXT3_SVM ; env->cpuid_ext_features =CPUID_EXT_SSE3 ; env->cpuid_features |=CPUID_FXSR |CPUID_MMX |CPUID_SSE |CPUID_SSE2 |CPUID_PAE |CPUID_SEP ; env->cpuid_features |=CPUID_APIC ;
@@ -131,7 +133,7 @@ CPUX86State *cpu_x86_init(void)/* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features &0x0183F3FF ); env->cpuid_ext2_features |=CPUID_EXT2_LM |CPUID_EXT2_SYSCALL |CPUID_EXT2_NX ; - env->cpuid_xlevel =0x80000008 ; + env->cpuid_xlevel =0x8000000a ;/* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |=CPUID_MTRR |CPUID_CLFLUSH |CPUID_MCA ;
@@ -160,6 +162,7 @@ void cpu_reset(CPUX86State *env)#ifdef CONFIG_SOFTMMU env->hflags |=HF_SOFTMMU_MASK ;#endif + env->hflags |=HF_GIF_MASK ;cpu_x86_update_cr0 (env,0x60000010 ); env->a20_mask =0xffffffff ;
@@ -863,7 +866,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State do_fault_protect: error_code =PG_ERROR_P_MASK ; do_fault: - env->cr[2 ] = addr; error_code |= (is_write <<PG_ERROR_W_BIT );if (is_user) error_code |=PG_ERROR_U_MASK ;
@@ -871,8 +873,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |=PG_ERROR_I_D_MASK ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + }else { + env->cr[2 ] = addr; + } env->error_code = error_code; env->exception_index =EXCP0E_PAGE ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE ))// the VMM will handle this +return 2 ;return 1 ; }
target-i386/translate.c +179 -7
440 lines not on this page · raw message
target-i386/cpu.h +21 -0
@@ -46,6 +46,8 @@#include "softfloat.h" +#include "svm.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU ) && !defined(__APPLE__)#define USE_CODE_COPY #endif
@@ -84,6 +86,7 @@#define DESC_AVL_MASK (1 << 20)#define DESC_P_MASK (1 << 15)#define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT)#define DESC_S_MASK (1 << 12)#define DESC_TYPE_SHIFT 8#define DESC_A_MASK (1 << 8)
@@ -149,6 +152,8 @@#define HF_VM_SHIFT 17/* must be same as eflags */ #define HF_HALTED_SHIFT 18/* CPU halted */ #define HF_SMM_SHIFT 19/* CPU in SMM mode */ +#define HF_GIF_SHIFT 20/* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21/* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT)#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +171,8 @@#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)#define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT)#define CR0_PE_MASK (1 << 0)#define CR0_MP_MASK (1 << 1)
@@ -249,6 +256,8 @@#define MSR_GSBASE 0xc0000101#define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 +/* cpuid_features bits */ #define CPUID_FP87 (1 << 0)#define CPUID_VME (1 << 1)
@@ -283,6 +292,8 @@#define CPUID_EXT2_FFXSR (1 << 25)#define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) +#define EXCP00_DIVZ 0#define EXCP01_SSTP 1#define EXCP02_NMI 2
@@ -489,6 +500,16 @@ typedef struct CPUX86State {uint32_t sysenter_eip;uint64_t efer;uint64_t star; + +target_phys_addr_t vm_hsave; +target_phys_addr_t vm_vmcb; +uint64_t intercept; +uint16_t intercept_cr_read; +uint16_t intercept_cr_write; +uint16_t intercept_dr_read; +uint16_t intercept_dr_write; +uint32_t intercept_exceptions; +#ifdef TARGET_X86_64 target_ulong lstar;target_ulong cstar;
target-i386/op.c +74 -0
83 lines not on this page · raw message
target-i386/helper.c +472 -2
528 lines not on this page · raw message
target-i386/svm.h new file +357 -0
357 lines not on this page · raw message
cpu-exec.c +34 -3
@@ -104,6 +104,9 @@ static TranslationBlock *tb_find_slow(taif (tb->pc == pc && tb->page_addr[0 ] == phys_page1 && tb->cs_base == cs_base && +#if defined(TARGET_I386) + tb->intercept == env->intercept && +#endif tb->flags == flags) {/* check next page if needed */ if (tb->page_addr[1 ] !=-1 ) {
@@ -132,6 +135,9 @@ static TranslationBlock *tb_find_slow(ta tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; +#if defined(TARGET_I386 ) + tb->intercept = env->intercept; +#endif tb->flags = flags;cpu_gen_code (env, tb,CODE_GEN_MAX_SIZE , &code_gen_size); code_gen_ptr = (void *)(((unsigned long )code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 ));
@@ -214,7 +220,11 @@ static inline TranslationBlock *tb_find_#endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func (pc)];if (__builtin_expect (!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags,0 )) { + tb->flags != flags +#if defined(TARGET_I386) + || tb->intercept != env->intercept +#endif + , 0)) { tb =tb_find_slow (pc, cs_base, flags);/* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */
@@ -373,7 +383,11 @@ int cpu_exec(CPUState *env1) tmp_T0 =T0 ;#endif interrupt_request = env->interrupt_request; -if (__builtin_expect (interrupt_request,0 )) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386 ) + && env->hflags & HF_GIF_MASK +#endif + ) {if (interrupt_request &CPU_INTERRUPT_DEBUG ) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG ; env->exception_index =EXCP_DEBUG ;
@@ -391,6 +405,7 @@ int cpu_exec(CPUState *env1)#if defined(TARGET_I386 )if ((interrupt_request &CPU_INTERRUPT_SMI ) && !(env->hflags &HF_SMM_MASK )) { +svm_check_intercept (SVM_EXIT_SMI ); env->interrupt_request &= ~CPU_INTERRUPT_SMI ;do_smm_enter ();#if defined(__sparc__) && !defined(HOST_SOLARIS )
@@ -399,9 +414,10 @@ int cpu_exec(CPUState *env1)T0 =0 ;#endif }else if ((interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ) && + (env->eflags &IF_MASK || env->hflags &HF_HIF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) {int intno; +svm_check_intercept (SVM_EXIT_INTR ); env->interrupt_request &= ~CPU_INTERRUPT_HARD ; intno =cpu_get_pic_interrupt (env);if (loglevel &CPU_LOG_TB_IN_ASM ) {
@@ -415,6 +431,21 @@ int cpu_exec(CPUState *env1)#else T0 =0 ;#endif + }else if ((interrupt_request &CPU_INTERRUPT_VIRQ ) && + (env->eflags &IF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) { +int intno; +// FIXME: this should respect TPR + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); +if (loglevel &CPU_LOG_TB_IN_ASM ) +fprintf (logfile,"Servicing virtual hardware INT=0x%02x\n" , intno); +do_interrupt (intno,0 ,0 ,-1 ,1 ); +#if defined(__sparc__) && !defined(HOST_SOLARIS ) + tmp_T0 =0 ; +#else +T0 =0 ; +#endif }#elif defined(TARGET_PPC)#if 0
target-i386/exec.h +10 -0
@@ -501,6 +501,15 @@ void update_fp_status(void);void helper_hlt (void );void helper_monitor (void );void helper_mwait (void ); +void helper_vmrun (target_ulong addr); +void helper_vmmcall (void ); +void helper_vmload (target_ulong addr); +void helper_vmsave (target_ulong addr); +void helper_stgi (void ); +void helper_clgi (void ); +void helper_skinit (void ); +void helper_invlpga (void ); +void vmexit (uint64_t exit_code,uint64_t exit_info_1);extern const uint8_t parity_table[256 ];extern const uint8_t rclw_table[32 ];
@@ -588,3 +597,4 @@ static inline int cpu_halted(CPUState *e }return EXCP_HALTED ; } +
exec.c +5 -0
@@ -1281,6 +1281,11 @@ void cpu_abort(CPUState *env, const charvfprintf (stderr, fmt, ap);fprintf (stderr,"\n" );#ifdef TARGET_I386 +if (env->intercept &INTERCEPT_SVM_MASK ) { +// most probably the virtual machine should not +// be shut down but rather caught by the VMM +vmexit (SVM_EXIT_SHUTDOWN ,0 ); + }cpu_dump_state (env, stderr, fprintf,X86_DUMP_FPU |X86_DUMP_CCOP );#else cpu_dump_state (env, stderr, fprintf,0 );
exec-all.h +1 -0
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */
cpu-all.h +1 -0
@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void cpu_reset_interrupt (CPUState *env,int mask);
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.
Alexander Graf
target-i386/helper2.c +11 -3
@@ -27,6 +27,7 @@#include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU
@@ -111,10 +112,11 @@ CPUX86State *cpu_x86_init(void)CPUID_CX8 |CPUID_PGE |CPUID_CMOV | CPUID_PAT); env->pat =0x0007040600070406ULL ; + env->cpuid_ext3_features =CPUID_EXT3_SVM ; env->cpuid_ext_features =CPUID_EXT_SSE3 ; env->cpuid_features |=CPUID_FXSR |CPUID_MMX |CPUID_SSE |CPUID_SSE2 |CPUID_PAE |CPUID_SEP ; env->cpuid_features |=CPUID_APIC ; - env->cpuid_xlevel =0 ; + env->cpuid_xlevel =0x8000000a ; {const char *model_id ="QEMU Virtual CPU version " QEMU_VERSION ;int c, len, i;
@@ -131,7 +133,6 @@ CPUX86State *cpu_x86_init(void)/* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features &0x0183F3FF ); env->cpuid_ext2_features |=CPUID_EXT2_LM |CPUID_EXT2_SYSCALL |CPUID_EXT2_NX ; - env->cpuid_xlevel =0x80000008 ;/* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |=CPUID_MTRR |CPUID_CLFLUSH |CPUID_MCA ;
@@ -160,6 +161,7 @@ void cpu_reset(CPUX86State *env)#ifdef CONFIG_SOFTMMU env->hflags |=HF_SOFTMMU_MASK ;#endif + env->hflags |=HF_GIF_MASK ;cpu_x86_update_cr0 (env,0x60000010 ); env->a20_mask =0xffffffff ;
@@ -863,7 +865,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State do_fault_protect: error_code =PG_ERROR_P_MASK ; do_fault: - env->cr[2 ] = addr; error_code |= (is_write <<PG_ERROR_W_BIT );if (is_user) error_code |=PG_ERROR_U_MASK ;
@@ -871,8 +872,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |=PG_ERROR_I_D_MASK ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + }else { + env->cr[2 ] = addr; + } env->error_code = error_code; env->exception_index =EXCP0E_PAGE ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE ))// the VMM will handle this +return 2 ;return 1 ; }
target-i386/translate.c +177 -6
432 lines not on this page · raw message
target-i386/cpu.h +22 -0
@@ -46,6 +46,8 @@#include "softfloat.h" +#include "svm.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU ) && !defined(__APPLE__)#define USE_CODE_COPY #endif
@@ -84,6 +86,7 @@#define DESC_AVL_MASK (1 << 20)#define DESC_P_MASK (1 << 15)#define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT)#define DESC_S_MASK (1 << 12)#define DESC_TYPE_SHIFT 8#define DESC_A_MASK (1 << 8)
@@ -149,6 +152,8 @@#define HF_VM_SHIFT 17/* must be same as eflags */ #define HF_HALTED_SHIFT 18/* CPU halted */ #define HF_SMM_SHIFT 19/* CPU in SMM mode */ +#define HF_GIF_SHIFT 20/* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21/* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT)#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +171,8 @@#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)#define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT)#define CR0_PE_MASK (1 << 0)#define CR0_MP_MASK (1 << 1)
@@ -249,6 +256,8 @@#define MSR_GSBASE 0xc0000101#define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 +/* cpuid_features bits */ #define CPUID_FP87 (1 << 0)#define CPUID_VME (1 << 1)
@@ -283,6 +292,8 @@#define CPUID_EXT2_FFXSR (1 << 25)#define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) +#define EXCP00_DIVZ 0#define EXCP01_SSTP 1#define EXCP02_NMI 2
@@ -489,6 +500,16 @@ typedef struct CPUX86State {uint32_t sysenter_eip;uint64_t efer;uint64_t star; + +target_phys_addr_t vm_hsave; +target_phys_addr_t vm_vmcb; +uint64_t intercept; +uint16_t intercept_cr_read; +uint16_t intercept_cr_write; +uint16_t intercept_dr_read; +uint16_t intercept_dr_write; +uint32_t intercept_exceptions; +#ifdef TARGET_X86_64 target_ulong lstar;target_ulong cstar;
@@ -530,6 +551,7 @@ typedef struct CPUX86State {uint32_t cpuid_xlevel;uint32_t cpuid_model[12 ];uint32_t cpuid_ext2_features; +uint32_t cpuid_ext3_features;uint32_t cpuid_apic_id;#ifdef USE_KQEMU
target-i386/op.c +80 -2
103 lines not on this page · raw message
target-i386/helper.c +489 -2
545 lines not on this page · raw message
target-i386/svm.h new file +357 -0
357 lines not on this page · raw message
cpu-exec.c +34 -3
@@ -104,6 +104,9 @@ static TranslationBlock *tb_find_slow(taif (tb->pc == pc && tb->page_addr[0 ] == phys_page1 && tb->cs_base == cs_base && +#if defined(TARGET_I386) + tb->intercept == env->intercept && +#endif tb->flags == flags) {/* check next page if needed */ if (tb->page_addr[1 ] !=-1 ) {
@@ -132,6 +135,9 @@ static TranslationBlock *tb_find_slow(ta tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; +#if defined(TARGET_I386 ) + tb->intercept = env->intercept; +#endif tb->flags = flags;cpu_gen_code (env, tb,CODE_GEN_MAX_SIZE , &code_gen_size); code_gen_ptr = (void *)(((unsigned long )code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 ));
@@ -214,7 +220,11 @@ static inline TranslationBlock *tb_find_#endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func (pc)];if (__builtin_expect (!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags,0 )) { + tb->flags != flags +#if defined(TARGET_I386) + || tb->intercept != env->intercept +#endif + , 0)) { tb =tb_find_slow (pc, cs_base, flags);/* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */
@@ -373,7 +383,11 @@ int cpu_exec(CPUState *env1) tmp_T0 =T0 ;#endif interrupt_request = env->interrupt_request; -if (__builtin_expect (interrupt_request,0 )) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386 ) + && env->hflags & HF_GIF_MASK +#endif + ) {if (interrupt_request &CPU_INTERRUPT_DEBUG ) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG ; env->exception_index =EXCP_DEBUG ;
@@ -391,6 +405,7 @@ int cpu_exec(CPUState *env1)#if defined(TARGET_I386 )if ((interrupt_request &CPU_INTERRUPT_SMI ) && !(env->hflags &HF_SMM_MASK )) { +svm_check_intercept (SVM_EXIT_SMI ); env->interrupt_request &= ~CPU_INTERRUPT_SMI ;do_smm_enter ();#if defined(__sparc__) && !defined(HOST_SOLARIS )
@@ -399,9 +414,10 @@ int cpu_exec(CPUState *env1)T0 =0 ;#endif }else if ((interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ) && + (env->eflags &IF_MASK || env->hflags &HF_HIF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) {int intno; +svm_check_intercept (SVM_EXIT_INTR ); env->interrupt_request &= ~CPU_INTERRUPT_HARD ; intno =cpu_get_pic_interrupt (env);if (loglevel &CPU_LOG_TB_IN_ASM ) {
@@ -415,6 +431,21 @@ int cpu_exec(CPUState *env1)#else T0 =0 ;#endif + }else if ((interrupt_request &CPU_INTERRUPT_VIRQ ) && + (env->eflags &IF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) { +int intno; +// FIXME: this should respect TPR + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); +if (loglevel &CPU_LOG_TB_IN_ASM ) +fprintf (logfile,"Servicing virtual hardware INT=0x%02x\n" , intno); +do_interrupt (intno,0 ,0 ,-1 ,1 ); +#if defined(__sparc__) && !defined(HOST_SOLARIS ) + tmp_T0 =0 ; +#else +T0 =0 ; +#endif }#elif defined(TARGET_PPC)#if 0
target-i386/exec.h +10 -0
@@ -501,6 +501,15 @@ void update_fp_status(void);void helper_hlt (void );void helper_monitor (void );void helper_mwait (void ); +void helper_vmrun (target_ulong addr); +void helper_vmmcall (void ); +void helper_vmload (target_ulong addr); +void helper_vmsave (target_ulong addr); +void helper_stgi (void ); +void helper_clgi (void ); +void helper_skinit (void ); +void helper_invlpga (void ); +void vmexit (uint64_t exit_code,uint64_t exit_info_1);extern const uint8_t parity_table[256 ];extern const uint8_t rclw_table[32 ];
@@ -588,3 +597,4 @@ static inline int cpu_halted(CPUState *e }return EXCP_HALTED ; } +
exec.c +5 -0
@@ -1281,6 +1281,11 @@ void cpu_abort(CPUState *env, const charvfprintf (stderr, fmt, ap);fprintf (stderr,"\n" );#ifdef TARGET_I386 +if (env->intercept &INTERCEPT_SVM_MASK ) { +// most probably the virtual machine should not +// be shut down but rather caught by the VMM +vmexit (SVM_EXIT_SHUTDOWN ,0 ); + }cpu_dump_state (env, stderr, fprintf,X86_DUMP_FPU |X86_DUMP_CCOP );#else cpu_dump_state (env, stderr, fprintf,0 );
exec-all.h +1 -0
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */
cpu-all.h +1 -0
@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void cpu_reset_interrupt (CPUState *env,int mask);
Quoted 4 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.
Tried that on PPC/Linux:
libqemu.a(cpu-exec.o): In function cpu_x86_exec':/home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference to ldl_phys' /home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference to stl_phys' /home/ths/qemu/qemu-work/cpu-exec.c:440: undefined reference to ldl_phys' libqemu.a(op.o): In function op_svm_check_intercept_io':/home/ths/qemu/qemu-work/target-i386/op.c:1282: undefined reference to stq_phys' libqemu.a(translate-op.o): In function dyngen_code':/home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference to stq_phys' /home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference to stq_phys'
collect2: ld returned 1 exit status
make[1]: *** [qemu-i386] Error 1
make: *** [subdir-i386-linux-user] Error 2
Thiemo
Quoted 24 lines · Thiemo Seufer
Quoted 5 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.Tried that on PPC/Linux:
libqemu.a(cpu-exec.o): In functioncpu_x86_exec':/home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference toldl_phys'/home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference tostl_phys'/home/ths/qemu/qemu-work/cpu-exec.c:440: undefined reference toldl_phys'libqemu.a(op.o): In functionop_svm_check_intercept_io':/home/ths/qemu/qemu-work/target-i386/op.c:1282: undefined reference tostq_phys'libqemu.a(translate-op.o): In functiondyngen_code':/home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference tostq_phys'/home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference tostq_phys'
collect2: ld returned 1 exit status
make[1]: *** [qemu-i386] Error 1
make: *** [subdir-i386-linux-user] Error 2
Quoted 4 lines
Thiemo
Wow sorry about that, looks like I missed these.
Alex
target-i386/helper2.c +11 -3
@@ -27,6 +27,7 @@#include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU
@@ -111,10 +112,11 @@ CPUX86State *cpu_x86_init(void)CPUID_CX8 |CPUID_PGE |CPUID_CMOV | CPUID_PAT); env->pat =0x0007040600070406ULL ; + env->cpuid_ext3_features =CPUID_EXT3_SVM ; env->cpuid_ext_features =CPUID_EXT_SSE3 ; env->cpuid_features |=CPUID_FXSR |CPUID_MMX |CPUID_SSE |CPUID_SSE2 |CPUID_PAE |CPUID_SEP ; env->cpuid_features |=CPUID_APIC ; - env->cpuid_xlevel =0 ; + env->cpuid_xlevel =0x8000000a ; {const char *model_id ="QEMU Virtual CPU version " QEMU_VERSION ;int c, len, i;
@@ -131,7 +133,6 @@ CPUX86State *cpu_x86_init(void)/* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features &0x0183F3FF ); env->cpuid_ext2_features |=CPUID_EXT2_LM |CPUID_EXT2_SYSCALL |CPUID_EXT2_NX ; - env->cpuid_xlevel =0x80000008 ;/* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |=CPUID_MTRR |CPUID_CLFLUSH |CPUID_MCA ;
@@ -160,6 +161,7 @@ void cpu_reset(CPUX86State *env)#ifdef CONFIG_SOFTMMU env->hflags |=HF_SOFTMMU_MASK ;#endif + env->hflags |=HF_GIF_MASK ;cpu_x86_update_cr0 (env,0x60000010 ); env->a20_mask =0xffffffff ;
@@ -863,7 +865,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State do_fault_protect: error_code =PG_ERROR_P_MASK ; do_fault: - env->cr[2 ] = addr; error_code |= (is_write <<PG_ERROR_W_BIT );if (is_user) error_code |=PG_ERROR_U_MASK ;
@@ -871,8 +872,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |=PG_ERROR_I_D_MASK ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + }else { + env->cr[2 ] = addr; + } env->error_code = error_code; env->exception_index =EXCP0E_PAGE ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE ))// the VMM will handle this +return 2 ;return 1 ; }
target-i386/translate.c +179 -6
434 lines not on this page · raw message
target-i386/cpu.h +22 -0
@@ -46,6 +46,8 @@#include "softfloat.h" +#include "svm.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU ) && !defined(__APPLE__)#define USE_CODE_COPY #endif
@@ -84,6 +86,7 @@#define DESC_AVL_MASK (1 << 20)#define DESC_P_MASK (1 << 15)#define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT)#define DESC_S_MASK (1 << 12)#define DESC_TYPE_SHIFT 8#define DESC_A_MASK (1 << 8)
@@ -149,6 +152,8 @@#define HF_VM_SHIFT 17/* must be same as eflags */ #define HF_HALTED_SHIFT 18/* CPU halted */ #define HF_SMM_SHIFT 19/* CPU in SMM mode */ +#define HF_GIF_SHIFT 20/* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21/* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT)#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +171,8 @@#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)#define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT)#define CR0_PE_MASK (1 << 0)#define CR0_MP_MASK (1 << 1)
@@ -249,6 +256,8 @@#define MSR_GSBASE 0xc0000101#define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 +/* cpuid_features bits */ #define CPUID_FP87 (1 << 0)#define CPUID_VME (1 << 1)
@@ -283,6 +292,8 @@#define CPUID_EXT2_FFXSR (1 << 25)#define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) +#define EXCP00_DIVZ 0#define EXCP01_SSTP 1#define EXCP02_NMI 2
@@ -489,6 +500,16 @@ typedef struct CPUX86State {uint32_t sysenter_eip;uint64_t efer;uint64_t star; + +target_phys_addr_t vm_hsave; +target_phys_addr_t vm_vmcb; +uint64_t intercept; +uint16_t intercept_cr_read; +uint16_t intercept_cr_write; +uint16_t intercept_dr_read; +uint16_t intercept_dr_write; +uint32_t intercept_exceptions; +#ifdef TARGET_X86_64 target_ulong lstar;target_ulong cstar;
@@ -530,6 +551,7 @@ typedef struct CPUX86State {uint32_t cpuid_xlevel;uint32_t cpuid_model[12 ];uint32_t cpuid_ext2_features; +uint32_t cpuid_ext3_features;uint32_t cpuid_apic_id;#ifdef USE_KQEMU
target-i386/op.c +82 -2
105 lines not on this page · raw message
target-i386/helper.c +489 -2
545 lines not on this page · raw message
target-i386/svm.h new file +357 -0
357 lines not on this page · raw message
cpu-exec.c +36 -3
@@ -104,6 +104,9 @@ static TranslationBlock *tb_find_slow(taif (tb->pc == pc && tb->page_addr[0 ] == phys_page1 && tb->cs_base == cs_base && +#if defined(TARGET_I386) + tb->intercept == env->intercept && +#endif tb->flags == flags) {/* check next page if needed */ if (tb->page_addr[1 ] !=-1 ) {
@@ -132,6 +135,9 @@ static TranslationBlock *tb_find_slow(ta tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; +#if defined(TARGET_I386 ) + tb->intercept = env->intercept; +#endif tb->flags = flags;cpu_gen_code (env, tb,CODE_GEN_MAX_SIZE , &code_gen_size); code_gen_ptr = (void *)(((unsigned long )code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 ));
@@ -218,7 +224,11 @@ static inline TranslationBlock *tb_find_#endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func (pc)];if (__builtin_expect (!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags,0 )) { + tb->flags != flags +#if defined(TARGET_I386) + || tb->intercept != env->intercept +#endif + , 0)) { tb =tb_find_slow (pc, cs_base, flags);/* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */
@@ -386,7 +396,11 @@ int cpu_exec(CPUState *env1) tmp_T0 =T0 ;#endif interrupt_request = env->interrupt_request; -if (__builtin_expect (interrupt_request,0 )) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386 ) + && env->hflags & HF_GIF_MASK +#endif + ) {if (interrupt_request &CPU_INTERRUPT_DEBUG ) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG ; env->exception_index =EXCP_DEBUG ;
@@ -404,6 +418,7 @@ int cpu_exec(CPUState *env1)#if defined(TARGET_I386 )if ((interrupt_request &CPU_INTERRUPT_SMI ) && !(env->hflags &HF_SMM_MASK )) { +svm_check_intercept (SVM_EXIT_SMI ); env->interrupt_request &= ~CPU_INTERRUPT_SMI ;do_smm_enter ();#if defined(__sparc__) && !defined(HOST_SOLARIS )
@@ -412,9 +427,10 @@ int cpu_exec(CPUState *env1)T0 =0 ;#endif }else if ((interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ) && + (env->eflags &IF_MASK || env->hflags &HF_HIF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) {int intno; +svm_check_intercept (SVM_EXIT_INTR ); env->interrupt_request &= ~CPU_INTERRUPT_HARD ; intno =cpu_get_pic_interrupt (env);if (loglevel &CPU_LOG_TB_IN_ASM ) {
@@ -428,6 +444,23 @@ int cpu_exec(CPUState *env1)#else T0 =0 ;#endif +#if !defined(CONFIG_USER_ONLY ) + } else if((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags &IF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) { +int intno; +// FIXME: this should respect TPR + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); +if (loglevel &CPU_LOG_TB_IN_ASM ) +fprintf (logfile,"Servicing virtual hardware INT=0x%02x\n" , intno); +do_interrupt (intno,0 ,0 ,-1 ,1 ); +#if defined(__sparc__) && !defined(HOST_SOLARIS ) + tmp_T0 =0 ; +#else +T0 =0 ; +#endif +#endif }#elif defined(TARGET_PPC)#if 0
target-i386/exec.h +10 -0
@@ -502,6 +502,15 @@ void update_fp_status(void);void helper_hlt (void );void helper_monitor (void );void helper_mwait (void ); +void helper_vmrun (target_ulong addr); +void helper_vmmcall (void ); +void helper_vmload (target_ulong addr); +void helper_vmsave (target_ulong addr); +void helper_stgi (void ); +void helper_clgi (void ); +void helper_skinit (void ); +void helper_invlpga (void ); +void vmexit (uint64_t exit_code,uint64_t exit_info_1);extern const uint8_t parity_table[256 ];extern const uint8_t rclw_table[32 ];
@@ -589,3 +598,4 @@ static inline int cpu_halted(CPUState *e }return EXCP_HALTED ; } +
exec.c +5 -0
@@ -1295,6 +1295,11 @@ void cpu_abort(CPUState *env, const charvfprintf (stderr, fmt, ap);fprintf (stderr,"\n" );#ifdef TARGET_I386 +if (env->intercept &INTERCEPT_SVM_MASK ) { +// most probably the virtual machine should not +// be shut down but rather caught by the VMM +vmexit (SVM_EXIT_SHUTDOWN ,0 ); + }cpu_dump_state (env, stderr, fprintf,X86_DUMP_FPU |X86_DUMP_CCOP );#else cpu_dump_state (env, stderr, fprintf,0 );
exec-all.h +1 -0
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */
cpu-all.h +1 -0
@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void cpu_reset_interrupt (CPUState *env,int mask);
Quoted 9 lines · Alexander Graf
Quoted 8 lines · Thiemo Seufer
Quoted 5 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.
[...]
Quoted 4 lines
Quoted 3 lines
Wow sorry about that, looks like I missed these.
exec-all.h +2 -0
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was
generated */
uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */
cpu-all.h +0 -0
@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending
*/
#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */
+#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */
void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask);
Those two patches look ugly to me as target specific features should never go in generic code or structures.
The CPU_INTERRUPT flags should just contain information about the emulator behavior, thus CPU_INTERRUPT_TIMER, CPU_INTERRUPT_SMI are to be removed. Target specific informations about the exception nature should go in the CPUState structure... Then, adding a CPU_INTERRUPT_VIRQ seems not a good idea at all: it's outside of the generic emulator scope and pointless for most targets.
For the same reason, the intercept field in the TB structure seems not acceptable, as TB specific target informations are already to be stored in the flags field. As intercept seems only to be a bit field, it should go, in a way or another, in tb flags. And as it seems that some interceptions are related with functions implemented in helpers (not micro-ops), you'd better check the interception in the helper at runtime, which would add no visible overhead (as calling a helper is slow compared to direct micro-ops execution), then you would not need to store those infos in the TB structure. This may even make the emulation run faster has you won't fill the TB cache with multiple translation of the same code each time the env->intercept changes, thus have chance to avoid many TB caches flushes.
Regards.
Signature · 2 lines
J. Mayer <[email protected]> Never organized
Quoted 49 lines · J. Mayer
Quoted 11 lines · Alexander Graf
Quoted 9 lines · Thiemo Seufer
Quoted 6 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.[...]
Quoted 4 lines
Quoted 2 lines
Wow sorry about that, looks like I missed these.
Index:
qemu-0.9.0.cvs/exec-all.h
===================================================================exec-all.h +2
-0@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code wasgenerated */
uint16_tsize; /* size of target code for this block (1 <=
size <=TARGET_PAGE_SIZE) */
Index:qemu-0.9.0.cvs/cpu-all.h
===================================================================cpu-all.h +1
-0@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void
cpu_reset_interrupt(CPUState *env, int mask);
Quoted 9 lines
Those two patches look ugly to me as target specific features should never go in generic code or structures.
TheCPU_INTERRUPTflags should just contain information about the emulator behavior, thusCPU_INTERRUPT_TIMER,CPU_INTERRUPT_SMIare to be removed. Target specific informations about the exception nature should go in the CPUState structure... Then, adding aCPU_INTERRUPT_VIRQseems not a good idea at all: it's outside of the generic emulator scope and pointless for most targets.
I don't see any practical reason not to do it this way. We could define a CPU_INTERRUPT_TARGET interrupt, that stores the information in a the target specific CPUState, but this would hit performance (marginally though) and does not improve the situation. I don't think that we should should forcefully try to seperate targets where we are not even close to running out of constants. If everyone on this list sees the situation as Jocelyn does, I would be fine with writing a patch that puts target specific interrupts to the specific targets.
Quoted 5 lines
For the same reason, the intercept field in the TB structure seems not acceptable, as TB specific target informations are already to be stored in the flags field. As intercept seems only to be a bit field, it should go, in a way or another, in tb flags. And as it seems that some
TB flags is a 32-bit bitfield, where several bits are already used. Currently SVM supports 45 intercepts and each combination can generate a different TB, as we do not want to reduce performance for the non-intercepted case. Think of the intercept field as flags2, that could be used by other virtualization implementations on other architectures too (though I do not know of any)
Quoted 6 lines
interceptions are related with functions implemented in helpers (not micro-ops), you'd better check the interception in the helper at runtime, which would add no visible overhead (as calling a helper is slow compared to direct micro-ops execution), then you would not need to store those infos in the TB structure. This may even make the emulation
This was the case in an earlier version of the patch. The current implementation you see is an optimization to make it running faster, as there is (nearly) no need for runtime detection.
Quoted 4 lines
run faster has you won't fill the TB cache with multiple translation of the same code each time the
env->interceptchanges, thus have chance to avoid many TB caches flushes.
This is actually intended, as I believe the emulated machine should run as fast as before when not using any interceptions
Quoted 3 lines
Regards.
Regards,
Alex
Quoted 59 lines · Alexander Graf
Quoted 49 lines · J. Mayer
Quoted 11 lines · Alexander Graf
Quoted 9 lines · Thiemo Seufer
Quoted 6 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.[...]
Quoted 4 lines
Quoted 2 lines
Wow sorry about that, looks like I missed these.
Index:
qemu-0.9.0.cvs/exec-all.h
===================================================================exec-all.h +2
-0@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code wasgenerated */
uint16_tsize; /* size of target code for this block (1 <=
size <=TARGET_PAGE_SIZE) */
Index:qemu-0.9.0.cvs/cpu-all.h
===================================================================cpu-all.h +1
-0@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void
cpu_reset_interrupt(CPUState *env, int mask);Quoted 9 lines
Those two patches look ugly to me as target specific features should never go in generic code or structures.
TheCPU_INTERRUPTflags should just contain information about the emulator behavior, thusCPU_INTERRUPT_TIMER,CPU_INTERRUPT_SMIare to be removed. Target specific informations about the exception nature should go in the CPUState structure... Then, adding aCPU_INTERRUPT_VIRQseems not a good idea at all: it's outside of the generic emulator scope and pointless for most targets.
Quoted 8 lines
I don't see any practical reason not to do it this way. We could define a
CPU_INTERRUPT_TARGETinterrupt, that stores the information in a the target specific CPUState, but this would hit performance (marginally though) and does not improve the situation. I don't think that we should should forcefully try to seperate targets where we are not even close to running out of constants. If everyone on this list sees the situation as Jocelyn does, I would be fine with writing a patch that puts target specific interrupts to the specific targets.
I was to do the same to add some functionality to the PowerPC target, long time ago, and Fabrice Bellard convinced me not to do and agreed it has been a bad idea to add the target specific CPU_INTERRUPT_xxx flags. Then I did manage the PowerPC target to use only generic CPU_INTERRUPT_xxx and put all other target specific informations in the CPUState structure. It absolutelly changes nothing in terms of functionality nor performance. The only thing is that it makes the generic parts simpler and could even allow the cpu_exec function to contain almost no target specific code, which would really great imho.
Quoted 11 lines
Quoted 5 lines
For the same reason, the intercept field in the TB structure seems not acceptable, as TB specific target informations are already to be stored in the flags field. As intercept seems only to be a bit field, it should go, in a way or another, in tb flags. And as it seems that some
TB flags is a 32-bit bitfield, where several bits are already used. Currently SVM supports 45 intercepts and each combination can generate a different TB, as we do not want to reduce performance for the non-intercepted case. Think of the intercept field as flags2, that could be used by other virtualization implementations on other architectures too (though I do not know of any)
So, why not make it generic and extend the flag field to as many bits as you need ? Intercept is x86 specific and has no meaning outside of this scope. Having more bits for flags is generic and may be useful for some other targets... The easy way is to convert flag to 64 bits, if you have enough bits. Another way is to make it a table, but this may need changes in all targets code...
Quoted 9 lines
Quoted 6 lines
interceptions are related with functions implemented in helpers (not micro-ops), you'd better check the interception in the helper at runtime, which would add no visible overhead (as calling a helper is slow compared to direct micro-ops execution), then you would not need to store those infos in the TB structure. This may even make the emulation
This was the case in an earlier version of the patch. The current implementation you see is an optimization to make it running faster, as there is (nearly) no need for runtime detection.
For all interceptions related to operations in helpers, it's not a actual optimisation. Things done in helpers are slow and not widely used (compared to the translated code, I mean), then adding a single test for interception in a helper may not hurt global performances. You may need TB flags only for operations you want to intercept that would be inlined in the translated code, then maybe reduce the number of bits needed without decreasing performanced. But, not knowing a lot about x86 VM specification I may be wrong...
Quoted 6 lines
Quoted 4 lines
run faster has you won't fill the TB cache with multiple translation of the same code each time the
env->interceptchanges, thus have chance to avoid many TB caches flushes.This is actually intended, as I believe the emulated machine should run as fast as before when not using any interceptions
It depends if those flags are to be changed often or not, which depends on the hypervisor software in use I guess. If the flags never change, there'll be no TB flush, I agree...
Regards.
Signature · 1 line
Jocelyn Mayer <[email protected]>
Quoted 78 lines · Jocelyn Mayer
Quoted 66 lines · Alexander Graf
Quoted 54 lines · J. Mayer
Quoted 14 lines · Alexander Graf
Quoted 11 lines · Thiemo Seufer
Quoted 7 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.[...]
Quoted 6 lines
Quoted 3 lines
Wow sorry about that, looks like I missed these.
Index:
qemu-0.9.0.cvs/exec-all.h
===================================================================exec-all.h +2
-0@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code wasgenerated */
uint16_tsize; /* size of target code for this block (1 <=
size <=TARGET_PAGE_SIZE) */
Index:qemu-0.9.0.cvs/cpu-all.h
===================================================================cpu-all.h +1
-0@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void
cpu_reset_interrupt(CPUState *env, int mask);Quoted 10 lines
Those two patches look ugly to me as target specific features should never go in generic code or structures.
TheCPU_INTERRUPTflags should just contain information about the emulator behavior, thusCPU_INTERRUPT_TIMER,CPU_INTERRUPT_SMIare to be removed. Target specific informations about the exception nature should go in the CPUState structure... Then, adding aCPU_INTERRUPT_VIRQseems not a good idea at all: it's outside of the generic emulator scope and pointless for most targets.Quoted 9 lines
I don't see any practical reason not to do it this way. We could define a
CPU_INTERRUPT_TARGETinterrupt, that stores the information in a the target specific CPUState, but this would hit performance (marginally though) and does not improve the situation. I don't think that we should should forcefully try to seperate targets where we are not even close to running out of constants. If everyone on this list sees the situation as Jocelyn does, I would be fine with writing a patch that puts target specific interrupts to the specific targets.
Quoted 10 lines
I was to do the same to add some functionality to the PowerPC target, long time ago, and Fabrice Bellard convinced me not to do and agreed it has been a bad idea to add the target specific
CPU_INTERRUPT_xxxflags. Then I did manage the PowerPC target to use only genericCPU_INTERRUPT_xxxand put all other target specific informations in the CPUState structure. It absolutelly changes nothing in terms of functionality nor performance. The only thing is that it makes the generic parts simpler and could even allow thecpu_execfunction to contain almost no target specific code, which would really great imho.
I can give that a try :-). Sounds reasonable for me.
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
For the same reason, the intercept field in the TB structure seems not acceptable, as TB specific target informations are already to be stored in the flags field. As intercept seems only to be a bit field, it should go, in a way or another, in tb flags. And as it seems that some
Quoted 7 lines
TB flags is a 32-bit bitfield, where several bits are already used. Currently SVM supports 45 intercepts and each combination can generate a different TB, as we do not want to reduce performance for the non-intercepted case. Think of the intercept field as flags2, that could be used by other virtualization implementations on other architectures too (though I do not know of any)
Quoted 7 lines
So, why not make it generic and extend the flag field to as many bits as you need ? Intercept is x86 specific and has no meaning outside of this scope. Having more bits for flags is generic and may be useful for some other targets... The easy way is to convert flag to 64 bits, if you have enough bits. Another way is to make it a table, but this may need changes in all targets code...
I think it might be quite a bad idea to extend flags until everything fits in there. I'm planning on implementing VMX as well and there are intercepts too so the meaning of the different fields change and I would not want that happening with the normal flags vector. What would you think of an #ifdef TARGET_I386? This way intercepts are x86 only and don't interfere with any other target architecture, but are still seperated from the flags (which is semantically correct as far as it goes for me).
Quoted 13 lines
Quoted 8 lines
Quoted 8 lines
interceptions are related with functions implemented in helpers (not micro-ops), you'd better check the interception in the helper at runtime, which would add no visible overhead (as calling a helper is slow compared to direct micro-ops execution), then you would not need to store those infos in the TB structure. This may even make the emulation
Quoted 4 lines
This was the case in an earlier version of the patch. The current implementation you see is an optimization to make it running faster, as there is (nearly) no need for runtime detection.
Quoted 10 lines
For all interceptions related to operations in helpers, it's not a actual optimisation. Things done in helpers are slow and not widely used (compared to the translated code, I mean), then adding a single test for interception in a helper may not hurt global performances. You may need TB flags only for operations you want to intercept that would be inlined in the translated code, then maybe reduce the number of bits needed without decreasing performanced. But, not knowing a lot about x86 VM specification I may be wrong...
I feel really uncomfortable with supporting hundreds of different ways of interception. It took me days to take all the intercept checks out of the helpers into the translate.c, as it is way easier to maintain and read that way. I do not like the idea of converting the intercept vector to something internal. It's quite nice to be able to use the very same constants as kvm does. This makes debugging really easy and you don't have to define everything twice. Additionally this way you can just set a variable without calculating anything, which does come in handy as well.
Basically the reason I really want to have everyting in translate.c is simplicity though.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
run faster has you won't fill the TB cache with multiple translation of the same code each time the
env->interceptchanges, thus have chance to avoid many TB caches flushes.
Quoted 8 lines
Quoted 3 lines
This is actually intended, as I believe the emulated machine should run as fast as before when not using any interceptions
It depends if those flags are to be changed often or not, which depends on the hypervisor software in use I guess. If the flags never change, there'll be no TB flush, I agree...
Usually (at least that's the case with kvm) you have two different sets of intercept flags. One for the real machine and one for the virtualized one. There is only one minor situation where that might change but that's not worth mentioning here. Nevertheless TBs point to physical memory (afaik) so since the virtual kernel is on a different page than the real one, we could not reuse TBs anyway so having the intercept information in the TB only helps in finding out which intercepts to check for as only a minority of the possible intercepts actually get used.
Regards,
Alex
Quoted 25 lines · Alexander Graf
Quoted 11 lines · Jocelyn Mayer
Quoted 11 lines
I don't see any practical reason not to do it this way. We could define a
CPU_INTERRUPT_TARGETinterrupt, that stores the information in a the target specific CPUState, but this would hit performance (marginally though) and does not improve the situation. I don't think that we should should forcefully try to seperate targets where we are not even close to running out of constants. If everyone on this list sees the situation as Jocelyn does, I would be fine with writing a patch that puts target specific interrupts to the specific targets.Quoted 11 lines
I was to do the same to add some functionality to the PowerPC target, long time ago, and Fabrice Bellard convinced me not to do and agreed it has been a bad idea to add the target specific
CPU_INTERRUPT_xxxflags. Then I did manage the PowerPC target to use only genericCPU_INTERRUPT_xxxand put all other target specific informations in the CPUState structure. It absolutelly changes nothing in terms of functionality nor performance. The only thing is that it makes the generic parts simpler and could even allow thecpu_execfunction to contain almost no target specific code, which would really great imho.
Quoted 3 lines
I can give that a try :-). Sounds reasonable for me.
Oh well I just thought about this a bit more and while stumbling across CPU_INTERRUPT_FIQ which does the same thing one major problem came to me on that one: Priority. Real interrupts have priority over virtual interrupts so the VIRQs have to be processed after HARD IRQs, whereas SMIs and NMIs have to be taken care of before the HARD IRQs. It simply wouldn't work out to generalize the IRQs, just as it would not work with the VIRQ, as it has to be handled as a real IRQ but without accessing the APIC which has to be done for HARD IRQs.
I guess we're stuck with what's there now.
Greetings,
Alex
Quoted 102 lines · Alexander Graf
Quoted 78 lines · Jocelyn Mayer
Quoted 66 lines · Alexander Graf
Quoted 54 lines · J. Mayer
Quoted 14 lines · Alexander Graf
Quoted 11 lines · Thiemo Seufer
Quoted 7 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.[...]
Quoted 6 lines
Quoted 3 lines
Wow sorry about that, looks like I missed these.
Index:
qemu-0.9.0.cvs/exec-all.h
===================================================================exec-all.h +2
-0@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code wasgenerated */
uint16_tsize; /* size of target code for this block (1 <=
size <=TARGET_PAGE_SIZE) */
Index:qemu-0.9.0.cvs/cpu-all.h
===================================================================cpu-all.h +1
-0@@ -715,6 +715,7 @@ extern int code_copy_enabled;#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void
cpu_reset_interrupt(CPUState *env, int mask);Quoted 10 lines
Those two patches look ugly to me as target specific features should never go in generic code or structures.
TheCPU_INTERRUPTflags should just contain information about the emulator behavior, thusCPU_INTERRUPT_TIMER,CPU_INTERRUPT_SMIare to be removed. Target specific informations about the exception nature should go in the CPUState structure... Then, adding aCPU_INTERRUPT_VIRQseems not a good idea at all: it's outside of the generic emulator scope and pointless for most targets.Quoted 9 lines
I don't see any practical reason not to do it this way. We could define a
CPU_INTERRUPT_TARGETinterrupt, that stores the information in a the target specific CPUState, but this would hit performance (marginally though) and does not improve the situation. I don't think that we should should forcefully try to seperate targets where we are not even close to running out of constants. If everyone on this list sees the situation as Jocelyn does, I would be fine with writing a patch that puts target specific interrupts to the specific targets.Quoted 10 lines
I was to do the same to add some functionality to the PowerPC target, long time ago, and Fabrice Bellard convinced me not to do and agreed it has been a bad idea to add the target specific
CPU_INTERRUPT_xxxflags. Then I did manage the PowerPC target to use only genericCPU_INTERRUPT_xxxand put all other target specific informations in the CPUState structure. It absolutelly changes nothing in terms of functionality nor performance. The only thing is that it makes the generic parts simpler and could even allow thecpu_execfunction to contain almost no target specific code, which would really great imho.I can give that a try :-). Sounds reasonable for me.
[Next message]
Oh well I just thought about this a bit more and while stumbling acrossCPU_INTERRUPT_FIQwhich does the same thing one major problem came to me on that one: Priority. Real interrupts have priority over virtual interrupts so the VIRQs have to be processed after HARD IRQs, whereas SMIs and NMIs have to be taken care of before the HARD IRQs. It simply wouldn't work out to generalize the IRQs, just as it would not work with the VIRQ, as it has to be handled as a real IRQ but without accessing the APIC which has to be done for HARD IRQs.
Quoted 1 line
I guess we're stuck with what's there now.
Priorities are not an issue, you can take a look to the ppc_hw_interrupt function to see how the PowerPC emulation code manages priorities and masking between 10 different hardware interruption sources. The code could be better (I wanted to preserve existing code) but it's a solution that actually works... But looking better the x86 emulation code, I agree that if you don't want to change it too much, you have to add a flag. The other solution (and best, imho) would be to do the same as what has been done for PowerPC: just let the generic code in the cpu_exec loop and move the x86 specific code somewhere in target-i386 code. Going this way, I see no reason why the interruption code in the cpu_exec loop could not finally become:
interrupt_request = env->interrupt_request;
if (__builtin_expect(interrupt_request, 0)) {
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
env->exception_index = EXCP_DEBUG;
cpu_loop_exit();
}
if (interrupt_request & CPU_INTERRUPT_HALT) {
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
env->exception_index = EXCP_HLT;
cpu_loop_exit();
}
if (interrupt_request & CPU_INTERRUPT_HARD) {
hw_interrupt(env);
if (env->pending_interrupts == 0)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
if (interrupt_request & CPU_INTERRUPT_EXIT) {
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
}All the targets specific tricks could be done in the hw_interrupt routine. And the generic code would become much more readable. But this needs some works (not so much) and intensive tests... And I guess nobody feels like taking this risk right now ;-)
But I think this will have to be done someday...
Quoted 23 lines
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
For the same reason, the intercept field in the TB structure seems not acceptable, as TB specific target informations are already to be stored in the flags field. As intercept seems only to be a bit field, it should go, in a way or another, in tb flags. And as it seems that some
Quoted 7 lines
TB flags is a 32-bit bitfield, where several bits are already used. Currently SVM supports 45 intercepts and each combination can generate a different TB, as we do not want to reduce performance for the non-intercepted case. Think of the intercept field as flags2, that could be used by other virtualization implementations on other architectures too (though I do not know of any)
Quoted 7 lines
So, why not make it generic and extend the flag field to as many bits as you need ? Intercept is x86 specific and has no meaning outside of this scope. Having more bits for flags is generic and may be useful for some other targets... The easy way is to convert flag to 64 bits, if you have enough bits. Another way is to make it a table, but this may need changes in all targets code...
Quoted 8 lines
I think it might be quite a bad idea to extend flags until everything fits in there. I'm planning on implementing VMX as well and there are intercepts too so the meaning of the different fields change and I would not want that happening with the normal flags vector. What would you think of an #ifdef
TARGET_I386? This way intercepts are x86 only and don't interfere with any other target architecture, but are still seperated from the flags (which is semantically correct as far as it goes for me).
I don't consider as a problem that one bit in the TB flags field can have different meanings.
This field is something opaque from the generic code. I actually have the same thing in
the PowerPC emulation (even if it's not fully done for now): TB flags are just an
selection of the Machine State Register bits. Some of those bits can have different
meanings depending on the PowerPC implementation (ie CPU model). But the only thing important is to know if the current CPUState flags are equal to the
TB flags, not the actual meaning of the bits. As the MSR is 32 bits on 32 bits
PowerPC implementations, I have no hesitation to use those bits directly even if their actual meaning, from the CPU "point of view" changes. Then, imho, you should not hesitate to put those intercept bits in a generic field...
Quoted 33 lines
Quoted 13 lines
Quoted 8 lines
Quoted 8 lines
interceptions are related with functions implemented in helpers (not micro-ops), you'd better check the interception in the helper at runtime, which would add no visible overhead (as calling a helper is slow compared to direct micro-ops execution), then you would not need to store those infos in the TB structure. This may even make the emulation
Quoted 4 lines
This was the case in an earlier version of the patch. The current implementation you see is an optimization to make it running faster, as there is (nearly) no need for runtime detection.
Quoted 10 lines
For all interceptions related to operations in helpers, it's not a actual optimisation. Things done in helpers are slow and not widely used (compared to the translated code, I mean), then adding a single test for interception in a helper may not hurt global performances. You may need TB flags only for operations you want to intercept that would be inlined in the translated code, then maybe reduce the number of bits needed without decreasing performanced. But, not knowing a lot about x86 VM specification I may be wrong...
I feel really uncomfortable with supporting hundreds of different ways of interception. It took me days to take all the intercept checks out of the helpers into the
translate.c, as it is way easier to maintain and read that way. I do not like the idea of converting the intercept vector to something internal. It's quite nice to be able to use the very same constants as kvm does. This makes debugging really easy and you don't have to define everything twice. Additionally this way you can just set a variable without calculating anything, which does come in handy as well.
Quoted 2 lines
Basically the reason I really want to have everyting in
translate.cis simplicity though.
OK, I understand that using the same code for all interceptions can make your coding
far easier...
Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
run faster has you won't fill the TB cache with multiple translation of the same code each time the
env->interceptchanges, thus have chance to avoid many TB caches flushes.Quoted 8 lines
Quoted 3 lines
This is actually intended, as I believe the emulated machine should run as fast as before when not using any interceptions
It depends if those flags are to be changed often or not, which depends on the hypervisor software in use I guess. If the flags never change, there'll be no TB flush, I agree...
Quoted 8 lines
Usually (at least that's the case with kvm) you have two different sets of intercept flags. One for the real machine and one for the virtualized one. There is only one minor situation where that might change but that's not worth mentioning here. Nevertheless TBs point to physical memory (afaik) so since the virtual kernel is on a different page than the real one, we could not reuse TBs anyway so having the intercept information in the TB only helps in finding out which intercepts to check for as only a minority of the possible intercepts actually get used.
So as far as the hypervisor do not provide shared routines to be used by the OS,
you should never have any "collisison" between translated blocks in different environments ?
I guess you need a complete TB flush when switching between the virtualized environments.
Then, OK, the interception flags should never lead to fill the TB cache with multiple translations
of the same blocks...
Regards.
Signature · 2 lines
J. Mayer <[email protected]> Never organized
Quoted 43 lines · J. Mayer
Going this way, I see no reason why the interruption code in the
cpu_execloop could not finally become:interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0)) { if (interrupt_request & CPU_INTERRUPT_DEBUG) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; env->exception_index = EXCP_DEBUG; cpu_loop_exit(); } if (interrupt_request & CPU_INTERRUPT_HALT) { env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(); } if (interrupt_request & CPU_INTERRUPT_HARD) { hw_interrupt(env); if (env->pending_interrupts == 0) env->interrupt_request &= ~CPU_INTERRUPT_HARD; #if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; #endif } /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ if (interrupt_request & CPU_INTERRUPT_EXITTB) { env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ #if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; #endif } if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; env->exception_index = EXCP_INTERRUPT; cpu_loop_exit(); } }
Quoted 4 lines
All the targets specific tricks could be done in the
hw_interruptroutine. And the generic code would become much more readable. But this needs some works (not so much) and intensive tests... And I guess nobody feels like taking this risk right now ;-)
But I think this will have to be done someday...
I vote for this. There are some other places where we could use the same API:cpu_dump_state()cpu_list()cpu_register()
Quoted 25 lines · Alexander Graf
Quoted 24 lines · Thiemo Seufer
Quoted 5 lines · Alexander Graf
Thanks to Michael Peter who tried the patch on an x86 host I found some compilation problems.
This updated patch addresses these issues and thus should compile on every platform for every target available.Tried that on PPC/Linux:
libqemu.a(cpu-exec.o): In functioncpu_x86_exec':/home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference toldl_phys'/home/ths/qemu/qemu-work/cpu-exec.c:439: undefined reference tostl_phys'/home/ths/qemu/qemu-work/cpu-exec.c:440: undefined reference toldl_phys'libqemu.a(op.o): In functionop_svm_check_intercept_io':/home/ths/qemu/qemu-work/target-i386/op.c:1282: undefined reference tostq_phys'libqemu.a(translate-op.o): In functiondyngen_code':/home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference tostq_phys'/home/ths/qemu/qemu-work/i386-linux-user/./op.h:4101: undefined reference tostq_phys'
collect2: ld returned 1 exit status
make[1]: *** [qemu-i386] Error 1
make: *** [subdir-i386-linux-user] Error 2
Quoted 5 lines
Quoted 4 lines
Thiemo
Wow sorry about that, looks like I missed these.
I worked a bit on the patch to remove some coding style issues and data type mismatches which caused compiler warnings. The result is attached and seems to work reasonably well for me.
That said, J. Mayers comments point out worthwile improvements, so I don't commit it for now. Please incorporate my changes in your patch, and look into improving it further.
Thiemo
target-i386/helper2.c +12 -3
@@ -27,6 +27,7 @@#include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU
@@ -111,10 +112,11 @@CPUID_CX8 |CPUID_PGE |CPUID_CMOV | CPUID_PAT); env->pat =0x0007040600070406ULL ; + env->cpuid_ext3_features =CPUID_EXT3_SVM ; env->cpuid_ext_features =CPUID_EXT_SSE3 ; env->cpuid_features |=CPUID_FXSR |CPUID_MMX |CPUID_SSE |CPUID_SSE2 |CPUID_PAE |CPUID_SEP ; env->cpuid_features |=CPUID_APIC ; - env->cpuid_xlevel =0x80000006 ; + env->cpuid_xlevel =0x8000000e ; {const char *model_id ="QEMU Virtual CPU version " QEMU_VERSION ;int c, len, i;
@@ -131,7 +133,6 @@/* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features &0x0183F3FF ); env->cpuid_ext2_features |=CPUID_EXT2_LM |CPUID_EXT2_SYSCALL |CPUID_EXT2_NX ; - env->cpuid_xlevel =0x80000008 ;/* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |=CPUID_MTRR |CPUID_CLFLUSH |CPUID_MCA ;
@@ -162,6 +163,7 @@#ifdef CONFIG_SOFTMMU env->hflags |=HF_SOFTMMU_MASK ;#endif + env->hflags |=HF_GIF_MASK ;cpu_x86_update_cr0 (env,0x60000010 ); env->a20_mask =0xffffffff ;
@@ -865,7 +867,6 @@ do_fault_protect: error_code =PG_ERROR_P_MASK ; do_fault: - env->cr[2 ] = addr; error_code |= (is_write <<PG_ERROR_W_BIT );if (is_user) error_code |=PG_ERROR_U_MASK ;
@@ -873,8 +874,16 @@ (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |=PG_ERROR_I_D_MASK ; +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + }else { + env->cr[2 ] = addr; + } env->error_code = error_code; env->exception_index =EXCP0E_PAGE ; +/* the VMM will handle this */ +if (INTERCEPTEDl (_exceptions,1 <<EXCP0E_PAGE )) +return 2 ;return 1 ; }
target-i386/translate.c +240 -5
494 lines not on this page · raw message
target-i386/cpu.h +22 -0
@@ -46,6 +46,8 @@#include "softfloat.h" +#include "svm.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU ) && !defined(__APPLE__)#define USE_CODE_COPY #endif
@@ -84,6 +86,7 @@#define DESC_AVL_MASK (1 << 20)#define DESC_P_MASK (1 << 15)#define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT)#define DESC_S_MASK (1 << 12)#define DESC_TYPE_SHIFT 8#define DESC_A_MASK (1 << 8)
@@ -149,6 +152,8 @@#define HF_VM_SHIFT 17/* must be same as eflags */ #define HF_HALTED_SHIFT 18/* CPU halted */ #define HF_SMM_SHIFT 19/* CPU in SMM mode */ +#define HF_GIF_SHIFT 20/* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21/* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT)#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +171,8 @@#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)#define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT)#define CR0_PE_MASK (1 << 0)#define CR0_MP_MASK (1 << 1)
@@ -249,6 +256,8 @@#define MSR_GSBASE 0xc0000101#define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 +/* cpuid_features bits */ #define CPUID_FP87 (1 << 0)#define CPUID_VME (1 << 1)
@@ -283,6 +292,8 @@#define CPUID_EXT2_FFXSR (1 << 25)#define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) +#define EXCP00_DIVZ 0#define EXCP01_SSTP 1#define EXCP02_NMI 2
@@ -489,6 +500,16 @@uint32_t sysenter_eip;uint64_t efer;uint64_t star; + +target_phys_addr_t vm_hsave; +target_phys_addr_t vm_vmcb; +uint64_t intercept; +uint16_t intercept_cr_read; +uint16_t intercept_cr_write; +uint16_t intercept_dr_read; +uint16_t intercept_dr_write; +uint32_t intercept_exceptions; +#ifdef TARGET_X86_64 target_ulong lstar;target_ulong cstar;
@@ -530,6 +551,7 @@uint32_t cpuid_xlevel;uint32_t cpuid_model[12 ];uint32_t cpuid_ext2_features; +uint32_t cpuid_ext3_features;uint32_t cpuid_apic_id;#ifdef USE_KQEMU
target-i386/op.c +85 -3
114 lines not on this page · raw message
target-i386/helper.c +518 -2
569 lines not on this page · raw message
target-i386/svm.h new file +356 -0
356 lines not on this page · raw message
cpu-exec.c +37 -3
@@ -104,6 +104,9 @@if (tb->pc == pc && tb->page_addr[0 ] == phys_page1 && tb->cs_base == cs_base && +#if defined(TARGET_I386) + tb->intercept == env->intercept && +#endif tb->flags == flags) {/* check next page if needed */ if (tb->page_addr[1 ] !=-1 ) {
@@ -132,6 +135,9 @@ tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; +#if defined(TARGET_I386 ) + tb->intercept = env->intercept; +#endif tb->flags = flags;cpu_gen_code (env, tb,CODE_GEN_MAX_SIZE , &code_gen_size); code_gen_ptr = (void *)(((unsigned long )code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 ));
@@ -214,7 +220,11 @@#endif tb = env->tb_jmp_cache[tb_jmp_cache_hash_func (pc)];if (__builtin_expect (!tb || tb->pc != pc || tb->cs_base != cs_base || - tb->flags != flags,0 )) { + tb->flags != flags +#if defined(TARGET_I386) + || tb->intercept != env->intercept +#endif + , 0)) { tb =tb_find_slow (pc, cs_base, flags);/* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */
@@ -373,7 +383,11 @@ tmp_T0 =T0 ;#endif interrupt_request = env->interrupt_request; -if (__builtin_expect (interrupt_request,0 )) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386 ) + && env->hflags & HF_GIF_MASK +#endif + ) {if (interrupt_request &CPU_INTERRUPT_DEBUG ) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG ; env->exception_index =EXCP_DEBUG ;
@@ -391,6 +405,7 @@#if defined(TARGET_I386 )if ((interrupt_request &CPU_INTERRUPT_SMI ) && !(env->hflags &HF_SMM_MASK )) { +svm_check_intercept (SVM_EXIT_SMI ); env->interrupt_request &= ~CPU_INTERRUPT_SMI ;do_smm_enter ();#if defined(__sparc__) && !defined(HOST_SOLARIS )
@@ -399,9 +414,10 @@T0 =0 ;#endif }else if ((interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ) && + (env->eflags &IF_MASK || env->hflags &HF_HIF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) {int intno; +svm_check_intercept (SVM_EXIT_INTR ); env->interrupt_request &= ~CPU_INTERRUPT_HARD ; intno =cpu_get_pic_interrupt (env);if (loglevel &CPU_LOG_TB_IN_ASM ) {
@@ -415,6 +431,24 @@#else T0 =0 ;#endif +#if !defined(CONFIG_USER_ONLY ) + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags &IF_MASK ) && !(env->hflags &HF_INHIBIT_IRQ_MASK )) { +int intno; +/* FIXME: this should respect TPR */ + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), + ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); +if (loglevel &CPU_LOG_TB_IN_ASM ) +fprintf (logfile,"Servicing virtual hardware INT=0x%02x\n" , intno); +do_interrupt (intno,0 ,0 ,-1 ,1 ); +#if defined(__sparc__) && !defined(HOST_SOLARIS ) + tmp_T0 =0 ; +#else +T0 =0 ; +#endif +#endif }#elif defined(TARGET_PPC)#if 0
target-i386/exec.h +10 -0
@@ -502,6 +502,15 @@void helper_hlt (void );void helper_monitor (void );void helper_mwait (void ); +void helper_vmrun (target_ulong addr); +void helper_vmmcall (void ); +void helper_vmload (target_ulong addr); +void helper_vmsave (target_ulong addr); +void helper_stgi (void ); +void helper_clgi (void ); +void helper_skinit (void ); +void helper_invlpga (void ); +void vmexit (uint64_t exit_code,uint64_t exit_info_1);extern const uint8_t parity_table[256 ];extern const uint8_t rclw_table[32 ];
@@ -589,3 +598,4 @@ }return EXCP_HALTED ; } +
exec.c +5 -0
@@ -1292,6 +1292,11 @@vfprintf (stderr, fmt, ap);fprintf (stderr,"\n" );#ifdef TARGET_I386 +if (env->intercept &INTERCEPT_SVM_MASK ) { +/* most probably the virtual machine should not +be shut down but rather caught by the VMM */ +vmexit (SVM_EXIT_SHUTDOWN ,0 ); + }cpu_dump_state (env, stderr, fprintf,X86_DUMP_FPU |X86_DUMP_CCOP );#else cpu_dump_state (env, stderr, fprintf,0 );
exec-all.h +1 -0
@@ -166,6 +166,7 @@ typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ + uint64_t intercept; /* SVM intercept vector */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */
cpu-all.h +1 -0
@@ -716,6 +716,7 @@#define CPU_INTERRUPT_HALT 0x20/* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40/* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80/* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100/* virtual interrupt pending. */ void cpu_interrupt (CPUState *s,int mask);void cpu_reset_interrupt (CPUState *env,int mask);