asmlinkage long s390_futex(u32 *uaddr, int op, int val, struct timespec *utime, u32 *uaddr2) { struct pt_regs *regs; regs = __KSTK_PTREGS(current); return sys_futex(uaddr, op, val, utime, uaddr2, regs->gprs[7]); }
/* * Write a word to the user area of a process at location addr. This * operation does have an additional problem compared to peek_user. * Stores to the program status word and on the floating point * control register needs to get checked for validity. */ static int poke_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; addr_t offset, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with * an alignment of 4. Programmers from hell indeed... */ mask = __ADDR_MASK; #ifdef CONFIG_ARCH_S390X if (addr >= (addr_t) &dummy->regs.acrs && addr < (addr_t) &dummy->regs.orig_gpr2) mask = 3; #endif if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { /* * psw and gprs are stored on the stack */ if (addr == (addr_t) &dummy->regs.psw.mask && #ifdef CONFIG_S390_SUPPORT data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && #endif data != PSW_MASK_MERGE(PSW_USER_BITS, data)) /* Invalid psw mask. */ return -EINVAL; #ifndef CONFIG_ARCH_S390X if (addr == (addr_t) &dummy->regs.psw.addr) /* I'd like to reject addresses without the high order bit but older gdb's rely on it */ data |= PSW_ADDR_AMODE; #endif *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data; } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { /* * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy->regs.acrs; #ifdef CONFIG_ARCH_S390X /* * Very special case: old & broken 64 bit gdb writing * to acrs[15] with a 64 bit value. Ignore the lower * half of the value and write the upper 32 bit to * acrs[15]. Sick... */ if (addr == (addr_t) &dummy->regs.acrs[15]) child->thread.acrs[15] = (unsigned int) (data >> 32); else
static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs) { struct pt_regs *ptregs = __KSTK_PTREGS(tsk); 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]; memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs)); regs->orig_gpr2 = ptregs->orig_gpr2; return 1; }
static void FixPerRegisters(struct task_struct *task) { struct pt_regs *regs; per_struct *per_info; regs = __KSTK_PTREGS(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_S390_SUPPORT if (test_thread_flag(TIF_31BIT)) 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; }
void FixPerRegisters(struct task_struct *task) { struct pt_regs *regs = __KSTK_PTREGS(task); per_struct *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; per_info->control_regs.bits.ending_addr=0x7fffffffUL; } 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_PER_MASK; else regs->psw.mask &= ~PSW_PER_MASK; if (per_info->control_regs.bits.em_storage_alteration) { per_info->control_regs.bits.storage_alt_space_ctl=1; //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK; } else { per_info->control_regs.bits.storage_alt_space_ctl=0; //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK; } }
void FixPerRegisters(struct task_struct *task) { struct pt_regs *regs = __KSTK_PTREGS(task); per_struct *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_S390_SUPPORT if (current->thread.flags & S390_FLAG_31BIT) { per_info->control_regs.bits.ending_addr=0x7fffffffUL; } else #endif { per_info->control_regs.bits.ending_addr=-1L; } } 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_PER_MASK; else regs->psw.mask &= ~PSW_PER_MASK; if (per_info->control_regs.bits.storage_alt_space_ctl) task->thread.user_seg |= USER_STD_MASK; else task->thread.user_seg &= ~USER_STD_MASK; }
/* * Read the word at offset addr from the user area of a process. The * trouble here is that the information is littered over different * locations. The process registers are found on the kernel stack, * the floating point stuff and the trace settings are stored in * the task structure. In addition the different structures in * struct user contain pad bytes that should be read as zeroes. * Lovely... */ static int peek_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; addr_t offset, tmp, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with * an alignment of 4. Programmers from hell... */ mask = __ADDR_MASK; #ifdef CONFIG_ARCH_S390X if (addr >= (addr_t) &dummy->regs.acrs && addr < (addr_t) &dummy->regs.orig_gpr2) mask = 3; #endif if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { /* * psw and gprs are stored on the stack */ tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr); if (addr == (addr_t) &dummy->regs.psw.mask) /* Remove per bit from user psw. */ tmp &= ~PSW_MASK_PER; } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { /* * access registers are stored in the thread structure */ offset = addr - (addr_t) &dummy->regs.acrs; #ifdef CONFIG_ARCH_S390X /* * Very special case: old & broken 64 bit gdb reading * from acrs[15]. Result is a 64 bit value. Read the * 32 bit acrs[15] value and shift it by 32. Sick... */ if (addr == (addr_t) &dummy->regs.acrs[15]) tmp = ((unsigned long) child->thread.acrs[15]) << 32; else #endif tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { /* * orig_gpr2 is stored on the kernel stack */ tmp = (addr_t) __KSTK_PTREGS(child)->orig_gpr2; } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { /* * floating point regs. are stored in the thread structure */ offset = addr - (addr_t) &dummy->regs.fp_regs; tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); if (addr == (addr_t) &dummy->regs.fp_regs.fpc) tmp &= (unsigned long) FPC_VALID_MASK << (BITS_PER_LONG - 32); } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { /* * per_info is found in the thread structure */ offset = addr - (addr_t) &dummy->regs.per_info; tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset); } else tmp = 0; return put_user(tmp, (addr_t __user *) data); }
int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr, int len, int tofromuser, int writingtouser) { int copylen=0,copymax; addr_t realuseraddr; saddr_t enduseraddr; unsigned long mask; #ifdef CONFIG_S390_SUPPORT if (current->thread.flags & S390_FLAG_31BIT) { /* adjust user offsets to 64 bit structure */ if (useraddr < PT_PSWADDR / 2) useraddr = 2 * useraddr; else if(useraddr < PT_ACR0 / 2) useraddr = 2 * useraddr + sizeof(addr_t) / 2; else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2; else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0)) useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; } #endif enduseraddr=useraddr+len; if (useraddr < 0 || enduseraddr > sizeof(struct user)|| (useraddr < PT_ENDREGS && (useraddr&3))|| (enduseraddr < PT_ENDREGS && (enduseraddr&3))) return (-EIO); while(len>0) { mask=PSW_ADDR_MASK; if(useraddr<PT_FPC) { realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr; if(useraddr<PT_PSWMASK) { copymax=PT_PSWMASK; } else if(useraddr<(PT_PSWMASK+8)) { copymax=(PT_PSWMASK+8); if(writingtouser) mask=PSW_MASK_DEBUGCHANGE; } else if(useraddr<(PT_PSWADDR+8)) { copymax=PT_PSWADDR+8; mask=PSW_ADDR_DEBUGCHANGE; } else copymax=PT_FPC; } else if(useraddr<(PT_FPR15+sizeof(freg_t))) { copymax=(PT_FPR15+sizeof(freg_t)); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } else if(useraddr<sizeof(struct user_regs_struct)) { copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else { copymax=sizeof(struct user); realuseraddr=(addr_t)NULL; } copylen=copymax-useraddr; copylen=(copylen>len ? len:copylen); if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask)) return (-EIO); copyaddr+=copylen; len-=copylen; useraddr+=copylen; } FixPerRegisters(task); return(0); }
int copy_user(struct task_struct *task,saddr_t useraddr,addr_t copyaddr,int len,int tofromuser,int writingtouser) { int copylen=0,copymax; addr_t realuseraddr; saddr_t enduseraddr=useraddr+len; u32 mask; if (useraddr < 0 || enduseraddr > sizeof(struct user)|| (useraddr < PT_ENDREGS && (useraddr&3))|| (enduseraddr < PT_ENDREGS && (enduseraddr&3))) return (-EIO); while(len>0) { mask=0xffffffff; if(useraddr<PT_FPC) { realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr; if(useraddr<PT_PSWMASK) { copymax=PT_PSWMASK; } else if(useraddr<(PT_PSWMASK+4)) { copymax=(PT_PSWMASK+4); if(writingtouser) mask=PSW_MASK_DEBUGCHANGE; } else if(useraddr<(PT_PSWADDR+4)) { copymax=PT_PSWADDR+4; mask=PSW_ADDR_DEBUGCHANGE; } else copymax=PT_FPC; } else if(useraddr<(PT_FPR15_LO+4)) { copymax=(PT_FPR15_LO+4); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } else if(useraddr<sizeof(struct user_regs_struct)) { copymax=sizeof(struct user_regs_struct); realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else { copymax=sizeof(struct user); realuseraddr=(addr_t)NULL; } copylen=copymax-useraddr; copylen=(copylen>len ? len:copylen); if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask)) return (-EIO); copyaddr+=copylen; len-=copylen; useraddr+=copylen; } FixPerRegisters(task); return(0); }