[Concept,02/12] x86: Use MSR_FS_BASE for gd pointer on x86_64
Commit Message
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(-)
@@ -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)
@@ -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