Add the FP feature check in the set of hwcap tests.
Signed-off-by: Zeng Heng zengheng4@huawei.com --- tools/testing/selftests/arm64/abi/hwcap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index 6a0adf916028..eaf9881c2e43 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -39,6 +39,12 @@ static void cssc_sigill(void) asm volatile(".inst 0xdac01c00" : : : "x0"); }
+static void fp_sigill(void) +{ + /* FMOV S0, #1 */ + asm volatile(".inst 0x1e2e1000" : : : ); +} + static void ilrcpc_sigill(void) { /* LDAPUR W0, [SP, #8] */ @@ -235,6 +241,13 @@ static const struct hwcap_data { .cpuinfo = "cssc", .sigill_fn = cssc_sigill, }, + { + .name = "FP", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_FP, + .cpuinfo = "fp", + .sigill_fn = fp_sigill, + }, { .name = "LRCPC", .at_hwcap = AT_HWCAP,
Add the CRC32 feature check in the set of hwcap tests.
Signed-off-by: Zeng Heng zengheng4@huawei.com --- tools/testing/selftests/arm64/abi/hwcap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index eaf9881c2e43..7ea526e7934e 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -33,6 +33,12 @@ */ typedef void (*sigill_fn)(void);
+static void crc32_sigill(void) +{ + /* CRC32W W0, W0, W1 */ + asm volatile(".inst 0x1ac14800" : : : ); +} + static void cssc_sigill(void) { /* CNT x0, x0 */ @@ -234,6 +240,13 @@ static const struct hwcap_data { sigill_fn sigill_fn; bool sigill_reliable; } hwcaps[] = { + { + .name = "CRC32", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_CRC32, + .cpuinfo = "crc32", + .sigill_fn = crc32_sigill, + }, { .name = "CSSC", .at_hwcap = AT_HWCAP2,
On Tue, Aug 08, 2023 at 02:13:52PM +0800, Zeng Heng wrote:
+static void crc32_sigill(void) +{
- /* CRC32W W0, W0, W1 */
- asm volatile(".inst 0x1ac14800" : : : );
+}
Same here, you could assemble rather than hand encode but otherwise
Reviewed-by: Mark Brown broonie@kernel.org
Add macro definition functions DEF_SIGHANDLER_FUNC() and DEF_INST_RAISE_SIG() helpers.
Furthermore, there is no need to modify the default SIGILL handling function throughout the entire testing lifecycle in the main() function. It is reasonable to narrow the scope to the context of the sig_fn function only.
This is a pre-patch for the subsequent SIGBUS handler patch.
Signed-off-by: Zeng Heng zengheng4@huawei.com --- tools/testing/selftests/arm64/abi/hwcap.c | 118 ++++++++++++++-------- 1 file changed, 75 insertions(+), 43 deletions(-)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index 7ea526e7934e..eebadb2bc9bf 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -440,18 +440,21 @@ static const struct hwcap_data { }, };
-static bool seen_sigill; - -static void handle_sigill(int sig, siginfo_t *info, void *context) -{ - ucontext_t *uc = context; - - seen_sigill = true; - - /* Skip over the offending instruction */ - uc->uc_mcontext.pc += 4; +typedef void (*sighandler_fn)(int, siginfo_t *, void *); + +#define DEF_SIGHANDLER_FUNC(SIG, NUM) \ +static bool seen_##SIG; \ +static void handle_##SIG(int sig, siginfo_t *info, void *context) \ +{ \ + ucontext_t *uc = context; \ + \ + seen_##SIG = true; \ + /* Skip over the offending instruction */ \ + uc->uc_mcontext.pc += 4; \ }
+DEF_SIGHANDLER_FUNC(sigill, SIGILL); + bool cpuinfo_present(const char *name) { FILE *f; @@ -494,25 +497,77 @@ bool cpuinfo_present(const char *name) return false; }
-int main(void) +static int install_sigaction(int signum, sighandler_fn handler) { - const struct hwcap_data *hwcap; - int i, ret; - bool have_cpuinfo, have_hwcap; + int ret; struct sigaction sa;
- ksft_print_header(); - ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handle_sigill; + sa.sa_sigaction = handler; sa.sa_flags = SA_RESTART | SA_SIGINFO; sigemptyset(&sa.sa_mask); - ret = sigaction(SIGILL, &sa, NULL); + ret = sigaction(signum, &sa, NULL); if (ret < 0) ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n", strerror(errno), errno);
+ return ret; +} + +static void uninstall_sigaction(int signum) +{ + if (sigaction(signum, NULL, NULL) < 0) + ksft_exit_fail_msg("Failed to uninstall SIGILL handler: %s (%d)\n", + strerror(errno), errno); +} + +#define DEF_INST_RAISE_SIG(SIG, NUM) \ +static bool inst_raise_##SIG(const struct hwcap_data *hwcap, \ + bool have_hwcap) \ +{ \ + if (!hwcap->SIG##_fn) { \ + ksft_test_result_skip(#SIG"_%s\n", hwcap->name); \ + /* assume that it would raise exception in default */ \ + return true; \ + } \ + \ + install_sigaction(NUM, handle_##SIG); \ + \ + seen_##SIG = false; \ + hwcap->SIG##_fn(); \ + \ + if (have_hwcap) { \ + /* Should be able to use the extension */ \ + ksft_test_result(!seen_##SIG, \ + #SIG"_%s\n", hwcap->name); \ + } else if (hwcap->SIG##_reliable) { \ + /* Guaranteed a SIGNAL */ \ + ksft_test_result(seen_##SIG, \ + #SIG"_%s\n", hwcap->name); \ + } else { \ + /* Missing SIGNAL might be fine */ \ + ksft_print_msg(#SIG"_%sreported for %s\n", \ + seen_##SIG ? "" : "not ", \ + hwcap->name); \ + ksft_test_result_skip(#SIG"_%s\n", \ + hwcap->name); \ + } \ + \ + uninstall_sigaction(NUM); \ + return seen_##SIG; \ +} + +DEF_INST_RAISE_SIG(sigill, SIGILL); + +int main(void) +{ + int i; + const struct hwcap_data *hwcap; + bool have_cpuinfo, have_hwcap; + + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); + for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { hwcap = &hwcaps[i];
@@ -525,30 +580,7 @@ int main(void) ksft_test_result(have_hwcap == have_cpuinfo, "cpuinfo_match_%s\n", hwcap->name);
- if (hwcap->sigill_fn) { - seen_sigill = false; - hwcap->sigill_fn(); - - if (have_hwcap) { - /* Should be able to use the extension */ - ksft_test_result(!seen_sigill, "sigill_%s\n", - hwcap->name); - } else if (hwcap->sigill_reliable) { - /* Guaranteed a SIGILL */ - ksft_test_result(seen_sigill, "sigill_%s\n", - hwcap->name); - } else { - /* Missing SIGILL might be fine */ - ksft_print_msg("SIGILL %sreported for %s\n", - seen_sigill ? "" : "not ", - hwcap->name); - ksft_test_result_skip("sigill_%s\n", - hwcap->name); - } - } else { - ksft_test_result_skip("sigill_%s\n", - hwcap->name); - } + inst_raise_sigill(hwcap, have_hwcap); }
ksft_print_cnts();
Some enhanced features, such as the LSE2 feature, do not result in SILLILL if LSE2 is missing and LSE is present, but will generate a SIGBUS exception when atomic access unaligned.
Therefore, we add test item to test this type of features.
Notice that testing for SIGBUS only makes sense after make sure that the instruction does not cause a SIGILL signal.
Signed-off-by: Zeng Heng zengheng4@huawei.com --- tools/testing/selftests/arm64/abi/hwcap.c | 33 ++++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index eebadb2bc9bf..bc1491075987 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -19,19 +19,20 @@
#include "../../kselftest.h"
-#define TESTS_PER_HWCAP 2 +#define TESTS_PER_HWCAP 3
/* - * Function expected to generate SIGILL when the feature is not - * supported and return when it is supported. If SIGILL is generated - * then the handler must be able to skip over the instruction safely. + * Function expected to generate exception when the feature is not + * supported and return when it is supported. If the specific exception + * is generated then the handler must be able to skip over the + * instruction safely. * * Note that it is expected that for many architecture extensions * there are no specific traps due to no architecture state being * added so we may not fault if running on a kernel which doesn't know * to add the hwcap. */ -typedef void (*sigill_fn)(void); +typedef void (*sig_fn)(void);
static void crc32_sigill(void) { @@ -237,8 +238,10 @@ static const struct hwcap_data { unsigned long at_hwcap; unsigned long hwcap_bit; const char *cpuinfo; - sigill_fn sigill_fn; + sig_fn sigill_fn; bool sigill_reliable; + sig_fn sigbus_fn; + bool sigbus_reliable; } hwcaps[] = { { .name = "CRC32", @@ -454,6 +457,7 @@ static void handle_##SIG(int sig, siginfo_t *info, void *context) \ }
DEF_SIGHANDLER_FUNC(sigill, SIGILL); +DEF_SIGHANDLER_FUNC(sigbus, SIGBUS);
bool cpuinfo_present(const char *name) { @@ -508,7 +512,7 @@ static int install_sigaction(int signum, sighandler_fn handler) sigemptyset(&sa.sa_mask); ret = sigaction(signum, &sa, NULL); if (ret < 0) - ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n", + ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n", strerror(errno), errno);
return ret; @@ -517,7 +521,7 @@ static int install_sigaction(int signum, sighandler_fn handler) static void uninstall_sigaction(int signum) { if (sigaction(signum, NULL, NULL) < 0) - ksft_exit_fail_msg("Failed to uninstall SIGILL handler: %s (%d)\n", + ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n", strerror(errno), errno); }
@@ -558,12 +562,13 @@ static bool inst_raise_##SIG(const struct hwcap_data *hwcap, \ }
DEF_INST_RAISE_SIG(sigill, SIGILL); +DEF_INST_RAISE_SIG(sigbus, SIGBUS);
int main(void) { int i; const struct hwcap_data *hwcap; - bool have_cpuinfo, have_hwcap; + bool have_cpuinfo, have_hwcap, raise_sigill;
ksft_print_header(); ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); @@ -580,7 +585,15 @@ int main(void) ksft_test_result(have_hwcap == have_cpuinfo, "cpuinfo_match_%s\n", hwcap->name);
- inst_raise_sigill(hwcap, have_hwcap); + /* + * Testing for SIGBUS only makes sense after make sure + * that the instruction does not cause a SIGILL signal. + */ + raise_sigill = inst_raise_sigill(hwcap, have_hwcap); + if (!raise_sigill) + inst_raise_sigbus(hwcap, have_hwcap); + else + ksft_test_result_skip("sigbus_%s\n", hwcap->name); }
ksft_print_cnts();
Add the LSE and various features check in the set of hwcap tests.
As stated in the ARM manual, the LSE2 feature allows for atomic access to unaligned memory. Therefore, for processors that only have the LSE feature, we register .sigbus_fn to test their ability to perform unaligned access.
Signed-off-by: Zeng Heng zengheng4@huawei.com --- tools/testing/selftests/arm64/abi/hwcap.c | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index bc1491075987..d702f05f33e3 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -34,6 +34,12 @@ */ typedef void (*sig_fn)(void);
+static void atomics_sigill(void) +{ + /* STADD W0, [SP] */ + asm volatile(".inst 0xb82003ff" : : : ); +} + static void crc32_sigill(void) { /* CRC32W W0, W0, W1 */ @@ -233,6 +239,14 @@ static void svebf16_sigill(void) asm volatile(".inst 0x658aa000" : : : "z0"); }
+static void uscat_sigbus(void) +{ + /* unaligned atomic access */ + asm volatile("ADD x1, sp, #2" : : : ); + /* STADD W0, [X1] */ + asm volatile(".inst 0xb820003f" : : : ); +} + static const struct hwcap_data { const char *name; unsigned long at_hwcap; @@ -278,6 +292,22 @@ static const struct hwcap_data { .cpuinfo = "ilrcpc", .sigill_fn = ilrcpc_sigill, }, + { + .name = "LSE", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_ATOMICS, + .cpuinfo = "atomics", + .sigill_fn = atomics_sigill, + }, + { + .name = "LSE2", + .at_hwcap = AT_HWCAP, + .hwcap_bit = HWCAP_USCAT, + .cpuinfo = "uscat", + .sigill_fn = atomics_sigill, + .sigbus_fn = uscat_sigbus, + .sigbus_reliable = true, + }, { .name = "MOPS", .at_hwcap = AT_HWCAP2,
Add new feature checks and provide testing item to support capturing SIGBUS exception signal.
The following is a log snippet from my local testing environment: ~~~ TAP version 13 1..90 # CRC32 present ok 1 cpuinfo_match_CRC32 ok 2 sigill_CRC32 ok 3 # SKIP sigbus_CRC32 ok 4 cpuinfo_match_CSSC # sigill_reported for CSSC ok 5 # SKIP sigill_CSSC ok 6 # SKIP sigbus_CSSC # FP present ok 7 cpuinfo_match_FP ok 8 sigill_FP ok 9 # SKIP sigbus_FP # LRCPC present ok 10 cpuinfo_match_LRCPC ok 11 sigill_LRCPC ok 12 # SKIP sigbus_LRCPC # LRCPC2 present ok 13 cpuinfo_match_LRCPC2 ok 14 sigill_LRCPC2 ok 15 # SKIP sigbus_LRCPC2 # LSE present ok 16 cpuinfo_match_LSE ok 17 sigill_LSE ok 18 # SKIP sigbus_LSE # LSE2 present ok 19 cpuinfo_match_LSE2 ok 20 sigill_LSE2 ok 21 sigbus_LSE2 ok 22 cpuinfo_match_MOPS ok 23 sigill_MOPS ok 24 # SKIP sigbus_MOPS # RNG present ok 25 cpuinfo_match_RNG ok 26 sigill_RNG ok 27 # SKIP sigbus_RNG ok 28 cpuinfo_match_RPRFM ok 29 # SKIP sigill_RPRFM ok 30 # SKIP sigbus_RPRFM ok 31 cpuinfo_match_SME ok 32 sigill_SME ok 33 # SKIP sigbus_SME ok 34 cpuinfo_match_SME2 ok 35 sigill_SME2 ok 36 # SKIP sigbus_SME2 ok 37 cpuinfo_match_SME 2.1 # sigill_reported for SME 2.1 ok 38 # SKIP sigill_SME 2.1 ok 39 # SKIP sigbus_SME 2.1 ok 40 cpuinfo_match_SME I16I32 # sigill_reported for SME I16I32 ok 41 # SKIP sigill_SME I16I32 ok 42 # SKIP sigbus_SME I16I32 ok 43 cpuinfo_match_SME BI32I32 # sigill_reported for SME BI32I32 ok 44 # SKIP sigill_SME BI32I32 ok 45 # SKIP sigbus_SME BI32I32 ok 46 cpuinfo_match_SME B16B16 # sigill_reported for SME B16B16 ok 47 # SKIP sigill_SME B16B16 ok 48 # SKIP sigbus_SME B16B16 ok 49 cpuinfo_match_SME F16F16 # sigill_reported for SME F16F16 ok 50 # SKIP sigill_SME F16F16 ok 51 # SKIP sigbus_SME F16F16 # SVE present ok 52 cpuinfo_match_SVE ok 53 sigill_SVE ok 54 # SKIP sigbus_SVE ok 55 cpuinfo_match_SVE 2 # sigill_reported for SVE 2 ok 56 # SKIP sigill_SVE 2 ok 57 # SKIP sigbus_SVE 2 ok 58 cpuinfo_match_SVE 2.1 # sigill_reported for SVE 2.1 ok 59 # SKIP sigill_SVE 2.1 ok 60 # SKIP sigbus_SVE 2.1 ok 61 cpuinfo_match_SVE AES # sigill_reported for SVE AES ok 62 # SKIP sigill_SVE AES ok 63 # SKIP sigbus_SVE AES ok 64 cpuinfo_match_SVE2 PMULL # sigill_reported for SVE2 PMULL ok 65 # SKIP sigill_SVE2 PMULL ok 66 # SKIP sigbus_SVE2 PMULL ok 67 cpuinfo_match_SVE2 BITPERM # sigill_reported for SVE2 BITPERM ok 68 # SKIP sigill_SVE2 BITPERM ok 69 # SKIP sigbus_SVE2 BITPERM ok 70 cpuinfo_match_SVE2 SHA3 # sigill_reported for SVE2 SHA3 ok 71 # SKIP sigill_SVE2 SHA3 ok 72 # SKIP sigbus_SVE2 SHA3 ok 73 cpuinfo_match_SVE2 SM4 # sigill_reported for SVE2 SM4 ok 74 # SKIP sigill_SVE2 SM4 ok 75 # SKIP sigbus_SVE2 SM4 # SVE2 I8MM present ok 76 cpuinfo_match_SVE2 I8MM ok 77 sigill_SVE2 I8MM ok 78 # SKIP sigbus_SVE2 I8MM # SVE2 F32MM present ok 79 cpuinfo_match_SVE2 F32MM ok 80 sigill_SVE2 F32MM ok 81 # SKIP sigbus_SVE2 F32MM # SVE2 F64MM present ok 82 cpuinfo_match_SVE2 F64MM ok 83 sigill_SVE2 F64MM ok 84 # SKIP sigbus_SVE2 F64MM # SVE2 BF16 present ok 85 cpuinfo_match_SVE2 BF16 ok 86 sigill_SVE2 BF16 ok 87 # SKIP sigbus_SVE2 BF16 ok 88 cpuinfo_match_SVE2 EBF16 ok 89 # SKIP sigill_SVE2 EBF16 ok 90 # SKIP sigbus_SVE2 EBF16 # Totals: pass:46 fail:0 xfail:0 xpass:0 skip:44 error:0 ~~~
Zeng Heng (5): kselftest/arm64: add float-point feature to hwcap test kselftest/arm64: add crc32 feature to hwcap test kselftest/arm64: add DEF_SIGHANDLER_FUNC() and DEF_INST_RAISE_SIG() helpers kselftest/arm64: add test item that support to capturing the SIGBUS signal kselftest/arm64: add lse and lse2 features to hwcap test
tools/testing/selftests/arm64/abi/hwcap.c | 201 ++++++++++++++++------ 1 file changed, 151 insertions(+), 50 deletions(-)
-- 2.25.1
On Tue, Aug 08, 2023 at 02:13:56PM +0800, Zeng Heng wrote:
Add new feature checks and provide testing item to support capturing SIGBUS exception signal.
I've not checked that the specific LSE2 behaviour is sensible but the integration with the framework looks good. The manual encoding is not really important, just a stylistic nit.
Reviewed-by: Mark Brown broonie@kernel.org
On Tue, Aug 08, 2023 at 02:13:51PM +0800, Zeng Heng wrote:
+static void fp_sigill(void) +{
- /* FMOV S0, #1 */
- asm volatile(".inst 0x1e2e1000" : : : );
+}
That should assemble even with the toolchain configured for v8.0 so there shouldn't be any need to hand encode here. Otherwise
Reviewed-by: Mark Brown broonie@kernel.org
在 2023/8/8 20:25, Mark Brown 写道:
On Tue, Aug 08, 2023 at 02:13:51PM +0800, Zeng Heng wrote:
+static void fp_sigill(void) +{
- /* FMOV S0, #1 */
- asm volatile(".inst 0x1e2e1000" : : : );
+}
That should assemble even with the toolchain configured for v8.0 so there shouldn't be any need to hand encode here. Otherwise
Reviewed-by: Mark Brown broonie@kernel.org
I would update to assemble language in V2.
Zeng Heng
linux-kselftest-mirror@lists.linaro.org