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; }
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; }
int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) { int i; if (!access_ok(VERIFY_WRITE, data, 33 * 8)) return -EIO; if (tsk_used_math(child)) { union fpureg *fregs = get_fpu_regs(child); for (i = 0; i < 32; i++) __put_user(get_fpr64(&fregs[i], 0), i + (__u64 __user *)data); } else { for (i = 0; i < 32; i++) __put_user((__u64) -1, i + (__u64 __user *) data); } __put_user(child->thread.fpu.fcr31, data + 64); __put_user(boot_cpu_data.fpu_id, data + 65); return 0; }
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; }
static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs) { pr_info("Dumping GP/FPU registers for %d\n", pid); /* * This is inspired by kernel function check_syscall_restart in * arch/powerpc/kernel/signal.c */ #ifndef TRAP #define TRAP(r) ((r).trap & ~0xF) #endif if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) { /* Restart the system call */ switch (regs->gpr[3]) { case ERESTARTNOHAND: case ERESTARTSYS: case ERESTARTNOINTR: regs->gpr[3] = regs->orig_gpr3; regs->nip -= 4; break; case ERESTART_RESTARTBLOCK: regs->gpr[0] = __NR_restart_syscall; regs->nip -= 4; break; } } /* Resetting trap since we are now coming from user space. */ regs->trap = 0; fpregs->flags = 0; /* * Check for Transactional Memory operation in progress. * Until we have support of TM register's state through the ptrace API, * we can't checkpoint process with TM operation in progress (almost * impossible) or suspended (easy to get). */ if (MSR_TM_ACTIVE(regs->msr)) { pr_debug("Task %d has %s TM operation at 0x%lx\n", pid, (regs->msr & MSR_TMS) ? "a suspended" : "an active", regs->nip); if (get_tm_regs(pid, fpregs)) return -1; fpregs->flags = USER_FPREGS_FL_TM; } if (get_fpu_regs(pid, fpregs)) return -1; if (get_altivec_regs(pid, fpregs)) return -1; if (fpregs->flags & USER_FPREGS_FL_ALTIVEC) { /* * Save the VSX registers if Altivec registers are supported */ if (get_vsx_regs(pid, fpregs)) return -1; } return 0; }
int get_task_regs(pid_t pid, user_regs_struct_t regs, CoreEntry *core) { int i; pr_info("Dumping GP/FPU registers for %d\n", pid); /* * This is inspired by kernel function check_syscall_restart in * arch/powerpc/kernel/signal.c */ #ifndef TRAP #define TRAP(r) ((r).trap & ~0xF) #endif if (TRAP(regs) == 0x0C00 && regs.ccr & 0x10000000) { /* Restart the system call */ switch (regs.gpr[3]) { case ERESTARTNOHAND: case ERESTARTSYS: case ERESTARTNOINTR: regs.gpr[3] = regs.orig_gpr3; regs.nip -= 4; break; case ERESTART_RESTARTBLOCK: regs.gpr[0] = __NR_restart_syscall; regs.nip -= 4; break; } } /* Resetting trap since we are now comming from user space. */ regs.trap = 0; #define assign_reg(dst, src, e) do { \ dst->e = (__typeof__(dst->e))src.e; \ } while (0) for (i=0; i<32; i++) assign_reg(core->ti_ppc64->gpregs, regs, gpr[i]); assign_reg(core->ti_ppc64->gpregs, regs, nip); assign_reg(core->ti_ppc64->gpregs, regs, msr); assign_reg(core->ti_ppc64->gpregs, regs, orig_gpr3); assign_reg(core->ti_ppc64->gpregs, regs, ctr); assign_reg(core->ti_ppc64->gpregs, regs, link); assign_reg(core->ti_ppc64->gpregs, regs, xer); assign_reg(core->ti_ppc64->gpregs, regs, ccr); assign_reg(core->ti_ppc64->gpregs, regs, trap); #undef assign_reg if (get_fpu_regs(pid, core)) return -1; if (get_altivec_regs(pid, core)) return -1; /* * Don't save the VSX registers if Altivec registers are not * supported */ if (CORE_THREAD_ARCH_INFO(core)->vrstate && get_vsx_regs(pid, core)) return -1; return 0; }