static int protected_restore_fp_context32(struct sigcontext32 __user *sc, unsigned used_math) { int err, tmp __maybe_unused; bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA); while (1) { lock_fpu_owner(); if (is_fpu_owner()) { err = restore_fp_context32(sc); if (restore_msa && !err) { enable_msa(); err = _restore_msa_context32(sc); } else { /* signal handler may have used MSA */ disable_msa(); } unlock_fpu_owner(); } else { unlock_fpu_owner(); err = copy_fp_from_sigcontext32(sc); if (restore_msa && !err) err = copy_msa_from_sigcontext32(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 */ } return err; }
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { unsigned long status; /* New thread loses kernel privileges. */ status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); status |= KU_USER; regs->cp0_status = status; clear_used_math(); clear_fpu_owner(); init_dsp(); clear_thread_flag(TIF_USEDMSA); clear_thread_flag(TIF_MSA_CTX_LIVE); disable_msa(); regs->cp0_epc = pc; regs->regs[29] = sp; }
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; }
int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; unsigned long treg; int err = 0; int i; /* 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); #ifdef CONFIG_CPU_HAS_SMARTMIPS err |= __get_user(regs->acx, &sc->sc_acx); #endif err |= __get_user(regs->hi, &sc->sc_mdhi); err |= __get_user(regs->lo, &sc->sc_mdlo); if (cpu_has_dsp) { err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); } for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); err |= __get_user(used_math, &sc->sc_used_math); conditional_used_math(used_math); if (used_math) { /* restore fpu context if we have used it before */ if (!err) err = check_and_restore_fp_context(sc, used_math); } else { /* signal handler may have used FPU or MSA. Disable them. */ disable_msa(); lose_fpu(0); } return err; }
/* * Helper routines */ static int protected_save_fp_context(struct sigcontext __user *sc, unsigned used_math) { int err; bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA); #ifndef CONFIG_EVA while (1) { lock_fpu_owner(); if (is_fpu_owner()) { err = save_fp_context(sc); if (save_msa && !err) err = _save_msa_context(sc); unlock_fpu_owner(); } else { unlock_fpu_owner(); err = copy_fp_to_sigcontext(sc); if (save_msa && !err) err = copy_msa_to_sigcontext(sc); } if (likely(!err)) break; /* touch the sigcontext and try again */ err = __put_user(0, &sc->sc_fpregs[0]) | __put_user(0, &sc->sc_fpregs[31]) | __put_user(0, &sc->sc_fpc_csr); if (err) break; /* really bad sigcontext */ } #else /* * EVA does not have FPU EVA instructions so saving fpu context directly * does not work. */ disable_msa(); lose_fpu(1); err = save_fp_context(sc); /* this might fail */ if (save_msa && !err) err = copy_msa_to_sigcontext(sc); #endif return err; }