int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { union fpureg *fregs; u64 fpr_val; u32 value; int i; if (!access_ok(VERIFY_READ, data, 33 * 8)) return -EIO; init_fp_ctx(child); fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) { __get_user(fpr_val, i + (__u64 __user *)data); set_fpr64(&fregs[i], 0, fpr_val); } __get_user(value, data + 64); ptrace_setfcr31(child, value); /* FIR may not be written. */ return 0; }
static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { unsigned i; int err; u64 fpr_val; /* XXX fcr31 */ init_fp_ctx(target); if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) return user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fpu, 0, sizeof(elf_fpregset_t)); for (i = 0; i < NUM_FPU_REGS; i++) { err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); } return 0; }
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { union fpureg *fregs; u64 fpr_val; u32 fcr31; u32 value; u32 mask; int i; if (!access_ok(VERIFY_READ, data, 33 * 8)) return -EIO; init_fp_ctx(child); fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) { __get_user(fpr_val, i + (__u64 __user *)data); set_fpr64(&fregs[i], 0, fpr_val); } __get_user(value, data + 64); fcr31 = child->thread.fpu.fcr31; mask = boot_cpu_data.fpu_msk31; child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); /* FIR may not be written. */ return 0; }
static int copy_msa_from_sigcontext32(struct sigcontext32 __user *sc) { int i; int err = 0; u64 val; for (i = 0; i < NUM_FPU_REGS; i++) { err |= __get_user(val, &sc->sc_msaregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 1, val); } err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr); return err; }
static int copy_fp_from_sigcontext(struct sigcontext __user *sc) { int i; int err = 0; u64 fpr_val; for (i = 0; i < NUM_FPU_REGS; i++) { err |= __get_user(fpr_val, &sc->sc_fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; }
static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc) { int i; int err = 0; int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; u64 fpr_val; for (i = 0; i < NUM_FPU_REGS; i += inc) { err |= __get_user(fpr_val, &sc->sc_fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); return err; }
/* * Copy the supplied NT_PRFPREG buffer to the floating-point context, * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64 * bits only of FP context's general register slots. Only general * registers are copied. */ static int fpr_set_msa(struct task_struct *target, unsigned int *pos, unsigned int *count, const void **kbuf, const void __user **ubuf) { unsigned int i; u64 fpr_val; int err; BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { err = user_regset_copyin(pos, count, kbuf, ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); } return 0; }
static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { unsigned i; int err; u64 fpr_val; u32 fcr31; if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) { err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fpu.fpr, 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); if (err) return err; } else { for (i = 0; i < NUM_FPU_REGS; i++) { err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); } } err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fcr31, NUM_FPU_REGS * sizeof(elf_fpreg_t), (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32)); if (err) return err; target->thread.fpu.fcr31 = fcr31 & ~FPU_CSR_ALL_X; return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32), sizeof(elf_fpregset_t)); }
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { union fpureg *fregs; u64 fpr_val; int i; if (!access_ok(VERIFY_READ, data, 33 * 8)) return -EIO; fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) { __get_user(fpr_val, i + (__u64 __user *)data); set_fpr64(&fregs[i], 0, fpr_val); } __get_user(child->thread.fpu.fcr31, data + 64); child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; /* FIR may not be written. */ return 0; }
long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; void __user *addrp = (void __user *) addr; void __user *datavp = (void __user *) data; unsigned long __user *datalp = (void __user *) data; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: ret = generic_ptrace_peekdata(child, addr, data); break; /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; union fpureg *fregs; unsigned long tmp = 0; regs = task_pt_regs(child); ret = 0; /* Default return value. */ switch (addr) { case 0 ... 31: tmp = regs->regs[addr]; break; case FPR_BASE ... FPR_BASE + 31: if (!tsk_used_math(child)) { /* FP not yet used */ tmp = -1; break; } fregs = get_fpu_regs(child); #ifdef CONFIG_32BIT if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers. */ tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE], addr & 1); break; } #endif tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; break; case CAUSE: tmp = regs->cp0_cause; break; case BADVADDR: tmp = regs->cp0_badvaddr; break; case MMHI: tmp = regs->hi; break; case MMLO: tmp = regs->lo; break; #ifdef CONFIG_CPU_HAS_SMARTMIPS case ACX: tmp = regs->acx; break; #endif case FPC_CSR: tmp = child->thread.fpu.fcr31; break; case FPC_EIR: /* implementation / version register */ tmp = boot_cpu_data.fpu_id; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; if (!cpu_has_dsp) { tmp = 0; ret = -EIO; goto out; } dregs = __get_dsp_regs(child); tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: if (!cpu_has_dsp) { tmp = 0; ret = -EIO; goto out; } tmp = child->thread.dsp.dspcontrol; break; default: tmp = 0; ret = -EIO; goto out; } ret = put_user(tmp, datalp); break; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: { struct pt_regs *regs; ret = 0; regs = task_pt_regs(child); switch (addr) { case 0 ... 31: regs->regs[addr] = data; /* System call number may have been changed */ if (addr == 2) mips_syscall_update_nr(child, regs); else if (addr == 4 && mips_syscall_is_indirect(child, regs)) mips_syscall_update_nr(child, regs); break; case FPR_BASE ... FPR_BASE + 31: { union fpureg *fregs = get_fpu_regs(child); init_fp_ctx(child); #ifdef CONFIG_32BIT if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers. */ set_fpr32(&fregs[(addr & ~1) - FPR_BASE], addr & 1, data); break; } #endif set_fpr64(&fregs[addr - FPR_BASE], 0, data); break; } case PC: regs->cp0_epc = data; break; case MMHI: regs->hi = data; break; case MMLO: regs->lo = data; break; #ifdef CONFIG_CPU_HAS_SMARTMIPS case ACX: regs->acx = data; break; #endif case FPC_CSR: init_fp_ctx(child); ptrace_setfcr31(child, data); break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; if (!cpu_has_dsp) { ret = -EIO; break; } dregs = __get_dsp_regs(child); dregs[addr - DSP_BASE] = data; break; } case DSP_CONTROL: if (!cpu_has_dsp) { ret = -EIO; break; } child->thread.dsp.dspcontrol = data; break; default: /* The rest are not allowed. */ ret = -EIO; break; } break; } case PTRACE_GETREGS: ret = ptrace_getregs(child, datavp); break; case PTRACE_SETREGS: ret = ptrace_setregs(child, datavp); break; case PTRACE_GETFPREGS: ret = ptrace_getfpregs(child, datavp); break; case PTRACE_SETFPREGS: ret = ptrace_setfpregs(child, datavp); break; case PTRACE_GET_THREAD_AREA: ret = put_user(task_thread_info(child)->tp_value, datalp); break; case PTRACE_GET_WATCH_REGS: ret = ptrace_get_watch_regs(child, addrp); break; case PTRACE_SET_WATCH_REGS: ret = ptrace_set_watch_regs(child, addrp); break; default: ret = ptrace_request(child, request, addr, data); break; } out: return ret; }