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(®s); 87 regs.gpr[3] = (unsigned long) &a; 88 89 /* ld r5, 0(r3) */ 90 stepped = emulate_step(®s, 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(®s); 105 regs.gpr[3] = (unsigned long) &a; 106 107 /* lwz r5, 0(r3) */ 108 stepped = emulate_step(®s, 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(®s); 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(®s, 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(®s); 142 regs.gpr[3] = (unsigned long) &a; 143 regs.gpr[5] = 0x5678; 144 145 /* std r5, 0(r3) */ 146 stepped = emulate_step(®s, 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(®s); 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(®s, 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(®s, 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(®s); 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(®s, 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(®s, 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(®s); 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(®s, 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(®s, 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(®s); 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(®s, 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(®s, 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(®s); 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(®s, TEST_LXVD2X(39, 3, 4)); 389 390 if (stepped == 1 && cpu_has_feature(CPU_FTR_VSX)) { 391 show_result("lxvd2x", "PASS"); 392 } else { 393 if (!cpu_has_feature(CPU_FTR_VSX)) 394 show_result("lxvd2x", "PASS (!CPU_FTR_VSX)"); 395 else 396 show_result("lxvd2x", "FAIL"); 397 } 398 399 400 /*** stxvd2x ***/ 401 402 c.b[0] = 21379463; 403 c.b[1] = 87; 404 c.b[2] = 374234; 405 c.b[3] = 4; 406 407 /* stxvd2x vsr39, r3, r4 */ 408 stepped = emulate_step(®s, TEST_STXVD2X(39, 3, 4)); 409 410 if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] && 411 cached_b[2] == c.b[2] && cached_b[3] == c.b[3] && 412 cpu_has_feature(CPU_FTR_VSX)) { 413 show_result("stxvd2x", "PASS"); 414 } else { 415 if (!cpu_has_feature(CPU_FTR_VSX)) 416 show_result("stxvd2x", "PASS (!CPU_FTR_VSX)"); 417 else 418 show_result("stxvd2x", "FAIL"); 419 } 420 } 421 #else 422 static void __init test_lxvd2x_stxvd2x(void) 423 { 424 show_result("lxvd2x", "SKIP (CONFIG_VSX is not set)"); 425 show_result("stxvd2x", "SKIP (CONFIG_VSX is not set)"); 426 } 427 #endif /* CONFIG_VSX */ 428 429 static int __init test_emulate_step(void) 430 { 431 test_ld(); 432 test_lwz(); 433 test_lwzx(); 434 test_std(); 435 test_ldarx_stdcx(); 436 test_lfsx_stfsx(); 437 test_lfdx_stfdx(); 438 test_lvx_stvx(); 439 test_lxvd2x_stxvd2x(); 440 441 return 0; 442 } 443 late_initcall(test_emulate_step); 444