From: Simon Glass <simon.glass@canonical.com> The x86_64 global data pointer currently relies on a writable global_data_ptr variable in the .data section, which needs RAM to be available before relocation. Use MSR_FS_BASE to hold the address of gd->arch.gd_addr instead, mirroring how 32-bit x86 uses the FS segment descriptor base. Remove the global_data_ptr variable from misc.c and update arch_setup_gd() to call set_gd(). Separate the EFI_APP and X86_64 cases in global_data.h so each has its own set_gd() implementation. Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- arch/x86/cpu/x86_64/misc.c | 12 ++---------- arch/x86/include/asm/global_data.h | 26 ++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/arch/x86/cpu/x86_64/misc.c b/arch/x86/cpu/x86_64/misc.c index fc449ca4ed6..cb953a92eee 100644 --- a/arch/x86/cpu/x86_64/misc.c +++ b/arch/x86/cpu/x86_64/misc.c @@ -5,21 +5,13 @@ */ #include <init.h> +#include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; -/* - * Global declaration of gd. - * - * As we write to it before relocation we have to make sure it is not put into - * a .bss section which may overlap a .rela section. Initialization forces it - * into a .data section which cannot overlap any .rela section. - */ -struct global_data *global_data_ptr = (struct global_data *)~0; - void arch_setup_gd(gd_t *new_gd) { - global_data_ptr = new_gd; + set_gd(new_gd); } int misc_init_r(void) diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 0d9fa823121..1b614067f76 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -10,6 +10,7 @@ #ifndef __ASSEMBLY__ #include <linux/types.h> +#include <asm/msr-index.h> #include <asm/processor.h> #include <asm/mrccache.h> #include <asm/u-boot.h> @@ -137,9 +138,8 @@ struct arch_global_data { #include <asm-generic/global_data.h> #ifndef __ASSEMBLY__ -# if defined(CONFIG_EFI_APP) || CONFIG_IS_ENABLED(X86_64) +# if defined(CONFIG_EFI_APP) -/* TODO(sjg@chromium.org): Consider using a fixed register for gd on x86_64 */ #define gd global_data_ptr static inline void set_gd(volatile gd_t *gd_ptr) @@ -166,6 +166,28 @@ static inline notrace gd_t *get_fs_gd_ptr(void) #define gd get_fs_gd_ptr() +#if CONFIG_IS_ENABLED(X86_64) +/* + * On x86_64, use MSR_FS_BASE to hold the address of gd->arch.gd_addr, mirroring + * how 32-bit x86 uses the FS segment descriptor base. This avoids the need for + * a writable global_data_ptr variable, which would require the .data section to + * be in RAM before relocation. + */ +static inline void set_gd(volatile gd_t *gd_ptr) +{ + gd_t *p = (gd_t *)gd_ptr; + unsigned long addr; + + p->arch.gd_addr = p; + addr = (unsigned long)&p->arch.gd_addr; + asm volatile("wrmsr" : : + "c" (MSR_FS_BASE), + "a" ((unsigned int)addr), + "d" ((unsigned int)(addr >> 32)) + : "memory"); +} +#endif + #define DECLARE_GLOBAL_DATA_PTR # endif -- 2.43.0