1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Ptrace test for GPR/FPR registers in TM Suspend context |
4 | * |
5 | * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. |
6 | */ |
7 | #include "ptrace.h" |
8 | #include "ptrace-gpr.h" |
9 | #include "tm.h" |
10 | |
11 | /* Tracer and Tracee Shared Data */ |
12 | int shm_id; |
13 | int *cptr, *pptr; |
14 | |
15 | double a = FPR_1; |
16 | double b = FPR_2; |
17 | double c = FPR_3; |
18 | double d = FPR_4; |
19 | |
20 | __attribute__((used)) void wait_parent(void) |
21 | { |
22 | cptr[2] = 1; |
23 | while (!cptr[1]) |
24 | asm volatile("" : : : "memory" ); |
25 | } |
26 | |
27 | void tm_spd_gpr(void) |
28 | { |
29 | unsigned long gpr_buf[18]; |
30 | unsigned long result, texasr; |
31 | double fpr_buf[32]; |
32 | |
33 | cptr = (int *)shmat(shm_id, NULL, 0); |
34 | |
35 | trans: |
36 | cptr[2] = 0; |
37 | asm __volatile__( |
38 | ASM_LOAD_GPR_IMMED(gpr_1) |
39 | ASM_LOAD_FPR(flt_1) |
40 | |
41 | "1: ;" |
42 | "tbegin.;" |
43 | "beq 2f;" |
44 | |
45 | ASM_LOAD_GPR_IMMED(gpr_2) |
46 | "tsuspend.;" |
47 | ASM_LOAD_GPR_IMMED(gpr_4) |
48 | ASM_LOAD_FPR(flt_4) |
49 | |
50 | "bl wait_parent;" |
51 | "tresume.;" |
52 | "tend.;" |
53 | "li 0, 0;" |
54 | "ori %[res], 0, 0;" |
55 | "b 3f;" |
56 | |
57 | /* Transaction abort handler */ |
58 | "2: ;" |
59 | "li 0, 1;" |
60 | "ori %[res], 0, 0;" |
61 | "mfspr %[texasr], %[sprn_texasr];" |
62 | |
63 | "3: ;" |
64 | : [res] "=r" (result), [texasr] "=r" (texasr) |
65 | : [gpr_1]"i" (GPR_1), [gpr_2]"i" (GPR_2), [gpr_4]"i" (GPR_4), |
66 | [sprn_texasr] "i" (SPRN_TEXASR), [flt_1] "b" (&a), |
67 | [flt_4] "b" (&d) |
68 | : "memory" , "r0" , "r5" , "r6" , "r7" , |
69 | "r8" , "r9" , "r10" , "r11" , "r12" , "r13" , "r14" , "r15" , |
70 | "r16" , "r17" , "r18" , "r19" , "r20" , "r21" , "r22" , "r23" , |
71 | "r24" , "r25" , "r26" , "r27" , "r28" , "r29" , "r30" , "r31" |
72 | ); |
73 | |
74 | if (result) { |
75 | if (!cptr[0]) |
76 | goto trans; |
77 | |
78 | shmdt((void *)cptr); |
79 | store_gpr(addr: gpr_buf); |
80 | store_fpr(fpr_buf); |
81 | |
82 | if (validate_gpr(gpr: gpr_buf, GPR_3)) |
83 | exit(1); |
84 | |
85 | if (validate_fpr_double(fpr: fpr_buf, val: c)) |
86 | exit(1); |
87 | exit(0); |
88 | } |
89 | shmdt((void *)cptr); |
90 | exit(1); |
91 | } |
92 | |
93 | int trace_tm_spd_gpr(pid_t child) |
94 | { |
95 | unsigned long gpr[18]; |
96 | __u64 fpr[32]; |
97 | |
98 | FAIL_IF(start_trace(child)); |
99 | FAIL_IF(show_gpr(child, gpr)); |
100 | FAIL_IF(validate_gpr(gpr, GPR_4)); |
101 | FAIL_IF(show_fpr(child, fpr)); |
102 | FAIL_IF(validate_fpr(fpr, FPR_4_REP)); |
103 | FAIL_IF(show_ckpt_fpr(child, fpr)); |
104 | FAIL_IF(validate_fpr(fpr, FPR_1_REP)); |
105 | FAIL_IF(show_ckpt_gpr(child, gpr)); |
106 | FAIL_IF(validate_gpr(gpr, GPR_1)); |
107 | FAIL_IF(write_ckpt_gpr(child, GPR_3)); |
108 | FAIL_IF(write_ckpt_fpr(child, FPR_3_REP)); |
109 | |
110 | pptr[0] = 1; |
111 | pptr[1] = 1; |
112 | FAIL_IF(stop_trace(child)); |
113 | return TEST_PASS; |
114 | } |
115 | |
116 | int ptrace_tm_spd_gpr(void) |
117 | { |
118 | pid_t pid; |
119 | int ret, status; |
120 | |
121 | SKIP_IF_MSG(!have_htm(), "Don't have transactional memory" ); |
122 | SKIP_IF_MSG(htm_is_synthetic(), "Transactional memory is synthetic" ); |
123 | shm_id = shmget(IPC_PRIVATE, sizeof(int) * 3, 0777|IPC_CREAT); |
124 | pid = fork(); |
125 | if (pid < 0) { |
126 | perror("fork() failed" ); |
127 | return TEST_FAIL; |
128 | } |
129 | |
130 | if (pid == 0) |
131 | tm_spd_gpr(); |
132 | |
133 | if (pid) { |
134 | pptr = (int *)shmat(shm_id, NULL, 0); |
135 | pptr[0] = 0; |
136 | pptr[1] = 0; |
137 | |
138 | while (!pptr[2]) |
139 | asm volatile("" : : : "memory" ); |
140 | ret = trace_tm_spd_gpr(child: pid); |
141 | if (ret) { |
142 | kill(pid, SIGTERM); |
143 | shmdt((void *)pptr); |
144 | shmctl(shm_id, IPC_RMID, NULL); |
145 | return TEST_FAIL; |
146 | } |
147 | |
148 | shmdt((void *)pptr); |
149 | |
150 | ret = wait(&status); |
151 | shmctl(shm_id, IPC_RMID, NULL); |
152 | if (ret != pid) { |
153 | printf("Child's exit status not captured\n" ); |
154 | return TEST_FAIL; |
155 | } |
156 | |
157 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : |
158 | TEST_PASS; |
159 | } |
160 | return TEST_PASS; |
161 | } |
162 | |
163 | int main(int argc, char *argv[]) |
164 | { |
165 | return test_harness(ptrace_tm_spd_gpr, "ptrace_tm_spd_gpr" ); |
166 | } |
167 | |