/* Returns non-zero on fault. */ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { _sigregs user_sregs; save_access_regs(current->thread.acrs); /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ user_sregs.regs.psw.mask = PSW_USER_BITS | (regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); user_sregs.regs.psw.addr = regs->psw.addr; memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, sizeof(user_sregs.regs.acrs)); /* * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ save_fp_ctl(¤t->thread.fp_regs.fpc); save_fp_regs(current->thread.fp_regs.fprs); memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, sizeof(user_sregs.fpregs)); if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) return -EFAULT; return 0; }
/* Returns non-zero on fault. */ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { unsigned long old_mask = regs->psw.mask; int err; save_access_regs(current->thread.acrs); /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); err = __copy_to_user(&sregs->regs.psw, ®s->psw, sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs)); regs->psw.mask = old_mask; if (err != 0) return err; err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs, sizeof(sregs->regs.acrs)); if (err != 0) return err; /* * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ save_fp_regs(¤t->thread.fp_regs); return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs, sizeof(s390_fp_regs)); }
/* * Returns the address space associated with the fault. * Returns 0 for kernel space, 1 for user space and * 2 for code execution in user space with noexec=on. */ static inline int check_space(struct task_struct *tsk) { /* * The lowest two bits of S390_lowcore.trans_exc_code * indicate which paging table was used. */ int desc = S390_lowcore.trans_exc_code & 3; if (desc == 3) /* Home Segment Table Descriptor */ return switch_amode == 0; if (desc == 2) /* Secondary Segment Table Descriptor */ return tsk->thread.mm_segment.ar4; #ifdef CONFIG_S390_SWITCH_AMODE if (unlikely(desc == 1)) { /* STD determined via access register */ /* %a0 always indicates primary space. */ if (S390_lowcore.exc_access_id != 0) { save_access_regs(tsk->thread.acrs); /* * An alet of 0 indicates primary space. * An alet of 1 indicates secondary space. * Any other alet values generate an * alen-translation exception. */ if (tsk->thread.acrs[S390_lowcore.exc_access_id]) return tsk->thread.mm_segment.ar4; } } #endif /* Primary Segment Table Descriptor */ return switch_amode << s390_noexec; }
static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs) { int i; memcpy(®s->psw.mask, &ptregs->psw.mask, 4); memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4); for (i = 0; i < NUM_GPRS; i++) regs->gprs[i] = ptregs->gprs[i]; save_access_regs(regs->acrs); regs->orig_gpr2 = ptregs->orig_gpr2; return 1; }
/* Store registers needed to create the signal frame */ static void store_sigregs(void) { int i; save_access_regs(current->thread.acrs); save_fp_ctl(¤t->thread.fp_regs.fpc); if (current->thread.vxrs) { save_vx_regs(current->thread.vxrs); for (i = 0; i < __NUM_FPRS; i++) current->thread.fp_regs.fprs[i] = *(freg_t *)(current->thread.vxrs + i); } else save_fp_regs(current->thread.fp_regs.fprs); }
/* * Check which address space the address belongs to. * Returns 1 for user space and 0 for kernel space. */ static inline int check_user_space(struct pt_regs *regs, int error_code) { /* * The lowest two bits of S390_lowcore.trans_exc_code indicate * which paging table was used: * 0: Primary Segment Table Descriptor * 1: STD determined via access register * 2: Secondary Segment Table Descriptor * 3: Home Segment Table Descriptor */ int descriptor = S390_lowcore.trans_exc_code & 3; if (descriptor == 1) { save_access_regs(current->thread.acrs); return __check_access_register(regs, error_code); } return descriptor >> 1; }
static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) { _s390_regs_common32 regs32; int err, i; regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits, (__u32)(regs->psw.mask >> 32)); regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; for (i = 0; i < NUM_GPRS; i++) regs32.gprs[i] = (__u32) regs->gprs[i]; save_access_regs(current->thread.acrs); memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs)); err = __copy_to_user(&sregs->regs, ®s32, sizeof(regs32)); if (err) return err; save_fp_regs(¤t->thread.fp_regs); /* s390_fp_regs and _s390_fp_regs32 are the same ! */ return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs, sizeof(_s390_fp_regs32)); }
/* * Check which address space is addressed by the access * register in S390_lowcore.exc_access_id. * Returns 1 for user space and 0 for kernel space. */ static int __check_access_register(struct pt_regs *regs, int error_code) { int areg = S390_lowcore.exc_access_id; if (areg == 0) /* Access via access register 0 -> kernel address */ return 0; save_access_regs(current->thread.acrs); if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1) /* * access register contains 0 -> kernel address, * access register contains 1 -> user space address */ return current->thread.acrs[areg]; /* Something unhealthy was done with the access registers... */ die("page fault via unknown access register", regs, error_code); do_exit(SIGKILL); return 0; }
/* Returns non-zero on fault. */ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { _sigregs user_sregs; save_access_regs(current->thread.acrs); /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask); user_sregs.regs.psw.addr = regs->psw.addr; memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, sizeof(sregs->regs.acrs)); /* * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ save_fp_regs(¤t->thread.fp_regs); memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, sizeof(s390_fp_regs)); return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs)); }
static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) { _sigregs32 user_sregs; int i; user_sregs.regs.psw.mask = (__u32)(regs->psw.mask >> 32); user_sregs.regs.psw.mask &= PSW32_MASK_USER | PSW32_MASK_RI; user_sregs.regs.psw.mask |= psw32_user_bits; user_sregs.regs.psw.addr = (__u32) regs->psw.addr | (__u32)(regs->psw.mask & PSW_MASK_BA); for (i = 0; i < NUM_GPRS; i++) user_sregs.regs.gprs[i] = (__u32) regs->gprs[i]; save_access_regs(current->thread.acrs); memcpy(&user_sregs.regs.acrs, current->thread.acrs, sizeof(user_sregs.regs.acrs)); save_fp_ctl(¤t->thread.fp_regs.fpc); save_fp_regs(current->thread.fp_regs.fprs); memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, sizeof(user_sregs.fpregs)); if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32))) return -EFAULT; return 0; }
int copy_thread(unsigned long clone_flags, unsigned long new_stackp, unsigned long arg, struct task_struct *p) { struct thread_info *ti; struct fake_frame { struct stack_frame sf; struct pt_regs childregs; } *frame; frame = container_of(task_pt_regs(p), struct fake_frame, childregs); p->thread.ksp = (unsigned long) frame; /* Save access registers to new thread structure. */ save_access_regs(&p->thread.acrs[0]); /* start new process with ar4 pointing to the correct address space */ p->thread.mm_segment = get_fs(); /* Don't copy debug registers */ memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); clear_tsk_thread_flag(p, TIF_SINGLE_STEP); /* Initialize per thread user and system timer values */ ti = task_thread_info(p); ti->user_timer = 0; ti->system_timer = 0; frame->sf.back_chain = 0; /* new return point is ret_from_fork */ frame->sf.gprs[8] = (unsigned long) ret_from_fork; /* fake return stack for resume(), don't go back to schedule */ frame->sf.gprs[9] = (unsigned long) frame; /* Store access registers to kernel stack of new process. */ if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ memset(&frame->childregs, 0, sizeof(struct pt_regs)); frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; frame->childregs.psw.addr = PSW_ADDR_AMODE | (unsigned long) kernel_thread_starter; frame->childregs.gprs[9] = new_stackp; /* function */ frame->childregs.gprs[10] = arg; frame->childregs.gprs[11] = (unsigned long) do_exit; frame->childregs.orig_gpr2 = -1; return 0; } frame->childregs = *current_pt_regs(); frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ frame->childregs.flags = 0; if (new_stackp) frame->childregs.gprs[15] = new_stackp; /* Don't copy runtime instrumentation info */ p->thread.ri_cb = NULL; p->thread.ri_signum = 0; frame->childregs.psw.mask &= ~PSW_MASK_RI; #ifndef CONFIG_64BIT /* * save fprs to current->thread.fp_regs to merge them with * the emulated registers and then copy the result to the child. */ save_fp_ctl(¤t->thread.fp_regs.fpc); save_fp_regs(current->thread.fp_regs.fprs); memcpy(&p->thread.fp_regs, ¤t->thread.fp_regs, sizeof(s390_fp_regs)); /* Set a new TLS ? */ if (clone_flags & CLONE_SETTLS) p->thread.acrs[0] = frame->childregs.gprs[6]; #else /* CONFIG_64BIT */ /* Save the fpu registers to new thread structure. */ save_fp_ctl(&p->thread.fp_regs.fpc); save_fp_regs(p->thread.fp_regs.fprs); p->thread.fp_regs.pad = 0; /* Set a new TLS ? */ if (clone_flags & CLONE_SETTLS) { unsigned long tls = frame->childregs.gprs[6]; if (is_compat_task()) { p->thread.acrs[0] = (unsigned int)tls; } else { p->thread.acrs[0] = (unsigned int)(tls >> 32); p->thread.acrs[1] = (unsigned int)tls; } }
/* Store registers needed to create the signal frame */ static void store_sigregs(void) { save_access_regs(current->thread.acrs); save_fpu_regs(); }