[Concept,02/12] x86: Use MSR_FS_BASE for gd pointer on x86_64

Message ID 20260211143309.1183113-3-sjg@u-boot.org
State New
Headers
Series x86: Add single 64-bit U-Boot without SPL for QEMU |

Commit Message

Simon Glass Feb. 11, 2026, 2:32 p.m. UTC
  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(-)
  

Patch

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