riscv: Access gd with inline assembly when building with LTO or Clang

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>
This commit is contained in:
Yao Zi
2025-04-27 14:50:11 +00:00
committed by Leo Yu-Chi Liang
parent 6016308094
commit 307666be28
4 changed files with 33 additions and 3 deletions

View 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);
}

View 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

View 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;

View File

@@ -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;