[PATCH] Add RISCV_ISA_ZALRSC_ONLY to rewrite amo instructions via lr and sc

Bo Gan ganboing at gmail.com
Thu Jan 9 17:14:16 PST 2025


Hi Chaoying,

On 1/9/25 16:24, Chao-ying Fu wrote:
> Some platforms implement lr and sc in hardware, and emulate amo
> instructions via the exception handler. To get better performance,
> we use lr and sc only, when the config is defined.

This comment seems to be self-contradictory. If the core does not support
amo, then there's no way currently in opensbi to trap/emulate it through
exception handler. Thus, from your description, it's not only performance,
but correctness instead. Also do you have a concrete example of such HW?
I wonder if it's worthwhile to maintain for such special HW. I know the
S7 hart in hifive/unmatched and starfive/jh7110 works the other way around:
it only supports AMO, but not lr/sc.

> ---
>   firmware/fw_base.S       |  8 ++++++
>   lib/sbi/riscv_atomic.c   | 54 ++++++++++++++++++++++++++++++++++++++++
>   lib/sbi/riscv_locks.c    |  7 ++++++
>   platform/generic/Kconfig |  4 +++
>   4 files changed, 73 insertions(+)
> 
> diff --git a/firmware/fw_base.S b/firmware/fw_base.S
> index d027e5e..835d64a 100644
> --- a/firmware/fw_base.S
> +++ b/firmware/fw_base.S
> @@ -59,8 +59,16 @@ _try_lottery:
>   	/* Jump to relocation wait loop if we don't get relocation lottery */
>   	lla	a6, _boot_lottery
>   	li	a7, BOOT_LOTTERY_ACQUIRED
> +#ifndef CONFIG_RISCV_ISA_ZALRSC_ONLY
>   	amoswap.w a6, a7, (a6)
>   	bnez	a6, _wait_for_boot_hart
> +#else
> +_sc_fail:
> +	lr.w	t0, (a6)
> +	sc.w	t1, a7, (a6)
> +	bnez	t1, _sc_fail
> +	bnez	t0, _wait_for_boot_hart
> +#endif
>   
>   	/* relocate the global table content */
>   	li	t0, FW_TEXT_START	/* link start */
> diff --git a/lib/sbi/riscv_atomic.c b/lib/sbi/riscv_atomic.c
> index 32cf3f0..c5f47eb 100644
> --- a/lib/sbi/riscv_atomic.c
> +++ b/lib/sbi/riscv_atomic.c
> @@ -31,6 +31,7 @@ void atomic_write(atomic_t *atom, long value)
>   
>   long atomic_add_return(atomic_t *atom, long value)
>   {
> +#ifndef CONFIG_RISCV_ISA_ZALRSC_ONLY
>   	long ret;
>   #if __SIZEOF_LONG__ == 4
>   	__asm__ __volatile__("	amoadd.w.aqrl  %1, %2, %0"
> @@ -43,6 +44,27 @@ long atomic_add_return(atomic_t *atom, long value)
>   			     : "r"(value)
>   			     : "memory");
>   #endif
> +#else
> +	long ret, temp;
> +#if __SIZEOF_LONG__ == 4
> +	__asm__ __volatile__("1:lr.w.aqrl	%1,%0\n"
> +			     "  add	%2,%1,%3\n"
> +			     "  sc.w.aqrl	%2,%2,%0\n"
> +			     "  bnez	%2,1b"
> +			     : "+A"(atom->counter), "=&r"(ret), "=&r"(temp)
> +			     : "r"(value)
> +			     : "memory");
> +#elif __SIZEOF_LONG__ == 8
> +	__asm__ __volatile__("1:lr.d.aqrl	%1,%0\n"
> +			     "  add	%2,%1,%3\n"
> +			     "  sc.d.aqrl	%2,%2,%0\n"
> +			     "  bnez	%2,1b"
> +			     : "+A"(atom->counter), "=&r"(ret), "=&r"(temp)
> +			     : "r"(value)
> +			     : "memory");
> +#endif
> +#endif
> +
>   	return ret + value;
>   }
>   
> @@ -51,6 +73,7 @@ long atomic_sub_return(atomic_t *atom, long value)
>   	return atomic_add_return(atom, -value);
>   }
>   
> +#ifndef CONFIG_RISCV_ISA_ZALRSC_ONLY
>   #define __axchg(ptr, new, size)							\
>   	({									\
>   		__typeof__(ptr) __ptr = (ptr);					\
> @@ -76,6 +99,37 @@ long atomic_sub_return(atomic_t *atom, long value)
>   		}								\
>   		__ret;								\
>   	})
> +#else
> +#define __axchg(ptr, new, size)							\
> +	({									\
> +		__typeof__(ptr) __ptr = (ptr);					\
> +		__typeof__(new) __new = (new);					\
> +		__typeof__(*(ptr)) __ret, __temp;					\
> +		switch (size) {							\
> +		case 4:								\
> +			__asm__ __volatile__ (					\
> +				"1:	lr.w.aqrl %0, %1\n"			\
> +				"	sc.w.aqrl %2, %3, %1\n"			\
> +				"	bnez	  %2, 1b\n"			\
> +				: "=&r" (__ret), "+A" (*__ptr), "=&r" (__temp)	\
> +				: "r" (__new)					\
> +				: "memory");					\
> +			break;							\
> +		case 8:								\
> +			__asm__ __volatile__ (					\
> +				"1:	lr.d.aqrl %0, %1\n"			\
> +				"	sc.d.aqrl %2, %3, %1\n"			\
> +				"	bnez	  %2, 1b\n"			\
> +				: "=&r" (__ret), "+A" (*__ptr), "=&r" (__temp)	\
> +				: "r" (__new)					\
> +				: "memory");					\
> +			break;							\
> +		default:							\
> +			break;							\
> +		}								\
> +		__ret;								\
> +	})
> +#endif
>   
>   #define axchg(ptr, x)								\
>   	({									\
> diff --git a/lib/sbi/riscv_locks.c b/lib/sbi/riscv_locks.c
> index acab776..11f87bf 100644
> --- a/lib/sbi/riscv_locks.c
> +++ b/lib/sbi/riscv_locks.c
> @@ -53,7 +53,14 @@ void spin_lock(spinlock_t *lock)
>   
>   	__asm__ __volatile__(
>   		/* Atomically increment the next ticket. */
> +#ifndef CONFIG_RISCV_ISA_ZALRSC_ONLY
>   		"	amoadd.w.aqrl	%0, %4, %3\n"
> +#else
> +		"3:	lr.w.aqrl	%0, %3\n"
> +		"	add	%1, %0, %4\n"
> +		"	sc.w.aqrl	%1, %1, %3\n"
> +		"	bnez	%1, 3b\n"
> +#endif
>   
>   		/* Did we get the lock? */
>   		"	srli	%1, %0, %6\n"
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index 688da3f..a5ecbd5 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -7,6 +7,10 @@ config PLATFORM_GENERIC
>   	select FDT_PMU
>   	default y
>   
> +config RISCV_ISA_ZALRSC_ONLY
> +	bool "Use lr/sc only"
> +	default n
> +
>   if PLATFORM_GENERIC
>   
>   config PLATFORM_GENERIC_NAME

Bo



More information about the opensbi mailing list