1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Ptrace test for VMX/VSX 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-vsx.h" |
10 | |
11 | int shm_id; |
12 | int *cptr, *pptr; |
13 | |
14 | unsigned long fp_load[VEC_MAX]; |
15 | unsigned long fp_load_new[VEC_MAX]; |
16 | unsigned long fp_store[VEC_MAX]; |
17 | unsigned long fp_load_ckpt[VEC_MAX]; |
18 | unsigned long fp_load_ckpt_new[VEC_MAX]; |
19 | |
20 | __attribute__((used)) void load_vsx(void) |
21 | { |
22 | loadvsx(p: fp_load, tmp: 0); |
23 | } |
24 | |
25 | __attribute__((used)) void load_vsx_new(void) |
26 | { |
27 | loadvsx(p: fp_load_new, tmp: 0); |
28 | } |
29 | |
30 | __attribute__((used)) void load_vsx_ckpt(void) |
31 | { |
32 | loadvsx(p: fp_load_ckpt, tmp: 0); |
33 | } |
34 | |
35 | __attribute__((used)) void wait_parent(void) |
36 | { |
37 | cptr[2] = 1; |
38 | while (!cptr[1]) |
39 | asm volatile("" : : : "memory" ); |
40 | } |
41 | |
42 | void tm_spd_vsx(void) |
43 | { |
44 | unsigned long result, texasr; |
45 | int ret; |
46 | |
47 | cptr = (int *)shmat(shm_id, NULL, 0); |
48 | |
49 | trans: |
50 | cptr[2] = 0; |
51 | asm __volatile__( |
52 | "bl load_vsx_ckpt;" |
53 | |
54 | "1: ;" |
55 | "tbegin.;" |
56 | "beq 2f;" |
57 | |
58 | "bl load_vsx_new;" |
59 | "tsuspend.;" |
60 | "bl load_vsx;" |
61 | "bl wait_parent;" |
62 | "tresume.;" |
63 | |
64 | "tend.;" |
65 | "li 0, 0;" |
66 | "ori %[res], 0, 0;" |
67 | "b 3f;" |
68 | |
69 | "2: ;" |
70 | "li 0, 1;" |
71 | "ori %[res], 0, 0;" |
72 | "mfspr %[texasr], %[sprn_texasr];" |
73 | |
74 | "3: ;" |
75 | : [res] "=r" (result), [texasr] "=r" (texasr) |
76 | : [sprn_texasr] "i" (SPRN_TEXASR) |
77 | : "memory" , "r0" , "r3" , "r4" , |
78 | "r7" , "r8" , "r9" , "r10" , "r11" , "lr" |
79 | ); |
80 | |
81 | if (result) { |
82 | if (!cptr[0]) |
83 | goto trans; |
84 | shmdt((void *)cptr); |
85 | |
86 | storevsx(p: fp_store, tmp: 0); |
87 | ret = compare_vsx_vmx(store: fp_store, load: fp_load_ckpt_new); |
88 | if (ret) |
89 | exit(1); |
90 | exit(0); |
91 | } |
92 | shmdt((void *)cptr); |
93 | exit(1); |
94 | } |
95 | |
96 | int trace_tm_spd_vsx(pid_t child) |
97 | { |
98 | unsigned long vsx[VSX_MAX]; |
99 | unsigned long vmx[VMX_MAX + 2][2]; |
100 | |
101 | FAIL_IF(start_trace(child)); |
102 | FAIL_IF(show_vsx(child, vsx)); |
103 | FAIL_IF(validate_vsx(vsx, load: fp_load)); |
104 | FAIL_IF(show_vmx(child, vmx)); |
105 | FAIL_IF(validate_vmx(vmx, load: fp_load)); |
106 | FAIL_IF(show_vsx_ckpt(child, vsx)); |
107 | FAIL_IF(validate_vsx(vsx, load: fp_load_ckpt)); |
108 | FAIL_IF(show_vmx_ckpt(child, vmx)); |
109 | FAIL_IF(validate_vmx(vmx, load: fp_load_ckpt)); |
110 | |
111 | memset(vsx, 0, sizeof(vsx)); |
112 | memset(vmx, 0, sizeof(vmx)); |
113 | |
114 | load_vsx_vmx(load: fp_load_ckpt_new, vsx, vmx); |
115 | |
116 | FAIL_IF(write_vsx_ckpt(child, vsx)); |
117 | FAIL_IF(write_vmx_ckpt(child, vmx)); |
118 | |
119 | pptr[0] = 1; |
120 | pptr[1] = 1; |
121 | FAIL_IF(stop_trace(child)); |
122 | |
123 | return TEST_PASS; |
124 | } |
125 | |
126 | int ptrace_tm_spd_vsx(void) |
127 | { |
128 | pid_t pid; |
129 | int ret, status, i; |
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 | |
135 | for (i = 0; i < 128; i++) { |
136 | fp_load[i] = 1 + rand(); |
137 | fp_load_new[i] = 1 + 2 * rand(); |
138 | fp_load_ckpt[i] = 1 + 3 * rand(); |
139 | fp_load_ckpt_new[i] = 1 + 4 * rand(); |
140 | } |
141 | |
142 | pid = fork(); |
143 | if (pid < 0) { |
144 | perror("fork() failed" ); |
145 | return TEST_FAIL; |
146 | } |
147 | |
148 | if (pid == 0) |
149 | tm_spd_vsx(); |
150 | |
151 | if (pid) { |
152 | pptr = (int *)shmat(shm_id, NULL, 0); |
153 | while (!pptr[2]) |
154 | asm volatile("" : : : "memory" ); |
155 | |
156 | ret = trace_tm_spd_vsx(child: pid); |
157 | if (ret) { |
158 | kill(pid, SIGKILL); |
159 | shmdt((void *)pptr); |
160 | shmctl(shm_id, IPC_RMID, NULL); |
161 | return TEST_FAIL; |
162 | } |
163 | |
164 | shmdt((void *)pptr); |
165 | ret = wait(&status); |
166 | shmctl(shm_id, IPC_RMID, NULL); |
167 | if (ret != pid) { |
168 | printf("Child's exit status not captured\n" ); |
169 | return TEST_FAIL; |
170 | } |
171 | |
172 | return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : |
173 | TEST_PASS; |
174 | } |
175 | return TEST_PASS; |
176 | } |
177 | |
178 | int main(int argc, char *argv[]) |
179 | { |
180 | return test_harness(ptrace_tm_spd_vsx, "ptrace_tm_spd_vsx" ); |
181 | } |
182 | |