[PATCH] uml: S390 preparation, abstract host page fault data
This patch removes the arch-specific fault/trap-infos from thread and skas-regs. It adds a new struct faultinfo, that is arch-specific defined in sysdep/faultinfo.h. The structure is inserted in thread.arch and thread.regs.skas and thread.regs.tt Now, segv and other trap-handlers can copy the contents from regs.X.faultinfo to thread.arch.faultinfo with one simple assignment. Also, the number of macros necessary is reduced to FAULT_ADDRESS(struct faultinfo) extracts the faulting address from faultinfo FAULT_WRITE(struct faultinfo) extracts the "is_write" flag SEGV_IS_FIXABLE(struct faultinfo) is true for the fixable segvs, i.e. (TRAP == 14) on i386 UPT_FAULTINFO(regs) result is (struct faultinfo *) to the faultinfo in regs->skas.faultinfo GET_FAULTINFO_FROM_SC(struct faultinfo, struct sigcontext *) copies the relevant parts of the sigcontext to struct faultinfo. On SIGSEGV, call user_signal() instead of handle_segv(), if the architecture provides the information needed in PTRACE_FAULTINFO, or if PTRACE_FAULTINFO is missing, because segv-stub will provide the info. The benefit of the change is, that in case of a non-fixable SIGSEGV, we can give user processes a SIGSEGV, instead of possibly looping on pagefault handling. Since handle_segv() sikked arch_fixup() implicitly by passing ip==0 to segv(), I changed segv() to call arch_fixup() only, if !is_user. Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com> Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
ea66e8a3b6
commit
c578455a3e
@@ -133,12 +133,19 @@ static int check_remapped_addr(unsigned long address, int is_write)
|
||||
return(0);
|
||||
}
|
||||
|
||||
unsigned long segv(unsigned long address, unsigned long ip, int is_write,
|
||||
int is_user, void *sc)
|
||||
/*
|
||||
* We give a *copy* of the faultinfo in the regs to segv.
|
||||
* This must be done, since nesting SEGVs could overwrite
|
||||
* the info in the regs. A pointer to the info then would
|
||||
* give us bad data!
|
||||
*/
|
||||
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
|
||||
{
|
||||
struct siginfo si;
|
||||
void *catcher;
|
||||
int err;
|
||||
int is_write = FAULT_WRITE(fi);
|
||||
unsigned long address = FAULT_ADDRESS(fi);
|
||||
|
||||
if(!is_user && (address >= start_vm) && (address < end_vm)){
|
||||
flush_tlb_kernel_vm();
|
||||
@@ -159,7 +166,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
|
||||
}
|
||||
else if(current->thread.fault_addr != NULL)
|
||||
panic("fault_addr set but no fault catcher");
|
||||
else if(arch_fixup(ip, sc))
|
||||
else if(!is_user && arch_fixup(ip, sc))
|
||||
return(0);
|
||||
|
||||
if(!is_user)
|
||||
@@ -171,6 +178,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
|
||||
si.si_errno = 0;
|
||||
si.si_code = BUS_ADRERR;
|
||||
si.si_addr = (void *)address;
|
||||
current->thread.arch.faultinfo = fi;
|
||||
force_sig_info(SIGBUS, &si, current);
|
||||
}
|
||||
else if(err == -ENOMEM){
|
||||
@@ -180,22 +188,20 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
|
||||
else {
|
||||
si.si_signo = SIGSEGV;
|
||||
si.si_addr = (void *) address;
|
||||
current->thread.cr2 = address;
|
||||
current->thread.err = is_write;
|
||||
current->thread.arch.faultinfo = fi;
|
||||
force_sig_info(SIGSEGV, &si, current);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void bad_segv(unsigned long address, unsigned long ip, int is_write)
|
||||
void bad_segv(struct faultinfo fi, unsigned long ip)
|
||||
{
|
||||
struct siginfo si;
|
||||
|
||||
si.si_signo = SIGSEGV;
|
||||
si.si_code = SEGV_ACCERR;
|
||||
si.si_addr = (void *) address;
|
||||
current->thread.cr2 = address;
|
||||
current->thread.err = is_write;
|
||||
si.si_addr = (void *) FAULT_ADDRESS(fi);
|
||||
current->thread.arch.faultinfo = fi;
|
||||
force_sig_info(SIGSEGV, &si, current);
|
||||
}
|
||||
|
||||
@@ -204,6 +210,7 @@ void relay_signal(int sig, union uml_pt_regs *regs)
|
||||
if(arch_handle_signal(sig, regs)) return;
|
||||
if(!UPT_IS_USER(regs))
|
||||
panic("Kernel mode signal %d", sig);
|
||||
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
|
||||
force_sig(sig, current);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user