.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/arch/arm/mm/alignment.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * Thumb alignment fault fixups (c) 2004 MontaVista Software, Inc. |
---|
7 | 8 | * - Adapted from gdb/sim/arm/thumbemu.c -- Thumb instruction emulation. |
---|
8 | 9 | * Copyright (C) 1996, Cygnus Software Technologies Ltd. |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License version 2 as |
---|
12 | | - * published by the Free Software Foundation. |
---|
13 | 10 | */ |
---|
14 | 11 | #include <linux/moduleparam.h> |
---|
15 | 12 | #include <linux/compiler.h> |
---|
.. | .. |
---|
133 | 130 | static int alignment_proc_show(struct seq_file *m, void *v) |
---|
134 | 131 | { |
---|
135 | 132 | seq_printf(m, "User:\t\t%lu\n", ai_user); |
---|
136 | | - seq_printf(m, "System:\t\t%lu (%pF)\n", ai_sys, ai_sys_last_pc); |
---|
| 133 | + seq_printf(m, "System:\t\t%lu (%pS)\n", ai_sys, ai_sys_last_pc); |
---|
137 | 134 | seq_printf(m, "Skipped:\t%lu\n", ai_skipped); |
---|
138 | 135 | seq_printf(m, "Half:\t\t%lu\n", ai_half); |
---|
139 | 136 | seq_printf(m, "Word:\t\t%lu\n", ai_word); |
---|
.. | .. |
---|
165 | 162 | return count; |
---|
166 | 163 | } |
---|
167 | 164 | |
---|
168 | | -static const struct file_operations alignment_proc_fops = { |
---|
169 | | - .open = alignment_proc_open, |
---|
170 | | - .read = seq_read, |
---|
171 | | - .llseek = seq_lseek, |
---|
172 | | - .release = single_release, |
---|
173 | | - .write = alignment_proc_write, |
---|
| 165 | +static const struct proc_ops alignment_proc_ops = { |
---|
| 166 | + .proc_open = alignment_proc_open, |
---|
| 167 | + .proc_read = seq_read, |
---|
| 168 | + .proc_lseek = seq_lseek, |
---|
| 169 | + .proc_release = single_release, |
---|
| 170 | + .proc_write = alignment_proc_write, |
---|
174 | 171 | }; |
---|
175 | 172 | #endif /* CONFIG_PROC_FS */ |
---|
176 | 173 | |
---|
.. | .. |
---|
327 | 324 | __put32_unaligned_check("strbt", val, addr) |
---|
328 | 325 | |
---|
329 | 326 | static void |
---|
330 | | -do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset) |
---|
| 327 | +do_alignment_finish_ldst(unsigned long addr, u32 instr, struct pt_regs *regs, union offset_union offset) |
---|
331 | 328 | { |
---|
332 | 329 | if (!LDST_U_BIT(instr)) |
---|
333 | 330 | offset.un = -offset.un; |
---|
.. | .. |
---|
340 | 337 | } |
---|
341 | 338 | |
---|
342 | 339 | static int |
---|
343 | | -do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) |
---|
| 340 | +do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs) |
---|
344 | 341 | { |
---|
345 | 342 | unsigned int rd = RD_BITS(instr); |
---|
346 | 343 | |
---|
.. | .. |
---|
389 | 386 | } |
---|
390 | 387 | |
---|
391 | 388 | static int |
---|
392 | | -do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, |
---|
393 | | - struct pt_regs *regs) |
---|
| 389 | +do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs) |
---|
394 | 390 | { |
---|
395 | 391 | unsigned int rd = RD_BITS(instr); |
---|
396 | 392 | unsigned int rd2; |
---|
.. | .. |
---|
452 | 448 | } |
---|
453 | 449 | |
---|
454 | 450 | static int |
---|
455 | | -do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) |
---|
| 451 | +do_alignment_ldrstr(unsigned long addr, u32 instr, struct pt_regs *regs) |
---|
456 | 452 | { |
---|
457 | 453 | unsigned int rd = RD_BITS(instr); |
---|
458 | 454 | |
---|
.. | .. |
---|
501 | 497 | * PU = 10 A B |
---|
502 | 498 | */ |
---|
503 | 499 | static int |
---|
504 | | -do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs) |
---|
| 500 | +do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs) |
---|
505 | 501 | { |
---|
506 | 502 | unsigned int rd, rn, correction, nr_regs, regbits; |
---|
507 | 503 | unsigned long eaddr, newaddr; |
---|
.. | .. |
---|
542 | 538 | * processor for us. |
---|
543 | 539 | */ |
---|
544 | 540 | if (addr != eaddr) { |
---|
545 | | - pr_err("LDMSTM: PC = %08lx, instr = %08lx, " |
---|
| 541 | + pr_err("LDMSTM: PC = %08lx, instr = %08x, " |
---|
546 | 542 | "addr = %08lx, eaddr = %08lx\n", |
---|
547 | 543 | instruction_pointer(regs), instr, addr, eaddr); |
---|
548 | 544 | show_regs(regs); |
---|
.. | .. |
---|
698 | 694 | return subset[(L<<1) | ((tinstr & (1<<8)) >> 8)] | |
---|
699 | 695 | (tinstr & 255); /* register_list */ |
---|
700 | 696 | } |
---|
701 | | - /* Else fall through for illegal instruction case */ |
---|
| 697 | + fallthrough; /* for illegal instruction case */ |
---|
702 | 698 | |
---|
703 | 699 | default: |
---|
704 | 700 | return BAD_INSTR; |
---|
.. | .. |
---|
719 | 715 | * 2. Register name Rt from ARMv7 is same as Rd from ARMv6 (Rd is Rt) |
---|
720 | 716 | */ |
---|
721 | 717 | static void * |
---|
722 | | -do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs, |
---|
| 718 | +do_alignment_t32_to_handler(u32 *pinstr, struct pt_regs *regs, |
---|
723 | 719 | union offset_union *poffset) |
---|
724 | 720 | { |
---|
725 | | - unsigned long instr = *pinstr; |
---|
| 721 | + u32 instr = *pinstr; |
---|
726 | 722 | u16 tinst1 = (instr >> 16) & 0xffff; |
---|
727 | 723 | u16 tinst2 = instr & 0xffff; |
---|
728 | 724 | |
---|
.. | .. |
---|
754 | 750 | case 0xe8e0: |
---|
755 | 751 | case 0xe9e0: |
---|
756 | 752 | poffset->un = (tinst2 & 0xff) << 2; |
---|
| 753 | + fallthrough; |
---|
| 754 | + |
---|
757 | 755 | case 0xe940: |
---|
758 | 756 | case 0xe9c0: |
---|
759 | 757 | return do_alignment_ldrdstrd; |
---|
.. | .. |
---|
768 | 766 | return NULL; |
---|
769 | 767 | } |
---|
770 | 768 | |
---|
771 | | -static int alignment_get_arm(struct pt_regs *regs, u32 *ip, unsigned long *inst) |
---|
| 769 | +static int alignment_get_arm(struct pt_regs *regs, u32 *ip, u32 *inst) |
---|
772 | 770 | { |
---|
773 | 771 | u32 instr = 0; |
---|
774 | 772 | int fault; |
---|
.. | .. |
---|
776 | 774 | if (user_mode(regs)) |
---|
777 | 775 | fault = get_user(instr, ip); |
---|
778 | 776 | else |
---|
779 | | - fault = probe_kernel_address(ip, instr); |
---|
| 777 | + fault = get_kernel_nofault(instr, ip); |
---|
780 | 778 | |
---|
781 | 779 | *inst = __mem_to_opcode_arm(instr); |
---|
782 | 780 | |
---|
.. | .. |
---|
791 | 789 | if (user_mode(regs)) |
---|
792 | 790 | fault = get_user(instr, ip); |
---|
793 | 791 | else |
---|
794 | | - fault = probe_kernel_address(ip, instr); |
---|
| 792 | + fault = get_kernel_nofault(instr, ip); |
---|
795 | 793 | |
---|
796 | 794 | *inst = __mem_to_opcode_thumb16(instr); |
---|
797 | 795 | |
---|
.. | .. |
---|
801 | 799 | static int |
---|
802 | 800 | do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) |
---|
803 | 801 | { |
---|
804 | | - union offset_union uninitialized_var(offset); |
---|
805 | | - unsigned long instr = 0, instrptr; |
---|
806 | | - int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); |
---|
| 802 | + union offset_union offset; |
---|
| 803 | + unsigned long instrptr; |
---|
| 804 | + int (*handler)(unsigned long addr, u32 instr, struct pt_regs *regs); |
---|
807 | 805 | unsigned int type; |
---|
| 806 | + u32 instr = 0; |
---|
808 | 807 | u16 tinstr = 0; |
---|
809 | 808 | int isize = 4; |
---|
810 | 809 | int thumb2_32b = 0; |
---|
.. | .. |
---|
936 | 935 | if (type == TYPE_LDST) |
---|
937 | 936 | do_alignment_finish_ldst(addr, instr, regs, offset); |
---|
938 | 937 | |
---|
| 938 | + if (thumb_mode(regs)) |
---|
| 939 | + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); |
---|
| 940 | + |
---|
939 | 941 | return 0; |
---|
940 | 942 | |
---|
941 | 943 | bad_or_fault: |
---|
.. | .. |
---|
955 | 957 | * Oops, we didn't handle the instruction. |
---|
956 | 958 | */ |
---|
957 | 959 | pr_err("Alignment trap: not handling instruction " |
---|
958 | | - "%0*lx at [<%08lx>]\n", |
---|
| 960 | + "%0*x at [<%08lx>]\n", |
---|
959 | 961 | isize << 1, |
---|
960 | 962 | isize == 2 ? tinstr : instr, instrptr); |
---|
961 | 963 | ai_skipped += 1; |
---|
.. | .. |
---|
965 | 967 | ai_user += 1; |
---|
966 | 968 | |
---|
967 | 969 | if (ai_usermode & UM_WARN) |
---|
968 | | - printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx " |
---|
| 970 | + printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*x " |
---|
969 | 971 | "Address=0x%08lx FSR 0x%03x\n", current->comm, |
---|
970 | 972 | task_pid_nr(current), instrptr, |
---|
971 | 973 | isize << 1, |
---|
.. | .. |
---|
976 | 978 | goto fixup; |
---|
977 | 979 | |
---|
978 | 980 | if (ai_usermode & UM_SIGNAL) { |
---|
979 | | - siginfo_t si; |
---|
980 | | - |
---|
981 | | - clear_siginfo(&si); |
---|
982 | | - si.si_signo = SIGBUS; |
---|
983 | | - si.si_errno = 0; |
---|
984 | | - si.si_code = BUS_ADRALN; |
---|
985 | | - si.si_addr = (void __user *)addr; |
---|
986 | | - |
---|
987 | | - force_sig_info(si.si_signo, &si, current); |
---|
| 981 | + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr); |
---|
988 | 982 | } else { |
---|
989 | 983 | /* |
---|
990 | 984 | * We're about to disable the alignment trap and return to |
---|
.. | .. |
---|
1025 | 1019 | struct proc_dir_entry *res; |
---|
1026 | 1020 | |
---|
1027 | 1021 | res = proc_create("cpu/alignment", S_IWUSR | S_IRUGO, NULL, |
---|
1028 | | - &alignment_proc_fops); |
---|
| 1022 | + &alignment_proc_ops); |
---|
1029 | 1023 | if (!res) |
---|
1030 | 1024 | return -ENOMEM; |
---|
1031 | 1025 | #endif |
---|
.. | .. |
---|
1055 | 1049 | return 0; |
---|
1056 | 1050 | } |
---|
1057 | 1051 | |
---|
1058 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
---|
1059 | | -fs_initcall_sync(alignment_init); |
---|
1060 | | -#else |
---|
1061 | 1052 | fs_initcall(alignment_init); |
---|
1062 | | -#endif |
---|