qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] target-arm: Clean up DISAS_UPDATE usage in AArc


From: Sergey Fedorov
Subject: Re: [Qemu-devel] [PATCH] target-arm: Clean up DISAS_UPDATE usage in AArch32 translation code
Date: Mon, 9 Nov 2015 21:33:05 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0

On 06.11.2015 15:46, Peter Maydell wrote:
> On 2 November 2015 at 18:16, Sergey Fedorov <address@hidden> wrote:
>> AArch32 translation code does not distinguish between DISAS_UPDATE and
>> DISAS_JUMP. Thus, we cannot use any of them without first updating PC in
>> CPU state. Furthermore, it is too complicated to update PC in CPU state
>> before PC gets updated in disas context. So it is hardly possible to
>> correctly end TB early if is is not likely to be executed before calling
>> disas_*_insn(), e.g. just after calling breakpoint check helper.
>>
>> Modify DISAS_UPDATE and DISAS_JUMP usage in AArch32 translation and
>> apply to them the same semantic as AArch64 translation does:
>>  - DISAS_UPDATE: update PC in CPU state when finishing translation
>>  - DISAS_JUMP:   preserve current PC value in CPU state when finishing
>>                  translation
>>
>> Signed-off-by: Sergey Fedorov <address@hidden>
>> ---
>>  target-arm/translate.c | 16 +++++++++-------
>>  1 file changed, 9 insertions(+), 7 deletions(-)
>>
>> diff --git a/target-arm/translate.c b/target-arm/translate.c
>> index 9f1d740..ec740fd 100644
>> --- a/target-arm/translate.c
>> +++ b/target-arm/translate.c
>> @@ -870,7 +870,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t 
>> addr)
>>  {
>>      TCGv_i32 tmp;
>>
>> -    s->is_jmp = DISAS_UPDATE;
>> +    s->is_jmp = DISAS_JUMP;
>>      if (s->thumb != (addr & 1)) {
>>          tmp = tcg_temp_new_i32();
>>          tcg_gen_movi_i32(tmp, addr & 1);
>> @@ -883,7 +883,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t 
>> addr)
>>  /* Set PC and Thumb state from var.  var is marked as dead.  */
>>  static inline void gen_bx(DisasContext *s, TCGv_i32 var)
>>  {
>> -    s->is_jmp = DISAS_UPDATE;
>> +    s->is_jmp = DISAS_JUMP;
>>      tcg_gen_andi_i32(cpu_R[15], var, ~1);
>>      tcg_gen_andi_i32(var, var, 1);
>>      store_cpu_field(var, thumb);
>> @@ -1062,7 +1062,7 @@ static void gen_exception_insn(DisasContext *s, int 
>> offset, int excp,
>>  static inline void gen_lookup_tb(DisasContext *s)
>>  {
>>      tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
>> -    s->is_jmp = DISAS_UPDATE;
>> +    s->is_jmp = DISAS_JUMP;
>>  }
>>
>>  static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
>> @@ -4096,7 +4096,7 @@ static void gen_exception_return(DisasContext *s, 
>> TCGv_i32 pc)
>>      tmp = load_cpu_field(spsr);
>>      gen_set_cpsr(tmp, CPSR_ERET_MASK);
>>      tcg_temp_free_i32(tmp);
>> -    s->is_jmp = DISAS_UPDATE;
>> +    s->is_jmp = DISAS_JUMP;
>>  }
>>
>>  /* Generate a v6 exception return.  Marks both values as dead.  */
>> @@ -4105,7 +4105,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, 
>> TCGv_i32 cpsr)
>>      gen_set_cpsr(cpsr, CPSR_ERET_MASK);
>>      tcg_temp_free_i32(cpsr);
>>      store_reg(s, 15, pc);
>> -    s->is_jmp = DISAS_UPDATE;
>> +    s->is_jmp = DISAS_JUMP;
>>  }
>>
>>  static void gen_nop_hint(DisasContext *s, int val)
>> @@ -9035,7 +9035,7 @@ static void disas_arm_insn(DisasContext *s, unsigned 
>> int insn)
>>                      tmp = load_cpu_field(spsr);
>>                      gen_set_cpsr(tmp, CPSR_ERET_MASK);
>>                      tcg_temp_free_i32(tmp);
>> -                    s->is_jmp = DISAS_UPDATE;
>> +                    s->is_jmp = DISAS_JUMP;
>>                  }
>>              }
>>              break;
>> @@ -11488,8 +11488,10 @@ void gen_intermediate_code(CPUARMState *env, 
>> TranslationBlock *tb)
>>              gen_goto_tb(dc, 1, dc->pc);
>>              break;
>>          default:
>> -        case DISAS_JUMP:
>>          case DISAS_UPDATE:
>> +            gen_set_pc_im(dc, dc->pc);
>> +            /* fall through */
>> +        case DISAS_JUMP:
> This is also changing the behaviour for the "default" label, which
> I think is unintentional. In particular DISAS_EXC doesn't appear
> in this switch and so we're relying on the default being "do nothing".
> (I think it's just an oversight that DISAS_EXC isn't an explicit
> case in this switch, as it is for target-a64.c.)

Thanks for the catch, I'll fix this.

> This patch leaves three instances of DISAS_UPDATE. For two
> of those [userspace kernel page and the M profile exception-return
> magic addresses], we've just done a gen_exception_internal(), so
> updating the PC here is pointless. Those should be DISAS_EXC
> instead I think. (The effect of your patch on these is just
> generating unreachable code, so no user visible problems.)

This one, too.

> The third one is in the breakpoint handling, which I guess
> is the case we're aiming to fix?

Yes, that is what I'm going to fix. I'll mention this in a commit message.

> I think if we want to use DISAS_UPDATE then we also need
> to handle it inside the
>  if (unlikely(cs->singlestep_enabled || dc->ss_active)) {
> branch. Specifically, this check:
>    if (dc->condjmp || !dc->is_jmp)
> is trying to say "if this was a conditional jump, or it
> has not already set the PC", and so now needs to read
>    if (dc->condjmp || dc->is_jmp == DISAS_NEXT ||
>        dc->is_jmp == DISAS_UPDATE)

This issue is a subtle one. Looks like I'm going to have to spend some
time getting into this. Actually, I just don't understand this code for
now :) Would it be OK, if I just do what you suggest and send v2 as soon
as possible and get into this later on?

> Also, I've just noticed that we don't do a gen_set_pc_im()
> *before* calling gen_helper_check_breakpoints(). That means
> that if the possible breakpoint is not at the start of a TB
> then the helper function will not see the correct env->pc.

I'm going to prepare a separate patch to fix this.

Thanks,
Sergey

>
>>              /* indicate that the hash table must be used to find the next 
>> TB */
>>              tcg_gen_exit_tb(0);
>>              break;
>> --
>> 1.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]