Begin to unify do_page_fault(), easy code movement first. Signed-off-by: Harvey Harrison <[EMAIL PROTECTED]> --- Ingo, similar to the kprobes unification patches I did, it gets a bit uglier before it gets better ;-)
arch/x86/mm/fault_32.c | 38 +++++++++++++++++++++++++++++--------- arch/x86/mm/fault_64.c | 23 ++++++++++++++++++----- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index b1893eb..051a4ec 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c @@ -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 diff --git a/arch/x86/mm/fault_64.c b/arch/x86/mm/fault_64.c index 357a3e0..97b92b6 100644 --- a/arch/x86/mm/fault_64.c +++ b/arch/x86/mm/fault_64.c @@ -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; -- 1.5.4.rc2.1097.gb6e0d -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/