Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp599295ybz; Fri, 24 Apr 2020 06:09:46 -0700 (PDT) X-Google-Smtp-Source: APiQypI4yWJiJTbsWRuWbzcMUQ08AZ/ILMP7PYDXeTelUPQNhzTcG34uNfGfV/1lg7VXB69v2FJP X-Received: by 2002:a50:d90f:: with SMTP id t15mr6992376edj.209.1587733786709; Fri, 24 Apr 2020 06:09:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1587733786; cv=none; d=google.com; s=arc-20160816; b=LQS+PdT5URaaN2FrfRC9u7sH5n0zwPOOX3P8cnRUKGE8o7sZGhK08pUZqn7Zg5v1+m hNx9tenXFPKXg3vNXdKCAIEZo33OXja2956o9TBh5yYdQ/PUmJc5gqRBxphjcqyx/bco 89yaucTUJvyD+l2rMhM+Cmm6sAzQwNxLfma7Qjm7FRrURv0/HUVALX1b74D15KexPjhG cEhrMWakTUaKAXcsW3bjwLxf/oKLO3kENQluM/xbIUThJdsNgsyCVqy8hqoYD9Ju5P8l woSzWPGax6vDOqkDHgfQ/0Pix7ri3lftYEkK3kutw/1Dn93pqYnvTz+bkycFMvOIWZOp eQDA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=+W15MEiMOkX1S9tt5RCs7sVBejrIBszsMaM4Rc35ju8=; b=j5eK0nKSgvgHJ5yB4k6oMkTuEM7+sdc4UYJ1LzoAAHDTiamdDD76yB5HeZ7v9r+h7f 9Dnkmn06C7835oy3C+ZN4rWXg01WWmTUWX6GlhrzTXoLoVH88QiHjRm6cYPb7tlVhLaB zrSicNfzljvrc+c2GhgbP9zRyoRUt5UYLF3mjinx5XYOg8bjYmIJLSIGjh0LTE1SHJAS mhRYITY7jx8EZCb/qhHuP9mh+auzAcYtkpQ8m0pvwLsJpyCeN/6bJa7hgcIWiOEHr/Zh MTkLeyNFWeLploy81KsXIz2JUMfWp6rzoItBlTZRX2b9Fc2ntwZSMZqn0RkkEe/HS65g EDXQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=1Smbt+vI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v25si3143369ejx.386.2020.04.24.06.09.18; Fri, 24 Apr 2020 06:09:46 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=1Smbt+vI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728231AbgDXNHF (ORCPT + 99 others); Fri, 24 Apr 2020 09:07:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:57624 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728182AbgDXNG6 (ORCPT ); Fri, 24 Apr 2020 09:06:58 -0400 Received: from e123331-lin.home (amontpellier-657-1-18-247.w109-210.abo.wanadoo.fr [109.210.65.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 16D0721569; Fri, 24 Apr 2020 13:06:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1587733617; bh=vZ2mY0Fi8GtL2gtiC4tR9yAyAZ8ys6huFhYY105Hm+8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1Smbt+vIBubprOoGwndT69kEsRuXbh3Dsu0UOcxmxjFKs+bMmlvRHLXa/1tydGz9I DLzsaXCidBM3eeDXC7cZoy+KqzY3oU57rYyQ7FGcY7kreCuOps/dEfKvShQgyD0dXQ EHFkQ2Fk8ULBr04u6XmDgewrAxMaJ0Ep8TiBV/Ys= From: Ard Biesheuvel To: linux-efi@vger.kernel.org, Ingo Molnar , Thomas Gleixner Cc: Ard Biesheuvel , linux-kernel@vger.kernel.org, Arvind Sankar , Atish Patra , Palmer Dabbelt , Zou Wei Subject: [PATCH 21/33] efi/libstub/arm64: Replace 'preferred' offset with alignment check Date: Fri, 24 Apr 2020 15:05:19 +0200 Message-Id: <20200424130531.30518-22-ardb@kernel.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200424130531.30518-1-ardb@kernel.org> References: <20200424130531.30518-1-ardb@kernel.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The notion of a 'preferred' load offset for the kernel dates back to the times when the kernel's primary mapping overlapped with the linear region, and memory below it could not be used at all. Today, the arm64 kernel does not really care where it is loaded in physical memory, as long as the alignment requirements are met, and so there is no point in unconditionally moving the kernel to a new location in memory at boot. Instead, we can - check for a KASLR seed, and randomly reallocate the kernel if one is provided - otherwise, check whether the alignment requirements are met for the current placement of the kernel, and just run it in place if they are - finally, do an ordinary page allocation and reallocate the kernel to a suitably aligned buffer anywhere in memory. By the same reasoning, there is no need to take TEXT_OFFSET into account if it is a round multiple of the minimum alignment, which is the usual case for relocatable kernels with TEXT_OFFSET randomization disabled. Otherwise, it suffices to use the relative misaligment of TEXT_OFFSET when reallocating the kernel. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/arm64-stub.c | 62 +++++++++-------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index fc9f8ab533a7..cfd535c13242 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -34,6 +34,15 @@ efi_status_t check_platform_features(void) return EFI_SUCCESS; } +/* + * Relocatable kernels can fix up the misalignment with respect to + * MIN_KIMG_ALIGN, so they only require a minimum alignment of EFI_KIMG_ALIGN + * (which accounts for the alignment of statically allocated objects such as + * the swapper stack.) + */ +static const u64 min_kimg_align = IS_ENABLED(CONFIG_RELOCATABLE) ? EFI_KIMG_ALIGN + : MIN_KIMG_ALIGN; + efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, @@ -43,7 +52,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0; - unsigned long preferred_offset; u64 phys_seed = 0; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { @@ -61,14 +69,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, } } - /* - * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond - * a 2 MB aligned base, which itself may be lower than dram_base, as - * long as the resulting offset equals or exceeds it. - */ - preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET; - if (preferred_offset < dram_base) - preferred_offset += MIN_KIMG_ALIGN; + if (image->image_base != _text) + pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); kernel_size = _edata - _text; kernel_memsize = kernel_size + (_end - _edata); @@ -103,46 +105,32 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, *image_addr = *reserve_addr + offset; } else { - /* - * Else, try a straight allocation at the preferred offset. - * This will work around the issue where, if dram_base == 0x0, - * efi_low_alloc() refuses to allocate at 0x0 (to prevent the - * address of the allocation to be mistaken for a FAIL return - * value or a NULL pointer). It will also ensure that, on - * platforms where the [dram_base, dram_base + TEXT_OFFSET) - * interval is partially occupied by the firmware (like on APM - * Mustang), we can still place the kernel at the address - * 'dram_base + TEXT_OFFSET'. - */ - *image_addr = (unsigned long)_text; - if (*image_addr == preferred_offset) - return EFI_SUCCESS; - - *image_addr = *reserve_addr = preferred_offset; - *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN); - - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, - EFI_LOADER_DATA, - *reserve_size / EFI_PAGE_SIZE, - (efi_physical_addr_t *)reserve_addr); + status = EFI_OUT_OF_RESOURCES; } if (status != EFI_SUCCESS) { - *reserve_size = kernel_memsize + TEXT_OFFSET; + if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align)) { + /* + * Just execute from wherever we were loaded by the + * UEFI PE/COFF loader if the alignment is suitable. + */ + *image_addr = (u64)_text; + *reserve_size = 0; + return EFI_SUCCESS; + } + + *reserve_size = kernel_memsize + TEXT_OFFSET % min_kimg_align; status = efi_low_alloc(*reserve_size, - MIN_KIMG_ALIGN, reserve_addr); + min_kimg_align, reserve_addr); if (status != EFI_SUCCESS) { pr_efi_err("Failed to relocate kernel\n"); *reserve_size = 0; return status; } - *image_addr = *reserve_addr + TEXT_OFFSET; + *image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align; } - if (image->image_base != _text) - pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); - memcpy((void *)*image_addr, _text, kernel_size); return EFI_SUCCESS; -- 2.17.1