The register variable form of gd cannot be used with LTO (GCC bug 68384). The LTO link fails with "multiple definition of `r2'". In LTO builds define gd through inline assembly accessors that read and write r2, following ARM and RISC-V. Other builds keep the register variable, and set_gd() assigns it.
Every assignment to gd has to go through set_gd() for that to work, so convert all PowerPC ones, including those in common code, and give PowerPC its own arch_setup_gd() in the new arch/powerpc/lib/gd.c instead of the weak one, which assigns gd. Rename the gd parameter of the SPL board_init_r() functions, which the gd macro would otherwise replace. Signed-off-by: Josef Schlehofer <[email protected]> Reviewed-by: Marek Mojík <[email protected]> Cc: Marek Behún <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Mario Six <[email protected]> Cc: Priyanka Jain <[email protected]> Cc: Qiang Zhao <[email protected]> Cc: Peng Fan <[email protected]> Cc: Shengzhou Liu <[email protected]> Cc: Marek Mojík <[email protected]> --- (no changes since v1) The mpc83xx and common/spl/spl.c hunks change no build: mpc83xx cannot enable LTO and no PowerPC board builds common/spl/spl.c. They are converted so that no PowerPC code assigns gd directly. Unlike on ARM and RISC-V, set_gd() assigns the register variable in builds without LTO. GCC requires inline assembly that accesses a global register variable to declare that access through constraints. In the T-series SPLs, the board_init_r() bodies now use the global gd instead of the parameter. relocate_code() passes the CONFIG_SPL_GD_ADDR that board_init_f() has already set as gd and leaves r2 alone, so the pointer is the same. checkpatch asks for IS_ENABLED() on the #if lines in common/board_r.c, common/init/board_init.c and common/spl/spl.c. They choose how gd is set per architecture: set_gd() exists only on ARM, RISC-V and PowerPC, so IS_ENABLED() cannot replace them. The new arch/powerpc/lib/gd.c is covered by the POWERPC entry in MAINTAINERS. --- arch/powerpc/cpu/mpc83xx/cpu_init.c | 3 +-- arch/powerpc/cpu/mpc83xx/spl_minimal.c | 3 +-- arch/powerpc/cpu/mpc85xx/cpu_init_early.c | 3 +-- arch/powerpc/include/asm/global_data.h | 30 +++++++++++++++++++++++ arch/powerpc/lib/Makefile | 1 + arch/powerpc/lib/gd.c | 14 +++++++++++ board/nxp/p1010rdb/spl_minimal.c | 2 +- board/nxp/p1_p2_rdb_pc/spl_minimal.c | 2 +- board/nxp/t102xrdb/spl.c | 4 +-- board/nxp/t104xrdb/spl.c | 4 +-- board/nxp/t208xqds/spl.c | 4 +-- board/nxp/t208xrdb/spl.c | 4 +-- board/nxp/t4rdb/spl.c | 4 +-- common/board_r.c | 2 +- common/init/board_init.c | 9 ++++--- common/spl/spl.c | 4 ++- 16 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 arch/powerpc/lib/gd.c diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c index 340f9a0da56..5618b79a78b 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c @@ -139,8 +139,7 @@ void cpu_init_f (volatile immap_t * im) #endif 0; - /* Pointer is writable since we allocated a register for it */ - gd = (gd_t *)SYS_INIT_SP_ADDR; + set_gd((gd_t *)SYS_INIT_SP_ADDR); /* global data region was cleared in start.S */ diff --git a/arch/powerpc/cpu/mpc83xx/spl_minimal.c b/arch/powerpc/cpu/mpc83xx/spl_minimal.c index 7036e3fae0c..1d48428573d 100644 --- a/arch/powerpc/cpu/mpc83xx/spl_minimal.c +++ b/arch/powerpc/cpu/mpc83xx/spl_minimal.c @@ -25,8 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; */ void cpu_init_f (volatile immap_t * im) { - /* Pointer is writable since we allocated a register for it */ - gd = (gd_t *)SYS_INIT_SP_ADDR; + set_gd((gd_t *)SYS_INIT_SP_ADDR); /* global data region was cleared in start.S */ diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c index 75bfc07fe97..fb3d662c9d3 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c @@ -95,8 +95,7 @@ void cpu_init_early_f(void *fdt) int i; #endif - /* Pointer is writable since we allocated a register for it */ - gd = (gd_t *)SYS_INIT_SP_ADDR; + set_gd((gd_t *)SYS_INIT_SP_ADDR); /* gd area was zeroed during startup */ diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 26cbc7854d9..d8aefd2ca0a 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -93,8 +93,38 @@ struct arch_global_data { #include <asm-generic/global_data.h> +#ifdef LTO_ENABLE + +#define DECLARE_GLOBAL_DATA_PTR +#define gd get_gd() + +static inline gd_t *get_gd(void) +{ + gd_t *gd_ptr; + + __asm__ volatile("mr %0, 2\n" : "=r" (gd_ptr)); + + return gd_ptr; +} + +static inline void set_gd(gd_t *gd_ptr) +{ + __asm__ volatile("mr 2, %0\n" : : "r" (gd_ptr)); +} + +#else + #define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("r2") +/* + * GCC does not see an asm statement write r2 and assumes that the + * register variable is unchanged, so it may move gd accesses across the + * write. Assign the variable itself. + */ +#define set_gd(gd_ptr) (gd = (gd_ptr)) + +#endif + #include <asm/u-boot.h> #endif /* __ASM_GBL_DATA_H */ diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index c0caa703caa..a3048975ae7 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -18,6 +18,7 @@ endif endif obj-y += bdinfo.o +obj-y += gd.o ifdef MINIMAL obj-y += cache.o time.o diff --git a/arch/powerpc/lib/gd.c b/arch/powerpc/lib/gd.c new file mode 100644 index 00000000000..d36f784fbf7 --- /dev/null +++ b/arch/powerpc/lib/gd.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Josef Schlehofer <[email protected]> + */ + +#include <init.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +void arch_setup_gd(gd_t *new_gd) +{ + set_gd(new_gd); +} diff --git a/board/nxp/p1010rdb/spl_minimal.c b/board/nxp/p1010rdb/spl_minimal.c index 8cd79c6fb5f..33930fef8d9 100644 --- a/board/nxp/p1010rdb/spl_minimal.c +++ b/board/nxp/p1010rdb/spl_minimal.c @@ -45,7 +45,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { puts("\nSecond program loader running in sram..."); nand_boot(); diff --git a/board/nxp/p1_p2_rdb_pc/spl_minimal.c b/board/nxp/p1_p2_rdb_pc/spl_minimal.c index 511bcf5506b..960b2c41457 100644 --- a/board/nxp/p1_p2_rdb_pc/spl_minimal.c +++ b/board/nxp/p1_p2_rdb_pc/spl_minimal.c @@ -43,7 +43,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { puts("\nSecond program loader running in sram..."); nand_boot(); diff --git a/board/nxp/t102xrdb/spl.c b/board/nxp/t102xrdb/spl.c index de6cdda194e..f527f62a5dd 100644 --- a/board/nxp/t102xrdb/spl.c +++ b/board/nxp/t102xrdb/spl.c @@ -58,7 +58,7 @@ void board_init_f(ulong bootflag) memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(gd_t)); /* Update GD pointer */ - gd = (gd_t *)(CONFIG_SPL_GD_ADDR); + set_gd((gd_t *)(CONFIG_SPL_GD_ADDR)); console_init_f(); @@ -87,7 +87,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, (gd_t *)CONFIG_SPL_GD_ADDR, 0x0); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { struct bd_info *bd; diff --git a/board/nxp/t104xrdb/spl.c b/board/nxp/t104xrdb/spl.c index e02a1f95d4c..0310baa381c 100644 --- a/board/nxp/t104xrdb/spl.c +++ b/board/nxp/t104xrdb/spl.c @@ -55,7 +55,7 @@ void board_init_f(ulong bootflag) memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(gd_t)); /* Update GD pointer */ - gd = (gd_t *)(CONFIG_SPL_GD_ADDR); + set_gd((gd_t *)(CONFIG_SPL_GD_ADDR)); #ifdef CONFIG_DEEP_SLEEP /* disable the console if boot from deep sleep */ @@ -78,7 +78,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, (gd_t *)CONFIG_SPL_GD_ADDR, 0x0); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { struct bd_info *bd; diff --git a/board/nxp/t208xqds/spl.c b/board/nxp/t208xqds/spl.c index 44ad4e68d9f..f8c641a9c64 100644 --- a/board/nxp/t208xqds/spl.c +++ b/board/nxp/t208xqds/spl.c @@ -73,7 +73,7 @@ void board_init_f(ulong bootflag) memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(gd_t)); /* Update GD pointer */ - gd = (gd_t *)(CONFIG_SPL_GD_ADDR); + set_gd((gd_t *)(CONFIG_SPL_GD_ADDR)); console_init_f(); @@ -96,7 +96,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, (gd_t *)CONFIG_SPL_GD_ADDR, 0x0); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { struct bd_info *bd; diff --git a/board/nxp/t208xrdb/spl.c b/board/nxp/t208xrdb/spl.c index df3b9c6fe40..4b1ab3618c3 100644 --- a/board/nxp/t208xrdb/spl.c +++ b/board/nxp/t208xrdb/spl.c @@ -33,7 +33,7 @@ void board_init_f(ulong bootflag) memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(gd_t)); /* Update GD pointer */ - gd = (gd_t *)(CONFIG_SPL_GD_ADDR); + set_gd((gd_t *)(CONFIG_SPL_GD_ADDR)); console_init_f(); @@ -56,7 +56,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, (gd_t *)CONFIG_SPL_GD_ADDR, 0x0); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { struct bd_info *bd; diff --git a/board/nxp/t4rdb/spl.c b/board/nxp/t4rdb/spl.c index 9d2472dec25..441015bf5a4 100644 --- a/board/nxp/t4rdb/spl.c +++ b/board/nxp/t4rdb/spl.c @@ -39,7 +39,7 @@ void board_init_f(ulong bootflag) memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(gd_t)); /* Update GD pointer */ - gd = (gd_t *)(CONFIG_SPL_GD_ADDR); + set_gd((gd_t *)(CONFIG_SPL_GD_ADDR)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("" : : : "memory"); @@ -59,7 +59,7 @@ void board_init_f(ulong bootflag) relocate_code(CONFIG_SPL_RELOC_STACK, (gd_t *)CONFIG_SPL_GD_ADDR, 0x0); } -void board_init_r(gd_t *gd, ulong dest_addr) +void board_init_r(gd_t *dummy, ulong dest_addr) { struct bd_info *bd; diff --git a/common/board_r.c b/common/board_r.c index a397e20959d..7a9de6ba5f3 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -796,7 +796,7 @@ 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_RISCV) +#if defined(CONFIG_RISCV) || defined(CONFIG_PPC) set_gd(new_gd); #elif !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) gd = new_gd; diff --git a/common/init/board_init.c b/common/init/board_init.c index 2a6f39f51ad..2faea5432c0 100644 --- a/common/init/board_init.c +++ b/common/init/board_init.c @@ -14,15 +14,16 @@ DECLARE_GLOBAL_DATA_PTR; /* - * Unfortunately x86, ARM and RISC-V can't compile this code as gd is defined - * as macro and cannot be assigned. + * x86, RISC-V and PowerPC provide their own arch_setup_gd(), and ARM does + * not call it. */ -#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) +#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) && \ + !defined(CONFIG_PPC) __weak void arch_setup_gd(struct global_data *gd_ptr) { gd = gd_ptr; } -#endif /* !CONFIG_X86 && !CONFIG_ARM */ +#endif /* !CONFIG_X86 && !CONFIG_ARM && !CONFIG_RISCV && !CONFIG_PPC */ /** * This function is called from board_init_f_init_reserve to set up diff --git a/common/spl/spl.c b/common/spl/spl.c index 6c9a1a1cbcc..81aec2b1108 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -956,7 +956,9 @@ ulong spl_relocate_stack_gd(void) #if CONFIG_IS_ENABLED(LOG) log_fixup_for_gd_move(new_gd); #endif -#if !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) +#if defined(CONFIG_PPC) + set_gd(new_gd); +#elif !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) gd = new_gd; #endif return ptr; -- 2.54.0 (Apple Git-157)
