Commit f90dc9f3 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (19/27): ptrace cleanup.

Rewrite s390 ptrace code in a more readable and less buggy way. As a part of
this, all psw related definitions are moved into ptrace.h from a number of
different locations.
parent 91b9f2e4
...@@ -75,9 +75,10 @@ void default_idle(void) ...@@ -75,9 +75,10 @@ void default_idle(void)
/* /*
* Wait for external, I/O or machine check interrupt and * Wait for external, I/O or machine check interrupt and
* switch of machine check bit after the wait has ended. * switch off machine check bit after the wait has ended.
*/ */
wait_psw.mask = _WAIT_PSW_MASK; wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT;
asm volatile ( asm volatile (
" basr %0,0\n" " basr %0,0\n"
"0: la %0,1f-0b(%0)\n" "0: la %0,1f-0b(%0)\n"
...@@ -114,7 +115,7 @@ void show_regs(struct pt_regs *regs) ...@@ -114,7 +115,7 @@ void show_regs(struct pt_regs *regs)
show_registers(regs); show_registers(regs);
/* Show stack backtrace if pt_regs is from kernel mode */ /* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) if (!(regs->psw.mask & PSW_MASK_PSTATE))
show_trace((unsigned long *) regs->gprs[15]); show_trace((unsigned long *) regs->gprs[15]);
} }
...@@ -135,8 +136,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ...@@ -135,8 +136,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
struct pt_regs regs; struct pt_regs regs;
memset(&regs, 0, sizeof(regs)); memset(&regs, 0, sizeof(regs));
regs.psw.mask = _SVC_PSW_MASK; regs.psw.mask = PSW_KERNEL_BITS;
regs.psw.addr = (__u32) kernel_thread_starter | _ADDR_31; regs.psw.addr = (__u32) kernel_thread_starter | PSW_ADDR_AMODE31;
regs.gprs[7] = STACK_FRAME_OVERHEAD; regs.gprs[7] = STACK_FRAME_OVERHEAD;
regs.gprs[8] = __LC_KERNEL_STACK; regs.gprs[8] = __LC_KERNEL_STACK;
regs.gprs[9] = (unsigned long) fn; regs.gprs[9] = (unsigned long) fn;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* S390 version * S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
* Based on PowerPC version * Based on PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
...@@ -21,7 +22,6 @@ ...@@ -21,7 +22,6 @@
* this archive for more details. * this archive for more details.
*/ */
#include <stddef.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -39,169 +39,52 @@ ...@@ -39,169 +39,52 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
void FixPerRegisters(struct task_struct *task) static void FixPerRegisters(struct task_struct *task)
{ {
struct pt_regs *regs = __KSTK_PTREGS(task); struct pt_regs *regs;
per_struct *per_info= per_struct *per_info;
(per_struct *)&task->thread.per_info;
per_info->control_regs.bits.em_instruction_fetch= regs = __KSTK_PTREGS(task);
per_info->single_step|per_info->instruction_fetch; 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) if (per_info->single_step) {
{ per_info->control_regs.bits.starting_addr = 0;
per_info->control_regs.bits.starting_addr=0; per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
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_MASK_PER;
else else
{ regs->psw.mask &= ~PSW_MASK_PER;
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) if (per_info->control_regs.bits.em_storage_alteration)
{ per_info->control_regs.bits.storage_alt_space_ctl = 1;
per_info->control_regs.bits.storage_alt_space_ctl=1;
//((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK;
}
else else
{ per_info->control_regs.bits.storage_alt_space_ctl = 0;
per_info->control_regs.bits.storage_alt_space_ctl=0;
//((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK;
}
} }
void set_single_step(struct task_struct *task) void set_single_step(struct task_struct *task)
{ {
per_struct *per_info= task->thread.per_info.single_step = 1;
(per_struct *)&task->thread.per_info;
per_info->single_step=1; /* Single step */
FixPerRegisters(task); FixPerRegisters(task);
} }
void clear_single_step(struct task_struct *task) void clear_single_step(struct task_struct *task)
{ {
per_struct *per_info= task->thread.per_info.single_step = 0;
(per_struct *)&task->thread.per_info;
per_info->single_step=0;
FixPerRegisters(task); FixPerRegisters(task);
} }
int ptrace_usercopy(addr_t realuseraddr,addr_t copyaddr,int len,int tofromuser,int writeuser,u32 mask)
{
u32 tempuser;
int retval=0;
if(writeuser&&realuseraddr==(addr_t)NULL)
return(0);
if(mask!=0xffffffff)
{
tempuser=*((u32 *)realuseraddr);
if(!writeuser)
{
tempuser&=mask;
realuseraddr=(addr_t)&tempuser;
}
}
if(tofromuser)
{
if(writeuser)
{
retval=copy_from_user((void *)realuseraddr,(void *)copyaddr,len) ? -EFAULT : 0;
}
else
{
if(realuseraddr==(addr_t)NULL)
retval=(clear_user((void *)copyaddr,len) ? -EIO:0);
else
retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len) ? -EIO:0);
}
}
else
{
if(writeuser)
memcpy((void *)realuseraddr,(void *)copyaddr,len);
else
memcpy((void *)copyaddr,(void *)realuseraddr,len);
}
if(mask!=0xffffffff&&writeuser)
(*((u32 *)realuseraddr))=(((*((u32 *)realuseraddr))&mask)|(tempuser&~mask));
return(retval);
}
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);
}
/* /*
* Called by kernel/ptrace.c when detaching.. * Called by kernel/ptrace.c when detaching..
* *
...@@ -213,92 +96,159 @@ void ptrace_disable(struct task_struct *child) ...@@ -213,92 +96,159 @@ void ptrace_disable(struct task_struct *child)
clear_single_step(child); clear_single_step(child);
} }
asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /*
* 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 task_struct *child; struct user *dummy = NULL;
int ret = -EPERM; addr_t offset;
unsigned long tmp; __u32 tmp;
int copied;
ptrace_area parea; if ((addr & 3) || addr > sizeof(struct user) - 3)
return -EIO;
if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
/*
* psw, gprs, acrs and orig_gpr2 are stored on the stack
*/
tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + addr);
} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
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 = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
} else if (addr >= (addr_t) &dummy->regs.per_info &&
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 = *(__u32 *)((addr_t) &child->thread.per_info + offset);
} else
tmp = 0;
return put_user(tmp, (__u32 *) data);
}
/*
* 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;
if ((addr & 3) || addr > sizeof(struct user) - 3)
return -EIO;
if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
/*
* psw, gprs, acrs and orig_gpr2 are stored on the stack
*/
if (addr == (addr_t) &dummy->regs.psw.mask &&
(data & ~PSW_MASK_CC) != PSW_USER_BITS)
/* Invalid psw mask. */
return -EINVAL;
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_AMODE31;
*(__u32 *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
/*
* floating point regs. are stored in the thread structure
*/
if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
(data & ~FPC_VALID_MASK) != 0)
return -EINVAL;
offset = addr - (addr_t) &dummy->regs.fp_regs;
*(__u32 *)((addr_t) &child->thread.fp_regs + offset) = data;
} else if (addr >= (addr_t) &dummy->regs.per_info &&
addr < (addr_t) (&dummy->regs.per_info + 1)) {
/*
* per_info is found in the thread structure
*/
offset = addr - (addr_t) &dummy->regs.per_info;
*(__u32 *)((addr_t) &child->thread.per_info + offset) = data;
lock_kernel();
if (request == PTRACE_TRACEME)
{
/* are we already being traced? */
if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out;
}
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM;
if (pid == 1) /* you may not mess with init */
goto out_tsk;
if (request == PTRACE_ATTACH)
{
ret = ptrace_attach(child);
goto out_tsk;
} }
ret = -ESRCH;
// printk("child=%lX child->flags=%lX",child,child->flags); FixPerRegisters(child);
/* I added child!=current line so we can get the */ return 0;
/* ieee_instruction_pointer from the user structure DJB */ }
if(child!=current)
{ static int
if (!(child->ptrace & PT_PTRACED)) do_ptrace(struct task_struct *child, long request, long addr, long data)
goto out_tsk; {
if (child->state != TASK_STOPPED) unsigned long tmp;
{ ptrace_area parea;
if (request != PTRACE_KILL) int copied, ret;
goto out_tsk;
} if (request == PTRACE_ATTACH)
if (child->parent != current) return ptrace_attach(child);
goto out_tsk;
/*
* I added child != current line so we can get the
* ieee_instruction_pointer from the user structure DJB
*/
if (child != current) {
ret = ptrace_check_attach(child, request == PTRACE_KILL);
if (ret < 0)
return ret;
} }
switch (request)
{ /* Remove high order bit from address. */
/* If I and D space are separate, these will need to be fixed. */ addr &= PSW_ADDR_INSN;
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: switch (request) {
copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0); case PTRACE_PEEKTEXT:
ret = -EIO; case PTRACE_PEEKDATA:
/* read word at location addr. */
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
if (copied != sizeof(tmp)) if (copied != sizeof(tmp))
break; return -EIO;
ret = put_user(tmp,(unsigned long *) data); return put_user(tmp, (unsigned long *) data);
break;
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: case PTRACE_PEEKUSR:
ret=copy_user(child,addr,data,sizeof(unsigned long),1,0); /* read the word at location addr in the USER area. */
break; return peek_user(child, addr, data);
/* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT:
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA: case PTRACE_POKEDATA:
ret = 0; /* write the word at location addr. */
if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data)) copied = access_process_vm(child, addr, &data, sizeof(data),1);
break; if (copied != sizeof(data))
ret = -EIO; return -EIO;
break; return 0;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ case PTRACE_POKEUSR:
ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1); /* write the word at location addr in the USER area */
break; return poke_user(child, addr, data);
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_SYSCALL:
case PTRACE_CONT: /* restart after signal. */ /* continue and stop at next (return from) syscall */
ret = -EIO; case PTRACE_CONT:
/* restart after signal. */
if ((unsigned long) data >= _NSIG) if ((unsigned long) data >= _NSIG)
break; return -EIO;
if (request == PTRACE_SYSCALL) if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else else
...@@ -307,60 +257,104 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -307,60 +257,104 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
clear_single_step(child); clear_single_step(child);
wake_up_process(child); wake_up_process(child);
ret = 0; return 0;
break;
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; /*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->state == TASK_ZOMBIE) /* already dead */
break; return 0;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
clear_single_step(child); clear_single_step(child);
wake_up_process(child); wake_up_process(child);
/* make sure the single step bit is not set. */ return 0;
break;
case PTRACE_SINGLESTEP: /* set the trap flag. */ case PTRACE_SINGLESTEP:
ret = -EIO; /* set the trap flag. */
if ((unsigned long) data >= _NSIG) if ((unsigned long) data >= _NSIG)
break; return -EIO;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data; child->exit_code = data;
set_single_step(child); set_single_step(child);
/* give it a chance to run. */ /* give it a chance to run. */
wake_up_process(child); wake_up_process(child);
ret = 0; return 0;
break;
case PTRACE_DETACH:
/* detach a process that was attached. */
return ptrace_detach(child, data);
case PTRACE_DETACH: /* detach a process that was attached. */
ret = ptrace_detach(child, data);
break;
case PTRACE_PEEKUSR_AREA: case PTRACE_PEEKUSR_AREA:
case PTRACE_POKEUSR_AREA: case PTRACE_POKEUSR_AREA:
if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0) if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
ret=copy_user(child,parea.kernel_addr,parea.process_addr, return -EFAULT;
parea.len,1,(request==PTRACE_POKEUSR_AREA)); addr = parea.kernel_addr;
break; data = parea.process_addr;
case PTRACE_SETOPTIONS: { copied = 0;
while (copied < parea.len) {
if (request == PTRACE_PEEKUSR_AREA)
ret = peek_user(child, addr, data);
else
ret = poke_user(child, addr, data);
if (ret)
return ret;
addr += sizeof(unsigned long);
data += sizeof(unsigned long);
copied += sizeof(unsigned long);
}
return 0;
case PTRACE_SETOPTIONS:
if (data & PTRACE_O_TRACESYSGOOD) if (data & PTRACE_O_TRACESYSGOOD)
child->ptrace |= PT_TRACESYSGOOD; child->ptrace |= PT_TRACESYSGOOD;
else else
child->ptrace &= ~PT_TRACESYSGOOD; child->ptrace &= ~PT_TRACESYSGOOD;
ret = 0; return 0;
break;
} }
default: return -EIO;
ret = -EIO; }
break;
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
int ret;
lock_kernel();
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
ret = -EPERM;
if (current->ptrace & PT_PTRACED)
goto out;
ret = security_ops->ptrace(current->parent, current);
if (ret)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
goto out;
} }
out_tsk:
ret = -EPERM;
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = do_ptrace(child, request, addr, data);
put_task_struct(child); put_task_struct(child);
out: out:
unlock_kernel(); unlock_kernel();
return ret; return ret;
} }
...@@ -371,8 +365,8 @@ asmlinkage void syscall_trace(void) ...@@ -371,8 +365,8 @@ asmlinkage void syscall_trace(void)
return; return;
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) current->exit_code =
? 0x80 : 0); SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0);
current->state = TASK_STOPPED; current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD); notify_parent(current, SIGCHLD);
schedule(); schedule();
......
...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p)
unsigned long start_pfn, end_pfn; unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0; static unsigned int smptrap=0;
unsigned long delay = 0; unsigned long delay = 0;
struct _lowcore *lowcore; struct _lowcore *lc;
int i; int i;
if (smptrap) if (smptrap)
...@@ -451,27 +451,26 @@ void __init setup_arch(char **cmdline_p) ...@@ -451,27 +451,26 @@ void __init setup_arch(char **cmdline_p)
/* /*
* Setup lowcore for boot cpu * Setup lowcore for boot cpu
*/ */
lowcore = (struct _lowcore *) lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); memset(lc, 0, PAGE_SIZE);
memset(lowcore, 0, PAGE_SIZE); lc->restart_psw.mask = PSW_BASE_BITS;
lowcore->restart_psw.mask = _RESTART_PSW_MASK; lc->restart_psw.addr = PSW_ADDR_AMODE31 + (__u32) restart_int_handler;
lowcore->restart_psw.addr = _ADDR_31 + (addr_t) &restart_int_handler; lc->external_new_psw.mask = PSW_KERNEL_BITS;
lowcore->external_new_psw.mask = _EXT_PSW_MASK; lc->external_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) ext_int_handler;
lowcore->external_new_psw.addr = _ADDR_31 + (addr_t) &ext_int_handler; lc->svc_new_psw.mask = PSW_KERNEL_BITS;
lowcore->svc_new_psw.mask = _SVC_PSW_MASK; lc->svc_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) system_call;
lowcore->svc_new_psw.addr = _ADDR_31 + (addr_t) &system_call; lc->program_new_psw.mask = PSW_KERNEL_BITS;
lowcore->program_new_psw.mask = _PGM_PSW_MASK; lc->program_new_psw.addr = PSW_ADDR_AMODE31 + (__u32)pgm_check_handler;
lowcore->program_new_psw.addr = _ADDR_31 + (addr_t) &pgm_check_handler; lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK; lc->mcck_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) mcck_int_handler;
lowcore->mcck_new_psw.addr = _ADDR_31 + (addr_t) &mcck_int_handler; lc->io_new_psw.mask = PSW_KERNEL_BITS;
lowcore->io_new_psw.mask = _IO_PSW_MASK; lc->io_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) io_int_handler;
lowcore->io_new_psw.addr = _ADDR_31 + (addr_t) &io_int_handler; lc->ipl_device = S390_lowcore.ipl_device;
lowcore->ipl_device = S390_lowcore.ipl_device; lc->kernel_stack = ((__u32) &init_thread_union) + 8192;
lowcore->kernel_stack = ((__u32) &init_thread_union) + 8192; lc->async_stack = (__u32)
lowcore->async_stack = (__u32)
__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192; __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192;
lowcore->jiffy_timer = -1LL; lc->jiffy_timer = -1LL;
set_prefix((__u32) lowcore); set_prefix((__u32) lc);
cpu_init(); cpu_init();
__cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
......
...@@ -167,8 +167,8 @@ static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs) ...@@ -167,8 +167,8 @@ static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
int err; int err;
err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common)); err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
regs->psw.mask = _USER_PSW_MASK | (regs->psw.mask & PSW_MASK_DEBUGCHANGE); regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
regs->psw.addr |= _ADDR_31; regs->psw.addr |= PSW_ADDR_AMODE31;
if (err) if (err)
return err; return err;
...@@ -298,9 +298,9 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -298,9 +298,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
(u16 *)(frame->retcode))) (u16 *)(frame->retcode)))
goto give_sigsegv; goto give_sigsegv;
...@@ -311,12 +311,12 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -311,12 +311,12 @@ static void setup_frame(int sig, struct k_sigaction *ka,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u32) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
regs->psw.mask = _USER_PSW_MASK; regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->sc; regs->gprs[3] = (__u32) &frame->sc;
/* We forgot to include these in the sigcontext. /* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility, they are passed as args. */ To avoid breaking binary compatibility, they are passed as args. */
...@@ -356,9 +356,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -356,9 +356,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
(u16 *)(frame->retcode)); (u16 *)(frame->retcode));
} }
...@@ -368,13 +368,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -368,13 +368,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u32) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
regs->psw.mask = _USER_PSW_MASK; regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->info; regs->gprs[3] = (__u32) &frame->info;
regs->gprs[4] = (addr_t)&frame->uc; regs->gprs[4] = (__u32) &frame->uc;
return; return;
give_sigsegv: give_sigsegv:
......
...@@ -116,22 +116,22 @@ void show_trace(unsigned long * stack) ...@@ -116,22 +116,22 @@ void show_trace(unsigned long * stack)
stack = (unsigned long*)&stack; stack = (unsigned long*)&stack;
printk("Call Trace: "); printk("Call Trace: ");
low_addr = ((unsigned long) stack) & PSW_ADDR_MASK; low_addr = ((unsigned long) stack) & PSW_ADDR_INSN;
high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
/* Skip the first frame (biased stack) */ /* Skip the first frame (biased stack) */
backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK; backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN;
/* Print up to 8 lines */ /* Print up to 8 lines */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (backchain < low_addr || backchain >= high_addr) if (backchain < low_addr || backchain >= high_addr)
break; break;
ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK; ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_INSN;
if (!kernel_text_address(ret_addr)) if (!kernel_text_address(ret_addr))
break; break;
if (i && ((i % 6) == 0)) if (i && ((i % 6) == 0))
printk("\n "); printk("\n ");
printk("[<%08lx>] ", ret_addr); printk("[<%08lx>] ", ret_addr);
low_addr = backchain; low_addr = backchain;
backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK; backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN;
} }
printk("\n"); printk("\n");
} }
...@@ -184,7 +184,7 @@ void show_registers(struct pt_regs *regs) ...@@ -184,7 +184,7 @@ void show_registers(struct pt_regs *regs)
char *mode; char *mode;
int i; int i;
mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl"; mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
printk("%s PSW : %08lx %08lx\n", printk("%s PSW : %08lx %08lx\n",
mode, (unsigned long) regs->psw.mask, mode, (unsigned long) regs->psw.mask,
(unsigned long) regs->psw.addr); (unsigned long) regs->psw.addr);
...@@ -210,7 +210,7 @@ void show_registers(struct pt_regs *regs) ...@@ -210,7 +210,7 @@ void show_registers(struct pt_regs *regs)
* time of the fault. * time of the fault.
*/ */
old_fs = get_fs(); old_fs = get_fs();
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
set_fs(USER_DS); set_fs(USER_DS);
else else
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
...@@ -287,10 +287,10 @@ static void inline do_trap(long interruption_code, int signr, char *str, ...@@ -287,10 +287,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) { if (regs->psw.mask & PSW_MASK_PSTATE) {
struct task_struct *tsk = current; struct task_struct *tsk = current;
tsk->thread.trap_no = interruption_code & 0xffff; tsk->thread.trap_no = interruption_code & 0xffff;
...@@ -322,12 +322,12 @@ static void inline do_trap(long interruption_code, int signr, char *str, ...@@ -322,12 +322,12 @@ static void inline do_trap(long interruption_code, int signr, char *str,
static inline void *get_check_address(struct pt_regs *regs) static inline void *get_check_address(struct pt_regs *regs)
{ {
return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc); return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
} }
int do_debugger_trap(struct pt_regs *regs,int signal) int do_debugger_trap(struct pt_regs *regs,int signal)
{ {
if(regs->psw.mask&PSW_PROBLEM_STATE) if(regs->psw.mask&PSW_MASK_PSTATE)
{ {
if(current->ptrace & PT_PTRACED) if(current->ptrace & PT_PTRACED)
force_sig(signal,current); force_sig(signal,current);
...@@ -423,10 +423,10 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) ...@@ -423,10 +423,10 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
else else
*((__u16 *)opcode)=*((__u16 *)location); *((__u16 *)opcode)=*((__u16 *)location);
...@@ -436,7 +436,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) ...@@ -436,7 +436,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
signal = SIGILL; signal = SIGILL;
} }
#ifdef CONFIG_MATHEMU #ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_PROBLEM_STATE) else if (regs->psw.mask & PSW_MASK_PSTATE)
{ {
if (opcode[0] == 0xb3) { if (opcode[0] == 0xb3) {
get_user(*((__u16 *) (opcode+2)), location+1); get_user(*((__u16 *) (opcode+2)), location+1);
...@@ -484,10 +484,10 @@ specification_exception(struct pt_regs * regs, long interruption_code) ...@@ -484,10 +484,10 @@ specification_exception(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) { if (regs->psw.mask & PSW_MASK_PSTATE) {
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
switch (opcode[0]) { switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */ case 0x28: /* LDR Rx,Ry */
...@@ -547,7 +547,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) ...@@ -547,7 +547,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (MACHINE_HAS_IEEE) if (MACHINE_HAS_IEEE)
...@@ -555,7 +555,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) ...@@ -555,7 +555,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
: "=m" (current->thread.fp_regs.fpc)); : "=m" (current->thread.fp_regs.fpc));
#ifdef CONFIG_MATHEMU #ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_PROBLEM_STATE) { else if (regs->psw.mask & PSW_MASK_PSTATE) {
__u8 opcode[6]; __u8 opcode[6];
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
switch (opcode[0]) { switch (opcode[0]) {
...@@ -679,21 +679,19 @@ void __init trap_init(void) ...@@ -679,21 +679,19 @@ void __init trap_init(void)
void handle_per_exception(struct pt_regs *regs) void handle_per_exception(struct pt_regs *regs)
{ {
if(regs->psw.mask&PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE) {
{
per_struct *per_info=&current->thread.per_info; per_struct *per_info=&current->thread.per_info;
per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid; per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
per_info->lowcore.words.address=S390_lowcore.per_address; per_info->lowcore.words.address=S390_lowcore.per_address;
per_info->lowcore.words.access_id=S390_lowcore.per_access_id; per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
} }
if(do_debugger_trap(regs,SIGTRAP)) if (do_debugger_trap(regs,SIGTRAP)) {
{
/* I've seen this possibly a task structure being reused ? */ /* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n"); printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n"); printk("switching off per tracing for this task.\n");
show_regs(regs); show_regs(regs);
/* Hopefully switching off per tracing will help us survive */ /* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK; regs->psw.mask &= ~PSW_MASK_PER;
} }
} }
...@@ -48,7 +48,7 @@ search_exception_table(unsigned long addr) ...@@ -48,7 +48,7 @@ search_exception_table(unsigned long addr)
addr &= 0x7fffffff; /* remove amode bit from address */ addr &= 0x7fffffff; /* remove amode bit from address */
/* There is only the kernel to search. */ /* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
if (ret) ret = FIX_PSW(ret); if (ret) ret = ret | PSW_ADDR_AMODE31;
return ret; return ret;
#else #else
unsigned long flags; unsigned long flags;
...@@ -63,7 +63,7 @@ search_exception_table(unsigned long addr) ...@@ -63,7 +63,7 @@ search_exception_table(unsigned long addr)
ret = search_one_table(mp->ex_table_start, ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr); mp->ex_table_end - 1, addr);
if (ret) { if (ret) {
ret = FIX_PSW(ret); ret = ret | PSW_ADDR_AMODE31;
break; break;
} }
} }
......
...@@ -166,7 +166,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -166,7 +166,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
/* Low-address protection hit in kernel mode means /* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */ NULL pointer write access in kernel mode. */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
address = 0; address = 0;
user_address = 0; user_address = 0;
goto no_context; goto no_context;
...@@ -258,7 +258,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -258,7 +258,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_PROBLEM_STATE) { if (regs->psw.mask & PSW_MASK_PSTATE) {
tsk->thread.prot_addr = address; tsk->thread.prot_addr = address;
tsk->thread.trap_no = error_code; tsk->thread.trap_no = error_code;
force_sigsegv(regs, error_code, si_code, address); force_sigsegv(regs, error_code, si_code, address);
...@@ -298,7 +298,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -298,7 +298,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
goto survive; goto survive;
} }
printk("VM: killing process %s\n", tsk->comm); printk("VM: killing process %s\n", tsk->comm);
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
do_exit(SIGKILL); do_exit(SIGKILL);
goto no_context; goto no_context;
...@@ -314,7 +314,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -314,7 +314,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
force_sig(SIGBUS, tsk); force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */ /* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) if (!(regs->psw.mask & PSW_MASK_PSTATE))
goto no_context; goto no_context;
} }
...@@ -393,7 +393,7 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -393,7 +393,7 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
spin_unlock(&pseudo_wait_spinlock); spin_unlock(&pseudo_wait_spinlock);
} else { } else {
/* Pseudo page faults in kernel mode is a bad idea */ /* Pseudo page faults in kernel mode is a bad idea */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
/* /*
* VM presents pseudo page faults if the interrupted * VM presents pseudo page faults if the interrupted
* state was not disabled for interrupts. So we can * state was not disabled for interrupts. So we can
...@@ -528,7 +528,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -528,7 +528,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (subcode & 0x0080) { if (subcode & 0x0080) {
......
...@@ -8,8 +8,6 @@ ...@@ -8,8 +8,6 @@
#include <linux/nfsd/nfsd.h> #include <linux/nfsd/nfsd.h>
#include <linux/nfsd/export.h> #include <linux/nfsd/export.h>
#ifdef CONFIG_S390_SUPPORT
/* Macro that masks the high order bit of an 32 bit pointer and converts it*/ /* Macro that masks the high order bit of an 32 bit pointer and converts it*/
/* to a 64 bit pointer */ /* to a 64 bit pointer */
#define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL)) #define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
...@@ -194,6 +192,32 @@ typedef struct ...@@ -194,6 +192,32 @@ typedef struct
__u32 addr; __u32 addr;
} _psw_t32 __attribute__ ((aligned(8))); } _psw_t32 __attribute__ ((aligned(8)));
#define PSW32_MASK_PER 0x40000000UL
#define PSW32_MASK_DAT 0x04000000UL
#define PSW32_MASK_IO 0x02000000UL
#define PSW32_MASK_EXT 0x01000000UL
#define PSW32_MASK_KEY 0x00F00000UL
#define PSW32_MASK_MCHECK 0x00040000UL
#define PSW32_MASK_WAIT 0x00020000UL
#define PSW32_MASK_PSTATE 0x00010000UL
#define PSW32_MASK_ASC 0x0000C000UL
#define PSW32_MASK_CC 0x00003000UL
#define PSW32_MASK_PM 0x00000f00UL
#define PSW32_ADDR_AMODE31 0x80000000UL
#define PSW32_ADDR_INSN 0x7FFFFFFFUL
#define PSW32_BASE_BITS 0x00080000UL
#define PSW32_ASC_PRIMARY 0x00000000UL
#define PSW32_ASC_ACCREG 0x00004000UL
#define PSW32_ASC_SECONDARY 0x00008000UL
#define PSW32_ASC_HOME 0x0000C000UL
#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
PSW32_MASK_PSTATE)
typedef struct typedef struct
{ {
_psw_t32 psw; _psw_t32 psw;
...@@ -241,6 +265,4 @@ struct ucontext32 { ...@@ -241,6 +265,4 @@ struct ucontext32 {
sigset_t32 uc_sigmask; /* mask last for extensibility */ sigset_t32 uc_sigmask; /* mask last for extensibility */
}; };
#endif /* !CONFIG_S390_SUPPORT */
#endif /* _ASM_S390X_S390_H */ #endif /* _ASM_S390X_S390_H */
...@@ -75,9 +75,10 @@ void default_idle(void) ...@@ -75,9 +75,10 @@ void default_idle(void)
/* /*
* Wait for external, I/O or machine check interrupt and * Wait for external, I/O or machine check interrupt and
* switch of machine check bit after the wait has ended. * switch off machine check bit after the wait has ended.
*/ */
wait_psw.mask = _WAIT_PSW_MASK; wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT;
asm volatile ( asm volatile (
" larl %0,0f\n" " larl %0,0f\n"
" stg %0,8(%1)\n" " stg %0,8(%1)\n"
...@@ -111,7 +112,7 @@ void show_regs(struct pt_regs *regs) ...@@ -111,7 +112,7 @@ void show_regs(struct pt_regs *regs)
show_registers(regs); show_registers(regs);
/* Show stack backtrace if pt_regs is from kernel mode */ /* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) if (!(regs->psw.mask & PSW_MASK_PSTATE))
show_trace((unsigned long *) regs->gprs[15]); show_trace((unsigned long *) regs->gprs[15]);
} }
...@@ -132,7 +133,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ...@@ -132,7 +133,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
struct pt_regs regs; struct pt_regs regs;
memset(&regs, 0, sizeof(regs)); memset(&regs, 0, sizeof(regs));
regs.psw.mask = _SVC_PSW_MASK; regs.psw.mask = PSW_KERNEL_BITS;
regs.psw.addr = (__u64) kernel_thread_starter; regs.psw.addr = (__u64) kernel_thread_starter;
regs.gprs[7] = STACK_FRAME_OVERHEAD; regs.gprs[7] = STACK_FRAME_OVERHEAD;
regs.gprs[8] = __LC_KERNEL_STACK; regs.gprs[8] = __LC_KERNEL_STACK;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* S390 version * S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
* Based on PowerPC version * Based on PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
...@@ -38,49 +39,48 @@ ...@@ -38,49 +39,48 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
#include "linux32.h" #include "ptrace32.h"
#else
#define parent_31bit 0
#endif #endif
static void FixPerRegisters(struct task_struct *task)
void FixPerRegisters(struct task_struct *task)
{ {
struct pt_regs *regs = __KSTK_PTREGS(task); struct pt_regs *regs;
per_struct *per_info= per_struct *per_info;
(per_struct *)&task->thread.per_info;
regs = __KSTK_PTREGS(task);
per_info = (per_struct *) &task->thread.per_info;
per_info->control_regs.bits.em_instruction_fetch = per_info->control_regs.bits.em_instruction_fetch =
per_info->single_step | per_info->instruction_fetch; per_info->single_step | per_info->instruction_fetch;
if (per_info->single_step) { if (per_info->single_step) {
per_info->control_regs.bits.starting_addr=0; per_info->control_regs.bits.starting_addr = 0;
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
if (current->thread.flags & S390_FLAG_31BIT) { if (current->thread.flags & S390_FLAG_31BIT)
per_info->control_regs.bits.ending_addr=0x7fffffffUL; per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
} else
else #endif
#endif per_info->control_regs.bits.ending_addr = -1;
{
per_info->control_regs.bits.ending_addr=-1L;
}
} else { } else {
per_info->control_regs.bits.starting_addr= per_info->control_regs.bits.starting_addr =
per_info->starting_addr; per_info->starting_addr;
per_info->control_regs.bits.ending_addr= per_info->control_regs.bits.ending_addr =
per_info->ending_addr; per_info->ending_addr;
} }
/* if any of the control reg tracing bits are on /*
we switch on per in the psw */ * 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) if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
regs->psw.mask |= PSW_PER_MASK; regs->psw.mask |= PSW_MASK_PER;
else else
regs->psw.mask &= ~PSW_PER_MASK; regs->psw.mask &= ~PSW_MASK_PER;
if (per_info->control_regs.bits.storage_alt_space_ctl)
task->thread.user_seg |= USER_STD_MASK; if (per_info->control_regs.bits.em_storage_alteration)
per_info->control_regs.bits.storage_alt_space_ctl = 1;
else else
task->thread.user_seg &= ~USER_STD_MASK; per_info->control_regs.bits.storage_alt_space_ctl = 0;
} }
void set_single_step(struct task_struct *task) void set_single_step(struct task_struct *task)
...@@ -99,424 +99,406 @@ void clear_single_step(struct task_struct *task) ...@@ -99,424 +99,406 @@ void clear_single_step(struct task_struct *task)
FixPerRegisters (task); FixPerRegisters (task);
} }
int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len, /*
int tofromuser, int writeuser, unsigned long mask) * Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
*/
void ptrace_disable(struct task_struct *child)
{ {
unsigned long *realuserptr, *copyptr; /* make sure the single step bit is not set. */
unsigned long tempuser; clear_single_step(child);
int retval;
retval = 0;
realuserptr = (unsigned long *) realuseraddr;
copyptr = (unsigned long *) copyaddr;
if (writeuser && realuserptr == NULL)
return 0;
if (mask != -1L) {
tempuser = *realuserptr;
if (!writeuser) {
tempuser &= mask;
realuserptr = &tempuser;
}
}
if (tofromuser) {
if (writeuser) {
retval = copy_from_user(realuserptr, copyptr, len);
} else {
if (realuserptr == NULL)
retval = clear_user(copyptr, len);
else
retval = copy_to_user(copyptr,realuserptr,len);
retval = retval ? -EIO : 0;
}
} else {
if (writeuser)
memcpy(realuserptr, copyptr, len);
else
memcpy(copyptr, realuserptr, len);
}
if (mask != -1L && writeuser)
*realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
return retval;
} }
#ifdef CONFIG_S390_SUPPORT /*
* Read the word at offset addr from the user area of a process. The
typedef struct * 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)
{ {
__u32 cr[3]; struct user *dummy = NULL;
} per_cr_words32 __attribute__((packed)); addr_t offset;
__u64 tmp;
if ((addr & 7) || addr > sizeof(struct user) - 7)
return -EIO;
if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
/*
* psw, gprs, acrs and orig_gpr2 are stored on the stack
*/
tmp = *(__u64 *)((addr_t) __KSTK_PTREGS(child) + addr);
} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
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 = *(__u64 *)((addr_t) &child->thread.fp_regs + offset);
} else if (addr >= (addr_t) &dummy->regs.per_info &&
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 = *(__u64 *)((addr_t) &child->thread.per_info + offset);
} else
tmp = 0;
return put_user(tmp, (__u64 *) data);
}
typedef struct /*
* 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)
{ {
__u16 perc_atmid; /* 0x096 */ struct user *dummy = NULL;
__u32 address; /* 0x098 */ addr_t offset;
__u8 access_id; /* 0x0a1 */
} per_lowcore_words32 __attribute__((packed));
typedef struct if ((addr & 7) || addr > sizeof(struct user) - 7)
{ return -EIO;
union {
per_cr_words32 words; if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
} control_regs __attribute__((packed)); /*
/* * psw, gprs, acrs and orig_gpr2 are stored on the stack
* Use these flags instead of setting em_instruction_fetch */
* directly they are used so that single stepping can be if (addr == (addr_t) &dummy->regs.psw.mask &&
* switched on & off while not affecting other tracing
*/
unsigned single_step : 1;
unsigned instruction_fetch : 1;
unsigned : 30;
/*
* These addresses are copied into cr10 & cr11 if single
* stepping is switched off
*/
__u32 starting_addr;
__u32 ending_addr;
union {
per_lowcore_words32 words;
} lowcore;
} per_struct32 __attribute__((packed));
struct user_regs_struct32
{
_psw_t32 psw;
u32 gprs[NUM_GPRS];
u32 acrs[NUM_ACRS];
u32 orig_gpr2;
s390_fp_regs fp_regs;
/*
* These per registers are in here so that gdb can modify them
* itself as there is no "official" ptrace interface for hardware
* watchpoints. This is the way intel does it.
*/
per_struct32 per_info;
u32 ieee_instruction_pointer;
/* Used to give failing instruction back to user for ieee exceptions */
};
struct user32 {
/* We start with the registers, to mimic the way that "memory" is returned
from the ptrace(3,...) function. */
struct user_regs_struct32 regs; /* Where the registers are actually stored */
/* The rest of this junk is to help gdb figure out what goes where */
u32 u_tsize; /* Text segment size (pages). */
u32 u_dsize; /* Data segment size (pages). */
u32 u_ssize; /* Stack segment size (pages). */
u32 start_code; /* Starting virtual address of text. */
u32 start_stack; /* Starting virtual address of stack area.
This is actually the bottom of the stack,
the top of the stack is always found in the
esp register. */
s32 signal; /* Signal that caused the core dump. */
u32 u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
u32 magic; /* To uniquely identify a core file */
char u_comm[32]; /* User command that was responsible */
};
#define PT32_PSWMASK 0x0
#define PT32_PSWADDR 0x04
#define PT32_GPR0 0x08
#define PT32_GPR15 0x44
#define PT32_ACR0 0x48
#define PT32_ACR15 0x84
#define PT32_ORIGGPR2 0x88
#define PT32_FPC 0x90
#define PT32_FPR0_HI 0x98
#define PT32_FPR15_LO 0x114
#define PT32_CR_9 0x118
#define PT32_CR_11 0x120
#define PT32_IEEE_IP 0x13C
#define PT32_LASTOFF PT32_IEEE_IP
#define PT32_ENDREGS 0x140-1
#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
#define U64OFFSETOF(member) offsetof(struct user,regs.member)
#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
#define PT_SINGLE_STEP (PT_CR_11+8)
#define PT32_SINGLE_STEP (PT32_CR_11+4)
#endif /* CONFIG_S390_SUPPORT */
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
int parent_31bit=current->thread.flags & S390_FLAG_31BIT;
int skip;
#endif
enduseraddr=useraddr+len;
if ((useraddr<0||useraddr&3||enduseraddr&3)||
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
(parent_31bit && enduseraddr > sizeof(struct user32)) || (data & ~PSW_MASK_CC) != PSW_USER32_BITS &&
#endif #endif
enduseraddr > sizeof(struct user)) (data & ~PSW_MASK_CC) != PSW_USER_BITS)
return (-EIO); /* Invalid psw mask. */
return -EINVAL;
*(__u64 *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
/*
* floating point regs. are stored in the thread structure
*/
if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
((data >> 32) & ~FPC_VALID_MASK) != 0)
/* Invalid floating pointer control. */
return -EINVAL;
offset = addr - (addr_t) &dummy->regs.fp_regs;
*(__u64 *)((addr_t) &child->thread.fp_regs + offset) = data;
} else if (addr >= (addr_t) &dummy->regs.per_info &&
addr < (addr_t) (&dummy->regs.per_info + 1)) {
/*
* per_info is found in the thread structure
*/
offset = addr - (addr_t) &dummy->regs.per_info;
*(__u64 *)((addr_t) &child->thread.per_info + offset) = data;
#ifdef CONFIG_S390_SUPPORT
if(parent_31bit)
{
if(useraddr != PT32_PSWMASK)
{
if (useraddr == PT32_PSWADDR)
useraddr = PT_PSWADDR+4;
else if(useraddr <= PT32_GPR15)
useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
else if(useraddr <= PT32_ACR15)
useraddr += PT_ACR0-PT32_ACR0;
else if(useraddr == PT32_ORIGGPR2)
useraddr = PT_ORIGGPR2+4;
else if(useraddr <= PT32_FPR15_LO)
useraddr += PT_FPR0-PT32_FPR0_HI;
else if(useraddr <= PT32_CR_11)
useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
else if(useraddr == PT32_SINGLE_STEP)
useraddr = PT_SINGLE_STEP;
else if(useraddr <= U32OFFSETOF(per_info.ending_addr))
useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) +
U64OFFSETOF(per_info.starting_addr)+4;
else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
else if(useraddr == PT32_IEEE_IP)
useraddr = PT_IEEE_IP+4;
}
} }
#endif /* CONFIG_S390_SUPPORT */
while(len>0) FixPerRegisters(child);
{ return 0;
#ifdef CONFIG_S390_SUPPORT }
skip=0;
#endif
mask=PSW_ADDR_MASK;
if(useraddr<PT_FPC)
{
realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
if(useraddr<(PT_PSWMASK+8))
{
if(parent_31bit)
{
copymax=PT_PSWMASK+4;
#ifdef CONFIG_S390_SUPPORT
skip=8;
#endif
}
else
{
copymax=PT_PSWMASK+8;
}
if(writingtouser)
mask=PSW_MASK_DEBUGCHANGE;
}
else if(useraddr<(PT_PSWADDR+8))
{
copymax=PT_PSWADDR+8;
mask=PSW_ADDR_DEBUGCHANGE;
#ifdef CONFIG_S390_SUPPORT
if(parent_31bit)
skip=4;
#endif
} static int
else do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
{ {
#ifdef CONFIG_S390_SUPPORT unsigned long tmp;
if(parent_31bit && useraddr <= PT_GPR15+4) ptrace_area parea;
{ int copied, ret;
copymax=useraddr+4;
if(useraddr<PT_GPR15+4) switch (request) {
skip=4; case PTRACE_PEEKTEXT:
} case PTRACE_PEEKDATA:
else /* read word at location addr. */
#endif copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
copymax=PT_FPC; if (copied != sizeof(tmp))
} return -EIO;
} return put_user(tmp, (unsigned long *) data);
else if(useraddr<(PT_FPR15+sizeof(freg_t)))
{ case PTRACE_PEEKUSR:
copymax=(PT_FPR15+sizeof(freg_t)); /* read the word at location addr in the USER area. */
realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); return peek_user(child, addr, data);
}
else if(useraddr<sizeof(struct user_regs_struct)) case PTRACE_POKETEXT:
{ case PTRACE_POKEDATA:
#ifdef CONFIG_S390_SUPPORT /* write the word at location addr. */
if( parent_31bit && useraddr <= PT_IEEE_IP+4) copied = access_process_vm(child, addr, &data, sizeof(data),1);
{ if (copied != sizeof(data))
switch(useraddr) return -EIO;
{ return 0;
case PT_CR_11+4:
case U64OFFSETOF(per_info.ending_addr)+4: case PTRACE_POKEUSR:
case U64OFFSETOF(per_info.lowcore.words.address)+4: /* write the word at location addr in the USER area */
copymax=useraddr+4; return poke_user(child, addr, data);
break;
case PT_SINGLE_STEP: case PTRACE_PEEKUSR_AREA:
case U64OFFSETOF(per_info.lowcore.words.perc_atmid): case PTRACE_POKEUSR_AREA:
/* We copy 2 bytes in excess for the atmid member this also gets around */ if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
/* alignment for this member in 32 bit */ return -EFAULT;
skip=8; addr = parea.kernel_addr;
copymax=useraddr+4; data = parea.process_addr;
break; copied = 0;
default: while (copied < parea.len) {
copymax=useraddr+4; if (request == PTRACE_PEEKUSR_AREA)
skip=4; ret = peek_user(child, addr, data);
}
}
else else
#endif ret = poke_user(child, addr, data);
{ if (ret)
copymax=sizeof(struct user_regs_struct); return ret;
} addr += sizeof(unsigned long);
realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); data += sizeof(unsigned long);
copied += sizeof(unsigned long);
} }
else return 0;
{
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
#if CONFIG_S390_SUPPORT
+skip
#endif
;
} }
FixPerRegisters(task); return -EIO;
return(0);
} }
#ifdef CONFIG_S390_SUPPORT
/* /*
* Called by kernel/ptrace.c when detaching.. * Now the fun part starts... a 31 bit program running in the
* * 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
* Make sure single step bits etc are not set. * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy
* to handle, the difference to the 64 bit versions of the requests
* is that the access is done in multiples of 4 byte instead of
* 8 bytes (sizeof(unsigned long) on 31/64 bit).
* The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA,
* PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program
* is a 31 bit program too, the content of struct user can be
* emulated. A 31 bit program peeking into the struct user of
* a 64 bit program is a no-no.
*/ */
void ptrace_disable(struct task_struct *child)
/*
* Same as peek_user but for a 31 bit program.
*/
static int peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
{ {
/* make sure the single step bit is not set. */ struct user32 *dummy32 = NULL;
clear_single_step(child); per_struct32 *dummy_per32 = NULL;
addr_t offset;
__u32 tmp;
if (!(child->thread.flags & S390_FLAG_31BIT) ||
(addr & 3) || addr > sizeof(struct user) - 3)
return -EIO;
if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
/*
* psw, gprs, acrs and orig_gpr2 are stored on the stack
*/
if (addr == (addr_t) &dummy32->regs.psw.mask) {
/* Fake a 31 bit psw mask. */
tmp = (__u32)(__KSTK_PTREGS(child)->psw.mask >> 32);
tmp = (tmp & PSW32_MASK_CC) | PSW32_USER_BITS;
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Fake a 31 bit psw address. */
tmp = (__u32) __KSTK_PTREGS(child)->psw.addr |
PSW32_ADDR_AMODE31;
} else
tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) +
addr*2 + 4);
} else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
/*
* floating point regs. are stored in the thread structure
*/
offset = addr - (addr_t) &dummy32->regs.fp_regs;
tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
} else if (addr >= (addr_t) &dummy32->regs.per_info &&
addr < (addr_t) (&dummy32->regs.per_info + 1)) {
/*
* per_info is found in the thread structure
*/
offset = addr - (addr_t) &dummy32->regs.per_info;
/* This is magic. See per_struct and per_struct32. */
if ((offset >= (addr_t) &dummy_per32->control_regs &&
offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
(offset >= (addr_t) &dummy_per32->starting_addr &&
offset <= (addr_t) &dummy_per32->ending_addr) ||
offset == (addr_t) &dummy_per32->lowcore.words.address)
offset = offset*2 + 4;
else
offset = offset*2;
tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);
} else
tmp = 0;
return put_user(tmp, (__u32 *) data);
} }
typedef struct /*
* Same as poke_user but for a 31 bit program.
*/
static int poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
{ {
__u32 len; struct user32 *dummy32 = NULL;
__u32 kernel_addr; per_struct32 *dummy_per32 = NULL;
__u32 process_addr; addr_t offset;
} ptrace_area_emu31; __u32 tmp;
int ret;
if (!(child->thread.flags & S390_FLAG_31BIT) ||
(addr & 3) || addr > sizeof(struct user32) - 3)
return -EIO;
tmp = (__u32) data;
if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
/*
* psw, gprs, acrs and orig_gpr2 are stored on the stack
*/
if (addr == (addr_t) &dummy32->regs.psw.mask) {
/* Build a 64 bit psw mask from 31 bit mask. */
if ((tmp & ~PSW32_MASK_CC) != PSW32_USER_BITS)
/* Invalid psw mask. */
return -EINVAL;
__KSTK_PTREGS(child)->psw.mask = PSW_USER_BITS |
((tmp & PSW32_MASK_CC) << 32);
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Build a 64 bit psw address from 31 bit address. */
__KSTK_PTREGS(child)->psw.addr =
(__u64) tmp & PSW32_ADDR_INSN;
} else
*(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) =
tmp;
} else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
/*
* floating point regs. are stored in the thread structure
*/
if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
(tmp & ~FPC_VALID_MASK) != 0)
/* Invalid floating pointer control. */
return -EINVAL;
offset = addr - (addr_t) &dummy32->regs.fp_regs;
*(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
} else if (addr >= (addr_t) &dummy32->regs.per_info &&
addr < (addr_t) (&dummy32->regs.per_info + 1)) {
/*
* per_info is found in the thread structure.
*/
offset = addr - (addr_t) &dummy32->regs.per_info;
/*
* This is magic. See per_struct and per_struct32.
* By incident the offsets in per_struct are exactly
* twice the offsets in per_struct32 for all fields.
* The 8 byte fields need special handling though,
* because the second half (bytes 4-7) is needed and
* not the first half.
*/
if ((offset >= (addr_t) &dummy_per32->control_regs &&
offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
(offset >= (addr_t) &dummy_per32->starting_addr &&
offset <= (addr_t) &dummy_per32->ending_addr) ||
offset == (addr_t) &dummy_per32->lowcore.words.address)
offset = offset*2 + 4;
else
offset = offset*2;
*(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp;
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data) FixPerRegisters(child);
return 0;
}
static int
do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
{ {
struct task_struct *child; unsigned int tmp; /* 4 bytes !! */
int ret = -EPERM; ptrace_area_emu31 parea;
int copied; int copied, ret;
#ifdef CONFIG_S390_SUPPORT
int parent_31bit; switch (request) {
int sizeof_parent_long; case PTRACE_PEEKTEXT:
u8 *dataptr; case PTRACE_PEEKDATA:
#else /* read word at location addr. */
#define sizeof_parent_long 8 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
#define dataptr (u8 *)&data if (copied != sizeof(tmp))
#endif return -EIO;
lock_kernel(); return put_user(tmp, (unsigned int *) data);
if (request == PTRACE_TRACEME)
{ case PTRACE_PEEKUSR:
/* are we already being traced? */ /* read the word at location addr in the USER area. */
if (current->ptrace & PT_PTRACED) return peek_user_emu31(child, addr, data);
goto out;
/* set the ptrace bit in the process flags. */ case PTRACE_POKETEXT:
current->ptrace |= PT_PTRACED; case PTRACE_POKEDATA:
ret = 0; /* write the word at location addr. */
goto out; tmp = data;
} copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
ret = -ESRCH; if (copied != sizeof(tmp))
read_lock(&tasklist_lock); return -EIO;
child = find_task_by_pid(pid); return 0;
if (child)
get_task_struct(child); case PTRACE_POKEUSR:
read_unlock(&tasklist_lock); /* write the word at location addr in the USER area */
if (!child) return poke_user_emu31(child, addr, data);
goto out;
ret = -EPERM; case PTRACE_PEEKUSR_AREA:
if (pid == 1) /* you may not mess with init */ case PTRACE_POKEUSR_AREA:
goto out_tsk; if (!copy_from_user(&parea, (void *) addr, sizeof(parea)))
if (request == PTRACE_ATTACH) return -EFAULT;
{ addr = parea.kernel_addr;
ret = ptrace_attach(child); data = parea.process_addr;
goto out_tsk; copied = 0;
} while (copied < parea.len) {
ret = -ESRCH; if (request == PTRACE_PEEKUSR_AREA)
// printk("child=%lX child->flags=%lX",child,child->flags); ret = peek_user_emu31(child, addr, data);
/* I added child!=current line so we can get the */ else
/* ieee_instruction_pointer from the user structure DJB */ ret = poke_user_emu31(child, addr, data);
if(child!=current) if (ret)
{ return ret;
if (!(child->ptrace & PT_PTRACED)) addr += sizeof(unsigned int);
goto out_tsk; data += sizeof(unsigned int);
if (child->state != TASK_STOPPED) copied += sizeof(unsigned int);
{
if (request != PTRACE_KILL)
goto out_tsk;
} }
if (child->parent != current) return 0;
goto out_tsk;
} }
#ifdef CONFIG_S390_SUPPORT return -EIO;
parent_31bit=(current->thread.flags & S390_FLAG_31BIT); }
sizeof_parent_long=(parent_31bit ? 4:8);
dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
#endif #endif
switch (request)
{ static int
/* If I and D space are separate, these will need to be fixed. */ do_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_PEEKTEXT: /* read word at location addr. */ {
case PTRACE_PEEKDATA: int ret;
{
u8 tmp[8]; if (request == PTRACE_ATTACH)
copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0); return ptrace_attach(child);
ret = -EIO;
if (copied != sizeof_parent_long) /*
break; * I added child != current line so we can get the
ret = copy_to_user((void *)data,tmp,sizeof_parent_long); * ieee_instruction_pointer from the user structure DJB
break; */
if (child != current) {
ret = ptrace_check_attach(child, request == PTRACE_KILL);
if (ret < 0)
return ret;
} }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
break;
/* If I and D space are separate, this will have to be fixed. */ switch (request) {
case PTRACE_POKETEXT: /* write the word at location addr. */ /* First the common request for 31/64 bit */
case PTRACE_POKEDATA: case PTRACE_SYSCALL:
ret = 0; /* continue and stop at next (return from) syscall */
if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long) case PTRACE_CONT:
break; /* restart after signal. */
ret = -EIO;
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
break;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */
ret = -EIO;
if ((unsigned long) data >= _NSIG) if ((unsigned long) data >= _NSIG)
break; return -EIO;
if (request == PTRACE_SYSCALL) if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else else
...@@ -525,86 +507,104 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -525,86 +507,104 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
clear_single_step(child); clear_single_step(child);
wake_up_process(child); wake_up_process(child);
ret = 0; return 0;
break;
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; /*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->state == TASK_ZOMBIE) /* already dead */
break; return 0;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
clear_single_step(child); clear_single_step(child);
wake_up_process(child); wake_up_process(child);
/* make sure the single step bit is not set. */ return 0;
break;
case PTRACE_SINGLESTEP: /* set the trap flag. */ case PTRACE_SINGLESTEP:
ret = -EIO; /* set the trap flag. */
if ((unsigned long) data >= _NSIG) if ((unsigned long) data >= _NSIG)
break; return -EIO;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data; child->exit_code = data;
set_single_step(child); set_single_step(child);
/* give it a chance to run. */ /* give it a chance to run. */
wake_up_process(child); wake_up_process(child);
ret = 0; return 0;
break;
case PTRACE_DETACH: /* detach a process that was attached. */ case PTRACE_DETACH:
ret = ptrace_detach(child, data); /* detach a process that was attached. */
break; return ptrace_detach(child, data);
case PTRACE_PEEKUSR_AREA: case PTRACE_SETOPTIONS:
case PTRACE_POKEUSR_AREA:
if(parent_31bit)
{
ptrace_area_emu31 parea;
if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)
ret=copy_user(child,parea.kernel_addr,parea.process_addr,
parea.len,1,(request==PTRACE_POKEUSR_AREA));
}
else
{
ptrace_area parea;
if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)
ret=copy_user(child,parea.kernel_addr,parea.process_addr,
parea.len,1,(request==PTRACE_POKEUSR_AREA));
}
break;
case PTRACE_SETOPTIONS: {
if (data & PTRACE_O_TRACESYSGOOD) if (data & PTRACE_O_TRACESYSGOOD)
child->ptrace |= PT_TRACESYSGOOD; child->ptrace |= PT_TRACESYSGOOD;
else else
child->ptrace &= ~PT_TRACESYSGOOD; child->ptrace &= ~PT_TRACESYSGOOD;
ret = 0; return 0;
break; /* Do requests that differ for 31/64 bit */
}
default: default:
ret = -EIO; #ifdef CONFIG_S390_SUPPORT
break; if (current->thread.flags & S390_FLAG_31BIT)
return do_ptrace_emu31(child, request, addr, data);
#endif
return do_ptrace_normal(child, request, addr, data);
} }
out_tsk: return -EIO;
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
int ret;
lock_kernel();
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
ret = -EPERM;
if (current->ptrace & PT_PTRACED)
goto out;
ret = security_ops->ptrace(current->parent, current);
if (ret)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
goto out;
}
ret = -EPERM;
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = do_ptrace(child, request, addr, data);
put_task_struct(child); put_task_struct(child);
out: out:
unlock_kernel(); unlock_kernel();
return ret; return ret;
} }
asmlinkage void syscall_trace(void) asmlinkage void syscall_trace(void)
{ {
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
return; return;
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) current->exit_code =
? 0x80 : 0); SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0);
current->state = TASK_STOPPED; current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD); notify_parent(current, SIGCHLD);
schedule(); schedule();
......
#ifndef _PTRACE32_H
#define _PTRACE32_H
#include "linux32.h" /* needed for _psw_t32 */
typedef struct
{
__u32 cr[3];
} per_cr_words32 __attribute__((packed));
typedef struct
{
__u16 perc_atmid; /* 0x096 */
__u32 address; /* 0x098 */
__u8 access_id; /* 0x0a1 */
} per_lowcore_words32 __attribute__((packed));
typedef struct
{
union {
per_cr_words32 words;
} control_regs __attribute__((packed));
/*
* Use these flags instead of setting em_instruction_fetch
* directly they are used so that single stepping can be
* switched on & off while not affecting other tracing
*/
unsigned single_step : 1;
unsigned instruction_fetch : 1;
unsigned : 30;
/*
* These addresses are copied into cr10 & cr11 if single
* stepping is switched off
*/
__u32 starting_addr;
__u32 ending_addr;
union {
per_lowcore_words32 words;
} lowcore;
} per_struct32 __attribute__((packed));
struct user_regs_struct32
{
_psw_t32 psw;
u32 gprs[NUM_GPRS];
u32 acrs[NUM_ACRS];
u32 orig_gpr2;
s390_fp_regs fp_regs;
/*
* These per registers are in here so that gdb can modify them
* itself as there is no "official" ptrace interface for hardware
* watchpoints. This is the way intel does it.
*/
per_struct32 per_info;
u32 ieee_instruction_pointer;
/* Used to give failing instruction back to user for ieee exceptions */
};
struct user32 {
/* We start with the registers, to mimic the way that "memory"
is returned from the ptrace(3,...) function. */
struct user_regs_struct32 regs; /* Where the registers are actually stored */
/* The rest of this junk is to help gdb figure out what goes where */
u32 u_tsize; /* Text segment size (pages). */
u32 u_dsize; /* Data segment size (pages). */
u32 u_ssize; /* Stack segment size (pages). */
u32 start_code; /* Starting virtual address of text. */
u32 start_stack; /* Starting virtual address of stack area.
This is actually the bottom of the stack,
the top of the stack is always found in the
esp register. */
s32 signal; /* Signal that caused the core dump. */
u32 u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
u32 magic; /* To uniquely identify a core file */
char u_comm[32]; /* User command that was responsible */
};
typedef struct
{
__u32 len;
__u32 kernel_addr;
__u32 process_addr;
} ptrace_area_emu31;
#endif /* _PTRACE32_H */
...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p)
unsigned long start_pfn, end_pfn; unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0; static unsigned int smptrap=0;
unsigned long delay = 0; unsigned long delay = 0;
struct _lowcore *lowcore; struct _lowcore *lc;
int i; int i;
if (smptrap) if (smptrap)
...@@ -441,27 +441,30 @@ void __init setup_arch(char **cmdline_p) ...@@ -441,27 +441,30 @@ void __init setup_arch(char **cmdline_p)
/* /*
* Setup lowcore for boot cpu * Setup lowcore for boot cpu
*/ */
lowcore = (struct _lowcore *) lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0); memset(lc, 0, 2*PAGE_SIZE);
memset(lowcore, 0, 2*PAGE_SIZE); lc->restart_psw.mask = PSW_BASE_BITS;
lowcore->restart_psw.mask = _RESTART_PSW_MASK; lc->restart_psw.addr = (addr_t) &restart_int_handler;
lowcore->restart_psw.addr = (addr_t) &restart_int_handler; lc->external_new_psw.mask = PSW_KERNEL_BITS;
lowcore->external_new_psw.mask = _EXT_PSW_MASK; lc->external_new_psw.addr = (addr_t) &ext_int_handler;
lowcore->external_new_psw.addr = (addr_t) &ext_int_handler; lc->svc_new_psw.mask = PSW_KERNEL_BITS;
lowcore->svc_new_psw.mask = _SVC_PSW_MASK; lc->svc_new_psw.addr = (addr_t) &system_call;
lowcore->svc_new_psw.addr = (addr_t) &system_call; lc->program_new_psw.mask = PSW_KERNEL_BITS;
lowcore->program_new_psw.mask = _PGM_PSW_MASK; lc->program_new_psw.addr = (addr_t) &pgm_check_handler;
lowcore->program_new_psw.addr = (addr_t) &pgm_check_handler; lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK; lc->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
lowcore->mcck_new_psw.addr = (addr_t) &mcck_int_handler; lc->io_new_psw.mask = PSW_KERNEL_BITS;
lowcore->io_new_psw.mask = _IO_PSW_MASK; lc->io_new_psw.addr = (addr_t) &io_int_handler;
lowcore->io_new_psw.addr = (addr_t) &io_int_handler; lc->ipl_device = S390_lowcore.ipl_device;
lowcore->ipl_device = S390_lowcore.ipl_device; lc->kernel_stack = ((__u64) &init_thread_union) + 16384;
lowcore->kernel_stack = ((__u64) &init_thread_union) + 16384; lc->async_stack = (__u64)
lowcore->async_stack = (__u64)
__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384; __alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
lowcore->jiffy_timer = -1LL; lc->jiffy_timer = -1LL;
set_prefix((__u32)(__u64) lowcore); if (MACHINE_HAS_DIAG44)
lc->diag44_opcode = 0x83000044;
else
lc->diag44_opcode = 0x07000700;
set_prefix((__u32)(__u64) lc);
cpu_init(); cpu_init();
__cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
......
...@@ -162,7 +162,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs *sregs) ...@@ -162,7 +162,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs *sregs)
int err; int err;
err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common)); err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
regs->psw.mask = _USER_PSW_MASK | (regs->psw.mask & PSW_MASK_DEBUGCHANGE); regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
if (err) if (err)
return err; return err;
...@@ -292,9 +292,9 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -292,9 +292,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u64) ka->sa.sa_restorer;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u64) frame->retcode;
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
(u16 *)(frame->retcode))) (u16 *)(frame->retcode)))
goto give_sigsegv; goto give_sigsegv;
...@@ -305,12 +305,12 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -305,12 +305,12 @@ static void setup_frame(int sig, struct k_sigaction *ka,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u64) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u64) ka->sa.sa_handler;
regs->psw.mask = _USER_PSW_MASK; regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->sc; regs->gprs[3] = (__u64) &frame->sc;
/* We forgot to include these in the sigcontext. /* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility, they are passed as args. */ To avoid breaking binary compatibility, they are passed as args. */
...@@ -350,9 +350,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -350,9 +350,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u64) ka->sa.sa_restorer;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u64) frame->retcode;
err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
(u16 *)(frame->retcode)); (u16 *)(frame->retcode));
} }
...@@ -362,13 +362,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -362,13 +362,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u64) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u64) ka->sa.sa_handler;
regs->psw.mask = _USER_PSW_MASK; regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->info; regs->gprs[3] = (__u64) &frame->info;
regs->gprs[4] = (addr_t)&frame->uc; regs->gprs[4] = (__u64) &frame->uc;
return; return;
give_sigsegv: give_sigsegv:
......
...@@ -29,15 +29,10 @@ ...@@ -29,15 +29,10 @@
#include <asm/ucontext.h> #include <asm/ucontext.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "linux32.h" #include "linux32.h"
#include "ptrace32.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
#define _ADDR_31 0x80000000
#define _USER_PSW_MASK_EMU32 0x070DC000
#define _USER_PSW_MASK32 0x0705C00080000000
#define PSW_MASK_DEBUGCHANGE32 0x00003000UL
#define PSW_ADDR_DEBUGCHANGE32 0x7FFFFFFFUL
typedef struct typedef struct
{ {
__u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
...@@ -297,9 +292,9 @@ static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) ...@@ -297,9 +292,9 @@ static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
_s390_regs_common32 regs32; _s390_regs_common32 regs32;
int err, i; int err, i;
regs32.psw.mask = _USER_PSW_MASK_EMU32 | regs32.psw.mask = PSW32_USER_BITS |
(__u32)((regs->psw.mask & PSW_MASK_DEBUGCHANGE) >> 32); ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_CC);
regs32.psw.addr = _ADDR_31 | (__u32) regs->psw.addr; regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
for (i = 0; i < NUM_GPRS; i++) for (i = 0; i < NUM_GPRS; i++)
regs32.gprs[i] = (__u32) regs->gprs[i]; regs32.gprs[i] = (__u32) regs->gprs[i];
memcpy(regs32.acrs, regs->acrs, sizeof(regs32.acrs)); memcpy(regs32.acrs, regs->acrs, sizeof(regs32.acrs));
...@@ -320,9 +315,9 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) ...@@ -320,9 +315,9 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32)); err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
if (err) if (err)
return err; return err;
regs->psw.mask = _USER_PSW_MASK32 | regs->psw.mask = PSW_USER32_BITS |
(__u64)(regs32.psw.mask & PSW_MASK_DEBUGCHANGE32) << 32; (__u64)(regs32.psw.mask & PSW32_MASK_CC) << 32;
regs->psw.addr = (__u64)(regs32.psw.addr & PSW_ADDR_DEBUGCHANGE32); regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
for (i = 0; i < NUM_GPRS; i++) for (i = 0; i < NUM_GPRS; i++)
regs->gprs[i] = (__u64) regs32.gprs[i]; regs->gprs[i] = (__u64) regs32.gprs[i];
memcpy(regs->acrs, regs32.acrs, sizeof(regs32.acrs)); memcpy(regs->acrs, regs32.acrs, sizeof(regs32.acrs));
...@@ -467,9 +462,9 @@ static void setup_frame32(int sig, struct k_sigaction *ka, ...@@ -467,9 +462,9 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u64) ka->sa.sa_restorer;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u64) frame->retcode;
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
(u16 *)(frame->retcode))) (u16 *)(frame->retcode)))
goto give_sigsegv; goto give_sigsegv;
...@@ -480,12 +475,12 @@ static void setup_frame32(int sig, struct k_sigaction *ka, ...@@ -480,12 +475,12 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u64) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u64) ka->sa.sa_handler;
regs->psw.mask = _USER_PSW_MASK32; regs->psw.mask = PSW_USER32_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->sc; regs->gprs[3] = (__u64) &frame->sc;
/* We forgot to include these in the sigcontext. /* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility, they are passed as args. */ To avoid breaking binary compatibility, they are passed as args. */
...@@ -525,9 +520,9 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -525,9 +520,9 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer); regs->gprs[14] = (__u64) ka->sa.sa_restorer;
} else { } else {
regs->gprs[14] = FIX_PSW(frame->retcode); regs->gprs[14] = (__u64) frame->retcode;
err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
(u16 *)(frame->retcode)); (u16 *)(frame->retcode));
} }
...@@ -537,13 +532,13 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -537,13 +532,13 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Set up registers for signal handler */ /* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame; regs->gprs[15] = (__u64) frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler); regs->psw.addr = (__u64) ka->sa.sa_handler;
regs->psw.mask = _USER_PSW_MASK32; regs->psw.mask = PSW_USER32_BITS;
regs->gprs[2] = map_signal(sig); regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->info; regs->gprs[3] = (__u64) &frame->info;
regs->gprs[4] = (addr_t)&frame->uc; regs->gprs[4] = (__u64) &frame->uc;
return; return;
give_sigsegv: give_sigsegv:
......
...@@ -118,22 +118,22 @@ void show_trace(unsigned long * stack) ...@@ -118,22 +118,22 @@ void show_trace(unsigned long * stack)
stack = (unsigned long*)&stack; stack = (unsigned long*)&stack;
printk("Call Trace: "); printk("Call Trace: ");
low_addr = ((unsigned long) stack) & PSW_ADDR_MASK; low_addr = (unsigned long) stack;
high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
/* Skip the first frame (biased stack) */ /* Skip the first frame (biased stack) */
backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK; backchain = *(unsigned long *) low_addr;
/* Print up to 8 lines */ /* Print up to 8 lines */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (backchain < low_addr || backchain >= high_addr) if (backchain < low_addr || backchain >= high_addr)
break; break;
ret_addr = *((unsigned long *) (backchain+112)) & PSW_ADDR_MASK; ret_addr = *(unsigned long *) (backchain+112);
if (!kernel_text_address(ret_addr)) if (!kernel_text_address(ret_addr))
break; break;
if (i && ((i % 3) == 0)) if (i && ((i % 3) == 0))
printk("\n "); printk("\n ");
printk("[<%016lx>] ", ret_addr); printk("[<%016lx>] ", ret_addr);
low_addr = backchain; low_addr = backchain;
backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK; backchain = *(unsigned long *) backchain;
} }
printk("\n"); printk("\n");
} }
...@@ -186,7 +186,7 @@ void show_registers(struct pt_regs *regs) ...@@ -186,7 +186,7 @@ void show_registers(struct pt_regs *regs)
char *mode; char *mode;
int i; int i;
mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl"; mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
printk("%s PSW : %016lx %016lx\n", printk("%s PSW : %016lx %016lx\n",
mode, (unsigned long) regs->psw.mask, mode, (unsigned long) regs->psw.mask,
(unsigned long) regs->psw.addr); (unsigned long) regs->psw.addr);
...@@ -212,7 +212,7 @@ void show_registers(struct pt_regs *regs) ...@@ -212,7 +212,7 @@ void show_registers(struct pt_regs *regs)
* time of the fault. * time of the fault.
*/ */
old_fs = get_fs(); old_fs = get_fs();
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
set_fs(USER_DS); set_fs(USER_DS);
else else
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
...@@ -289,10 +289,10 @@ static void inline do_trap(long interruption_code, int signr, char *str, ...@@ -289,10 +289,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) { if (regs->psw.mask & PSW_MASK_PSTATE) {
struct task_struct *tsk = current; struct task_struct *tsk = current;
tsk->thread.trap_no = interruption_code & 0xffff; tsk->thread.trap_no = interruption_code & 0xffff;
if (info) if (info)
...@@ -323,12 +323,12 @@ static void inline do_trap(long interruption_code, int signr, char *str, ...@@ -323,12 +323,12 @@ static void inline do_trap(long interruption_code, int signr, char *str,
static inline void *get_check_address(struct pt_regs *regs) static inline void *get_check_address(struct pt_regs *regs)
{ {
return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc); return (void *)(regs->psw.addr - S390_lowcore.pgm_ilc);
} }
int do_debugger_trap(struct pt_regs *regs,int signal) int do_debugger_trap(struct pt_regs *regs,int signal)
{ {
if(regs->psw.mask&PSW_PROBLEM_STATE) if(regs->psw.mask&PSW_MASK_PSTATE)
{ {
if(current->ptrace & PT_PTRACED) if(current->ptrace & PT_PTRACED)
force_sig(signal,current); force_sig(signal,current);
...@@ -426,14 +426,14 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) ...@@ -426,14 +426,14 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
/* WARNING don't change this check back to */ /* WARNING don't change this check back to */
/* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */ /* int problem_state=(regs->psw.mask & PSW_MASK_PSTATE); */
/* & then doing if(problem_state) an int is too small for this */ /* & then doing if(problem_state) an int is too small for this */
/* check on 64 bit. */ /* check on 64 bit. */
if(regs->psw.mask & PSW_PROBLEM_STATE) if(regs->psw.mask & PSW_MASK_PSTATE)
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
else else
*((__u16 *)opcode)=*((__u16 *)location); *((__u16 *)opcode)=*((__u16 *)location);
...@@ -459,7 +459,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) ...@@ -459,7 +459,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
__asm__ volatile ("stfpc %0\n\t" __asm__ volatile ("stfpc %0\n\t"
...@@ -527,21 +527,19 @@ void __init trap_init(void) ...@@ -527,21 +527,19 @@ void __init trap_init(void)
void handle_per_exception(struct pt_regs *regs) void handle_per_exception(struct pt_regs *regs)
{ {
if(regs->psw.mask&PSW_PROBLEM_STATE) if (regs->psw.mask&PSW_MASK_PSTATE) {
{
per_struct *per_info=&current->thread.per_info; per_struct *per_info=&current->thread.per_info;
per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid; per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
per_info->lowcore.words.address=S390_lowcore.per_address; per_info->lowcore.words.address=S390_lowcore.per_address;
per_info->lowcore.words.access_id=S390_lowcore.per_access_id; per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
} }
if(do_debugger_trap(regs,SIGTRAP)) if (do_debugger_trap(regs,SIGTRAP)) {
{
/* I've seen this possibly a task structure being reused ? */ /* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n"); printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n"); printk("switching off per tracing for this task.\n");
show_regs(regs); show_regs(regs);
/* Hopefully switching off per tracing will help us survive */ /* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK; regs->psw.mask &= ~PSW_MASK_PER;
} }
} }
...@@ -166,7 +166,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -166,7 +166,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
/* Low-address protection hit in kernel mode means /* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */ NULL pointer write access in kernel mode. */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
address = 0; address = 0;
user_address = 0; user_address = 0;
goto no_context; goto no_context;
...@@ -258,7 +258,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -258,7 +258,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_PROBLEM_STATE) { if (regs->psw.mask & PSW_MASK_PSTATE) {
tsk->thread.prot_addr = address; tsk->thread.prot_addr = address;
tsk->thread.trap_no = error_code; tsk->thread.trap_no = error_code;
force_sigsegv(regs, error_code, si_code, address); force_sigsegv(regs, error_code, si_code, address);
...@@ -298,7 +298,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -298,7 +298,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
goto survive; goto survive;
} }
printk("VM: killing process %s\n", tsk->comm); printk("VM: killing process %s\n", tsk->comm);
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
do_exit(SIGKILL); do_exit(SIGKILL);
goto no_context; goto no_context;
...@@ -314,7 +314,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -314,7 +314,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
force_sig(SIGBUS, tsk); force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */ /* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) if (!(regs->psw.mask & PSW_MASK_PSTATE))
goto no_context; goto no_context;
} }
...@@ -440,7 +440,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -440,7 +440,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code)
* We got all needed information from the lowcore and can * We got all needed information from the lowcore and can
* now safely switch on interrupts. * now safely switch on interrupts.
*/ */
if (regs->psw.mask & PSW_PROBLEM_STATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (subcode & 0x0080) { if (subcode & 0x0080) {
......
...@@ -98,7 +98,6 @@ static inline int ...@@ -98,7 +98,6 @@ static inline int
s390_do_sync_wait(int irq, int do_tpi) s390_do_sync_wait(int irq, int do_tpi)
{ {
unsigned long psw_mask; unsigned long psw_mask;
int ccode;
uint64_t time_start; uint64_t time_start;
uint64_t time_curr; uint64_t time_curr;
...@@ -116,31 +115,7 @@ s390_do_sync_wait(int irq, int do_tpi) ...@@ -116,31 +115,7 @@ s390_do_sync_wait(int irq, int do_tpi)
* sync. interrupt arrived we reset the I/O old PSW to * sync. interrupt arrived we reset the I/O old PSW to
* its original value. * its original value.
*/ */
psw_mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_WAIT;
ccode = iac ();
switch (ccode) {
case 0: /* primary-space */
psw_mask = _IO_PSW_MASK
| _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
break;
case 1: /* secondary-space */
psw_mask = _IO_PSW_MASK
| _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
break;
case 2: /* access-register */
psw_mask = _IO_PSW_MASK
| _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
break;
case 3: /* home-space */
psw_mask = _IO_PSW_MASK
| _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
break;
default:
panic ("start_IO() : unexpected "
"address-space-control %d\n", ccode);
break;
}
/* /*
* Martin didn't like modifying the new PSW, now we take * Martin didn't like modifying the new PSW, now we take
...@@ -201,7 +176,6 @@ s390_do_sync_wait_haltclear(int irq, int halt) ...@@ -201,7 +176,6 @@ s390_do_sync_wait_haltclear(int irq, int halt)
int io_sub; int io_sub;
__u32 io_parm; __u32 io_parm;
unsigned long psw_mask; unsigned long psw_mask;
int ccode;
int ready = 0; int ready = 0;
...@@ -212,32 +186,7 @@ s390_do_sync_wait_haltclear(int irq, int halt) ...@@ -212,32 +186,7 @@ s390_do_sync_wait_haltclear(int irq, int halt)
* FIXME: Are there case where we can't rely on an interrupt * FIXME: Are there case where we can't rely on an interrupt
* to occurr? Need to check... * to occurr? Need to check...
*/ */
psw_mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_WAIT;
ccode = iac ();
switch (ccode) {
case 0: /* primary-space */
psw_mask = _IO_PSW_MASK
| _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
break;
case 1: /* secondary-space */
psw_mask = _IO_PSW_MASK
| _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
break;
case 2: /* access-register */
psw_mask = _IO_PSW_MASK
| _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
break;
case 3: /* home-space */
psw_mask = _IO_PSW_MASK
| _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
break;
default: /* FIXME: isn't ccode only 2 bits anyway? */
panic (halt?"halt":"clear"
"_IO() : unexpected address-space-control %d\n",
ccode);
break;
}
/* /*
* Martin didn't like modifying the new PSW, now we take * Martin didn't like modifying the new PSW, now we take
...@@ -960,7 +909,7 @@ do_IRQ (struct pt_regs regs) ...@@ -960,7 +909,7 @@ do_IRQ (struct pt_regs regs)
* entry condition to synchronous I/O. * entry condition to synchronous I/O.
*/ */
if (*(__u32 *) __LC_SYNC_IO_WORD) { if (*(__u32 *) __LC_SYNC_IO_WORD) {
regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT); regs.psw.mask &= ~(PSW_MASK_WAIT | PSW_MASK_IO);
return; return;
} }
/* endif */ /* endif */
......
...@@ -52,41 +52,12 @@ ...@@ -52,41 +52,12 @@
#define __LC_PFAULT_INTPARM 0x080 #define __LC_PFAULT_INTPARM 0x080
/* interrupt handler start with all io, external and mcck interrupt disabled */
#define _RESTART_PSW_MASK 0x00080000
#define _EXT_PSW_MASK 0x04080000
#define _PGM_PSW_MASK 0x04080000
#define _SVC_PSW_MASK 0x04080000
#define _MCCK_PSW_MASK 0x04080000
#define _IO_PSW_MASK 0x04080000
#define _USER_PSW_MASK 0x070DC000/* DAT, IO, EXT, Home-space */
#define _WAIT_PSW_MASK 0x070E0000/* DAT, IO, EXT, Wait, Home-space */
#define _DW_PSW_MASK 0x000A0000/* disabled wait PSW mask */
#define _PRIMARY_MASK 0x0000 /* MASK for SACF */
#define _SECONDARY_MASK 0x0100 /* MASK for SACF */
#define _ACCESS_MASK 0x0200 /* MASK for SACF */
#define _HOME_MASK 0x0300 /* MASK for SACF */
#define _PSW_PRIM_SPACE_MODE 0x00000000
#define _PSW_SEC_SPACE_MODE 0x00008000
#define _PSW_ACC_REG_MODE 0x00004000
#define _PSW_HOME_SPACE_MODE 0x0000C000
#define _PSW_WAIT_MASK_BIT 0x00020000 /* Wait bit */
#define _PSW_IO_MASK_BIT 0x02000000 /* IO bit */
#define _PSW_IO_WAIT 0x02020000 /* IO & Wait bit */
/* we run in 31 Bit mode */
#define _ADDR_31 0x80000000
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/config.h> #include <linux/config.h>
#include <asm/processor.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/sigp.h> #include <asm/sigp.h>
void restart_int_handler(void); void restart_int_handler(void);
......
...@@ -101,8 +101,8 @@ typedef struct thread_struct thread_struct; ...@@ -101,8 +101,8 @@ typedef struct thread_struct thread_struct;
/* need to define ... */ /* need to define ... */
#define start_thread(regs, new_psw, new_stackp) do { \ #define start_thread(regs, new_psw, new_stackp) do { \
regs->psw.mask = _USER_PSW_MASK; \ regs->psw.mask = PSW_USER_BITS; \
regs->psw.addr = new_psw | 0x80000000; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE31; \
regs->gprs[15] = new_stackp ; \ regs->gprs[15] = new_stackp ; \
} while (0) } while (0)
...@@ -136,19 +136,6 @@ unsigned long get_wchan(struct task_struct *p); ...@@ -136,19 +136,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier() #define cpu_relax() barrier()
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
/* Only let our hackers near the condition codes */
#define PSW_MASK_DEBUGCHANGE 0x00003000UL
/* Don't let em near the addressing mode either */
#define PSW_ADDR_DEBUGCHANGE 0x7FFFFFFFUL
#define PSW_ADDR_MASK 0x7FFFFFFFUL
/* Program event recording mask */
#define PSW_PER_MASK 0x40000000UL
#define USER_STD_MASK 0x00000080UL
#define PSW_PROBLEM_STATE 0x00010000UL
/* /*
* Set PSW mask to specified value, while leaving the * Set PSW mask to specified value, while leaving the
* PSW addr pointing to the next instruction. * PSW addr pointing to the next instruction.
...@@ -178,7 +165,8 @@ static inline void enabled_wait(void) ...@@ -178,7 +165,8 @@ static inline void enabled_wait(void)
unsigned long reg; unsigned long reg;
psw_t wait_psw; psw_t wait_psw;
wait_psw.mask = 0x070e0000; wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
PSW_MASK_MCHECK | PSW_MASK_WAIT;
asm volatile ( asm volatile (
" basr %0,0\n" " basr %0,0\n"
"0: la %0,1f-0b(%0)\n" "0: la %0,1f-0b(%0)\n"
...@@ -200,7 +188,7 @@ static inline void disabled_wait(unsigned long code) ...@@ -200,7 +188,7 @@ static inline void disabled_wait(unsigned long code)
psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1) psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
& -sizeof(psw_t)); & -sizeof(psw_t));
dw_psw->mask = 0x000a0000; dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
dw_psw->addr = code; dw_psw->addr = code;
/* /*
* Store status and then load disabled wait psw, * Store status and then load disabled wait psw,
......
...@@ -114,7 +114,6 @@ ...@@ -114,7 +114,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/setup.h> #include <asm/setup.h>
/* this typedef defines how a Program Status Word looks like */ /* this typedef defines how a Program Status Word looks like */
...@@ -124,10 +123,32 @@ typedef struct ...@@ -124,10 +123,32 @@ typedef struct
__u32 addr; __u32 addr;
} __attribute__ ((aligned(8))) psw_t; } __attribute__ ((aligned(8))) psw_t;
#ifdef __KERNEL__ #define PSW_MASK_PER 0x40000000UL
#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) #define PSW_MASK_DAT 0x04000000UL
#define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) #define PSW_MASK_IO 0x02000000UL
#endif #define PSW_MASK_EXT 0x01000000UL
#define PSW_MASK_KEY 0x00F00000UL
#define PSW_MASK_MCHECK 0x00040000UL
#define PSW_MASK_WAIT 0x00020000UL
#define PSW_MASK_PSTATE 0x00010000UL
#define PSW_MASK_ASC 0x0000C000UL
#define PSW_MASK_CC 0x00003000UL
#define PSW_MASK_PM 0x00000F00UL
#define PSW_ADDR_AMODE31 0x80000000UL
#define PSW_ADDR_INSN 0x7FFFFFFFUL
#define PSW_BASE_BITS 0x00080000UL
#define PSW_ASC_PRIMARY 0x00000000UL
#define PSW_ASC_ACCREG 0x00004000UL
#define PSW_ASC_SECONDARY 0x00008000UL
#define PSW_ASC_HOME 0x0000C000UL
#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY)
#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
PSW_MASK_PSTATE)
typedef union typedef union
{ {
...@@ -328,8 +349,8 @@ struct user_regs_struct ...@@ -328,8 +349,8 @@ struct user_regs_struct
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_MASK_INSN)
extern void show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs);
#endif #endif
......
...@@ -56,32 +56,6 @@ ...@@ -56,32 +56,6 @@
#define __LC_PFAULT_INTPARM 0x11B8 #define __LC_PFAULT_INTPARM 0x11B8
/* interrupt handler start with all io, external and mcck interrupt disabled */
#define _RESTART_PSW_MASK 0x0000000180000000
#define _EXT_PSW_MASK 0x0400000180000000
#define _PGM_PSW_MASK 0x0400000180000000
#define _SVC_PSW_MASK 0x0400000180000000
#define _MCCK_PSW_MASK 0x0400000180000000
#define _IO_PSW_MASK 0x0400000180000000
#define _USER_PSW_MASK 0x0705C00180000000
#define _WAIT_PSW_MASK 0x0706000180000000
#define _DW_PSW_MASK 0x0002000180000000
#define _PRIMARY_MASK 0x0000 /* MASK for SACF */
#define _SECONDARY_MASK 0x0100 /* MASK for SACF */
#define _ACCESS_MASK 0x0200 /* MASK for SACF */
#define _HOME_MASK 0x0300 /* MASK for SACF */
#define _PSW_PRIM_SPACE_MODE 0x0000000000000000
#define _PSW_SEC_SPACE_MODE 0x0000800000000000
#define _PSW_ACC_REG_MODE 0x0000400000000000
#define _PSW_HOME_SPACE_MODE 0x0000C00000000000
#define _PSW_WAIT_MASK_BIT 0x0002000000000000
#define _PSW_IO_MASK_BIT 0x0200000000000000
#define _PSW_IO_WAIT 0x0202000000000000
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/config.h> #include <linux/config.h>
......
...@@ -111,13 +111,13 @@ typedef struct thread_struct thread_struct; ...@@ -111,13 +111,13 @@ typedef struct thread_struct thread_struct;
/* need to define ... */ /* need to define ... */
#define start_thread(regs, new_psw, new_stackp) do { \ #define start_thread(regs, new_psw, new_stackp) do { \
regs->psw.mask = _USER_PSW_MASK; \ regs->psw.mask = PSW_USER_BITS; \
regs->psw.addr = new_psw; \ regs->psw.addr = new_psw; \
regs->gprs[15] = new_stackp; \ regs->gprs[15] = new_stackp; \
} while (0) } while (0)
#define start_thread31(regs, new_psw, new_stackp) do { \ #define start_thread31(regs, new_psw, new_stackp) do { \
regs->psw.mask = _USER_PSW_MASK & ~(1L << 32); \ regs->psw.mask = PSW_USER32_BITS; \
regs->psw.addr = new_psw; \ regs->psw.addr = new_psw; \
regs->gprs[15] = new_stackp; \ regs->gprs[15] = new_stackp; \
} while (0) } while (0)
...@@ -153,19 +153,6 @@ unsigned long get_wchan(struct task_struct *p); ...@@ -153,19 +153,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier() #define cpu_relax() barrier()
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
/* Only let our hackers near the condition codes */
#define PSW_MASK_DEBUGCHANGE 0x0000300000000000UL
/* Don't let em near the addressing mode either */
#define PSW_ADDR_DEBUGCHANGE 0xFFFFFFFFFFFFFFFFUL
#define PSW_ADDR_MASK 0xFFFFFFFFFFFFFFFFUL
/* Program event recording mask */
#define PSW_PER_MASK 0x4000000000000000UL
#define USER_STD_MASK 0x0000000000000080UL
#define PSW_PROBLEM_STATE 0x0001000000000000UL
/* /*
* Set PSW mask to specified value, while leaving the * Set PSW mask to specified value, while leaving the
* PSW addr pointing to the next instruction. * PSW addr pointing to the next instruction.
...@@ -194,7 +181,8 @@ static inline void enabled_wait(void) ...@@ -194,7 +181,8 @@ static inline void enabled_wait(void)
unsigned long reg; unsigned long reg;
psw_t wait_psw; psw_t wait_psw;
wait_psw.mask = 0x0706000180000000; wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
PSW_MASK_MCHECK | PSW_MASK_WAIT;
asm volatile ( asm volatile (
" larl %0,0f\n" " larl %0,0f\n"
" stg %0,8(%1)\n" " stg %0,8(%1)\n"
...@@ -214,7 +202,7 @@ static inline void disabled_wait(addr_t code) ...@@ -214,7 +202,7 @@ static inline void disabled_wait(addr_t code)
psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1) psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
& -sizeof(psw_t)); & -sizeof(psw_t));
dw_psw->mask = 0x0002000180000000; dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
dw_psw->addr = code; dw_psw->addr = code;
/* /*
* Store status and then load disabled wait psw, * Store status and then load disabled wait psw,
......
...@@ -104,10 +104,33 @@ typedef struct ...@@ -104,10 +104,33 @@ typedef struct
__u64 addr; __u64 addr;
} __attribute__ ((aligned(8))) psw_t; } __attribute__ ((aligned(8))) psw_t;
#ifdef __KERNEL__ #define PSW_MASK_PER 0x4000000000000000UL
#define FIX_PSW(addr) ((unsigned long)(addr)) #define PSW_MASK_DAT 0x0400000000000000UL
#define ADDR_BITS_REMOVE(addr) ((addr)) #define PSW_MASK_IO 0x0200000000000000UL
#endif #define PSW_MASK_EXT 0x0100000000000000UL
#define PSW_MASK_KEY 0x00F0000000000000UL
#define PSW_MASK_MCHECK 0x0004000000000000UL
#define PSW_MASK_WAIT 0x0002000000000000UL
#define PSW_MASK_PSTATE 0x0001000000000000UL
#define PSW_MASK_ASC 0x0000C00000000000UL
#define PSW_MASK_CC 0x0000300000000000UL
#define PSW_MASK_PM 0x00000F0000000000UL
#define PSW_BASE_BITS 0x0000000180000000UL
#define PSW_BASE32_BITS 0x0000000080000000UL
#define PSW_ASC_PRIMARY 0x0000000000000000UL
#define PSW_ASC_ACCREG 0x0000400000000000UL
#define PSW_ASC_SECONDARY 0x0000800000000000UL
#define PSW_ASC_HOME 0x0000C00000000000UL
#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY)
#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
PSW_MASK_PSTATE)
#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
PSW_MASK_PSTATE)
typedef union typedef union
{ {
...@@ -309,7 +332,7 @@ struct user_regs_struct ...@@ -309,7 +332,7 @@ struct user_regs_struct
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr) #define instruction_pointer(regs) ((regs)->psw.addr)
extern void show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment