From 42b209f816aba6cbc0da85de146d486531ffc3eb Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 20 Nov 2024 23:25:44 -0800 Subject: [PATCH] xtensa: optimize syscall helper functions The original idea of the syscall helpers is to workaround an issue where the compiler could not correctly model register usage with inline functions. It was supposed to be only used when there are more then 3 arguments to syscalls. However, during the original MMU code development, the helper got expanded to cover "less then 2 arguments syscalls" as a way for debugging syscall handling code and was never removed. So fix that now by limiting the helper for syscalls with more than 3 arguments. Moreover, instead of using one helper with 6 arguments, now we have separate implementations for both 4 and 5 arguments syscall helpers. Now the compiler does not have to generate code to always handle 6 arguments which saves a few code bytes as there is no need to pass extra zeroes as arguments. This has been verified to work with xt-clang RI-2022.10. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 2 +- arch/xtensa/core/syscall_helper.c | 103 +++++++++++++++++++++++++-- include/zephyr/arch/xtensa/syscall.h | 60 +++++++--------- 3 files changed, 126 insertions(+), 39 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 8722c879e8b..b69d8bcf02b 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -283,7 +283,7 @@ config XTENSA_SYSCALL_USE_HELPER default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xt-clang" depends on (XTENSA_MMU || XTENSA_MPU) && USERSPACE help - Use syscall helpers for passing more then 3 arguments. + Use syscall helpers for passing more than 3 arguments. This is a workaround for toolchains where they have issue modeling register usage. diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c index 24feda91c80..f9673e67814 100644 --- a/arch/xtensa/core/syscall_helper.c +++ b/arch/xtensa/core/syscall_helper.c @@ -12,10 +12,10 @@ #include #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER -uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id) +uintptr_t xtensa_syscall_helper_args_6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) { register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -33,6 +33,101 @@ uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, return a2; } + +uintptr_t xtensa_syscall_helper_args_5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +} + +uintptr_t xtensa_syscall_helper_args_4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +} + +uintptr_t xtensa_syscall_helper_args_3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +} + +uintptr_t xtensa_syscall_helper_args_2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +} + +uintptr_t xtensa_syscall_helper_args_1(uintptr_t arg1, uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +} + +uintptr_t xtensa_syscall_helper_args_0(uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +} #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ #if XCHAL_HAVE_THREADPTR == 0 diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h index 67b001cd329..9fdbe2b0977 100644 --- a/include/zephyr/arch/xtensa/syscall.h +++ b/include/zephyr/arch/xtensa/syscall.h @@ -31,10 +31,18 @@ extern "C" { #endif #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER -uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t arg6, - uintptr_t call_id); +uintptr_t xtensa_syscall_helper_args_6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); + +uintptr_t xtensa_syscall_helper_args_5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id); + +uintptr_t xtensa_syscall_helper_args_4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id); #define SYSINL ALWAYS_INLINE #else @@ -50,13 +58,14 @@ uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, * **/ + static SYSINL uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, arg6, call_id); + return xtensa_syscall_helper_args_6(arg1, arg2, arg3, arg4, arg5, arg6, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -77,11 +86,11 @@ static SYSINL uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, } static SYSINL uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t arg5, uintptr_t call_id) + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, 0, call_id); + return xtensa_syscall_helper_args_5(arg1, arg2, arg3, arg4, arg5, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -101,11 +110,11 @@ static SYSINL uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, } static SYSINL uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t arg4, - uintptr_t call_id) + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) { #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, arg2, arg3, arg4, 0, 0, call_id); + return xtensa_syscall_helper_args_4(arg1, arg2, arg3, arg4, call_id); #else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -123,12 +132,9 @@ static SYSINL uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static SYSINL uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, - uintptr_t arg3, uintptr_t call_id) +static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) { -#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, arg2, arg3, 0, 0, 0, call_id); -#else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; register uintptr_t a3 __asm__("%a3") = arg2; @@ -140,15 +146,11 @@ static SYSINL uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, : "memory"); return a2; -#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ } -static SYSINL uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, - uintptr_t call_id) +static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) { -#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, arg2, 0, 0, 0, 0, call_id); -#else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; register uintptr_t a3 __asm__("%a3") = arg2; @@ -159,15 +161,10 @@ static SYSINL uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, : "memory"); return a2; -#endif } -static SYSINL uintptr_t arch_syscall_invoke1(uintptr_t arg1, - uintptr_t call_id) +static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, uintptr_t call_id) { -#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(arg1, 0, 0, 0, 0, 0, call_id); -#else register uintptr_t a2 __asm__("%a2") = call_id; register uintptr_t a6 __asm__("%a6") = arg1; @@ -177,14 +174,10 @@ static SYSINL uintptr_t arch_syscall_invoke1(uintptr_t arg1, : "memory"); return a2; -#endif } -static SYSINL uintptr_t arch_syscall_invoke0(uintptr_t call_id) +static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) { -#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER - return xtensa_syscall_helper(0, 0, 0, 0, 0, 0, call_id); -#else register uintptr_t a2 __asm__("%a2") = call_id; __asm__ volatile("syscall\n\t" @@ -193,7 +186,6 @@ static SYSINL uintptr_t arch_syscall_invoke0(uintptr_t call_id) : "memory"); return a2; -#endif } /*