|
@@ -211,7 +211,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long address)
|
|
|
}
|
|
|
|
|
|
static noinline void
|
|
|
-no_context(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+no_context(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address)
|
|
|
{
|
|
|
/* Are we prepared to handle this kernel fault? */
|
|
@@ -229,13 +229,13 @@ no_context(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
|
|
|
show_fault_oops(regs, address);
|
|
|
|
|
|
- die("Oops", regs, writeaccess);
|
|
|
+ die("Oops", regs, error_code);
|
|
|
bust_spinlocks(0);
|
|
|
do_exit(SIGKILL);
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-__bad_area_nosemaphore(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address, int si_code)
|
|
|
{
|
|
|
struct task_struct *tsk = current;
|
|
@@ -252,18 +252,18 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- no_context(regs, writeaccess, address);
|
|
|
+ no_context(regs, error_code, address);
|
|
|
}
|
|
|
|
|
|
static noinline void
|
|
|
-bad_area_nosemaphore(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address)
|
|
|
{
|
|
|
- __bad_area_nosemaphore(regs, writeaccess, address, SEGV_MAPERR);
|
|
|
+ __bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR);
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-__bad_area(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+__bad_area(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address, int si_code)
|
|
|
{
|
|
|
struct mm_struct *mm = current->mm;
|
|
@@ -274,20 +274,20 @@ __bad_area(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
*/
|
|
|
up_read(&mm->mmap_sem);
|
|
|
|
|
|
- __bad_area_nosemaphore(regs, writeaccess, address, si_code);
|
|
|
+ __bad_area_nosemaphore(regs, error_code, address, si_code);
|
|
|
}
|
|
|
|
|
|
static noinline void
|
|
|
-bad_area(struct pt_regs *regs, unsigned long writeaccess, unsigned long address)
|
|
|
+bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
|
|
|
{
|
|
|
- __bad_area(regs, writeaccess, address, SEGV_MAPERR);
|
|
|
+ __bad_area(regs, error_code, address, SEGV_MAPERR);
|
|
|
}
|
|
|
|
|
|
static noinline void
|
|
|
-bad_area_access_error(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address)
|
|
|
{
|
|
|
- __bad_area(regs, writeaccess, address, SEGV_ACCERR);
|
|
|
+ __bad_area(regs, error_code, address, SEGV_ACCERR);
|
|
|
}
|
|
|
|
|
|
static void out_of_memory(void)
|
|
@@ -302,7 +302,7 @@ static void out_of_memory(void)
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-do_sigbus(struct pt_regs *regs, unsigned long writeaccess, unsigned long address)
|
|
|
+do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address)
|
|
|
{
|
|
|
struct task_struct *tsk = current;
|
|
|
struct mm_struct *mm = tsk->mm;
|
|
@@ -311,13 +311,13 @@ do_sigbus(struct pt_regs *regs, unsigned long writeaccess, unsigned long address
|
|
|
|
|
|
/* Kernel mode? Handle exceptions or die: */
|
|
|
if (!user_mode(regs))
|
|
|
- no_context(regs, writeaccess, address);
|
|
|
+ no_context(regs, error_code, address);
|
|
|
|
|
|
force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
|
|
|
}
|
|
|
|
|
|
static noinline int
|
|
|
-mm_fault_error(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+mm_fault_error(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address, unsigned int fault)
|
|
|
{
|
|
|
/*
|
|
@@ -328,7 +328,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
if (!(fault & VM_FAULT_RETRY))
|
|
|
up_read(¤t->mm->mmap_sem);
|
|
|
if (!user_mode(regs))
|
|
|
- no_context(regs, writeaccess, address);
|
|
|
+ no_context(regs, error_code, address);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -339,14 +339,14 @@ mm_fault_error(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
/* Kernel mode? Handle exceptions or die: */
|
|
|
if (!user_mode(regs)) {
|
|
|
up_read(¤t->mm->mmap_sem);
|
|
|
- no_context(regs, writeaccess, address);
|
|
|
+ no_context(regs, error_code, address);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
out_of_memory();
|
|
|
} else {
|
|
|
if (fault & VM_FAULT_SIGBUS)
|
|
|
- do_sigbus(regs, writeaccess, address);
|
|
|
+ do_sigbus(regs, error_code, address);
|
|
|
else
|
|
|
BUG();
|
|
|
}
|
|
@@ -381,7 +381,7 @@ static int fault_in_kernel_space(unsigned long address)
|
|
|
* routines.
|
|
|
*/
|
|
|
asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|
|
- unsigned long writeaccess,
|
|
|
+ unsigned long error_code,
|
|
|
unsigned long address)
|
|
|
{
|
|
|
unsigned long vec;
|
|
@@ -389,8 +389,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|
|
struct mm_struct *mm;
|
|
|
struct vm_area_struct * vma;
|
|
|
int fault;
|
|
|
+ int write = error_code & FAULT_CODE_WRITE;
|
|
|
unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
|
|
|
- (writeaccess ? FAULT_FLAG_WRITE : 0));
|
|
|
+ (write ? FAULT_FLAG_WRITE : 0));
|
|
|
|
|
|
tsk = current;
|
|
|
mm = tsk->mm;
|
|
@@ -411,7 +412,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|
|
if (notify_page_fault(regs, vec))
|
|
|
return;
|
|
|
|
|
|
- bad_area_nosemaphore(regs, writeaccess, address);
|
|
|
+ bad_area_nosemaphore(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -429,7 +430,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|
|
* in an atomic region then we must not take the fault:
|
|
|
*/
|
|
|
if (unlikely(in_atomic() || !mm)) {
|
|
|
- bad_area_nosemaphore(regs, writeaccess, address);
|
|
|
+ bad_area_nosemaphore(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -438,17 +439,17 @@ retry:
|
|
|
|
|
|
vma = find_vma(mm, address);
|
|
|
if (unlikely(!vma)) {
|
|
|
- bad_area(regs, writeaccess, address);
|
|
|
+ bad_area(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
if (likely(vma->vm_start <= address))
|
|
|
goto good_area;
|
|
|
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
|
|
|
- bad_area(regs, writeaccess, address);
|
|
|
+ bad_area(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
if (unlikely(expand_stack(vma, address))) {
|
|
|
- bad_area(regs, writeaccess, address);
|
|
|
+ bad_area(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -457,11 +458,13 @@ retry:
|
|
|
* we can handle it..
|
|
|
*/
|
|
|
good_area:
|
|
|
- if (unlikely(access_error(writeaccess, vma))) {
|
|
|
- bad_area_access_error(regs, writeaccess, address);
|
|
|
+ if (unlikely(access_error(error_code, vma))) {
|
|
|
+ bad_area_access_error(regs, error_code, address);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ set_thread_fault_code(error_code);
|
|
|
+
|
|
|
/*
|
|
|
* If for any reason at all we couldn't handle the fault,
|
|
|
* make sure we exit gracefully rather than endlessly redo
|
|
@@ -470,7 +473,7 @@ good_area:
|
|
|
fault = handle_mm_fault(mm, vma, address, flags);
|
|
|
|
|
|
if (unlikely(fault & (VM_FAULT_RETRY | VM_FAULT_ERROR)))
|
|
|
- if (mm_fault_error(regs, writeaccess, address, fault))
|
|
|
+ if (mm_fault_error(regs, error_code, address, fault))
|
|
|
return;
|
|
|
|
|
|
if (flags & FAULT_FLAG_ALLOW_RETRY) {
|
|
@@ -502,7 +505,7 @@ good_area:
|
|
|
* Called with interrupts disabled.
|
|
|
*/
|
|
|
asmlinkage int __kprobes
|
|
|
-handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
+handle_tlbmiss(struct pt_regs *regs, unsigned long error_code,
|
|
|
unsigned long address)
|
|
|
{
|
|
|
pgd_t *pgd;
|
|
@@ -535,10 +538,10 @@ handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
entry = *pte;
|
|
|
if (unlikely(pte_none(entry) || pte_not_present(entry)))
|
|
|
return 1;
|
|
|
- if (unlikely(writeaccess && !pte_write(entry)))
|
|
|
+ if (unlikely(error_code && !pte_write(entry)))
|
|
|
return 1;
|
|
|
|
|
|
- if (writeaccess)
|
|
|
+ if (error_code)
|
|
|
entry = pte_mkdirty(entry);
|
|
|
entry = pte_mkyoung(entry);
|
|
|
|
|
@@ -550,10 +553,11 @@ handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
|
|
|
* the case of an initial page write exception, so we need to
|
|
|
* flush it in order to avoid potential TLB entry duplication.
|
|
|
*/
|
|
|
- if (writeaccess == 2)
|
|
|
+ if (error_code == FAULT_CODE_INITIAL)
|
|
|
local_flush_tlb_one(get_asid(), address & PAGE_MASK);
|
|
|
#endif
|
|
|
|
|
|
+ set_thread_fault_code(error_code);
|
|
|
update_mmu_cache(NULL, address, pte);
|
|
|
|
|
|
return 0;
|