forked from Mirrors/opensbi
		
	firmware: Add preferred boot HART field in struct fw_dynamic_info
It has been reported that link address range of previous booting stage (such as U-Boot SPL) can overlap the link address rage of FW_DYNAMIC. This means self-relocation in FW_DYNAMIC can potentially corrupt previous booting stage if any of the secondary HART enter FW_DYNAMIC before primary HART. To tackle this, we add preferred boot HART field (i.e boot_hart) in struct fw_dyanmic_info. We use this field to force secondary HARTs into relocation wait loop till preferred/primary boot HART enters FW_DYNAMIC completes self-relocation. If preferred boot HART is not available then we fall back to relocation lottery approach. Signed-off-by: Anup Patel <anup.patel@wdc.com> Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
		@@ -46,6 +46,16 @@
 | 
			
		||||
	.globl _start
 | 
			
		||||
	.globl _start_warm
 | 
			
		||||
_start:
 | 
			
		||||
	/* Find preferred boot HART id */
 | 
			
		||||
	MOV_3R	s0, a0, s1, a1, s2, a2
 | 
			
		||||
	call	fw_boot_hart
 | 
			
		||||
	add	a6, a0, zero
 | 
			
		||||
	MOV_3R	a0, s0, a1, s1, a2, s2
 | 
			
		||||
	li	a7, -1
 | 
			
		||||
	beq	a6, a7, _try_lottery
 | 
			
		||||
	/* Jump to relocation wait loop if we are not boot hart */
 | 
			
		||||
	bne	a0, a6, _wait_relocate_copy_done
 | 
			
		||||
_try_lottery:
 | 
			
		||||
	/* Jump to relocation wait loop if we don't get relocation lottery */
 | 
			
		||||
	la	a6, _relocate_lottery
 | 
			
		||||
	li	a7, 1
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,32 @@ _bad_dynamic_info:
 | 
			
		||||
	wfi
 | 
			
		||||
	j	_bad_dynamic_info
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_boot_hart
 | 
			
		||||
	/*
 | 
			
		||||
	 * This function is called very early even before
 | 
			
		||||
	 * fw_save_info() is called.
 | 
			
		||||
	 * We can only use a0, a1, and a2 registers here.
 | 
			
		||||
	 * The boot HART id should be returned in 'a0'.
 | 
			
		||||
	 */
 | 
			
		||||
fw_boot_hart:
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	li	a1, FW_DYNAMIC_INFO_MAGIC_VALUE
 | 
			
		||||
	REG_L	a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
 | 
			
		||||
	bne	a0, a1, _bad_dynamic_info
 | 
			
		||||
	li	a1, FW_DYNAMIC_INFO_VERSION_MAX
 | 
			
		||||
	REG_L	a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
 | 
			
		||||
	bgt	a0, a1, _bad_dynamic_info
 | 
			
		||||
 | 
			
		||||
	/* Read boot HART id */
 | 
			
		||||
	li	a1, 0x2
 | 
			
		||||
	blt	a0, a1, 2f
 | 
			
		||||
	REG_L	a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
 | 
			
		||||
	ret
 | 
			
		||||
2:	li	a0, -1
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_save_info
 | 
			
		||||
@@ -27,14 +53,19 @@ _bad_dynamic_info:
 | 
			
		||||
	 * Nothing to be returned here.
 | 
			
		||||
	 */
 | 
			
		||||
fw_save_info:
 | 
			
		||||
	/* Save next arg1 in 'a1' */
 | 
			
		||||
	la	a4, _dynamic_next_arg1
 | 
			
		||||
	REG_S	a1, (a4)
 | 
			
		||||
 | 
			
		||||
	/* Sanity checks */
 | 
			
		||||
	li	a4, FW_DYNAMIC_INFO_MAGIC_VALUE
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
 | 
			
		||||
	bne	a3, a4, _bad_dynamic_info
 | 
			
		||||
	li	a4, FW_DYNAMIC_INFO_VERSION_MAX
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
 | 
			
		||||
	bgt	a3, a4, _bad_dynamic_info
 | 
			
		||||
 | 
			
		||||
	/* Save version == 0x1 fields */
 | 
			
		||||
	la	a4, _dynamic_next_addr
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
 | 
			
		||||
	REG_S	a3, (a4)
 | 
			
		||||
@@ -44,6 +75,15 @@ fw_save_info:
 | 
			
		||||
	la	a4, _dynamic_options
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
 | 
			
		||||
	REG_S	a3, (a4)
 | 
			
		||||
 | 
			
		||||
	/* Save version == 0x2 fields */
 | 
			
		||||
	li	a4, 0x2
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
 | 
			
		||||
	blt	a3, a4, 2f
 | 
			
		||||
	la	a4, _dynamic_boot_hart
 | 
			
		||||
	REG_L	a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
 | 
			
		||||
	REG_S	a3, (a4)
 | 
			
		||||
2:
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
@@ -116,3 +156,5 @@ _dynamic_next_mode:
 | 
			
		||||
	RISCV_PTR PRV_S
 | 
			
		||||
_dynamic_options:
 | 
			
		||||
	RISCV_PTR 0x0
 | 
			
		||||
_dynamic_boot_hart:
 | 
			
		||||
	RISCV_PTR -1
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,19 @@
 | 
			
		||||
 | 
			
		||||
#include "fw_base.S"
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_boot_hart
 | 
			
		||||
	/*
 | 
			
		||||
	 * This function is called very early even before
 | 
			
		||||
	 * fw_save_info() is called.
 | 
			
		||||
	 * We can only use a0, a1, and a2 registers here.
 | 
			
		||||
	 * The boot HART id should be returned in 'a0'.
 | 
			
		||||
	 */
 | 
			
		||||
fw_boot_hart:
 | 
			
		||||
	li	a0, -1
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_save_info
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,19 @@
 | 
			
		||||
 | 
			
		||||
#include "fw_base.S"
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_boot_hart
 | 
			
		||||
	/*
 | 
			
		||||
	 * This function is called very early even before
 | 
			
		||||
	 * fw_save_info() is called.
 | 
			
		||||
	 * We can only use a0, a1, and a2 registers here.
 | 
			
		||||
	 * The boot HART id should be returned in 'a0'.
 | 
			
		||||
	 */
 | 
			
		||||
fw_boot_hart:
 | 
			
		||||
	li	a0, -1
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.align 3
 | 
			
		||||
	.section .entry, "ax", %progbits
 | 
			
		||||
	.global fw_save_info
 | 
			
		||||
 
 | 
			
		||||
@@ -18,18 +18,20 @@
 | 
			
		||||
#define FW_DYNAMIC_INFO_MAGIC_OFFSET		(0 * __SIZEOF_POINTER__)
 | 
			
		||||
/** Offset of version member in fw_dynamic_info */
 | 
			
		||||
#define FW_DYNAMIC_INFO_VERSION_OFFSET		(1 * __SIZEOF_POINTER__)
 | 
			
		||||
/** Offset of next_addr member in fw_dynamic_info */
 | 
			
		||||
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
 | 
			
		||||
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET	(2 * __SIZEOF_POINTER__)
 | 
			
		||||
/** Offset of next_mode member in fw_dynamic_info */
 | 
			
		||||
/** Offset of next_mode member in fw_dynamic_info  (version >= 1) */
 | 
			
		||||
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET	(3 * __SIZEOF_POINTER__)
 | 
			
		||||
/** Offset of options member in fw_dynamic_info */
 | 
			
		||||
/** Offset of options member in fw_dynamic_info  (version >= 1) */
 | 
			
		||||
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET		(4 * __SIZEOF_POINTER__)
 | 
			
		||||
/** Offset of boot_hart member in fw_dynamic_info  (version >= 2) */
 | 
			
		||||
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET	(5 * __SIZEOF_POINTER__)
 | 
			
		||||
 | 
			
		||||
/** Expected value of info magic ('OSBI' ascii string in hex) */
 | 
			
		||||
#define FW_DYNAMIC_INFO_MAGIC_VALUE		0x4942534f
 | 
			
		||||
 | 
			
		||||
/** Maximum supported info version */
 | 
			
		||||
#define FW_DYNAMIC_INFO_VERSION_MAX		0x1
 | 
			
		||||
#define FW_DYNAMIC_INFO_VERSION_MAX		0x2
 | 
			
		||||
 | 
			
		||||
/** Possible next mode values */
 | 
			
		||||
#define FW_DYNAMIC_INFO_NEXT_MODE_U		0x0
 | 
			
		||||
@@ -54,6 +56,22 @@ struct fw_dynamic_info {
 | 
			
		||||
	unsigned long next_mode;
 | 
			
		||||
	/** Options for OpenSBI library */
 | 
			
		||||
	unsigned long options;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Preferred boot HART id
 | 
			
		||||
	 *
 | 
			
		||||
	 * It is possible that the previous booting stage uses same link
 | 
			
		||||
	 * address as the FW_DYNAMIC firmware. In this case, the relocation
 | 
			
		||||
	 * lottery mechanism can potentially overwrite the previous booting
 | 
			
		||||
	 * stage while other HARTs are still running in the previous booting
 | 
			
		||||
	 * stage leading to boot-time crash. To avoid this boot-time crash,
 | 
			
		||||
	 * the previous booting stage can specify last HART that will jump
 | 
			
		||||
	 * to the FW_DYNAMIC firmware as the preferred boot HART.
 | 
			
		||||
	 *
 | 
			
		||||
	 * To avoid specifying a preferred boot HART, the previous booting
 | 
			
		||||
	 * stage can set it to -1UL which will force the FW_DYNAMIC firmware
 | 
			
		||||
	 * to use the relocation lottery mechanism.
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned long boot_hart;
 | 
			
		||||
} __packed;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user