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