1*ee30cf14SThomas Huth /* 2*ee30cf14SThomas Huth * Test Special Purpose Registers 3*ee30cf14SThomas Huth * 4*ee30cf14SThomas Huth * Copyright 2017 Thomas Huth, Red Hat Inc. 5*ee30cf14SThomas Huth * 6*ee30cf14SThomas Huth * This work is licensed under the terms of the GNU LGPL, version 2. 7*ee30cf14SThomas Huth * 8*ee30cf14SThomas Huth * The basic idea of this test is to check whether the contents of the Special 9*ee30cf14SThomas Huth * Purpose Registers (SPRs) are preserved correctly during migration. So we 10*ee30cf14SThomas Huth * fill in the SPRs with a well-known value, read the values back (since not 11*ee30cf14SThomas Huth * all bits might be retained in the SPRs), then wait for a key or NMI (if the 12*ee30cf14SThomas Huth * '-w' option has been specified) so that the user has a chance to migrate the 13*ee30cf14SThomas Huth * VM. Alternatively, the test can also simply sleep a little bit with the 14*ee30cf14SThomas Huth * H_CEDE hypercall, in the hope that we'll get scheduled to another host CPU 15*ee30cf14SThomas Huth * and thus register contents might have changed, too (in case of bugs). 16*ee30cf14SThomas Huth * Finally, we read back the values from the SPRs and compare them with the 17*ee30cf14SThomas Huth * values before the migration. Mismatches are reported as test failures. 18*ee30cf14SThomas Huth * Note that we do not test all SPRs since some of the registers change their 19*ee30cf14SThomas Huth * content automatically, and some are only accessible with hypervisor privi- 20*ee30cf14SThomas Huth * leges or have bad side effects, so we have to omit those registers. 21*ee30cf14SThomas Huth */ 22*ee30cf14SThomas Huth #include <libcflat.h> 23*ee30cf14SThomas Huth #include <util.h> 24*ee30cf14SThomas Huth #include <alloc.h> 25*ee30cf14SThomas Huth #include <asm/handlers.h> 26*ee30cf14SThomas Huth #include <asm/hcall.h> 27*ee30cf14SThomas Huth #include <asm/processor.h> 28*ee30cf14SThomas Huth #include <asm/barrier.h> 29*ee30cf14SThomas Huth 30*ee30cf14SThomas Huth #define mfspr(nr) ({ \ 31*ee30cf14SThomas Huth uint64_t ret; \ 32*ee30cf14SThomas Huth asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \ 33*ee30cf14SThomas Huth ret; \ 34*ee30cf14SThomas Huth }) 35*ee30cf14SThomas Huth 36*ee30cf14SThomas Huth #define mtspr(nr, val) \ 37*ee30cf14SThomas Huth asm volatile("mtspr %0,%1" : : "i"(nr), "r"(val)) 38*ee30cf14SThomas Huth 39*ee30cf14SThomas Huth uint64_t before[1024], after[1024]; 40*ee30cf14SThomas Huth 41*ee30cf14SThomas Huth volatile int nmi_occurred; 42*ee30cf14SThomas Huth 43*ee30cf14SThomas Huth static void nmi_handler(struct pt_regs *regs __unused, void *opaque __unused) 44*ee30cf14SThomas Huth { 45*ee30cf14SThomas Huth nmi_occurred = 1; 46*ee30cf14SThomas Huth } 47*ee30cf14SThomas Huth 48*ee30cf14SThomas Huth static int h_get_term_char(uint64_t termno) 49*ee30cf14SThomas Huth { 50*ee30cf14SThomas Huth register uint64_t r3 asm("r3") = 0x54; /* H_GET_TERM_CHAR */ 51*ee30cf14SThomas Huth register uint64_t r4 asm("r4") = termno; 52*ee30cf14SThomas Huth register uint64_t r5 asm("r5"); 53*ee30cf14SThomas Huth 54*ee30cf14SThomas Huth asm volatile (" sc 1 " : "+r"(r3), "+r"(r4), "=r"(r5) 55*ee30cf14SThomas Huth : "r"(r3), "r"(r4)); 56*ee30cf14SThomas Huth 57*ee30cf14SThomas Huth return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : 0; 58*ee30cf14SThomas Huth } 59*ee30cf14SThomas Huth 60*ee30cf14SThomas Huth /* Common SPRs for all PowerPC CPUs */ 61*ee30cf14SThomas Huth static void set_sprs_common(uint64_t val) 62*ee30cf14SThomas Huth { 63*ee30cf14SThomas Huth mtspr(9, val); /* CTR */ 64*ee30cf14SThomas Huth // mtspr(273, val); /* SPRG1 */ /* Used by our exception handler */ 65*ee30cf14SThomas Huth mtspr(274, val); /* SPRG2 */ 66*ee30cf14SThomas Huth mtspr(275, val); /* SPRG3 */ 67*ee30cf14SThomas Huth } 68*ee30cf14SThomas Huth 69*ee30cf14SThomas Huth /* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */ 70*ee30cf14SThomas Huth static void set_sprs_book3s_201(uint64_t val) 71*ee30cf14SThomas Huth { 72*ee30cf14SThomas Huth mtspr(18, val); /* DSISR */ 73*ee30cf14SThomas Huth mtspr(19, val); /* DAR */ 74*ee30cf14SThomas Huth mtspr(152, val); /* CTRL */ 75*ee30cf14SThomas Huth mtspr(256, val); /* VRSAVE */ 76*ee30cf14SThomas Huth mtspr(786, val); /* MMCRA */ 77*ee30cf14SThomas Huth mtspr(795, val); /* MMCR0 */ 78*ee30cf14SThomas Huth mtspr(798, val); /* MMCR1 */ 79*ee30cf14SThomas Huth } 80*ee30cf14SThomas Huth 81*ee30cf14SThomas Huth /* SPRs from PowerISA 2.07 Book III-S */ 82*ee30cf14SThomas Huth static void set_sprs_book3s_207(uint64_t val) 83*ee30cf14SThomas Huth { 84*ee30cf14SThomas Huth mtspr(3, val); /* DSCR */ 85*ee30cf14SThomas Huth mtspr(13, val); /* AMR */ 86*ee30cf14SThomas Huth mtspr(17, val); /* DSCR */ 87*ee30cf14SThomas Huth mtspr(18, val); /* DSISR */ 88*ee30cf14SThomas Huth mtspr(19, val); /* DAR */ 89*ee30cf14SThomas Huth mtspr(29, val); /* AMR */ 90*ee30cf14SThomas Huth mtspr(61, val); /* IAMR */ 91*ee30cf14SThomas Huth // mtspr(152, val); /* CTRL */ /* TODO: Needs a fix in KVM */ 92*ee30cf14SThomas Huth mtspr(153, val); /* FSCR */ 93*ee30cf14SThomas Huth mtspr(157, val); /* UAMOR */ 94*ee30cf14SThomas Huth mtspr(159, val); /* PSPB */ 95*ee30cf14SThomas Huth mtspr(256, val); /* VRSAVE */ 96*ee30cf14SThomas Huth // mtspr(272, val); /* SPRG0 */ /* Used by our exception handler */ 97*ee30cf14SThomas Huth mtspr(769, val); /* MMCR2 */ 98*ee30cf14SThomas Huth mtspr(770, val); /* MMCRA */ 99*ee30cf14SThomas Huth mtspr(771, val); /* PMC1 */ 100*ee30cf14SThomas Huth mtspr(772, val); /* PMC2 */ 101*ee30cf14SThomas Huth mtspr(773, val); /* PMC3 */ 102*ee30cf14SThomas Huth mtspr(774, val); /* PMC4 */ 103*ee30cf14SThomas Huth mtspr(775, val); /* PMC5 */ 104*ee30cf14SThomas Huth mtspr(776, val); /* PMC6 */ 105*ee30cf14SThomas Huth mtspr(779, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ 106*ee30cf14SThomas Huth mtspr(784, val); /* SIER */ 107*ee30cf14SThomas Huth mtspr(785, val); /* MMCR2 */ 108*ee30cf14SThomas Huth mtspr(786, val); /* MMCRA */ 109*ee30cf14SThomas Huth mtspr(787, val); /* PMC1 */ 110*ee30cf14SThomas Huth mtspr(788, val); /* PMC2 */ 111*ee30cf14SThomas Huth mtspr(789, val); /* PMC3 */ 112*ee30cf14SThomas Huth mtspr(790, val); /* PMC4 */ 113*ee30cf14SThomas Huth mtspr(791, val); /* PMC5 */ 114*ee30cf14SThomas Huth mtspr(792, val); /* PMC6 */ 115*ee30cf14SThomas Huth mtspr(795, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ 116*ee30cf14SThomas Huth mtspr(796, val); /* SIAR */ 117*ee30cf14SThomas Huth mtspr(797, val); /* SDAR */ 118*ee30cf14SThomas Huth mtspr(798, val); /* MMCR1 */ 119*ee30cf14SThomas Huth mtspr(800, val); /* BESCRS */ 120*ee30cf14SThomas Huth mtspr(801, val); /* BESCCRSU */ 121*ee30cf14SThomas Huth mtspr(802, val); /* BESCRR */ 122*ee30cf14SThomas Huth mtspr(803, val); /* BESCRRU */ 123*ee30cf14SThomas Huth mtspr(804, val); /* EBBHR */ 124*ee30cf14SThomas Huth mtspr(805, val); /* EBBRR */ 125*ee30cf14SThomas Huth mtspr(806, val); /* BESCR */ 126*ee30cf14SThomas Huth mtspr(815, val); /* TAR */ 127*ee30cf14SThomas Huth } 128*ee30cf14SThomas Huth 129*ee30cf14SThomas Huth static void set_sprs(uint64_t val) 130*ee30cf14SThomas Huth { 131*ee30cf14SThomas Huth uint32_t pvr = mfspr(287); /* Processor Version Register */ 132*ee30cf14SThomas Huth 133*ee30cf14SThomas Huth set_sprs_common(val); 134*ee30cf14SThomas Huth 135*ee30cf14SThomas Huth switch (pvr >> 16) { 136*ee30cf14SThomas Huth case 0x39: /* PPC970 */ 137*ee30cf14SThomas Huth case 0x3C: /* PPC970FX */ 138*ee30cf14SThomas Huth case 0x44: /* PPC970MP */ 139*ee30cf14SThomas Huth set_sprs_book3s_201(val); 140*ee30cf14SThomas Huth break; 141*ee30cf14SThomas Huth case 0x4b: /* POWER8E */ 142*ee30cf14SThomas Huth case 0x4c: /* POWER8NVL */ 143*ee30cf14SThomas Huth case 0x4d: /* POWER8 */ 144*ee30cf14SThomas Huth set_sprs_book3s_207(val); 145*ee30cf14SThomas Huth break; 146*ee30cf14SThomas Huth default: 147*ee30cf14SThomas Huth puts("Warning: Unknown processor version!\n"); 148*ee30cf14SThomas Huth } 149*ee30cf14SThomas Huth } 150*ee30cf14SThomas Huth 151*ee30cf14SThomas Huth static void get_sprs_common(uint64_t *v) 152*ee30cf14SThomas Huth { 153*ee30cf14SThomas Huth v[9] = mfspr(9); /* CTR */ 154*ee30cf14SThomas Huth // v[273] = mfspr(273); /* SPRG1 */ /* Used by our exception handler */ 155*ee30cf14SThomas Huth v[274] = mfspr(274); /* SPRG2 */ 156*ee30cf14SThomas Huth v[275] = mfspr(275); /* SPRG3 */ 157*ee30cf14SThomas Huth } 158*ee30cf14SThomas Huth 159*ee30cf14SThomas Huth static void get_sprs_book3s_201(uint64_t *v) 160*ee30cf14SThomas Huth { 161*ee30cf14SThomas Huth v[18] = mfspr(18); /* DSISR */ 162*ee30cf14SThomas Huth v[19] = mfspr(19); /* DAR */ 163*ee30cf14SThomas Huth v[136] = mfspr(136); /* CTRL */ 164*ee30cf14SThomas Huth v[256] = mfspr(256); /* VRSAVE */ 165*ee30cf14SThomas Huth v[786] = mfspr(786); /* MMCRA */ 166*ee30cf14SThomas Huth v[795] = mfspr(795); /* MMCR0 */ 167*ee30cf14SThomas Huth v[798] = mfspr(798); /* MMCR1 */ 168*ee30cf14SThomas Huth } 169*ee30cf14SThomas Huth 170*ee30cf14SThomas Huth static void get_sprs_book3s_207(uint64_t *v) 171*ee30cf14SThomas Huth { 172*ee30cf14SThomas Huth v[3] = mfspr(3); /* DSCR */ 173*ee30cf14SThomas Huth v[13] = mfspr(13); /* AMR */ 174*ee30cf14SThomas Huth v[17] = mfspr(17); /* DSCR */ 175*ee30cf14SThomas Huth v[18] = mfspr(18); /* DSISR */ 176*ee30cf14SThomas Huth v[19] = mfspr(19); /* DAR */ 177*ee30cf14SThomas Huth v[29] = mfspr(29); /* AMR */ 178*ee30cf14SThomas Huth v[61] = mfspr(61); /* IAMR */ 179*ee30cf14SThomas Huth // v[136] = mfspr(136); /* CTRL */ /* TODO: Needs a fix in KVM */ 180*ee30cf14SThomas Huth v[153] = mfspr(153); /* FSCR */ 181*ee30cf14SThomas Huth v[157] = mfspr(157); /* UAMOR */ 182*ee30cf14SThomas Huth v[159] = mfspr(159); /* PSPB */ 183*ee30cf14SThomas Huth v[256] = mfspr(256); /* VRSAVE */ 184*ee30cf14SThomas Huth v[259] = mfspr(259); /* SPRG3 (read only) */ 185*ee30cf14SThomas Huth // v[272] = mfspr(272); /* SPRG0 */ /* Used by our exception handler */ 186*ee30cf14SThomas Huth v[769] = mfspr(769); /* MMCR2 */ 187*ee30cf14SThomas Huth v[770] = mfspr(770); /* MMCRA */ 188*ee30cf14SThomas Huth v[771] = mfspr(771); /* PMC1 */ 189*ee30cf14SThomas Huth v[772] = mfspr(772); /* PMC2 */ 190*ee30cf14SThomas Huth v[773] = mfspr(773); /* PMC3 */ 191*ee30cf14SThomas Huth v[774] = mfspr(774); /* PMC4 */ 192*ee30cf14SThomas Huth v[775] = mfspr(775); /* PMC5 */ 193*ee30cf14SThomas Huth v[776] = mfspr(776); /* PMC6 */ 194*ee30cf14SThomas Huth v[779] = mfspr(779); /* MMCR0 */ 195*ee30cf14SThomas Huth v[780] = mfspr(780); /* SIAR (read only) */ 196*ee30cf14SThomas Huth v[781] = mfspr(781); /* SDAR (read only) */ 197*ee30cf14SThomas Huth v[782] = mfspr(782); /* MMCR1 (read only) */ 198*ee30cf14SThomas Huth v[784] = mfspr(784); /* SIER */ 199*ee30cf14SThomas Huth v[785] = mfspr(785); /* MMCR2 */ 200*ee30cf14SThomas Huth v[786] = mfspr(786); /* MMCRA */ 201*ee30cf14SThomas Huth v[787] = mfspr(787); /* PMC1 */ 202*ee30cf14SThomas Huth v[788] = mfspr(788); /* PMC2 */ 203*ee30cf14SThomas Huth v[789] = mfspr(789); /* PMC3 */ 204*ee30cf14SThomas Huth v[790] = mfspr(790); /* PMC4 */ 205*ee30cf14SThomas Huth v[791] = mfspr(791); /* PMC5 */ 206*ee30cf14SThomas Huth v[792] = mfspr(792); /* PMC6 */ 207*ee30cf14SThomas Huth v[795] = mfspr(795); /* MMCR0 */ 208*ee30cf14SThomas Huth v[796] = mfspr(796); /* SIAR */ 209*ee30cf14SThomas Huth v[797] = mfspr(797); /* SDAR */ 210*ee30cf14SThomas Huth v[798] = mfspr(798); /* MMCR1 */ 211*ee30cf14SThomas Huth v[800] = mfspr(800); /* BESCRS */ 212*ee30cf14SThomas Huth v[801] = mfspr(801); /* BESCCRSU */ 213*ee30cf14SThomas Huth v[802] = mfspr(802); /* BESCRR */ 214*ee30cf14SThomas Huth v[803] = mfspr(803); /* BESCRRU */ 215*ee30cf14SThomas Huth v[804] = mfspr(804); /* EBBHR */ 216*ee30cf14SThomas Huth v[805] = mfspr(805); /* EBBRR */ 217*ee30cf14SThomas Huth v[806] = mfspr(806); /* BESCR */ 218*ee30cf14SThomas Huth v[815] = mfspr(815); /* TAR */ 219*ee30cf14SThomas Huth } 220*ee30cf14SThomas Huth 221*ee30cf14SThomas Huth static void get_sprs(uint64_t *v) 222*ee30cf14SThomas Huth { 223*ee30cf14SThomas Huth uint32_t pvr = mfspr(287); /* Processor Version Register */ 224*ee30cf14SThomas Huth 225*ee30cf14SThomas Huth get_sprs_common(v); 226*ee30cf14SThomas Huth 227*ee30cf14SThomas Huth switch (pvr >> 16) { 228*ee30cf14SThomas Huth case 0x39: /* PPC970 */ 229*ee30cf14SThomas Huth case 0x3C: /* PPC970FX */ 230*ee30cf14SThomas Huth case 0x44: /* PPC970MP */ 231*ee30cf14SThomas Huth get_sprs_book3s_201(v); 232*ee30cf14SThomas Huth break; 233*ee30cf14SThomas Huth case 0x4b: /* POWER8E */ 234*ee30cf14SThomas Huth case 0x4c: /* POWER8NVL */ 235*ee30cf14SThomas Huth case 0x4d: /* POWER8 */ 236*ee30cf14SThomas Huth get_sprs_book3s_207(v); 237*ee30cf14SThomas Huth break; 238*ee30cf14SThomas Huth } 239*ee30cf14SThomas Huth } 240*ee30cf14SThomas Huth 241*ee30cf14SThomas Huth int main(int argc, char **argv) 242*ee30cf14SThomas Huth { 243*ee30cf14SThomas Huth int i; 244*ee30cf14SThomas Huth bool pause = false; 245*ee30cf14SThomas Huth uint64_t pat = 0xcafefacec0debabeULL; 246*ee30cf14SThomas Huth const uint64_t patterns[] = { 247*ee30cf14SThomas Huth 0xcafefacec0debabeULL, ~0xcafefacec0debabeULL, 248*ee30cf14SThomas Huth 0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL, 249*ee30cf14SThomas Huth 0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL, 250*ee30cf14SThomas Huth -1ULL, 251*ee30cf14SThomas Huth }; 252*ee30cf14SThomas Huth 253*ee30cf14SThomas Huth for (i = 1; i < argc; i++) { 254*ee30cf14SThomas Huth if (!strcmp(argv[i], "-w")) { 255*ee30cf14SThomas Huth pause = true; 256*ee30cf14SThomas Huth } else if (!strcmp(argv[i], "-p")) { 257*ee30cf14SThomas Huth i += 1; 258*ee30cf14SThomas Huth if (i >= argc || *argv[i] < '0' 259*ee30cf14SThomas Huth || *argv[i] >= '0' + ARRAY_SIZE(patterns)) 260*ee30cf14SThomas Huth report_abort("Error: bad value for -p"); 261*ee30cf14SThomas Huth pat ^= patterns[*argv[i] - '0']; 262*ee30cf14SThomas Huth } else if (!strcmp(argv[i], "-t")) { 263*ee30cf14SThomas Huth /* Randomize with timebase register */ 264*ee30cf14SThomas Huth asm volatile("mftb %0" : "=r"(i)); 265*ee30cf14SThomas Huth pat ^= i; 266*ee30cf14SThomas Huth asm volatile("mftb %0" : "=r"(i)); 267*ee30cf14SThomas Huth pat ^= ~(uint64_t)i << 32; 268*ee30cf14SThomas Huth } else { 269*ee30cf14SThomas Huth report_abort("Warning: Unsupported argument: %s", 270*ee30cf14SThomas Huth argv[i]); 271*ee30cf14SThomas Huth } 272*ee30cf14SThomas Huth } 273*ee30cf14SThomas Huth 274*ee30cf14SThomas Huth printf("Settings SPRs to 0x%lx...\n", pat); 275*ee30cf14SThomas Huth set_sprs(pat); 276*ee30cf14SThomas Huth 277*ee30cf14SThomas Huth memset(before, 0, sizeof(before)); 278*ee30cf14SThomas Huth memset(after, 0, sizeof(after)); 279*ee30cf14SThomas Huth 280*ee30cf14SThomas Huth get_sprs(before); 281*ee30cf14SThomas Huth 282*ee30cf14SThomas Huth if (pause) { 283*ee30cf14SThomas Huth handle_exception(0x100, &nmi_handler, NULL); 284*ee30cf14SThomas Huth puts("Now migrate the VM, then press a key or send NMI...\n"); 285*ee30cf14SThomas Huth while (!nmi_occurred && h_get_term_char(0) == 0) 286*ee30cf14SThomas Huth cpu_relax(); 287*ee30cf14SThomas Huth } else { 288*ee30cf14SThomas Huth puts("Sleeping...\n"); 289*ee30cf14SThomas Huth handle_exception(0x900, &dec_except_handler, NULL); 290*ee30cf14SThomas Huth asm volatile ("mtdec %0" : : "r" (0x3FFFFFFF)); 291*ee30cf14SThomas Huth hcall(H_CEDE); 292*ee30cf14SThomas Huth } 293*ee30cf14SThomas Huth 294*ee30cf14SThomas Huth get_sprs(after); 295*ee30cf14SThomas Huth 296*ee30cf14SThomas Huth puts("Checking SPRs...\n"); 297*ee30cf14SThomas Huth for (i = 0; i < 1024; i++) { 298*ee30cf14SThomas Huth if (before[i] != 0 || after[i] != 0) 299*ee30cf14SThomas Huth report("SPR %d:\t0x%016lx <==> 0x%016lx", 300*ee30cf14SThomas Huth before[i] == after[i], i, before[i], after[i]); 301*ee30cf14SThomas Huth } 302*ee30cf14SThomas Huth 303*ee30cf14SThomas Huth return report_summary(); 304*ee30cf14SThomas Huth } 305