From 773d3f838f1b418257472a78e2b0425e6f439537 Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Mon, 8 Jul 2024 13:13:41 +0100 Subject: [PATCH] core: kernel: Fix checking register convention r1/x1 value of transfer_list According to recently firmware handsoff spec [1]'s "Register usage at handoff boundary", Transfer List's signature value was changed from 0x40_b10b (3 bytes) to 4a0f_b10b (4 bytes). As updating of TL's signature, register value of x1/r1 should be: In aarch32's r1 value should be R1[23:0]: set to the TL signature (4a0f_b10b->masked value: 0f_b10b) R1[31:24]: version of the register convention == 1 and In aarch64's x1 value should be X1[31:0]: set to the TL signature (4a0f_b10b) X1[39:32]: version of the register convention == 1 X1[63:40]: MBZ (See the [2] and [3]). Therefore, it requires to separate mask and shift value for register convention version field when checking each r1/x1 value. This patch fix two problems: 1. breaking X1 value with updated specification in aarch64 - change of length of signature field. 2. previous error value set in R1 in arm32. - length of signature should be 24, but it uses 32bit signature. This patch is a breaking change. It works only TF-A is updated. Link: https://github.com/FirmwareHandoff/firmware_handoff [1] Link: https://github.com/FirmwareHandoff/firmware_handoff/issues/32 [2] Link: https://github.com/FirmwareHandoff/firmware_handoff/commit/5aa7aa1d3a1db75213e458d392b751f0707de027 [3] Fixes: 508e2476b232 ("core: update transfer list header and signature") Signed-off-by: Levi Yun Reviewed-by: Jens Wiklander --- core/arch/arm/kernel/boot.c | 13 ++++++++----- core/include/kernel/transfer_list.h | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/arch/arm/kernel/boot.c b/core/arch/arm/kernel/boot.c index 5a1b11ed786..86ce1c7a14b 100644 --- a/core/arch/arm/kernel/boot.c +++ b/core/arch/arm/kernel/boot.c @@ -1381,22 +1381,25 @@ void __weak boot_save_args(unsigned long a0, unsigned long a1, * Transfer List * a0 - DTB address or 0 (AArch64) * - must be 0 (AArch32) - * a1 - TRANSFER_LIST_SIGNATURE | REG_CONVENTION_VER_MASK + * a1 - 1 << 32 | TRANSFER_LIST_SIGNATURE[0:31] (AArch64) + * - 1 << 24 | TRANSFER_LIST_SIGNATURE[0:23] (AArch32) * a2 - must be 0 (AArch64) * - DTB address or 0 (AArch32) * a3 - Transfer list base address * a4 - Not used */ - if (IS_ENABLED(CFG_TRANSFER_LIST) && - a1 == (TRANSFER_LIST_SIGNATURE | REG_CONVENTION_VER_MASK)) { - if (IS_ENABLED(CFG_ARM64_core)) { + if (IS_ENABLED(CFG_TRANSFER_LIST)) { + if (IS_ENABLED(CFG_ARM64_core) && + a1 == TL_HANDOFF_X1_VALUE(TL_REG_CONVENTION_VER)) { boot_save_transfer_list(a2, a3, a0); boot_arg_fdt = a0; - } else { + } else if (IS_ENABLED(CFG_ARM32_core) && + a1 == TL_HANDOFF_R1_VALUE(TL_REG_CONVENTION_VER)) { boot_save_transfer_list(a0, a3, a2); boot_arg_fdt = a2; } + return; } diff --git a/core/include/kernel/transfer_list.h b/core/include/kernel/transfer_list.h index ed813979f28..30e8a739764 100644 --- a/core/include/kernel/transfer_list.h +++ b/core/include/kernel/transfer_list.h @@ -22,7 +22,22 @@ * Version of the register convention used. * Set to 1 for both AArch64 and AArch32 according to fw handoff spec v0.9 */ -#define REG_CONVENTION_VER_MASK BIT(24) +#define TL_REG_CONVENTION_VER_SHIFT_64 UL(32) +#define TL_REG_CONVENTION_VER_SHIFT_32 UL(24) +#define TL_REG_CONVENTION_VER_MASK UL(0xff) +#define TL_REG_CONVENTION_VER UL(1) + +#define TL_HANDOFF_X1_VALUE(__version) \ + ((TRANSFER_LIST_SIGNATURE & \ + ((BIT64(TL_REG_CONVENTION_VER_SHIFT_64)) - 1)) | \ + (((__version) & TL_REG_CONVENTION_VER_MASK) << \ + TL_REG_CONVENTION_VER_SHIFT_64)) + +#define TL_HANDOFF_R1_VALUE(__version) \ + ((TRANSFER_LIST_SIGNATURE & \ + ((BIT32(TL_REG_CONVENTION_VER_SHIFT_32)) - 1)) | \ + (((__version) & TL_REG_CONVENTION_VER_MASK) << \ + TL_REG_CONVENTION_VER_SHIFT_32)) #define TL_FLAGS_HAS_CHECKSUM BIT(0)