x86: fault_{32|64}.c unify do_page_fault
PATCH v2 1/1 x86: fault_{32|64}.c unify do_page_fault
Begin to unify do_page_fault(), easy code movement first.
Signed-off-by Harvey Harrison <[email protected]>
---
Ingo, Alexey Dobriyan noticed an obvious typo CONFIG_x86_64 in the previous version, this is a fixed patch.
arch/x86/mm/fault_32.c | 38 +++++++++++++++++++++++++++++--------- arch/x86/mm/fault_64.c | 23 ++++++++++++++++++----- 2 files changed, 47 insertions(+), 14 deletions(-)
arch/x86/mm/fault_32.c +29 -9
@@ -375,19 +375,26 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)struct mm_struct *mm;struct vm_area_struct *vma;unsigned long address; -int write, si_code; -int fault; +int write, fault; +#ifdef CONFIG_X86_64 +unsigned long flags; +#endif +int si_code;/* * We can fault from pretty much anywhere, with unknown IRQ state. */ trace_hardirqs_fixup (); -/* get the address */ - address =read_cr2 (); - tsk = current; + mm = tsk->mm; +#ifdef CONFIG_X86_64 +prefetchw (&mm->mmap_sem); +#endif + +/* get the address */ + address =read_cr2 (); si_code =SEGV_MAPERR ;/*
@@ -403,9 +410,24 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)* (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 9) == 0. */ +#ifdef CONFIG_X86_32 if (unlikely (address >=TASK_SIZE )) { -if (!(error_code &0x0000000d ) &&vmalloc_fault (address) >=0 ) +if (!(error_code & (PF_RSVD |PF_USER |PF_PROT )) && +vmalloc_fault (address) >=0 )return ; +#else +if (unlikely (address >=TASK_SIZE64 )) { +/* +* Don't check for the module range here: its PML4 +* is always initialized because it's shared with the main +* kernel text. Only vmalloc may need PML4 syncups. +*/ +if (!(error_code & (PF_RSVD |PF_USER |PF_PROT )) && + ((address >=VMALLOC_START && address <VMALLOC_END ))) { +if (vmalloc_fault (address) >=0 ) +return ; + } +#endif if (notify_page_fault (regs))return ;/*
@@ -423,8 +445,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)if (regs->flags & (X86_EFLAGS_IF |VM_MASK ))local_irq_enable (); - mm = tsk->mm; -/* * If we're in an interrupt, have no user context or are running in an * atomic region then we must not take the fault.
@@ -495,7 +515,7 @@ good_area: goto bad_area; } - survive: +survive:/* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo
arch/x86/mm/fault_64.c +18 -5
@@ -426,7 +426,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,struct vm_area_struct *vma;unsigned long address;int write, fault; +#ifdef CONFIG_X86_64 unsigned long flags; +#endif int si_code;/*
@@ -436,14 +438,15 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, tsk = current; mm = tsk->mm; + +#ifdef CONFIG_X86_64 prefetchw (&mm->mmap_sem); +#endif /* get the address */ address =read_cr2 (); - si_code =SEGV_MAPERR ; -/* * We fault-in kernel-space virtual memory on-demand. The * 'reference' page table is init_mm.pgd.
@@ -457,6 +460,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,* (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 9) == 0. */ +#ifdef CONFIG_X86_32 +if (unlikely (address >=TASK_SIZE )) { +if (!(error_code & (PF_RSVD |PF_USER |PF_PROT )) && +vmalloc_fault (address) >=0 ) +return ; +#else if (unlikely (address >=TASK_SIZE64 )) {/* * Don't check for the module range here: its PML4
@@ -468,6 +477,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,if (vmalloc_fault (address) >=0 ) return; } +#endif if (notify_page_fault (regs))return ;/*
@@ -500,7 +510,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,if (user_mode_vm (regs)) error_code |=PF_USER ; - again: +again:/* 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. Unfortunately, in the case of an
@@ -531,8 +541,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,if (!(vma->vm_flags &VM_GROWSDOWN )) goto bad_area;if (error_code &PF_USER ) { -/* Allow userspace just enough access below the stack pointer -* to let the 'enter' instruction work. +/* +* Accessing the stack below %sp is always a bug. +* The large cushion allows instructions like enter +* and pusha to work. ("enter $65535,$31" pushes +* 32 pointers and then decrements %sp by 65535.) */ if (address +65536 +32 *sizeof (unsigned long ) < regs->sp) goto bad_area;
Signature · 1 line
1.5.4.rc2.1097.gb6e0d