git: 4b136ef259ce - main - amd64: Set GS.base before calling init_secondary() on APs

Mark Johnston markj at FreeBSD.org
Thu Jul 29 14:49:14 UTC 2021


The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=4b136ef259cefedc9b6404afc09138aeb8acbd91

commit 4b136ef259cefedc9b6404afc09138aeb8acbd91
Author:     Mark Johnston <markj at FreeBSD.org>
AuthorDate: 2021-07-29 14:22:37 +0000
Commit:     Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-07-29 14:22:37 +0000

    amd64: Set GS.base before calling init_secondary() on APs
    
    KMSAN instrumentation requires thread-local storage to track
    initialization state for function parameters and return values.  This
    buffer is accessed as part of each function prologue.  It is provided by
    the KMSAN runtime, which looks up a pointer in the current thread's
    structure.
    
    When KMSAN is configured, init_secondary() is instrumented, but this
    means that GS.base must be initialized first, otherwise the runtime
    cannot safely access curthread.  Work around this by loading GS.base
    before calling init_secondary(), so that the runtime can at least check
    curthread == NULL and return a pointer to some dummy storage.  Note that
    init_secondary() still must reload GS.base after calling lgdt(), which
    loads a selector into %gs, which in turn clears the base register.
    
    Reviewed by:    kib
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D31336
---
 sys/amd64/amd64/mp_machdep.c |  8 ++++----
 sys/amd64/amd64/mpboot.S     | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 86a5d78c8a8e..343589ae4c6a 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -103,6 +103,7 @@ static char *doublefault_stack;
 static char *mce_stack;
 static char *nmi_stack;
 static char *dbg_stack;
+void *bootpcpu;
 
 extern u_int mptramp_la57;
 extern u_int mptramp_nx;
@@ -197,10 +198,8 @@ init_secondary(void)
 	/* Update microcode before doing anything else. */
 	ucode_load_ap(cpu);
 
-	/* Get per-cpu data and save  */
-	pc = &__pcpu[cpu];
-
-	/* prime data page for it to use */
+	/* Initialize the PCPU area. */
+	pc = bootpcpu;
 	pcpu_init(pc, cpu, sizeof(struct pcpu));
 	dpcpu_init(dpcpu, cpu);
 	pc->pc_apic_id = cpu_apic_ids[cpu];
@@ -431,6 +430,7 @@ start_all_aps(void)
 		dpcpu = (void *)kmem_malloc_domainset(DOMAINSET_PREF(domain),
 		    DPCPU_SIZE, M_WAITOK | M_ZERO);
 
+		bootpcpu = &__pcpu[cpu];
 		bootSTK = (char *)bootstacks[cpu] +
 		    kstack_pages * PAGE_SIZE - 8;
 		bootAP = cpu;
diff --git a/sys/amd64/amd64/mpboot.S b/sys/amd64/amd64/mpboot.S
index b6c599a2aff3..1b5657d3bef8 100644
--- a/sys/amd64/amd64/mpboot.S
+++ b/sys/amd64/amd64/mpboot.S
@@ -260,4 +260,21 @@ bootMP_size:
 	.p2align 4,0
 entry_64:
 	movq	bootSTK, %rsp
+
+	/*
+	 * Initialize the segment register used for the PCPU area.  The PCPU
+	 * area will be initialized by init_secondary(), but it should be
+	 * accessible before that to support sanitizer instrumentation which
+	 * accesses per-CPU variables.
+	 *
+	 * Note that GS.base is loaded again in init_secondary().  This is not
+	 * redundant: lgdt() loads a selector into %gs and this has the side
+	 * effect of clearing GS.base.
+	 */
+	movl	$MSR_GSBASE, %ecx
+	movq	bootpcpu, %rax
+	movq	%rax, %rdx
+	shrq	$32, %rdx
+	wrmsr
+
 	jmp	init_secondary


More information about the dev-commits-src-all mailing list