Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / tools / testing / selftests / powerpc / ptrace / ptrace-tm-spr.c
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 }