1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Ptrace test for TAR, PPR, DSCR registers in the TM Suspend context |
4 | * |
5 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. |
6 | */ |
7 | #include "ptrace.h" |
8 | #include "tm.h" |
9 | #include "ptrace-tar.h" |
10 | |
11 | int shm_id; |
12 | int *cptr, *pptr; |
13 | |
14 | __attribute__((used)) void wait_parent(void) |
15 | { |
16 | cptr[2] = 1; |
17 | while (!cptr[1]) |
18 | asm volatile("" : : : "memory" ); |
19 | } |
20 | |
21 | void tm_spd_tar(void) |
22 | { |
23 | unsigned long result, texasr; |
24 | unsigned long regs[3]; |
25 | int ret; |
26 | |
27 | cptr = (int *)shmat(shm_id, NULL, 0); |
28 | |
29 | trans: |
30 | cptr[2] = 0; |
31 | asm __volatile__( |
32 | "li 4, %[tar_1];" |
33 | "mtspr %[sprn_tar], 4;" /* TAR_1 */ |
34 | "li 4, %[dscr_1];" |
35 | "mtspr %[sprn_dscr], 4;" /* DSCR_1 */ |
36 | "or 31,31,31;" /* PPR_1*/ |
37 | |
38 | "1: ;" |
39 | "tbegin.;" |
40 | "beq 2f;" |
41 | |
42 | "li 4, %[tar_2];" |
43 | "mtspr %[sprn_tar], 4;" /* TAR_2 */ |
44 | "li 4, %[dscr_2];" |
45 | "mtspr %[sprn_dscr], 4;" /* DSCR_2 */ |
46 | "or 1,1,1;" /* PPR_2 */ |
47 | |
48 | "tsuspend.;" |
49 | "li 4, %[tar_3];" |
50 | "mtspr %[sprn_tar], 4;" /* TAR_3 */ |
51 | "li 4, %[dscr_3];" |
52 | "mtspr %[sprn_dscr], 4;" /* DSCR_3 */ |
53 | "or 6,6,6;" /* PPR_3 */ |
54 | "bl wait_parent;" |
55 | "tresume.;" |
56 | |
57 | "tend.;" |
58 | "li 0, 0;" |
59 | "ori %[res], 0, 0;" |
60 | "b 3f;" |
61 | |
62 | /* Transaction abort handler */ |
63 | "2: ;" |
64 | "li 0, 1;" |
65 | "ori %[res], 0, 0;" |
66 | "mfspr %[texasr], %[sprn_texasr];" |
67 | |
68 | "3: ;" |
69 | |
70 | : [res] "=r" (result), [texasr] "=r" (texasr) |
71 | : [sprn_dscr]"i" (SPRN_DSCR), |
72 | [sprn_tar]"i" (SPRN_TAR), [sprn_ppr]"i" (SPRN_PPR), |
73 | [sprn_texasr]"i" (SPRN_TEXASR), [tar_1]"i" (TAR_1), |
74 | [dscr_1]"i" (DSCR_1), [tar_2]"i" (TAR_2), [dscr_2]"i" (DSCR_2), |
75 | [tar_3]"i" (TAR_3), [dscr_3]"i" (DSCR_3) |
76 | : "memory" , "r0" , "r3" , "r4" , "r5" , "r6" , "lr" |
77 | ); |
78 | |
79 | /* TM failed, analyse */ |
80 | if (result) { |
81 | if (!cptr[0]) |
82 | goto trans; |
83 | |
84 | regs[0] = mfspr(SPRN_TAR); |
85 | regs[1] = mfspr(SPRN_PPR); |
86 | regs[2] = mfspr(SPRN_DSCR); |
87 | |
88 | shmdt(&cptr); |
89 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n" , |
90 | user_read, regs[0], regs[1], regs[2]); |
91 | |
92 | ret = validate_tar_registers(reg: regs, TAR_4, PPR_4, DSCR_4); |
93 | if (ret) |
94 | exit(1); |
95 | exit(0); |
96 | } |
97 | shmdt(&cptr); |
98 | exit(1); |
99 | } |
100 | |
101 | int trace_tm_spd_tar(pid_t child) |
102 | { |
103 | unsigned long regs[3]; |
104 | |
105 | FAIL_IF(start_trace(child)); |
106 | FAIL_IF(show_tar_registers(child, out: regs)); |
107 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n" , |
108 | ptrace_read_running, regs[0], regs[1], regs[2]); |
109 | |
110 | FAIL_IF(validate_tar_registers(reg: regs, TAR_3, PPR_3, DSCR_3)); |
111 | FAIL_IF(show_tm_checkpointed_state(child, out: regs)); |
112 | printf("%-30s TAR: %lu PPR: %lx DSCR: %lu\n" , |
113 | ptrace_read_ckpt, regs[0], regs[1], regs[2]); |
114 | |
115 | FAIL_IF(validate_tar_registers(reg: regs, TAR_1, PPR_1, DSCR_1)); |
116 | FAIL_IF(write_ckpt_tar_registers(child, TAR_4, PPR_4, DSCR_4)); |
117 | printf("%-30s TAR: %u PPR: %lx DSCR: %u\n" , |
118 | ptrace_write_ckpt, TAR_4, PPR_4, DSCR_4); |
119 | |
120 | pptr[0] = 1; |
121 | pptr[1] = 1; |
122 | FAIL_IF(stop_trace(child)); |
123 | return TEST_PASS; |
124 | } |
125 | |
126 | int ptrace_tm_spd_tar(void) |
127 | { |
128 | pid_t pid; |
129 | int ret, status; |
130 | |
131 | SKIP_IF_MSG(!have_htm(), "Don't have transactional memory" ); |
132 | SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic" ); |
133 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); |
134 | pid = fork(); |
135 | if (pid == 0) |
136 | tm_spd_tar(); |
137 | |
138 | pptr = (int *)shmat(shm_id, NULL, 0); |
139 | pptr[0] = 0; |
140 | pptr[1] = 0; |
141 | |
142 | if (pid) { |
143 | while (!pptr[2]) |
144 | asm volatile("" : : : "memory" ); |
145 | ret = trace_tm_spd_tar(child: pid); |
146 | if (ret) { |
147 | kill(pid, SIGTERM); |
148 | shmdt(&pptr); |
149 | shmctl(shm_id, IPC_RMID, NULL); |
150 | return TEST_FAIL; |
151 | } |
152 | |
153 | shmdt(&pptr); |
154 | |
155 | ret = wait(&status); |
156 | shmctl(shm_id, IPC_RMID, NULL); |
157 | if (ret != pid) { |
158 | printf("Child's exit status not captured\n" ); |
159 | return TEST_FAIL; |
160 | } |
161 | |
162 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : |
163 | TEST_PASS; |
164 | } |
165 | return TEST_PASS; |
166 | } |
167 | |
168 | int main(int argc, char *argv[]) |
169 | { |
170 | return test_harness(ptrace_tm_spd_tar, "ptrace_tm_spd_tar" ); |
171 | } |
172 | |