18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Ptrace test for TAR, PPR, DSCR registers
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include "ptrace.h"
88c2ecf20Sopenharmony_ci#include "ptrace-tar.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Tracer and Tracee Shared Data */
118c2ecf20Sopenharmony_ciint shm_id;
128c2ecf20Sopenharmony_ciint *cptr;
138c2ecf20Sopenharmony_ciint *pptr;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_civoid tar(void)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	unsigned long reg[3];
188c2ecf20Sopenharmony_ci	int ret;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	cptr = (int *)shmat(shm_id, NULL, 0);
218c2ecf20Sopenharmony_ci	printf("%-30s TAR: %u PPR: %lx DSCR: %u\n",
228c2ecf20Sopenharmony_ci			user_write, TAR_1, PPR_1, DSCR_1);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	mtspr(SPRN_TAR, TAR_1);
258c2ecf20Sopenharmony_ci	mtspr(SPRN_PPR, PPR_1);
268c2ecf20Sopenharmony_ci	mtspr(SPRN_DSCR, DSCR_1);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	cptr[2] = 1;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* Wait on parent */
318c2ecf20Sopenharmony_ci	while (!cptr[0])
328c2ecf20Sopenharmony_ci		asm volatile("" : : : "memory");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	reg[0] = mfspr(SPRN_TAR);
358c2ecf20Sopenharmony_ci	reg[1] = mfspr(SPRN_PPR);
368c2ecf20Sopenharmony_ci	reg[2] = mfspr(SPRN_DSCR);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n",
398c2ecf20Sopenharmony_ci			user_read, reg[0], reg[1], reg[2]);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* Unblock the parent now */
428c2ecf20Sopenharmony_ci	cptr[1] = 1;
438c2ecf20Sopenharmony_ci	shmdt((int *)cptr);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	ret = validate_tar_registers(reg, TAR_2, PPR_2, DSCR_2);
468c2ecf20Sopenharmony_ci	if (ret)
478c2ecf20Sopenharmony_ci		exit(1);
488c2ecf20Sopenharmony_ci	exit(0);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint trace_tar(pid_t child)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	unsigned long reg[3];
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	FAIL_IF(start_trace(child));
568c2ecf20Sopenharmony_ci	FAIL_IF(show_tar_registers(child, reg));
578c2ecf20Sopenharmony_ci	printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n",
588c2ecf20Sopenharmony_ci			ptrace_read_running, reg[0], reg[1], reg[2]);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	FAIL_IF(validate_tar_registers(reg, TAR_1, PPR_1, DSCR_1));
618c2ecf20Sopenharmony_ci	FAIL_IF(stop_trace(child));
628c2ecf20Sopenharmony_ci	return TEST_PASS;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciint trace_tar_write(pid_t child)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	FAIL_IF(start_trace(child));
688c2ecf20Sopenharmony_ci	FAIL_IF(write_tar_registers(child, TAR_2, PPR_2, DSCR_2));
698c2ecf20Sopenharmony_ci	printf("%-30s TAR: %u PPR: %lx DSCR: %u\n",
708c2ecf20Sopenharmony_ci			ptrace_write_running, TAR_2, PPR_2, DSCR_2);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	FAIL_IF(stop_trace(child));
738c2ecf20Sopenharmony_ci	return TEST_PASS;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciint ptrace_tar(void)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	pid_t pid;
798c2ecf20Sopenharmony_ci	int ret, status;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	// TAR was added in v2.07
828c2ecf20Sopenharmony_ci	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT);
858c2ecf20Sopenharmony_ci	pid = fork();
868c2ecf20Sopenharmony_ci	if (pid < 0) {
878c2ecf20Sopenharmony_ci		perror("fork() failed");
888c2ecf20Sopenharmony_ci		return TEST_FAIL;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (pid == 0)
928c2ecf20Sopenharmony_ci		tar();
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (pid) {
958c2ecf20Sopenharmony_ci		pptr = (int *)shmat(shm_id, NULL, 0);
968c2ecf20Sopenharmony_ci		pptr[0] = 0;
978c2ecf20Sopenharmony_ci		pptr[1] = 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		while (!pptr[2])
1008c2ecf20Sopenharmony_ci			asm volatile("" : : : "memory");
1018c2ecf20Sopenharmony_ci		ret = trace_tar(pid);
1028c2ecf20Sopenharmony_ci		if (ret)
1038c2ecf20Sopenharmony_ci			return ret;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci		ret = trace_tar_write(pid);
1068c2ecf20Sopenharmony_ci		if (ret)
1078c2ecf20Sopenharmony_ci			return ret;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		/* Unblock the child now */
1108c2ecf20Sopenharmony_ci		pptr[0] = 1;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		/* Wait on child */
1138c2ecf20Sopenharmony_ci		while (!pptr[1])
1148c2ecf20Sopenharmony_ci			asm volatile("" : : : "memory");
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		shmdt((int *)pptr);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		ret = wait(&status);
1198c2ecf20Sopenharmony_ci		shmctl(shm_id, IPC_RMID, NULL);
1208c2ecf20Sopenharmony_ci		if (ret != pid) {
1218c2ecf20Sopenharmony_ci			printf("Child's exit status not captured\n");
1228c2ecf20Sopenharmony_ci			return TEST_PASS;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL :
1268c2ecf20Sopenharmony_ci			TEST_PASS;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci	return TEST_PASS;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return test_harness(ptrace_tar, "ptrace_tar");
1348c2ecf20Sopenharmony_ci}
135