static int protected_restore_fp_context(struct sigcontext __user *sc) { int err, tmp __maybe_unused; #ifndef CONFIG_EVA while (1) { lock_fpu_owner(); if (is_fpu_owner()) { err = restore_fp_context(sc); unlock_fpu_owner(); } else { unlock_fpu_owner(); err = copy_fp_from_sigcontext(sc); } if (likely(!err)) break; /* touch the sigcontext and try again */ err = __get_user(tmp, &sc->sc_fpregs[0]) | __get_user(tmp, &sc->sc_fpregs[31]) | __get_user(tmp, &sc->sc_fpc_csr); if (err) break; /* really bad sigcontext */ } #else /* * EVA does not have FPU EVA instructions so restoring fpu context * directly does not work. */ lose_fpu(0); err = restore_fp_context(sc); /* this might fail */ #endif return err; }
asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(regs->hi, &sc->sc_mdhi); err |= __get_user(regs->lo, &sc->sc_mdlo); #define restore_gp_reg(i) do { \ err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); restore_gp_reg(31); #undef restore_gp_reg err |= __get_user(current->used_math, &sc->sc_used_math); if (current->used_math) { /* restore fpu context if we have used it before */ own_fpu(); err |= restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); } return err; }
static int protected_restore_fp_context(struct sigcontext __user *sc, unsigned used_math) { int err, tmp __maybe_unused; bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA); #ifndef CONFIG_EVA while (1) { lock_fpu_owner(); if (is_fpu_owner()) { err = restore_fp_context(sc); if (restore_msa && !err) { enable_msa(); err = _restore_msa_context(sc); } else { /* signal handler may have used MSA */ disable_msa(); } unlock_fpu_owner(); } else { unlock_fpu_owner(); err = copy_fp_from_sigcontext(sc); if (!err && (used_math & USEDMATH_MSA)) err = copy_msa_from_sigcontext(sc); } if (likely(!err)) break; /* touch the sigcontext and try again */ err = __get_user(tmp, &sc->sc_fpregs[0]) | __get_user(tmp, &sc->sc_fpregs[31]) | __get_user(tmp, &sc->sc_fpc_csr); if (err) break; /* really bad sigcontext */ } #else /* * EVA does not have FPU EVA instructions so restoring fpu context * directly does not work. */ enable_msa(); lose_fpu(0); err = restore_fp_context(sc); /* this might fail */ if (restore_msa && !err) err = copy_msa_from_sigcontext(sc); #endif return err; }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int owned_fp; int err = 0; u64 reg; err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(reg, &sc->sc_mdhi); regs->hi = (int) reg; err |= __get_user(reg, &sc->sc_mdlo); regs->lo = (int) reg; #define restore_gp_reg(i) do { \ err |= __get_user(reg, &sc->sc_regs[i]); \ regs->regs[i] = reg; \ } while(0); restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); restore_gp_reg(31); #undef restore_gp_reg err |= __get_user(owned_fp, &sc->sc_ownedfp); err |= __get_user(current->used_math, &sc->sc_used_math); if (owned_fp) { err |= restore_fp_context(sc); goto out; } if (current == last_task_used_math) { /* Signal handler acquired FPU - give it back */ last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; } if (current->used_math) { /* Undo possible contamination of thread state */ err |= restore_thread_fp_context(sc); } out: return err; }
static int protected_restore_fp_context(struct sigcontext __user *sc) { int err, tmp __maybe_unused; while (1) { lock_fpu_owner(); own_fpu_inatomic(0); err = restore_fp_context(sc); /* this might fail */ unlock_fpu_owner(); if (likely(!err)) break; /* touch the sigcontext and try again */ err = __get_user(tmp, &sc->sc_fpregs[0]) | __get_user(tmp, &sc->sc_fpregs[31]) | __get_user(tmp, &sc->sc_fpc_csr); if (err) break; /* really bad sigcontext */ } return err; }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int err = 0; u64 reg; err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(reg, &sc->sc_mdhi); regs->hi = (int) reg; err |= __get_user(reg, &sc->sc_mdlo); regs->lo = (int) reg; #define restore_gp_reg(i) do { \ err |= __get_user(reg, &sc->sc_regs[i]); \ regs->regs[i] = reg; \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); restore_gp_reg(31); #undef restore_gp_reg err |= __get_user(current->used_math, &sc->sc_used_math); if (current->used_math) { /* restore fpu context if we have used it before */ own_fpu(); err |= restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); } return err; }
asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int owned_fp; int err = 0; u64 reg; err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(reg, &sc->sc_mdhi); regs->hi = (int) reg; err |= __get_user(reg, &sc->sc_mdlo); regs->lo = (int) reg; #define restore_gp_reg(i) do { \ err |= __get_user(reg, &sc->sc_regs[i]); \ regs->regs[i] = reg; \ } while(0); restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); restore_gp_reg(31); #undef restore_gp_reg err |= __get_user(owned_fp, &sc->sc_ownedfp); if (owned_fp) { err |= restore_fp_context(sc); last_task_used_math = current; } return err; }