git: b27fe1c3ba2a - main - amd64: stop doing special allocation for the AP startup trampoline

Konstantin Belousov kib at FreeBSD.org
Thu Jul 29 22:21:06 UTC 2021


The branch main has been updated by kib:

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

commit b27fe1c3ba2a1302c2866751e0c618b5a697bf30
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-07-29 00:22:35 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-07-29 22:20:45 +0000

    amd64: stop doing special allocation for the AP startup trampoline
    
    There is no reason now why do we need to allocate trampoline page very
    early in the boot process.  The only requirement for the page is that
    it is below 1M to be usable by the real mode during init.  This can be
    handled by vm_alloc_contig() when we do the startup.
    
    Also assert that startup trampoline fits into single page.  In principle
    we can do multi-page allocation if needed, but it is not.
    
    Move the alloc_ap_trampoline() function and the boot_address variable to
    i386/mp_machdep.c.  Keep existing mechanism of early alloc on i386.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Differential revision:  https://reviews.freebsd.org/D31343
---
 sys/amd64/amd64/machdep.c    | 10 --------
 sys/amd64/amd64/mp_machdep.c | 19 +++++++++++----
 sys/i386/i386/mp_machdep.c   | 55 ++++++++++++++++++++++++++++++++++++++++++++
 sys/x86/include/x86_smp.h    | 10 ++++++--
 sys/x86/x86/mp_x86.c         | 54 -------------------------------------------
 5 files changed, 77 insertions(+), 71 deletions(-)

diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 49e245e1fdfe..0cb72314e68d 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1272,16 +1272,6 @@ getmemsize(caddr_t kmdp, u_int64_t first)
 	    (boothowto & RB_VERBOSE))
 		printf("Physical memory use set to %ldK\n", Maxmem * 4);
 
-	/*
-	 * Make hole for "AP -> long mode" bootstrap code.  The
-	 * mp_bootaddress vector is only available when the kernel
-	 * is configured to support APs and APs for the system start
-	 * in real mode mode (e.g. SMP bare metal).
-	 */
-#ifdef SMP
-	alloc_ap_trampoline(physmap, &physmap_idx);
-#endif
-
 	/* call pmap initialization to make new kernel address space */
 	pmap_bootstrap(&first);
 
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 343589ae4c6a..62f715fd6ed3 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -112,7 +112,7 @@ extern u_int mptramp_nx;
  * Local data and functions.
  */
 
-static int	start_ap(int apic_id);
+static int start_ap(int apic_id, vm_paddr_t boot_address);
 
 /*
  * Initialize the IPI handlers and start up the AP's.
@@ -322,17 +322,25 @@ mp_realloc_pcpu(int cpuid, int domain)
 int
 start_all_aps(void)
 {
-	vm_page_t m_pml4, m_pdp, m_pd[4];
+	vm_page_t m_boottramp, m_pml4, m_pdp, m_pd[4];
 	pml5_entry_t old_pml45;
 	pml4_entry_t *v_pml4;
 	pdp_entry_t *v_pdp;
 	pd_entry_t *v_pd;
+	vm_paddr_t boot_address;
 	u_int32_t mpbioswarmvec;
 	int apic_id, cpu, domain, i;
 	u_char mpbiosreason;
 
 	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
 
+	MPASS(bootMP_size <= PAGE_SIZE);
+	m_boottramp = vm_page_alloc_contig(NULL, 0, VM_ALLOC_NORMAL |
+	    VM_ALLOC_NOBUSY | VM_ALLOC_NOOBJ, 1, 0,
+	    (1ULL << 20), /* Trampoline should be below 1M for real mode */
+	    PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+	boot_address = VM_PAGE_TO_PHYS(m_boottramp);
+
 	/* Create a transient 1:1 mapping of low 4G */
 	if (la57) {
 		m_pml4 = pmap_page_alloc_below_4g(true);
@@ -382,7 +390,7 @@ start_all_aps(void)
 	/* copy the AP 1st level boot code */
 	bcopy(mptramp_start, (void *)PHYS_TO_DMAP(boot_address), bootMP_size);
 	if (bootverbose)
-		printf("AP boot address %#x\n", boot_address);
+		printf("AP boot address %#lx\n", boot_address);
 
 	/* save the current value of the warm-start vector */
 	if (!efi_boot)
@@ -436,7 +444,7 @@ start_all_aps(void)
 		bootAP = cpu;
 
 		/* attempt to start the Application Processor */
-		if (!start_ap(apic_id)) {
+		if (!start_ap(apic_id, boot_address)) {
 			/* restore the warmstart vector */
 			*(u_int32_t *) WARMBOOT_OFF = mpbioswarmvec;
 			panic("AP #%d (PHY# %d) failed!", cpu, apic_id);
@@ -461,6 +469,7 @@ start_all_aps(void)
 	vm_page_free(m_pd[1]);
 	vm_page_free(m_pd[0]);
 	vm_page_free(m_pdp);
+	vm_page_free(m_boottramp);
 
 	/* number of APs actually started */
 	return (mp_naps);
@@ -474,7 +483,7 @@ start_all_aps(void)
  * but it seems to work.
  */
 static int
-start_ap(int apic_id)
+start_ap(int apic_id, vm_paddr_t boot_address)
 {
 	int vector, ms;
 	int cpus;
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 91ca6945f1ae..156702118c45 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -147,6 +147,61 @@ static int	start_ap(int apic_id);
 
 static char *ap_copyout_buf;
 static char *ap_tramp_stack_base;
+
+unsigned int boot_address;
+
+#define MiB(v)	(v ## ULL << 20)
+
+/* Allocate memory for the AP trampoline. */
+void
+alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx)
+{
+	unsigned int i;
+	bool allocated;
+
+	allocated = false;
+	for (i = *physmap_idx; i <= *physmap_idx; i -= 2) {
+		/*
+		 * Find a memory region big enough and below the 1MB boundary
+		 * for the trampoline code.
+		 * NB: needs to be page aligned.
+		 */
+		if (physmap[i] >= MiB(1) ||
+		    (trunc_page(physmap[i + 1]) - round_page(physmap[i])) <
+		    round_page(bootMP_size))
+			continue;
+
+		allocated = true;
+		/*
+		 * Try to steal from the end of the region to mimic previous
+		 * behaviour, else fallback to steal from the start.
+		 */
+		if (physmap[i + 1] < MiB(1)) {
+			boot_address = trunc_page(physmap[i + 1]);
+			if ((physmap[i + 1] - boot_address) < bootMP_size)
+				boot_address -= round_page(bootMP_size);
+			physmap[i + 1] = boot_address;
+		} else {
+			boot_address = round_page(physmap[i]);
+			physmap[i] = boot_address + round_page(bootMP_size);
+		}
+		if (physmap[i] == physmap[i + 1] && *physmap_idx != 0) {
+			memmove(&physmap[i], &physmap[i + 2],
+			    sizeof(*physmap) * (*physmap_idx - i + 2));
+			*physmap_idx -= 2;
+		}
+		break;
+	}
+
+	if (!allocated) {
+		boot_address = basemem * 1024 - bootMP_size;
+		if (bootverbose)
+			printf(
+"Cannot find enough space for the boot trampoline, placing it at %#x",
+			    boot_address);
+	}
+}
+
 /*
  * Initialize the IPI handlers and start up the AP's.
  */
diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h
index e01f869a58f6..b9a1febb70f2 100644
--- a/sys/x86/include/x86_smp.h
+++ b/sys/x86/include/x86_smp.h
@@ -23,6 +23,10 @@
 
 struct pmap;
 
+#ifdef __i386__
+extern unsigned int boot_address;
+#endif
+
 /* global data in mp_x86.c */
 extern int mp_naps;
 extern int boot_cpu_id;
@@ -32,7 +36,6 @@ extern int bootAP;
 extern void *dpcpu;
 extern char *bootSTK;
 extern void *bootstacks[];
-extern unsigned int boot_address;
 extern unsigned int bootMP_size;
 extern volatile int aps_ready;
 extern struct mtx ap_boot_mtx;
@@ -84,12 +87,15 @@ inthand_t
 typedef void (*smp_invl_cb_t)(struct pmap *, vm_offset_t addr1,
     vm_offset_t addr2);
 
+#ifdef __i386__
+void	alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx);
+#endif
+
 /* functions in x86_mp.c */
 void	assign_cpu_ids(void);
 void	cpu_add(u_int apic_id, char boot_cpu);
 void	cpustop_handler(void);
 void	cpususpend_handler(void);
-void	alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx);
 void	init_secondary_tail(void);
 void	init_secondary(void);
 void	ipi_startup(int apic_id, int vector);
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
index 0698cb51b2d0..5e9a9735b09a 100644
--- a/sys/x86/x86/mp_x86.c
+++ b/sys/x86/x86/mp_x86.c
@@ -168,14 +168,10 @@ struct cache_info {
 	int	present;
 } static caches[MAX_CACHE_LEVELS];
 
-unsigned int boot_address;
-
 static bool stop_mwait = false;
 SYSCTL_BOOL(_machdep, OID_AUTO, stop_mwait, CTLFLAG_RWTUN, &stop_mwait, 0,
     "Use MONITOR/MWAIT when stopping CPU, if available");
 
-#define MiB(v)	(v ## ULL << 20)
-
 void
 mem_range_AP_init(void)
 {
@@ -939,56 +935,6 @@ cpu_mp_probe(void)
 	return (mp_ncpus > 1);
 }
 
-/* Allocate memory for the AP trampoline. */
-void
-alloc_ap_trampoline(vm_paddr_t *physmap, unsigned int *physmap_idx)
-{
-	unsigned int i;
-	bool allocated;
-
-	allocated = false;
-	for (i = *physmap_idx; i <= *physmap_idx; i -= 2) {
-		/*
-		 * Find a memory region big enough and below the 1MB boundary
-		 * for the trampoline code.
-		 * NB: needs to be page aligned.
-		 */
-		if (physmap[i] >= MiB(1) ||
-		    (trunc_page(physmap[i + 1]) - round_page(physmap[i])) <
-		    round_page(bootMP_size))
-			continue;
-
-		allocated = true;
-		/*
-		 * Try to steal from the end of the region to mimic previous
-		 * behaviour, else fallback to steal from the start.
-		 */
-		if (physmap[i + 1] < MiB(1)) {
-			boot_address = trunc_page(physmap[i + 1]);
-			if ((physmap[i + 1] - boot_address) < bootMP_size)
-				boot_address -= round_page(bootMP_size);
-			physmap[i + 1] = boot_address;
-		} else {
-			boot_address = round_page(physmap[i]);
-			physmap[i] = boot_address + round_page(bootMP_size);
-		}
-		if (physmap[i] == physmap[i + 1] && *physmap_idx != 0) {
-			memmove(&physmap[i], &physmap[i + 2],
-			    sizeof(*physmap) * (*physmap_idx - i + 2));
-			*physmap_idx -= 2;
-		}
-		break;
-	}
-
-	if (!allocated) {
-		boot_address = basemem * 1024 - bootMP_size;
-		if (bootverbose)
-			printf(
-"Cannot find enough space for the boot trampoline, placing it at %#x",
-			    boot_address);
-	}
-}
-
 /*
  * AP CPU's call this to initialize themselves.
  */


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