Fix exceptions handling for MIPS, PowerPC, and i386
v7 cover Fix exceptions handling for MIPS, PowerPC, and i386
QEMU targets ISAs contain instruction that can break the execution flow with exceptions. When exception breaks the execution of the translation block it may corrupt PC and icount values.
This set of patches fixes exception handling for MIPS, PowerPC, and i386 targets.
Incorrect execution for i386 is causes by exceptions raised by MMU functions. MMU helper functions are called from generated code and other helper functions. In both cases they try to get function's return address for restoring virtual CPU state.
When MMU helper is called from some other helper function (like helper_maskmov_xmm) through cpu_st* function, the return address will point to that helper. That is why CPU state cannot be restored in the case of MMU fault.
This bug can occur when maskmov instruction is located in the middle of the translation block.
Execution sequence for this example:
TB start:
PC1: instr1
instr2
PC2: maskmov <page fault>
<page fault processing>
PC1: instr1
instr2
maskmov
At the start of TB execution guest PC points to instr1. When page fault occurs QEMU tries to restore guest PC (which should be equal to PC2). It reads host PC from the call stack and checks whether it points to TB or not. Bug in ldst helpers implementation provides incorrect host PC, which is not located within the TB. That's why QEMU cannot recover guest PC and it remains the same (PC1). After page fault processing QEMU restarts TB and executes instr1 and instr2 for the second time, because guest PC was not recovered.
Bugs in helper functions for other targets do not break the execution in regular TCG mode, because PC value is updated before calling the functions that can raise an exception. But icount value cannot be updated this way. Therefore exceptions make execution in icount mode non-determinisic. In icount mode every translation block looks as follows:
if icount < n then exit
icount -= n
instr1
instr2
...
instrn
exit
When one of these instructions initiates an exception, icount should be restored and adjusted number of instructions should be subtracted from icount instead of initial n.
tlb_fill function passes retaddr to raise_exception, which allows restoring current instructions in TB and correct icount calculation.
When exception triggered with other function (e.g. by embedding call to exception raising helper into TB), then PC is not passed as retaddr and correct icount is not recovered. In such cases icount will be decreased by the value equal to the size of TB.
This behavior leads to incorrect values of virtual clock and non-deterministic execution of the code.
These patches passes pointer to the translation block code to the exception handler. It allows correct restoring of PC and icount values.
v7 changes:
* Removed cur_eip parameter of gen_movl_seg_T0 function for i386 (as suggested by Richard Henderson)
* Made direct next_eip passing to lcall_protected and ljmp_protected for i386 (as suggested by Richard Henderson)
* Removed changes for unimplemented instructions (as suggested by Richard Henderson)
* Added patch for removing unused softmmu functions (as suggested by Aurelien Jarno)
v6 changes:
* Removed several calls to gen_update_cc_op(s) (as suggested by Aurelien Jarno)
* Introduced do_* versions for fxsave and fxrstor (as suggested by Richard Henderson)
* Removed useless seg functions changes (as suggested by Richard Henderson)
* Fixed ppc linux user build (as suggested by Aurelien Jarno)
v5 changes:
* Added helper functions for usermode ldst (as suggested by Aurelien Jarno)
* Fixed memory helpers for MIPS (as suggested by Aurelien Jarno)
* Added _ra version of raise_exception functions (as suggested by Richard Henderson)
* Split i386 patch into several parts (as suggested by Richard Henderson)
v4 changes:
* Fixed exceptions handling for PowerPC
* Fixed passing of mmu_idx into helpers (as suggested by Aurelien Jarno)
* Added cpu_loop_exit_restore function (as suggested by Aurelien Jarno)
* Fixed exceptions handling in compare helper functions for MIPS (as suggested by Aurelien Jarno)
* Removed several CPU state saving calls for MIPS (as suggested by Aurelien Jarno)
v3 changes:
* Modified exception handling for syscall (as suggested by Aurelien Jarno)
* Removed redundant calls to save_cpu_state (as suggested by Aurelien Jarno)
* Removed helper_call* functions from softmmu (as suggested by Paolo Bonzini)
v2 changes:
* Added softmmu functions to pass TB return value into memory operations handlers
* Fixed memory operations handling for MIPS
* Disabled updates of the PC that are overridden with cpu_restore_state
* Fixed memory operations and exceptions invoked by i386 helpers
---
Pavel Dovgalyuk (11):
softmmu: add helper function to pass through retaddr
softmmu: remove now unused functions
cpu-exec: introduce loop exit with restore function
target-mips: improve exception handling
target-i386: introduce new raise_exception functions
target-i386: exception handling for FPU instructions
target-i386: exception handling for div instructions
target-i386: exception handling for memory helpers
target-i386: exception handling for seg_helper functions
target-i386: exception handling for other helper functions
target-ppc: exceptions handling in icount mode
cpu-exec.c | 9 include/exec/cpu_ldst.h | 19 - include/exec/cpu_ldst_template.h | 59 ++- include/exec/cpu_ldst_useronly_template.h | 25 + include/exec/exec-all.h | 1 softmmu_template.h | 22 - target-i386/cc_helper.c | 2 target-i386/cpu.h | 4 target-i386/excp_helper.c | 30 + target-i386/fpu_helper.c | 164 ++++---- target-i386/helper.h | 4 target-i386/int_helper.c | 32 +- target-i386/mem_helper.c | 39 +- target-i386/misc_helper.c | 8 target-i386/ops_sse.h | 2 target-i386/seg_helper.c | 616 +++++++++++++++-------------- target-i386/translate.c | 77 ---- target-mips/cpu.h | 23 + target-mips/helper.h | 1 target-mips/msa_helper.c | 158 ++++--- target-mips/op_helper.c | 169 ++++---- target-mips/translate.c | 363 ++++++++--------- target-ppc/cpu.h | 3 target-ppc/excp_helper.c | 38 +- target-ppc/fpu_helper.c | 191 +++++---- target-ppc/helper.h | 1 target-ppc/mem_helper.c | 6 target-ppc/misc_helper.c | 8 target-ppc/mmu-hash64.c | 12 - target-ppc/mmu_helper.c | 18 - target-ppc/timebase_helper.c | 20 - target-ppc/translate.c | 84 ---- tcg/tcg.h | 23 + 33 files changed, 1126 insertions(+), 1105 deletions(-)
Signature · 1 line
Pavel Dovgalyuk
PATCH v7 1/11 softmmu: add helper function to pass through retaddr
This patch introduces several helpers to pass return address which points to the TB. Correct return address allows correct restoring of the guest PC and icount. These functions should be used when helpers embedded into TB invoke memory operations.
--- include/exec/cpu_ldst_template.h | 59 +++++++++++++++++++++++++---- include/exec/cpu_ldst_useronly_template.h | 25 ++++++++++++ softmmu_template.h | 6 --- tcg/tcg.h | 23 +++++++++++ 4 files changed, 99 insertions(+), 14 deletions(-)
include/exec/cpu_ldst_template.h +51 -8
@@ -27,20 +27,24 @@#define SUFFIX q#define USUFFIX q#define DATA_TYPE uint64_t +#define SHIFT 3#elif DATA_SIZE ==4 #define SUFFIX l#define USUFFIX l#define DATA_TYPE uint32_t +#define SHIFT 2#elif DATA_SIZE ==2 #define SUFFIX w#define USUFFIX uw#define DATA_TYPE uint16_t#define DATA_STYPE int16_t +#define SHIFT 1#elif DATA_SIZE ==1 #define SUFFIX b#define USUFFIX ub#define DATA_TYPE uint8_t#define DATA_STYPE int8_t +#define SHIFT 0#else #error unsupported data size#endif
@@ -54,27 +58,36 @@#ifdef SOFTMMU_CODE_ACCESS #define ADDR_READ addr_code#define MMUSUFFIX _cmmu +#define URETSUFFIX SUFFIX +#define SRETSUFFIX SUFFIX#else #define ADDR_READ addr_read#define MMUSUFFIX _mmu +#define URETSUFFIX USUFFIX +#define SRETSUFFIX glue(s, SUFFIX)#endif /* generic load/store macros */ static inline RES_TYPE -glue (glue (cpu_ld ,USUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr) +glue (glue (glue (cpu_ld ,USUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +uintptr_t retaddr) {int page_index;RES_TYPE res;target_ulong addr;int mmu_idx; +TCGMemOpIdx oi; addr = ptr; page_index = (addr >>TARGET_PAGE_BITS ) & (CPU_TLB_SIZE -1 ); mmu_idx =CPU_MMU_INDEX ;if (unlikely (env->tlb_table[mmu_idx][page_index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE -1 ))))) { - res =glue (glue (helper_ld,SUFFIX ),MMUSUFFIX )(env, addr, mmu_idx); + oi =make_memop_idx (SHIFT , mmu_idx); + res =glue (glue (helper_ret_ld,URETSUFFIX ),MMUSUFFIX )(env, addr, + oi, retaddr); }else {uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res =glue (glue (ld,USUFFIX ), _p)((uint8_t *)hostaddr);
@@ -82,27 +95,43 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)return res; } +static inline RES_TYPE +glue (glue (cpu_ld ,USUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr) +{ +return glue (glue (glue (cpu_ld,USUFFIX ),MEMSUFFIX ), _ra)(env, ptr,0 ); +} +#if DATA_SIZE <=2 static inline int -glue (glue (cpu_lds ,SUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr) +glue (glue (glue (cpu_lds ,SUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +uintptr_t retaddr) {int res, page_index;target_ulong addr;int mmu_idx; +TCGMemOpIdx oi; addr = ptr; page_index = (addr >>TARGET_PAGE_BITS ) & (CPU_TLB_SIZE -1 ); mmu_idx =CPU_MMU_INDEX ;if (unlikely (env->tlb_table[mmu_idx][page_index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE -1 ))))) { - res = (DATA_STYPE )glue (glue (helper_ld,SUFFIX ), -MMUSUFFIX )(env, addr, mmu_idx); + oi =make_memop_idx (SHIFT , mmu_idx); + res = (DATA_STYPE )glue (glue (helper_ret_ld,SRETSUFFIX ), +MMUSUFFIX )(env, addr, oi, retaddr); }else {uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res =glue (glue (lds,SUFFIX ), _p)((uint8_t *)hostaddr); }return res; } + +static inline int +glue (glue (cpu_lds ,SUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr) +{ +return glue (glue (glue (cpu_lds,SUFFIX ),MEMSUFFIX ), _ra)(env, ptr,0 ); +}#endif #ifndef SOFTMMU_CODE_ACCESS
@@ -110,25 +139,36 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)/* generic store macro */ static inline void -glue (glue (cpu_st ,SUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr, -RES_TYPE v) +glue (glue (glue (cpu_st ,SUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +RES_TYPE v,uintptr_t retaddr) {int page_index;target_ulong addr;int mmu_idx; +TCGMemOpIdx oi; addr = ptr; page_index = (addr >>TARGET_PAGE_BITS ) & (CPU_TLB_SIZE -1 ); mmu_idx =CPU_MMU_INDEX ;if (unlikely (env->tlb_table[mmu_idx][page_index].addr_write != (addr & (TARGET_PAGE_MASK | (DATA_SIZE -1 ))))) { -glue (glue (helper_st,SUFFIX ),MMUSUFFIX )(env, addr, v, mmu_idx); + oi =make_memop_idx (SHIFT , mmu_idx); +glue (glue (helper_ret_st,SUFFIX ),MMUSUFFIX )(env, addr, v, oi, + retaddr); }else {uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;glue (glue (st,SUFFIX ), _p)((uint8_t *)hostaddr, v); } } +static inline void +glue (glue (cpu_st ,SUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr, +RES_TYPE v) +{ +glue (glue (glue (cpu_st,SUFFIX ),MEMSUFFIX ), _ra)(env, ptr, v,0 ); +} +#endif /* !SOFTMMU_CODE_ACCESS */ #undef RES_TYPE
@@ -139,3 +179,6 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr,#undef DATA_SIZE#undef MMUSUFFIX#undef ADDR_READ +#undef URETSUFFIX +#undef SRETSUFFIX +#undef SHIFT
include/exec/cpu_ldst_useronly_template.h +25 -0
@@ -56,12 +56,28 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)return glue (glue (ld,USUFFIX ), _p)(g2h (ptr)); } +static inline RES_TYPE +glue (glue (glue (cpu_ld ,USUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +uintptr_t retaddr) +{ +return glue (glue (cpu_ld,USUFFIX ),MEMSUFFIX )(env, ptr); +} +#if DATA_SIZE <=2 static inline int glue (glue (cpu_lds ,SUFFIX ),MEMSUFFIX )(CPUArchState *env,target_ulong ptr) {return glue (glue (lds,SUFFIX ), _p)(g2h (ptr)); } + +static inline int +glue (glue (glue (cpu_lds ,SUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +uintptr_t retaddr) +{ +return glue (glue (cpu_lds,SUFFIX ),MEMSUFFIX )(env, ptr); +}#endif #ifndef CODE_ACCESS
@@ -71,6 +87,15 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr, {glue (glue (st,SUFFIX ), _p)(g2h (ptr), v); } + +static inline void +glue (glue (glue (cpu_st ,SUFFIX ),MEMSUFFIX ),_ra )(CPUArchState *env, +target_ulong ptr, +RES_TYPE v, +uintptr_t retaddr) +{ +glue (glue (cpu_st,SUFFIX ),MEMSUFFIX )(env, ptr, v); +}#endif #undef RES_TYPE
softmmu_template.h +0 -6
@@ -165,9 +165,6 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, }#endif -#ifdef SOFTMMU_CODE_ACCESS -static __attribute__((unused)) -#endifWORD_TYPE helper_le_ld_name (CPUArchState *env,target_ulong addr,TCGMemOpIdx oi,uintptr_t retaddr) {
@@ -252,9 +249,6 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, }#if DATA_SIZE >1 -#ifdef SOFTMMU_CODE_ACCESS -static __attribute__((unused)) -#endifWORD_TYPE helper_be_ld_name (CPUArchState *env,target_ulong addr,TCGMemOpIdx oi,uintptr_t retaddr) {
tcg/tcg.h +23 -0
@@ -983,25 +983,48 @@ void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,void helper_be_stq_mmu (CPUArchState *env,target_ulong addr,uint64_t val,TCGMemOpIdx oi,uintptr_t retaddr); +uint8_t helper_ret_ldb_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint16_t helper_le_ldw_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint32_t helper_le_ldl_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint64_t helper_le_ldq_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint16_t helper_be_ldw_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint32_t helper_be_ldl_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +uint64_t helper_be_ldq_cmmu (CPUArchState *env,target_ulong addr, +TCGMemOpIdx oi,uintptr_t retaddr); +/* Temporary aliases until backends are converted. */ #ifdef TARGET_WORDS_BIGENDIAN # define helper_ret_ldsw_mmu helper_be_ldsw_mmu# define helper_ret_lduw_mmu helper_be_lduw_mmu# define helper_ret_ldsl_mmu helper_be_ldsl_mmu# define helper_ret_ldul_mmu helper_be_ldul_mmu +# define helper_ret_ldl_mmu helper_be_ldul_mmu# define helper_ret_ldq_mmu helper_be_ldq_mmu# define helper_ret_stw_mmu helper_be_stw_mmu# define helper_ret_stl_mmu helper_be_stl_mmu# define helper_ret_stq_mmu helper_be_stq_mmu +# define helper_ret_ldw_cmmu helper_be_ldw_cmmu +# define helper_ret_ldl_cmmu helper_be_ldl_cmmu +# define helper_ret_ldq_cmmu helper_be_ldq_cmmu#else # define helper_ret_ldsw_mmu helper_le_ldsw_mmu# define helper_ret_lduw_mmu helper_le_lduw_mmu# define helper_ret_ldsl_mmu helper_le_ldsl_mmu# define helper_ret_ldul_mmu helper_le_ldul_mmu +# define helper_ret_ldl_mmu helper_le_ldul_mmu# define helper_ret_ldq_mmu helper_le_ldq_mmu# define helper_ret_stw_mmu helper_le_stw_mmu# define helper_ret_stl_mmu helper_le_stl_mmu# define helper_ret_stq_mmu helper_le_stq_mmu +# define helper_ret_ldw_cmmu helper_le_ldw_cmmu +# define helper_ret_ldl_cmmu helper_le_ldl_cmmu +# define helper_ret_ldq_cmmu helper_le_ldq_cmmu#endif #endif /* CONFIG_SOFTMMU */
PATCH v7 2/11 softmmu: remove now unused functions
In reply to Pavel DovgalyukNow that the cpu_ld/st_* function directly call helper_ret_ld/st, we can drop the old helper_ld/st functions.
--- include/exec/cpu_ldst.h | 19 ------------------- softmmu_template.h | 16 ---------------- 2 files changed, 0 insertions(+), 35 deletions(-)
include/exec/cpu_ldst.h +0 -19
@@ -113,25 +113,6 @@/* The memory helpers for tcg-generated code need tcg_target_long etc. */ #include "tcg.h" -uint8_t helper_ldb_mmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint16_t helper_ldw_mmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint32_t helper_ldl_mmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint64_t helper_ldq_mmu (CPUArchState *env,target_ulong addr,int mmu_idx); - -void helper_stb_mmu (CPUArchState *env,target_ulong addr, -uint8_t val,int mmu_idx); -void helper_stw_mmu (CPUArchState *env,target_ulong addr, -uint16_t val,int mmu_idx); -void helper_stl_mmu (CPUArchState *env,target_ulong addr, -uint32_t val,int mmu_idx); -void helper_stq_mmu (CPUArchState *env,target_ulong addr, -uint64_t val,int mmu_idx); - -uint8_t helper_ldb_cmmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint16_t helper_ldw_cmmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint32_t helper_ldl_cmmu (CPUArchState *env,target_ulong addr,int mmu_idx); -uint64_t helper_ldq_cmmu (CPUArchState *env,target_ulong addr,int mmu_idx); -#ifdef MMU_MODE0_SUFFIX #define CPU_MMU_INDEX 0#define MEMSUFFIX MMU_MODE0_SUFFIX
softmmu_template.h +0 -16
@@ -329,14 +329,6 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, }#endif /* DATA_SIZE > 1 */ -DATA_TYPE -glue (glue (helper_ld ,SUFFIX ),MMUSUFFIX )(CPUArchState *env,target_ulong addr, -int mmu_idx) -{ -TCGMemOpIdx oi =make_memop_idx (SHIFT , mmu_idx); -return helper_te_ld_name (env, addr, oi,GETRA ()); -} -#ifndef SOFTMMU_CODE_ACCESS /* Provide signed versions of the load routines as well. We can of course
@@ -534,14 +526,6 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, }#endif /* DATA_SIZE > 1 */ -void -glue (glue (helper_st ,SUFFIX ),MMUSUFFIX )(CPUArchState *env,target_ulong addr, -DATA_TYPE val,int mmu_idx) -{ -TCGMemOpIdx oi =make_memop_idx (SHIFT , mmu_idx); -helper_te_st_name (env, addr, val, oi,GETRA ()); -} -#if DATA_SIZE ==1 /* Probe for whether the specified guest write access is permitted. * If it is not permitted then an exception will be taken in the same
PATCH v7 3/11 cpu-exec: introduce loop exit with restore function
In reply to Pavel DovgalyukThis patch introduces loop exit function, which also restores guest CPU state according to the value of host program counter.
--- cpu-exec.c | 9 +++++++++ include/exec/exec-all.h | 1 + 2 files changed, 10 insertions(+), 0 deletions(-)
cpu-exec.c +9 -0
@@ -133,6 +133,15 @@ void cpu_loop_exit(CPUState *cpu)siglongjmp (cpu->jmp_env,1 ); } +void cpu_loop_exit_restore (CPUState *cpu,uintptr_t pc) +{ +if (pc) { +cpu_restore_state (cpu, pc); + } + cpu->current_tb =NULL ; +siglongjmp (cpu->jmp_env,1 ); +} +/* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator */
include/exec/exec-all.h +1 -0
@@ -90,6 +90,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, int cflags);void cpu_exec_init (CPUArchState *env); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); +void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);#if !defined(CONFIG_USER_ONLY )bool qemu_in_vcpu_thread (void );
PATCH v7 4/11 target-mips: improve exception handling
In reply to Pavel DovgalyukThis patch improves exception handling in MIPS.
Instructions generate several types of exceptions.
When exception is generated, it breaks the execution of the current translation block. Implementation of the exceptions handling does not correctly restore icount for the instruction which caused the exception. In most cases icount will be decreased by the value equal to the size of TB. This patch passes pointer to the translation block internals to the exception handler. It allows correct restoring of the icount value.
v3 changes:
This patch stops translation when instruction which always generates exception is translated. This improves the performance of the patched version compared to original one.
--- target-mips/cpu.h | 23 +++ target-mips/helper.h | 1 target-mips/msa_helper.c | 158 +++++++++++--------- target-mips/op_helper.c | 169 ++++++++++----------- target-mips/translate.c | 363 ++++++++++++++++++++++------------------------ 5 files changed, 359 insertions(+), 355 deletions(-)
target-mips/cpu.h +23 -0
@@ -1049,4 +1049,27 @@ static inline void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) }#endif +static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, +uint32_t exception, +int error_code, +uintptr_t pc) +{ +CPUState *cs =CPU (mips_env_get_cpu (env)); + +if (exception <EXCP_SC ) { +qemu_log ("%s: %d %d\n" , __func__, exception, error_code); + } + cs->exception_index = exception; + env->error_code = error_code; + +cpu_loop_exit_restore (cs, pc); +} + +static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, +uint32_t exception, +uintptr_t pc) +{ +do_raise_exception_err (env, exception,0 , pc); +} +#endif /* !defined (__MIPS_CPU_H__) */
target-mips/helper.h +1 -0
@@ -1,5 +1,6 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) +DEF_HELPER_1(raise_exception_debug, noreturn, env)DEF_HELPER_1 (do_semihosting, void, env)
target-mips/msa_helper.c +85 -73
586 lines not on this page · raw message
target-mips/op_helper.c +77 -92
419 lines not on this page · raw message
target-mips/translate.c +173 -190
1,414 lines not on this page · raw message
Re: [Qemu-devel] [PATCH v7 04/11] target-mips: improve exception handling
Quoted 5 lines · Pavel Dovgalyuk
target-mips/translate.c +0
-1@@ -2364,14 +2363,12 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,#if defined(TARGET_MIPS64 )case OPC_SCD :case R6_OPC_SCD : -save_cpu_state (ctx,1 );
target-mips/translate.c static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, · line 2374
Quoted 10 lines
target-mips/translate.c +0
-1op_st_scd (t1, t0, rt, ctx); opn ="scd" ;break ;#endif case OPC_SC :case R6_OPC_SC : -save_cpu_state (ctx,1 );op_st_sc (t1, t0, rt, ctx); opn ="sc" ;break ;
Wouldn't we be better off assuming that conditional stores in linux-user always take an exception (we generate fake EXCP_SC exception) and avoid retranslation? After applying these changes I observed significant impact on performance in linux-user multithreaded apps, for instance c11-atomic-exec test before the change took just 2 seconds to finish, whereas now more than 30...
Thanks,
Leon
PS: multithreaded MIPS apps fail horribly in linux-user with this patch as it's much more likely to get bitten by race conditions in translate-all.c. But "translate-all.c thread-safety" patch series seem to fix it.
Re: [Qemu-devel] [PATCH v7 04/11] target-mips: improve exception handling
Quoted 14 lines · Leon Alrae
Quoted 13 lines · Pavel Dovgalyuk
target-mips/translate.c +0
-2@@ -2364,14 +2363,12 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,#if defined(TARGET_MIPS64 )case OPC_SCD :case R6_OPC_SCD : -save_cpu_state (ctx,1 );op_st_scd (t1, t0, rt, ctx); opn ="scd" ;break ;#endif case OPC_SC :case R6_OPC_SC : -save_cpu_state (ctx,1 );op_st_sc (t1, t0, rt, ctx);
Quoted 8 lines
target-mips/translate.c static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, · line 2374
Quoted 2 lines
target-mips/translate.c +0
-0opn ="sc" ;break ;Wouldn't we be better off assuming that conditional stores in linux-user always take an exception (we generate fake
EXCP_SCexception) and avoid retranslation? After applying these changes I observed significant impact on performance in linux-user multithreaded apps, for instance c11-atomic-exec test before the change took just 2 seconds to finish, whereas now more than 30...
This really show the impact of retranslation and why we should avoid it when not necessary. Coming back to the issue here, the fact that we go through retranslation is actually due to the fact that helper_raise_exception has been changed to go through retranslation.
Given the code path between user-mode and softmmu is quite different, we definitely need a different code path wrt exception and retranslation for the two cases. That said if we want deterministic code execution (the original purpose of this patch), I don't see how we can do without forcing retranslation. Pavel, do you have an idea for that?
Aurelien
Signature · 2 lines
Aurelien Jarno GPG: 4096R/1DDD8C9B [email protected] http://www.aurel32.net
Re: [Qemu-devel] [PATCH v7 04/11] target-mips: improve exception handling
Quoted 30 lines
From: Aurelien Jarno [mailto:[email protected]]
Quoted 14 lines · Leon Alrae
Quoted 13 lines · Pavel Dovgalyuk
target-mips/translate.c +0
-2@@ -2364,14 +2363,12 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,#if defined(TARGET_MIPS64 )case OPC_SCD :case R6_OPC_SCD : -save_cpu_state (ctx,1 );op_st_scd (t1, t0, rt, ctx); opn ="scd" ;break ;#endif case OPC_SC :case R6_OPC_SC : -save_cpu_state (ctx,1 );op_st_sc (t1, t0, rt, ctx);Quoted 8 lines
target-mips/translate.c static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, · line 2374
Quoted 2 lines
target-mips/translate.c +0
-0opn ="sc" ;break ;Wouldn't we be better off assuming that conditional stores in linux-user always take an exception (we generate fake
EXCP_SCexception) and avoid retranslation? After applying these changes I observed significant impact on performance in linux-user multithreaded apps, for instance c11-atomic-exec test before the change took just 2 seconds to finish, whereas now more than 30...This really show the impact of retranslation and why we should avoid it when not necessary. Coming back to the issue here, the fact that we go through retranslation is actually due to the fact that
helper_raise_exceptionhas been changed to go through retranslation.
Quoted 5 lines
Given the code path between user-mode and softmmu is quite different, we definitely need a different code path wrt exception and retranslation for the two cases. That said if we want deterministic code execution (the original purpose of this patch), I don't see how we can do without forcing retranslation. Pavel, do you have an idea for that?
There is only one case when we can execute without retranslation - when the instruction is the last instruction in translation block. Then we can setup PC and flags before this last instruction. If the exception happens, we can just break the execution. The drawback of this method is breaking translation blocks into the smaller parts.
Pavel Dovgalyuk
Re: [Qemu-devel] [PATCH v7 04/11] target-mips: improve exception handling
Quoted 36 lines · Pavel Dovgaluk
Quoted 30 lines
From: Aurelien Jarno [mailto:[email protected]]
Quoted 14 lines · Leon Alrae
Quoted 13 lines · Pavel Dovgalyuk
(quoted diff) +0
-2@@ -2364,14 +2363,12 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, #if defined(TARGET_MIPS64) case OPC_SCD: case R6_OPC_SCD: - save_cpu_state(ctx, 1); op_st_scd(t1, t0, rt, ctx); opn = "scd"; break; #endif case OPC_SC: case R6_OPC_SC: - save_cpu_state(ctx, 1); op_st_sc(t1, t0, rt, ctx);Quoted 8 lines
Review static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, · line 2374
Quoted 2 lines
(quoted diff) +0
-0opn = "sc"; break;Wouldn't we be better off assuming that conditional stores in linux-user always take an exception (we generate fake
EXCP_SCexception) and avoid retranslation? After applying these changes I observed significant impact on performance in linux-user multithreaded apps, for instance c11-atomic-exec test before the change took just 2 seconds to finish, whereas now more than 30...This really show the impact of retranslation and why we should avoid it when not necessary. Coming back to the issue here, the fact that we go through retranslation is actually due to the fact that
helper_raise_exceptionhas been changed to go through retranslation.Quoted 5 lines
Given the code path between user-mode and softmmu is quite different, we definitely need a different code path wrt exception and retranslation for the two cases. That said if we want deterministic code execution (the original purpose of this patch), I don't see how we can do without forcing retranslation. Pavel, do you have an idea for that?
Quoted 6 lines
There is only one case when we can execute without retranslation - when the instruction is the last instruction in translation block. Then we can setup PC and flags before this last instruction. If the exception happens, we can just break the execution. The drawback of this method is breaking translation blocks into the smaller parts.
c11-atomic-exec.4 test execution time in linux-user:
* no changes:
real 0m3.039s user 0m2.976s sys 0m1.908s
* tb_lock + patch:
real 1m1.167s user 0m57.240s sys 0m36.678s
* tb_lock + patch + SC-without-retranslation:
real 0m3.016s user 0m2.988s sys 0m1.848s
I had to add tb_lock() to cpu_restore_state() in the first place, otherwise all of my multithreaded user mode tests crash QEMU with this patch.
SC-without-retranslation (the diff below) seems to improve the situation, and if I understand correctly we retain deterministic code execution. Therefore if there are no objections I'll apply this patch + SC correction to mips-next.
Thanks,
Leon
target-mips/translate.c +1 -1
@@ -2060,7 +2060,7 @@ static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx)tcg_gen_movi_tl (t0, rt | ((almask <<3 ) &0x20 )); \tcg_gen_st_tl (t0, cpu_env, offsetof(CPUMIPSState , llreg)); \tcg_gen_st_tl (arg1, cpu_env, offsetof(CPUMIPSState , llnewval)); \ -gen_helper_0e0i (raise_exception,EXCP_SC ); \ +generate_exception_end (ctx,EXCP_SC ); \gen_set_label (l2); \tcg_gen_movi_tl (t0,0 ); \gen_store_gpr (t0, rt); \
Re: [Qemu-devel] [PATCH v7 04/11] target-mips: improve exception handling
Quoted 62 lines
From: Leon Alrae [mailto:[email protected]]
Quoted 36 lines · Pavel Dovgaluk
Quoted 30 lines
From: Aurelien Jarno [mailto:[email protected]]
Quoted 14 lines · Leon Alrae
Quoted 13 lines · Pavel Dovgalyuk
(quoted diff) +0
-2@@ -2364,14 +2363,12 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, #if defined(TARGET_MIPS64) case OPC_SCD: case R6_OPC_SCD: - save_cpu_state(ctx, 1); op_st_scd(t1, t0, rt, ctx); opn = "scd"; break; #endif case OPC_SC: case R6_OPC_SC: - save_cpu_state(ctx, 1); op_st_sc(t1, t0, rt, ctx);Quoted 8 lines
Review static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, · line 2374
Quoted 2 lines
(quoted diff) +0
-0opn = "sc"; break;Wouldn't we be better off assuming that conditional stores in linux-user always take an exception (we generate fake
EXCP_SCexception) and avoid retranslation? After applying these changes I observed significant impact on performance in linux-user multithreaded apps, for instance c11-atomic-exec test before the change took just 2 seconds to finish, whereas now more than 30...This really show the impact of retranslation and why we should avoid it when not necessary. Coming back to the issue here, the fact that we go through retranslation is actually due to the fact that
helper_raise_exceptionhas been changed to go through retranslation.Quoted 5 lines
Given the code path between user-mode and softmmu is quite different, we definitely need a different code path wrt exception and retranslation for the two cases. That said if we want deterministic code execution (the original purpose of this patch), I don't see how we can do without forcing retranslation. Pavel, do you have an idea for that?
Quoted 6 lines
There is only one case when we can execute without retranslation - when the instruction is the last instruction in translation block. Then we can setup PC and flags before this last instruction. If the exception happens, we can just break the execution. The drawback of this method is breaking translation blocks into the smaller parts.
c11-atomic-exec.4 test execution time in linux-user:
* no changes:
real 0m3.039s user 0m2.976s sys 0m1.908s*
tb_lock+ patch:real 1m1.167s user 0m57.240s sys 0m36.678s*
tb_lock+ patch + SC-without-retranslation:real 0m3.016s user 0m2.988s sys 0m1.848s
Quoted 7 lines
I had to add
tb_lock()tocpu_restore_state()in the first place, otherwise all of my multithreaded user mode tests crash QEMU with this patch.SC-without-retranslation (the diff below) seems to improve the situation, and if I understand correctly we retain deterministic code execution. Therefore if there are no objections I'll apply this patch + SC correction to mips-next.
diff below implements exactly what I meant.
Pavel Dovgalyuk
Quoted 15 lines
target-mips/translate.c +1
-1@@ -2060,7 +2060,7 @@ static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \tcg_gen_st_tl (t0, cpu_env, offsetof(CPUMIPSState , llreg)); \tcg_gen_st_tl (arg1, cpu_env, offsetof(CPUMIPSState , llnewval)); \ -gen_helper_0e0i (raise_exception,EXCP_SC ); \ +generate_exception_end (ctx,EXCP_SC ); \gen_set_label (l2); \tcg_gen_movi_tl (t0,0 ); \gen_store_gpr(t0, rt); \
PATCH v7 5/11 target-i386: introduce new raise_exception functions
In reply to Pavel DovgalyukThis patch introduces new versions of raise_exception functions that receive TB return address as an argument.
--- target-i386/cpu.h | 4 ++++ target-i386/excp_helper.c | 30 +++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-)
target-i386/cpu.h +4 -0
@@ -1263,8 +1263,12 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,/* excp_helper.c */ void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index); +void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index, +uintptr_t retaddr); void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index,int error_code); +void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index, +int error_code,uintptr_t retaddr); void QEMU_NORETURN raise_interrupt(CPUX86State *nenv, int intno, int is_int,int error_code,int next_eip_addend);
target-i386/excp_helper.c +17 -13
@@ -22,14 +22,6 @@#include "sysemu/sysemu.h" #include "exec/helper-proto.h" -#if 0 -#define raise_exception_err (env, a, b) \ - do { \ - qemu_log("raise_exception line=%d\n", __LINE__); \ - (raise_exception_err)(env, a, b); \ - } while (0) -#endif -void helper_raise_interrupt (CPUX86State *env,int intno,int next_eip_addend) {raise_interrupt (env, intno,1 ,0 , next_eip_addend);
@@ -92,7 +84,8 @@ static int check_exception(CPUX86State *env, int intno, int *error_code)*/ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,int is_int,int error_code, -int next_eip_addend) +int next_eip_addend, +uintptr_t retaddr) {CPUState *cs =CPU (x86_env_get_cpu (env));
@@ -108,7 +101,7 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, env->error_code = error_code; env->exception_is_int = is_int; env->exception_next_eip = env->eip + next_eip_addend; -cpu_loop_exit (cs); +cpu_loop_exit_restore (cs, retaddr); }/* shortcuts to generate exceptions */
@@ -116,16 +109,27 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int,int error_code,int next_eip_addend) { -raise_interrupt2 (env, intno, is_int, error_code, next_eip_addend); +raise_interrupt2 (env, intno, is_int, error_code, next_eip_addend,0 ); }void raise_exception_err (CPUX86State *env,int exception_index,int error_code) { -raise_interrupt2 (env, exception_index,0 , error_code,0 ); +raise_interrupt2 (env, exception_index,0 , error_code,0 ,0 ); +} + +void raise_exception_err_ra (CPUX86State *env,int exception_index, +int error_code,uintptr_t retaddr) +{ +raise_interrupt2 (env, exception_index,0 , error_code,0 , retaddr); }void raise_exception (CPUX86State *env,int exception_index) { -raise_interrupt2 (env, exception_index,0 ,0 ,0 ); +raise_interrupt2 (env, exception_index,0 ,0 ,0 ,0 ); +} + +void raise_exception_ra (CPUX86State *env,int exception_index,uintptr_t retaddr) +{ +raise_interrupt2 (env, exception_index,0 ,0 ,0 , retaddr); }
PATCH v7 6/11 target-i386: exception handling for FPU instructions
In reply to Pavel DovgalyukThis patch fixes exception handling for FPU instructions and removes obsolete PC update from translate.c.
--- target-i386/fpu_helper.c | 164 +++++++++++++++++++++++++++------------------- target-i386/translate.c | 24 ------- 2 files changed, 95 insertions(+), 93 deletions(-)
target-i386/fpu_helper.c +95 -69
@@ -68,22 +68,24 @@ static inline void fpop(CPUX86State *env) env->fpstt = (env->fpstt +1 ) &7 ; } -static inline floatx80 helper_fldt (CPUX86State *env,target_ulong ptr) +static inline floatx80 helper_fldt (CPUX86State *env,target_ulong ptr, +uintptr_t retaddr) {CPU_LDoubleU temp; - temp.l.lower =cpu_ldq_data (env, ptr); - temp.l.upper =cpu_lduw_data (env, ptr +8 ); + temp.l.lower =cpu_ldq_data_ra (env, ptr, retaddr); + temp.l.upper =cpu_lduw_data_ra (env, ptr +8 , retaddr);return temp.d; } -static inline void helper_fstt (CPUX86State *env,floatx80 f,target_ulong ptr) +static inline void helper_fstt (CPUX86State *env,floatx80 f,target_ulong ptr, +uintptr_t retaddr) {CPU_LDoubleU temp; temp.d = f; -cpu_stq_data (env, ptr, temp.l.lower); -cpu_stw_data (env, ptr +8 , temp.l.upper); +cpu_stq_data_ra (env, ptr, temp.l.lower, retaddr); +cpu_stw_data_ra (env, ptr +8 , temp.l.upper, retaddr); }/* x87 FPU helpers */
@@ -126,10 +128,10 @@ static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)return floatx80_div (a, b, &env->fp_status); } -static void fpu_raise_exception (CPUX86State *env) +static void fpu_raise_exception (CPUX86State *env,uintptr_t retaddr) {if (env->cr[0 ] &CR0_NE_MASK ) { -raise_exception (env,EXCP10_COPR ); +raise_exception_ra (env,EXCP10_COPR , retaddr); }#if !defined(CONFIG_USER_ONLY ) else {
@@ -314,14 +316,14 @@ void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)int new_fpstt; new_fpstt = (env->fpstt -1 ) &7 ; - env->fpregs[new_fpstt].d =helper_fldt (env, ptr); + env->fpregs[new_fpstt].d =helper_fldt (env, ptr,GETPC ()); env->fpstt = new_fpstt; env->fptags[new_fpstt] =0 ;/* validate stack entry */ }void helper_fstt_ST0 (CPUX86State *env,target_ulong ptr) { -helper_fstt (env,ST0 , ptr); +helper_fstt (env,ST0 , ptr,GETPC ()); }void helper_fpush (CPUX86State *env)
@@ -604,7 +606,7 @@ void helper_fclex(CPUX86State *env)void helper_fwait (CPUX86State *env) {if (env->fpus &FPUS_SE ) { -fpu_raise_exception (env); +fpu_raise_exception (env,GETPC ()); } }
@@ -634,11 +636,11 @@ void helper_fbld_ST0(CPUX86State *env, target_ulong ptr) val =0 ;for (i =8 ; i >=0 ; i--) { - v =cpu_ldub_data (env, ptr + i); + v =cpu_ldub_data_ra (env, ptr + i,GETPC ()); val = (val *100 ) + ((v >>4 ) *10 ) + (v &0xf ); } tmp =int64_to_floatx80 (val, &env->fp_status); -if (cpu_ldub_data (env, ptr +9 ) &0x80 ) { +if (cpu_ldub_data_ra (env, ptr +9 ,GETPC ()) &0x80 ) { tmp =floatx80_chs (tmp); }fpush (env);
@@ -655,10 +657,10 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) mem_ref = ptr; mem_end = mem_ref +9 ;if (val <0 ) { -cpu_stb_data (env, mem_end,0x80 ); +cpu_stb_data_ra (env, mem_end,0x80 ,GETPC ()); val = -val; }else { -cpu_stb_data (env, mem_end,0x00 ); +cpu_stb_data_ra (env, mem_end,0x00 ,GETPC ()); }while (mem_ref < mem_end) {if (val ==0 ) {
@@ -667,10 +669,10 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) v = val %100 ; val = val /100 ; v = ((v /10 ) <<4 ) | (v %10 ); -cpu_stb_data (env, mem_ref++, v); +cpu_stb_data_ra (env, mem_ref++, v,GETPC ()); }while (mem_ref < mem_end) { -cpu_stb_data (env, mem_ref++,0 ); +cpu_stb_data_ra (env, mem_ref++,0 ,GETPC ()); } }
@@ -978,7 +980,8 @@ void helper_fxam_ST0(CPUX86State *env) } } -void helper_fstenv (CPUX86State *env,target_ulong ptr,int data32) +static void do_fstenv (CPUX86State *env,target_ulong ptr,int data32, +uintptr_t retaddr) {int fpus, fptag, exp, i;uint64_t mant;
@@ -1006,37 +1009,43 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32) }if (data32) {/* 32 bit */ -cpu_stl_data (env, ptr, env->fpuc); -cpu_stl_data (env, ptr +4 , fpus); -cpu_stl_data (env, ptr +8 , fptag); -cpu_stl_data (env, ptr +12 ,0 );/* fpip */ -cpu_stl_data (env, ptr +16 ,0 );/* fpcs */ -cpu_stl_data (env, ptr +20 ,0 );/* fpoo */ -cpu_stl_data (env, ptr +24 ,0 );/* fpos */ +cpu_stl_data_ra (env, ptr, env->fpuc, retaddr); +cpu_stl_data_ra (env, ptr +4 , fpus, retaddr); +cpu_stl_data_ra (env, ptr +8 , fptag, retaddr); +cpu_stl_data_ra (env, ptr +12 ,0 , retaddr);/* fpip */ +cpu_stl_data_ra (env, ptr +16 ,0 , retaddr);/* fpcs */ +cpu_stl_data_ra (env, ptr +20 ,0 , retaddr);/* fpoo */ +cpu_stl_data_ra (env, ptr +24 ,0 , retaddr);/* fpos */ }else {/* 16 bit */ -cpu_stw_data (env, ptr, env->fpuc); -cpu_stw_data (env, ptr +2 , fpus); -cpu_stw_data (env, ptr +4 , fptag); -cpu_stw_data (env, ptr +6 ,0 ); -cpu_stw_data (env, ptr +8 ,0 ); -cpu_stw_data (env, ptr +10 ,0 ); -cpu_stw_data (env, ptr +12 ,0 ); +cpu_stw_data_ra (env, ptr, env->fpuc, retaddr); +cpu_stw_data_ra (env, ptr +2 , fpus, retaddr); +cpu_stw_data_ra (env, ptr +4 , fptag, retaddr); +cpu_stw_data_ra (env, ptr +6 ,0 , retaddr); +cpu_stw_data_ra (env, ptr +8 ,0 , retaddr); +cpu_stw_data_ra (env, ptr +10 ,0 , retaddr); +cpu_stw_data_ra (env, ptr +12 ,0 , retaddr); } } -void helper_fldenv (CPUX86State *env,target_ulong ptr,int data32) +void helper_fstenv (CPUX86State *env,target_ulong ptr,int data32) +{ +do_fstenv (env, ptr, data32,GETPC ()); +} + +static void do_fldenv (CPUX86State *env,target_ulong ptr,int data32, +uintptr_t retaddr) {int i, fpus, fptag;if (data32) { -cpu_set_fpuc (env,cpu_lduw_data (env, ptr)); - fpus =cpu_lduw_data (env, ptr +4 ); - fptag =cpu_lduw_data (env, ptr +8 ); +cpu_set_fpuc (env,cpu_lduw_data_ra (env, ptr, retaddr)); + fpus =cpu_lduw_data_ra (env, ptr +4 , retaddr); + fptag =cpu_lduw_data_ra (env, ptr +8 , retaddr); }else { -cpu_set_fpuc (env,cpu_lduw_data (env, ptr)); - fpus =cpu_lduw_data (env, ptr +2 ); - fptag =cpu_lduw_data (env, ptr +4 ); +cpu_set_fpuc (env,cpu_lduw_data_ra (env, ptr, retaddr)); + fpus =cpu_lduw_data_ra (env, ptr +2 , retaddr); + fptag =cpu_lduw_data_ra (env, ptr +4 , retaddr); } env->fpstt = (fpus >>11 ) &7 ; env->fpus = fpus & ~0x3800 ;
@@ -1046,17 +1055,22 @@ void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32) } } +void helper_fldenv (CPUX86State *env,target_ulong ptr,int data32) +{ +do_fldenv (env, ptr, data32,GETPC ()); +} +void helper_fsave (CPUX86State *env,target_ulong ptr,int data32) {floatx80 tmp;int i; -helper_fstenv (env, ptr, data32); +do_fstenv (env, ptr, data32,GETPC ()); ptr += (14 << data32);for (i =0 ; i <8 ; i++) { tmp =ST (i); -helper_fstt (env, tmp, ptr); +helper_fstt (env, tmp, ptr,GETPC ()); ptr +=10 ; }
@@ -1079,11 +1093,11 @@ void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)floatx80 tmp;int i; -helper_fldenv (env, ptr, data32); +do_fldenv (env, ptr, data32,GETPC ()); ptr += (14 << data32);for (i =0 ; i <8 ; i++) { - tmp =helper_fldt (env, ptr); + tmp =helper_fldt (env, ptr,GETPC ());ST (i) = tmp; ptr +=10 ; }
@@ -1101,7 +1115,8 @@ void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) }#endif -void helper_fxsave (CPUX86State *env,target_ulong ptr,int data64) +static void do_fxsave (CPUX86State *env,target_ulong ptr,int data64, +uintptr_t retaddr) {int fpus, fptag, i, nb_xmm_regs;floatx80 tmp;
@@ -1109,7 +1124,7 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)/* The operand must be 16 byte aligned */ if (ptr &0xf ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF , retaddr); } fpus = (env->fpus & ~0x3800 ) | (env->fpstt &0x7 ) <<11 ;
@@ -1117,33 +1132,33 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)for (i =0 ; i <8 ; i++) { fptag |= (env->fptags[i] << i); } -cpu_stw_data (env, ptr, env->fpuc); -cpu_stw_data (env, ptr +2 , fpus); -cpu_stw_data (env, ptr +4 , fptag ^0xff ); +cpu_stw_data_ra (env, ptr, env->fpuc, retaddr); +cpu_stw_data_ra (env, ptr +2 , fpus, retaddr); +cpu_stw_data_ra (env, ptr +4 , fptag ^0xff , retaddr);#ifdef TARGET_X86_64 if (data64) { -cpu_stq_data (env, ptr +0x08 ,0 );/* rip */ -cpu_stq_data (env, ptr +0x10 ,0 );/* rdp */ +cpu_stq_data_ra (env, ptr +0x08 ,0 , retaddr);/* rip */ +cpu_stq_data_ra (env, ptr +0x10 ,0 , retaddr);/* rdp */ } else#endif { -cpu_stl_data (env, ptr +0x08 ,0 );/* eip */ -cpu_stl_data (env, ptr +0x0c ,0 );/* sel */ -cpu_stl_data (env, ptr +0x10 ,0 );/* dp */ -cpu_stl_data (env, ptr +0x14 ,0 );/* sel */ +cpu_stl_data_ra (env, ptr +0x08 ,0 , retaddr);/* eip */ +cpu_stl_data_ra (env, ptr +0x0c ,0 , retaddr);/* sel */ +cpu_stl_data_ra (env, ptr +0x10 ,0 , retaddr);/* dp */ +cpu_stl_data_ra (env, ptr +0x14 ,0 , retaddr);/* sel */ } addr = ptr +0x20 ;for (i =0 ; i <8 ; i++) { tmp =ST (i); -helper_fstt (env, tmp, addr); +helper_fstt (env, tmp, addr, retaddr); addr +=16 ; }if (env->cr[4 ] &CR4_OSFXSR_MASK ) {/* XXX: finish it */ -cpu_stl_data (env, ptr +0x18 , env->mxcsr);/* mxcsr */ -cpu_stl_data (env, ptr +0x1c ,0x0000ffff );/* mxcsr_mask */ +cpu_stl_data_ra (env, ptr +0x18 , env->mxcsr, retaddr);/* mxcsr */ +cpu_stl_data_ra (env, ptr +0x1c ,0x0000ffff , retaddr);/* mxcsr_mask */ if (env->hflags &HF_CS64_MASK ) { nb_xmm_regs =16 ; }else {
@@ -1155,15 +1170,21 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64) || (env->hflags & HF_CPL_MASK) || !(env->hflags & HF_LMA_MASK)) {for (i =0 ; i < nb_xmm_regs; i++) { -cpu_stq_data (env, addr, env->xmm_regs[i].XMM_Q (0 )); -cpu_stq_data (env, addr +8 , env->xmm_regs[i].XMM_Q (1 )); +cpu_stq_data_ra (env, addr, env->xmm_regs[i].XMM_Q (0 ), retaddr); +cpu_stq_data_ra (env, addr +8 , env->xmm_regs[i].XMM_Q (1 ), retaddr); addr +=16 ; } } } } -void helper_fxrstor (CPUX86State *env,target_ulong ptr,int data64) +void helper_fxsave (CPUX86State *env,target_ulong ptr,int data64) +{ +do_fxsave (env, ptr, data64,GETPC ()); +} + +static void do_fxrstor (CPUX86State *env,target_ulong ptr,int data64, +uintptr_t retaddr) {int i, fpus, fptag, nb_xmm_regs;floatx80 tmp;
@@ -1171,12 +1192,12 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)/* The operand must be 16 byte aligned */ if (ptr &0xf ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF , retaddr); } -cpu_set_fpuc (env,cpu_lduw_data (env, ptr)); - fpus =cpu_lduw_data (env, ptr +2 ); - fptag =cpu_lduw_data (env, ptr +4 ); +cpu_set_fpuc (env,cpu_lduw_data_ra (env, ptr, retaddr)); + fpus =cpu_lduw_data_ra (env, ptr +2 , retaddr); + fptag =cpu_lduw_data_ra (env, ptr +4 , retaddr); env->fpstt = (fpus >>11 ) &7 ; env->fpus = fpus & ~0x3800 ; fptag ^=0xff ;
@@ -1186,15 +1207,15 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64) addr = ptr +0x20 ;for (i =0 ; i <8 ; i++) { - tmp =helper_fldt (env, addr); + tmp =helper_fldt (env, addr, retaddr);ST (i) = tmp; addr +=16 ; }if (env->cr[4 ] &CR4_OSFXSR_MASK ) {/* XXX: finish it */ -cpu_set_mxcsr (env,cpu_ldl_data (env, ptr +0x18 )); -/* cpu_ldl_data(env, ptr + 0x1c); */ +cpu_set_mxcsr (env,cpu_ldl_data_ra (env, ptr +0x18 , retaddr)); +/* cpu_ldl_data_ra(env, ptr + 0x1c, retaddr); */ if (env->hflags &HF_CS64_MASK ) { nb_xmm_regs =16 ; }else {
@@ -1206,14 +1227,19 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64) || (env->hflags & HF_CPL_MASK) || !(env->hflags & HF_LMA_MASK)) {for (i =0 ; i < nb_xmm_regs; i++) { - env->xmm_regs[i].XMM_Q (0 ) =cpu_ldq_data (env, addr); - env->xmm_regs[i].XMM_Q (1 ) =cpu_ldq_data (env, addr +8 ); + env->xmm_regs[i].XMM_Q (0 ) =cpu_ldq_data_ra (env, addr, retaddr); + env->xmm_regs[i].XMM_Q (1 ) =cpu_ldq_data_ra (env, addr +8 , retaddr); addr +=16 ; } } } } +void helper_fxrstor (CPUX86State *env,target_ulong ptr,int data64) +{ +do_fxrstor (env, ptr, data64,GETPC ()); +} +void cpu_get_fp80 (uint64_t *pmant,uint16_t *pexp,floatx80 f) {CPU_LDoubleU temp;
target-i386/translate.c +0 -24
@@ -5837,8 +5837,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, }break ;case 0x0c :/* fldenv mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fldenv (cpu_env, cpu_A0,tcg_const_i32 (dflag -1 ));break ;case 0x0d :/* fldcw mem */
@@ -5847,8 +5845,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,gen_helper_fldcw (cpu_env, cpu_tmp2_i32);break ;case 0x0e :/* fnstenv mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fstenv (cpu_env, cpu_A0,tcg_const_i32 (dflag -1 ));break ;case 0x0f :/* fnstcw mem */
@@ -5857,24 +5853,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->mem_index, MO_LEUW);break ;case 0x1d :/* fldt mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fldt_ST0 (cpu_env, cpu_A0);break ;case 0x1f :/* fstpt mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fstt_ST0 (cpu_env, cpu_A0);gen_helper_fpop (cpu_env);break ;case 0x2c :/* frstor mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_frstor (cpu_env, cpu_A0,tcg_const_i32 (dflag -1 ));break ;case 0x2e :/* fnsave mem */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fsave (cpu_env, cpu_A0,tcg_const_i32 (dflag -1 ));break ;case 0x2f :/* fnstsw mem */
@@ -5883,13 +5871,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->mem_index, MO_LEUW);break ;case 0x3c :/* fbld */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fbld_ST0 (cpu_env, cpu_A0);break ;case 0x3e :/* fbstp */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fbst_ST0 (cpu_env, cpu_A0);gen_helper_fpop (cpu_env);break ;
@@ -5924,8 +5908,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,switch (rm) {case 0 :/* fnop */ /* check exceptions (FreeBSD FPU probe) */ -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fwait (cpu_env);break ;default :
@@ -6895,8 +6877,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, (HF_MP_MASK | HF_TS_MASK)) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); } else { -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fwait (cpu_env); }break ;
@@ -7726,8 +7706,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,break ; }gen_lea_modrm (env, s, modrm); -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fxsave (cpu_env, cpu_A0,tcg_const_i32 (dflag ==MO_64 ));break ;case 1 :/* fxrstor */
@@ -7739,8 +7717,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,break ; }gen_lea_modrm (env, s, modrm); -gen_update_cc_op (s); -gen_jmp_im (pc_start - s->cs_base);gen_helper_fxrstor (cpu_env, cpu_A0,tcg_const_i32 (dflag ==MO_64 ));break ;case 2 :/* ldmxcsr */
PATCH v7 7/11 target-i386: exception handling for div instructions
In reply to Pavel DovgalyukThis patch fixes exception handling for div instructions and removes obsolete PC update from translate.c.
--- target-i386/int_helper.c | 32 ++++++++++++++++---------------- target-i386/translate.c | 8 -------- 2 files changed, 16 insertions(+), 24 deletions(-)
target-i386/int_helper.c +16 -16
@@ -48,11 +48,11 @@ void helper_divb_AL(CPUX86State *env, target_ulong t0) num = (env->regs[R_EAX ] &0xffff ); den = (t0 &0xff );if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den);if (q >0xff ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q &=0xff ; r = (num % den) &0xff ;
@@ -66,11 +66,11 @@ void helper_idivb_AL(CPUX86State *env, target_ulong t0) num = (int16_t )env->regs[R_EAX ]; den = (int8_t )t0;if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den);if (q != (int8_t )q) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q &=0xff ; r = (num % den) &0xff ;
@@ -84,11 +84,11 @@ void helper_divw_AX(CPUX86State *env, target_ulong t0) num = (env->regs[R_EAX ] &0xffff ) | ((env->regs[R_EDX ] &0xffff ) <<16 ); den = (t0 &0xffff );if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den);if (q >0xffff ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q &=0xffff ; r = (num % den) &0xffff ;
@@ -103,11 +103,11 @@ void helper_idivw_AX(CPUX86State *env, target_ulong t0) num = (env->regs[R_EAX ] &0xffff ) | ((env->regs[R_EDX ] &0xffff ) <<16 ); den = (int16_t )t0;if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den);if (q != (int16_t )q) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q &=0xffff ; r = (num % den) &0xffff ;
@@ -123,12 +123,12 @@ void helper_divl_EAX(CPUX86State *env, target_ulong t0) num = ((uint32_t )env->regs[R_EAX ]) | ((uint64_t )((uint32_t )env->regs[R_EDX ]) <<32 ); den = t0;if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den); r = (num % den);if (q >0xffffffff ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } env->regs[R_EAX ] = (uint32_t )q; env->regs[R_EDX ] = (uint32_t )r;
@@ -142,12 +142,12 @@ void helper_idivl_EAX(CPUX86State *env, target_ulong t0) num = ((uint32_t )env->regs[R_EAX ]) | ((uint64_t )((uint32_t )env->regs[R_EDX ]) <<32 ); den = t0;if (den ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } q = (num / den); r = (num % den);if (q != (int32_t )q) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } env->regs[R_EAX ] = (uint32_t )q; env->regs[R_EDX ] = (uint32_t )r;
@@ -379,12 +379,12 @@ void helper_divq_EAX(CPUX86State *env, target_ulong t0)uint64_t r0, r1;if (t0 ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } r0 = env->regs[R_EAX ]; r1 = env->regs[R_EDX ];if (div64 (&r0, &r1, t0)) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } env->regs[R_EAX ] = r0; env->regs[R_EDX ] = r1;
@@ -395,12 +395,12 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0)uint64_t r0, r1;if (t0 ==0 ) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } r0 = env->regs[R_EAX ]; r1 = env->regs[R_EDX ];if (idiv64 (&r0, &r1, t0)) { -raise_exception (env,EXCP00_DIVZ ); +raise_exception_ra (env,EXCP00_DIVZ ,GETPC ()); } env->regs[R_EAX ] = r0; env->regs[R_EDX ] = r1;
target-i386/translate.c +0 -8
@@ -4842,21 +4842,17 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,case 6 :/* div */ switch (ot) {case MO_8 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_divb_AL (cpu_env, cpu_T[0 ]);break ;case MO_16 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_divw_AX (cpu_env, cpu_T[0 ]);break ;default :case MO_32 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_divl_EAX (cpu_env, cpu_T[0 ]);break ;#ifdef TARGET_X86_64 case MO_64 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_divq_EAX (cpu_env, cpu_T[0 ]);break ;#endif
@@ -4865,21 +4861,17 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,case 7 :/* idiv */ switch (ot) {case MO_8 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_idivb_AL (cpu_env, cpu_T[0 ]);break ;case MO_16 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_idivw_AX (cpu_env, cpu_T[0 ]);break ;default :case MO_32 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_idivl_EAX (cpu_env, cpu_T[0 ]);break ;#ifdef TARGET_X86_64 case MO_64 : -gen_jmp_im (pc_start - s->cs_base);gen_helper_idivq_EAX (cpu_env, cpu_T[0 ]);break ;#endif
PATCH v7 8/11 target-i386: exception handling for memory helpers
In reply to Pavel DovgalyukThis patch fixes exception handling for memory helpers and removes obsolete PC update from translate.c.
--- target-i386/mem_helper.c | 39 ++++++++++++++++++--------------------- target-i386/translate.c | 3 --- 2 files changed, 18 insertions(+), 24 deletions(-)
target-i386/mem_helper.c +18 -21
@@ -41,13 +41,14 @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)int eflags; eflags =cpu_cc_compute_all (env,CC_OP ); - d =cpu_ldq_data (env, a0); + d =cpu_ldq_data_ra (env, a0,GETPC ());if (d == (((uint64_t )env->regs[R_EDX ] <<32 ) | (uint32_t )env->regs[R_EAX ])) { -cpu_stq_data (env, a0, ((uint64_t )env->regs[R_ECX ] <<32 ) | (uint32_t )env->regs[R_EBX ]); +cpu_stq_data_ra (env, a0, ((uint64_t )env->regs[R_ECX ] <<32 ) + | (uint32_t )env->regs[R_EBX ],GETPC ()); eflags |=CC_Z ; }else {/* always do the store */ -cpu_stq_data (env, a0, d); +cpu_stq_data_ra (env, a0, d,GETPC ()); env->regs[R_EDX ] = (uint32_t )(d >>32 ); env->regs[R_EAX ] = (uint32_t )d; eflags &= ~CC_Z ;
@@ -62,19 +63,19 @@ void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)int eflags;if ((a0 &0xf ) !=0 ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); } eflags =cpu_cc_compute_all (env,CC_OP ); - d0 =cpu_ldq_data (env, a0); - d1 =cpu_ldq_data (env, a0 +8 ); + d0 =cpu_ldq_data_ra (env, a0,GETPC ()); + d1 =cpu_ldq_data_ra (env, a0 +8 ,GETPC ());if (d0 == env->regs[R_EAX ] && d1 == env->regs[R_EDX ]) { -cpu_stq_data (env, a0, env->regs[R_EBX ]); -cpu_stq_data (env, a0 +8 , env->regs[R_ECX ]); +cpu_stq_data_ra (env, a0, env->regs[R_EBX ],GETPC ()); +cpu_stq_data_ra (env, a0 +8 , env->regs[R_ECX ],GETPC ()); eflags |=CC_Z ; }else {/* always do the store */ -cpu_stq_data (env, a0, d0); -cpu_stq_data (env, a0 +8 , d1); +cpu_stq_data_ra (env, a0, d0,GETPC ()); +cpu_stq_data_ra (env, a0 +8 , d1,GETPC ()); env->regs[R_EDX ] = d1; env->regs[R_EAX ] = d0; eflags &= ~CC_Z ;
@@ -87,11 +88,11 @@ void helper_boundw(CPUX86State *env, target_ulong a0, int v) {int low, high; - low =cpu_ldsw_data (env, a0); - high =cpu_ldsw_data (env, a0 +2 ); + low =cpu_ldsw_data_ra (env, a0,GETPC ()); + high =cpu_ldsw_data_ra (env, a0 +2 ,GETPC ()); v = (int16_t )v;if (v < low || v > high) { -raise_exception (env,EXCP05_BOUND ); +raise_exception_ra (env,EXCP05_BOUND ,GETPC ()); } }
@@ -99,10 +100,10 @@ void helper_boundl(CPUX86State *env, target_ulong a0, int v) {int low, high; - low =cpu_ldl_data (env, a0); - high =cpu_ldl_data (env, a0 +4 ); + low =cpu_ldl_data_ra (env, a0,GETPC ()); + high =cpu_ldl_data_ra (env, a0 +4 ,GETPC ());if (v < low || v > high) { -raise_exception (env,EXCP05_BOUND ); +raise_exception_ra (env,EXCP05_BOUND ,GETPC ()); } }
@@ -122,11 +123,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,X86CPU *cpu =X86_CPU (cs);CPUX86State *env = &cpu->env; -if (retaddr) { -/* now we have a real cpu fault */ -cpu_restore_state (cs, retaddr); - } - raise_exception_err(env, cs->exception_index, env->error_code); + raise_exception_err_ra(env, cs->exception_index, env->error_code, retaddr); } }#endif
target-i386/translate.c +0 -3
@@ -5204,7 +5204,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,if (dflag ==MO_64 ) {if (!(s->cpuid_ext_features &CPUID_EXT_CX16 )) goto illegal_op; -gen_jmp_im (pc_start - s->cs_base);gen_update_cc_op (s);gen_lea_modrm (env, s, modrm);gen_helper_cmpxchg16b (cpu_env, cpu_A0);
@@ -5213,7 +5212,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, {if (!(s->cpuid_features &CPUID_CX8 )) goto illegal_op; -gen_jmp_im (pc_start - s->cs_base);gen_update_cc_op (s);gen_lea_modrm (env, s, modrm);gen_helper_cmpxchg8b (cpu_env, cpu_A0);
@@ -6952,7 +6950,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, goto illegal_op;gen_op_mov_v_reg (ot, cpu_T[0 ], reg);gen_lea_modrm (env, s, modrm); -gen_jmp_im (pc_start - s->cs_base);tcg_gen_trunc_tl_i32 (cpu_tmp2_i32, cpu_T[0 ]);if (ot ==MO_16 ) {gen_helper_boundw (cpu_env, cpu_A0, cpu_tmp2_i32);
PATCH v7 9/11 target-i386: exception handling for seg_helper functions
In reply to Pavel DovgalyukThis patch fixes exception handling for seg_helper functions.
--- target-i386/helper.h | 4 target-i386/seg_helper.c | 616 ++++++++++++++++++++++++---------------------- target-i386/translate.c | 42 +-- 3 files changed, 335 insertions(+), 327 deletions(-)
target-i386/helper.h +2 -2
@@ -30,9 +30,9 @@ DEF_HELPER_2(verw, void, env, tl) DEF_HELPER_2(lldt, void, env, int) DEF_HELPER_2(ltr, void, env, int) DEF_HELPER_3(load_seg, void, env, int, int) -DEF_HELPER_4(ljmp_protected, void, env, int, tl, int) +DEF_HELPER_4(ljmp_protected, void, env, int, tl, tl) DEF_HELPER_5(lcall_real, void, env, int, tl, int, int) -DEF_HELPER_5(lcall_protected, void, env, int, tl, int, int) +DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl) DEF_HELPER_2(iret_real, void, env, int) DEF_HELPER_3(iret_protected, void, env, int, int)DEF_HELPER_3 (lret_protected, void, env, int, int)
target-i386/seg_helper.c +324 -292
1,390 lines not on this page · raw message
target-i386/translate.c +9 -33
142 lines not on this page · raw message
Re: [Qemu-devel] [PATCH v7 09/11] target-i386: exception handling for seg_helper functions
Quoted 8 lines · Pavel Dovgalyuk
This patch fixes exception handling for
seg_helperfunctions.Signed-off-by Pavel Dovgalyuk <[email protected]>--- target-i386/helper.h | 4 target-i386/seg_helper.c | 616 ++++++++++++++++++++++++---------------------- target-i386/translate.c | 42 +-- 3 files changed, 335 insertions(+), 327 deletions(-)
r~
PATCH v7 10/11 target-i386: exception handling for other helper functions
In reply to Pavel DovgalyukThis patch fixes exception handling for other helper functions.
--- target-i386/cc_helper.c | 2 +- target-i386/misc_helper.c | 8 ++++---- target-i386/ops_sse.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-)
target-i386/cc_helper.c +1 -1
@@ -378,7 +378,7 @@ void helper_sti_vm(CPUX86State *env) { env->eflags |=VIF_MASK ;if (env->eflags &VIP_MASK ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); } }#endif
target-i386/misc_helper.c +4 -4
@@ -220,7 +220,7 @@ void helper_rdtsc(CPUX86State *env)uint64_t val;if ((env->cr[4 ] &CR4_TSD_MASK ) && ((env->hflags &HF_CPL_MASK ) !=0 )) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); }cpu_svm_check_intercept_param (env,SVM_EXIT_RDTSC ,0 );
@@ -238,7 +238,7 @@ void helper_rdtscp(CPUX86State *env)void helper_rdpmc (CPUX86State *env) {if ((env->cr[4 ] &CR4_PCE_MASK ) && ((env->hflags &HF_CPL_MASK ) !=0 )) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); }cpu_svm_check_intercept_param (env,SVM_EXIT_RDPMC ,0 );
@@ -589,7 +589,7 @@ void helper_hlt(CPUX86State *env, int next_eip_addend)void helper_monitor (CPUX86State *env,target_ulong ptr) {if ((uint32_t )env->regs[R_ECX ] !=0 ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); }/* XXX: store address? */ cpu_svm_check_intercept_param (env,SVM_EXIT_MONITOR ,0 );
@@ -601,7 +601,7 @@ void helper_mwait(CPUX86State *env, int next_eip_addend)X86CPU *cpu;if ((uint32_t )env->regs[R_ECX ] !=0 ) { -raise_exception (env,EXCP0D_GPF ); +raise_exception_ra (env,EXCP0D_GPF ,GETPC ()); }cpu_svm_check_intercept_param (env,SVM_EXIT_MWAIT ,0 ); env->eip += next_eip_addend;
target-i386/ops_sse.h +1 -1
@@ -483,7 +483,7 @@ void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,for (i =0 ; i < (8 <<SHIFT ); i++) {if (s->B (i) &0x80 ) { -cpu_stb_data (env, a0 + i, d->B (i)); +cpu_stb_data_ra (env, a0 + i, d->B (i),GETPC ()); } } }
PATCH v7 11/11 target-ppc: exceptions handling in icount mode
In reply to Pavel DovgalyukThis patch fixes exception handling in PowerPC.
Instructions generate several types of exceptions.
When exception is generated, it breaks the execution of the current translation block. Implementation of the exceptions handling does not correctly restore icount for the instruction which caused the exception. In most cases icount will be decreased by the value equal to the size of TB. This patch passes pointer to the translation block internals to the exception handler. It allows correct restoring of the icount value.
--- target-ppc/cpu.h | 3 + target-ppc/excp_helper.c | 38 ++++++-- target-ppc/fpu_helper.c | 191 ++++++++++++++++++++++-------------------- target-ppc/helper.h | 1 target-ppc/mem_helper.c | 6 + target-ppc/misc_helper.c | 8 +- target-ppc/mmu-hash64.c | 12 +-- target-ppc/mmu_helper.c | 18 ++-- target-ppc/timebase_helper.c | 20 ++-- target-ppc/translate.c | 84 +----------------- 10 files changed, 167 insertions(+), 214 deletions(-)
target-ppc/cpu.h +3 -0
@@ -2328,4 +2328,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);*/ PowerPCCPU *ppc_get_vcpu_by_dt_id (int cpu_dt_id); +void raise_exception_err (CPUPPCState *env,uint32_t exception, +uint32_t error_code,uintptr_t pc); +#endif /* !defined (__CPU_PPC_H__) */
target-ppc/excp_helper.c +29 -9
@@ -846,8 +846,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)/*****************************************************************************/ /* Exceptions processing helpers */ -void helper_raise_exception_err (CPUPPCState *env,uint32_t exception, -uint32_t error_code) +void raise_exception_err (CPUPPCState *env,uint32_t exception, +uint32_t error_code,uintptr_t pc) {CPUState *cs =CPU (ppc_env_get_cpu (env));
@@ -856,15 +856,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,#endif cs->exception_index = exception; env->error_code = error_code; -cpu_loop_exit (cs); +cpu_loop_exit_restore (cs, pc); +} + +void helper_raise_exception_err (CPUPPCState *env,uint32_t exception, +uint32_t error_code) +{ +raise_exception_err (env, exception, error_code,GETPC ()); +} + +void helper_raise_exception_end (CPUPPCState *env,uint32_t exception, +uint32_t error_code) +{ +raise_exception_err (env, exception, error_code,0 ); }void helper_raise_exception (CPUPPCState *env,uint32_t exception) { -helper_raise_exception_err (env, exception,0 ); +raise_exception_err (env, exception,0 ,GETPC ()); }#if !defined(CONFIG_USER_ONLY ) +static void raise_exception (CPUPPCState *env,uint32_t exception,uintptr_t pc) +{ +raise_exception_err (env, exception,0 , pc); +} +void helper_store_msr (CPUPPCState *env,target_ulong val) {CPUState *cs;
@@ -873,7 +890,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)if (val !=0 ) { cs =CPU (ppc_env_get_cpu (env)); cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; -helper_raise_exception (env, val); +/* nip is updated by generated code */ +raise_exception (env, val,0 ); } }
@@ -971,8 +989,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_TRAP ); +/* nip is updated in TB */ +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_TRAP ,0 ); } }
@@ -985,8 +1004,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_TRAP ); +/* nip is updated in TB */ +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_TRAP ,0 ); } }#endif
target-ppc/fpu_helper.c +98 -93
645 lines not on this page · raw message
target-ppc/helper.h +1 -0
@@ -1,4 +1,5 @@ DEF_HELPER_3(raise_exception_err, void, env, i32, i32) +DEF_HELPER_3(raise_exception_end, void, env, i32, i32) DEF_HELPER_2(raise_exception, void, env, i32) DEF_HELPER_4(tw, void, env, tl, tl, i32)#if defined(TARGET_PPC64 )
target-ppc/mem_helper.c +3 -3
@@ -102,9 +102,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,if (likely (xer_bc !=0 )) {if (unlikely ((ra !=0 && reg < ra && (reg + xer_bc) > ra) || (reg < rb && (reg + xer_bc) > rb))) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL | -POWERPC_EXCP_INVAL_LSWX ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL | +POWERPC_EXCP_INVAL_LSWX ,GETPC ()); }else {helper_lsw (env, addr, xer_bc, reg); }
target-ppc/misc_helper.c +4 -4
@@ -37,7 +37,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)#ifdef TARGET_PPC64 static void raise_fu_exception (CPUPPCState *env,uint32_t bit, -uint32_t sprn,uint32_t cause) +uint32_t sprn,uint32_t cause,uintptr_t retaddr) {qemu_log ("Facility SPR %d is unavailable (SPR FSCR:%d)\n" , sprn, bit);
@@ -45,7 +45,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit, cause &=FSCR_IC_MASK ; env->spr[SPR_FSCR ] |= (target_ulong )cause <<FSCR_IC_POS ; - helper_raise_exception_err(env, POWERPC_EXCP_FU, 0); + raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr); }#endif
@@ -57,7 +57,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,/* Facility is enabled, continue */ return; } -raise_fu_exception (env, bit, sprn, cause); +raise_fu_exception (env, bit, sprn, cause,GETPC ());#endif }
@@ -69,7 +69,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,/* Facility is enabled, continue */ return; } -raise_fu_exception (env, bit, sprn, cause); +raise_fu_exception (env, bit, sprn, cause,GETPC ());#endif }
target-ppc/mmu-hash64.c +6 -6
@@ -197,8 +197,8 @@ static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,void helper_store_slb (CPUPPCState *env,target_ulong rb,target_ulong rs) {if (ppc_store_slb (env, rb, rs) <0 ) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL ,GETPC ()); } }
@@ -207,8 +207,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)target_ulong rt =0 ;if (ppc_load_slb_esid (env, rb, &rt) <0 ) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL ,GETPC ()); }return rt; }
@@ -218,8 +218,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)target_ulong rt =0 ;if (ppc_load_slb_vsid (env, rb, &rt) <0 ) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL ,GETPC ()); }return rt; }
target-ppc/mmu_helper.c +7 -11
@@ -2635,9 +2635,9 @@ void helper_booke206_tlbwe(CPUPPCState *env) tlb =booke206_cur_tlb (env);if (!tlb) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL | -POWERPC_EXCP_INVAL_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL | +POWERPC_EXCP_INVAL_INVAL ,GETPC ()); }/* check that we support the targeted size */
@@ -2645,9 +2645,9 @@ void helper_booke206_tlbwe(CPUPPCState *env) size_ps =booke206_tlbnps (env, tlbn);if ((env->spr[SPR_BOOKE_MAS1 ] &MAS1_VALID ) && (tlbncfg & TLBnCFG_AVAIL) && !(size_ps & (1 << size_tlb))) { -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL | -POWERPC_EXCP_INVAL_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL | +POWERPC_EXCP_INVAL_INVAL ,GETPC ()); }if (msr_gs) {
@@ -2924,10 +2924,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, ret =cpu_ppc_handle_mmu_fault (env, addr, is_write, mmu_idx); }if (unlikely (ret !=0 )) { -if (likely (retaddr)) { -/* now we have a real cpu fault */ -cpu_restore_state (cs, retaddr); - } -helper_raise_exception_err (env, cs->exception_index, env->error_code); +raise_exception_err (env, cs->exception_index, env->error_code, retaddr); } }
target-ppc/timebase_helper.c +10 -10
@@ -131,14 +131,14 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)if (unlikely (env->dcr_env ==NULL )) {qemu_log ("No DCR environment\n" ); -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL | -POWERPC_EXCP_INVAL_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL | +POWERPC_EXCP_INVAL_INVAL ,GETPC ()); }else if (unlikely (ppc_dcr_read (env->dcr_env, (uint32_t )dcrn, &val) !=0 )) {qemu_log ("DCR read error %d %03x\n" , (uint32_t )dcrn, (uint32_t )dcrn); -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL |POWERPC_EXCP_PRIV_REG ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL |POWERPC_EXCP_PRIV_REG ,GETPC ()); }return val; }
@@ -147,13 +147,13 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val) {if (unlikely (env->dcr_env ==NULL )) {qemu_log ("No DCR environment\n" ); -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL | -POWERPC_EXCP_INVAL_INVAL ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL | +POWERPC_EXCP_INVAL_INVAL ,GETPC ()); }else if (unlikely (ppc_dcr_write (env->dcr_env, (uint32_t )dcrn, (uint32_t )val) !=0 )) {qemu_log ("DCR write error %d %03x\n" , (uint32_t )dcrn, (uint32_t )dcrn); -helper_raise_exception_err (env,POWERPC_EXCP_PROGRAM , -POWERPC_EXCP_INVAL |POWERPC_EXCP_PRIV_REG ); +raise_exception_err (env,POWERPC_EXCP_PROGRAM , +POWERPC_EXCP_INVAL |POWERPC_EXCP_PRIV_REG ,GETPC ()); } }
target-ppc/translate.c +6 -78
312 lines not on this page · raw message
Quoted 4 lines · Pavel Dovgalyuk
Pavel Dovgalyuk (11):
softmmu: add helper function to pass through retaddr
softmmu: remove now unused functions
cpu-exec: introduce loop exit with restore function
These first three have been merged now.
Quoted 8 lines
target-mips: improve exception handling
target-i386: introduce newraise_exceptionfunctions
target-i386: exception handling for FPU instructions
target-i386: exception handling for div instructions
target-i386: exception handling for memory helpers
target-i386: exception handling forseg_helperfunctions
target-i386: exception handling for other helper functions
target-ppc: exceptions handling in icount mode
And I've applied the target-i386 patches to my tgt-i386-next branch. They'll be merged soon. That leaves the mips and ppc patches; I hope that Leon and Alex will review these.
r~
Quoted 17 lines · Richard Henderson
Quoted 4 lines · Pavel Dovgalyuk
Pavel Dovgalyuk (11):
softmmu: add helper function to pass through retaddr
softmmu: remove now unused functions
cpu-exec: introduce loop exit with restore functionThese first three have been merged now.
Quoted 8 lines
target-mips: improve exception handling
target-i386: introduce newraise_exceptionfunctions
target-i386: exception handling for FPU instructions
target-i386: exception handling for div instructions
target-i386: exception handling for memory helpers
target-i386: exception handling forseg_helperfunctions
target-i386: exception handling for other helper functions
target-ppc: exceptions handling in icount mode
Quoted 3 lines
And I've applied the target-i386 patches to my tgt-i386-next branch. They'll be merged soon. That leaves the mips and ppc patches; I hope that Leon and Alex will review these.
AFAIK Leon already started to look at the mips patch. The problem is that there introduced a serious performance regression in user mode:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg01620.html
Signature · 2 lines
Aurelien Jarno GPG: 4096R/1DDD8C9B [email protected] http://www.aurel32.net
Quoted 18 lines · Aurelien Jarno
Quoted 17 lines · Richard Henderson
Quoted 4 lines · Pavel Dovgalyuk
Pavel Dovgalyuk (11):
softmmu: add helper function to pass through retaddr
softmmu: remove now unused functions
cpu-exec: introduce loop exit with restore functionThese first three have been merged now.
Quoted 8 lines
target-mips: improve exception handling
target-i386: introduce newraise_exceptionfunctions
target-i386: exception handling for FPU instructions
target-i386: exception handling for div instructions
target-i386: exception handling for memory helpers
target-i386: exception handling forseg_helperfunctions
target-i386: exception handling for other helper functions
target-ppc: exceptions handling in icount mode
Quoted 8 lines
Quoted 3 lines
And I've applied the target-i386 patches to my tgt-i386-next branch. They'll be merged soon. That leaves the mips and ppc patches; I hope that Leon and Alex will review these.
AFAIK Leon already started to look at the mips patch. The problem is that there introduced a serious performance regression in user mode:
https://lists.gnu.org/archive/html/qemu-devel/2015-08/msg01620.html
I haven't got round to trying Pavel's suggestion yet. I'll try to move it towards the beginning of my todo list.
Leon
Quoted 17 lines · Richard Henderson
Quoted 4 lines · Pavel Dovgalyuk
Pavel Dovgalyuk (11):
softmmu: add helper function to pass through retaddr
softmmu: remove now unused functions
cpu-exec: introduce loop exit with restore functionThese first three have been merged now.
Quoted 8 lines
target-mips: improve exception handling
target-i386: introduce newraise_exceptionfunctions
target-i386: exception handling for FPU instructions
target-i386: exception handling for div instructions
target-i386: exception handling for memory helpers
target-i386: exception handling forseg_helperfunctions
target-i386: exception handling for other helper functions
target-ppc: exceptions handling in icount mode
Quoted 3 lines
And I've applied the target-i386 patches to my tgt-i386-next branch. They'll be merged soon. That leaves the mips and ppc patches; I hope that Leon and Alex will review these.
Sorry, I won't get around to review the ppc parts for the next 2 months at least. David / Aurelien, could you please help out here?
Alex