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