kselftest/arm64: Convert tpidr2 test to use kselftest.h

Recent work by Thomas Weißschuh means that it is now possible to use
kselftest.h with nolibc. Convert the tpidr2 test which is nolibc specific
to use kselftest.h, making it look more standard and ensuring it gets the
benefit of any work done on kselftest.h.

Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20250609-kselftest-arm64-nolibc-header-v1-1-16ee1c6fbfed@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Mark Brown
2025-06-09 14:29:10 +01:00
committed by Catalin Marinas
parent 19272b37aa
commit 6d80cb7313
2 changed files with 38 additions and 104 deletions

View File

@@ -12,4 +12,4 @@ $(OUTPUT)/syscall-abi: syscall-abi.c syscall-abi-asm.S
$(OUTPUT)/tpidr2: tpidr2.c $(OUTPUT)/tpidr2: tpidr2.c
$(CC) -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ $(CC) -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
-static -include ../../../../include/nolibc/nolibc.h \ -static -include ../../../../include/nolibc/nolibc.h \
-ffreestanding -Wall $^ -o $@ -lgcc -I../.. -ffreestanding -Wall $^ -o $@ -lgcc

View File

@@ -3,31 +3,12 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/wait.h> #include <linux/wait.h>
#include "kselftest.h"
#define SYS_TPIDR2 "S3_3_C13_C0_5" #define SYS_TPIDR2 "S3_3_C13_C0_5"
#define EXPECTED_TESTS 5 #define EXPECTED_TESTS 5
static void putstr(const char *str)
{
write(1, str, strlen(str));
}
static void putnum(unsigned int num)
{
char c;
if (num / 10)
putnum(num / 10);
c = '0' + (num % 10);
write(1, &c, 1);
}
static int tests_run;
static int tests_passed;
static int tests_failed;
static int tests_skipped;
static void set_tpidr2(uint64_t val) static void set_tpidr2(uint64_t val)
{ {
asm volatile ( asm volatile (
@@ -50,20 +31,6 @@ static uint64_t get_tpidr2(void)
return val; return val;
} }
static void print_summary(void)
{
if (tests_passed + tests_failed + tests_skipped != EXPECTED_TESTS)
putstr("# UNEXPECTED TEST COUNT: ");
putstr("# Totals: pass:");
putnum(tests_passed);
putstr(" fail:");
putnum(tests_failed);
putstr(" xfail:0 xpass:0 skip:");
putnum(tests_skipped);
putstr(" error:0\n");
}
/* Processes should start with TPIDR2 == 0 */ /* Processes should start with TPIDR2 == 0 */
static int default_value(void) static int default_value(void)
{ {
@@ -105,9 +72,8 @@ static int write_fork_read(void)
if (newpid == 0) { if (newpid == 0) {
/* In child */ /* In child */
if (get_tpidr2() != oldpid) { if (get_tpidr2() != oldpid) {
putstr("# TPIDR2 changed in child: "); ksft_print_msg("TPIDR2 changed in child: %llx\n",
putnum(get_tpidr2()); get_tpidr2());
putstr("\n");
exit(0); exit(0);
} }
@@ -115,14 +81,12 @@ static int write_fork_read(void)
if (get_tpidr2() == getpid()) { if (get_tpidr2() == getpid()) {
exit(1); exit(1);
} else { } else {
putstr("# Failed to set TPIDR2 in child\n"); ksft_print_msg("Failed to set TPIDR2 in child\n");
exit(0); exit(0);
} }
} }
if (newpid < 0) { if (newpid < 0) {
putstr("# fork() failed: -"); ksft_print_msg("fork() failed: %d\n", newpid);
putnum(-newpid);
putstr("\n");
return 0; return 0;
} }
@@ -132,23 +96,22 @@ static int write_fork_read(void)
if (waiting < 0) { if (waiting < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
putstr("# waitpid() failed: "); ksft_print_msg("waitpid() failed: %d\n", errno);
putnum(errno);
putstr("\n");
return 0; return 0;
} }
if (waiting != newpid) { if (waiting != newpid) {
putstr("# waitpid() returned wrong PID\n"); ksft_print_msg("waitpid() returned wrong PID: %d != %d\n",
waiting, newpid);
return 0; return 0;
} }
if (!WIFEXITED(status)) { if (!WIFEXITED(status)) {
putstr("# child did not exit\n"); ksft_print_msg("child did not exit\n");
return 0; return 0;
} }
if (getpid() != get_tpidr2()) { if (getpid() != get_tpidr2()) {
putstr("# TPIDR2 corrupted in parent\n"); ksft_print_msg("TPIDR2 corrupted in parent\n");
return 0; return 0;
} }
@@ -188,35 +151,32 @@ static int write_clone_read(void)
stack = malloc(__STACK_SIZE); stack = malloc(__STACK_SIZE);
if (!stack) { if (!stack) {
putstr("# malloc() failed\n"); ksft_print_msg("malloc() failed\n");
return 0; return 0;
} }
ret = sys_clone(CLONE_VM, (unsigned long)stack + __STACK_SIZE, ret = sys_clone(CLONE_VM, (unsigned long)stack + __STACK_SIZE,
&parent_tid, 0, &child_tid); &parent_tid, 0, &child_tid);
if (ret == -1) { if (ret == -1) {
putstr("# clone() failed\n"); ksft_print_msg("clone() failed: %d\n", errno);
putnum(errno);
putstr("\n");
return 0; return 0;
} }
if (ret == 0) { if (ret == 0) {
/* In child */ /* In child */
if (get_tpidr2() != 0) { if (get_tpidr2() != 0) {
putstr("# TPIDR2 non-zero in child: "); ksft_print_msg("TPIDR2 non-zero in child: %llx\n",
putnum(get_tpidr2()); get_tpidr2());
putstr("\n");
exit(0); exit(0);
} }
if (gettid() == 0) if (gettid() == 0)
putstr("# Child TID==0\n"); ksft_print_msg("Child TID==0\n");
set_tpidr2(gettid()); set_tpidr2(gettid());
if (get_tpidr2() == gettid()) { if (get_tpidr2() == gettid()) {
exit(1); exit(1);
} else { } else {
putstr("# Failed to set TPIDR2 in child\n"); ksft_print_msg("Failed to set TPIDR2 in child\n");
exit(0); exit(0);
} }
} }
@@ -227,25 +187,22 @@ static int write_clone_read(void)
if (waiting < 0) { if (waiting < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
putstr("# wait4() failed: "); ksft_print_msg("wait4() failed: %d\n", errno);
putnum(errno);
putstr("\n");
return 0; return 0;
} }
if (waiting != ret) { if (waiting != ret) {
putstr("# wait4() returned wrong PID "); ksft_print_msg("wait4() returned wrong PID %d\n",
putnum(waiting); waiting);
putstr("\n");
return 0; return 0;
} }
if (!WIFEXITED(status)) { if (!WIFEXITED(status)) {
putstr("# child did not exit\n"); ksft_print_msg("child did not exit\n");
return 0; return 0;
} }
if (parent != get_tpidr2()) { if (parent != get_tpidr2()) {
putstr("# TPIDR2 corrupted in parent\n"); ksft_print_msg("TPIDR2 corrupted in parent\n");
return 0; return 0;
} }
@@ -253,35 +210,14 @@ static int write_clone_read(void)
} }
} }
#define run_test(name) \
if (name()) { \
tests_passed++; \
} else { \
tests_failed++; \
putstr("not "); \
} \
putstr("ok "); \
putnum(++tests_run); \
putstr(" " #name "\n");
#define skip_test(name) \
tests_skipped++; \
putstr("ok "); \
putnum(++tests_run); \
putstr(" # SKIP " #name "\n");
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
putstr("TAP version 13\n"); ksft_print_header();
putstr("1.."); ksft_set_plan(5);
putnum(EXPECTED_TESTS);
putstr("\n");
putstr("# PID: "); ksft_print_msg("PID: %d\n", getpid());
putnum(getpid());
putstr("\n");
/* /*
* This test is run with nolibc which doesn't support hwcap and * This test is run with nolibc which doesn't support hwcap and
@@ -290,23 +226,21 @@ int main(int argc, char **argv)
*/ */
ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0); ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
if (ret >= 0) { if (ret >= 0) {
run_test(default_value); ksft_test_result(default_value(), "default_value\n");
run_test(write_read); ksft_test_result(write_read, "write_read\n");
run_test(write_sleep_read); ksft_test_result(write_sleep_read, "write_sleep_read\n");
run_test(write_fork_read); ksft_test_result(write_fork_read, "write_fork_read\n");
run_test(write_clone_read); ksft_test_result(write_clone_read, "write_clone_read\n");
} else { } else {
putstr("# SME support not present\n"); ksft_print_msg("SME support not present\n");
skip_test(default_value); ksft_test_result_skip("default_value\n");
skip_test(write_read); ksft_test_result_skip("write_read\n");
skip_test(write_sleep_read); ksft_test_result_skip("write_sleep_read\n");
skip_test(write_fork_read); ksft_test_result_skip("write_fork_read\n");
skip_test(write_clone_read); ksft_test_result_skip("write_clone_read\n");
} }
print_summary(); ksft_finished();
return 0;
} }