diff options
Diffstat (limited to 'arch/csky')
-rw-r--r-- | arch/csky/Kconfig | 30 | ||||
-rw-r--r-- | arch/csky/abiv2/inc/abi/entry.h | 3 | ||||
-rw-r--r-- | arch/csky/abiv2/mcount.S | 4 | ||||
-rw-r--r-- | arch/csky/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/csky/include/asm/bug.h | 3 | ||||
-rw-r--r-- | arch/csky/include/asm/irq_work.h | 11 | ||||
-rw-r--r-- | arch/csky/include/asm/processor.h | 6 | ||||
-rw-r--r-- | arch/csky/include/asm/ptrace.h | 7 | ||||
-rw-r--r-- | arch/csky/include/asm/thread_info.h | 2 | ||||
-rw-r--r-- | arch/csky/kernel/entry.S | 28 | ||||
-rw-r--r-- | arch/csky/kernel/ftrace.c | 5 | ||||
-rw-r--r-- | arch/csky/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/csky/kernel/ptrace.c | 37 | ||||
-rw-r--r-- | arch/csky/kernel/smp.c | 62 | ||||
-rw-r--r-- | arch/csky/kernel/traps.c | 223 | ||||
-rw-r--r-- | arch/csky/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/csky/lib/error-inject.c | 10 | ||||
-rw-r--r-- | arch/csky/mm/fault.c | 10 | ||||
-rw-r--r-- | arch/csky/mm/highmem.c | 2 |
19 files changed, 311 insertions, 146 deletions
diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index bd31ab12f77d..3d5afb5f5685 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -9,6 +9,7 @@ config CSKY select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_QUEUED_RWLOCKS if NR_CPUS>2 select ARCH_WANT_FRAME_POINTERS if !CPU_CK610 + select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT select COMMON_CLK select CLKSRC_MMIO select CSKY_MPINTC if CPU_CK860 @@ -38,12 +39,16 @@ config CSKY select GX6605S_TIMER if CPU_CK610 select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_AUDITSYSCALL - select HAVE_COPY_THREAD_TLS + select HAVE_ARCH_MMAP_RND_BITS + select HAVE_ARCH_SECCOMP_FILTER + select HAVE_CONTEXT_TRACKING + select HAVE_VIRT_CPU_ACCOUNTING_GEN select HAVE_DEBUG_BUGVERBOSE select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FTRACE_MCOUNT_RECORD select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO @@ -149,6 +154,14 @@ config L1_CACHE_SHIFT default "5" if (CPU_CK807 || CPU_CK810) default "6" if (CPU_CK860) +config ARCH_MMAP_RND_BITS_MIN + default 8 + +# max bits determined by the following formula: +# VA_BITS - PAGE_SHIFT - 3 +config ARCH_MMAP_RND_BITS_MAX + default 17 + menu "Processor type and features" choice @@ -267,7 +280,7 @@ config NR_CPUS int "Maximum number of CPUs (2-32)" range 2 32 depends on SMP - default "2" + default "4" config HIGHMEM bool "High Memory Support" @@ -296,3 +309,16 @@ endmenu source "arch/csky/Kconfig.platforms" source "kernel/Kconfig.hz" + +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via prctl(PR_SET_SECCOMP), it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. diff --git a/arch/csky/abiv2/inc/abi/entry.h b/arch/csky/abiv2/inc/abi/entry.h index 4fdd6c12e7ff..bedcc6f06bba 100644 --- a/arch/csky/abiv2/inc/abi/entry.h +++ b/arch/csky/abiv2/inc/abi/entry.h @@ -136,8 +136,6 @@ .macro RESTORE_REGS_FTRACE ldw tls, (sp, 0) - ldw a0, (sp, 16) - mtcr a0, ss0 #ifdef CONFIG_CPU_HAS_HILO ldw a0, (sp, 140) @@ -158,7 +156,6 @@ addi sp, 40 ldm r16-r30, (sp) addi sp, 72 - mfcr sp, ss0 .endm .macro SAVE_SWITCH_STACK diff --git a/arch/csky/abiv2/mcount.S b/arch/csky/abiv2/mcount.S index 911512bf480f..d745e10c10b0 100644 --- a/arch/csky/abiv2/mcount.S +++ b/arch/csky/abiv2/mcount.S @@ -55,7 +55,9 @@ .macro mcount_exit_regs RESTORE_REGS_FTRACE - ldw t1, (sp, 0) + subi sp, 152 + ldw t1, (sp, 4) + addi sp, 152 ldw r8, (sp, 4) ldw lr, (sp, 8) addi sp, 12 diff --git a/arch/csky/include/asm/Kbuild b/arch/csky/include/asm/Kbuild index 93372255984d..64876e59e2ef 100644 --- a/arch/csky/include/asm/Kbuild +++ b/arch/csky/include/asm/Kbuild @@ -4,5 +4,6 @@ generic-y += gpio.h generic-y += kvm_para.h generic-y += local64.h generic-y += qrwlock.h +generic-y += seccomp.h generic-y += user.h generic-y += vmlinux.lds.h diff --git a/arch/csky/include/asm/bug.h b/arch/csky/include/asm/bug.h index bd7b3235bb84..33ebd16b9c78 100644 --- a/arch/csky/include/asm/bug.h +++ b/arch/csky/include/asm/bug.h @@ -20,7 +20,8 @@ do { \ struct pt_regs; -void die_if_kernel(char *str, struct pt_regs *regs, int nr); +void die(struct pt_regs *regs, const char *str); void show_regs(struct pt_regs *regs); +void show_code(struct pt_regs *regs); #endif /* __ASM_CSKY_BUG_H */ diff --git a/arch/csky/include/asm/irq_work.h b/arch/csky/include/asm/irq_work.h new file mode 100644 index 000000000000..33aaf39d6f94 --- /dev/null +++ b/arch/csky/include/asm/irq_work.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_CSKY_IRQ_WORK_H +#define __ASM_CSKY_IRQ_WORK_H + +static inline bool arch_irq_work_has_interrupt(void) +{ + return true; +} +extern void arch_irq_work_raise(void); +#endif /* __ASM_CSKY_IRQ_WORK_H */ diff --git a/arch/csky/include/asm/processor.h b/arch/csky/include/asm/processor.h index 24442d8e86f9..4800f6563abb 100644 --- a/arch/csky/include/asm/processor.h +++ b/arch/csky/include/asm/processor.h @@ -82,12 +82,6 @@ static inline void release_thread(struct task_struct *dead_task) extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) -#define forget_segments() do { } while (0) - -extern unsigned long thread_saved_pc(struct task_struct *tsk); - unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) diff --git a/arch/csky/include/asm/ptrace.h b/arch/csky/include/asm/ptrace.h index bcfb7070e48d..91ceb1b454c9 100644 --- a/arch/csky/include/asm/ptrace.h +++ b/arch/csky/include/asm/ptrace.h @@ -24,6 +24,7 @@ #define user_mode(regs) (!((regs)->sr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) +#define trap_no(regs) ((regs->sr >> 16) & 0xff) static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long val) @@ -52,6 +53,12 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->a0; } +static inline void regs_set_return_value(struct pt_regs *regs, + unsigned long val) +{ + regs->a0 = val; +} + /* Valid only for Kernel mode traps. */ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) { diff --git a/arch/csky/include/asm/thread_info.h b/arch/csky/include/asm/thread_info.h index 8980e4e64391..68e7a1227170 100644 --- a/arch/csky/include/asm/thread_info.h +++ b/arch/csky/include/asm/thread_info.h @@ -85,6 +85,6 @@ static inline struct thread_info *current_thread_info(void) _TIF_NOTIFY_RESUME | _TIF_UPROBE) #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ - _TIF_SYSCALL_TRACEPOINT) + _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP) #endif /* _ASM_CSKY_THREAD_INFO_H */ diff --git a/arch/csky/kernel/entry.S b/arch/csky/kernel/entry.S index f13800383a19..5a5cabd076e1 100644 --- a/arch/csky/kernel/entry.S +++ b/arch/csky/kernel/entry.S @@ -23,6 +23,24 @@ #endif .endm +.macro context_tracking +#ifdef CONFIG_CONTEXT_TRACKING + mfcr a0, epsr + btsti a0, 31 + bt 1f + jbsr context_tracking_user_exit + ldw a0, (sp, LSAVE_A0) + ldw a1, (sp, LSAVE_A1) + ldw a2, (sp, LSAVE_A2) + ldw a3, (sp, LSAVE_A3) +#if defined(__CSKYABIV1__) + ldw r6, (sp, LSAVE_A4) + ldw r7, (sp, LSAVE_A5) +#endif +1: +#endif +.endm + .macro tlbop_begin name, val0, val1, val2 ENTRY(csky_\name) mtcr a3, ss2 @@ -103,6 +121,7 @@ ENTRY(csky_\name) .endm .macro tlbop_end is_write zero_fp + context_tracking RD_MEH a2 psrset ee, ie mov a0, sp @@ -128,6 +147,7 @@ tlbop_end 1 ENTRY(csky_systemcall) SAVE_ALL TRAP0_SIZE zero_fp + context_tracking psrset ee, ie lrw r9, __NR_syscalls @@ -168,6 +188,8 @@ ENTRY(csky_systemcall) csky_syscall_trace: mov a0, sp /* sp = pt_regs pointer */ jbsr syscall_trace_enter + cmpnei a0, 0 + bt 1f /* Prepare args before do system call */ ldw a0, (sp, LSAVE_A0) ldw a1, (sp, LSAVE_A1) @@ -188,6 +210,7 @@ csky_syscall_trace: #endif stw a0, (sp, LSAVE_A0) /* Save return value */ +1: #ifdef CONFIG_DEBUG_RSEQ mov a0, sp jbsr rseq_syscall @@ -234,6 +257,9 @@ ret_from_exception: and r10, r9 cmpnei r10, 0 bt exit_work +#ifdef CONFIG_CONTEXT_TRACKING + jbsr context_tracking_user_enter +#endif 1: #ifdef CONFIG_PREEMPTION mov r9, sp @@ -274,6 +300,7 @@ work_resched: ENTRY(csky_trap) SAVE_ALL 0 zero_fp + context_tracking psrset ee mov a0, sp /* Push Stack pointer arg */ jbsr trap_c /* Call C-level trap handler */ @@ -308,6 +335,7 @@ ENTRY(csky_get_tls) ENTRY(csky_irq) SAVE_ALL 0 zero_fp + context_tracking psrset ee #ifdef CONFIG_TRACE_IRQFLAGS diff --git a/arch/csky/kernel/ftrace.c b/arch/csky/kernel/ftrace.c index 3c425b84e3be..b4a7ec1517ff 100644 --- a/arch/csky/kernel/ftrace.c +++ b/arch/csky/kernel/ftrace.c @@ -72,7 +72,8 @@ static int ftrace_check_current_nop(unsigned long hook) uint16_t olds[7]; unsigned long hook_pos = hook - 2; - if (probe_kernel_read((void *)olds, (void *)hook_pos, sizeof(nops))) + if (copy_from_kernel_nofault((void *)olds, (void *)hook_pos, + sizeof(nops))) return -EFAULT; if (memcmp((void *)nops, (void *)olds, sizeof(nops))) { @@ -97,7 +98,7 @@ static int ftrace_modify_code(unsigned long hook, unsigned long target, make_jbsr(target, hook, call, nolr); - ret = probe_kernel_write((void *)hook_pos, enable ? call : nops, + ret = copy_to_kernel_nofault((void *)hook_pos, enable ? call : nops, sizeof(nops)); if (ret) return -EPERM; diff --git a/arch/csky/kernel/process.c b/arch/csky/kernel/process.c index 8b3fad062ab2..f730869e21ee 100644 --- a/arch/csky/kernel/process.c +++ b/arch/csky/kernel/process.c @@ -30,17 +30,7 @@ asmlinkage void ret_from_kernel_thread(void); */ void flush_thread(void){} -/* - * Return saved PC from a blocked thread - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.sp; - - return sw->r15; -} - -int copy_thread_tls(unsigned long clone_flags, +int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long kthread_arg, struct task_struct *p, diff --git a/arch/csky/kernel/ptrace.c b/arch/csky/kernel/ptrace.c index 6d93db817429..d822144906ac 100644 --- a/arch/csky/kernel/ptrace.c +++ b/arch/csky/kernel/ptrace.c @@ -316,16 +316,20 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } -asmlinkage void syscall_trace_enter(struct pt_regs *regs) +asmlinkage int syscall_trace_enter(struct pt_regs *regs) { if (test_thread_flag(TIF_SYSCALL_TRACE)) if (tracehook_report_syscall_entry(regs)) - syscall_set_nr(current, regs, -1); + return -1; + + if (secure_computing() == -1) + return -1; if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, syscall_get_nr(current, regs)); audit_syscall_entry(regs_syscallid(regs), regs->a0, regs->a1, regs->a2, regs->a3); + return 0; } asmlinkage void syscall_trace_exit(struct pt_regs *regs) @@ -339,13 +343,8 @@ asmlinkage void syscall_trace_exit(struct pt_regs *regs) trace_sys_exit(regs, syscall_get_return_value(current, regs)); } -extern void show_stack(struct task_struct *task, unsigned long *stack, const char *loglvl); void show_regs(struct pt_regs *fp) { - unsigned long *sp; - unsigned char *tp; - int i; - pr_info("\nCURRENT PROCESS:\n\n"); pr_info("COMM=%s PID=%d\n", current->comm, current->pid); @@ -392,29 +391,9 @@ void show_regs(struct pt_regs *fp) fp->regs[0], fp->regs[1], fp->regs[2], fp->regs[3]); pr_info("r10: 0x%08lx r11: 0x%08lx r12: 0x%08lx r13: 0x%08lx\n", fp->regs[4], fp->regs[5], fp->regs[6], fp->regs[7]); - pr_info("r14: 0x%08lx r1: 0x%08lx r15: 0x%08lx\n", - fp->regs[8], fp->regs[9], fp->lr); + pr_info("r14: 0x%08lx r1: 0x%08lx\n", + fp->regs[8], fp->regs[9]); #endif - pr_info("\nCODE:"); - tp = ((unsigned char *) fp->pc) - 0x20; - tp += ((int)tp % 4) ? 2 : 0; - for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { - if ((i % 0x10) == 0) - pr_cont("\n%08x: ", (int) (tp + i)); - pr_cont("%08x ", (int) *sp++); - } - pr_cont("\n"); - - pr_info("\nKERNEL STACK:"); - tp = ((unsigned char *) fp) - 0x40; - for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { - if ((i % 0x10) == 0) - pr_cont("\n%08x: ", (int) (tp + i)); - pr_cont("%08x ", (int) *sp++); - } - pr_cont("\n"); - - show_stack(NULL, (unsigned long *)fp->regs[4], KERN_INFO); return; } diff --git a/arch/csky/kernel/smp.c b/arch/csky/kernel/smp.c index b5c5bc3afeb5..e7425e6b0419 100644 --- a/arch/csky/kernel/smp.c +++ b/arch/csky/kernel/smp.c @@ -12,8 +12,10 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/irq.h> +#include <linux/irq_work.h> #include <linux/irqdomain.h> #include <linux/of.h> +#include <linux/seq_file.h> #include <linux/sched/task_stack.h> #include <linux/sched/mm.h> #include <linux/sched/hotplug.h> @@ -26,20 +28,24 @@ #include <abi/fpu.h> #endif -struct ipi_data_struct { - unsigned long bits ____cacheline_aligned; -}; -static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data); - enum ipi_message_type { IPI_EMPTY, IPI_RESCHEDULE, IPI_CALL_FUNC, + IPI_IRQ_WORK, IPI_MAX }; +struct ipi_data_struct { + unsigned long bits ____cacheline_aligned; + unsigned long stats[IPI_MAX] ____cacheline_aligned; +}; +static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data); + static irqreturn_t handle_ipi(int irq, void *dev) { + unsigned long *stats = this_cpu_ptr(&ipi_data)->stats; + while (true) { unsigned long ops; @@ -47,11 +53,20 @@ static irqreturn_t handle_ipi(int irq, void *dev) if (ops == 0) return IRQ_HANDLED; - if (ops & (1 << IPI_RESCHEDULE)) + if (ops & (1 << IPI_RESCHEDULE)) { + stats[IPI_RESCHEDULE]++; scheduler_ipi(); + } - if (ops & (1 << IPI_CALL_FUNC)) + if (ops & (1 << IPI_CALL_FUNC)) { + stats[IPI_CALL_FUNC]++; generic_smp_call_function_interrupt(); + } + + if (ops & (1 << IPI_IRQ_WORK)) { + stats[IPI_IRQ_WORK]++; + irq_work_run(); + } BUG_ON((ops >> IPI_MAX) != 0); } @@ -83,6 +98,29 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) send_arch_ipi(to_whom); } +static const char * const ipi_names[] = { + [IPI_EMPTY] = "Empty interrupts", + [IPI_RESCHEDULE] = "Rescheduling interrupts", + [IPI_CALL_FUNC] = "Function call interrupts", + [IPI_IRQ_WORK] = "Irq work interrupts", +}; + +int arch_show_interrupts(struct seq_file *p, int prec) +{ + unsigned int cpu, i; + + for (i = 0; i < IPI_MAX; i++) { + seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, + prec >= 4 ? " " : ""); + for_each_online_cpu(cpu) + seq_printf(p, "%10lu ", + per_cpu_ptr(&ipi_data, cpu)->stats[i]); + seq_printf(p, " %s\n", ipi_names[i]); + } + + return 0; +} + void arch_send_call_function_ipi_mask(struct cpumask *mask) { send_ipi_message(mask, IPI_CALL_FUNC); @@ -108,6 +146,13 @@ void smp_send_reschedule(int cpu) send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } +#ifdef CONFIG_IRQ_WORK +void arch_irq_work_raise(void) +{ + send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); +} +#endif + void __init smp_prepare_boot_cpu(void) { } @@ -156,6 +201,7 @@ void __init setup_smp(void) extern void _start_smp_secondary(void); volatile unsigned int secondary_hint; +volatile unsigned int secondary_hint2; volatile unsigned int secondary_ccr; volatile unsigned int secondary_stack; @@ -168,6 +214,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) secondary_stack = (unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8; secondary_hint = mfcr("cr31"); + secondary_hint2 = mfcr("cr<21, 1>"); secondary_ccr = mfcr("cr18"); secondary_msa1 = read_mmu_msa1(); @@ -209,6 +256,7 @@ void csky_start_secondary(void) unsigned int cpu = smp_processor_id(); mtcr("cr31", secondary_hint); + mtcr("cr<21, 1>", secondary_hint2); mtcr("cr18", secondary_ccr); mtcr("vbr", vec_base); diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c index fcc3a69831ad..959a917c989d 100644 --- a/arch/csky/kernel/traps.c +++ b/arch/csky/kernel/traps.c @@ -15,6 +15,8 @@ #include <linux/rtc.h> #include <linux/uaccess.h> #include <linux/kprobes.h> +#include <linux/kdebug.h> +#include <linux/sched/debug.h> #include <asm/setup.h> #include <asm/traps.h> @@ -27,6 +29,8 @@ #include <abi/fpu.h> #endif +int show_unhandled_signals = 1; + /* Defined in entry.S */ asmlinkage void csky_trap(void); @@ -77,117 +81,184 @@ void __init trap_init(void) #endif } -void die_if_kernel(char *str, struct pt_regs *regs, int nr) +static DEFINE_SPINLOCK(die_lock); + +void die(struct pt_regs *regs, const char *str) { - if (user_mode(regs)) - return; + static int die_counter; + int ret; + oops_enter(); + + spin_lock_irq(&die_lock); console_verbose(); - pr_err("%s: %08x\n", str, nr); + bust_spinlocks(1); + + pr_emerg("%s [#%d]\n", str, ++die_counter); + print_modules(); show_regs(regs); + show_stack(current, (unsigned long *)regs->regs[4], KERN_INFO); + + ret = notify_die(DIE_OOPS, str, regs, 0, trap_no(regs), SIGSEGV); + + bust_spinlocks(0); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); - do_exit(SIGSEGV); + spin_unlock_irq(&die_lock); + oops_exit(); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + if (panic_on_oops) + panic("Fatal exception"); + if (ret != NOTIFY_STOP) + do_exit(SIGSEGV); } -void buserr(struct pt_regs *regs) +void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) { -#ifdef CONFIG_CPU_CK810 - static unsigned long prev_pc; + struct task_struct *tsk = current; - if ((regs->pc == prev_pc) && prev_pc != 0) { - prev_pc = 0; - } else { - prev_pc = regs->pc; - return; + if (show_unhandled_signals && unhandled_signal(tsk, signo) + && printk_ratelimit()) { + pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx", + tsk->comm, task_pid_nr(tsk), signo, code, addr); + print_vma_addr(KERN_CONT " in ", instruction_pointer(regs)); + pr_cont("\n"); + show_regs(regs); } -#endif - die_if_kernel("Kernel mode BUS error", regs, 0); + force_sig_fault(signo, code, (void __user *)addr); +} - pr_err("User mode Bus Error\n"); - show_regs(regs); +static void do_trap_error(struct pt_regs *regs, int signo, int code, + unsigned long addr, const char *str) +{ + current->thread.trap_no = trap_no(regs); - force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc); + if (user_mode(regs)) { + do_trap(regs, signo, code, addr); + } else { + if (!fixup_exception(regs)) + die(regs, str); + } } -asmlinkage void trap_c(struct pt_regs *regs) -{ - int sig; - unsigned long vector; - siginfo_t info; - struct task_struct *tsk = current; +#define DO_ERROR_INFO(name, signo, code, str) \ +asmlinkage __visible void name(struct pt_regs *regs) \ +{ \ + do_trap_error(regs, signo, code, regs->pc, "Oops - " str); \ +} - vector = (regs->sr >> 16) & 0xff; +DO_ERROR_INFO(do_trap_unknown, + SIGILL, ILL_ILLTRP, "unknown exception"); +DO_ERROR_INFO(do_trap_zdiv, + SIGFPE, FPE_INTDIV, "error zero div exception"); +DO_ERROR_INFO(do_trap_buserr, + SIGSEGV, ILL_ILLADR, "error bus error exception"); - switch (vector) { - case VEC_ZERODIV: - die_if_kernel("Kernel mode ZERO DIV", regs, vector); - sig = SIGFPE; - break; - /* ptrace */ - case VEC_TRACE: +asmlinkage void do_trap_misaligned(struct pt_regs *regs) +{ +#ifdef CONFIG_CPU_NEED_SOFTALIGN + csky_alignment(regs); +#else + current->thread.trap_no = trap_no(regs); + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->pc, + "Oops - load/store address misaligned"); +#endif +} + +asmlinkage void do_trap_bkpt(struct pt_regs *regs) +{ #ifdef CONFIG_KPROBES - if (kprobe_single_step_handler(regs)) - return; + if (kprobe_single_step_handler(regs)) + return; #endif #ifdef CONFIG_UPROBES - if (uprobe_single_step_handler(regs)) - return; + if (uprobe_single_step_handler(regs)) + return; #endif - info.si_code = TRAP_TRACE; - sig = SIGTRAP; - break; - case VEC_ILLEGAL: - tsk->thread.trap_no = vector; + if (user_mode(regs)) { + send_sig(SIGTRAP, current, 0); + return; + } + + do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->pc, + "Oops - illegal trap exception"); +} + +asmlinkage void do_trap_illinsn(struct pt_regs *regs) +{ + current->thread.trap_no = trap_no(regs); + #ifdef CONFIG_KPROBES - if (kprobe_breakpoint_handler(regs)) - return; + if (kprobe_breakpoint_handler(regs)) + return; #endif #ifdef CONFIG_UPROBES - if (uprobe_breakpoint_handler(regs)) - return; + if (uprobe_breakpoint_handler(regs)) + return; #endif - die_if_kernel("Kernel mode ILLEGAL", regs, vector); #ifndef CONFIG_CPU_NO_USER_BKPT - if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) + if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) { + send_sig(SIGTRAP, current, 0); + return; + } #endif - { - sig = SIGILL; - break; - } - /* gdbserver breakpoint */ + + do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, + "Oops - illegal instruction exception"); +} + +asmlinkage void do_trap_fpe(struct pt_regs *regs) +{ +#ifdef CONFIG_CPU_HAS_FP + return fpu_fpe(regs); +#else + do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, + "Oops - fpu instruction exception"); +#endif +} + +asmlinkage void do_trap_priv(struct pt_regs *regs) +{ +#ifdef CONFIG_CPU_HAS_FP + if (user_mode(regs) && fpu_libc_helper(regs)) + return; +#endif + do_trap_error(regs, SIGILL, ILL_PRVOPC, regs->pc, + "Oops - illegal privileged exception"); +} + +asmlinkage void trap_c(struct pt_regs *regs) +{ + switch (trap_no(regs)) { + case VEC_ZERODIV: + do_trap_zdiv(regs); + break; + case VEC_TRACE: + do_trap_bkpt(regs); + break; + case VEC_ILLEGAL: + do_trap_illinsn(regs); + break; case VEC_TRAP1: - /* jtagserver breakpoint */ case VEC_BREAKPOINT: - die_if_kernel("Kernel mode BKPT", regs, vector); - info.si_code = TRAP_BRKPT; - sig = SIGTRAP; + do_trap_bkpt(regs); break; case VEC_ACCESS: - tsk->thread.trap_no = vector; - return buserr(regs); -#ifdef CONFIG_CPU_NEED_SOFTALIGN + do_trap_buserr(regs); + break; case VEC_ALIGN: - tsk->thread.trap_no = vector; - return csky_alignment(regs); -#endif -#ifdef CONFIG_CPU_HAS_FPU + do_trap_misaligned(regs); + break; case VEC_FPE: - tsk->thread.trap_no = vector; - die_if_kernel("Kernel mode FPE", regs, vector); - return fpu_fpe(regs); + do_trap_fpe(regs); + break; case VEC_PRIV: - tsk->thread.trap_no = vector; - die_if_kernel("Kernel mode PRIV", regs, vector); - if (fpu_libc_helper(regs)) - return; -#endif + do_trap_priv(regs); + break; default: - sig = SIGSEGV; + do_trap_unknown(regs); break; } - - tsk->thread.trap_no = vector; - - send_sig(sig, current, 0); } diff --git a/arch/csky/lib/Makefile b/arch/csky/lib/Makefile index 078e2d5f32e1..7fbdbb2c4d12 100644 --- a/arch/csky/lib/Makefile +++ b/arch/csky/lib/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only lib-y := usercopy.o delay.o +obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/csky/lib/error-inject.c b/arch/csky/lib/error-inject.c new file mode 100644 index 000000000000..c15fb36fe067 --- /dev/null +++ b/arch/csky/lib/error-inject.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/error-injection.h> +#include <linux/kprobes.h> + +void override_function_with_return(struct pt_regs *regs) +{ + instruction_pointer_set(regs, regs->lr); +} +NOKPROBE_SYMBOL(override_function_with_return); diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c index 0b9cbf2cf6a9..b1dce9f2f04d 100644 --- a/arch/csky/mm/fault.c +++ b/arch/csky/mm/fault.c @@ -183,13 +183,13 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { - tsk->thread.trap_no = (regs->sr >> 16) & 0xff; + tsk->thread.trap_no = trap_no(regs); force_sig_fault(SIGSEGV, si_code, (void __user *)address); return; } no_context: - tsk->thread.trap_no = (regs->sr >> 16) & 0xff; + tsk->thread.trap_no = trap_no(regs); /* Are we prepared to handle this kernel fault? */ if (fixup_exception(regs)) @@ -202,10 +202,10 @@ no_context: bust_spinlocks(1); pr_alert("Unable to handle kernel paging request at virtual " "address 0x%08lx, pc: 0x%08lx\n", address, regs->pc); - die_if_kernel("Oops", regs, write); + die(regs, "Oops"); out_of_memory: - tsk->thread.trap_no = (regs->sr >> 16) & 0xff; + tsk->thread.trap_no = trap_no(regs); /* * We ran out of memory, call the OOM killer, and return the userspace @@ -215,7 +215,7 @@ out_of_memory: return; do_sigbus: - tsk->thread.trap_no = (regs->sr >> 16) & 0xff; + tsk->thread.trap_no = trap_no(regs); mmap_read_unlock(mm); diff --git a/arch/csky/mm/highmem.c b/arch/csky/mm/highmem.c index 89ec32e602a1..89c10800a002 100644 --- a/arch/csky/mm/highmem.c +++ b/arch/csky/mm/highmem.c @@ -19,8 +19,6 @@ void kmap_flush_tlb(unsigned long addr) } EXPORT_SYMBOL(kmap_flush_tlb); -EXPORT_SYMBOL(kmap); - void *kmap_atomic_high_prot(struct page *page, pgprot_t prot) { unsigned long vaddr; |