riscv: Access gd with inline assembly when building with LTO or Clang
authorYao Zi <ziyao@disroot.org>
Sun, 27 Apr 2025 14:50:11 +0000 (14:50 +0000)
committerLeo Yu-Chi Liang <ycliang@andestech.com>
Wed, 21 May 2025 08:46:16 +0000 (16:46 +0800)
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 <ziyao@disroot.org>
Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
arch/riscv/cpu/cpu.c
arch/riscv/include/asm/global_data.h
common/board_r.c
common/init/board_init.c

index 5b31da6..15c4e14 100644 (file)
@@ -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);
+}
index d356752..47b5e2c 100644 (file)
@@ -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
index b90a4d9..41c8dec 100644 (file)
@@ -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;
index a06ec1c..2a6f39f 100644 (file)
 
 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;