From owner-svn-src-all@freebsd.org Tue Aug 28 18:47:03 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0E2201094EBD; Tue, 28 Aug 2018 18:47:03 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id B4D2A91E2B; Tue, 28 Aug 2018 18:47:02 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7BCD51220C; Tue, 28 Aug 2018 18:47:02 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w7SIl24J013937; Tue, 28 Aug 2018 18:47:02 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w7SIl2Dp013936; Tue, 28 Aug 2018 18:47:02 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201808281847.w7SIl2Dp013936@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Tue, 28 Aug 2018 18:47:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r338356 - head/sys/amd64/amd64 X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: head/sys/amd64/amd64 X-SVN-Commit-Revision: 338356 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Aug 2018 18:47:03 -0000 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 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",