From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-4.3 required=5.0 tests=ALL_TRUSTED,BAYES_00, RP_MATCHES_RCVD autolearn=unavailable autolearn_force=no version=3.4.1 From: Alexey Sheplyakov To: devel-kernel@lists.altlinux.org Date: Wed, 14 Dec 2022 17:18:55 +0400 Message-Id: <20221214131919.681481-8-asheplyakov@basealt.ru> X-Mailer: git-send-email 2.33.5 In-Reply-To: <20221214131919.681481-1-asheplyakov@basealt.ru> References: <20221214131919.681481-1-asheplyakov@basealt.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Cc: =?UTF-8?q?=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD=20=D0=A1=D1=82=D0=B0=D0=B2=D1=86=D0=B5=D0=B2?= , =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D1=83=D0=B4=D0=BE=D0=B2?= , =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=A1=D0=B8=D0=BD=D0=B5=D0=BB=D1=8C=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= , =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A2=D0=B5=D1=80=D1=91=D1=85=D0=B8=D0=BD?= Subject: [d-kernel] [PATCH 08/32] arm64-stub: fixed secondary cores boot on Baikal-M SoC X-BeenThere: devel-kernel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux kernel packages development List-Id: ALT Linux kernel packages development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Dec 2022 13:20:01 -0000 Archived-At: List-Archive: List-Post: Old versions of Baikal-M firmware (ARM-TF) deny execution attempts outside of the (physical) address ranges [0x80000000, 0x8FFFFFFF] and [0xA0000000, 0xBFFFFFFF] Thus PSCI calls to boot secondary cores fail unless the kernel image resides in one of these address ranges. However UEFI PE/COFF loader puts the kernel image into the forbidden range. Since the alignment is good enough EFI stub does not try to relocate the kernel. As a result secondary CPUs fail to boot. Relocation to a random address is not going to work either. Therefore automatically disable kaslr on "known bad" systems (for now only Baikal-M) and forcibly relocate the kernel to a low(er) address. This patch is necessary only for old firmware (pre SDK-M 5.1) and prevents kalsr from working on Baikal-M systems. Signed-off-by: Alexey Sheplyakov X-DONTUPSTREAM X-legacy X-feature-Baikal-M --- drivers/firmware/efi/libstub/arm64-stub.c | 62 ++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index f9de5217ea65..665a59a287dc 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "efistub.h" @@ -57,6 +58,32 @@ efi_status_t check_platform_features(void) return EFI_SUCCESS; } +static const char* machines_need_low_alloc[] = { + "baikal,baikal-m", + "baikal,bm1000", +}; + +static bool need_low_alloc(void) { + size_t i; + const void *fdt; + const char *match; + + fdt = get_efi_config_table(DEVICE_TREE_GUID); + if (!fdt) { + efi_info("failed to retrive FDT from EFI\n"); + return false; + } + + for (i = 0; i < ARRAY_SIZE(machines_need_low_alloc); i++) { + match = machines_need_low_alloc[i]; + if (fdt_node_check_compatible(fdt, 0, match) == 0) { + efi_info("machine %s: forcing kernel relocation to low address\n", match); + return true; + } + } + return false; +} + /* * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail * to provide space, and fail to zero it). Check for this condition by double @@ -93,6 +120,18 @@ static bool check_image_region(u64 base, u64 size) return ret; } +static inline efi_status_t efi_low_alloc(unsigned long size, unsigned long align, + unsigned long *addr) +{ + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. Skip the first 8 + * bytes so we start at a nice even number. + */ + return efi_low_alloc_above(size, align, addr, 0x8); +} + + efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, @@ -114,12 +153,21 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, */ u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN; + bool force_low_reloc = need_low_alloc(); + if (force_low_reloc) { + if (!efi_nokaslr) { + efi_info("booting on a broken firmware, KASLR will be disabled\n"); + efi_nokaslr = true; + } + } + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID; void *p; if (efi_nokaslr) { - efi_info("KASLR disabled on kernel command line\n"); + if (!force_low_reloc) + efi_info("KASLR disabled on kernel command line\n"); } else if (efi_bs_call(handle_protocol, image_handle, &li_fixed_proto, &p) == EFI_SUCCESS) { efi_info("Image placement fixed by loader\n"); @@ -161,6 +209,15 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, status = EFI_OUT_OF_RESOURCES; } + if (force_low_reloc) { + status = efi_low_alloc(*reserve_size, + min_kimg_align, + reserve_addr); + if (status != EFI_SUCCESS) { + efi_err("Failed to relocate kernel, expect secondary CPUs boot failure\n"); + } + } + if (status != EFI_SUCCESS) { if (!check_image_region((u64)_text, kernel_memsize)) { efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n"); @@ -185,6 +242,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, } *image_addr = *reserve_addr; + if (efi_nokaslr) { + efi_info("relocating kernel to 0x%lx\n", *image_addr); + } memcpy((void *)*image_addr, _text, kernel_size); return EFI_SUCCESS; -- 2.33.5