Loading arch/arm64/kernel/ptrace.c +38 −29 Original line number Diff line number Diff line Loading @@ -1237,6 +1237,22 @@ enum compat_regset { REGSET_COMPAT_VFP, }; static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx) { struct pt_regs *regs = task_pt_regs(task); switch (idx) { case 15: return regs->pc; case 16: return pstate_to_compat_psr(regs->pstate); case 17: return regs->orig_x0; default: return regs->regs[idx]; } } static int compat_gpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, Loading @@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target, return -EIO; for (i = 0; i < num_regs; ++i) { unsigned int idx = start + i; compat_ulong_t reg; switch (idx) { case 15: reg = task_pt_regs(target)->pc; break; case 16: reg = task_pt_regs(target)->pstate; reg = pstate_to_compat_psr(reg); break; case 17: reg = task_pt_regs(target)->orig_x0; break; default: reg = task_pt_regs(target)->regs[idx]; } compat_ulong_t reg = compat_get_user_reg(target, start + i); if (kbuf) { memcpy(kbuf, ®, sizeof(reg)); Loading Loading @@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, else if (off == COMPAT_PT_TEXT_END_ADDR) tmp = tsk->mm->end_code; else if (off < sizeof(compat_elf_gregset_t)) return copy_regset_to_user(tsk, &user_aarch32_view, REGSET_COMPAT_GPR, off, sizeof(compat_ulong_t), ret); tmp = compat_get_user_reg(tsk, off >> 2); else if (off >= COMPAT_USER_SZ) return -EIO; else Loading @@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, compat_ulong_t val) { int ret; mm_segment_t old_fs = get_fs(); struct pt_regs newregs = *task_pt_regs(tsk); unsigned int idx = off / 4; if (off & 3 || off >= COMPAT_USER_SZ) return -EIO; Loading @@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, if (off >= sizeof(compat_elf_gregset_t)) return 0; set_fs(KERNEL_DS); ret = copy_regset_from_user(tsk, &user_aarch32_view, REGSET_COMPAT_GPR, off, sizeof(compat_ulong_t), &val); set_fs(old_fs); switch (idx) { case 15: newregs.pc = val; break; case 16: newregs.pstate = compat_psr_to_pstate(val); break; case 17: newregs.orig_x0 = val; break; default: newregs.regs[idx] = val; } if (!valid_user_regs(&newregs.user_regs, tsk)) return -EINVAL; return ret; *task_pt_regs(tsk) = newregs; return 0; } #ifdef CONFIG_HAVE_HW_BREAKPOINT Loading arch/ia64/kernel/ptrace.c +98 −177 Original line number Diff line number Diff line Loading @@ -1273,52 +1273,43 @@ struct regset_getset { int ret; }; static const ptrdiff_t pt_offsets[32] = { #define R(n) offsetof(struct pt_regs, r##n) [0] = -1, R(1), R(2), R(3), [4] = -1, [5] = -1, [6] = -1, [7] = -1, R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), #undef R }; static int access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info, unsigned long addr, unsigned long *data, int write_access) { struct pt_regs *pt; unsigned long *ptr = NULL; int ret; char nat = 0; struct pt_regs *pt = task_pt_regs(target); unsigned reg = addr / sizeof(unsigned long); ptrdiff_t d = pt_offsets[reg]; pt = task_pt_regs(target); switch (addr) { case ELF_GR_OFFSET(1): ptr = &pt->r1; break; case ELF_GR_OFFSET(2): case ELF_GR_OFFSET(3): ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2)); break; case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7): if (d >= 0) { unsigned long *ptr = (void *)pt + d; if (write_access) *ptr = *data; else *data = *ptr; return 0; } else { char nat = 0; if (write_access) { /* read NaT bit first: */ unsigned long dummy; ret = unw_get_gr(info, addr/8, &dummy, &nat); int ret = unw_get_gr(info, reg, &dummy, &nat); if (ret < 0) return ret; } return unw_access_gr(info, addr/8, data, &nat, write_access); case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11): ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8); break; case ELF_GR_OFFSET(12): case ELF_GR_OFFSET(13): ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12); break; case ELF_GR_OFFSET(14): ptr = &pt->r14; break; case ELF_GR_OFFSET(15): ptr = &pt->r15; return unw_access_gr(info, reg, data, &nat, write_access); } if (write_access) *ptr = *data; else *data = *ptr; return 0; } static int Loading Loading @@ -1490,7 +1481,7 @@ static int access_elf_reg(struct task_struct *target, struct unw_frame_info *info, unsigned long addr, unsigned long *data, int write_access) { if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15)) if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31)) return access_elf_gpreg(target, info, addr, data, write_access); else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7)) return access_elf_breg(target, info, addr, data, write_access); Loading @@ -1500,10 +1491,7 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info, void do_gpregs_get(struct unw_frame_info *info, void *arg) { struct pt_regs *pt; struct regset_getset *dst = arg; elf_greg_t tmp[16]; unsigned int i, index, min_copy; if (unw_unwind_to_user(info) < 0) return; Loading @@ -1526,160 +1514,70 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg) &dst->u.get.kbuf, &dst->u.get.ubuf, 0, ELF_GR_OFFSET(1)); if (dst->ret || dst->count == 0) return; } /* gr1 - gr15 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_GR_OFFSET(16); for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); if (dst->ret || dst->count == 0) if (dst->ret) return; } /* r16-r31 */ if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { pt = task_pt_regs(dst->target); dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16, ELF_GR_OFFSET(16), ELF_NAT_OFFSET); if (dst->ret || dst->count == 0) return; } while (dst->count && dst->pos < ELF_AR_END_OFFSET) { unsigned int n, from, to; elf_greg_t tmp[16]; /* nat, pr, b0 - b7 */ if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_CR_IIP_OFFSET; for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { from = dst->pos; to = from + min(dst->count, (unsigned)sizeof(tmp)); if (to > ELF_AR_END_OFFSET) to = ELF_AR_END_OFFSET; for (n = 0; from < to; from += sizeof(elf_greg_t), n++) { if (access_elf_reg(dst->target, info, from, &tmp[n], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); if (dst->ret || dst->count == 0) return; } /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_AR_END_OFFSET; for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); dst->pos, to); if (dst->ret) return; } } void do_gpregs_set(struct unw_frame_info *info, void *arg) { struct pt_regs *pt; struct regset_getset *dst = arg; elf_greg_t tmp[16]; unsigned int i, index; if (unw_unwind_to_user(info) < 0) return; if (!dst->count) return; /* Skip r0 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { if (dst->pos < ELF_GR_OFFSET(1)) { dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, 0, ELF_GR_OFFSET(1)); if (dst->ret || dst->count == 0) return; } /* gr1-gr15 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { i = dst->pos; index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); if (dst->ret) return; for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { dst->ret = -EIO; return; } if (dst->count == 0) return; } /* gr16-gr31 */ if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { pt = task_pt_regs(dst->target); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16, ELF_GR_OFFSET(16), ELF_NAT_OFFSET); if (dst->ret || dst->count == 0) return; } /* nat, pr, b0 - b7 */ if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { i = dst->pos; index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); if (dst->ret) return; for (; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { dst->ret = -EIO; return; } if (dst->count == 0) return; } while (dst->count && dst->pos < ELF_AR_END_OFFSET) { unsigned int n, from, to; elf_greg_t tmp[16]; /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { i = dst->pos; index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); from = dst->pos; to = from + sizeof(tmp); if (to > ELF_AR_END_OFFSET) to = ELF_AR_END_OFFSET; /* get up to 16 values */ dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); from, to); if (dst->ret) return; for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { /* now copy them into registers */ for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++) if (access_elf_reg(dst->target, info, from, &tmp[n], 1) < 0) { dst->ret = -EIO; return; } Loading Loading @@ -1913,7 +1811,6 @@ access_uarea(struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { unsigned int pos = -1; /* an invalid value */ int ret; unsigned long *ptr, regnum; if ((addr & 0x7) != 0) { Loading Loading @@ -1945,14 +1842,39 @@ access_uarea(struct task_struct *child, unsigned long addr, } if (pos != -1) { unsigned reg = pos / sizeof(elf_fpreg_t); int which_half = (pos / sizeof(unsigned long)) & 1; if (reg < 32) { /* fr2-fr31 */ struct unw_frame_info info; elf_fpreg_t fpreg; memset(&info, 0, sizeof(info)); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) return 0; if (unw_get_fr(&info, reg, &fpreg)) return -1; if (write_access) { fpreg.u.bits[which_half] = *data; if (unw_set_fr(&info, reg, fpreg)) return -1; } else { *data = fpreg.u.bits[which_half]; } } else { /* fph */ elf_fpreg_t *p = &child->thread.fph[reg - 32]; unsigned long *bits = &p->u.bits[which_half]; ia64_sync_fph(child); if (write_access) ret = fpregs_set(child, NULL, pos, sizeof(unsigned long), data, NULL); *bits = *data; else if (child->thread.flags & IA64_THREAD_FPH_VALID) *data = *bits; else ret = fpregs_get(child, NULL, pos, sizeof(unsigned long), data, NULL); if (ret != 0) return -1; *data = 0; } return 0; } Loading Loading @@ -2038,15 +1960,14 @@ access_uarea(struct task_struct *child, unsigned long addr, } if (pos != -1) { if (write_access) ret = gpregs_set(child, NULL, pos, sizeof(unsigned long), data, NULL); else ret = gpregs_get(child, NULL, pos, sizeof(unsigned long), data, NULL); if (ret != 0) return -1; struct unw_frame_info info; memset(&info, 0, sizeof(info)); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) return 0; return access_elf_reg(child, &info, pos, data, write_access); } /* access debug registers */ Loading arch/sparc/kernel/ptrace_32.c +155 −71 Original line number Diff line number Diff line Loading @@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target, if (ret || !count) return ret; if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs)) return -EFAULT; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 16 * sizeof(u32), 32 * sizeof(u32)); if (ret || !count) if (ret) return ret; } uregs[0] = regs->psr; uregs[1] = regs->pc; Loading Loading @@ -139,7 +137,6 @@ static int genregs32_set(struct task_struct *target, if (ret || !count) return ret; if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs)) return -EFAULT; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, Loading @@ -151,7 +148,7 @@ static int genregs32_set(struct task_struct *target, return -EFAULT; if (!count) return 0; } ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &psr, 32 * sizeof(u32), 33 * sizeof(u32)); Loading Loading @@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target, user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 32 * sizeof(u32), 33 * sizeof(u32)); if (!ret && count > 0) { if (!ret) ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 33 * sizeof(u32), 34 * sizeof(u32)); } if (!ret) ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 34 * sizeof(u32), -1); Loading Loading @@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = { }, }; static int getregs_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; u32 v[4]; int ret; if (target == current) flush_user_windows(); v[0] = regs->psr; v[1] = regs->pc; v[2] = regs->npc; v[3] = regs->y; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, v, 0 * sizeof(u32), 4 * sizeof(u32)); if (ret) return ret; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs + 1, 4 * sizeof(u32), 19 * sizeof(u32)); } static int setregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { struct pt_regs *regs = target->thread.kregs; u32 v[4]; int ret; if (target == current) flush_user_windows(); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, v, 0, 4 * sizeof(u32)); if (ret) return ret; regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) | (v[0] & (PSR_ICC | PSR_SYSCALL)); regs->pc = v[1]; regs->npc = v[2]; regs->y = v[3]; return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs + 1, 4 * sizeof(u32) , 19 * sizeof(u32)); } static int getfpregs_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) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 32 * sizeof(u32), 33 * sizeof(u32)); if (ret) return ret; return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 33 * sizeof(u32), 68 * sizeof(u32)); } static int setfpregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { unsigned long *fpregs = target->thread.float_regs; int ret; #if 0 if (target == current) save_and_clear_fpu(); #endif ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fpregs, 0, 32 * sizeof(u32)); if (ret) return ret; return user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 32 * sizeof(u32), 33 * sizeof(u32)); } static const struct user_regset ptrace32_regsets[] = { [REGSET_GENERAL] = { .n = 19, .size = sizeof(u32), .get = getregs_get, .set = setregs_set, }, [REGSET_FP] = { .n = 68, .size = sizeof(u32), .get = getfpregs_get, .set = setfpregs_set, }, }; static const struct user_regset_view ptrace32_view = { .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets) }; static const struct user_regset_view user_sparc32_view = { .name = "sparc", .e_machine = EM_SPARC, .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) Loading Loading @@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request, { unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; void __user *addr2p; const struct user_regset_view *view; struct pt_regs __user *pregs; struct fps __user *fps; int ret; view = task_user_regset_view(current); addr2p = (void __user *) addr2; pregs = (struct pt_regs __user *) addr; fps = (struct fps __user *) addr; switch(request) { case PTRACE_GETREGS: { ret = copy_regset_to_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), &pregs->psr); if (!ret) copy_regset_to_user(child, view, REGSET_GENERAL, 1 * sizeof(u32), 15 * sizeof(u32), &pregs->u_regs[0]); ret = copy_regset_to_user(child, &ptrace32_view, REGSET_GENERAL, 0, 19 * sizeof(u32), pregs); break; } case PTRACE_SETREGS: { ret = copy_regset_from_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), &pregs->psr); if (!ret) copy_regset_from_user(child, view, REGSET_GENERAL, 1 * sizeof(u32), 15 * sizeof(u32), &pregs->u_regs[0]); ret = copy_regset_from_user(child, &ptrace32_view, REGSET_GENERAL, 0, 19 * sizeof(u32), pregs); break; } case PTRACE_GETFPREGS: { ret = copy_regset_to_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), &fps->regs[0]); if (!ret) ret = copy_regset_to_user(child, view, REGSET_FP, 33 * sizeof(u32), 1 * sizeof(u32), &fps->fsr); if (!ret) { if (__put_user(0, &fps->fpqd) || __put_user(0, &fps->flags) || __put_user(0, &fps->extra) || clear_user(fps->fpq, sizeof(fps->fpq))) ret = -EFAULT; } ret = copy_regset_to_user(child, &ptrace32_view, REGSET_FP, 0, 68 * sizeof(u32), fps); break; } case PTRACE_SETFPREGS: { ret = copy_regset_from_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), &fps->regs[0]); if (!ret) ret = copy_regset_from_user(child, view, REGSET_FP, ret = copy_regset_from_user(child, &ptrace32_view, REGSET_FP, 0, 33 * sizeof(u32), 1 * sizeof(u32), &fps->fsr); fps); break; } Loading arch/sparc/kernel/ptrace_64.c +291 −110 File changed.Preview size limit exceeded, changes collapsed. Show changes arch/x86/include/asm/fpu/internal.h +0 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src); extern void fpu__clear_user_states(struct fpu *fpu); extern void fpu__clear_all(struct fpu *fpu); extern int fpu__exception_code(struct fpu *fpu, int trap_nr); extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate); /* * Boot time FPU initialization functions: Loading Loading
arch/arm64/kernel/ptrace.c +38 −29 Original line number Diff line number Diff line Loading @@ -1237,6 +1237,22 @@ enum compat_regset { REGSET_COMPAT_VFP, }; static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx) { struct pt_regs *regs = task_pt_regs(task); switch (idx) { case 15: return regs->pc; case 16: return pstate_to_compat_psr(regs->pstate); case 17: return regs->orig_x0; default: return regs->regs[idx]; } } static int compat_gpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, Loading @@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target, return -EIO; for (i = 0; i < num_regs; ++i) { unsigned int idx = start + i; compat_ulong_t reg; switch (idx) { case 15: reg = task_pt_regs(target)->pc; break; case 16: reg = task_pt_regs(target)->pstate; reg = pstate_to_compat_psr(reg); break; case 17: reg = task_pt_regs(target)->orig_x0; break; default: reg = task_pt_regs(target)->regs[idx]; } compat_ulong_t reg = compat_get_user_reg(target, start + i); if (kbuf) { memcpy(kbuf, ®, sizeof(reg)); Loading Loading @@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, else if (off == COMPAT_PT_TEXT_END_ADDR) tmp = tsk->mm->end_code; else if (off < sizeof(compat_elf_gregset_t)) return copy_regset_to_user(tsk, &user_aarch32_view, REGSET_COMPAT_GPR, off, sizeof(compat_ulong_t), ret); tmp = compat_get_user_reg(tsk, off >> 2); else if (off >= COMPAT_USER_SZ) return -EIO; else Loading @@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, compat_ulong_t val) { int ret; mm_segment_t old_fs = get_fs(); struct pt_regs newregs = *task_pt_regs(tsk); unsigned int idx = off / 4; if (off & 3 || off >= COMPAT_USER_SZ) return -EIO; Loading @@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, if (off >= sizeof(compat_elf_gregset_t)) return 0; set_fs(KERNEL_DS); ret = copy_regset_from_user(tsk, &user_aarch32_view, REGSET_COMPAT_GPR, off, sizeof(compat_ulong_t), &val); set_fs(old_fs); switch (idx) { case 15: newregs.pc = val; break; case 16: newregs.pstate = compat_psr_to_pstate(val); break; case 17: newregs.orig_x0 = val; break; default: newregs.regs[idx] = val; } if (!valid_user_regs(&newregs.user_regs, tsk)) return -EINVAL; return ret; *task_pt_regs(tsk) = newregs; return 0; } #ifdef CONFIG_HAVE_HW_BREAKPOINT Loading
arch/ia64/kernel/ptrace.c +98 −177 Original line number Diff line number Diff line Loading @@ -1273,52 +1273,43 @@ struct regset_getset { int ret; }; static const ptrdiff_t pt_offsets[32] = { #define R(n) offsetof(struct pt_regs, r##n) [0] = -1, R(1), R(2), R(3), [4] = -1, [5] = -1, [6] = -1, [7] = -1, R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), #undef R }; static int access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info, unsigned long addr, unsigned long *data, int write_access) { struct pt_regs *pt; unsigned long *ptr = NULL; int ret; char nat = 0; struct pt_regs *pt = task_pt_regs(target); unsigned reg = addr / sizeof(unsigned long); ptrdiff_t d = pt_offsets[reg]; pt = task_pt_regs(target); switch (addr) { case ELF_GR_OFFSET(1): ptr = &pt->r1; break; case ELF_GR_OFFSET(2): case ELF_GR_OFFSET(3): ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2)); break; case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7): if (d >= 0) { unsigned long *ptr = (void *)pt + d; if (write_access) *ptr = *data; else *data = *ptr; return 0; } else { char nat = 0; if (write_access) { /* read NaT bit first: */ unsigned long dummy; ret = unw_get_gr(info, addr/8, &dummy, &nat); int ret = unw_get_gr(info, reg, &dummy, &nat); if (ret < 0) return ret; } return unw_access_gr(info, addr/8, data, &nat, write_access); case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11): ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8); break; case ELF_GR_OFFSET(12): case ELF_GR_OFFSET(13): ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12); break; case ELF_GR_OFFSET(14): ptr = &pt->r14; break; case ELF_GR_OFFSET(15): ptr = &pt->r15; return unw_access_gr(info, reg, data, &nat, write_access); } if (write_access) *ptr = *data; else *data = *ptr; return 0; } static int Loading Loading @@ -1490,7 +1481,7 @@ static int access_elf_reg(struct task_struct *target, struct unw_frame_info *info, unsigned long addr, unsigned long *data, int write_access) { if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15)) if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31)) return access_elf_gpreg(target, info, addr, data, write_access); else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7)) return access_elf_breg(target, info, addr, data, write_access); Loading @@ -1500,10 +1491,7 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info, void do_gpregs_get(struct unw_frame_info *info, void *arg) { struct pt_regs *pt; struct regset_getset *dst = arg; elf_greg_t tmp[16]; unsigned int i, index, min_copy; if (unw_unwind_to_user(info) < 0) return; Loading @@ -1526,160 +1514,70 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg) &dst->u.get.kbuf, &dst->u.get.ubuf, 0, ELF_GR_OFFSET(1)); if (dst->ret || dst->count == 0) return; } /* gr1 - gr15 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_GR_OFFSET(16); for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); if (dst->ret || dst->count == 0) if (dst->ret) return; } /* r16-r31 */ if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { pt = task_pt_regs(dst->target); dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16, ELF_GR_OFFSET(16), ELF_NAT_OFFSET); if (dst->ret || dst->count == 0) return; } while (dst->count && dst->pos < ELF_AR_END_OFFSET) { unsigned int n, from, to; elf_greg_t tmp[16]; /* nat, pr, b0 - b7 */ if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_CR_IIP_OFFSET; for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { from = dst->pos; to = from + min(dst->count, (unsigned)sizeof(tmp)); if (to > ELF_AR_END_OFFSET) to = ELF_AR_END_OFFSET; for (n = 0; from < to; from += sizeof(elf_greg_t), n++) { if (access_elf_reg(dst->target, info, from, &tmp[n], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); if (dst->ret || dst->count == 0) return; } /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ? (dst->pos + dst->count) : ELF_AR_END_OFFSET; for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 0) < 0) { dst->ret = -EIO; return; } dst->ret = user_regset_copyout(&dst->pos, &dst->count, &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); dst->pos, to); if (dst->ret) return; } } void do_gpregs_set(struct unw_frame_info *info, void *arg) { struct pt_regs *pt; struct regset_getset *dst = arg; elf_greg_t tmp[16]; unsigned int i, index; if (unw_unwind_to_user(info) < 0) return; if (!dst->count) return; /* Skip r0 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { if (dst->pos < ELF_GR_OFFSET(1)) { dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, 0, ELF_GR_OFFSET(1)); if (dst->ret || dst->count == 0) return; } /* gr1-gr15 */ if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { i = dst->pos; index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); if (dst->ret) return; for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { dst->ret = -EIO; return; } if (dst->count == 0) return; } /* gr16-gr31 */ if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { pt = task_pt_regs(dst->target); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16, ELF_GR_OFFSET(16), ELF_NAT_OFFSET); if (dst->ret || dst->count == 0) return; } /* nat, pr, b0 - b7 */ if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { i = dst->pos; index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); if (dst->ret) return; for (; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { dst->ret = -EIO; return; } if (dst->count == 0) return; } while (dst->count && dst->pos < ELF_AR_END_OFFSET) { unsigned int n, from, to; elf_greg_t tmp[16]; /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { i = dst->pos; index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); from = dst->pos; to = from + sizeof(tmp); if (to > ELF_AR_END_OFFSET) to = ELF_AR_END_OFFSET; /* get up to 16 values */ dst->ret = user_regset_copyin(&dst->pos, &dst->count, &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); from, to); if (dst->ret) return; for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) if (access_elf_reg(dst->target, info, i, &tmp[index], 1) < 0) { /* now copy them into registers */ for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++) if (access_elf_reg(dst->target, info, from, &tmp[n], 1) < 0) { dst->ret = -EIO; return; } Loading Loading @@ -1913,7 +1811,6 @@ access_uarea(struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { unsigned int pos = -1; /* an invalid value */ int ret; unsigned long *ptr, regnum; if ((addr & 0x7) != 0) { Loading Loading @@ -1945,14 +1842,39 @@ access_uarea(struct task_struct *child, unsigned long addr, } if (pos != -1) { unsigned reg = pos / sizeof(elf_fpreg_t); int which_half = (pos / sizeof(unsigned long)) & 1; if (reg < 32) { /* fr2-fr31 */ struct unw_frame_info info; elf_fpreg_t fpreg; memset(&info, 0, sizeof(info)); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) return 0; if (unw_get_fr(&info, reg, &fpreg)) return -1; if (write_access) { fpreg.u.bits[which_half] = *data; if (unw_set_fr(&info, reg, fpreg)) return -1; } else { *data = fpreg.u.bits[which_half]; } } else { /* fph */ elf_fpreg_t *p = &child->thread.fph[reg - 32]; unsigned long *bits = &p->u.bits[which_half]; ia64_sync_fph(child); if (write_access) ret = fpregs_set(child, NULL, pos, sizeof(unsigned long), data, NULL); *bits = *data; else if (child->thread.flags & IA64_THREAD_FPH_VALID) *data = *bits; else ret = fpregs_get(child, NULL, pos, sizeof(unsigned long), data, NULL); if (ret != 0) return -1; *data = 0; } return 0; } Loading Loading @@ -2038,15 +1960,14 @@ access_uarea(struct task_struct *child, unsigned long addr, } if (pos != -1) { if (write_access) ret = gpregs_set(child, NULL, pos, sizeof(unsigned long), data, NULL); else ret = gpregs_get(child, NULL, pos, sizeof(unsigned long), data, NULL); if (ret != 0) return -1; struct unw_frame_info info; memset(&info, 0, sizeof(info)); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) return 0; return access_elf_reg(child, &info, pos, data, write_access); } /* access debug registers */ Loading
arch/sparc/kernel/ptrace_32.c +155 −71 Original line number Diff line number Diff line Loading @@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target, if (ret || !count) return ret; if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs)) return -EFAULT; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 16 * sizeof(u32), 32 * sizeof(u32)); if (ret || !count) if (ret) return ret; } uregs[0] = regs->psr; uregs[1] = regs->pc; Loading Loading @@ -139,7 +137,6 @@ static int genregs32_set(struct task_struct *target, if (ret || !count) return ret; if (pos < 32 * sizeof(u32)) { if (regwindow32_get(target, regs, uregs)) return -EFAULT; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, Loading @@ -151,7 +148,7 @@ static int genregs32_set(struct task_struct *target, return -EFAULT; if (!count) return 0; } ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &psr, 32 * sizeof(u32), 33 * sizeof(u32)); Loading Loading @@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target, user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 32 * sizeof(u32), 33 * sizeof(u32)); if (!ret && count > 0) { if (!ret) ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 33 * sizeof(u32), 34 * sizeof(u32)); } if (!ret) ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 34 * sizeof(u32), -1); Loading Loading @@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = { }, }; static int getregs_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; u32 v[4]; int ret; if (target == current) flush_user_windows(); v[0] = regs->psr; v[1] = regs->pc; v[2] = regs->npc; v[3] = regs->y; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, v, 0 * sizeof(u32), 4 * sizeof(u32)); if (ret) return ret; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs + 1, 4 * sizeof(u32), 19 * sizeof(u32)); } static int setregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { struct pt_regs *regs = target->thread.kregs; u32 v[4]; int ret; if (target == current) flush_user_windows(); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, v, 0, 4 * sizeof(u32)); if (ret) return ret; regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) | (v[0] & (PSR_ICC | PSR_SYSCALL)); regs->pc = v[1]; regs->npc = v[2]; regs->y = v[3]; return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs + 1, 4 * sizeof(u32) , 19 * sizeof(u32)); } static int getfpregs_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) return ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 32 * sizeof(u32), 33 * sizeof(u32)); if (ret) return ret; return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 33 * sizeof(u32), 68 * sizeof(u32)); } static int setfpregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { unsigned long *fpregs = target->thread.float_regs; int ret; #if 0 if (target == current) save_and_clear_fpu(); #endif ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fpregs, 0, 32 * sizeof(u32)); if (ret) return ret; return user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fsr, 32 * sizeof(u32), 33 * sizeof(u32)); } static const struct user_regset ptrace32_regsets[] = { [REGSET_GENERAL] = { .n = 19, .size = sizeof(u32), .get = getregs_get, .set = setregs_set, }, [REGSET_FP] = { .n = 68, .size = sizeof(u32), .get = getfpregs_get, .set = setfpregs_set, }, }; static const struct user_regset_view ptrace32_view = { .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets) }; static const struct user_regset_view user_sparc32_view = { .name = "sparc", .e_machine = EM_SPARC, .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) Loading Loading @@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request, { unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; void __user *addr2p; const struct user_regset_view *view; struct pt_regs __user *pregs; struct fps __user *fps; int ret; view = task_user_regset_view(current); addr2p = (void __user *) addr2; pregs = (struct pt_regs __user *) addr; fps = (struct fps __user *) addr; switch(request) { case PTRACE_GETREGS: { ret = copy_regset_to_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), &pregs->psr); if (!ret) copy_regset_to_user(child, view, REGSET_GENERAL, 1 * sizeof(u32), 15 * sizeof(u32), &pregs->u_regs[0]); ret = copy_regset_to_user(child, &ptrace32_view, REGSET_GENERAL, 0, 19 * sizeof(u32), pregs); break; } case PTRACE_SETREGS: { ret = copy_regset_from_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), &pregs->psr); if (!ret) copy_regset_from_user(child, view, REGSET_GENERAL, 1 * sizeof(u32), 15 * sizeof(u32), &pregs->u_regs[0]); ret = copy_regset_from_user(child, &ptrace32_view, REGSET_GENERAL, 0, 19 * sizeof(u32), pregs); break; } case PTRACE_GETFPREGS: { ret = copy_regset_to_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), &fps->regs[0]); if (!ret) ret = copy_regset_to_user(child, view, REGSET_FP, 33 * sizeof(u32), 1 * sizeof(u32), &fps->fsr); if (!ret) { if (__put_user(0, &fps->fpqd) || __put_user(0, &fps->flags) || __put_user(0, &fps->extra) || clear_user(fps->fpq, sizeof(fps->fpq))) ret = -EFAULT; } ret = copy_regset_to_user(child, &ptrace32_view, REGSET_FP, 0, 68 * sizeof(u32), fps); break; } case PTRACE_SETFPREGS: { ret = copy_regset_from_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), &fps->regs[0]); if (!ret) ret = copy_regset_from_user(child, view, REGSET_FP, ret = copy_regset_from_user(child, &ptrace32_view, REGSET_FP, 0, 33 * sizeof(u32), 1 * sizeof(u32), &fps->fsr); fps); break; } Loading
arch/sparc/kernel/ptrace_64.c +291 −110 File changed.Preview size limit exceeded, changes collapsed. Show changes
arch/x86/include/asm/fpu/internal.h +0 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src); extern void fpu__clear_user_states(struct fpu *fpu); extern void fpu__clear_all(struct fpu *fpu); extern int fpu__exception_code(struct fpu *fpu, int trap_nr); extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate); /* * Boot time FPU initialization functions: Loading