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