Skip to content

Commit

Permalink
riscv: signal: check fp-reserved words unconditionally
Browse files Browse the repository at this point in the history
In order to let kernel/user locate and identify an extension context on
the existing sigframe, we are going to utilize reserved space of fp and
encode the information there. And since the sigcontext has already
preserved a space for fp context w or w/o CONFIG_FPU, we move those
reserved words checking/setting routine back into generic code.

This commit also undone an additional logical change carried by the
refactor commit 007f5c3
("Refactor FPU code in signal setup/return procedures"). Originally we
did not restore fp context if restoring of gpr have failed. And it was
fine on the other side. In such way the kernel could keep the regfiles
intact, and potentially react at the failing point of restore.

Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Acked-by: Heiko Stuebner <heiko.stuebner@vrull.eu>
Tested-by: Heiko Stuebner <heiko.stuebner@vrull.eu>
Link: https://lore.kernel.org/r/20230605110724.21391-14-andy.chiu@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
  • Loading branch information
Andy Chiu authored and Palmer Dabbelt committed Jun 8, 2023
1 parent 0c59922 commit a45ceda
Showing 1 changed file with 28 additions and 27 deletions.
55 changes: 28 additions & 27 deletions arch/riscv/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,47 +40,23 @@ static long restore_fp_state(struct pt_regs *regs,
{
long err;
struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
size_t i;

err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
if (unlikely(err))
return err;

fstate_restore(current, regs);

/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
u32 value;

err = __get_user(value, &sc_fpregs->q.reserved[i]);
if (unlikely(err))
break;
if (value != 0)
return -EINVAL;
}

return err;
return 0;
}

static long save_fp_state(struct pt_regs *regs,
union __riscv_fp_state __user *sc_fpregs)
{
long err;
struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
size_t i;

fstate_save(current, regs);
err = __copy_to_user(state, &current->thread.fstate, sizeof(*state));
if (unlikely(err))
return err;

/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
err = __put_user(0, &sc_fpregs->q.reserved[i]);
if (unlikely(err))
break;
}

return err;
}
#else
Expand All @@ -92,11 +68,30 @@ static long restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
long err;
size_t i;

/* sc_regs is structured the same as the start of pt_regs */
err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
if (unlikely(err))
return err;

/* Restore the floating-point state. */
if (has_fpu())
err |= restore_fp_state(regs, &sc->sc_fpregs);
if (has_fpu()) {
err = restore_fp_state(regs, &sc->sc_fpregs);
if (unlikely(err))
return err;
}

/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) {
u32 value;

err = __get_user(value, &sc->sc_fpregs.q.reserved[i]);
if (unlikely(err))
break;
if (value != 0)
return -EINVAL;
}
return err;
}

Expand Down Expand Up @@ -147,11 +142,17 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
{
struct sigcontext __user *sc = &frame->uc.uc_mcontext;
long err;
size_t i;

/* sc_regs is structured the same as the start of pt_regs */
err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
/* Save the floating-point state. */
if (has_fpu())
err |= save_fp_state(regs, &sc->sc_fpregs);
/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++)
err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]);

return err;
}

Expand Down

0 comments on commit a45ceda

Please sign in to comment.