--- zzzz-none-000/linux-3.10.107/arch/arm/mm/fault.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/mm/fault.c 2021-02-04 17:41:59.000000000 +0000 @@ -25,9 +25,21 @@ #include #include #include +#if defined(CONFIG_AVM_SIMPLE_PROFILING) +#include +#endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ +#if defined(CONFIG_AVM_POWER) +#include +#endif /*--- #if defined(CONFIG_AVM_POWER) ---*/ + +#if defined(CONFIG_AVM_FASTIRQ) +#include +#endif/*--- #if defined(CONFIG_AVM_FASTIRQ) ---*/ #include "fault.h" +#include + #ifdef CONFIG_MMU #ifdef CONFIG_KPROBES @@ -63,9 +75,9 @@ if (!mm) mm = &init_mm; - printk(KERN_ALERT "pgd = %p\n", mm->pgd); + pr_alert("pgd = %p\n", mm->pgd); pgd = pgd_offset(mm, addr); - printk(KERN_ALERT "[%08lx] *pgd=%08llx", + pr_alert("[%08lx] *pgd=%08llx", addr, (long long)pgd_val(*pgd)); do { @@ -77,31 +89,31 @@ break; if (pgd_bad(*pgd)) { - printk("(bad)"); + pr_cont("(bad)"); break; } pud = pud_offset(pgd, addr); if (PTRS_PER_PUD != 1) - printk(", *pud=%08llx", (long long)pud_val(*pud)); + pr_cont(", *pud=%08llx", (long long)pud_val(*pud)); if (pud_none(*pud)) break; if (pud_bad(*pud)) { - printk("(bad)"); + pr_cont("(bad)"); break; } pmd = pmd_offset(pud, addr); if (PTRS_PER_PMD != 1) - printk(", *pmd=%08llx", (long long)pmd_val(*pmd)); + pr_cont(", *pmd=%08llx", (long long)pmd_val(*pmd)); if (pmd_none(*pmd)) break; if (pmd_bad(*pmd)) { - printk("(bad)"); + pr_cont("(bad)"); break; } @@ -110,15 +122,15 @@ break; pte = pte_offset_map(pmd, addr); - printk(", *pte=%08llx", (long long)pte_val(*pte)); + pr_cont(", *pte=%08llx", (long long)pte_val(*pte)); #ifndef CONFIG_ARM_LPAE - printk(", *ppte=%08llx", + pr_cont(", *ppte=%08llx", (long long)pte_val(pte[PTE_HWTABLE_PTRS])); #endif pte_unmap(pte); } while(0); - printk("\n"); + pr_cont("\n"); } #else /* CONFIG_MMU */ void show_pte(struct mm_struct *mm, unsigned long addr) @@ -132,6 +144,9 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs) { +#if defined(CONFIG_AVM_FASTIRQ) + struct pt_regs fregs; +#endif /* * Are we prepared to handle this kernel fault? */ @@ -141,11 +156,14 @@ /* * No handler, we'll have to terminate things with extreme prejudice. */ +#if defined(CONFIG_AVM_FASTIRQ) + prepare_register_for_trap(&fregs, ®s); + set_exc_regs(regs); +#endif bust_spinlocks(1); - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); + pr_alert("Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); show_pte(mm, addr); die("Oops", regs, fsr); @@ -164,6 +182,8 @@ { struct siginfo si; + trace_user_fault(tsk, addr, fsr); + #ifdef CONFIG_DEBUG_USER if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || ((user_debug & UDBG_BUS) && (sig == SIGBUS))) { @@ -244,7 +264,18 @@ goto out; } - return handle_mm_fault(mm, vma, addr & PAGE_MASK, flags); + /* + * If for any reason at all we couldn't handle the fault, make + * sure we exit gracefully rather than endlessly redo the fault. + */ +#if defined(CONFIG_AVM_POWER) + avm_page_statistic_fault_get(); +#endif/*--- #if defined(CONFIG_AVM_POWER) ---*/ + fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, flags); +#if defined(CONFIG_AVM_POWER) + avm_page_statistic_fault_put(); +#endif/*--- #if defined(CONFIG_AVM_POWER) ---*/ + return fault; check_stack: /* Don't allow expansion below FIRST_USER_ADDRESS */ @@ -263,6 +294,10 @@ int fault, sig, code; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_enter_irq_context(regs->ARM_pc, regs->ARM_lr); +#endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ + if (notify_page_fault(regs, fsr)) return 0; @@ -277,7 +312,7 @@ * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_atomic() || !mm) + if (faulthandler_disabled() || !mm) goto no_context; if (user_mode(regs)) @@ -309,7 +344,13 @@ #endif } +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_log(avm_profile_data_type_hw_irq_begin, (unsigned int)regs->ARM_pc, AVM_PROFILE_PAGE_FAULT_ID); +#endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ fault = __do_page_fault(mm, addr, fsr, flags, tsk); +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_log(avm_profile_data_type_hw_irq_end, (unsigned int)regs->ARM_pc, AVM_PROFILE_PAGE_FAULT_ID); +#endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ /* If we need to retry but a fatal signal is pending, handle the * signal first. We do not need to release the mmap_sem because @@ -431,6 +472,10 @@ if (addr < TASK_SIZE) return do_page_fault(addr, fsr, regs); +#if defined(CONFIG_AVM_SIMPLE_PROFILING) + avm_simple_profiling_enter_irq_context(regs->ARM_pc, regs->ARM_lr); +#endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ + if (user_mode(regs)) goto bad_area; @@ -494,12 +539,14 @@ * Some section permission faults need to be handled gracefully. * They can happen due to a __{get,put}_user during an oops. */ +#ifndef CONFIG_ARM_LPAE static int do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { do_bad_area(addr, fsr, regs); return 0; } +#endif /* CONFIG_ARM_LPAE */ /* * This abort handler always returns "fault". @@ -546,12 +593,24 @@ const struct fsr_info *inf = fsr_info + fsr_fs(fsr); struct siginfo info; +#if defined(CONFIG_AVM_FASTIRQ) + struct pt_regs fregs; +#endif if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) return; - printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", + pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); +#if defined(CONFIG_AVM_FASTIRQ) + if (!user_mode(regs)) { + prepare_register_for_trap(&fregs, ®s); + set_exc_regs(regs); + } +#endif + + show_pte(current->mm, addr); + info.si_signo = inf->sig; info.si_errno = 0; info.si_code = inf->code; @@ -578,12 +637,22 @@ const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); struct siginfo info; +#if defined(CONFIG_AVM_FASTIRQ) + struct pt_regs fregs; +#endif if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) return; - printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", + pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", inf->name, ifsr, addr); +#if defined(CONFIG_AVM_FASTIRQ) + if (!user_mode(regs)) { + prepare_register_for_trap(&fregs, ®s); + set_exc_regs(regs); + } +#endif + info.si_signo = inf->sig; info.si_errno = 0; info.si_code = inf->code; @@ -591,6 +660,28 @@ arm_notify_die("", regs, &info, ifsr, 0); } +/* + * Abort handler to be used only during first unmasking of asynchronous aborts + * on the boot CPU. This makes sure that the machine will not die if the + * firmware/bootloader left an imprecise abort pending for us to trip over. + */ +static int __init early_abort_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + pr_warn("Hit pending asynchronous external abort (FSR=0x%08x) during " + "first unmask, this is most likely caused by a " + "firmware/bootloader bug.\n", fsr); + + return 0; +} + +void __init early_abt_enable(void) +{ + fsr_info[FSR_FS_AEA].fn = early_abort_handler; + local_abt_enable(); + fsr_info[FSR_FS_AEA].fn = do_bad; +} + #ifndef CONFIG_ARM_LPAE static int __init exceptions_init(void) {