#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/memreg.h>
#include <asm/kdebug.h>
#include <asm/uaccess.h>
-#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
-
extern int prom_node_root;
/* At boot time we determine these two values necessary for setting
return 0;
}
+extern unsigned long safe_compute_effective_address(struct pt_regs *,
+ unsigned int);
+
+static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
+{
+ unsigned int insn;
+
+ if (text_fault)
+ return regs->pc;
+
+ if (regs->psr & PSR_PS) {
+ insn = *(unsigned int *) regs->pc;
+ } else {
+ __get_user(insn, (unsigned int *) regs->pc);
+ }
+
+ return safe_compute_effective_address(regs, insn);
+}
+
asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address)
{
* the fault.
*/
switch (handle_mm_fault(mm, vma, address, write)) {
- case 1:
- current->min_flt++;
- break;
- case 2:
+ case VM_FAULT_SIGBUS:
+ goto do_sigbus;
+ case VM_FAULT_OOM:
+ goto out_of_memory;
+ case VM_FAULT_MAJOR:
current->maj_flt++;
break;
- case 0:
- goto do_sigbus;
+ case VM_FAULT_MINOR:
default:
- goto out_of_memory;
+ current->min_flt++;
+ break;
}
up_read(&mm->mmap_sem);
return;
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *)compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return;
*/
out_of_memory:
up_read(&mm->mmap_sem);
- printk("VM: killing process %s\n", tsk->comm);
+ printk("VM: killing process %s(%d:#%u)\n",
+ tsk->comm, tsk->pid, tsk->xid);
if (from_user)
do_exit(SIGKILL);
goto no_context;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *) compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
if (!from_user)
address = regs->pc;
} else if (!write &&
!(regs->psr & PSR_PS)) {
- unsigned int insn, *ip;
+ unsigned int insn, __user *ip;
- ip = (unsigned int *)regs->pc;
- if (! get_user(insn, ip)) {
+ ip = (unsigned int __user *)regs->pc;
+ if (!get_user(insn, ip)) {
if ((insn & 0xc1680000) == 0xc0680000)
write = 1;
}
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- if (!handle_mm_fault(mm, vma, address, write))
+ switch (handle_mm_fault(mm, vma, address, write)) {
+ case VM_FAULT_SIGBUS:
+ case VM_FAULT_OOM:
goto do_sigbus;
+ }
up_read(&mm->mmap_sem);
return;
bad_area:
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *) address;
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *) address;
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
}