diff options
Diffstat (limited to 'arch/riscv/kernel')
| -rw-r--r-- | arch/riscv/kernel/compat_vdso/Makefile | 4 | ||||
| -rw-r--r-- | arch/riscv/kernel/ftrace.c | 13 | ||||
| -rw-r--r-- | arch/riscv/kernel/patch.c | 28 | ||||
| -rw-r--r-- | arch/riscv/kernel/setup.c | 6 | ||||
| -rw-r--r-- | arch/riscv/kernel/signal.c | 9 | ||||
| -rw-r--r-- | arch/riscv/kernel/stacktrace.c | 2 | 
6 files changed, 50 insertions, 12 deletions
| diff --git a/arch/riscv/kernel/compat_vdso/Makefile b/arch/riscv/kernel/compat_vdso/Makefile index 260daf3236d3..7f34f3c7c882 100644 --- a/arch/riscv/kernel/compat_vdso/Makefile +++ b/arch/riscv/kernel/compat_vdso/Makefile @@ -14,6 +14,10 @@ COMPAT_LD := $(LD)  COMPAT_CC_FLAGS := -march=rv32g -mabi=ilp32  COMPAT_LD_FLAGS := -melf32lriscv +# Disable attributes, as they're useless and break the build. +COMPAT_CC_FLAGS += $(call cc-option,-mno-riscv-attribute) +COMPAT_CC_FLAGS += $(call as-option,-Wa$(comma)-mno-arch-attr) +  # Files to link into the compat_vdso  obj-compat_vdso = $(patsubst %, %.o, $(compat_vdso-syms)) note.o diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 5bff37af4770..03a6434a8cdd 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -15,10 +15,19 @@  void ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex)  {  	mutex_lock(&text_mutex); + +	/* +	 * The code sequences we use for ftrace can't be patched while the +	 * kernel is running, so we need to use stop_machine() to modify them +	 * for now.  This doesn't play nice with text_mutex, we use this flag +	 * to elide the check. +	 */ +	riscv_patch_in_stop_machine = true;  }  void ftrace_arch_code_modify_post_process(void) __releases(&text_mutex)  { +	riscv_patch_in_stop_machine = false;  	mutex_unlock(&text_mutex);  } @@ -107,9 +116,9 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)  {  	int out; -	ftrace_arch_code_modify_prepare(); +	mutex_lock(&text_mutex);  	out = ftrace_make_nop(mod, rec, MCOUNT_ADDR); -	ftrace_arch_code_modify_post_process(); +	mutex_unlock(&text_mutex);  	return out;  } diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index 8086d1a281cd..575e71d6c8ae 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -11,6 +11,7 @@  #include <asm/kprobes.h>  #include <asm/cacheflush.h>  #include <asm/fixmap.h> +#include <asm/ftrace.h>  #include <asm/patch.h>  struct patch_insn { @@ -20,6 +21,8 @@ struct patch_insn {  	atomic_t cpu_count;  }; +int riscv_patch_in_stop_machine = false; +  #ifdef CONFIG_MMU  /*   * The fix_to_virt(, idx) needs a const value (not a dynamic variable of @@ -60,8 +63,15 @@ static int patch_insn_write(void *addr, const void *insn, size_t len)  	 * Before reaching here, it was expected to lock the text_mutex  	 * already, so we don't need to give another lock here and could  	 * ensure that it was safe between each cores. +	 * +	 * We're currently using stop_machine() for ftrace & kprobes, and while +	 * that ensures text_mutex is held before installing the mappings it +	 * does not ensure text_mutex is held by the calling thread.  That's +	 * safe but triggers a lockdep failure, so just elide it for that +	 * specific case.  	 */ -	lockdep_assert_held(&text_mutex); +	if (!riscv_patch_in_stop_machine) +		lockdep_assert_held(&text_mutex);  	if (across_pages)  		patch_map(addr + len, FIX_TEXT_POKE1); @@ -125,6 +135,7 @@ NOKPROBE_SYMBOL(patch_text_cb);  int patch_text(void *addr, u32 *insns, int ninsns)  { +	int ret;  	struct patch_insn patch = {  		.addr = addr,  		.insns = insns, @@ -132,7 +143,18 @@ int patch_text(void *addr, u32 *insns, int ninsns)  		.cpu_count = ATOMIC_INIT(0),  	}; -	return stop_machine_cpuslocked(patch_text_cb, -				       &patch, cpu_online_mask); +	/* +	 * kprobes takes text_mutex, before calling patch_text(), but as we call +	 * calls stop_machine(), the lockdep assertion in patch_insn_write() +	 * gets confused by the context in which the lock is taken. +	 * Instead, ensure the lock is held before calling stop_machine(), and +	 * set riscv_patch_in_stop_machine to skip the check in +	 * patch_insn_write(). +	 */ +	lockdep_assert_held(&text_mutex); +	riscv_patch_in_stop_machine = true; +	ret = stop_machine_cpuslocked(patch_text_cb, &patch, cpu_online_mask); +	riscv_patch_in_stop_machine = false; +	return ret;  }  NOKPROBE_SYMBOL(patch_text); diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 376d2827e736..a059b73f4ddb 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -278,12 +278,8 @@ void __init setup_arch(char **cmdline_p)  #if IS_ENABLED(CONFIG_BUILTIN_DTB)  	unflatten_and_copy_device_tree();  #else -	if (early_init_dt_verify(__va(XIP_FIXUP(dtb_early_pa)))) -		unflatten_device_tree(); -	else -		pr_err("No DTB found in kernel mappings\n"); +	unflatten_device_tree();  #endif -	early_init_fdt_scan_reserved_mem();  	misc_mem_init();  	init_resources(); diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index bfb2afa4135f..dee66c9290cc 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -19,6 +19,7 @@  #include <asm/signal32.h>  #include <asm/switch_to.h>  #include <asm/csr.h> +#include <asm/cacheflush.h>  extern u32 __user_rt_sigreturn[2]; @@ -181,6 +182,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,  {  	struct rt_sigframe __user *frame;  	long err = 0; +	unsigned long __maybe_unused addr;  	frame = get_sigframe(ksig, regs, sizeof(*frame));  	if (!access_ok(frame, sizeof(*frame))) @@ -209,7 +211,12 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,  	if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn,  			 sizeof(frame->sigreturn_code)))  		return -EFAULT; -	regs->ra = (unsigned long)&frame->sigreturn_code; + +	addr = (unsigned long)&frame->sigreturn_code; +	/* Make sure the two instructions are pushed to icache. */ +	flush_icache_range(addr, addr + sizeof(frame->sigreturn_code)); + +	regs->ra = addr;  #endif /* CONFIG_MMU */  	/* diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index f9a5a7c90ff0..64a9c093aef9 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -101,7 +101,7 @@ void notrace walk_stackframe(struct task_struct *task,  	while (!kstack_end(ksp)) {  		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))  			break; -		pc = (*ksp++) - 0x4; +		pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;  	}  } |