Date: Thu, 5 Apr 2018 14:39:51 +0000 (UTC) From: =?UTF-8?Q?Roger_Pau_Monn=c3=a9?= <royger@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r332073 - in head/sys: amd64/amd64 amd64/include i386/i386 i386/include x86/include x86/x86 Message-ID: <201804051439.w35EdpMM049557@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); + } } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201804051439.w35EdpMM049557>