diff mbox series

[alternate,2/2] target/riscv: Fix write_misa vs aligned next_pc

Message ID 20250425165055.807801-3-richard.henderson@linaro.org
State New
Headers show
Series target/riscv: Fix write_misa vs aligned next_pc | expand

Commit Message

Richard Henderson April 25, 2025, 4:50 p.m. UTC
Do not examine a random host return address, but examine the
guest pc via env->pc.

Fixes: f18637cd611 ("RISC-V: Add misa runtime write support")
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/csr.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

Comments

Daniel Henrique Barboza April 25, 2025, 10:20 p.m. UTC | #1
On 4/25/25 1:50 PM, Richard Henderson wrote:
> Do not examine a random host return address, but examine the
> guest pc via env->pc.
> 
> Fixes: f18637cd611 ("RISC-V: Add misa runtime write support")
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/riscv/csr.c | 9 ++++++---
>   1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index c52c87faae..992ec8ebff 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -2111,10 +2111,13 @@ static RISCVException write_misa(CPURISCVState *env, int csrno,
>       val &= env->misa_ext_mask;
>   
>       /*
> -     * Suppress 'C' if next instruction is not aligned
> -     * TODO: this should check next_pc
> +     * Suppress 'C' if next instruction is not aligned.
> +     * Outside of the context of a running cpu, env->pc contains next_pc.
> +     * Within the context of a running cpu, env->pc contains the pc of
> +     * the csrw/csrrw instruction.  But since all such instructions are
> +     * exactly 4 bytes, next_pc has the same alignment mod 4.


By "outside of the context of a running CPU" you mean a halted CPU, correct?

And now, for a running CPU, env->pc has the pc of csrw/csrrw because of patch 1.
Otherwise it would contain a pc that was synchronized via the last
synchronize_from_tb, or any other insn that happened to sync env->pc in
the same TB via gen_update_pc(). We're not keeping env->pc up to date all
the time because it would be extra work that wouldn't be needed most of the
time. Am I too off the mark?

The reason I'm asking is because I see at least one place (get_physical_address())
where it's stated that "the env->pc at this point is incorrect". And I see env->pc
being either the current PC or the next insn PC depending on the situation.
Reading these 2 patches clarified it a bit (assuming I'm not completely incorrect,
of course).




For the patch:


Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

>        */
> -    if ((val & RVC) && (GETPC() & ~3) != 0) {
> +    if ((val & RVC) && (env->pc & ~3) != 0) {
>           val &= ~RVC;
>       }
>
Richard Henderson April 26, 2025, 2:12 p.m. UTC | #2
On 4/25/25 15:20, Daniel Henrique Barboza wrote:
>> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> index c52c87faae..992ec8ebff 100644
>> --- a/target/riscv/csr.c
>> +++ b/target/riscv/csr.c
>> @@ -2111,10 +2111,13 @@ static RISCVException write_misa(CPURISCVState *env, int csrno,
>>       val &= env->misa_ext_mask;
>>       /*
>> -     * Suppress 'C' if next instruction is not aligned
>> -     * TODO: this should check next_pc
>> +     * Suppress 'C' if next instruction is not aligned.
>> +     * Outside of the context of a running cpu, env->pc contains next_pc.
>> +     * Within the context of a running cpu, env->pc contains the pc of
>> +     * the csrw/csrrw instruction.  But since all such instructions are
>> +     * exactly 4 bytes, next_pc has the same alignment mod 4.
> 
> 
> By "outside of the context of a running CPU" you mean a halted CPU, correct?

Correct, e.g. from gdbstub.

> 
> And now, for a running CPU, env->pc has the pc of csrw/csrrw because of patch 1.

Correct.

> Otherwise it would contain a pc that was synchronized via the last
> synchronize_from_tb, or any other insn that happened to sync env->pc in
> the same TB via gen_update_pc(). We're not keeping env->pc up to date all
> the time because it would be extra work that wouldn't be needed most of the
> time. Am I too off the mark?

Correct.

> 
> The reason I'm asking is because I see at least one place (get_physical_address())
> where it's stated that "the env->pc at this point is incorrect".

Correct, since get_physical_address is called from riscv_cpu_tlb_fill, which can be called 
during the processing of any guest memory operation.


> And I see env->pc
> being either the current PC or the next insn PC depending on the situation.
> Reading these 2 patches clarified it a bit (assuming I'm not completely incorrect,
> of course).

I would expect env->pc to be more or less random in get_physical_address, with a bias 
toward the PC of the first instruction of the TB.

I'm not sure why get_physical_address has that comment.  The current pc isn't relevant to 
resolving a virtual address.  It only becomes relevant when there is a fault, and the pc 
is restored via unwinding along the fault path.


r~
diff mbox series

Patch

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index c52c87faae..992ec8ebff 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2111,10 +2111,13 @@  static RISCVException write_misa(CPURISCVState *env, int csrno,
     val &= env->misa_ext_mask;
 
     /*
-     * Suppress 'C' if next instruction is not aligned
-     * TODO: this should check next_pc
+     * Suppress 'C' if next instruction is not aligned.
+     * Outside of the context of a running cpu, env->pc contains next_pc.
+     * Within the context of a running cpu, env->pc contains the pc of
+     * the csrw/csrrw instruction.  But since all such instructions are
+     * exactly 4 bytes, next_pc has the same alignment mod 4.
      */
-    if ((val & RVC) && (GETPC() & ~3) != 0) {
+    if ((val & RVC) && (env->pc & ~3) != 0) {
         val &= ~RVC;
     }