mirror of
				https://github.com/yuzu-emu/unicorn.git
				synced 2025-11-04 02:54:47 +00:00 
			
		
		
		
	target-i386: defer VMEXIT to do_interrupt
Paths through the softmmu code during code generation now need to be audited to check for double locking of tb_lock. In particular, VMEXIT can take tb_lock through cpu_vmexit -> cpu_x86_update_cr4 -> tlb_flush. To avoid this, split VMEXIT delivery in two parts, similar to what is done with exceptions. cpu_vmexit only records the VMEXIT exit code and information, and cc->do_interrupt can then deliver it when it is safe to take the lock. Backports commit 10cde894b63146139f981857e4eedf756fa53dcb from qemu
This commit is contained in:
		
							parent
							
								
									ad548f8110
								
							
						
					
					
						commit
						bc7a9ccfbd
					
				| 
						 | 
					@ -695,6 +695,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EXCP_SYSCALL    0x100 /* only happens in user only emulation
 | 
					#define EXCP_SYSCALL    0x100 /* only happens in user only emulation
 | 
				
			||||||
                                 for syscall instruction */
 | 
					                                 for syscall instruction */
 | 
				
			||||||
 | 
					#define EXCP_VMEXIT     0x100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* i386-specific interrupt pending bits.  */
 | 
					/* i386-specific interrupt pending bits.  */
 | 
				
			||||||
#define CPU_INTERRUPT_POLL      CPU_INTERRUPT_TGT_EXT_1
 | 
					#define CPU_INTERRUPT_POLL      CPU_INTERRUPT_TGT_EXT_1
 | 
				
			||||||
| 
						 | 
					@ -1605,6 +1606,7 @@ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
 | 
				
			||||||
                                   uint64_t param, uintptr_t retaddr);
 | 
					                                   uint64_t param, uintptr_t retaddr);
 | 
				
			||||||
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
 | 
					void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
 | 
				
			||||||
                uintptr_t retaddr);
 | 
					                uintptr_t retaddr);
 | 
				
			||||||
 | 
					void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* seg_helper.c */
 | 
					/* seg_helper.c */
 | 
				
			||||||
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
 | 
					void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1298,15 +1298,17 @@ void x86_cpu_do_interrupt(CPUState *cs)
 | 
				
			||||||
    /* successfully delivered */
 | 
					    /* successfully delivered */
 | 
				
			||||||
    env->old_exception = -1;
 | 
					    env->old_exception = -1;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    /* simulate a real cpu exception. On i386, it can
 | 
					    if (cs->exception_index >= EXCP_VMEXIT) {
 | 
				
			||||||
       trigger new exceptions, but we do not handle
 | 
					        assert(env->old_exception == -1);
 | 
				
			||||||
       double or triple faults yet. */
 | 
					        do_vmexit(env, cs->exception_index - EXCP_VMEXIT, env->error_code);
 | 
				
			||||||
    do_interrupt_all(cpu, cs->exception_index,
 | 
					    } else {
 | 
				
			||||||
                     env->exception_is_int,
 | 
					        do_interrupt_all(cpu, cs->exception_index,
 | 
				
			||||||
                     env->error_code,
 | 
					                         env->exception_is_int,
 | 
				
			||||||
                     env->exception_next_eip, 0);
 | 
					                         env->error_code,
 | 
				
			||||||
    /* successfully delivered */
 | 
					                         env->exception_next_eip, 0);
 | 
				
			||||||
    env->old_exception = -1;
 | 
					        /* successfully delivered */
 | 
				
			||||||
 | 
					        env->old_exception = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -568,12 +568,10 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Note: currently only 32 bits of exit_code are used */
 | 
					 | 
				
			||||||
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
 | 
					void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
 | 
				
			||||||
                uintptr_t retaddr)
 | 
					                uintptr_t retaddr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cs = CPU(x86_env_get_cpu(env));
 | 
					    CPUState *cs = CPU(x86_env_get_cpu(env));
 | 
				
			||||||
    uint32_t int_ctl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (retaddr) {
 | 
					    if (retaddr) {
 | 
				
			||||||
        cpu_restore_state(cs, retaddr);
 | 
					        cpu_restore_state(cs, retaddr);
 | 
				
			||||||
| 
						 | 
					@ -585,6 +583,18 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
 | 
				
			||||||
                  x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
 | 
					                  x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
 | 
				
			||||||
                                                   control.exit_info_2)),
 | 
					                                                   control.exit_info_2)),
 | 
				
			||||||
                  env->eip);
 | 
					                  env->eip);
 | 
				
			||||||
 | 
					    cs->exception_index = EXCP_VMEXIT + exit_code;
 | 
				
			||||||
 | 
					    env->error_code = exit_info_1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* remove any pending exception */
 | 
				
			||||||
 | 
					    env->old_exception = -1;
 | 
				
			||||||
 | 
					    cpu_loop_exit(cs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *cs = CPU(x86_env_get_cpu(env));
 | 
				
			||||||
 | 
					    uint32_t int_ctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (env->hflags & HF_INHIBIT_IRQ_MASK) {
 | 
					    if (env->hflags & HF_INHIBIT_IRQ_MASK) {
 | 
				
			||||||
        x86_stl_phys(cs,
 | 
					        x86_stl_phys(cs,
 | 
				
			||||||
| 
						 | 
					@ -747,13 +757,6 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
 | 
				
			||||||
    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
 | 
					    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
 | 
				
			||||||
       host's code segment or non-canonical (in the case of long mode), a
 | 
					       host's code segment or non-canonical (in the case of long mode), a
 | 
				
			||||||
       #GP fault is delivered inside the host. */
 | 
					       #GP fault is delivered inside the host. */
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* remove any pending exception */
 | 
					 | 
				
			||||||
    cs->exception_index = -1;
 | 
					 | 
				
			||||||
    env->error_code = 0;
 | 
					 | 
				
			||||||
    env->old_exception = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    cpu_loop_exit(cs);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue