* linux/arch/m32r/mm/fault.c
*
* Copyright (c) 2001, 2002 Hitoshi Yamamoto, and H. Kondo
+ * Copyright (c) 2004 Naoto Sugai, NIIBE Yutaka
*
* Some code taken from i386 version.
* Copyright (C) 1995 Linus Torvalds
*/
-/* $Id$ */
-
-#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
* bit 2 == 0 means kernel, 1 means user-mode
* bit 3 == 0 means data, 1 means instruction
*======================================================================*/
+#define ACE_PROTECTION 1
+#define ACE_WRITE 2
+#define ACE_USERMODE 4
+#define ACE_INSTRUCTION 8
+
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
* nothing more.
*
* This verifies that the fault happens in kernel space
- * (error_code & 4) == 0, and that the fault was not a
- * protection error (error_code & 1) == 0.
+ * (error_code & ACE_USERMODE) == 0, and that the fault was not a
+ * protection error (error_code & ACE_PROTECTION) == 0.
*/
- if (address >= TASK_SIZE && !(error_code & 4))
+ if (address >= TASK_SIZE && !(error_code & ACE_USERMODE))
goto vmalloc_fault;
mm = tsk->mm;
/* When running in the kernel we expect faults to occur only to
* addresses in user space. All other faults represent errors in the
* kernel and should generate an OOPS. Unfortunatly, in the case of an
- * erroneous fault occuring in a code path which already holds mmap_sem
+ * erroneous fault occurring in a code path which already holds mmap_sem
* we will deadlock attempting to validate the fault against the
* address space. Luckily the kernel only validly references user
* space from well defined areas of code, which are listed in the
* thus avoiding the deadlock.
*/
if (!down_read_trylock(&mm->mmap_sem)) {
- if ((error_code & 4) == 0 &&
+ if ((error_code & ACE_USERMODE) == 0 &&
!search_exception_tables(regs->psw))
goto bad_area_nosemaphore;
down_read(&mm->mmap_sem);
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
-#if 0
- if (error_code & 4) {
+
+ if (error_code & ACE_USERMODE) {
/*
* accessing the stack below "spu" is always a bug.
* The "+ 4" is there due to the push instruction
if (address + 4 < regs->spu)
goto bad_area;
}
-#endif
+
if (expand_stack(vma, address))
goto bad_area;
/*
good_area:
info.si_code = SEGV_ACCERR;
write = 0;
- switch (error_code & 3) {
+ switch (error_code & (ACE_WRITE|ACE_PROTECTION)) {
default: /* 3: write, present */
/* fall through */
- case 2: /* write, not present */
+ case ACE_WRITE: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
write++;
break;
- case 1: /* read, present */
+ case ACE_PROTECTION: /* read, present */
case 0: /* read, not present */
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
+ /*
+ * For instruction access exception, check if the area is executable
+ */
+ if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+
survive:
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- addr = (address & PAGE_MASK) | (error_code & 8);
+ addr = (address & PAGE_MASK);
+ set_thread_fault_code(error_code);
switch (handle_mm_fault(mm, vma, addr, write)) {
case VM_FAULT_MINOR:
tsk->min_flt++;
default:
BUG();
}
-
+ set_thread_fault_code(0);
up_read(&mm->mmap_sem);
return;
bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
- if (error_code & 4) {
+ if (error_code & ACE_USERMODE) {
tsk->thread.address = address;
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14;
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
}
printk("VM: killing process %s\n", tsk->comm);
- if (error_code & 4)
+ if (error_code & ACE_USERMODE)
do_exit(SIGKILL);
goto no_context;
up_read(&mm->mmap_sem);
/* Kernel mode? Handle exception or die */
- if (!(error_code & 4))
+ if (!(error_code & ACE_USERMODE))
goto no_context;
tsk->thread.address = address;
if (!pte_present(*pte_k))
goto no_context;
- addr = (address & PAGE_MASK) | (error_code & 8);
+ addr = (address & PAGE_MASK) | (error_code & ACE_INSTRUCTION);
update_mmu_cache(NULL, addr, *pte_k);
return;
}
unsigned long *entry1, *entry2;
unsigned long pte_data, flags;
unsigned int *entry_dat;
- int inst = vaddr & 8;
+ int inst = get_thread_fault_code() & ACE_INSTRUCTION;
int i;
/* Ptrace may call this routine. */