From e859cfc75076eeaf798c440a4aba40f79536839c Mon Sep 17 00:00:00 2001
From: Heiko Stuebner <heiko@sntech.de>
Date: Fri, 10 Dec 2021 16:19:19 +0100
Subject: [PATCH 01/14] riscv: prevent null-pointer dereference with
 sbi_remote_fence_i

The callback used inside sbi_remote_fence_i is set at sbi probe time
to the needed variant. Before that it is a NULL pointer.

flush_icache_all is from its name a pretty generic functionality
so probably shoudln't get a "only call after boot-step X" limit.

To prevent running into a null pointer dereference, add a default
__sbi_rfence_none returning an error code and adapt flush_icache_all
to check for an error from the remote fence to then fall back to a
simple local_icache_flush(), as that could really only happen if
called before other cpu cores are brought up.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/riscv/kernel/sbi.c    | 10 +++++++++-
 arch/riscv/mm/cacheflush.c | 15 ++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
index 2438d6fdb788..7f7a9630dc89 100644
--- a/arch/riscv/kernel/sbi.c
+++ b/arch/riscv/kernel/sbi.c
@@ -14,11 +14,19 @@
 unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT;
 EXPORT_SYMBOL(sbi_spec_version);
 
+static int __sbi_rfence_none(int fid, const struct cpumask *cpu_mask,
+			     unsigned long start, unsigned long size,
+			     unsigned long arg4, unsigned long arg5)
+{
+	return -EOPNOTSUPP;
+}
+
 static void (*__sbi_set_timer)(uint64_t stime) __ro_after_init;
 static int (*__sbi_send_ipi)(const struct cpumask *cpu_mask) __ro_after_init;
 static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask,
 			   unsigned long start, unsigned long size,
-			   unsigned long arg4, unsigned long arg5) __ro_after_init;
+			   unsigned long arg4, unsigned long arg5)
+			   __ro_after_init = __sbi_rfence_none;
 
 struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
 			unsigned long arg1, unsigned long arg2,
diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c
index 6cb7d96ad9c7..ea9634450557 100644
--- a/arch/riscv/mm/cacheflush.c
+++ b/arch/riscv/mm/cacheflush.c
@@ -18,10 +18,19 @@ void flush_icache_all(void)
 {
 	local_flush_icache_all();
 
-	if (IS_ENABLED(CONFIG_RISCV_SBI))
-		sbi_remote_fence_i(NULL);
-	else
+	if (IS_ENABLED(CONFIG_RISCV_SBI)) {
+		int ret = sbi_remote_fence_i(NULL);
+
+		/*
+		 * Only fails when sbi-init hasn't run yet, so the kernel
+		 * also is before SMP init, so flushing the local cpu
+		 * is enough.
+		 */
+		if (ret)
+			local_flush_icache_all();
+	} else {
 		on_each_cpu(ipi_remote_fence_i, NULL, 1);
+	}
 }
 EXPORT_SYMBOL(flush_icache_all);
 
-- 
2.30.2

