tools/testing/selftests/arm64/abi/tpidr2.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/arm64/abi/tpidr2.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/arm64/abi/tpidr2.c
Extension
.c
Size
5081 bytes
Lines
246
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (get_tpidr2() != oldpid) {
			ksft_print_msg("TPIDR2 changed in child: %llx\n",
				       get_tpidr2());
			exit(0);
		}

		set_tpidr2(getpid());
		if (get_tpidr2() == getpid()) {
			exit(1);
		} else {
			ksft_print_msg("Failed to set TPIDR2 in child\n");
			exit(0);
		}
	}
	if (newpid < 0) {
		ksft_print_msg("fork() failed: %d\n", newpid);
		return 0;
	}

	for (;;) {
		waiting = waitpid(newpid, &status, 0);

		if (waiting < 0) {
			if (errno == EINTR)
				continue;
			ksft_print_msg("waitpid() failed: %d\n", errno);
			return 0;
		}
		if (waiting != newpid) {
			ksft_print_msg("waitpid() returned wrong PID: %d != %d\n",
				       waiting, newpid);
			return 0;
		}

		if (!WIFEXITED(status)) {
			ksft_print_msg("child did not exit\n");
			return 0;
		}

		if (getpid() != get_tpidr2()) {
			ksft_print_msg("TPIDR2 corrupted in parent\n");
			return 0;
		}

		return WEXITSTATUS(status);
	}
}

/*
 * sys_clone() has a lot of per architecture variation so just define
 * it here rather than adding it to nolibc, plus the raw API is a
 * little more convenient for this test.
 */
static int sys_clone(unsigned long clone_flags, unsigned long newsp,
		     int *parent_tidptr, unsigned long tls,
		     int *child_tidptr)
{
	return syscall(__NR_clone, clone_flags, newsp, parent_tidptr, tls, child_tidptr);
}

#define __STACK_SIZE (8 * 1024 * 1024)

/*
 * If we clone with CLONE_VM then the value in the parent should
 * be unchanged and the child should start with zero and be able to
 * set its own value.
 */
static int write_clone_read(void)
{
	int parent_tid, child_tid;
	pid_t parent, waiting;
	int ret, status;
	void *stack;

	parent = getpid();
	set_tpidr2(parent);

	stack = malloc(__STACK_SIZE);
	if (!stack) {
		ksft_print_msg("malloc() failed\n");
		return 0;
	}

	ret = sys_clone(CLONE_VM, (unsigned long)stack + __STACK_SIZE,
			&parent_tid, 0, &child_tid);
	if (ret == -1) {
		ksft_print_msg("clone() failed: %d\n", errno);
		return 0;
	}

Annotation

Implementation Notes