[PATCH] target/openrisc: fix icount handling for timer instructions

Pavel Dovgalyuk posted 1 patch 3 years ago
Test checkpatch passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/161700376169.1135890.8707223959310729949.stgit@pasha-ThinkPad-X280
Maintainers: Stafford Horne <shorne@gmail.com>
target/openrisc/translate.c |   15 +++++++++++++++
1 file changed, 15 insertions(+)
[PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Pavel Dovgalyuk 3 years ago
This patch adds icount handling to mfspr/mtspr instructions
that may deal with hardware timers.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
---
 target/openrisc/translate.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index c6dce879f1..a9c81f8bd5 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
         gen_illegal_exception(dc);
     } else {
         TCGv spr = tcg_temp_new();
+
+        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+            gen_io_start();
+            if (dc->delayed_branch) {
+                tcg_gen_mov_tl(cpu_pc, jmp_pc);
+                tcg_gen_discard_tl(jmp_pc);
+            } else {
+                tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
+            }
+            dc->base.is_jmp = DISAS_EXIT;
+        }
+
         tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
         gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
         tcg_temp_free(spr);
@@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
     } else {
         TCGv spr;
 
+        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+            gen_io_start();
+        }
         /* For SR, we will need to exit the TB to recognize the new
          * exception state.  For NPC, in theory this counts as a branch
          * (although the SPR only exists for use by an ICE).  Save all


Re: [PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Stafford Horne 3 years ago
Hi Pavel,

Thanks for the patch.

On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote:
> This patch adds icount handling to mfspr/mtspr instructions
> that may deal with hardware timers.
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
> ---
>  target/openrisc/translate.c |   15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> index c6dce879f1..a9c81f8bd5 100644
> --- a/target/openrisc/translate.c
> +++ b/target/openrisc/translate.c
> @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
>          gen_illegal_exception(dc);
>      } else {
>          TCGv spr = tcg_temp_new();
> +
> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
> +            gen_io_start();
> +            if (dc->delayed_branch) {
> +                tcg_gen_mov_tl(cpu_pc, jmp_pc);
> +                tcg_gen_discard_tl(jmp_pc);
> +            } else {
> +                tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
> +            }
> +            dc->base.is_jmp = DISAS_EXIT;
> +        }

I don't know alot about how the icount works.  But I read this document to help
understand this patch.

https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html

Could you explain why we need to exit the tb on mfspr?  This may just be reading
a timer value, but I am not sure why we need it?

>          tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
>          gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
>          tcg_temp_free(spr);
> @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
>      } else {
>          TCGv spr;
>  
> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
> +            gen_io_start();
> +        }

Here and above, why do we need to call gen_io_start()?  This seems to need to be
called before io operations.

This may all be OK, but could you help explain the theory of operation?  Also,
have you tested this?

-Stafford

Re: [PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Pavel Dovgalyuk 3 years ago
On 31.03.2021 01:05, Stafford Horne wrote:
> Hi Pavel,
> 
> Thanks for the patch.
> 
> On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote:
>> This patch adds icount handling to mfspr/mtspr instructions
>> that may deal with hardware timers.
>>
>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
>> ---
>>   target/openrisc/translate.c |   15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
>> index c6dce879f1..a9c81f8bd5 100644
>> --- a/target/openrisc/translate.c
>> +++ b/target/openrisc/translate.c
>> @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
>>           gen_illegal_exception(dc);
>>       } else {
>>           TCGv spr = tcg_temp_new();
>> +
>> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
>> +            gen_io_start();
>> +            if (dc->delayed_branch) {
>> +                tcg_gen_mov_tl(cpu_pc, jmp_pc);
>> +                tcg_gen_discard_tl(jmp_pc);
>> +            } else {
>> +                tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
>> +            }
>> +            dc->base.is_jmp = DISAS_EXIT;
>> +        }
> 
> I don't know alot about how the icount works.  But I read this document to help
> understand this patch.
> 
> https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html
> 
> Could you explain why we need to exit the tb on mfspr?  This may just be reading
> a timer value, but I am not sure why we need it?

Because virtual clock in icount mode is correct only at the end of the 
block.
Allowing virtual clock reads in other places will make execution 
non-deterministic, because icount is updated to the value, which it gets 
after the block ends.

> 
>>           tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
>>           gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
>>           tcg_temp_free(spr);
>> @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
>>       } else {
>>           TCGv spr;
>>   
>> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
>> +            gen_io_start();
>> +        }
> 
> Here and above, why do we need to call gen_io_start()?  This seems to need to be
> called before io operations.

gen_io_start allows reading icount for the instruction.
It is needed to prevent invalid reads in the middle of the block.

> 
> This may all be OK, but could you help explain the theory of operation?  Also,
> have you tested this?

I have record/replay tests for openrisc, but I can't submit them without 
this patch, because they will fail.

Pavel Dovgalyuk

Re: [PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Stafford Horne 3 years ago
On Wed, Mar 31, 2021 at 10:27:21AM +0300, Pavel Dovgalyuk wrote:
> On 31.03.2021 01:05, Stafford Horne wrote:
> > Hi Pavel,
> > 
> > Thanks for the patch.
> > 
> > On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote:
> > > This patch adds icount handling to mfspr/mtspr instructions
> > > that may deal with hardware timers.
> > > 
> > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
> > > ---
> > >   target/openrisc/translate.c |   15 +++++++++++++++
> > >   1 file changed, 15 insertions(+)
> > > 
> > > diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> > > index c6dce879f1..a9c81f8bd5 100644
> > > --- a/target/openrisc/translate.c
> > > +++ b/target/openrisc/translate.c
> > > @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
> > >           gen_illegal_exception(dc);
> > >       } else {
> > >           TCGv spr = tcg_temp_new();
> > > +
> > > +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
> > > +            gen_io_start();
> > > +            if (dc->delayed_branch) {
> > > +                tcg_gen_mov_tl(cpu_pc, jmp_pc);
> > > +                tcg_gen_discard_tl(jmp_pc);
> > > +            } else {
> > > +                tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
> > > +            }
> > > +            dc->base.is_jmp = DISAS_EXIT;
> > > +        }
> > 
> > I don't know alot about how the icount works.  But I read this document to help
> > understand this patch.
> > 
> > https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html
> > 
> > Could you explain why we need to exit the tb on mfspr?  This may just be reading
> > a timer value, but I am not sure why we need it?
> 
> Because virtual clock in icount mode is correct only at the end of the
> block.
> Allowing virtual clock reads in other places will make execution
> non-deterministic, because icount is updated to the value, which it gets
> after the block ends.

OK, got it.

> > 
> > >           tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
> > >           gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
> > >           tcg_temp_free(spr);
> > > @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
> > >       } else {
> > >           TCGv spr;
> > > +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
> > > +            gen_io_start();
> > > +        }
> > 
> > Here and above, why do we need to call gen_io_start()?  This seems to need to be
> > called before io operations.
> 
> gen_io_start allows reading icount for the instruction.
> It is needed to prevent invalid reads in the middle of the block.
> 
> > 
> > This may all be OK, but could you help explain the theory of operation?  Also,
> > have you tested this?
> 
> I have record/replay tests for openrisc, but I can't submit them without
> this patch, because they will fail.

OK.

Acked-by: Stafford Horne <shorne@gmail.com>

I am not currently maintaining an openrisc queue, but I could start one.  Do you
have another way to submit this upstream?

-Stafford

Re: [PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Pavel Dovgalyuk 3 years ago
CC'ed Paolo.


On 31.03.2021 15:33, Stafford Horne wrote:
> On Wed, Mar 31, 2021 at 10:27:21AM +0300, Pavel Dovgalyuk wrote:
>> On 31.03.2021 01:05, Stafford Horne wrote:
>>> Hi Pavel,
>>>
>>> Thanks for the patch.
>>>
>>> On Mon, Mar 29, 2021 at 10:42:41AM +0300, Pavel Dovgalyuk wrote:
>>>> This patch adds icount handling to mfspr/mtspr instructions
>>>> that may deal with hardware timers.
>>>>
>>>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
>>>> ---
>>>>    target/openrisc/translate.c |   15 +++++++++++++++
>>>>    1 file changed, 15 insertions(+)
>>>>
>>>> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
>>>> index c6dce879f1..a9c81f8bd5 100644
>>>> --- a/target/openrisc/translate.c
>>>> +++ b/target/openrisc/translate.c
>>>> @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
>>>>            gen_illegal_exception(dc);
>>>>        } else {
>>>>            TCGv spr = tcg_temp_new();
>>>> +
>>>> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
>>>> +            gen_io_start();
>>>> +            if (dc->delayed_branch) {
>>>> +                tcg_gen_mov_tl(cpu_pc, jmp_pc);
>>>> +                tcg_gen_discard_tl(jmp_pc);
>>>> +            } else {
>>>> +                tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
>>>> +            }
>>>> +            dc->base.is_jmp = DISAS_EXIT;
>>>> +        }
>>>
>>> I don't know alot about how the icount works.  But I read this document to help
>>> understand this patch.
>>>
>>> https://qemu.readthedocs.io/en/latest/devel/tcg-icount.html
>>>
>>> Could you explain why we need to exit the tb on mfspr?  This may just be reading
>>> a timer value, but I am not sure why we need it?
>>
>> Because virtual clock in icount mode is correct only at the end of the
>> block.
>> Allowing virtual clock reads in other places will make execution
>> non-deterministic, because icount is updated to the value, which it gets
>> after the block ends.
> 
> OK, got it.
> 
>>>
>>>>            tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
>>>>            gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
>>>>            tcg_temp_free(spr);
>>>> @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
>>>>        } else {
>>>>            TCGv spr;
>>>> +        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
>>>> +            gen_io_start();
>>>> +        }
>>>
>>> Here and above, why do we need to call gen_io_start()?  This seems to need to be
>>> called before io operations.
>>
>> gen_io_start allows reading icount for the instruction.
>> It is needed to prevent invalid reads in the middle of the block.
>>
>>>
>>> This may all be OK, but could you help explain the theory of operation?  Also,
>>> have you tested this?
>>
>> I have record/replay tests for openrisc, but I can't submit them without
>> this patch, because they will fail.
> 
> OK.
> 
> Acked-by: Stafford Horne <shorne@gmail.com>
> 
> I am not currently maintaining an openrisc queue, but I could start one.  Do you
> have another way to submit this upstream?

Paolo, can you queue this one?

Pavel Dovgalyuk

Re: [PATCH] target/openrisc: fix icount handling for timer instructions
Posted by Paolo Bonzini 3 years ago
On 31/03/21 14:48, Pavel Dovgalyuk wrote:
>> Acked-by: Stafford Horne <shorne@gmail.com>
>>
>> I am not currently maintaining an openrisc queue, but I could start 
>> one.  Do you
>> have another way to submit this upstream?
> 
> Paolo, can you queue this one?

Sure, done.

Paolo