svn commit: r332073 - in head/sys: amd64/amd64 amd64/include i386/i386 i386/include x86/include x86/x86

Roger Pau Monné royger at FreeBSD.org
Thu Apr 5 14:39:53 UTC 2018


Author: royger
Date: Thu Apr  5 14:39:51 2018
New Revision: 332073
URL: https://svnweb.freebsd.org/changeset/base/332073

Log:
  x86: improve reservation of AP trampoline memory
  
  So that it doesn't rely on physmap[1] containing an address below
  1MiB. Instead scan the full physmap and search for a suitable address
  to place the trampoline code (below 1MiB) and the initial memory pages
  (below 4GiB).
  
  Sponsored by:		Citrix Systems R&D
  Reviewed by:		kib
  Differential Revision:	https://reviews.freebsd.org/D14878

Modified:
  head/sys/amd64/amd64/machdep.c
  head/sys/amd64/amd64/mp_machdep.c
  head/sys/amd64/amd64/mpboot.S
  head/sys/amd64/include/smp.h
  head/sys/i386/i386/machdep.c
  head/sys/i386/i386/mp_machdep.c
  head/sys/i386/include/smp.h
  head/sys/x86/include/init.h
  head/sys/x86/include/x86_smp.h
  head/sys/x86/x86/mp_x86.c

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/amd64/amd64/machdep.c	Thu Apr  5 14:39:51 2018	(r332073)
@@ -1246,14 +1246,10 @@ getmemsize(caddr_t kmdp, u_int64_t first)
 	 * 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 32bit mode (e.g. SMP bare metal).
+	 * in real mode mode (e.g. SMP bare metal).
 	 */
-	if (init_ops.mp_bootaddress) {
-		if (physmap[1] >= 0x100000000)
-			panic(
-	"Basemem segment is not suitable for AP bootstrap code!");
-		physmap[1] = init_ops.mp_bootaddress(physmap[1] / 1024);
-	}
+	if (init_ops.mp_bootaddress)
+		init_ops.mp_bootaddress(physmap, &physmap_idx);
 
 	/*
 	 * Maxmem isn't the "maximum memory", it's one larger than the

Modified: head/sys/amd64/amd64/mp_machdep.c
==============================================================================
--- head/sys/amd64/amd64/mp_machdep.c	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/amd64/amd64/mp_machdep.c	Thu Apr  5 14:39:51 2018	(r332073)
@@ -96,24 +96,45 @@ char *nmi_stack;
 
 static int	start_ap(int apic_id);
 
-static u_int	bootMP_size;
-static u_int	boot_address;
-
 /*
  * Calculate usable address in base memory for AP trampoline code.
  */
-u_int
-mp_bootaddress(u_int basemem)
+void
+mp_bootaddress(vm_paddr_t *physmap, unsigned int *physmap_idx)
 {
+	unsigned int i;
+	bool allocated;
 
-	bootMP_size = mptramp_end - mptramp_start;
-	boot_address = trunc_page(basemem * 1024); /* round down to 4k boundary */
-	if (((basemem * 1024) - boot_address) < bootMP_size)
-		boot_address -= PAGE_SIZE;	/* not enough, lower by 4k */
-	/* 3 levels of page table pages */
-	mptramp_pagetables = boot_address - (PAGE_SIZE * 3);
+	alloc_ap_trampoline(physmap, physmap_idx);
 
-	return mptramp_pagetables;
+	allocated = false;
+	for (i = *physmap_idx; i <= *physmap_idx; i -= 2) {
+		/*
+		 * Find a memory region big enough below the 4GB boundary to
+		 * store the initial page tables. Note that it needs to be
+		 * aligned to a page boundary.
+		 */
+		if (physmap[i] >= GiB(4) ||
+		    (physmap[i + 1] - round_page(physmap[i])) < (PAGE_SIZE * 3))
+			continue;
+
+		allocated = true;
+		mptramp_pagetables = round_page(physmap[i]);
+		physmap[i] = round_page(physmap[i]) + (PAGE_SIZE * 3);
+		if (physmap[i] == physmap[i + 1] && *physmap_idx != 0) {
+			memmove(&physmap[i], &physmap[i + 2],
+			    sizeof(*physmap) * (*physmap_idx - i + 2));
+			*physmap_idx -= 2;
+		}
+	}
+
+	if (!allocated) {
+		mptramp_pagetables = trunc_page(boot_address) - (PAGE_SIZE * 3);
+		if (bootverbose)
+			printf(
+"Cannot find enough space for the initial AP page tables, placing them at %#x",
+			    mptramp_pagetables);
+	}
 }
 
 /*

Modified: head/sys/amd64/amd64/mpboot.S
==============================================================================
--- head/sys/amd64/amd64/mpboot.S	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/amd64/amd64/mpboot.S	Thu Apr  5 14:39:51 2018	(r332073)
@@ -216,8 +216,14 @@ lgdt_desc:	
 	.word	gdtend-gdt		/* Length */
 	.long	gdt-mptramp_start	/* Offset plus %ds << 4 */
 
-	.globl	mptramp_end
 mptramp_end:
+	/*
+	 * The size of the trampoline code that needs to be relocated
+	 * below the 1MiB boundary.
+	 */
+	.globl	bootMP_size
+bootMP_size:
+	.long	mptramp_end - mptramp_start
 
 	/*
 	 * From here on down is executed in the kernel .text section.

Modified: head/sys/amd64/include/smp.h
==============================================================================
--- head/sys/amd64/include/smp.h	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/amd64/include/smp.h	Thu Apr  5 14:39:51 2018	(r332073)
@@ -23,7 +23,6 @@
 
 /* global symbols in mpboot.S */
 extern char			mptramp_start[];
-extern char			mptramp_end[];
 extern u_int32_t		mptramp_pagetables;
 
 /* IPI handlers */
@@ -59,6 +58,7 @@ void	invlpg_pcid_handler(void);
 void	invlrng_invpcid_handler(void);
 void	invlrng_pcid_handler(void);
 int	native_start_all_aps(void);
+void	mp_bootaddress(vm_paddr_t *, unsigned int *);
 
 #endif /* !LOCORE */
 #endif /* SMP */

Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/i386/i386/machdep.c	Thu Apr  5 14:39:51 2018	(r332073)
@@ -1903,7 +1903,7 @@ physmap_done:
 
 #ifdef SMP
 	/* make hole for AP bootstrap code */
-	physmap[1] = mp_bootaddress(physmap[1]);
+	alloc_ap_trampoline(physmap, &physmap_idx);
 #endif
 
 	/*

Modified: head/sys/i386/i386/mp_machdep.c
==============================================================================
--- head/sys/i386/i386/mp_machdep.c	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/i386/i386/mp_machdep.c	Thu Apr  5 14:39:51 2018	(r332073)
@@ -139,22 +139,6 @@ static void	install_ap_tramp(void);
 static int	start_all_aps(void);
 static int	start_ap(int apic_id);
 
-static u_int	boot_address;
-
-/*
- * Calculate usable address in base memory for AP trampoline code.
- */
-u_int
-mp_bootaddress(u_int basemem)
-{
-
-	boot_address = trunc_page(basemem);	/* round down to 4k boundary */
-	if ((basemem - boot_address) < bootMP_size)
-		boot_address -= PAGE_SIZE;	/* not enough, lower by 4k */
-
-	return boot_address;
-}
-
 /*
  * Initialize the IPI handlers and start up the AP's.
  */

Modified: head/sys/i386/include/smp.h
==============================================================================
--- head/sys/i386/include/smp.h	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/i386/include/smp.h	Thu Apr  5 14:39:51 2018	(r332073)
@@ -27,9 +27,6 @@
 #include <x86/apicvar.h>
 #include <machine/pcb.h>
 
-/* global data in mpboot.s */
-extern int bootMP_size;
-
 /* functions in mpboot.s */
 void bootMP(void);
 

Modified: head/sys/x86/include/init.h
==============================================================================
--- head/sys/x86/include/init.h	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/x86/include/init.h	Thu Apr  5 14:39:51 2018	(r332073)
@@ -41,7 +41,7 @@ struct init_ops {
 	void	(*early_clock_source_init)(void);
 	void	(*early_delay)(int);
 	void	(*parse_memmap)(caddr_t, vm_paddr_t *, int *);
-	u_int	(*mp_bootaddress)(u_int);
+	void	(*mp_bootaddress)(vm_paddr_t *, unsigned int *);
 	int	(*start_all_aps)(void);
 	void	(*msi_init)(void);
 };

Modified: head/sys/x86/include/x86_smp.h
==============================================================================
--- head/sys/x86/include/x86_smp.h	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/x86/include/x86_smp.h	Thu Apr  5 14:39:51 2018	(r332073)
@@ -32,6 +32,8 @@ extern int bootAP;
 extern void *dpcpu;
 extern char *bootSTK;
 extern void *bootstacks[];
+extern unsigned int boot_address;
+extern unsigned int bootMP_size;
 extern volatile u_int cpu_ipi_pending[];
 extern volatile int aps_ready;
 extern struct mtx ap_boot_mtx;
@@ -83,6 +85,7 @@ 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	invltlb_handler(void);
 void	invlpg_handler(void);
@@ -95,7 +98,6 @@ void 	ipi_bitmap_handler(struct trapframe frame);
 void	ipi_cpu(int cpu, u_int ipi);
 int	ipi_nmi_handler(void);
 void	ipi_selected(cpuset_t cpus, u_int ipi);
-u_int	mp_bootaddress(u_int);
 void	set_interrupt_apic_ids(void);
 void	smp_cache_flush(void);
 void	smp_masked_invlpg(cpuset_t mask, vm_offset_t addr, struct pmap *pmap);

Modified: head/sys/x86/x86/mp_x86.c
==============================================================================
--- head/sys/x86/x86/mp_x86.c	Thu Apr  5 14:31:54 2018	(r332072)
+++ head/sys/x86/x86/mp_x86.c	Thu Apr  5 14:39:51 2018	(r332073)
@@ -158,6 +158,8 @@ struct cache_info {
 	int	present;
 } static caches[MAX_CACHE_LEVELS];
 
+unsigned int boot_address;
+
 void
 mem_range_AP_init(void)
 {
@@ -903,6 +905,55 @@ cpu_mp_probe(void)
 	 */
 	CPU_SETOF(0, &all_cpus);
 	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;
+		}
+	}
+
+	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);
+	}
 }
 
 /*


More information about the svn-src-all mailing list