mirror of
https://abf.rosa.ru/djam/kernel-6.6.git
synced 2025-02-24 11:22:47 +00:00

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
187 lines
6 KiB
Diff
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
|
|
|