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(regs: (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, out: (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_MSG(!have_htm(), "Don't have transactional memory" ); |
117 | SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic" ); |
118 | shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); |
119 | shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); |
120 | pid = fork(); |
121 | if (pid < 0) { |
122 | perror("fork() failed" ); |
123 | return TEST_FAIL; |
124 | } |
125 | |
126 | if (pid == 0) |
127 | tm_spr(); |
128 | |
129 | if (pid) { |
130 | pptr = (struct shared *)shmat(shm_id, NULL, 0); |
131 | pptr1 = (int *)shmat(shm_id1, NULL, 0); |
132 | |
133 | while (!pptr1[0]) |
134 | asm volatile("" : : : "memory" ); |
135 | ret = trace_tm_spr(child: pid); |
136 | if (ret) { |
137 | kill(pid, SIGKILL); |
138 | shmdt((void *)pptr); |
139 | shmdt((void *)pptr1); |
140 | shmctl(shm_id, IPC_RMID, NULL); |
141 | shmctl(shm_id1, IPC_RMID, NULL); |
142 | return TEST_FAIL; |
143 | } |
144 | |
145 | shmdt((void *)pptr); |
146 | shmdt((void *)pptr1); |
147 | ret = wait(&status); |
148 | shmctl(shm_id, IPC_RMID, NULL); |
149 | shmctl(shm_id1, IPC_RMID, NULL); |
150 | if (ret != pid) { |
151 | printf("Child's exit status not captured\n" ); |
152 | return TEST_FAIL; |
153 | } |
154 | |
155 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : |
156 | TEST_PASS; |
157 | } |
158 | return TEST_PASS; |
159 | } |
160 | |
161 | int main(int argc, char *argv[]) |
162 | { |
163 | return test_harness(ptrace_tm_spr, "ptrace_tm_spr" ); |
164 | } |
165 | |