162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2022 ARM Limited.
462306a36Sopenharmony_ci * Original author: Mark Brown <broonie@kernel.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/sched.h>
1062306a36Sopenharmony_ci#include <linux/wait.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "kselftest.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define EXPECTED_TESTS 1
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciint fork_test(void);
1762306a36Sopenharmony_ciint verify_fork(void);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * If we fork the value in the parent should be unchanged and the
2162306a36Sopenharmony_ci * child should start with the same value.  This is called from the
2262306a36Sopenharmony_ci * fork_test() asm function.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ciint fork_test_c(void)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	pid_t newpid, waiting;
2762306a36Sopenharmony_ci	int child_status, parent_result;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	newpid = fork();
3062306a36Sopenharmony_ci	if (newpid == 0) {
3162306a36Sopenharmony_ci		/* In child */
3262306a36Sopenharmony_ci		if (!verify_fork()) {
3362306a36Sopenharmony_ci			ksft_print_msg("ZA state invalid in child\n");
3462306a36Sopenharmony_ci			exit(0);
3562306a36Sopenharmony_ci		} else {
3662306a36Sopenharmony_ci			exit(1);
3762306a36Sopenharmony_ci		}
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci	if (newpid < 0) {
4062306a36Sopenharmony_ci		ksft_print_msg("fork() failed: %d\n", newpid);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		return 0;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	parent_result = verify_fork();
4662306a36Sopenharmony_ci	if (!parent_result)
4762306a36Sopenharmony_ci		ksft_print_msg("ZA state invalid in parent\n");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	for (;;) {
5062306a36Sopenharmony_ci		waiting = waitpid(newpid, &child_status, 0);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		if (waiting < 0) {
5362306a36Sopenharmony_ci			if (errno == EINTR)
5462306a36Sopenharmony_ci				continue;
5562306a36Sopenharmony_ci			ksft_print_msg("waitpid() failed: %d\n", errno);
5662306a36Sopenharmony_ci			return 0;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci		if (waiting != newpid) {
5962306a36Sopenharmony_ci			ksft_print_msg("waitpid() returned wrong PID\n");
6062306a36Sopenharmony_ci			return 0;
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		if (!WIFEXITED(child_status)) {
6462306a36Sopenharmony_ci			ksft_print_msg("child did not exit\n");
6562306a36Sopenharmony_ci			return 0;
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		return WEXITSTATUS(child_status) && parent_result;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint main(int argc, char **argv)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int ret, i;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	ksft_print_header();
7762306a36Sopenharmony_ci	ksft_set_plan(EXPECTED_TESTS);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ksft_print_msg("PID: %d\n", getpid());
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/*
8262306a36Sopenharmony_ci	 * This test is run with nolibc which doesn't support hwcap and
8362306a36Sopenharmony_ci	 * it's probably disproportionate to implement so instead check
8462306a36Sopenharmony_ci	 * for the default vector length configuration in /proc.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
8762306a36Sopenharmony_ci	if (ret >= 0) {
8862306a36Sopenharmony_ci		ksft_test_result(fork_test(), "fork_test\n");
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	} else {
9162306a36Sopenharmony_ci		ksft_print_msg("SME not supported\n");
9262306a36Sopenharmony_ci		for (i = 0; i < EXPECTED_TESTS; i++) {
9362306a36Sopenharmony_ci			ksft_test_result_skip("fork_test\n");
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ksft_finished();
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return 0;
10062306a36Sopenharmony_ci}
101