]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - arch/powerpc/lib/test_emulate_step.c
Merge remote-tracking branches 'asoc/topic/rockchip', 'asoc/topic/rt5514', 'asoc...
[mirror_ubuntu-bionic-kernel.git] / arch / powerpc / lib / test_emulate_step.c
1 /*
2 * Simple sanity test for emulate_step load/store instructions.
3 *
4 * Copyright IBM Corp. 2016
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12 #define pr_fmt(fmt) "emulate_step_test: " fmt
13
14 #include <linux/ptrace.h>
15 #include <asm/sstep.h>
16 #include <asm/ppc-opcode.h>
17
18 #define IMM_L(i) ((uintptr_t)(i) & 0xffff)
19
20 /*
21 * Defined with TEST_ prefix so it does not conflict with other
22 * definitions.
23 */
24 #define TEST_LD(r, base, i) (PPC_INST_LD | ___PPC_RT(r) | \
25 ___PPC_RA(base) | IMM_L(i))
26 #define TEST_LWZ(r, base, i) (PPC_INST_LWZ | ___PPC_RT(r) | \
27 ___PPC_RA(base) | IMM_L(i))
28 #define TEST_LWZX(t, a, b) (PPC_INST_LWZX | ___PPC_RT(t) | \
29 ___PPC_RA(a) | ___PPC_RB(b))
30 #define TEST_STD(r, base, i) (PPC_INST_STD | ___PPC_RS(r) | \
31 ___PPC_RA(base) | ((i) & 0xfffc))
32 #define TEST_LDARX(t, a, b, eh) (PPC_INST_LDARX | ___PPC_RT(t) | \
33 ___PPC_RA(a) | ___PPC_RB(b) | \
34 __PPC_EH(eh))
35 #define TEST_STDCX(s, a, b) (PPC_INST_STDCX | ___PPC_RS(s) | \
36 ___PPC_RA(a) | ___PPC_RB(b))
37 #define TEST_LFSX(t, a, b) (PPC_INST_LFSX | ___PPC_RT(t) | \
38 ___PPC_RA(a) | ___PPC_RB(b))
39 #define TEST_STFSX(s, a, b) (PPC_INST_STFSX | ___PPC_RS(s) | \
40 ___PPC_RA(a) | ___PPC_RB(b))
41 #define TEST_LFDX(t, a, b) (PPC_INST_LFDX | ___PPC_RT(t) | \
42 ___PPC_RA(a) | ___PPC_RB(b))
43 #define TEST_STFDX(s, a, b) (PPC_INST_STFDX | ___PPC_RS(s) | \
44 ___PPC_RA(a) | ___PPC_RB(b))
45 #define TEST_LVX(t, a, b) (PPC_INST_LVX | ___PPC_RT(t) | \
46 ___PPC_RA(a) | ___PPC_RB(b))
47 #define TEST_STVX(s, a, b) (PPC_INST_STVX | ___PPC_RS(s) | \
48 ___PPC_RA(a) | ___PPC_RB(b))
49 #define TEST_LXVD2X(s, a, b) (PPC_INST_LXVD2X | VSX_XX1((s), R##a, R##b))
50 #define TEST_STXVD2X(s, a, b) (PPC_INST_STXVD2X | VSX_XX1((s), R##a, R##b))
51
52
53 static void __init init_pt_regs(struct pt_regs *regs)
54 {
55 static unsigned long msr;
56 static bool msr_cached;
57
58 memset(regs, 0, sizeof(struct pt_regs));
59
60 if (likely(msr_cached)) {
61 regs->msr = msr;
62 return;
63 }
64
65 asm volatile("mfmsr %0" : "=r"(regs->msr));
66
67 regs->msr |= MSR_FP;
68 regs->msr |= MSR_VEC;
69 regs->msr |= MSR_VSX;
70
71 msr = regs->msr;
72 msr_cached = true;
73 }
74
75 static void __init show_result(char *ins, char *result)
76 {
77 pr_info("%-14s : %s\n", ins, result);
78 }
79
80 static void __init test_ld(void)
81 {
82 struct pt_regs regs;
83 unsigned long a = 0x23;
84 int stepped = -1;
85
86 init_pt_regs(&regs);
87 regs.gpr[3] = (unsigned long) &a;
88
89 /* ld r5, 0(r3) */
90 stepped = emulate_step(&regs, TEST_LD(5, 3, 0));
91
92 if (stepped == 1 && regs.gpr[5] == a)
93 show_result("ld", "PASS");
94 else
95 show_result("ld", "FAIL");
96 }
97
98 static void __init test_lwz(void)
99 {
100 struct pt_regs regs;
101 unsigned int a = 0x4545;
102 int stepped = -1;
103
104 init_pt_regs(&regs);
105 regs.gpr[3] = (unsigned long) &a;
106
107 /* lwz r5, 0(r3) */
108 stepped = emulate_step(&regs, TEST_LWZ(5, 3, 0));
109
110 if (stepped == 1 && regs.gpr[5] == a)
111 show_result("lwz", "PASS");
112 else
113 show_result("lwz", "FAIL");
114 }
115
116 static void __init test_lwzx(void)
117 {
118 struct pt_regs regs;
119 unsigned int a[3] = {0x0, 0x0, 0x1234};
120 int stepped = -1;
121
122 init_pt_regs(&regs);
123 regs.gpr[3] = (unsigned long) a;
124 regs.gpr[4] = 8;
125 regs.gpr[5] = 0x8765;
126
127 /* lwzx r5, r3, r4 */
128 stepped = emulate_step(&regs, TEST_LWZX(5, 3, 4));
129 if (stepped == 1 && regs.gpr[5] == a[2])
130 show_result("lwzx", "PASS");
131 else
132 show_result("lwzx", "FAIL");
133 }
134
135 static void __init test_std(void)
136 {
137 struct pt_regs regs;
138 unsigned long a = 0x1234;
139 int stepped = -1;
140
141 init_pt_regs(&regs);
142 regs.gpr[3] = (unsigned long) &a;
143 regs.gpr[5] = 0x5678;
144
145 /* std r5, 0(r3) */
146 stepped = emulate_step(&regs, TEST_STD(5, 3, 0));
147 if (stepped == 1 || regs.gpr[5] == a)
148 show_result("std", "PASS");
149 else
150 show_result("std", "FAIL");
151 }
152
153 static void __init test_ldarx_stdcx(void)
154 {
155 struct pt_regs regs;
156 unsigned long a = 0x1234;
157 int stepped = -1;
158 unsigned long cr0_eq = 0x1 << 29; /* eq bit of CR0 */
159
160 init_pt_regs(&regs);
161 asm volatile("mfcr %0" : "=r"(regs.ccr));
162
163
164 /*** ldarx ***/
165
166 regs.gpr[3] = (unsigned long) &a;
167 regs.gpr[4] = 0;
168 regs.gpr[5] = 0x5678;
169
170 /* ldarx r5, r3, r4, 0 */
171 stepped = emulate_step(&regs, TEST_LDARX(5, 3, 4, 0));
172
173 /*
174 * Don't touch 'a' here. Touching 'a' can do Load/store
175 * of 'a' which result in failure of subsequent stdcx.
176 * Instead, use hardcoded value for comparison.
177 */
178 if (stepped <= 0 || regs.gpr[5] != 0x1234) {
179 show_result("ldarx / stdcx.", "FAIL (ldarx)");
180 return;
181 }
182
183
184 /*** stdcx. ***/
185
186 regs.gpr[5] = 0x9ABC;
187
188 /* stdcx. r5, r3, r4 */
189 stepped = emulate_step(&regs, TEST_STDCX(5, 3, 4));
190
191 /*
192 * Two possible scenarios that indicates successful emulation
193 * of stdcx. :
194 * 1. Reservation is active and store is performed. In this
195 * case cr0.eq bit will be set to 1.
196 * 2. Reservation is not active and store is not performed.
197 * In this case cr0.eq bit will be set to 0.
198 */
199 if (stepped == 1 && ((regs.gpr[5] == a && (regs.ccr & cr0_eq))
200 || (regs.gpr[5] != a && !(regs.ccr & cr0_eq))))
201 show_result("ldarx / stdcx.", "PASS");
202 else
203 show_result("ldarx / stdcx.", "FAIL (stdcx.)");
204 }
205
206 #ifdef CONFIG_PPC_FPU
207 static void __init test_lfsx_stfsx(void)
208 {
209 struct pt_regs regs;
210 union {
211 float a;
212 int b;
213 } c;
214 int cached_b;
215 int stepped = -1;
216
217 init_pt_regs(&regs);
218
219
220 /*** lfsx ***/
221
222 c.a = 123.45;
223 cached_b = c.b;
224
225 regs.gpr[3] = (unsigned long) &c.a;
226 regs.gpr[4] = 0;
227
228 /* lfsx frt10, r3, r4 */
229 stepped = emulate_step(&regs, TEST_LFSX(10, 3, 4));
230
231 if (stepped == 1)
232 show_result("lfsx", "PASS");
233 else
234 show_result("lfsx", "FAIL");
235
236
237 /*** stfsx ***/
238
239 c.a = 678.91;
240
241 /* stfsx frs10, r3, r4 */
242 stepped = emulate_step(&regs, TEST_STFSX(10, 3, 4));
243
244 if (stepped == 1 && c.b == cached_b)
245 show_result("stfsx", "PASS");
246 else
247 show_result("stfsx", "FAIL");
248 }
249
250 static void __init test_lfdx_stfdx(void)
251 {
252 struct pt_regs regs;
253 union {
254 double a;
255 long b;
256 } c;
257 long cached_b;
258 int stepped = -1;
259
260 init_pt_regs(&regs);
261
262
263 /*** lfdx ***/
264
265 c.a = 123456.78;
266 cached_b = c.b;
267
268 regs.gpr[3] = (unsigned long) &c.a;
269 regs.gpr[4] = 0;
270
271 /* lfdx frt10, r3, r4 */
272 stepped = emulate_step(&regs, TEST_LFDX(10, 3, 4));
273
274 if (stepped == 1)
275 show_result("lfdx", "PASS");
276 else
277 show_result("lfdx", "FAIL");
278
279
280 /*** stfdx ***/
281
282 c.a = 987654.32;
283
284 /* stfdx frs10, r3, r4 */
285 stepped = emulate_step(&regs, TEST_STFDX(10, 3, 4));
286
287 if (stepped == 1 && c.b == cached_b)
288 show_result("stfdx", "PASS");
289 else
290 show_result("stfdx", "FAIL");
291 }
292 #else
293 static void __init test_lfsx_stfsx(void)
294 {
295 show_result("lfsx", "SKIP (CONFIG_PPC_FPU is not set)");
296 show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");
297 }
298
299 static void __init test_lfdx_stfdx(void)
300 {
301 show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");
302 show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");
303 }
304 #endif /* CONFIG_PPC_FPU */
305
306 #ifdef CONFIG_ALTIVEC
307 static void __init test_lvx_stvx(void)
308 {
309 struct pt_regs regs;
310 union {
311 vector128 a;
312 u32 b[4];
313 } c;
314 u32 cached_b[4];
315 int stepped = -1;
316
317 init_pt_regs(&regs);
318
319
320 /*** lvx ***/
321
322 cached_b[0] = c.b[0] = 923745;
323 cached_b[1] = c.b[1] = 2139478;
324 cached_b[2] = c.b[2] = 9012;
325 cached_b[3] = c.b[3] = 982134;
326
327 regs.gpr[3] = (unsigned long) &c.a;
328 regs.gpr[4] = 0;
329
330 /* lvx vrt10, r3, r4 */
331 stepped = emulate_step(&regs, TEST_LVX(10, 3, 4));
332
333 if (stepped == 1)
334 show_result("lvx", "PASS");
335 else
336 show_result("lvx", "FAIL");
337
338
339 /*** stvx ***/
340
341 c.b[0] = 4987513;
342 c.b[1] = 84313948;
343 c.b[2] = 71;
344 c.b[3] = 498532;
345
346 /* stvx vrs10, r3, r4 */
347 stepped = emulate_step(&regs, TEST_STVX(10, 3, 4));
348
349 if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
350 cached_b[2] == c.b[2] && cached_b[3] == c.b[3])
351 show_result("stvx", "PASS");
352 else
353 show_result("stvx", "FAIL");
354 }
355 #else
356 static void __init test_lvx_stvx(void)
357 {
358 show_result("lvx", "SKIP (CONFIG_ALTIVEC is not set)");
359 show_result("stvx", "SKIP (CONFIG_ALTIVEC is not set)");
360 }
361 #endif /* CONFIG_ALTIVEC */
362
363 #ifdef CONFIG_VSX
364 static void __init test_lxvd2x_stxvd2x(void)
365 {
366 struct pt_regs regs;
367 union {
368 vector128 a;
369 u32 b[4];
370 } c;
371 u32 cached_b[4];
372 int stepped = -1;
373
374 init_pt_regs(&regs);
375
376
377 /*** lxvd2x ***/
378
379 cached_b[0] = c.b[0] = 18233;
380 cached_b[1] = c.b[1] = 34863571;
381 cached_b[2] = c.b[2] = 834;
382 cached_b[3] = c.b[3] = 6138911;
383
384 regs.gpr[3] = (unsigned long) &c.a;
385 regs.gpr[4] = 0;
386
387 /* lxvd2x vsr39, r3, r4 */
388 stepped = emulate_step(&regs, TEST_LXVD2X(39, 3, 4));
389
390 if (stepped == 1)
391 show_result("lxvd2x", "PASS");
392 else
393 show_result("lxvd2x", "FAIL");
394
395
396 /*** stxvd2x ***/
397
398 c.b[0] = 21379463;
399 c.b[1] = 87;
400 c.b[2] = 374234;
401 c.b[3] = 4;
402
403 /* stxvd2x vsr39, r3, r4 */
404 stepped = emulate_step(&regs, TEST_STXVD2X(39, 3, 4));
405
406 if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
407 cached_b[2] == c.b[2] && cached_b[3] == c.b[3])
408 show_result("stxvd2x", "PASS");
409 else
410 show_result("stxvd2x", "FAIL");
411 }
412 #else
413 static void __init test_lxvd2x_stxvd2x(void)
414 {
415 show_result("lxvd2x", "SKIP (CONFIG_VSX is not set)");
416 show_result("stxvd2x", "SKIP (CONFIG_VSX is not set)");
417 }
418 #endif /* CONFIG_VSX */
419
420 static int __init test_emulate_step(void)
421 {
422 test_ld();
423 test_lwz();
424 test_lwzx();
425 test_std();
426 test_ldarx_stdcx();
427 test_lfsx_stfsx();
428 test_lfdx_stfdx();
429 test_lvx_stvx();
430 test_lxvd2x_stxvd2x();
431
432 return 0;
433 }
434 late_initcall(test_emulate_step);