linux/arch/powerpc/lib/test_emulate_step.c
<<
>>
Prefs
   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
  53static 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
  75static void __init show_result(char *ins, char *result)
  76{
  77        pr_info("%-14s : %s\n", ins, result);
  78}
  79
  80static 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
  98static 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
 116static 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
 135static 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
 153static 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
 207static 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
 250static 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
 293static 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
 299static 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
 307static 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
 356static 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
 364static 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
 413static 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
 420static 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}
 434late_initcall(test_emulate_step);
 435