/* * this routine will put a word on the processes privileged stack. * the offset is how far from the base addr as stored in the THREAD. * this routine assumes that all the privileged stacks are in our * data space. */ static inline int put_user_reg(struct task_struct *task, int offset, long data) { struct pt_regs newregs, *regs = task_pt_regs(task); int ret = -EINVAL; newregs = *regs; newregs.uregs[offset] = data; if (valid_user_regs(&newregs)) { regs->uregs[offset] = data; ret = 0; } return ret; }
/* * Return saved PC of a blocked thread. used in kernel/sched. * resume in entry.S does not create a new stack frame, it * just stores the registers %r6-%r15 to the frame given by * schedule. We want to return the address of the caller of * schedule, so we have to walk the backchain one time to * find the frame schedule() store its return address. */ unsigned long thread_saved_pc(struct task_struct *tsk) { struct stack_frame *sf, *low, *high; if (!tsk || !task_stack_page(tsk)) return 0; low = task_stack_page(tsk); high = (struct stack_frame *) task_pt_regs(tsk); sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN); if (sf <= low || sf > high) return 0; sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN); if (sf <= low || sf > high) return 0; return sf->gprs[8]; }
/* Put registers back to task. */ static void putregs(struct task_struct *child, struct pt_regs *uregs) { struct pt_regs *regs = task_pt_regs(child); /* * Don't allow overwriting the kernel-internal flags word. * But do set PT_FLAGS_RESTORE_REGS so that the kernel will reload * all the callee-saved registers when returning to userspace. */ uregs->flags = regs->flags | PT_FLAGS_RESTORE_REGS; /* Only allow setting the ICS bit in the ex1 word. */ uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1)); *regs = *uregs; }
/* * Similar to pt_regs_to_gdb_regs() except that process is sleeping and so * we may not be able to get all the info. */ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) { struct pt_regs *thread_regs; const int NGPRS = TREG_LAST_GPR + 1; if (task == NULL) return; thread_regs = task_pt_regs(task); memcpy(gdb_regs, thread_regs, NGPRS * sizeof(unsigned long)); memset(&gdb_regs[NGPRS], 0, (TILEGX_PC_REGNUM - NGPRS) * sizeof(unsigned long)); gdb_regs[TILEGX_PC_REGNUM] = thread_regs->pc; gdb_regs[TILEGX_FAULTNUM_REGNUM] = thread_regs->faultnum; }
static void FixPerRegisters(struct task_struct *task) { struct pt_regs *regs; per_struct *per_info; per_cr_words cr_words; regs = task_pt_regs(task); per_info = (per_struct *) &task->thread.per_info; per_info->control_regs.bits.em_instruction_fetch = per_info->single_step | per_info->instruction_fetch; if (per_info->single_step) { per_info->control_regs.bits.starting_addr = 0; #ifdef CONFIG_COMPAT if (is_compat_task()) per_info->control_regs.bits.ending_addr = 0x7fffffffUL; else #endif per_info->control_regs.bits.ending_addr = PSW_ADDR_INSN; } else { per_info->control_regs.bits.starting_addr = per_info->starting_addr; per_info->control_regs.bits.ending_addr = per_info->ending_addr; } /* * if any of the control reg tracing bits are on * we switch on per in the psw */ if (per_info->control_regs.words.cr[0] & PER_EM_MASK) regs->psw.mask |= PSW_MASK_PER; else regs->psw.mask &= ~PSW_MASK_PER; if (per_info->control_regs.bits.em_storage_alteration) per_info->control_regs.bits.storage_alt_space_ctl = 1; else per_info->control_regs.bits.storage_alt_space_ctl = 0; if (task == current) { __ctl_store(cr_words, 9, 11); if (memcmp(&cr_words, &per_info->control_regs.words, sizeof(cr_words)) != 0) __ctl_load(per_info->control_regs.words, 9, 11); } }
static int gpr32_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 = task_pt_regs(target); u32 uregs[ELF_NGREG]; unsigned start, num_regs, i; int err; start = pos / sizeof(u32); num_regs = count / sizeof(u32); if (start + num_regs > ELF_NGREG) return -EIO; err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, sizeof(uregs)); if (err) return err; for (i = start; i < num_regs; i++) { /* * Cast all values to signed here so that if this is a 64-bit * kernel, the supplied 32-bit values will be sign extended. */ switch (i) { case MIPS32_EF_R1 ... MIPS32_EF_R25: /* k0/k1 are ignored. */ case MIPS32_EF_R28 ... MIPS32_EF_R31: regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i]; break; case MIPS32_EF_LO: regs->lo = (s32)uregs[i]; break; case MIPS32_EF_HI: regs->hi = (s32)uregs[i]; break; case MIPS32_EF_CP0_EPC: regs->cp0_epc = (s32)uregs[i]; break; } } return 0; }
long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; switch (request) { case PTRACE_SET_SYSCALL: task_pt_regs(child)->syscallno = data; ret = 0; break; default: ret = ptrace_request(child, request, addr, data); break; } return ret; }
/* Help handler running on IST stack to switch back to user stack for scheduling or signal handling. The actual stack switch is done in entry.S */ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) { struct pt_regs *regs = eregs; /* Did already sync */ if (eregs == (struct pt_regs *)eregs->sp) ; /* Exception from user space */ else if (user_mode(eregs)) regs = task_pt_regs(current); /* Exception from kernel and interrupts are enabled. Move to kernel process stack. */ else if (eregs->flags & X86_EFLAGS_IF) regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); if (eregs != regs) *regs = *eregs; return regs; }
static int gpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { int ret; struct user_pt_regs newregs; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1); if (ret) return ret; if (!valid_user_regs(&newregs)) return -EINVAL; task_pt_regs(target)->user_regs = newregs; return 0; }
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; struct task_struct *tsk; int err; childregs = task_pt_regs(p); *childregs = *regs; childregs->ax = 0; childregs->sp = sp; p->thread.sp = (unsigned long) childregs; p->thread.sp0 = (unsigned long) (childregs+1); p->thread.ip = (unsigned long) ret_from_fork; savesegment(gs, p->thread.gs); tsk = current; if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, IO_BITMAP_BYTES, GFP_KERNEL); if (!p->thread.io_bitmap_ptr) { p->thread.io_bitmap_max = 0; return -ENOMEM; } set_tsk_thread_flag(p, TIF_IO_BITMAP); } err = 0; /* * Set a new TLS for the child thread? */ if (clone_flags & CLONE_SETTLS) err = do_set_thread_area(p, -1, (struct user_desc __user *)childregs->si, 0); if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); p->thread.io_bitmap_max = 0; } return err; }
/* * this gets called so that we can store lazy state into memory and copy the * current task into the new thread. */ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { #ifdef CONFIG_SUPERH32 unlazy_fpu(src, task_pt_regs(src)); #endif *dst = *src; if (src->thread.xstate) { dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL); if (!dst->thread.xstate) return -ENOMEM; memcpy(dst->thread.xstate, src->thread.xstate, xstate_size); } return 0; }
int copy_thread(unsigned long clone_flags, unsigned long stack_start, unsigned long stk_sz, struct task_struct *p) { struct pt_regs *childregs = task_pt_regs(p); memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; /* * Read the current TLS pointer from tpidr_el0 as it may be * out-of-sync with the saved value. */ *task_user_tls(p) = read_sysreg(tpidr_el0); if (stack_start) { if (is_compat_thread(task_thread_info(p))) childregs->compat_sp = stack_start; else childregs->sp = stack_start; } /* * If a TLS pointer was passed to clone (4th argument), use it * for the new thread. */ if (clone_flags & CLONE_SETTLS) p->thread.tp_value = childregs->regs[3]; } else { memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h; if (IS_ENABLED(CONFIG_ARM64_UAO) && cpus_have_const_cap(ARM64_HAS_UAO)) childregs->pstate |= PSR_UAO_BIT; p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; } p->thread.cpu_context.pc = (unsigned long)ret_from_fork; p->thread.cpu_context.sp = (unsigned long)childregs; ptrace_hw_copy_thread(p); return 0; }
int copy_thread(unsigned long clone_flags, unsigned long spu, unsigned long unused, struct task_struct *tsk, struct pt_regs *regs) { struct pt_regs *childregs = task_pt_regs(tsk); extern void ret_from_fork(void); /* Copy registers */ *childregs = *regs; childregs->spu = spu; childregs->r0 = 0; /* Child gets zero as return value */ regs->r0 = tsk->pid; tsk->thread.sp = (unsigned long)childregs; tsk->thread.lr = (unsigned long)ret_from_fork; return 0; }
static int collect_syscall(struct task_struct *target, long *callno, unsigned long args[6], unsigned int maxargs, unsigned long *sp, unsigned long *pc) { struct pt_regs *regs = task_pt_regs(target); if (unlikely(!regs)) return -EAGAIN; *sp = user_stack_pointer(regs); *pc = instruction_pointer(regs); *callno = syscall_get_nr(target, regs); if (*callno != -1L && maxargs > 0) syscall_get_arguments(target, regs, 0, maxargs, args); return 0; }
/* * Endianness is explicitly ignored and left for BPF program authors to manage * as per the specific architecture. */ static void populate_seccomp_data(struct seccomp_data *sd) { struct task_struct *task = current; struct pt_regs *regs = task_pt_regs(task); unsigned long args[6]; sd->nr = syscall_get_nr(task, regs); sd->arch = syscall_get_arch(); syscall_get_arguments(task, regs, 0, 6, args); sd->args[0] = args[0]; sd->args[1] = args[1]; sd->args[2] = args[2]; sd->args[3] = args[3]; sd->args[4] = args[4]; sd->args[5] = args[5]; sd->instruction_pointer = KSTK_EIP(task); }
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, struct task_struct *p) { extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); struct thread_info *childti = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); struct pt_regs *regs = current_pt_regs(); struct switch_stack *childstack, *stack; childstack = ((struct switch_stack *) childregs) - 1; childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ memset(childstack, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs)); childstack->r26 = (unsigned long) ret_from_kernel_thread; childstack->r9 = usp; /* function */ childstack->r10 = arg; childregs->hae = alpha_mv.hae_cache, childti->pcb.usp = 0; return 0; } /* Note: if CLONE_SETTLS is not set, then we must inherit the value from the parent, which will have been set by the block copy in dup_task_struct. This is non-intuitive, but is required for proper operation in the case of a threaded application calling fork. */ if (clone_flags & CLONE_SETTLS) childti->pcb.unique = regs->r20; childti->pcb.usp = usp ?: rdusp(); *childregs = *regs; childregs->r0 = 0; childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; return 0; }
/* Returns the syscall nr to run (which should match regs->orig_ax). */ long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, unsigned long phase1_result) { struct thread_info *ti = pt_regs_to_thread_info(regs); long ret = 0; u32 work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY; if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) BUG_ON(regs != task_pt_regs(current)); /* * If we stepped into a sysenter/syscall insn, it trapped in * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. * If user-mode had set TF itself, then it's still clear from * do_debug() and we need to set it again to restore the user * state. If we entered on the slow path, TF was already set. */ if (work & _TIF_SINGLESTEP) regs->flags |= X86_EFLAGS_TF; #ifdef CONFIG_SECCOMP /* * Call seccomp_phase2 before running the other hooks so that * they can see any changes made by a seccomp tracer. */ if (phase1_result > 1 && seccomp_phase2(phase1_result)) { /* seccomp failures shouldn't expose any additional code. */ return -1; } #endif if (unlikely(work & _TIF_SYSCALL_EMU)) ret = -1L; if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && tracehook_report_syscall_entry(regs)) ret = -1L; if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->orig_ax); do_audit_syscall_entry(regs, arch); return ret ?: regs->orig_ax; }
struct perf_callchain_entry * get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, bool crosstask, bool add_mark) { struct perf_callchain_entry *entry; int rctx; entry = get_callchain_entry(&rctx); if (rctx == -1) return NULL; if (!entry) goto exit_put; entry->nr = init_nr; if (kernel && !user_mode(regs)) { if (add_mark) perf_callchain_store(entry, PERF_CONTEXT_KERNEL); perf_callchain_kernel(entry, regs); } if (user) { if (!user_mode(regs)) { if (current->mm) regs = task_pt_regs(current); else regs = NULL; } if (regs) { if (crosstask) goto exit_put; if (add_mark) perf_callchain_store(entry, PERF_CONTEXT_USER); perf_callchain_user(entry, regs); } } exit_put: put_callchain_entry(rctx); return entry; }
/* * update the contents of the MN10300 userspace general registers */ static int genregs_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 = task_pt_regs(target); unsigned long tmp; int ret; /* we need to skip regs->next */ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, PT_ORIG_D0 * sizeof(long)); if (ret < 0) return ret; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s->orig_d0, PT_ORIG_D0 * sizeof(long), PT_EPSW * sizeof(long)); if (ret < 0) return ret; /* we need to mask off changes to EPSW */ tmp = regs->epsw; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tmp, PT_EPSW * sizeof(long), PT_PC * sizeof(long)); tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z; tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z); regs->epsw = tmp; if (ret < 0) return ret; /* and finally load the PC */ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s->pc, PT_PC * sizeof(long), NR_PTREGS * sizeof(long)); if (ret < 0) return ret; return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, NR_PTREGS * sizeof(long), -1); }
static int gpr64_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 = task_pt_regs(target); u64 uregs[ELF_NGREG]; unsigned start, num_regs, i; int err; start = pos / sizeof(u64); num_regs = count / sizeof(u64); if (start + num_regs > ELF_NGREG) return -EIO; err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, sizeof(uregs)); if (err) return err; for (i = start; i < num_regs; i++) { switch (i) { case MIPS64_EF_R1 ... MIPS64_EF_R25: /* k0/k1 are ignored. */ case MIPS64_EF_R28 ... MIPS64_EF_R31: regs->regs[i - MIPS64_EF_R0] = uregs[i]; break; case MIPS64_EF_LO: regs->lo = uregs[i]; break; case MIPS64_EF_HI: regs->hi = uregs[i]; break; case MIPS64_EF_CP0_EPC: regs->cp0_epc = uregs[i]; break; } } /* System call number may have been changed */ mips_syscall_update_nr(target, regs); return 0; }
/* * Endianness is explicitly ignored and left for BPF program authors to manage * as per the specific architecture. */ static void populate_seccomp_data(struct seccomp_data *sd) { struct task_struct *task = current; struct pt_regs *regs = task_pt_regs(task); sd->nr = syscall_get_nr(task, regs); sd->arch = syscall_get_arch(task, regs); /* Unroll syscall_get_args to help gcc on arm. */ syscall_get_arguments(task, regs, 0, 1, (unsigned long *) &sd->args[0]); syscall_get_arguments(task, regs, 1, 1, (unsigned long *) &sd->args[1]); syscall_get_arguments(task, regs, 2, 1, (unsigned long *) &sd->args[2]); syscall_get_arguments(task, regs, 3, 1, (unsigned long *) &sd->args[3]); syscall_get_arguments(task, regs, 4, 1, (unsigned long *) &sd->args[4]); syscall_get_arguments(task, regs, 5, 1, (unsigned long *) &sd->args[5]); sd->instruction_pointer = KSTK_EIP(task); }
asmlinkage long sys32_sigreturn(void) { struct pt_regs *regs = task_pt_regs(current); sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; sigset_t set; if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) goto badframe; set_current_blocked(&set); if (restore_sigregs32(regs, &frame->sregs)) goto badframe; if (restore_sigregs_gprs_high(regs, frame->gprs_high)) goto badframe; return regs->gprs[2]; badframe: force_sig(SIGSEGV, current); return 0; }
static int gpr_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 newregs; int ret; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, sizeof(newregs)); if (ret) return ret; *task_pt_regs(target) = newregs; return 0; }
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs * childregs; struct switch_stack *swstack; /* put the pt_regs structure at the end of the new kernel stack page and fix it up * remember that the task_struct doubles as the kernel stack for the task */ childregs = task_pt_regs(p); *childregs = *regs; /* struct copy of pt_regs */ p->set_child_tid = p->clear_child_tid = NULL; childregs->r10 = 0; /* child returns 0 after a fork/clone */ /* put the switch stack right below the pt_regs */ swstack = ((struct switch_stack *)childregs) - 1; swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ /* we want to return into ret_from_sys_call after the _resume */ swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */ /* fix the user-mode stackpointer */ p->thread.usp = usp; /* and the kernel-mode one */ p->thread.ksp = (unsigned long) swstack; #ifdef DEBUG printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); show_registers(childregs); #endif return 0; }
/* * Return "current" if it looks plausible, or else a pointer to a dummy. * This can be helpful if we are just trying to emit a clean panic. */ struct task_struct *validate_current(void) { static struct task_struct corrupt = { .comm = "<corrupt>" }; struct task_struct *tsk = current; if (unlikely((unsigned long)tsk < PAGE_OFFSET || (void *)tsk > high_memory || ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) { pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer); tsk = &corrupt; } return tsk; } /* Take and return the pointer to the previous task, for schedule_tail(). */ struct task_struct *sim_notify_fork(struct task_struct *prev) { struct task_struct *tsk = current; __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK_PARENT | (tsk->thread.creator_pid << _SIM_CONTROL_OPERATOR_BITS)); __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK | (tsk->pid << _SIM_CONTROL_OPERATOR_BITS)); return prev; } int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) { struct pt_regs *ptregs = task_pt_regs(tsk); elf_core_copy_regs(regs, ptregs); return 1; } #if CHIP_HAS_TILE_DMA() /* Allow user processes to access the DMA SPRs */ void grant_dma_mpls(void) { #if CONFIG_KERNEL_PL == 2 __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); #else __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1); __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1); #endif }
/* * 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); }
int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; struct task_struct *tsk; childregs = task_pt_regs(p); *childregs = *regs; childregs->ax = 0; childregs->sp = sp; p->thread.sp = (unsigned long)childregs; p->thread.sp0 = (unsigned long)(childregs + 1); p->thread.ip = (unsigned long)ret_from_fork; task_user_gs(p) = get_user_gs(regs); p->thread.io_bitmap_ptr = NULL; tsk = current; err = -ENOMEM; memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); if (test_tsk_thread_flag(tsk, TIF_IO_BITMAP)) { p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, IO_BITMAP_BYTES, GFP_KERNEL); if (!p->thread.io_bitmap_ptr) { p->thread.io_bitmap_max = 0; return -ENOMEM; } set_tsk_thead_flag(p, TIF_IO_BITMAP); } err = 0; if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); p->thread.io_bitmap_max = 0; } return err; }
/* * Get contents of register REGNO in task TASK. */ long get_reg(struct task_struct *task, unsigned int regno) { /* USP is a special case, it's not in the pt_regs struct but * in the tasks thread struct */ unsigned long ret; if (regno <= PT_EDA) ret = ((unsigned long *)task_pt_regs(task))[regno]; else if (regno == PT_USP) ret = task->thread.usp; else if (regno == PT_PPC) ret = get_pseudo_pc(task); else if (regno <= PT_MAX) ret = get_debugreg(task->pid, regno); else ret = 0; return ret; }
/* * Write a general register set. As for PTRACE_GETREGS, we always use * the 64-bit format. On a 32-bit kernel only the lower order half * (according to endianness) will be used. */ int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data) { struct pt_regs *regs; int i; if (!access_ok(VERIFY_READ, data, 38 * 8)) return -EIO; regs = task_pt_regs(child); for (i = 0; i < 32; i++) __get_user(regs->regs[i], (__s64 __user *)&data->regs[i]); __get_user(regs->lo, (__s64 __user *)&data->lo); __get_user(regs->hi, (__s64 __user *)&data->hi); __get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc); /* badvaddr, status, and cause may not be written. */ return 0; }
asmlinkage long sys32_rt_sigreturn(void) { struct pt_regs *regs = task_pt_regs(current); rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; sigset_t set; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; set_current_blocked(&set); if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) goto badframe; if (restore_sigregs_gprs_high(regs, frame->gprs_high)) goto badframe; if (compat_restore_altstack(&frame->uc.uc_stack)) goto badframe; return regs->gprs[2]; badframe: force_sig(SIGSEGV, current); return 0; }