[PATCH 2/2] riscv: Access gd with inline assembly when building with LTO or Clang
Yao Zi
ziyao at disroot.org
Sun Apr 27 16:50:11 CEST 2025
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 at nathaniel.land>
Signed-off-by: Yao Zi <ziyao at 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
More information about the U-Boot
mailing list