qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: Michael Clark <mjc@sifive.com>
Cc: "Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	"QEMU Developers" <qemu-devel@nongnu.org>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Sagar Karandikar" <sagark@eecs.berkeley.edu>,
	"Bastian Koppelmann" <kbastian@mail.uni-paderborn.de>,
	"Palmer Dabbelt" <palmer@sifive.com>,
	"RISC-V Patches" <patches@groups.riscv.org>
Subject: Re: [Qemu-devel] [PATCH v1 1/1] RISC-V: Workaround for critical mstatus.FS MTTCG bug
Date: Fri, 30 Mar 2018 08:11:55 +0100	[thread overview]
Message-ID: <87po3m6nr8.fsf@linaro.org> (raw)
In-Reply-To: <CAHNT7Nt40C8Bh3VJHjv8f+obSbU6Ki8ThXH2L7o4zoSM2LnK5A@mail.gmail.com>


Michael Clark <mjc@sifive.com> writes:

> On Tue, Mar 27, 2018 at 3:17 PM, Philippe Mathieu-Daudé <f4bug@amsat.org>
> wrote:
>
>> Cc'ing Alex and Richard.
>>
>> On 03/27/2018 04:54 PM, Michael Clark wrote:
>> > This change is a workaround for a bug where mstatus.FS
>> > is not correctly reporting dirty when MTTCG and SMP are
>> > enabled which results in the floating point register file
>> > not being saved during context switches. This a critical
>> > bug for RISC-V in QEMU as it results in floating point
>> > register file corruption when running SMP Linux in the
>> > RISC-V 'virt' machine.
>> >
>> > This workaround will return dirty if mstatus.FS is
>> > switched from off to initial or clean. We have checked
>> > the specification and it is legal for an implementation
>> > to return either off, or dirty, if set to initial or clean.
>> >
>> > This workaround will result in unnecessary floating point
>> > save restore. When mstatus.FS is off, floating point
>> > instruction trap to indicate the process is using the FPU.
>> > The OS can then save floating-point state of the previous
>> > process using the FPU and set mstatus.FS to initial or
>> > clean. With this workaround, mstatus.FS will always return
>> > dirty if set to a non-zero value, indicating floating point
>> > save restore is necessary, versus misreporting mstatus.FS
>> > resulting in floating point register file corruption.
>> >
>> > Cc: Palmer Dabbelt <palmer@sifive.com>
>> > Cc: Sagar Karandikar <sagark@eecs.berkeley.edu>
>> > Cc: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
>> > Cc: Peter Maydell <peter.maydell@linaro.org>
>> > Tested-by: Richard W.M. Jones <rjones@redhat.com>
>> > Signed-off-by: Michael Clark <mjc@sifive.com>
>> > ---
>> >  target/riscv/op_helper.c | 19 +++++++++++++++++--
>> >  1 file changed, 17 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
>> > index e34715d..7281b98 100644
>> > --- a/target/riscv/op_helper.c
>> > +++ b/target/riscv/op_helper.c
>> > @@ -144,8 +144,23 @@ void csr_write_helper(CPURISCVState *env,
>> target_ulong val_to_write,
>> >          }
>> >
>> >          mstatus = (mstatus & ~mask) | (val_to_write & mask);
>> > -        int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS;
>> > -        dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS;
>> > +
>> > +        /* Note: this is a workaround for an issue where mstatus.FS
>> > +           does not report dirty when SMP and MTTCG is enabled. This
>> > +           workaround is technically compliant with the RISC-V
>> Privileged
>> > +           specification as it is legal to return only off, or dirty,
>> > +           however this may cause unnecessary saves of floating point
>> state.
>> > +           Without this workaround, floating point state is not saved
>> and
>> > +           restored correctly when SMP and MTTCG is enabled, */
>>
>
> On looking at this again, I think we may need to remove the
> qemu_tcg_mttcg_enabled conditional and always return dirty if the state is
> initial or clean, but not off.
>
> While testing on uniprocessor worked okay, it's likely because we were
> lucky and there was no task migration or multiple FPU tasks working. This
> would mean we would revert to Richard W.M. Jones initial patch.
>
>> +        if (qemu_tcg_mttcg_enabled()) {
>> > +            /* FP is always dirty or off */
>> > +            if (mstatus & MSTATUS_FS) {
>> > +                mstatus |= MSTATUS_FS;
>> > +            }
>> > +        }


I'm confused. If mstatus is a per-vCPU variable why does the enabling or
not of MTTCG matter here?

>> > +
>> > +        int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
>> > +                    ((mstatus & MSTATUS_XS) == MSTATUS_XS);
>> >          mstatus = set_field(mstatus, MSTATUS_SD, dirty);
>> >          env->mstatus = mstatus;
>> >          break;
>> >
>>
>
> The text from the specification that allows us to always return dirty if
> set to initial or clean, is below i.e. Dirty implies state has
> "potentially" been modified, so that gives us wriggle room.
>
> "
> When an extension's status is set to Off , any instruction that attempts to
> read or write the corresponding
> state will cause an exception. When the status is Initial, the
> corresponding state should
> have an initial constant value. When the status is Clean, the corresponding
> state is potentially
> di fferent from the initial value, but matches the last value stored on a
> context swap. When the
> status is Dirty, the corresponding state has potentially been modif ed
> since the last context save.
> "
>
> I think the problem is Linux is setting the state to clean after saving
> fpu register state [1], but we have no code in the QEMU FPU operations to
> set the state to dirty, if is clean or initial, only code to cause an
> exception if the floating point extension state is set to off e.g.
>
> static void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,
>         int rs2, target_long imm)
> {
>     TCGv t0;
>
>     if (!(ctx->flags & TB_FLAGS_FP_ENABLE)) {
>         gen_exception_illegal(ctx);
>         return;
>     }
>
>     t0 = tcg_temp_new();
>     gen_get_gpr(t0, rs1);
>     tcg_gen_addi_tl(t0, t0, imm);
>
>     switch (opc) {
>     case OPC_RISC_FSW:
>         tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEUL);
>         break;
>     case OPC_RISC_FSD:
>         tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEQ);
>         break;
>     default:
>         gen_exception_illegal(ctx);
>         break;
>     }
>
>     tcg_temp_free(t0);
> }
>
> [1]
> https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/switch_to.h


--
Alex Bennée

  parent reply	other threads:[~2018-03-30  7:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-27 19:54 [Qemu-devel] [PATCH v1 0/1] RISC-V: Critical fixes for QEMU 2.12 Michael Clark
2018-03-27 19:54 ` [Qemu-devel] [PATCH v1 1/1] RISC-V: Workaround for critical mstatus.FS MTTCG bug Michael Clark
2018-03-27 22:17   ` Philippe Mathieu-Daudé
2018-03-28  0:15     ` Michael Clark
2018-03-28  2:26       ` Richard Henderson
2018-03-30  7:11       ` Alex Bennée [this message]
2018-03-30 17:01         ` Michael Clark
2018-03-28  2:08   ` [Qemu-devel] [patches] " Palmer Dabbelt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87po3m6nr8.fsf@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=f4bug@amsat.org \
    --cc=kbastian@mail.uni-paderborn.de \
    --cc=mjc@sifive.com \
    --cc=palmer@sifive.com \
    --cc=patches@groups.riscv.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=sagark@eecs.berkeley.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).