kernel-6.6/0643-arm64-stub-fixed-secondary-cores-boot-on-Baikal-M-So.patch
Mikhail Novosyolov 37d488c3a9 Restore support of Baikal-M and update arm64 config
Ran
ARCH=arm64 ./scripts/kconfig/merge_config.sh /mnt/dev/rosa-pkgs/kernel-6.6/kernel-arm64.config /mnt/dev/rosa-pkgs/kernel-6.6/kernel-x86_64.config
inside kernel sources to merge arm64 and x86_64 configs
2024-06-10 11:50:42 +03:00

187 lines
6 KiB
Diff

From 470d48b18875d71f2c4c0cd25c91e5ffcc216159 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@basealt.ru>
Date: Wed, 3 Jan 2024 18:03:56 +0400
Subject: [PATCH 643/643] arm64-stub: fixed secondary cores boot on Baikal-M
SoC
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 GRUB and UEFI PE/COFF loader put the kernel image outside of
allowed 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 (KASLR) is not going to work either.
Therefore automatically disable kaslr for "known bad" Baikal-M
systems with old firmware (SDK-M 5.2 and older) and forcibly relocate
the kernel into [0x80000000, 0x8FFFFFFF] address range.
Newer firmwares (tested with SDK-M 5.3 ... 5.6) don't have such
a limitation, so keep KASLR enabled for such (Baikal-M) systems.
Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru>
X-feature-Baikal-M
X-legacy
X-DONTUPSTREAM
---
drivers/firmware/efi/libstub/arm64-stub.c | 125 +++++++++++++++++++++-
1 file changed, 123 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 452b7ccd330e..c8f4baddf680 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -13,6 +13,105 @@
#include <asm/sections.h>
#include "efistub.h"
+#include <linux/libfdt.h>
+
+
+/*
+ * Guess if we are booting on Baikal-M (aka BE-M1000) SoC.
+ * Use FDT and SMBIOS
+ */
+static bool is_baikalm(void) {
+ static const char *baikalm_compat[] = {
+ "baikal,baikal-m",
+ "baikal,bm1000",
+ };
+ struct efi_smbios_type4_record *cpu_record = NULL;
+ const u32 __aligned(1) *socid = NULL;
+ const char *match = NULL;
+ const void *fdt = NULL;
+
+ fdt = get_efi_config_table(DEVICE_TREE_GUID);
+ cpu_record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
+
+ if (fdt) {
+ for (size_t i = 0; i < ARRAY_SIZE(baikalm_compat); i++) {
+ match = baikalm_compat[i];
+ if (fdt_node_check_compatible(fdt, 0, match) == 0) {
+ efi_info_once("detected Baikal-M via FDT: %s\n", match);
+ return true;
+ }
+ }
+ } else {
+ efi_debug_once("failed to retrive FDT from EFI\n");
+ }
+
+ if (cpu_record) {
+ socid = (u32 *)cpu_record->processor_id;
+ switch (*socid) {
+ case 0x411fd073U:
+ efi_info_once("detected Baikal-M CPU via SMBIOS (SoC ID: %x)\n", *socid);
+ return true;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ efi_debug_once("failed to retrive processor_id from SMBIOS\n");
+ }
+ return false;
+}
+
+struct efi_smbios_type0_record {
+ struct efi_smbios_record header;
+ u8 data[];
+};
+
+static void get_bios_version(unsigned *fw_major, unsigned *fw_minor,
+ const struct efi_smbios_type0_record *firmware_record) {
+
+ if (!fw_major || !fw_minor ||!firmware_record) {
+ return;
+ }
+ if (firmware_record->header.length >= 0x18 &&
+ firmware_record->data[0x10] != 0xff &&
+ firmware_record->data[0x11] != 0xff) {
+ *fw_major = firmware_record->data[0x10];
+ *fw_minor = firmware_record->data[0x11];
+ }
+}
+
+/*
+ * Guess if we are booting on BE-M1000 CPU with pre SDK-M 5.3 firmware.
+ */
+static bool is_old_baikalm(void) {
+ struct efi_smbios_type0_record *firmware_record = NULL;
+ unsigned fw_major = 0xffU, fw_minor = 0xffU;
+
+ if (!is_baikalm()) {
+ return false;
+ }
+
+ firmware_record = (struct efi_smbios_type0_record *)efi_get_smbios_record(0);
+ if (firmware_record) {
+ get_bios_version(&fw_major, &fw_minor, firmware_record);
+ } else {
+ efi_debug("failed to retrive BIOS version record from SMBIOS\n");
+ return true;
+ }
+ if (fw_major != 0xff && fw_minor != 0xff) {
+ efi_info_once("booting on Baikal-M with SDK-M %u.%u\n",
+ fw_major,
+ fw_minor);
+ return fw_major <= 4
+ /* SDK-M 4.x */
+ || (fw_major == 5 && fw_minor < 3)
+ /* SDK-M < 5.3 */;
+ } else {
+ efi_info("failed to figure out Baikal-M firmware version\n");
+ return true; /* assume firmware is broken by default */
+ }
+ return false;
+}
efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
@@ -24,12 +123,12 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_status_t status;
unsigned long kernel_size, kernel_codesize, kernel_memsize;
- if (image->image_base != _text) {
+ if (image->image_base != _text && !is_baikalm()) {
efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
image->image_base = _text;
}
- if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN))
+ if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN) && !is_baikalm())
efi_err("FIRMWARE BUG: kernel image not aligned on %dk boundary\n",
SEGMENT_ALIGN >> 10);
@@ -39,6 +138,28 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
*reserve_size = kernel_memsize;
*image_addr = (unsigned long)_text;
+
+ if (is_baikalm() && is_old_baikalm()) {
+ static const unsigned long BAIKALM_RAM_START = 0x80000000UL;
+ static const unsigned long BAIKALM_ARMTF_RAM_END = 0x8FFFFFFFUL;
+ u64 min_kimg_align = efi_get_kimg_min_align();
+ if ((unsigned long)_end <= BAIKALM_ARMTF_RAM_END &&
+ (unsigned long)_text >= BAIKALM_RAM_START &&
+ IS_ALIGNED(*image_addr, min_kimg_align)) {
+ /* just execute from wherever we were loaded */
+ efi_info("Baikal-M: kernel loaded into lower 256 MB, executing from there\n");
+ *reserve_size = 0;
+ return EFI_SUCCESS;
+ }
+ efi_info("Baikal-M: kernel loaded outside of lower 256 MB, forcing relocation\n");
+ return efi_relocate_kernel(image_addr,
+ kernel_size,
+ kernel_memsize,
+ BAIKALM_RAM_START,
+ min_kimg_align,
+ BAIKALM_RAM_START);
+ }
+
status = efi_kaslr_relocate_kernel(image_addr,
reserve_addr, reserve_size,
kernel_size, kernel_codesize,
--
2.40.1