Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'csky-for-linus-5.7-rc1' of git://github.com/c-sky/csky-linux

Pull csky updates from Guo Ren:

- Add kproobes/uprobes support

- Add lockdep, rseq, gcov support

- Fixup init_fpu

- Fixup ftrace_modify deadlock

- Fixup speculative execution on IO area

* tag 'csky-for-linus-5.7-rc1' of git://github.com/c-sky/csky-linux:
csky: Fixup cpu speculative execution to IO area
csky: Add uprobes support
csky: Add kprobes supported
csky: Enable LOCKDEP_SUPPORT
csky: Enable the gcov function
csky: Fixup get wrong psr value from phyical reg
csky/ftrace: Fixup ftrace_modify_code deadlock without CPU_HAS_ICACHE_INS
csky: Implement ftrace with regs
csky: Add support for restartable sequence
csky: Implement ptrace regs and stack API
csky: Fixup init_fpu compile warning with __init

+1807 -74
+13
arch/csky/Kconfig
··· 3 3 def_bool y 4 4 select ARCH_32BIT_OFF_T 5 5 select ARCH_HAS_DMA_PREP_COHERENT 6 + select ARCH_HAS_GCOV_PROFILE_ALL 6 7 select ARCH_HAS_SYNC_DMA_FOR_CPU 7 8 select ARCH_HAS_SYNC_DMA_FOR_DEVICE 8 9 select ARCH_USE_BUILTIN_BSWAP ··· 39 38 select HAVE_ARCH_AUDITSYSCALL 40 39 select HAVE_COPY_THREAD_TLS 41 40 select HAVE_DYNAMIC_FTRACE 41 + select HAVE_DYNAMIC_FTRACE_WITH_REGS 42 42 select HAVE_FUNCTION_TRACER 43 43 select HAVE_FUNCTION_GRAPH_TRACER 44 44 select HAVE_FTRACE_MCOUNT_RECORD 45 45 select HAVE_KERNEL_GZIP 46 46 select HAVE_KERNEL_LZO 47 47 select HAVE_KERNEL_LZMA 48 + select HAVE_KPROBES if !CPU_CK610 49 + select HAVE_KPROBES_ON_FTRACE if !CPU_CK610 50 + select HAVE_KRETPROBES if !CPU_CK610 48 51 select HAVE_PERF_EVENTS 49 52 select HAVE_PERF_REGS 50 53 select HAVE_PERF_USER_STACK_DUMP 51 54 select HAVE_DMA_CONTIGUOUS 55 + select HAVE_REGS_AND_STACK_ACCESS_API 56 + select HAVE_RSEQ 52 57 select HAVE_STACKPROTECTOR 53 58 select HAVE_SYSCALL_TRACEPOINTS 54 59 select MAY_HAVE_SPARSE_IRQ ··· 71 64 select PCI_DOMAINS_GENERIC if PCI 72 65 select PCI_SYSCALL if PCI 73 66 select PCI_MSI if PCI 67 + 68 + config LOCKDEP_SUPPORT 69 + def_bool y 70 + 71 + config ARCH_SUPPORTS_UPROBES 72 + def_bool y if !CPU_CK610 74 73 75 74 config CPU_HAS_CACHEV2 76 75 bool
+1 -4
arch/csky/abiv1/inc/abi/entry.h
··· 172 172 addi r6, 0xe 173 173 cpwcr r6, cpcr30 174 174 175 - lsri r6, 28 176 - addi r6, 2 177 - lsli r6, 28 178 - addi r6, 0xe 175 + movi r6, 0 179 176 cpwcr r6, cpcr31 180 177 .endm 181 178
-5
arch/csky/abiv2/fpu.c
··· 10 10 #define MTCR_DIST 0xC0006420 11 11 #define MFCR_DIST 0xC0006020 12 12 13 - void __init init_fpu(void) 14 - { 15 - mtcr("cr<1, 2>", 0); 16 - } 17 - 18 13 /* 19 14 * fpu_libc_helper() is to help libc to excute: 20 15 * - mfcr %a, cr<1, 2>
+62 -5
arch/csky/abiv2/inc/abi/entry.h
··· 100 100 rte 101 101 .endm 102 102 103 + .macro SAVE_REGS_FTRACE 104 + subi sp, 152 105 + stw tls, (sp, 0) 106 + stw lr, (sp, 4) 107 + 108 + mfcr lr, psr 109 + stw lr, (sp, 12) 110 + 111 + addi lr, sp, 152 112 + stw lr, (sp, 16) 113 + 114 + stw a0, (sp, 20) 115 + stw a0, (sp, 24) 116 + stw a1, (sp, 28) 117 + stw a2, (sp, 32) 118 + stw a3, (sp, 36) 119 + 120 + addi sp, 40 121 + stm r4-r13, (sp) 122 + 123 + addi sp, 40 124 + stm r16-r30, (sp) 125 + #ifdef CONFIG_CPU_HAS_HILO 126 + mfhi lr 127 + stw lr, (sp, 60) 128 + mflo lr 129 + stw lr, (sp, 64) 130 + mfcr lr, cr14 131 + stw lr, (sp, 68) 132 + #endif 133 + subi sp, 80 134 + .endm 135 + 136 + .macro RESTORE_REGS_FTRACE 137 + ldw tls, (sp, 0) 138 + ldw a0, (sp, 16) 139 + mtcr a0, ss0 140 + 141 + #ifdef CONFIG_CPU_HAS_HILO 142 + ldw a0, (sp, 140) 143 + mthi a0 144 + ldw a0, (sp, 144) 145 + mtlo a0 146 + ldw a0, (sp, 148) 147 + mtcr a0, cr14 148 + #endif 149 + 150 + ldw a0, (sp, 24) 151 + ldw a1, (sp, 28) 152 + ldw a2, (sp, 32) 153 + ldw a3, (sp, 36) 154 + 155 + addi sp, 40 156 + ldm r4-r13, (sp) 157 + addi sp, 40 158 + ldm r16-r30, (sp) 159 + addi sp, 72 160 + mfcr sp, ss0 161 + .endm 162 + 103 163 .macro SAVE_SWITCH_STACK 104 164 subi sp, 64 105 165 stm r4-r11, (sp) ··· 290 230 addi r6, 0x1ce 291 231 mtcr r6, cr<30, 15> /* Set MSA0 */ 292 232 293 - lsri r6, 28 294 - addi r6, 2 295 - lsli r6, 28 296 - addi r6, 0x1ce 297 - mtcr r6, cr<31, 15> /* Set MSA1 */ 233 + movi r6, 0 234 + mtcr r6, cr<31, 15> /* Clr MSA1 */ 298 235 299 236 /* enable MMU */ 300 237 mfcr r6, cr18
+2 -1
arch/csky/abiv2/inc/abi/fpu.h
··· 9 9 10 10 int fpu_libc_helper(struct pt_regs *regs); 11 11 void fpu_fpe(struct pt_regs *regs); 12 - void __init init_fpu(void); 12 + 13 + static inline void init_fpu(void) { mtcr("cr<1, 2>", 0); } 13 14 14 15 void save_to_user_fp(struct user_fp *user_fp); 15 16 void restore_from_user_fp(struct user_fp *user_fp);
+48
arch/csky/abiv2/mcount.S
··· 3 3 4 4 #include <linux/linkage.h> 5 5 #include <asm/ftrace.h> 6 + #include <abi/entry.h> 7 + #include <asm/asm-offsets.h> 6 8 7 9 /* 8 10 * csky-gcc with -pg will put the following asm after prologue: ··· 43 41 ldw r8, (sp, 20) 44 42 ldw lr, (sp, 24) 45 43 addi sp, 28 44 + jmp t1 45 + .endm 46 + 47 + .macro mcount_enter_regs 48 + subi sp, 8 49 + stw lr, (sp, 0) 50 + stw r8, (sp, 4) 51 + SAVE_REGS_FTRACE 52 + .endm 53 + 54 + .macro mcount_exit_regs 55 + RESTORE_REGS_FTRACE 56 + ldw t1, (sp, 0) 57 + ldw r8, (sp, 4) 58 + ldw lr, (sp, 8) 59 + addi sp, 12 46 60 jmp t1 47 61 .endm 48 62 ··· 140 122 ldw a0, (sp, 16) 141 123 subi a0, 4 142 124 ldw a1, (sp, 24) 125 + lrw a2, function_trace_op 126 + ldw a2, (a2, 0) 143 127 144 128 nop 145 129 GLOBAL(ftrace_call) ··· 177 157 jmp lr 178 158 END(return_to_handler) 179 159 #endif 160 + 161 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 162 + ENTRY(ftrace_regs_caller) 163 + mcount_enter_regs 164 + 165 + lrw t1, PT_FRAME_SIZE 166 + add t1, sp 167 + 168 + ldw a0, (t1, 0) 169 + subi a0, 4 170 + ldw a1, (t1, 8) 171 + lrw a2, function_trace_op 172 + ldw a2, (a2, 0) 173 + mov a3, sp 174 + 175 + nop 176 + GLOBAL(ftrace_regs_call) 177 + nop32_stub 178 + 179 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 180 + nop 181 + GLOBAL(ftrace_graph_regs_call) 182 + nop32_stub 183 + #endif 184 + 185 + mcount_exit_regs 186 + ENDPROC(ftrace_regs_caller) 187 + #endif /* CONFIG_DYNAMIC_FTRACE */
+2
arch/csky/include/asm/ftrace.h
··· 10 10 11 11 #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR 12 12 13 + #define ARCH_SUPPORTS_FTRACE_OPS 1 14 + 13 15 #define MCOUNT_ADDR ((unsigned long)_mcount) 14 16 15 17 #ifndef __ASSEMBLY__
+48
arch/csky/include/asm/kprobes.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef __ASM_CSKY_KPROBES_H 4 + #define __ASM_CSKY_KPROBES_H 5 + 6 + #include <asm-generic/kprobes.h> 7 + 8 + #ifdef CONFIG_KPROBES 9 + #include <linux/types.h> 10 + #include <linux/ptrace.h> 11 + #include <linux/percpu.h> 12 + 13 + #define __ARCH_WANT_KPROBES_INSN_SLOT 14 + #define MAX_INSN_SIZE 1 15 + 16 + #define flush_insn_slot(p) do { } while (0) 17 + #define kretprobe_blacklist_size 0 18 + 19 + #include <asm/probes.h> 20 + 21 + struct prev_kprobe { 22 + struct kprobe *kp; 23 + unsigned int status; 24 + }; 25 + 26 + /* Single step context for kprobe */ 27 + struct kprobe_step_ctx { 28 + unsigned long ss_pending; 29 + unsigned long match_addr; 30 + }; 31 + 32 + /* per-cpu kprobe control block */ 33 + struct kprobe_ctlblk { 34 + unsigned int kprobe_status; 35 + unsigned long saved_sr; 36 + struct prev_kprobe prev_kprobe; 37 + struct kprobe_step_ctx ss_ctx; 38 + }; 39 + 40 + void arch_remove_kprobe(struct kprobe *p); 41 + int kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr); 42 + int kprobe_breakpoint_handler(struct pt_regs *regs); 43 + int kprobe_single_step_handler(struct pt_regs *regs); 44 + void kretprobe_trampoline(void); 45 + void __kprobes *trampoline_probe_handler(struct pt_regs *regs); 46 + 47 + #endif /* CONFIG_KPROBES */ 48 + #endif /* __ASM_CSKY_KPROBES_H */
+24
arch/csky/include/asm/probes.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ASM_CSKY_PROBES_H 4 + #define __ASM_CSKY_PROBES_H 5 + 6 + typedef u32 probe_opcode_t; 7 + typedef void (probes_handler_t) (u32 opcode, long addr, struct pt_regs *); 8 + 9 + /* architecture specific copy of original instruction */ 10 + struct arch_probe_insn { 11 + probe_opcode_t *insn; 12 + probes_handler_t *handler; 13 + /* restore address after simulation */ 14 + unsigned long restore; 15 + }; 16 + 17 + #ifdef CONFIG_KPROBES 18 + typedef u32 kprobe_opcode_t; 19 + struct arch_specific_insn { 20 + struct arch_probe_insn api; 21 + }; 22 + #endif 23 + 24 + #endif /* __ASM_CSKY_PROBES_H */
+1
arch/csky/include/asm/processor.h
··· 43 43 struct thread_struct { 44 44 unsigned long ksp; /* kernel stack pointer */ 45 45 unsigned long sr; /* saved status register */ 46 + unsigned long trap_no; /* saved status register */ 46 47 47 48 /* FPU regs */ 48 49 struct user_fp __aligned(16) user_fp;
+43
arch/csky/include/asm/ptrace.h
··· 7 7 #include <uapi/asm/ptrace.h> 8 8 #include <asm/traps.h> 9 9 #include <linux/types.h> 10 + #include <linux/compiler.h> 10 11 11 12 #ifndef __ASSEMBLY__ 12 13 13 14 #define PS_S 0x80000000 /* Supervisor Mode */ 15 + 16 + #define USR_BKPT 0x1464 14 17 15 18 #define arch_has_single_step() (1) 16 19 #define current_pt_regs() \ ··· 24 21 #define user_mode(regs) (!((regs)->sr & PS_S)) 25 22 #define instruction_pointer(regs) ((regs)->pc) 26 23 #define profile_pc(regs) instruction_pointer(regs) 24 + 25 + static inline void instruction_pointer_set(struct pt_regs *regs, 26 + unsigned long val) 27 + { 28 + regs->pc = val; 29 + } 30 + 31 + #if defined(__CSKYABIV2__) 32 + #define MAX_REG_OFFSET offsetof(struct pt_regs, dcsr) 33 + #else 34 + #define MAX_REG_OFFSET offsetof(struct pt_regs, regs[9]) 35 + #endif 27 36 28 37 static inline bool in_syscall(struct pt_regs const *regs) 29 38 { ··· 50 35 static inline unsigned long regs_return_value(struct pt_regs *regs) 51 36 { 52 37 return regs->a0; 38 + } 39 + 40 + /* Valid only for Kernel mode traps. */ 41 + static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) 42 + { 43 + return regs->usp; 44 + } 45 + 46 + extern int regs_query_register_offset(const char *name); 47 + extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, 48 + unsigned int n); 49 + 50 + /* 51 + * regs_get_register() - get register value from its offset 52 + * @regs: pt_regs from which register value is gotten 53 + * @offset: offset of the register. 54 + * 55 + * regs_get_register returns the value of a register whose offset from @regs. 56 + * The @offset is the offset of the register in struct pt_regs. 57 + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. 58 + */ 59 + static inline unsigned long regs_get_register(struct pt_regs *regs, 60 + unsigned int offset) 61 + { 62 + if (unlikely(offset > MAX_REG_OFFSET)) 63 + return 0; 64 + 65 + return *(unsigned long *)((unsigned long)regs + offset); 53 66 } 54 67 55 68 #endif /* __ASSEMBLY__ */
+2
arch/csky/include/asm/thread_info.h
··· 57 57 #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ 58 58 #define TIF_SYSCALL_TRACEPOINT 4 /* syscall tracepoint instrumentation */ 59 59 #define TIF_SYSCALL_AUDIT 5 /* syscall auditing */ 60 + #define TIF_UPROBE 6 /* uprobe breakpoint or singlestep */ 60 61 #define TIF_POLLING_NRFLAG 16 /* poll_idle() is TIF_NEED_RESCHED */ 61 62 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ 62 63 #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ ··· 69 68 #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 70 69 #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) 71 70 #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) 71 + #define _TIF_UPROBE (1 << TIF_UPROBE) 72 72 #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) 73 73 #define _TIF_MEMDIE (1 << TIF_MEMDIE) 74 74 #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
+33
arch/csky/include/asm/uprobes.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef __ASM_CSKY_UPROBES_H 4 + #define __ASM_CSKY_UPROBES_H 5 + 6 + #include <asm/probes.h> 7 + 8 + #define MAX_UINSN_BYTES 4 9 + 10 + #define UPROBE_SWBP_INSN USR_BKPT 11 + #define UPROBE_SWBP_INSN_SIZE 2 12 + #define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES 13 + 14 + typedef u32 uprobe_opcode_t; 15 + 16 + struct arch_uprobe_task { 17 + unsigned long saved_trap_no; 18 + }; 19 + 20 + struct arch_uprobe { 21 + union { 22 + u8 insn[MAX_UINSN_BYTES]; 23 + u8 ixol[MAX_UINSN_BYTES]; 24 + }; 25 + struct arch_probe_insn api; 26 + unsigned long insn_size; 27 + bool simulate; 28 + }; 29 + 30 + int uprobe_breakpoint_handler(struct pt_regs *regs); 31 + int uprobe_single_step_handler(struct pt_regs *regs); 32 + 33 + #endif /* __ASM_CSKY_UPROBES_H */
+1
arch/csky/kernel/Makefile
··· 4 4 obj-y += entry.o atomic.o signal.o traps.o irq.o time.o vdso.o 5 5 obj-y += power.o syscall.o syscall_table.o setup.o 6 6 obj-y += process.o cpu-probe.o ptrace.o dumpstack.o 7 + obj-y += probes/ 7 8 8 9 obj-$(CONFIG_MODULES) += module.o 9 10 obj-$(CONFIG_SMP) += smp.o
+1
arch/csky/kernel/asm-offsets.c
··· 72 72 DEFINE(PT_RLO, offsetof(struct pt_regs, rlo)); 73 73 #endif 74 74 DEFINE(PT_USP, offsetof(struct pt_regs, usp)); 75 + DEFINE(PT_FRAME_SIZE, sizeof(struct pt_regs)); 75 76 76 77 /* offsets into the irq_cpustat_t struct */ 77 78 DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t,
+16 -2
arch/csky/kernel/entry.S
··· 128 128 ENTRY(csky_systemcall) 129 129 SAVE_ALL TRAP0_SIZE 130 130 zero_fp 131 - 131 + #ifdef CONFIG_RSEQ_DEBUG 132 + mov a0, sp 133 + jbsr rseq_syscall 134 + #endif 132 135 psrset ee, ie 133 136 134 137 lrw r11, __NR_syscalls ··· 221 218 andn r9, r10 222 219 223 220 ldw r12, (r9, TINFO_FLAGS) 224 - andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) 221 + andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | _TIF_UPROBE) 225 222 cmpnei r12, 0 226 223 bt exit_work 227 224 1: 225 + #ifdef CONFIG_TRACE_IRQFLAGS 226 + ld r10, (sp, LSAVE_PSR) 227 + btsti r10, 6 228 + bf 2f 229 + jbsr trace_hardirqs_on 230 + 2: 231 + #endif 228 232 RESTORE_ALL 229 233 230 234 exit_work: ··· 286 276 SAVE_ALL 0 287 277 zero_fp 288 278 psrset ee 279 + 280 + #ifdef CONFIG_TRACE_IRQFLAGS 281 + jbsr trace_hardirqs_off 282 + #endif 289 283 290 284 #ifdef CONFIG_PREEMPTION 291 285 mov r9, sp /* Get current stack pointer */
+42
arch/csky/kernel/ftrace.c
··· 3 3 4 4 #include <linux/ftrace.h> 5 5 #include <linux/uaccess.h> 6 + #include <linux/stop_machine.h> 6 7 #include <asm/cacheflush.h> 7 8 8 9 #ifdef CONFIG_DYNAMIC_FTRACE ··· 127 126 { 128 127 int ret = ftrace_modify_code((unsigned long)&ftrace_call, 129 128 (unsigned long)func, true, true); 129 + if (!ret) 130 + ret = ftrace_modify_code((unsigned long)&ftrace_regs_call, 131 + (unsigned long)func, true, true); 130 132 return ret; 131 133 } 132 134 ··· 138 134 return 0; 139 135 } 140 136 #endif /* CONFIG_DYNAMIC_FTRACE */ 137 + 138 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 139 + int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, 140 + unsigned long addr) 141 + { 142 + return ftrace_modify_code(rec->ip, addr, true, true); 143 + } 144 + #endif 141 145 142 146 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 143 147 void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ··· 201 189 } 202 190 #endif /* CONFIG_DYNAMIC_FTRACE */ 203 191 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 192 + 193 + #ifndef CONFIG_CPU_HAS_ICACHE_INS 194 + struct ftrace_modify_param { 195 + int command; 196 + atomic_t cpu_count; 197 + }; 198 + 199 + static int __ftrace_modify_code(void *data) 200 + { 201 + struct ftrace_modify_param *param = data; 202 + 203 + if (atomic_inc_return(&param->cpu_count) == 1) { 204 + ftrace_modify_all_code(param->command); 205 + atomic_inc(&param->cpu_count); 206 + } else { 207 + while (atomic_read(&param->cpu_count) <= num_online_cpus()) 208 + cpu_relax(); 209 + local_icache_inv_all(NULL); 210 + } 211 + 212 + return 0; 213 + } 214 + 215 + void arch_ftrace_update_code(int command) 216 + { 217 + struct ftrace_modify_param param = { command, ATOMIC_INIT(0) }; 218 + 219 + stop_machine(__ftrace_modify_code, &param, cpu_online_mask); 220 + } 221 + #endif 204 222 205 223 /* _mcount is defined in abi's mcount.S */ 206 224 EXPORT_SYMBOL(_mcount);
+5
arch/csky/kernel/head.S
··· 21 21 ENTRY(_start_smp_secondary) 22 22 SETUP_MMU 23 23 24 + /* copy msa1 from CPU0 */ 25 + lrw r6, secondary_msa1 26 + ld.w r6, (r6, 0) 27 + mtcr r6, cr<31, 15> 28 + 24 29 /* set stack point */ 25 30 lrw r6, secondary_stack 26 31 ld.w r6, (r6, 0)
+7
arch/csky/kernel/probes/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o 3 + obj-$(CONFIG_KPROBES) += kprobes_trampoline.o 4 + obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o 5 + obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o 6 + 7 + CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
+49
arch/csky/kernel/probes/decode-insn.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include <linux/kernel.h> 4 + #include <linux/kprobes.h> 5 + #include <linux/module.h> 6 + #include <linux/kallsyms.h> 7 + #include <asm/sections.h> 8 + 9 + #include "decode-insn.h" 10 + #include "simulate-insn.h" 11 + 12 + /* Return: 13 + * INSN_REJECTED If instruction is one not allowed to kprobe, 14 + * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. 15 + */ 16 + enum probe_insn __kprobes 17 + csky_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api) 18 + { 19 + probe_opcode_t insn = le32_to_cpu(*addr); 20 + 21 + CSKY_INSN_SET_SIMULATE(br16, insn); 22 + CSKY_INSN_SET_SIMULATE(bt16, insn); 23 + CSKY_INSN_SET_SIMULATE(bf16, insn); 24 + CSKY_INSN_SET_SIMULATE(jmp16, insn); 25 + CSKY_INSN_SET_SIMULATE(jsr16, insn); 26 + CSKY_INSN_SET_SIMULATE(lrw16, insn); 27 + CSKY_INSN_SET_SIMULATE(pop16, insn); 28 + 29 + CSKY_INSN_SET_SIMULATE(br32, insn); 30 + CSKY_INSN_SET_SIMULATE(bt32, insn); 31 + CSKY_INSN_SET_SIMULATE(bf32, insn); 32 + CSKY_INSN_SET_SIMULATE(jmp32, insn); 33 + CSKY_INSN_SET_SIMULATE(jsr32, insn); 34 + CSKY_INSN_SET_SIMULATE(lrw32, insn); 35 + CSKY_INSN_SET_SIMULATE(pop32, insn); 36 + 37 + CSKY_INSN_SET_SIMULATE(bez32, insn); 38 + CSKY_INSN_SET_SIMULATE(bnez32, insn); 39 + CSKY_INSN_SET_SIMULATE(bnezad32, insn); 40 + CSKY_INSN_SET_SIMULATE(bhsz32, insn); 41 + CSKY_INSN_SET_SIMULATE(bhz32, insn); 42 + CSKY_INSN_SET_SIMULATE(blsz32, insn); 43 + CSKY_INSN_SET_SIMULATE(blz32, insn); 44 + CSKY_INSN_SET_SIMULATE(bsr32, insn); 45 + CSKY_INSN_SET_SIMULATE(jmpi32, insn); 46 + CSKY_INSN_SET_SIMULATE(jsri32, insn); 47 + 48 + return INSN_GOOD; 49 + }
+20
arch/csky/kernel/probes/decode-insn.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + 3 + #ifndef __CSKY_KERNEL_KPROBES_DECODE_INSN_H 4 + #define __CSKY_KERNEL_KPROBES_DECODE_INSN_H 5 + 6 + #include <asm/sections.h> 7 + #include <asm/kprobes.h> 8 + 9 + enum probe_insn { 10 + INSN_REJECTED, 11 + INSN_GOOD_NO_SLOT, 12 + INSN_GOOD, 13 + }; 14 + 15 + #define is_insn32(insn) ((insn & 0xc000) == 0xc000) 16 + 17 + enum probe_insn __kprobes 18 + csky_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *asi); 19 + 20 + #endif /* __CSKY_KERNEL_KPROBES_DECODE_INSN_H */
+66
arch/csky/kernel/probes/ftrace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/kprobes.h> 4 + 5 + int arch_check_ftrace_location(struct kprobe *p) 6 + { 7 + if (ftrace_location((unsigned long)p->addr)) 8 + p->flags |= KPROBE_FLAG_FTRACE; 9 + return 0; 10 + } 11 + 12 + /* Ftrace callback handler for kprobes -- called under preepmt disabed */ 13 + void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, 14 + struct ftrace_ops *ops, struct pt_regs *regs) 15 + { 16 + bool lr_saver = false; 17 + struct kprobe *p; 18 + struct kprobe_ctlblk *kcb; 19 + 20 + /* Preempt is disabled by ftrace */ 21 + p = get_kprobe((kprobe_opcode_t *)ip); 22 + if (!p) { 23 + p = get_kprobe((kprobe_opcode_t *)(ip - MCOUNT_INSN_SIZE)); 24 + if (unlikely(!p) || kprobe_disabled(p)) 25 + return; 26 + lr_saver = true; 27 + } 28 + 29 + kcb = get_kprobe_ctlblk(); 30 + if (kprobe_running()) { 31 + kprobes_inc_nmissed_count(p); 32 + } else { 33 + unsigned long orig_ip = instruction_pointer(regs); 34 + 35 + if (lr_saver) 36 + ip -= MCOUNT_INSN_SIZE; 37 + instruction_pointer_set(regs, ip); 38 + __this_cpu_write(current_kprobe, p); 39 + kcb->kprobe_status = KPROBE_HIT_ACTIVE; 40 + if (!p->pre_handler || !p->pre_handler(p, regs)) { 41 + /* 42 + * Emulate singlestep (and also recover regs->pc) 43 + * as if there is a nop 44 + */ 45 + instruction_pointer_set(regs, 46 + (unsigned long)p->addr + MCOUNT_INSN_SIZE); 47 + if (unlikely(p->post_handler)) { 48 + kcb->kprobe_status = KPROBE_HIT_SSDONE; 49 + p->post_handler(p, regs, 0); 50 + } 51 + instruction_pointer_set(regs, orig_ip); 52 + } 53 + /* 54 + * If pre_handler returns !0, it changes regs->pc. We have to 55 + * skip emulating post_handler. 56 + */ 57 + __this_cpu_write(current_kprobe, NULL); 58 + } 59 + } 60 + NOKPROBE_SYMBOL(kprobe_ftrace_handler); 61 + 62 + int arch_prepare_kprobe_ftrace(struct kprobe *p) 63 + { 64 + p->ainsn.api.insn = NULL; 65 + return 0; 66 + }
+499
arch/csky/kernel/probes/kprobes.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include <linux/kprobes.h> 4 + #include <linux/extable.h> 5 + #include <linux/slab.h> 6 + #include <linux/stop_machine.h> 7 + #include <asm/ptrace.h> 8 + #include <linux/uaccess.h> 9 + #include <asm/sections.h> 10 + #include <asm/cacheflush.h> 11 + 12 + #include "decode-insn.h" 13 + 14 + DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; 15 + DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 16 + 17 + static void __kprobes 18 + post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *); 19 + 20 + struct csky_insn_patch { 21 + kprobe_opcode_t *addr; 22 + u32 opcode; 23 + atomic_t cpu_count; 24 + }; 25 + 26 + static int __kprobes patch_text_cb(void *priv) 27 + { 28 + struct csky_insn_patch *param = priv; 29 + unsigned int addr = (unsigned int)param->addr; 30 + 31 + if (atomic_inc_return(&param->cpu_count) == 1) { 32 + *(u16 *) addr = cpu_to_le16(param->opcode); 33 + dcache_wb_range(addr, addr + 2); 34 + atomic_inc(&param->cpu_count); 35 + } else { 36 + while (atomic_read(&param->cpu_count) <= num_online_cpus()) 37 + cpu_relax(); 38 + } 39 + 40 + icache_inv_range(addr, addr + 2); 41 + 42 + return 0; 43 + } 44 + 45 + static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode) 46 + { 47 + struct csky_insn_patch param = { addr, opcode, ATOMIC_INIT(0) }; 48 + 49 + return stop_machine_cpuslocked(patch_text_cb, &param, cpu_online_mask); 50 + } 51 + 52 + static void __kprobes arch_prepare_ss_slot(struct kprobe *p) 53 + { 54 + unsigned long offset = is_insn32(p->opcode) ? 4 : 2; 55 + 56 + p->ainsn.api.restore = (unsigned long)p->addr + offset; 57 + 58 + patch_text(p->ainsn.api.insn, p->opcode); 59 + } 60 + 61 + static void __kprobes arch_prepare_simulate(struct kprobe *p) 62 + { 63 + p->ainsn.api.restore = 0; 64 + } 65 + 66 + static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs) 67 + { 68 + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 69 + 70 + if (p->ainsn.api.handler) 71 + p->ainsn.api.handler((u32)p->opcode, (long)p->addr, regs); 72 + 73 + post_kprobe_handler(kcb, regs); 74 + } 75 + 76 + int __kprobes arch_prepare_kprobe(struct kprobe *p) 77 + { 78 + unsigned long probe_addr = (unsigned long)p->addr; 79 + 80 + if (probe_addr & 0x1) { 81 + pr_warn("Address not aligned.\n"); 82 + return -EINVAL; 83 + } 84 + 85 + /* copy instruction */ 86 + p->opcode = le32_to_cpu(*p->addr); 87 + 88 + /* decode instruction */ 89 + switch (csky_probe_decode_insn(p->addr, &p->ainsn.api)) { 90 + case INSN_REJECTED: /* insn not supported */ 91 + return -EINVAL; 92 + 93 + case INSN_GOOD_NO_SLOT: /* insn need simulation */ 94 + p->ainsn.api.insn = NULL; 95 + break; 96 + 97 + case INSN_GOOD: /* instruction uses slot */ 98 + p->ainsn.api.insn = get_insn_slot(); 99 + if (!p->ainsn.api.insn) 100 + return -ENOMEM; 101 + break; 102 + } 103 + 104 + /* prepare the instruction */ 105 + if (p->ainsn.api.insn) 106 + arch_prepare_ss_slot(p); 107 + else 108 + arch_prepare_simulate(p); 109 + 110 + return 0; 111 + } 112 + 113 + /* install breakpoint in text */ 114 + void __kprobes arch_arm_kprobe(struct kprobe *p) 115 + { 116 + patch_text(p->addr, USR_BKPT); 117 + } 118 + 119 + /* remove breakpoint from text */ 120 + void __kprobes arch_disarm_kprobe(struct kprobe *p) 121 + { 122 + patch_text(p->addr, p->opcode); 123 + } 124 + 125 + void __kprobes arch_remove_kprobe(struct kprobe *p) 126 + { 127 + } 128 + 129 + static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) 130 + { 131 + kcb->prev_kprobe.kp = kprobe_running(); 132 + kcb->prev_kprobe.status = kcb->kprobe_status; 133 + } 134 + 135 + static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) 136 + { 137 + __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); 138 + kcb->kprobe_status = kcb->prev_kprobe.status; 139 + } 140 + 141 + static void __kprobes set_current_kprobe(struct kprobe *p) 142 + { 143 + __this_cpu_write(current_kprobe, p); 144 + } 145 + 146 + /* 147 + * Interrupts need to be disabled before single-step mode is set, and not 148 + * reenabled until after single-step mode ends. 149 + * Without disabling interrupt on local CPU, there is a chance of 150 + * interrupt occurrence in the period of exception return and start of 151 + * out-of-line single-step, that result in wrongly single stepping 152 + * into the interrupt handler. 153 + */ 154 + static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb, 155 + struct pt_regs *regs) 156 + { 157 + kcb->saved_sr = regs->sr; 158 + regs->sr &= ~BIT(6); 159 + } 160 + 161 + static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb, 162 + struct pt_regs *regs) 163 + { 164 + regs->sr = kcb->saved_sr; 165 + } 166 + 167 + static void __kprobes 168 + set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr, struct kprobe *p) 169 + { 170 + unsigned long offset = is_insn32(p->opcode) ? 4 : 2; 171 + 172 + kcb->ss_ctx.ss_pending = true; 173 + kcb->ss_ctx.match_addr = addr + offset; 174 + } 175 + 176 + static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb) 177 + { 178 + kcb->ss_ctx.ss_pending = false; 179 + kcb->ss_ctx.match_addr = 0; 180 + } 181 + 182 + #define TRACE_MODE_SI BIT(14) 183 + #define TRACE_MODE_MASK ~(0x3 << 14) 184 + #define TRACE_MODE_RUN 0 185 + 186 + static void __kprobes setup_singlestep(struct kprobe *p, 187 + struct pt_regs *regs, 188 + struct kprobe_ctlblk *kcb, int reenter) 189 + { 190 + unsigned long slot; 191 + 192 + if (reenter) { 193 + save_previous_kprobe(kcb); 194 + set_current_kprobe(p); 195 + kcb->kprobe_status = KPROBE_REENTER; 196 + } else { 197 + kcb->kprobe_status = KPROBE_HIT_SS; 198 + } 199 + 200 + if (p->ainsn.api.insn) { 201 + /* prepare for single stepping */ 202 + slot = (unsigned long)p->ainsn.api.insn; 203 + 204 + set_ss_context(kcb, slot, p); /* mark pending ss */ 205 + 206 + /* IRQs and single stepping do not mix well. */ 207 + kprobes_save_local_irqflag(kcb, regs); 208 + regs->sr = (regs->sr & TRACE_MODE_MASK) | TRACE_MODE_SI; 209 + instruction_pointer_set(regs, slot); 210 + } else { 211 + /* insn simulation */ 212 + arch_simulate_insn(p, regs); 213 + } 214 + } 215 + 216 + static int __kprobes reenter_kprobe(struct kprobe *p, 217 + struct pt_regs *regs, 218 + struct kprobe_ctlblk *kcb) 219 + { 220 + switch (kcb->kprobe_status) { 221 + case KPROBE_HIT_SSDONE: 222 + case KPROBE_HIT_ACTIVE: 223 + kprobes_inc_nmissed_count(p); 224 + setup_singlestep(p, regs, kcb, 1); 225 + break; 226 + case KPROBE_HIT_SS: 227 + case KPROBE_REENTER: 228 + pr_warn("Unrecoverable kprobe detected.\n"); 229 + dump_kprobe(p); 230 + BUG(); 231 + break; 232 + default: 233 + WARN_ON(1); 234 + return 0; 235 + } 236 + 237 + return 1; 238 + } 239 + 240 + static void __kprobes 241 + post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs) 242 + { 243 + struct kprobe *cur = kprobe_running(); 244 + 245 + if (!cur) 246 + return; 247 + 248 + /* return addr restore if non-branching insn */ 249 + if (cur->ainsn.api.restore != 0) 250 + regs->pc = cur->ainsn.api.restore; 251 + 252 + /* restore back original saved kprobe variables and continue */ 253 + if (kcb->kprobe_status == KPROBE_REENTER) { 254 + restore_previous_kprobe(kcb); 255 + return; 256 + } 257 + 258 + /* call post handler */ 259 + kcb->kprobe_status = KPROBE_HIT_SSDONE; 260 + if (cur->post_handler) { 261 + /* post_handler can hit breakpoint and single step 262 + * again, so we enable D-flag for recursive exception. 263 + */ 264 + cur->post_handler(cur, regs, 0); 265 + } 266 + 267 + reset_current_kprobe(); 268 + } 269 + 270 + int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr) 271 + { 272 + struct kprobe *cur = kprobe_running(); 273 + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 274 + 275 + switch (kcb->kprobe_status) { 276 + case KPROBE_HIT_SS: 277 + case KPROBE_REENTER: 278 + /* 279 + * We are here because the instruction being single 280 + * stepped caused a page fault. We reset the current 281 + * kprobe and the ip points back to the probe address 282 + * and allow the page fault handler to continue as a 283 + * normal page fault. 284 + */ 285 + regs->pc = (unsigned long) cur->addr; 286 + if (!instruction_pointer(regs)) 287 + BUG(); 288 + 289 + if (kcb->kprobe_status == KPROBE_REENTER) 290 + restore_previous_kprobe(kcb); 291 + else 292 + reset_current_kprobe(); 293 + 294 + break; 295 + case KPROBE_HIT_ACTIVE: 296 + case KPROBE_HIT_SSDONE: 297 + /* 298 + * We increment the nmissed count for accounting, 299 + * we can also use npre/npostfault count for accounting 300 + * these specific fault cases. 301 + */ 302 + kprobes_inc_nmissed_count(cur); 303 + 304 + /* 305 + * We come here because instructions in the pre/post 306 + * handler caused the page_fault, this could happen 307 + * if handler tries to access user space by 308 + * copy_from_user(), get_user() etc. Let the 309 + * user-specified handler try to fix it first. 310 + */ 311 + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) 312 + return 1; 313 + 314 + /* 315 + * In case the user-specified fault handler returned 316 + * zero, try to fix up. 317 + */ 318 + if (fixup_exception(regs)) 319 + return 1; 320 + } 321 + return 0; 322 + } 323 + 324 + int __kprobes 325 + kprobe_breakpoint_handler(struct pt_regs *regs) 326 + { 327 + struct kprobe *p, *cur_kprobe; 328 + struct kprobe_ctlblk *kcb; 329 + unsigned long addr = instruction_pointer(regs); 330 + 331 + kcb = get_kprobe_ctlblk(); 332 + cur_kprobe = kprobe_running(); 333 + 334 + p = get_kprobe((kprobe_opcode_t *) addr); 335 + 336 + if (p) { 337 + if (cur_kprobe) { 338 + if (reenter_kprobe(p, regs, kcb)) 339 + return 1; 340 + } else { 341 + /* Probe hit */ 342 + set_current_kprobe(p); 343 + kcb->kprobe_status = KPROBE_HIT_ACTIVE; 344 + 345 + /* 346 + * If we have no pre-handler or it returned 0, we 347 + * continue with normal processing. If we have a 348 + * pre-handler and it returned non-zero, it will 349 + * modify the execution path and no need to single 350 + * stepping. Let's just reset current kprobe and exit. 351 + * 352 + * pre_handler can hit a breakpoint and can step thru 353 + * before return. 354 + */ 355 + if (!p->pre_handler || !p->pre_handler(p, regs)) 356 + setup_singlestep(p, regs, kcb, 0); 357 + else 358 + reset_current_kprobe(); 359 + } 360 + return 1; 361 + } 362 + 363 + /* 364 + * The breakpoint instruction was removed right 365 + * after we hit it. Another cpu has removed 366 + * either a probepoint or a debugger breakpoint 367 + * at this address. In either case, no further 368 + * handling of this interrupt is appropriate. 369 + * Return back to original instruction, and continue. 370 + */ 371 + return 0; 372 + } 373 + 374 + int __kprobes 375 + kprobe_single_step_handler(struct pt_regs *regs) 376 + { 377 + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 378 + 379 + if ((kcb->ss_ctx.ss_pending) 380 + && (kcb->ss_ctx.match_addr == instruction_pointer(regs))) { 381 + clear_ss_context(kcb); /* clear pending ss */ 382 + 383 + kprobes_restore_local_irqflag(kcb, regs); 384 + regs->sr = (regs->sr & TRACE_MODE_MASK) | TRACE_MODE_RUN; 385 + 386 + post_kprobe_handler(kcb, regs); 387 + return 1; 388 + } 389 + return 0; 390 + } 391 + 392 + /* 393 + * Provide a blacklist of symbols identifying ranges which cannot be kprobed. 394 + * This blacklist is exposed to userspace via debugfs (kprobes/blacklist). 395 + */ 396 + int __init arch_populate_kprobe_blacklist(void) 397 + { 398 + int ret; 399 + 400 + ret = kprobe_add_area_blacklist((unsigned long)__irqentry_text_start, 401 + (unsigned long)__irqentry_text_end); 402 + return ret; 403 + } 404 + 405 + void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs) 406 + { 407 + struct kretprobe_instance *ri = NULL; 408 + struct hlist_head *head, empty_rp; 409 + struct hlist_node *tmp; 410 + unsigned long flags, orig_ret_address = 0; 411 + unsigned long trampoline_address = 412 + (unsigned long)&kretprobe_trampoline; 413 + kprobe_opcode_t *correct_ret_addr = NULL; 414 + 415 + INIT_HLIST_HEAD(&empty_rp); 416 + kretprobe_hash_lock(current, &head, &flags); 417 + 418 + /* 419 + * It is possible to have multiple instances associated with a given 420 + * task either because multiple functions in the call path have 421 + * return probes installed on them, and/or more than one 422 + * return probe was registered for a target function. 423 + * 424 + * We can handle this because: 425 + * - instances are always pushed into the head of the list 426 + * - when multiple return probes are registered for the same 427 + * function, the (chronologically) first instance's ret_addr 428 + * will be the real return address, and all the rest will 429 + * point to kretprobe_trampoline. 430 + */ 431 + hlist_for_each_entry_safe(ri, tmp, head, hlist) { 432 + if (ri->task != current) 433 + /* another task is sharing our hash bucket */ 434 + continue; 435 + 436 + orig_ret_address = (unsigned long)ri->ret_addr; 437 + 438 + if (orig_ret_address != trampoline_address) 439 + /* 440 + * This is the real return address. Any other 441 + * instances associated with this task are for 442 + * other calls deeper on the call stack 443 + */ 444 + break; 445 + } 446 + 447 + kretprobe_assert(ri, orig_ret_address, trampoline_address); 448 + 449 + correct_ret_addr = ri->ret_addr; 450 + hlist_for_each_entry_safe(ri, tmp, head, hlist) { 451 + if (ri->task != current) 452 + /* another task is sharing our hash bucket */ 453 + continue; 454 + 455 + orig_ret_address = (unsigned long)ri->ret_addr; 456 + if (ri->rp && ri->rp->handler) { 457 + __this_cpu_write(current_kprobe, &ri->rp->kp); 458 + get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; 459 + ri->ret_addr = correct_ret_addr; 460 + ri->rp->handler(ri, regs); 461 + __this_cpu_write(current_kprobe, NULL); 462 + } 463 + 464 + recycle_rp_inst(ri, &empty_rp); 465 + 466 + if (orig_ret_address != trampoline_address) 467 + /* 468 + * This is the real return address. Any other 469 + * instances associated with this task are for 470 + * other calls deeper on the call stack 471 + */ 472 + break; 473 + } 474 + 475 + kretprobe_hash_unlock(current, &flags); 476 + 477 + hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { 478 + hlist_del(&ri->hlist); 479 + kfree(ri); 480 + } 481 + return (void *)orig_ret_address; 482 + } 483 + 484 + void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, 485 + struct pt_regs *regs) 486 + { 487 + ri->ret_addr = (kprobe_opcode_t *)regs->lr; 488 + regs->lr = (unsigned long) &kretprobe_trampoline; 489 + } 490 + 491 + int __kprobes arch_trampoline_kprobe(struct kprobe *p) 492 + { 493 + return 0; 494 + } 495 + 496 + int __init arch_init_kprobes(void) 497 + { 498 + return 0; 499 + }
+19
arch/csky/kernel/probes/kprobes_trampoline.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + 3 + #include <linux/linkage.h> 4 + 5 + #include <abi/entry.h> 6 + 7 + ENTRY(kretprobe_trampoline) 8 + SAVE_REGS_FTRACE 9 + 10 + mov a0, sp /* pt_regs */ 11 + 12 + jbsr trampoline_probe_handler 13 + 14 + /* use the result as the return-address */ 15 + mov lr, a0 16 + 17 + RESTORE_REGS_FTRACE 18 + rts 19 + ENDPROC(kretprobe_trampoline)
+398
arch/csky/kernel/probes/simulate-insn.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include <linux/bitops.h> 4 + #include <linux/kernel.h> 5 + #include <linux/kprobes.h> 6 + 7 + #include "decode-insn.h" 8 + #include "simulate-insn.h" 9 + 10 + static inline bool csky_insn_reg_get_val(struct pt_regs *regs, 11 + unsigned long index, 12 + unsigned long *ptr) 13 + { 14 + if (index < 14) 15 + *ptr = *(&regs->a0 + index); 16 + 17 + if (index > 15 && index < 31) 18 + *ptr = *(&regs->exregs[0] + index - 16); 19 + 20 + switch (index) { 21 + case 14: 22 + *ptr = regs->usp; 23 + break; 24 + case 15: 25 + *ptr = regs->lr; 26 + break; 27 + case 31: 28 + *ptr = regs->tls; 29 + break; 30 + default: 31 + goto fail; 32 + } 33 + 34 + return true; 35 + fail: 36 + return false; 37 + } 38 + 39 + static inline bool csky_insn_reg_set_val(struct pt_regs *regs, 40 + unsigned long index, 41 + unsigned long val) 42 + { 43 + if (index < 14) 44 + *(&regs->a0 + index) = val; 45 + 46 + if (index > 15 && index < 31) 47 + *(&regs->exregs[0] + index - 16) = val; 48 + 49 + switch (index) { 50 + case 14: 51 + regs->usp = val; 52 + break; 53 + case 15: 54 + regs->lr = val; 55 + break; 56 + case 31: 57 + regs->tls = val; 58 + break; 59 + default: 60 + goto fail; 61 + } 62 + 63 + return true; 64 + fail: 65 + return false; 66 + } 67 + 68 + void __kprobes 69 + simulate_br16(u32 opcode, long addr, struct pt_regs *regs) 70 + { 71 + instruction_pointer_set(regs, 72 + addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 73 + } 74 + 75 + void __kprobes 76 + simulate_br32(u32 opcode, long addr, struct pt_regs *regs) 77 + { 78 + instruction_pointer_set(regs, 79 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 80 + } 81 + 82 + void __kprobes 83 + simulate_bt16(u32 opcode, long addr, struct pt_regs *regs) 84 + { 85 + if (regs->sr & 1) 86 + instruction_pointer_set(regs, 87 + addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 88 + else 89 + instruction_pointer_set(regs, addr + 2); 90 + } 91 + 92 + void __kprobes 93 + simulate_bt32(u32 opcode, long addr, struct pt_regs *regs) 94 + { 95 + if (regs->sr & 1) 96 + instruction_pointer_set(regs, 97 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 98 + else 99 + instruction_pointer_set(regs, addr + 4); 100 + } 101 + 102 + void __kprobes 103 + simulate_bf16(u32 opcode, long addr, struct pt_regs *regs) 104 + { 105 + if (!(regs->sr & 1)) 106 + instruction_pointer_set(regs, 107 + addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 108 + else 109 + instruction_pointer_set(regs, addr + 2); 110 + } 111 + 112 + void __kprobes 113 + simulate_bf32(u32 opcode, long addr, struct pt_regs *regs) 114 + { 115 + if (!(regs->sr & 1)) 116 + instruction_pointer_set(regs, 117 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 118 + else 119 + instruction_pointer_set(regs, addr + 4); 120 + } 121 + 122 + void __kprobes 123 + simulate_jmp16(u32 opcode, long addr, struct pt_regs *regs) 124 + { 125 + unsigned long tmp = (opcode >> 2) & 0xf; 126 + 127 + csky_insn_reg_get_val(regs, tmp, &tmp); 128 + 129 + instruction_pointer_set(regs, tmp & 0xfffffffe); 130 + } 131 + 132 + void __kprobes 133 + simulate_jmp32(u32 opcode, long addr, struct pt_regs *regs) 134 + { 135 + unsigned long tmp = opcode & 0x1f; 136 + 137 + csky_insn_reg_get_val(regs, tmp, &tmp); 138 + 139 + instruction_pointer_set(regs, tmp & 0xfffffffe); 140 + } 141 + 142 + void __kprobes 143 + simulate_jsr16(u32 opcode, long addr, struct pt_regs *regs) 144 + { 145 + unsigned long tmp = (opcode >> 2) & 0xf; 146 + 147 + csky_insn_reg_get_val(regs, tmp, &tmp); 148 + 149 + regs->lr = addr + 2; 150 + 151 + instruction_pointer_set(regs, tmp & 0xfffffffe); 152 + } 153 + 154 + void __kprobes 155 + simulate_jsr32(u32 opcode, long addr, struct pt_regs *regs) 156 + { 157 + unsigned long tmp = opcode & 0x1f; 158 + 159 + csky_insn_reg_get_val(regs, tmp, &tmp); 160 + 161 + regs->lr = addr + 4; 162 + 163 + instruction_pointer_set(regs, tmp & 0xfffffffe); 164 + } 165 + 166 + void __kprobes 167 + simulate_lrw16(u32 opcode, long addr, struct pt_regs *regs) 168 + { 169 + unsigned long val; 170 + unsigned long tmp = (opcode & 0x300) >> 3; 171 + unsigned long offset = ((opcode & 0x1f) | tmp) << 2; 172 + 173 + tmp = (opcode & 0xe0) >> 5; 174 + 175 + val = *(unsigned int *)(instruction_pointer(regs) + offset); 176 + 177 + csky_insn_reg_set_val(regs, tmp, val); 178 + } 179 + 180 + void __kprobes 181 + simulate_lrw32(u32 opcode, long addr, struct pt_regs *regs) 182 + { 183 + unsigned long val; 184 + unsigned long offset = (opcode & 0xffff0000) >> 14; 185 + unsigned long tmp = opcode & 0x0000001f; 186 + 187 + val = *(unsigned int *) 188 + ((instruction_pointer(regs) + offset) & 0xfffffffc); 189 + 190 + csky_insn_reg_set_val(regs, tmp, val); 191 + } 192 + 193 + void __kprobes 194 + simulate_pop16(u32 opcode, long addr, struct pt_regs *regs) 195 + { 196 + unsigned long *tmp = (unsigned long *)regs->usp; 197 + int i; 198 + 199 + for (i = 0; i < (opcode & 0xf); i++) { 200 + csky_insn_reg_set_val(regs, i + 4, *tmp); 201 + tmp += 1; 202 + } 203 + 204 + if (opcode & 0x10) { 205 + csky_insn_reg_set_val(regs, 15, *tmp); 206 + tmp += 1; 207 + } 208 + 209 + regs->usp = (unsigned long)tmp; 210 + 211 + instruction_pointer_set(regs, regs->lr); 212 + } 213 + 214 + void __kprobes 215 + simulate_pop32(u32 opcode, long addr, struct pt_regs *regs) 216 + { 217 + unsigned long *tmp = (unsigned long *)regs->usp; 218 + int i; 219 + 220 + for (i = 0; i < ((opcode & 0xf0000) >> 16); i++) { 221 + csky_insn_reg_set_val(regs, i + 4, *tmp); 222 + tmp += 1; 223 + } 224 + 225 + if (opcode & 0x100000) { 226 + csky_insn_reg_set_val(regs, 15, *tmp); 227 + tmp += 1; 228 + } 229 + 230 + for (i = 0; i < ((opcode & 0xe00000) >> 21); i++) { 231 + csky_insn_reg_set_val(regs, i + 16, *tmp); 232 + tmp += 1; 233 + } 234 + 235 + if (opcode & 0x1000000) { 236 + csky_insn_reg_set_val(regs, 29, *tmp); 237 + tmp += 1; 238 + } 239 + 240 + regs->usp = (unsigned long)tmp; 241 + 242 + instruction_pointer_set(regs, regs->lr); 243 + } 244 + 245 + void __kprobes 246 + simulate_bez32(u32 opcode, long addr, struct pt_regs *regs) 247 + { 248 + unsigned long tmp = opcode & 0x1f; 249 + 250 + csky_insn_reg_get_val(regs, tmp, &tmp); 251 + 252 + if (tmp == 0) { 253 + instruction_pointer_set(regs, 254 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 255 + } else 256 + instruction_pointer_set(regs, addr + 4); 257 + } 258 + 259 + void __kprobes 260 + simulate_bnez32(u32 opcode, long addr, struct pt_regs *regs) 261 + { 262 + unsigned long tmp = opcode & 0x1f; 263 + 264 + csky_insn_reg_get_val(regs, tmp, &tmp); 265 + 266 + if (tmp != 0) { 267 + instruction_pointer_set(regs, 268 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 269 + } else 270 + instruction_pointer_set(regs, addr + 4); 271 + } 272 + 273 + void __kprobes 274 + simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs) 275 + { 276 + unsigned long tmp = opcode & 0x1f; 277 + unsigned long val; 278 + 279 + csky_insn_reg_get_val(regs, tmp, &val); 280 + 281 + val -= 1; 282 + 283 + if (val > 0) { 284 + instruction_pointer_set(regs, 285 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 286 + } else 287 + instruction_pointer_set(regs, addr + 4); 288 + 289 + csky_insn_reg_set_val(regs, tmp, val); 290 + } 291 + 292 + void __kprobes 293 + simulate_bhsz32(u32 opcode, long addr, struct pt_regs *regs) 294 + { 295 + unsigned long tmp = opcode & 0x1f; 296 + unsigned long val; 297 + 298 + csky_insn_reg_get_val(regs, tmp, &val); 299 + 300 + if (val >= 0) { 301 + instruction_pointer_set(regs, 302 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 303 + } else 304 + instruction_pointer_set(regs, addr + 4); 305 + 306 + csky_insn_reg_set_val(regs, tmp, val); 307 + } 308 + 309 + void __kprobes 310 + simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs) 311 + { 312 + unsigned long tmp = opcode & 0x1f; 313 + unsigned long val; 314 + 315 + csky_insn_reg_get_val(regs, tmp, &val); 316 + 317 + if (val > 0) { 318 + instruction_pointer_set(regs, 319 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 320 + } else 321 + instruction_pointer_set(regs, addr + 4); 322 + 323 + csky_insn_reg_set_val(regs, tmp, val); 324 + } 325 + 326 + void __kprobes 327 + simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs) 328 + { 329 + unsigned long tmp = opcode & 0x1f; 330 + unsigned long val; 331 + 332 + csky_insn_reg_get_val(regs, tmp, &val); 333 + 334 + if (val <= 0) { 335 + instruction_pointer_set(regs, 336 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 337 + } else 338 + instruction_pointer_set(regs, addr + 4); 339 + 340 + csky_insn_reg_set_val(regs, tmp, val); 341 + } 342 + 343 + void __kprobes 344 + simulate_blz32(u32 opcode, long addr, struct pt_regs *regs) 345 + { 346 + unsigned long tmp = opcode & 0x1f; 347 + unsigned long val; 348 + 349 + csky_insn_reg_get_val(regs, tmp, &val); 350 + 351 + if (val < 0) { 352 + instruction_pointer_set(regs, 353 + addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 354 + } else 355 + instruction_pointer_set(regs, addr + 4); 356 + 357 + csky_insn_reg_set_val(regs, tmp, val); 358 + } 359 + 360 + void __kprobes 361 + simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs) 362 + { 363 + unsigned long tmp; 364 + 365 + tmp = (opcode & 0xffff) << 16; 366 + tmp |= (opcode & 0xffff0000) >> 16; 367 + 368 + instruction_pointer_set(regs, 369 + addr + sign_extend32((tmp & 0x3ffffff) << 1, 15)); 370 + 371 + regs->lr = addr + 4; 372 + } 373 + 374 + void __kprobes 375 + simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs) 376 + { 377 + unsigned long val; 378 + unsigned long offset = ((opcode & 0xffff0000) >> 14); 379 + 380 + val = *(unsigned int *) 381 + ((instruction_pointer(regs) + offset) & 0xfffffffc); 382 + 383 + instruction_pointer_set(regs, val); 384 + } 385 + 386 + void __kprobes 387 + simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs) 388 + { 389 + unsigned long val; 390 + unsigned long offset = ((opcode & 0xffff0000) >> 14); 391 + 392 + val = *(unsigned int *) 393 + ((instruction_pointer(regs) + offset) & 0xfffffffc); 394 + 395 + regs->lr = addr + 4; 396 + 397 + instruction_pointer_set(regs, val); 398 + }
+49
arch/csky/kernel/probes/simulate-insn.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + 3 + #ifndef __CSKY_KERNEL_PROBES_SIMULATE_INSN_H 4 + #define __CSKY_KERNEL_PROBES_SIMULATE_INSN_H 5 + 6 + #define __CSKY_INSN_FUNCS(name, mask, val) \ 7 + static __always_inline bool csky_insn_is_##name(probe_opcode_t code) \ 8 + { \ 9 + BUILD_BUG_ON(~(mask) & (val)); \ 10 + return (code & (mask)) == (val); \ 11 + } \ 12 + void simulate_##name(u32 opcode, long addr, struct pt_regs *regs); 13 + 14 + #define CSKY_INSN_SET_SIMULATE(name, code) \ 15 + do { \ 16 + if (csky_insn_is_##name(code)) { \ 17 + api->handler = simulate_##name; \ 18 + return INSN_GOOD_NO_SLOT; \ 19 + } \ 20 + } while (0) 21 + 22 + __CSKY_INSN_FUNCS(br16, 0xfc00, 0x0400) 23 + __CSKY_INSN_FUNCS(bt16, 0xfc00, 0x0800) 24 + __CSKY_INSN_FUNCS(bf16, 0xfc00, 0x0c00) 25 + __CSKY_INSN_FUNCS(jmp16, 0xffc3, 0x7800) 26 + __CSKY_INSN_FUNCS(jsr16, 0xffc3, 0x7801) 27 + __CSKY_INSN_FUNCS(lrw16, 0xfc00, 0x1000) 28 + __CSKY_INSN_FUNCS(pop16, 0xffe0, 0x1480) 29 + 30 + __CSKY_INSN_FUNCS(br32, 0x0000ffff, 0x0000e800) 31 + __CSKY_INSN_FUNCS(bt32, 0x0000ffff, 0x0000e860) 32 + __CSKY_INSN_FUNCS(bf32, 0x0000ffff, 0x0000e840) 33 + __CSKY_INSN_FUNCS(jmp32, 0xffffffe0, 0x0000e8c0) 34 + __CSKY_INSN_FUNCS(jsr32, 0xffffffe0, 0x0000e8e0) 35 + __CSKY_INSN_FUNCS(lrw32, 0x0000ffe0, 0x0000ea80) 36 + __CSKY_INSN_FUNCS(pop32, 0xfe00ffff, 0x0000ebc0) 37 + 38 + __CSKY_INSN_FUNCS(bez32, 0x0000ffe0, 0x0000e900) 39 + __CSKY_INSN_FUNCS(bnez32, 0x0000ffe0, 0x0000e920) 40 + __CSKY_INSN_FUNCS(bnezad32, 0x0000ffe0, 0x0000e820) 41 + __CSKY_INSN_FUNCS(bhsz32, 0x0000ffe0, 0x0000e9a0) 42 + __CSKY_INSN_FUNCS(bhz32, 0x0000ffe0, 0x0000e940) 43 + __CSKY_INSN_FUNCS(blsz32, 0x0000ffe0, 0x0000e960) 44 + __CSKY_INSN_FUNCS(blz32, 0x0000ffe0, 0x0000e980) 45 + __CSKY_INSN_FUNCS(bsr32, 0x0000fc00, 0x0000e000) 46 + __CSKY_INSN_FUNCS(jmpi32, 0x0000ffff, 0x0000eac0) 47 + __CSKY_INSN_FUNCS(jsri32, 0x0000ffff, 0x0000eae0) 48 + 49 + #endif /* __CSKY_KERNEL_PROBES_SIMULATE_INSN_H */
+150
arch/csky/kernel/probes/uprobes.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com> 4 + */ 5 + #include <linux/highmem.h> 6 + #include <linux/ptrace.h> 7 + #include <linux/uprobes.h> 8 + #include <asm/cacheflush.h> 9 + 10 + #include "decode-insn.h" 11 + 12 + #define UPROBE_TRAP_NR UINT_MAX 13 + 14 + unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) 15 + { 16 + return instruction_pointer(regs); 17 + } 18 + 19 + int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, 20 + unsigned long addr) 21 + { 22 + probe_opcode_t insn; 23 + 24 + insn = *(probe_opcode_t *)(&auprobe->insn[0]); 25 + 26 + auprobe->insn_size = is_insn32(insn) ? 4 : 2; 27 + 28 + switch (csky_probe_decode_insn(&insn, &auprobe->api)) { 29 + case INSN_REJECTED: 30 + return -EINVAL; 31 + 32 + case INSN_GOOD_NO_SLOT: 33 + auprobe->simulate = true; 34 + break; 35 + 36 + default: 37 + break; 38 + } 39 + 40 + return 0; 41 + } 42 + 43 + int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 44 + { 45 + struct uprobe_task *utask = current->utask; 46 + 47 + utask->autask.saved_trap_no = current->thread.trap_no; 48 + current->thread.trap_no = UPROBE_TRAP_NR; 49 + 50 + instruction_pointer_set(regs, utask->xol_vaddr); 51 + 52 + user_enable_single_step(current); 53 + 54 + return 0; 55 + } 56 + 57 + int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 58 + { 59 + struct uprobe_task *utask = current->utask; 60 + 61 + WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR); 62 + 63 + instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size); 64 + 65 + user_disable_single_step(current); 66 + 67 + return 0; 68 + } 69 + 70 + bool arch_uprobe_xol_was_trapped(struct task_struct *t) 71 + { 72 + if (t->thread.trap_no != UPROBE_TRAP_NR) 73 + return true; 74 + 75 + return false; 76 + } 77 + 78 + bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) 79 + { 80 + probe_opcode_t insn; 81 + unsigned long addr; 82 + 83 + if (!auprobe->simulate) 84 + return false; 85 + 86 + insn = *(probe_opcode_t *)(&auprobe->insn[0]); 87 + addr = instruction_pointer(regs); 88 + 89 + if (auprobe->api.handler) 90 + auprobe->api.handler(insn, addr, regs); 91 + 92 + return true; 93 + } 94 + 95 + void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 96 + { 97 + struct uprobe_task *utask = current->utask; 98 + 99 + /* 100 + * Task has received a fatal signal, so reset back to probbed 101 + * address. 102 + */ 103 + instruction_pointer_set(regs, utask->vaddr); 104 + 105 + user_disable_single_step(current); 106 + } 107 + 108 + bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, 109 + struct pt_regs *regs) 110 + { 111 + if (ctx == RP_CHECK_CHAIN_CALL) 112 + return regs->usp <= ret->stack; 113 + else 114 + return regs->usp < ret->stack; 115 + } 116 + 117 + unsigned long 118 + arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, 119 + struct pt_regs *regs) 120 + { 121 + unsigned long ra; 122 + 123 + ra = regs->lr; 124 + 125 + regs->lr = trampoline_vaddr; 126 + 127 + return ra; 128 + } 129 + 130 + int arch_uprobe_exception_notify(struct notifier_block *self, 131 + unsigned long val, void *data) 132 + { 133 + return NOTIFY_DONE; 134 + } 135 + 136 + int uprobe_breakpoint_handler(struct pt_regs *regs) 137 + { 138 + if (uprobe_pre_sstep_notifier(regs)) 139 + return 1; 140 + 141 + return 0; 142 + } 143 + 144 + int uprobe_single_step_handler(struct pt_regs *regs) 145 + { 146 + if (uprobe_post_sstep_notifier(regs)) 147 + return 1; 148 + 149 + return 0; 150 + }
+103
arch/csky/kernel/ptrace.c
··· 193 193 return &user_csky_view; 194 194 } 195 195 196 + struct pt_regs_offset { 197 + const char *name; 198 + int offset; 199 + }; 200 + 201 + #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} 202 + #define REG_OFFSET_END {.name = NULL, .offset = 0} 203 + 204 + static const struct pt_regs_offset regoffset_table[] = { 205 + REG_OFFSET_NAME(tls), 206 + REG_OFFSET_NAME(lr), 207 + REG_OFFSET_NAME(pc), 208 + REG_OFFSET_NAME(sr), 209 + REG_OFFSET_NAME(usp), 210 + REG_OFFSET_NAME(orig_a0), 211 + REG_OFFSET_NAME(a0), 212 + REG_OFFSET_NAME(a1), 213 + REG_OFFSET_NAME(a2), 214 + REG_OFFSET_NAME(a3), 215 + REG_OFFSET_NAME(regs[0]), 216 + REG_OFFSET_NAME(regs[1]), 217 + REG_OFFSET_NAME(regs[2]), 218 + REG_OFFSET_NAME(regs[3]), 219 + REG_OFFSET_NAME(regs[4]), 220 + REG_OFFSET_NAME(regs[5]), 221 + REG_OFFSET_NAME(regs[6]), 222 + REG_OFFSET_NAME(regs[7]), 223 + REG_OFFSET_NAME(regs[8]), 224 + REG_OFFSET_NAME(regs[9]), 225 + #if defined(__CSKYABIV2__) 226 + REG_OFFSET_NAME(exregs[0]), 227 + REG_OFFSET_NAME(exregs[1]), 228 + REG_OFFSET_NAME(exregs[2]), 229 + REG_OFFSET_NAME(exregs[3]), 230 + REG_OFFSET_NAME(exregs[4]), 231 + REG_OFFSET_NAME(exregs[5]), 232 + REG_OFFSET_NAME(exregs[6]), 233 + REG_OFFSET_NAME(exregs[7]), 234 + REG_OFFSET_NAME(exregs[8]), 235 + REG_OFFSET_NAME(exregs[9]), 236 + REG_OFFSET_NAME(exregs[10]), 237 + REG_OFFSET_NAME(exregs[11]), 238 + REG_OFFSET_NAME(exregs[12]), 239 + REG_OFFSET_NAME(exregs[13]), 240 + REG_OFFSET_NAME(exregs[14]), 241 + REG_OFFSET_NAME(rhi), 242 + REG_OFFSET_NAME(rlo), 243 + REG_OFFSET_NAME(dcsr), 244 + #endif 245 + REG_OFFSET_END, 246 + }; 247 + 248 + /** 249 + * regs_query_register_offset() - query register offset from its name 250 + * @name: the name of a register 251 + * 252 + * regs_query_register_offset() returns the offset of a register in struct 253 + * pt_regs from its name. If the name is invalid, this returns -EINVAL; 254 + */ 255 + int regs_query_register_offset(const char *name) 256 + { 257 + const struct pt_regs_offset *roff; 258 + 259 + for (roff = regoffset_table; roff->name != NULL; roff++) 260 + if (!strcmp(roff->name, name)) 261 + return roff->offset; 262 + return -EINVAL; 263 + } 264 + 265 + /** 266 + * regs_within_kernel_stack() - check the address in the stack 267 + * @regs: pt_regs which contains kernel stack pointer. 268 + * @addr: address which is checked. 269 + * 270 + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). 271 + * If @addr is within the kernel stack, it returns true. If not, returns false. 272 + */ 273 + static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) 274 + { 275 + return (addr & ~(THREAD_SIZE - 1)) == 276 + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)); 277 + } 278 + 279 + /** 280 + * regs_get_kernel_stack_nth() - get Nth entry of the stack 281 + * @regs: pt_regs which contains kernel stack pointer. 282 + * @n: stack entry number. 283 + * 284 + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which 285 + * is specified by @regs. If the @n th entry is NOT in the kernel stack, 286 + * this returns 0. 287 + */ 288 + unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) 289 + { 290 + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); 291 + 292 + addr += n; 293 + if (regs_within_kernel_stack(regs, (unsigned long)addr)) 294 + return *addr; 295 + else 296 + return 0; 297 + } 298 + 196 299 void ptrace_disable(struct task_struct *child) 197 300 { 198 301 singlestep_disable(child);
+14 -49
arch/csky/kernel/setup.c
··· 24 24 }; 25 25 #endif 26 26 27 - phys_addr_t __init_memblock memblock_end_of_REG0(void) 28 - { 29 - return (memblock.memory.regions[0].base + 30 - memblock.memory.regions[0].size); 31 - } 32 - 33 - phys_addr_t __init_memblock memblock_start_of_REG1(void) 34 - { 35 - return memblock.memory.regions[1].base; 36 - } 37 - 38 - size_t __init_memblock memblock_size_of_REG1(void) 39 - { 40 - return memblock.memory.regions[1].size; 41 - } 42 - 43 27 static void __init csky_memblock_init(void) 44 28 { 45 29 unsigned long zone_size[MAX_NR_ZONES]; 46 - unsigned long zhole_size[MAX_NR_ZONES]; 47 30 signed long size; 48 31 49 32 memblock_reserve(__pa(_stext), _end - _stext); ··· 37 54 memblock_dump_all(); 38 55 39 56 memset(zone_size, 0, sizeof(zone_size)); 40 - memset(zhole_size, 0, sizeof(zhole_size)); 41 57 42 58 min_low_pfn = PFN_UP(memblock_start_of_DRAM()); 43 - max_pfn = PFN_DOWN(memblock_end_of_DRAM()); 44 - 45 - max_low_pfn = PFN_UP(memblock_end_of_REG0()); 46 - if (max_low_pfn == 0) 47 - max_low_pfn = max_pfn; 59 + max_low_pfn = max_pfn = PFN_DOWN(memblock_end_of_DRAM()); 48 60 49 61 size = max_pfn - min_low_pfn; 50 62 51 - if (memblock.memory.cnt > 1) { 52 - zone_size[ZONE_NORMAL] = 53 - PFN_DOWN(memblock_start_of_REG1()) - min_low_pfn; 54 - zhole_size[ZONE_NORMAL] = 55 - PFN_DOWN(memblock_start_of_REG1()) - max_low_pfn; 63 + if (size <= PFN_DOWN(SSEG_SIZE - PHYS_OFFSET_OFFSET)) 64 + zone_size[ZONE_NORMAL] = size; 65 + else if (size < PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET)) { 66 + zone_size[ZONE_NORMAL] = 67 + PFN_DOWN(SSEG_SIZE - PHYS_OFFSET_OFFSET); 68 + max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL]; 56 69 } else { 57 - if (size <= PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET)) 58 - zone_size[ZONE_NORMAL] = max_pfn - min_low_pfn; 59 - else { 60 - zone_size[ZONE_NORMAL] = 70 + zone_size[ZONE_NORMAL] = 61 71 PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET); 62 - max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL]; 63 - } 72 + max_low_pfn = min_low_pfn + zone_size[ZONE_NORMAL]; 73 + write_mmu_msa1(read_mmu_msa0() + SSEG_SIZE); 64 74 } 65 75 66 76 #ifdef CONFIG_HIGHMEM 67 - size = 0; 68 - if (memblock.memory.cnt > 1) { 69 - size = PFN_DOWN(memblock_size_of_REG1()); 70 - highstart_pfn = PFN_DOWN(memblock_start_of_REG1()); 71 - } else { 72 - size = max_pfn - min_low_pfn - 73 - PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET); 74 - highstart_pfn = min_low_pfn + 75 - PFN_DOWN(LOWMEM_LIMIT - PHYS_OFFSET_OFFSET); 76 - } 77 + zone_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn; 77 78 78 - if (size > 0) 79 - zone_size[ZONE_HIGHMEM] = size; 80 - 81 - highend_pfn = max_pfn; 79 + highstart_pfn = max_low_pfn; 80 + highend_pfn = max_pfn; 82 81 #endif 83 82 memblock_set_current_limit(PFN_PHYS(max_low_pfn)); 84 83 85 84 dma_contiguous_reserve(0); 86 85 87 - free_area_init_node(0, zone_size, min_low_pfn, zhole_size); 86 + free_area_init_node(0, zone_size, min_low_pfn, NULL); 88 87 } 89 88 90 89 void __init setup_arch(char **cmdline_p)
+6
arch/csky/kernel/signal.c
··· 175 175 sigset_t *oldset = sigmask_to_save(); 176 176 int ret; 177 177 178 + rseq_signal_deliver(ksig, regs); 179 + 178 180 /* Are we from a system call? */ 179 181 if (in_syscall(regs)) { 180 182 /* Avoid additional syscall restarting via ret_from_exception */ ··· 253 251 asmlinkage void do_notify_resume(struct pt_regs *regs, 254 252 unsigned long thread_info_flags) 255 253 { 254 + if (thread_info_flags & _TIF_UPROBE) 255 + uprobe_notify_resume(regs); 256 + 256 257 /* Handle pending signal delivery */ 257 258 if (thread_info_flags & _TIF_SIGPENDING) 258 259 do_signal(regs); ··· 263 258 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 264 259 clear_thread_flag(TIF_NOTIFY_RESUME); 265 260 tracehook_notify_resume(regs); 261 + rseq_handle_notify_resume(NULL, regs); 266 262 } 267 263 }
+6
arch/csky/kernel/smp.c
··· 22 22 #include <asm/sections.h> 23 23 #include <asm/mmu_context.h> 24 24 #include <asm/pgalloc.h> 25 + #ifdef CONFIG_CPU_HAS_FPU 26 + #include <abi/fpu.h> 27 + #endif 25 28 26 29 struct ipi_data_struct { 27 30 unsigned long bits ____cacheline_aligned; ··· 159 156 volatile unsigned int secondary_ccr; 160 157 volatile unsigned int secondary_stack; 161 158 159 + unsigned long secondary_msa1; 160 + 162 161 int __cpu_up(unsigned int cpu, struct task_struct *tidle) 163 162 { 164 163 unsigned long mask = 1 << cpu; ··· 169 164 (unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8; 170 165 secondary_hint = mfcr("cr31"); 171 166 secondary_ccr = mfcr("cr18"); 167 + secondary_msa1 = read_mmu_msa1(); 172 168 173 169 /* 174 170 * Because other CPUs are in reset status, we must flush data
+27 -2
arch/csky/kernel/traps.c
··· 14 14 #include <linux/kallsyms.h> 15 15 #include <linux/rtc.h> 16 16 #include <linux/uaccess.h> 17 + #include <linux/kprobes.h> 17 18 18 19 #include <asm/setup.h> 19 20 #include <asm/traps.h> ··· 110 109 force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc); 111 110 } 112 111 113 - #define USR_BKPT 0x1464 114 112 asmlinkage void trap_c(struct pt_regs *regs) 115 113 { 116 114 int sig; 117 115 unsigned long vector; 118 116 siginfo_t info; 117 + struct task_struct *tsk = current; 119 118 120 - vector = (mfcr("psr") >> 16) & 0xff; 119 + vector = (regs->sr >> 16) & 0xff; 121 120 122 121 switch (vector) { 123 122 case VEC_ZERODIV: ··· 126 125 break; 127 126 /* ptrace */ 128 127 case VEC_TRACE: 128 + #ifdef CONFIG_KPROBES 129 + if (kprobe_single_step_handler(regs)) 130 + return; 131 + #endif 132 + #ifdef CONFIG_UPROBES 133 + if (uprobe_single_step_handler(regs)) 134 + return; 135 + #endif 129 136 info.si_code = TRAP_TRACE; 130 137 sig = SIGTRAP; 131 138 break; 132 139 case VEC_ILLEGAL: 140 + tsk->thread.trap_no = vector; 141 + #ifdef CONFIG_KPROBES 142 + if (kprobe_breakpoint_handler(regs)) 143 + return; 144 + #endif 145 + #ifdef CONFIG_UPROBES 146 + if (uprobe_breakpoint_handler(regs)) 147 + return; 148 + #endif 133 149 die_if_kernel("Kernel mode ILLEGAL", regs, vector); 134 150 #ifndef CONFIG_CPU_NO_USER_BKPT 135 151 if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) ··· 164 146 sig = SIGTRAP; 165 147 break; 166 148 case VEC_ACCESS: 149 + tsk->thread.trap_no = vector; 167 150 return buserr(regs); 168 151 #ifdef CONFIG_CPU_NEED_SOFTALIGN 169 152 case VEC_ALIGN: 153 + tsk->thread.trap_no = vector; 170 154 return csky_alignment(regs); 171 155 #endif 172 156 #ifdef CONFIG_CPU_HAS_FPU 173 157 case VEC_FPE: 158 + tsk->thread.trap_no = vector; 174 159 die_if_kernel("Kernel mode FPE", regs, vector); 175 160 return fpu_fpe(regs); 176 161 case VEC_PRIV: 162 + tsk->thread.trap_no = vector; 177 163 die_if_kernel("Kernel mode PRIV", regs, vector); 178 164 if (fpu_libc_helper(regs)) 179 165 return; ··· 186 164 sig = SIGSEGV; 187 165 break; 188 166 } 167 + 168 + tsk->thread.trap_no = vector; 169 + 189 170 send_sig(sig, current, 0); 190 171 }
+39 -6
arch/csky/mm/cachev2.c
··· 7 7 #include <asm/cache.h> 8 8 #include <asm/barrier.h> 9 9 10 + /* for L1-cache */ 10 11 #define INS_CACHE (1 << 0) 12 + #define DATA_CACHE (1 << 1) 11 13 #define CACHE_INV (1 << 4) 14 + #define CACHE_CLR (1 << 5) 15 + #define CACHE_OMS (1 << 6) 12 16 13 17 void local_icache_inv_all(void *priv) 14 18 { 15 19 mtcr("cr17", INS_CACHE|CACHE_INV); 16 20 sync_is(); 17 - } 18 - 19 - void icache_inv_all(void) 20 - { 21 - on_each_cpu(local_icache_inv_all, NULL, 1); 22 21 } 23 22 24 23 #ifdef CONFIG_CPU_HAS_ICACHE_INS ··· 30 31 sync_is(); 31 32 } 32 33 #else 34 + struct cache_range { 35 + unsigned long start; 36 + unsigned long end; 37 + }; 38 + 39 + static DEFINE_SPINLOCK(cache_lock); 40 + 41 + static inline void cache_op_line(unsigned long i, unsigned int val) 42 + { 43 + mtcr("cr22", i); 44 + mtcr("cr17", val); 45 + } 46 + 47 + void local_icache_inv_range(void *priv) 48 + { 49 + struct cache_range *param = priv; 50 + unsigned long i = param->start & ~(L1_CACHE_BYTES - 1); 51 + unsigned long flags; 52 + 53 + spin_lock_irqsave(&cache_lock, flags); 54 + 55 + for (; i < param->end; i += L1_CACHE_BYTES) 56 + cache_op_line(i, INS_CACHE | CACHE_INV | CACHE_OMS); 57 + 58 + spin_unlock_irqrestore(&cache_lock, flags); 59 + 60 + sync_is(); 61 + } 62 + 33 63 void icache_inv_range(unsigned long start, unsigned long end) 34 64 { 35 - icache_inv_all(); 65 + struct cache_range param = { start, end }; 66 + 67 + if (irqs_disabled()) 68 + local_icache_inv_range(&param); 69 + else 70 + on_each_cpu(local_icache_inv_range, &param, 1); 36 71 } 37 72 #endif 38 73
+11
arch/csky/mm/fault.c
··· 18 18 #include <linux/extable.h> 19 19 #include <linux/uaccess.h> 20 20 #include <linux/perf_event.h> 21 + #include <linux/kprobes.h> 21 22 22 23 #include <asm/hardirq.h> 23 24 #include <asm/mmu_context.h> ··· 53 52 int si_code; 54 53 int fault; 55 54 unsigned long address = mmu_meh & PAGE_MASK; 55 + 56 + if (kprobe_page_fault(regs, tsk->thread.trap_no)) 57 + return; 56 58 57 59 si_code = SEGV_MAPERR; 58 60 ··· 183 179 bad_area_nosemaphore: 184 180 /* User mode accesses just cause a SIGSEGV */ 185 181 if (user_mode(regs)) { 182 + tsk->thread.trap_no = (regs->sr >> 16) & 0xff; 186 183 force_sig_fault(SIGSEGV, si_code, (void __user *)address); 187 184 return; 188 185 } 189 186 190 187 no_context: 188 + tsk->thread.trap_no = (regs->sr >> 16) & 0xff; 189 + 191 190 /* Are we prepared to handle this kernel fault? */ 192 191 if (fixup_exception(regs)) 193 192 return; ··· 205 198 die_if_kernel("Oops", regs, write); 206 199 207 200 out_of_memory: 201 + tsk->thread.trap_no = (regs->sr >> 16) & 0xff; 202 + 208 203 /* 209 204 * We ran out of memory, call the OOM killer, and return the userspace 210 205 * (which will retry the fault, or kill us if we got oom-killed). ··· 215 206 return; 216 207 217 208 do_sigbus: 209 + tsk->thread.trap_no = (regs->sr >> 16) & 0xff; 210 + 218 211 up_read(&mm->mmap_sem); 219 212 220 213 /* Kernel mode? Handle exceptions or die */