| .. | .. |
|---|
| 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 |
|---|