Date: Tue, 28 Aug 2018 18:47:02 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r338356 - head/sys/amd64/amd64 Message-ID: <201808281847.w7SIl2Dp013936@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Aug 28 18:47:02 2018 New Revision: 338356 URL: https://svnweb.freebsd.org/changeset/base/338356 Log: Several bug fixes and robustness improvements for the AP boot page table allocation. At the time that mp_bootaddress() is called, phys_avail[] array does not reflect some memory reservations already done, like kernel placement. Recent changes to DMAP protection which make kernel text read-only in DMAP revealed this, where on some machines AP boot page tables selection appears to intersect with the kernel itself. Fix this by checking the addresses selected using the same algorithm as bootaddr_rwx(). Also, try to chomp pages for the page table not only at the start of the contiguous range, but also at the end. This should improve robustness when the only suitable range is already consumed by the kernel. Reported and tested by: Michael Gmelin <freebsd@grem.de> Reviewed by: jhb MFC after: 1 week Sponsored by: The FreeBSD Foundation Approved by: re (gjb) Differential revision: https://reviews.freebsd.org/D16907 Modified: head/sys/amd64/amd64/mp_machdep.c Modified: head/sys/amd64/amd64/mp_machdep.c ============================================================================== --- head/sys/amd64/amd64/mp_machdep.c Tue Aug 28 18:16:02 2018 (r338355) +++ head/sys/amd64/amd64/mp_machdep.c Tue Aug 28 18:47:02 2018 (r338356) @@ -86,6 +86,8 @@ __FBSDID("$FreeBSD$"); #define GiB(v) (v ## ULL << 30) +#define AP_BOOTPT_SZ (PAGE_SIZE * 3) + extern struct pcpu __pcpu[]; /* Temporary variables for init_secondary() */ @@ -100,45 +102,79 @@ char *dbg_stack; static int start_ap(int apic_id); +static bool +is_kernel_paddr(vm_paddr_t pa) +{ + + return (pa >= trunc_2mpage(btext - KERNBASE) && + pa < round_page(_end - KERNBASE)); +} + +static bool +is_mpboot_good(vm_paddr_t start, vm_paddr_t end) +{ + + return (start + AP_BOOTPT_SZ <= GiB(4) && atop(end) < Maxmem); +} + /* * Calculate usable address in base memory for AP trampoline code. */ void mp_bootaddress(vm_paddr_t *physmap, unsigned int *physmap_idx) { + vm_paddr_t start, end; unsigned int i; bool allocated; alloc_ap_trampoline(physmap, physmap_idx); + /* + * Find a memory region big enough below the 4GB boundary to + * store the initial page tables. Region must be mapped by + * the direct map. + * + * Note that it needs to be aligned to a page boundary. + */ 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. Region - * must be mapped by the direct map. - * - * Note that it needs to be aligned to a page - * boundary. + * First, try to chomp at the start of the physmap region. + * Kernel binary might claim it already. */ - if (physmap[i] >= GiB(4) || physmap[i + 1] - - round_page(physmap[i]) < PAGE_SIZE * 3 || - atop(physmap[i + 1]) > Maxmem) - continue; + start = round_page(physmap[i]); + end = start + AP_BOOTPT_SZ; + if (start < end && end <= physmap[i + 1] && + is_mpboot_good(start, end) && + !is_kernel_paddr(start) && !is_kernel_paddr(end - 1)) { + allocated = true; + physmap[i] = end; + break; + } - allocated = true; - mptramp_pagetables = round_page(physmap[i]); - physmap[i] = round_page(physmap[i]) + (PAGE_SIZE * 3); + /* + * Second, try to chomp at the end. Again, check + * against kernel. + */ + end = trunc_page(physmap[i + 1]); + start = end - AP_BOOTPT_SZ; + if (start < end && start >= physmap[i] && + is_mpboot_good(start, end) && + !is_kernel_paddr(start) && !is_kernel_paddr(end - 1)) { + allocated = true; + physmap[i + 1] = start; + break; + } + } + if (allocated) { + mptramp_pagetables = start; 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) { - mptramp_pagetables = trunc_page(boot_address) - (PAGE_SIZE * 3); + } else { + mptramp_pagetables = trunc_page(boot_address) - AP_BOOTPT_SZ; if (bootverbose) printf( "Cannot find enough space for the initial AP page tables, placing them at %#x",
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808281847.w7SIl2Dp013936>