--- zzzz-none-000/linux-3.10.107/arch/arm/mm/alignment.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/mm/alignment.c 2021-02-04 17:41:59.000000000 +0000 @@ -25,9 +25,14 @@ #include #include #include +#include #include "fault.h" - +#include "mm.h" +#if defined(CONFIG_ARM_UNWIND) +#include +#endif/*--- #if defined(CONFIG_ARM_UNWIND) ---*/ + /* * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 * /proc/sys/debug/alignment, modified and integrated into @@ -73,14 +78,14 @@ #define IS_T32(hi16) \ (((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800)) -static unsigned long ai_user; -static unsigned long ai_sys; +static void *ai_sys_last_pc; static unsigned long ai_skipped; static unsigned long ai_half; static unsigned long ai_word; static unsigned long ai_dword; static unsigned long ai_multi; static int ai_usermode; +static unsigned long cr_no_alignment; core_param(alignment, ai_usermode, int, 0600); @@ -88,10 +93,66 @@ #define UM_FIXUP (1 << 1) #define UM_SIGNAL (1 << 2) +#if defined(CONFIG_AVM_ENHANCED) +#include +static struct _ai_info { + unsigned long ai_count; + unsigned long last_pc; + char last_comm[TASK_COMM_LEN]; +} ai_info[2]; + +#define UM_BT (1 << 3) + +#define AI_SYS 0 +#define AI_USER 1 + +#define ai_user ai_info[AI_USER].ai_count +#define ai_sys ai_info[AI_SYS].ai_count + +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static inline void inc_ai_info(int ai_idx, unsigned long pc) { + ai_info[ai_idx].ai_count++; + ai_info[ai_idx].last_pc = pc; + memcpy(ai_info[ai_idx].last_comm, current->comm, TASK_COMM_LEN); + ai_add_to_scorelist(pc, (ai_idx == AI_USER) ? 1 : 0); +} +/**--------------------------------------------------------------------------------**\ + * \\brief: + * Liefere Unaligned-Daten + * user: 0 Kernel 1 Userland + * ret: Zeiger auf last_comm des Userprozesses +\**--------------------------------------------------------------------------------**/ +const char *get_last_unaligned_info(unsigned long *ai_count, unsigned long *last_pc, int user) { + int idx = user ? AI_USER : AI_SYS; + if(ai_count) *ai_count = ai_info[idx].ai_count; + if(last_pc) *last_pc = ai_info[idx].last_pc; + return ai_info[idx].last_comm; +} +static int ai_kernelmode = UM_FIXUP; + +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static char *map_mode(char *txt, int mode) { + int len = sprintf(txt, "%s%s%s%s%s", + (mode == 0) ? "ignore " : "", + (mode & UM_FIXUP) ? "fixup+" : "", + (mode & UM_SIGNAL) ? "signal+" : "", + (mode & UM_WARN) ? "warn+" : "", + (mode & UM_BT) ? "backtrace " : "" ); + txt[len-1] = 0; + return txt; +} +#else/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ +static unsigned long ai_user; +static unsigned long ai_sys; +#endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + + /* Return true if and only if the ARMv6 unaligned access model is in use. */ static bool cpu_is_v6_unaligned(void) { - return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U); + return cpu_architecture() >= CPU_ARCH_ARMv6 && get_cr() & CR_U; } static int safe_usermode(int new_usermode, bool warn) @@ -109,7 +170,7 @@ new_usermode |= UM_FIXUP; if (warn) - printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU. Defaulting to fixup mode.\n"); + pr_warn("alignment: ignoring faults is unsafe on this CPU. Defaulting to fixup mode.\n"); } return new_usermode; @@ -128,7 +189,7 @@ static int alignment_proc_show(struct seq_file *m, void *v) { seq_printf(m, "User:\t\t%lu\n", ai_user); - seq_printf(m, "System:\t\t%lu\n", ai_sys); + seq_printf(m, "System:\t\t%lu (%pF)\n", ai_sys, ai_sys_last_pc); seq_printf(m, "Skipped:\t%lu\n", ai_skipped); seq_printf(m, "Half:\t\t%lu\n", ai_half); seq_printf(m, "Word:\t\t%lu\n", ai_word); @@ -137,6 +198,19 @@ seq_printf(m, "Multi:\t\t%lu\n", ai_multi); seq_printf(m, "User faults:\t%i (%s)\n", ai_usermode, usermode_action[ai_usermode]); +#if defined(CONFIG_AVM_ENHANCED) + { + char txt[64]; + int ret; + seq_printf(m, "Kernel faults:\t%i (%s)\n", min(8,ai_kernelmode + 4), map_mode(txt, ai_kernelmode)); + if((ret = ai_show_scorelist(m, 1)) != ai_user) { + if(ret) seq_printf(m, "... only the newest user-unaligneds shown\n"); + } + if((ret = ai_show_scorelist(m, 0)) != ai_sys) { + if(ret) seq_printf(m, "... only the newest kernel-unaligneds shown\n"); + } + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ return 0; } @@ -150,12 +224,38 @@ size_t count, loff_t *pos) { char mode; +#if defined(CONFIG_AVM_ENHANCED) + char txt[4][64]; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ if (count > 0) { if (get_user(mode, buffer)) return -EFAULT; - if (mode >= '0' && mode <= '5') + if (mode >= '0' && mode <= '5') { ai_usermode = safe_usermode(mode - '0', true); +#if defined(CONFIG_AVM_ENHANCED) + printk(KERN_ERR "set user unaligned-mode: %s\n", map_mode(txt[0], ai_usermode)); + } else if (mode >= '6' && mode <= '8') { + ai_kernelmode = mode == '6' ? UM_FIXUP : + mode == '7' ? UM_FIXUP | UM_WARN : UM_FIXUP | UM_WARN | UM_BT; + printk(KERN_ERR "set kernel unaligned-mode: %s\n", map_mode(txt[0], ai_kernelmode)); + } else { + printk(KERN_ERR "parameter: user '2' %s '3' %s '4' %s '5' %s \n", map_mode(txt[0], UM_FIXUP), + map_mode(txt[1], UM_FIXUP | UM_WARN), + map_mode(txt[2], UM_SIGNAL), + map_mode(txt[3], UM_SIGNAL | UM_WARN)); + printk(KERN_ERR " system '6' %s '7' %s" +#if defined(CONFIG_ARM_UNWIND) + " '8' %s" +#endif/*--- #if defined(CONFIG_ARM_UNWIND) ---*/ + "\n", map_mode(txt[0], UM_FIXUP), + map_mode(txt[1], UM_FIXUP | UM_WARN) +#if defined(CONFIG_ARM_UNWIND) + ,map_mode(txt[2], UM_FIXUP | UM_WARN | UM_BT) +#endif/*--- #if defined(CONFIG_ARM_UNWIND) ---*/ + ); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + } } return count; } @@ -197,7 +297,7 @@ THUMB( "1: "ins" %1, [%2]\n" ) \ THUMB( " add %2, %2, #1\n" ) \ "2:\n" \ - " .pushsection .fixup,\"ax\"\n" \ + " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ "3: mov %0, #1\n" \ " b 2b\n" \ @@ -257,7 +357,7 @@ " mov %1, %1, "NEXT_BYTE"\n" \ "2: "ins" %1, [%2]\n" \ "3:\n" \ - " .pushsection .fixup,\"ax\"\n" \ + " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ "4: mov %0, #1\n" \ " b 3b\n" \ @@ -297,7 +397,7 @@ " mov %1, %1, "NEXT_BYTE"\n" \ "4: "ins" %1, [%2]\n" \ "5:\n" \ - " .pushsection .fixup,\"ax\"\n" \ + " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ "6: mov %0, #1\n" \ " b 5b\n" \ @@ -361,15 +461,21 @@ user: if (LDST_L_BIT(instr)) { unsigned long val; + unsigned int __ua_flags = uaccess_save_and_enable(); + get16t_unaligned_check(val, addr); + uaccess_restore(__ua_flags); /* signed half-word? */ if (instr & 0x40) val = (signed long)((signed short) val); regs->uregs[rd] = val; - } else + } else { + unsigned int __ua_flags = uaccess_save_and_enable(); put16t_unaligned_check(regs->uregs[rd], addr); + uaccess_restore(__ua_flags); + } return TYPE_LDST; @@ -416,14 +522,21 @@ user: if (load) { - unsigned long val; + unsigned long val, val2; + unsigned int __ua_flags = uaccess_save_and_enable(); + get32t_unaligned_check(val, addr); + get32t_unaligned_check(val2, addr + 4); + + uaccess_restore(__ua_flags); + regs->uregs[rd] = val; - get32t_unaligned_check(val, addr + 4); - regs->uregs[rd2] = val; + regs->uregs[rd2] = val2; } else { + unsigned int __ua_flags = uaccess_save_and_enable(); put32t_unaligned_check(regs->uregs[rd], addr); put32t_unaligned_check(regs->uregs[rd2], addr + 4); + uaccess_restore(__ua_flags); } return TYPE_LDST; @@ -454,10 +567,15 @@ trans: if (LDST_L_BIT(instr)) { unsigned int val; + unsigned int __ua_flags = uaccess_save_and_enable(); get32t_unaligned_check(val, addr); + uaccess_restore(__ua_flags); regs->uregs[rd] = val; - } else + } else { + unsigned int __ua_flags = uaccess_save_and_enable(); put32t_unaligned_check(regs->uregs[rd], addr); + uaccess_restore(__ua_flags); + } return TYPE_LDST; fault: @@ -519,7 +637,7 @@ * processor for us. */ if (addr != eaddr) { - printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " + pr_err("LDMSTM: PC = %08lx, instr = %08lx, " "addr = %08lx, eaddr = %08lx\n", instruction_pointer(regs), instr, addr, eaddr); show_regs(regs); @@ -527,6 +645,7 @@ #endif if (user_mode(regs)) { + unsigned int __ua_flags = uaccess_save_and_enable(); for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) if (regbits & 1) { @@ -538,6 +657,7 @@ put32t_unaligned_check(regs->uregs[rd], eaddr); eaddr += 4; } + uaccess_restore(__ua_flags); } else { for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) @@ -563,7 +683,7 @@ return TYPE_FAULT; bad: - printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); + pr_err("Alignment trap: not handling ldm with s-bit set\n"); return TYPE_ERROR; } @@ -763,21 +883,25 @@ if (thumb_mode(regs)) { u16 *ptr = (u16 *)(instrptr & ~1); fault = probe_kernel_address(ptr, tinstr); + tinstr = __mem_to_opcode_thumb16(tinstr); if (!fault) { if (cpu_architecture() >= CPU_ARCH_ARMv7 && IS_T32(tinstr)) { /* Thumb-2 32-bit */ u16 tinst2 = 0; fault = probe_kernel_address(ptr + 1, tinst2); - instr = (tinstr << 16) | tinst2; + tinst2 = __mem_to_opcode_thumb16(tinst2); + instr = __opcode_thumb32_compose(tinstr, tinst2); thumb2_32b = 1; } else { isize = 2; instr = thumb2arm(tinstr); } } - } else - fault = probe_kernel_address(instrptr, instr); + } else { + fault = probe_kernel_address((void *)instrptr, instr); + instr = __mem_to_opcode_arm(instr); + } if (fault) { type = TYPE_FAULT; @@ -787,7 +911,41 @@ if (user_mode(regs)) goto user; +#if defined(CONFIG_AVM_ENHANCED) + inc_ai_info(AI_SYS, instrptr); + if(ai_kernelmode & UM_WARN) { + printk(KERN_ERR"Kernel Alignment trap %lu: %s (%d) PC=0x%lxS Instr=0x%0*lx " + "Address=0x%08lx FSR 0x%03x\n", ai_sys, current->comm, + task_pid_nr(current), instrptr, + isize << 1, + isize == 2 ? tinstr : instr, + addr, fsr); + print_code_range(NULL, "Kernel Alignment trap:", instrptr, thumb_mode(regs)); + } +#if defined(CONFIG_ARM_UNWIND) + if(ai_kernelmode & UM_BT) { + unwind_backtrace(regs, NULL); + } +#endif/*--- #if defined(CONFIG_ARM_UNWIND) ---*/ + if(ai_kernelmode & UM_FIXUP) { + goto fixup; + } + if(ai_kernelmode & UM_SIGNAL) { + siginfo_t si; + + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void __user *)addr; + + force_sig_info(si.si_signo, &si, current); + } + goto bad; +#else/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ ai_sys += 1; +#endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + + ai_sys_last_pc = (void *)instruction_pointer(regs); fixup: @@ -890,13 +1048,13 @@ return 0; swp: - printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); + pr_err("Alignment trap: not handling swp instruction\n"); bad: /* * Oops, we didn't handle the instruction. */ - printk(KERN_ERR "Alignment trap: not handling instruction " + pr_err("Alignment trap: not handling instruction " "%0*lx at [<%08lx>]\n", isize << 1, isize == 2 ? tinstr : instr, instrptr); @@ -904,10 +1062,14 @@ return 1; user: +#if defined(CONFIG_AVM_ENHANCED) + inc_ai_info(AI_USER, instrptr); +#else/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ ai_user += 1; +#endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ if (ai_usermode & UM_WARN) - printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " + printk(KERN_ERR"User-Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " "Address=0x%08lx FSR 0x%03x\n", current->comm, task_pid_nr(current), instrptr, isize << 1, @@ -947,6 +1109,13 @@ return 0; } +static int __init noalign_setup(char *__unused) +{ + set_cr(__clear_cr(CR_A)); + return 1; +} +__setup("noalign", noalign_setup); + /* * This needs to be done after sysctl_init, otherwise sys/ will be * overwritten. Actually, this shouldn't be in sys/ at all since @@ -964,14 +1133,12 @@ return -ENOMEM; #endif -#ifdef CONFIG_CPU_CP15 if (cpu_is_v6_unaligned()) { - cr_alignment &= ~CR_A; - cr_no_alignment &= ~CR_A; - set_cr(cr_alignment); + set_cr(__clear_cr(CR_A)); ai_usermode = safe_usermode(ai_usermode, false); } -#endif + + cr_no_alignment = get_cr() & ~CR_A; hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN, "alignment exception");