[PATCH 1/2] arm: semihosting: replace inline assembly with assembly file

Sean Anderson sean.anderson at seco.com
Fri Feb 10 00:07:37 CET 2023


On 2/7/23 10:21, Andre Przywara wrote:
> So far we used inline assembly to inject the actual instruction that
> triggers the semihosting service. While this sounds elegant, as it's
> really only about one instruction, it has some serious downsides:
> - We need some barriers in place to force the compiler to issue writes
>   to a data structure before issuing the trap instruction.
> - We need to convince the compiler to actually fill the structures that
>   we use pointers to.
> - We need a memory clobber to avoid the compiler caching the data in
>   those structures, when semihosting writes data back.
> - We need register arguments to make sure the function ID and the
>   pointer land in the right registers.
> 
> This is all doable, but fragile and somewhat cumbersome. Since we now
> have a separate function in an extra file anyway, we can do away with
> all the magic and just write that in an actual assembly file.
> This is much more readable and robust.
> 
> Signed-off-by: Andre Przywara <andre.przywara at arm.com>
> ---
>  arch/arm/lib/semihosting.S | 31 +++++++++++++++++++++++++
>  arch/arm/lib/semihosting.c | 47 --------------------------------------
>  2 files changed, 31 insertions(+), 47 deletions(-)
>  create mode 100644 arch/arm/lib/semihosting.S
>  delete mode 100644 arch/arm/lib/semihosting.c
> 
> diff --git a/arch/arm/lib/semihosting.S b/arch/arm/lib/semihosting.S
> new file mode 100644
> index 00000000000..393aade94a5
> --- /dev/null
> +++ b/arch/arm/lib/semihosting.S
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2022 Arm Ltd.
> + */
> +
> +#include <config.h>
> +#include <asm/macro.h>
> +#include <linux/linkage.h>
> +
> +.pushsection .text.smh_trap, "ax"
> +/* long smh_trap(unsigned int sysnum, void *addr); */
> +ENTRY(smh_trap)
> +
> +#if defined(CONFIG_ARM64)
> +	hlt	#0xf000
> +#elif defined(CONFIG_CPU_V7M)
> +	bkpt	#0xab
> +#elif defined(CONFIG_SYS_THUMB_BUILD)
> +	svc	#0xab
> +#else
> +	svc	#0x123456
> +#endif
> +
> +#if defined(CONFIG_ARM64)
> +	ret
> +#else
> +	bx	lr
> +#endif
> +
> +ENDPROC(smh_trap)
> +.popsection
> diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c
> deleted file mode 100644
> index 7b7669bed06..00000000000
> --- a/arch/arm/lib/semihosting.c
> +++ /dev/null
> @@ -1,47 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * Copyright (C) 2022 Sean Anderson <sean.anderson at seco.com>
> - * Copyright 2014 Broadcom Corporation
> - */
> -
> -#include <common.h>
> -
> -/*
> - * Macro to force the compiler to *populate* memory (for an array or struct)
> - * before passing the pointer to an inline assembly call.
> - */
> -#define USE_PTR(ptr) *(const char (*)[]) (ptr)
> -
> -#if defined(CONFIG_ARM64)
> -	#define SMH_TRAP "hlt #0xf000"
> -#elif defined(CONFIG_CPU_V7M)
> -	#define SMH_TRAP "bkpt #0xAB"
> -#elif defined(CONFIG_SYS_THUMB_BUILD)
> -	#define SMH_TRAP "svc #0xab"
> -#else
> -	#define SMH_TRAP "svc #0x123456"
> -#endif
> -
> -/*
> - * Call the handler
> - */
> -long smh_trap(unsigned int sysnum, void *addr)
> -{
> -	register long result asm("r0");
> -	register void *_addr asm("r1") = addr;
> -
> -	/*
> -	 * We need a memory clobber (aka compiler barrier) for two reasons:
> -	 * - The compiler needs to populate any data structures pointed to
> -	 *   by "addr" *before* the trap instruction is called.
> -	 * - At least the SYSREAD function puts the result into memory pointed
> -	 *   to by "addr", so the compiler must not use a cached version of
> -	 *   the previous content, after the call has finished.
> -	 */
> -	asm volatile (SMH_TRAP
> -		      : "=r" (result)
> -		      : "0"(sysnum), "r"(USE_PTR(_addr))
> -		      : "memory");
> -
> -	return result;
> -}

Reviewed-by: Sean Anderson <sean.anderson at seco.com>


More information about the U-Boot mailing list