1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Ptrace test TM SPR registers
4  *
5  * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
6  */
7 #include "ptrace.h"
8 #include "tm.h"
9 
10 /* Tracee and tracer shared data */
11 struct shared {
12 	int flag;
13 	struct tm_spr_regs regs;
14 };
15 unsigned long tfhar;
16 
17 int shm_id;
18 struct shared *cptr, *pptr;
19 
20 int shm_id1;
21 int *cptr1, *pptr1;
22 
23 #define TM_KVM_SCHED   0xe0000001ac000001
24 int validate_tm_spr(struct tm_spr_regs *regs)
25 {
26 	FAIL_IF(regs->tm_tfhar != tfhar);
27 	FAIL_IF((regs->tm_texasr == TM_KVM_SCHED) && (regs->tm_tfiar != 0));
28 
29 	return TEST_PASS;
30 }
31 
32 void tm_spr(void)
33 {
34 	unsigned long result, texasr;
35 	int ret;
36 
37 	cptr = (struct shared *)shmat(shm_id, NULL, 0);
38 	cptr1 = (int *)shmat(shm_id1, NULL, 0);
39 
40 trans:
41 	cptr1[0] = 0;
42 	asm __volatile__(
43 		"1: ;"
44 		/* TM failover handler should follow "tbegin.;" */
45 		"mflr 31;"
46 		"bl 4f;"	/* $ = TFHAR - 12 */
47 		"4: ;"
48 		"mflr %[tfhar];"
49 		"mtlr 31;"
50 
51 		"tbegin.;"
52 		"beq 2f;"
53 
54 		"tsuspend.;"
55 		"li 8, 1;"
56 		"sth 8, 0(%[cptr1]);"
57 		"tresume.;"
58 		"b .;"
59 
60 		"tend.;"
61 		"li 0, 0;"
62 		"ori %[res], 0, 0;"
63 		"b 3f;"
64 
65 		"2: ;"
66 
67 		"li 0, 1;"
68 		"ori %[res], 0, 0;"
69 		"mfspr %[texasr], %[sprn_texasr];"
70 
71 		"3: ;"
72 		: [tfhar] "=r" (tfhar), [res] "=r" (result),
73 		[texasr] "=r" (texasr), [cptr1] "=b" (cptr1)
74 		: [sprn_texasr] "i"  (SPRN_TEXASR)
75 		: "memory", "r0", "r8", "r31"
76 		);
77 
78 	/* There are 2 32bit instructions before tbegin. */
79 	tfhar += 12;
80 
81 	if (result) {
82 		if (!cptr->flag)
83 			goto trans;
84 
85 		ret = validate_tm_spr((struct tm_spr_regs *)&cptr->regs);
86 		shmdt((void *)cptr);
87 		shmdt((void *)cptr1);
88 		if (ret)
89 			exit(1);
90 		exit(0);
91 	}
92 	shmdt((void *)cptr);
93 	shmdt((void *)cptr1);
94 	exit(1);
95 }
96 
97 int trace_tm_spr(pid_t child)
98 {
99 	FAIL_IF(start_trace(child));
100 	FAIL_IF(show_tm_spr(child, (struct tm_spr_regs *)&pptr->regs));
101 
102 	printf("TFHAR: %lx TEXASR: %lx TFIAR: %lx\n", pptr->regs.tm_tfhar,
103 				pptr->regs.tm_texasr, pptr->regs.tm_tfiar);
104 
105 	pptr->flag = 1;
106 	FAIL_IF(stop_trace(child));
107 
108 	return TEST_PASS;
109 }
110 
111 int ptrace_tm_spr(void)
112 {
113 	pid_t pid;
114 	int ret, status;
115 
116 	SKIP_IF(!have_htm());
117 	shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT);
118 	shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT);
119 	pid = fork();
120 	if (pid < 0) {
121 		perror("fork() failed");
122 		return TEST_FAIL;
123 	}
124 
125 	if (pid == 0)
126 		tm_spr();
127 
128 	if (pid) {
129 		pptr = (struct shared *)shmat(shm_id, NULL, 0);
130 		pptr1 = (int *)shmat(shm_id1, NULL, 0);
131 
132 		while (!pptr1[0])
133 			asm volatile("" : : : "memory");
134 		ret = trace_tm_spr(pid);
135 		if (ret) {
136 			kill(pid, SIGKILL);
137 			shmdt((void *)pptr);
138 			shmdt((void *)pptr1);
139 			shmctl(shm_id, IPC_RMID, NULL);
140 			shmctl(shm_id1, IPC_RMID, NULL);
141 			return TEST_FAIL;
142 		}
143 
144 		shmdt((void *)pptr);
145 		shmdt((void *)pptr1);
146 		ret = wait(&status);
147 		shmctl(shm_id, IPC_RMID, NULL);
148 		shmctl(shm_id1, IPC_RMID, NULL);
149 		if (ret != pid) {
150 			printf("Child's exit status not captured\n");
151 			return TEST_FAIL;
152 		}
153 
154 		return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL :
155 			TEST_PASS;
156 	}
157 	return TEST_PASS;
158 }
159 
160 int main(int argc, char *argv[])
161 {
162 	return test_harness(ptrace_tm_spr, "ptrace_tm_spr");
163 }
164