/* * Copy the thread state to a regset that can be interpreted by userspace. * * It doesn't matter what our internal pt_regs structure looks like. The * important thing is that we export a consistent view of the thread state * to userspace. As such, we need to make sure that the regset remains * ABI compatible as defined by the struct user_regs_struct: * * (Each item is a 32-bit word) * r0 = 0 (exported for clarity) * 31 GPRS r1-r31 * PC (Program counter) * SR (Supervision register) */ static int genregs_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user * ubuf) { const struct pt_regs *regs = task_pt_regs(target); int ret; /* r0 */ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4); if (!ret) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->gpr+1, 4, 4*32); if (!ret) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->pc, 4*32, 4*33); if (!ret) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->sr, 4*33, 4*34); if (!ret) ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 4*34, -1); return ret; }
static int hw_break_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { unsigned int note_type = regset->core_note_type; int ret, idx = 0, offset, limit; u32 info, ctrl; u64 addr; /* Resource info */ ret = ptrace_hbp_get_resource_info(note_type, &info); if (ret) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, sizeof(info)); if (ret) return ret; /* Pad */ offset = offsetof(struct user_hwdebug_state, pad); ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset, offset + PTRACE_HBP_PAD_SZ); if (ret) return ret; /* (address, ctrl) registers */ offset = offsetof(struct user_hwdebug_state, dbg_regs); limit = regset->n * regset->size; while (count && offset < limit) { ret = ptrace_hbp_get_addr(note_type, target, idx, &addr); if (ret) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr, offset, offset + PTRACE_HBP_ADDR_SZ); if (ret) return ret; offset += PTRACE_HBP_ADDR_SZ; ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); if (ret) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl, offset, offset + PTRACE_HBP_CTRL_SZ); if (ret) return ret; offset += PTRACE_HBP_CTRL_SZ; ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset, offset + PTRACE_HBP_PAD_SZ); if (ret) return ret; offset += PTRACE_HBP_PAD_SZ; idx++; } return 0; }
/* * VFP register get/set implementations. * * With respect to the kernel, struct user_fp is divided into three chunks: * 16 or 32 real VFP registers (d0-d15 or d0-31) * These are transferred to/from the real registers in the task's * vfp_hard_struct. The number of registers depends on the kernel * configuration. * * 16 or 0 fake VFP registers (d16-d31 or empty) * i.e., the user_vfp structure has space for 32 registers even if * the kernel doesn't have them all. * * vfp_get() reads this chunk as zero where applicable * vfp_set() ignores this chunk * * 1 word for the FPSCR * * The bounds-checking logic built into user_regset_copyout and friends * means that we can make a simple sequence of calls to map the relevant data * to/from the specified slice of the user regset structure. */ static int vfp_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { int ret; struct thread_info *thread = task_thread_info(target); struct vfp_hard_struct const *vfp = &thread->vfpstate.hard; const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); vfp_sync_hwstate(thread); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vfp->fpregs, user_fpregs_offset, user_fpregs_offset + sizeof(vfp->fpregs)); if (ret) return ret; ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, user_fpregs_offset + sizeof(vfp->fpregs), user_fpscr_offset); if (ret) return ret; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vfp->fpscr, user_fpscr_offset, user_fpscr_offset + sizeof(vfp->fpscr)); }
int metag_gp_regs_copyout(const struct pt_regs *regs, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { const void *ptr; unsigned long data; int ret; /* D{0-1}.{0-7} */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->ctx.DX, 0, 4*16); if (ret) goto out; /* A{0-1}.{0-1} */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->ctx.AX, 4*16, 4*20); if (ret) goto out; /* A{0-1}.2 */ if (regs->ctx.SaveMask & TBICTX_XEXT_BIT) ptr = regs->ctx.Ext.Ctx.pExt; else ptr = ®s->ctx.Ext.AX2; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ptr, 4*20, 4*22); if (ret) goto out; /* A{0-1}.3 */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->ctx.AX3, 4*22, 4*24); if (ret) goto out; /* PC */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->ctx.CurrPC, 4*24, 4*25); if (ret) goto out; /* TXSTATUS */ data = (unsigned long)regs->ctx.Flags; if (regs->ctx.SaveMask & TBICTX_CBUF_BIT) data |= USER_GP_REGS_STATUS_CATCH_BIT; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &data, 4*25, 4*26); if (ret) goto out; /* TXRPT, TXBPOBITS, TXMODE */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->ctx.CurrRPT, 4*26, 4*29); if (ret) goto out; /* Padding */ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 4*29, 4*30); out: return ret; }
static int fpregs32_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { const unsigned long *fpregs = target->thread.float_regs; int ret = 0; #if 0 if (target == current) save_and_clear_fpu(); #endif ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fpregs, 0, 32 * sizeof(u32)); if (!ret) ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 32 * sizeof(u32), 33 * sizeof(u32)); if (!ret) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 33 * sizeof(u32), 34 * sizeof(u32)); if (!ret) { unsigned long val; val = (1 << 8) | (8 << 16); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &val, 34 * sizeof(u32), 35 * sizeof(u32)); } if (!ret) ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 35 * sizeof(u32), -1); return ret; }
int metag_rp_state_copyout(const struct pt_regs *regs, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { unsigned long mask; u64 *ptr; int ret, i; /* Empty read pipeline */ if (!(regs->ctx.SaveMask & TBICTX_CBRP_BIT)) { ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4*13); goto out; } mask = (regs->ctx.CurrDIVTIME & TXDIVTIME_RPMASK_BITS) >> TXDIVTIME_RPMASK_S; /* Read pipeline entries */ ptr = (void *)®s->extcb0[1]; for (i = 0; i < 6; ++i, ++ptr) { if (mask & (1 << i)) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ptr, 8*i, 8*(i + 1)); else ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 8*i, 8*(i + 1)); if (ret) goto out; } /* Mask of entries */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &mask, 4*12, 4*13); out: return ret; }
int metag_cb_regs_copyout(const struct pt_regs *regs, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { int ret; /* TXCATCH{0-3} */ if (regs->ctx.SaveMask & TBICTX_XCBF_BIT) ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->extcb0, 0, 4*4); else ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4*4); return ret; }
/* * retrieve the contents of MN10300 userspace FPU registers */ static int fpuregs_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { const struct fpu_state_struct *fpregs = &target->thread.fpu_state; int ret; unlazy_fpu(target); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, fpregs, 0, sizeof(*fpregs)); if (ret < 0) return ret; return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, sizeof(*fpregs), -1); }
/* * retrieve the contents of Blackfin userspace general registers */ static int genregs_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { struct pt_regs *regs = task_pt_regs(target); int ret; /* This sucks ... */ regs->usp = target->thread.usp; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, sizeof(*regs)); if (ret < 0) return ret; return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, sizeof(*regs), -1); }
static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { unsigned i; int err; u64 fpr_val; if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) { err = user_regset_copyout(&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++) { fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &fpr_val, i * sizeof(elf_fpreg_t), (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; } } err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fpu.fcr31, NUM_FPU_REGS * sizeof(elf_fpreg_t), (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32)); if (err) return err; /* Zero fill the remaining 4 bytes. */ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, (NUM_FPU_REGS * sizeof(elf_fpreg_t)) + sizeof(u32), sizeof(elf_fpregset_t)); }
/* * retrieve the contents of MN10300 userspace general registers */ static int genregs_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { const struct pt_regs *regs = task_pt_regs(target); int ret; /* we need to skip regs->next */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, PT_ORIG_D0 * sizeof(long)); if (ret < 0) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s->orig_d0, PT_ORIG_D0 * sizeof(long), NR_PTREGS * sizeof(long)); if (ret < 0) return ret; return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, NR_PTREGS * sizeof(long), -1); }
static int genregs32_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { const struct pt_regs *regs = target->thread.kregs; unsigned long __user *reg_window; unsigned long *k = kbuf; unsigned long __user *u = ubuf; unsigned long reg; if (target == current) flush_user_windows(); pos /= sizeof(reg); count /= sizeof(reg); if (kbuf) { for (; count > 0 && pos < 16; count--) *k++ = regs->u_regs[pos++]; reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; reg_window -= 16; for (; count > 0 && pos < 32; count--) { if (get_user(*k++, ®_window[pos++])) return -EFAULT; } } else { for (; count > 0 && pos < 16; count--) { if (put_user(regs->u_regs[pos++], u++)) return -EFAULT; } reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; reg_window -= 16; for (; count > 0 && pos < 32; count--) { if (get_user(reg, ®_window[pos++]) || put_user(reg, u++)) return -EFAULT; } } while (count > 0) { switch (pos) { case 32: /* PSR */ reg = regs->psr; break; case 33: /* PC */ reg = regs->pc; break; case 34: /* NPC */ reg = regs->npc; break; case 35: /* Y */ reg = regs->y; break; case 36: /* WIM */ case 37: /* TBR */ reg = 0; break; default: goto finish; } if (kbuf) *k++ = reg; else if (put_user(reg, u++)) return -EFAULT; pos++; count--; } finish: pos *= sizeof(reg); count *= sizeof(reg); return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 38 * sizeof(reg), -1); }