Similar to AArch64's case, Clang may wrongly fold accesses to gd pointer
which is defined with register qualifier into constants, breaking
various components.

This patch defines gd as a macro when building with Clang or LTO, which
expands to get_gd() that accesses gp pointer in assembly, making RISC-V
ports function properly and preparing for introduction of LTO in the
future. Board initialization code is also adapted for non-assignable gd.

Reported-by: Nathaniel Hourt <i...@nathaniel.land>
Signed-off-by: Yao Zi <zi...@disroot.org>
---
 arch/riscv/cpu/cpu.c                 |  6 ++++++
 arch/riscv/include/asm/global_data.h | 19 +++++++++++++++++++
 common/board_r.c                     |  4 +++-
 common/init/board_init.c             |  7 +++++--
 4 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index 5b31da64cbd..15c4e14599d 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -18,6 +18,7 @@
 #include <asm/hwcap.h>
 #include <asm/cpufeature.h>
 #include <asm/cache.h>
+#include <asm/global_data.h>
 #include <dm/uclass-internal.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
@@ -746,3 +747,8 @@ __weak int cleanup_before_linux(void)
 
        return 0;
 }
+
+void arch_setup_gd(gd_t *new_gd)
+{
+       set_gd(new_gd);
+}
diff --git a/arch/riscv/include/asm/global_data.h 
b/arch/riscv/include/asm/global_data.h
index d356752a56a..47b5e2cfc8f 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -14,6 +14,7 @@
 #include <asm/smp.h>
 #include <asm/u-boot.h>
 #include <compiler.h>
+#include <config.h>
 
 /* Architecture-specific global data */
 struct arch_global_data {
@@ -47,8 +48,26 @@ struct arch_global_data {
 
 #include <asm-generic/global_data.h>
 
+#if defined(__clang__) || CONFIG_IS_ENABLED(LTO)
+
+#define DECLARE_GLOBAL_DATA_PTR
+#define gd                     get_gd()
+
+static inline gd_t *get_gd(void)
+{
+       gd_t *gd_ptr;
+
+       __asm__ volatile ("mv %0, gp\n" : "=r" (gd_ptr));
+
+       return gd_ptr;
+}
+
+#else
+
 #define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("gp")
 
+#endif
+
 static inline void set_gd(volatile gd_t *gd_ptr)
 {
 #ifdef CONFIG_64BIT
diff --git a/common/board_r.c b/common/board_r.c
index bc6fd6448c2..4fa092ab596 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -815,7 +815,9 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
        if (CONFIG_IS_ENABLED(X86_64) && !IS_ENABLED(CONFIG_EFI_APP))
                arch_setup_gd(new_gd);
 
-#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+#if defined(CONFIG_RISCV)
+       set_gd(new_gd);
+#elif !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
        gd = new_gd;
 #endif
        gd->flags &= ~GD_FLG_LOG_READY;
diff --git a/common/init/board_init.c b/common/init/board_init.c
index a06ec1caa2c..2a6f39f51ad 100644
--- a/common/init/board_init.c
+++ b/common/init/board_init.c
@@ -13,8 +13,11 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Unfortunately x86 or ARM can't compile this code as gd cannot be assigned */
-#if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
+/*
+ * Unfortunately x86, ARM and RISC-V can't compile this code as gd is defined
+ * as macro and cannot be assigned.
+ */
+#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_RISCV)
 __weak void arch_setup_gd(struct global_data *gd_ptr)
 {
        gd = gd_ptr;
-- 
2.49.0

Reply via email to