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 11*ffd9da55SAndrew Jones * all bits might be retained in the SPRs), then wait for migration to complete 12*ffd9da55SAndrew Jones * (if the '-w' option has been specified) so that the user has a chance to 13*ffd9da55SAndrew Jones * migrate the VM. Alternatively, the test can also simply sleep a little bit 14*ffd9da55SAndrew Jones * with the H_CEDE hypercall, in the hope that we'll get scheduled to another 15*ffd9da55SAndrew Jones * host CPU and thus register contents might have changed, too (in case of 16*ffd9da55SAndrew Jones * bugs). Finally, we read back the values from the SPRs and compare them with 17*ffd9da55SAndrew 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> 24ee30cf14SThomas Huth #include <alloc.h> 25ee30cf14SThomas Huth #include <asm/handlers.h> 26ee30cf14SThomas Huth #include <asm/hcall.h> 27ee30cf14SThomas Huth #include <asm/processor.h> 28ee30cf14SThomas Huth #include <asm/barrier.h> 29ee30cf14SThomas Huth 30ee30cf14SThomas Huth #define mfspr(nr) ({ \ 31ee30cf14SThomas Huth uint64_t ret; \ 32ee30cf14SThomas Huth asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \ 33ee30cf14SThomas Huth ret; \ 34ee30cf14SThomas Huth }) 35ee30cf14SThomas Huth 36ee30cf14SThomas Huth #define mtspr(nr, val) \ 37ee30cf14SThomas Huth asm volatile("mtspr %0,%1" : : "i"(nr), "r"(val)) 38ee30cf14SThomas Huth 39ee30cf14SThomas Huth uint64_t before[1024], after[1024]; 40ee30cf14SThomas Huth 41ee30cf14SThomas Huth static int h_get_term_char(uint64_t termno) 42ee30cf14SThomas Huth { 43ee30cf14SThomas Huth register uint64_t r3 asm("r3") = 0x54; /* H_GET_TERM_CHAR */ 44ee30cf14SThomas Huth register uint64_t r4 asm("r4") = termno; 45ee30cf14SThomas Huth register uint64_t r5 asm("r5"); 46ee30cf14SThomas Huth 47ee30cf14SThomas Huth asm volatile (" sc 1 " : "+r"(r3), "+r"(r4), "=r"(r5) 48ee30cf14SThomas Huth : "r"(r3), "r"(r4)); 49ee30cf14SThomas Huth 50ee30cf14SThomas Huth return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : 0; 51ee30cf14SThomas Huth } 52ee30cf14SThomas Huth 53ee30cf14SThomas Huth /* Common SPRs for all PowerPC CPUs */ 54ee30cf14SThomas Huth static void set_sprs_common(uint64_t val) 55ee30cf14SThomas Huth { 56ee30cf14SThomas Huth mtspr(9, val); /* CTR */ 57ee30cf14SThomas Huth // mtspr(273, val); /* SPRG1 */ /* Used by our exception handler */ 58ee30cf14SThomas Huth mtspr(274, val); /* SPRG2 */ 59ee30cf14SThomas Huth mtspr(275, val); /* SPRG3 */ 60ee30cf14SThomas Huth } 61ee30cf14SThomas Huth 62ee30cf14SThomas Huth /* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */ 63ee30cf14SThomas Huth static void set_sprs_book3s_201(uint64_t val) 64ee30cf14SThomas Huth { 65ee30cf14SThomas Huth mtspr(18, val); /* DSISR */ 66ee30cf14SThomas Huth mtspr(19, val); /* DAR */ 67ee30cf14SThomas Huth mtspr(152, val); /* CTRL */ 68ee30cf14SThomas Huth mtspr(256, val); /* VRSAVE */ 69ee30cf14SThomas Huth mtspr(786, val); /* MMCRA */ 70ee30cf14SThomas Huth mtspr(795, val); /* MMCR0 */ 71ee30cf14SThomas Huth mtspr(798, val); /* MMCR1 */ 72ee30cf14SThomas Huth } 73ee30cf14SThomas Huth 74ee30cf14SThomas Huth /* SPRs from PowerISA 2.07 Book III-S */ 75ee30cf14SThomas Huth static void set_sprs_book3s_207(uint64_t val) 76ee30cf14SThomas Huth { 77ee30cf14SThomas Huth mtspr(3, val); /* DSCR */ 78ee30cf14SThomas Huth mtspr(13, val); /* AMR */ 79ee30cf14SThomas Huth mtspr(17, val); /* DSCR */ 80ee30cf14SThomas Huth mtspr(18, val); /* DSISR */ 81ee30cf14SThomas Huth mtspr(19, val); /* DAR */ 82ee30cf14SThomas Huth mtspr(29, val); /* AMR */ 83ee30cf14SThomas Huth mtspr(61, val); /* IAMR */ 84ee30cf14SThomas Huth // mtspr(152, val); /* CTRL */ /* TODO: Needs a fix in KVM */ 85ee30cf14SThomas Huth mtspr(153, val); /* FSCR */ 86ee30cf14SThomas Huth mtspr(157, val); /* UAMOR */ 87ee30cf14SThomas Huth mtspr(159, val); /* PSPB */ 88ee30cf14SThomas Huth mtspr(256, val); /* VRSAVE */ 89ee30cf14SThomas Huth // mtspr(272, val); /* SPRG0 */ /* Used by our exception handler */ 90ee30cf14SThomas Huth mtspr(769, val); /* MMCR2 */ 91ee30cf14SThomas Huth mtspr(770, val); /* MMCRA */ 92ee30cf14SThomas Huth mtspr(771, val); /* PMC1 */ 93ee30cf14SThomas Huth mtspr(772, val); /* PMC2 */ 94ee30cf14SThomas Huth mtspr(773, val); /* PMC3 */ 95ee30cf14SThomas Huth mtspr(774, val); /* PMC4 */ 96ee30cf14SThomas Huth mtspr(775, val); /* PMC5 */ 97ee30cf14SThomas Huth mtspr(776, val); /* PMC6 */ 98ee30cf14SThomas Huth mtspr(779, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ 99ee30cf14SThomas Huth mtspr(784, val); /* SIER */ 100ee30cf14SThomas Huth mtspr(785, val); /* MMCR2 */ 101ee30cf14SThomas Huth mtspr(786, val); /* MMCRA */ 102ee30cf14SThomas Huth mtspr(787, val); /* PMC1 */ 103ee30cf14SThomas Huth mtspr(788, val); /* PMC2 */ 104ee30cf14SThomas Huth mtspr(789, val); /* PMC3 */ 105ee30cf14SThomas Huth mtspr(790, val); /* PMC4 */ 106ee30cf14SThomas Huth mtspr(791, val); /* PMC5 */ 107ee30cf14SThomas Huth mtspr(792, val); /* PMC6 */ 108ee30cf14SThomas Huth mtspr(795, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ 109ee30cf14SThomas Huth mtspr(796, val); /* SIAR */ 110ee30cf14SThomas Huth mtspr(797, val); /* SDAR */ 111ee30cf14SThomas Huth mtspr(798, val); /* MMCR1 */ 112ee30cf14SThomas Huth mtspr(800, val); /* BESCRS */ 113ee30cf14SThomas Huth mtspr(801, val); /* BESCCRSU */ 114ee30cf14SThomas Huth mtspr(802, val); /* BESCRR */ 115ee30cf14SThomas Huth mtspr(803, val); /* BESCRRU */ 116ee30cf14SThomas Huth mtspr(804, val); /* EBBHR */ 117ee30cf14SThomas Huth mtspr(805, val); /* EBBRR */ 118ee30cf14SThomas Huth mtspr(806, val); /* BESCR */ 119ee30cf14SThomas Huth mtspr(815, val); /* TAR */ 120ee30cf14SThomas Huth } 121ee30cf14SThomas Huth 12225a302cbSThomas Huth /* SPRs from PowerISA 3.00 Book III */ 12325a302cbSThomas Huth static void set_sprs_book3s_300(uint64_t val) 12425a302cbSThomas Huth { 12525a302cbSThomas Huth set_sprs_book3s_207(val); 12625a302cbSThomas Huth mtspr(48, val); /* PIDR */ 12725a302cbSThomas Huth mtspr(144, val); /* TIDR */ 12825a302cbSThomas Huth mtspr(823, val); /* PSSCR */ 12925a302cbSThomas Huth } 13025a302cbSThomas Huth 131ee30cf14SThomas Huth static void set_sprs(uint64_t val) 132ee30cf14SThomas Huth { 133ee30cf14SThomas Huth uint32_t pvr = mfspr(287); /* Processor Version Register */ 134ee30cf14SThomas Huth 135ee30cf14SThomas Huth set_sprs_common(val); 136ee30cf14SThomas Huth 137ee30cf14SThomas Huth switch (pvr >> 16) { 138ee30cf14SThomas Huth case 0x39: /* PPC970 */ 139ee30cf14SThomas Huth case 0x3C: /* PPC970FX */ 140ee30cf14SThomas Huth case 0x44: /* PPC970MP */ 141ee30cf14SThomas Huth set_sprs_book3s_201(val); 142ee30cf14SThomas Huth break; 143ee30cf14SThomas Huth case 0x4b: /* POWER8E */ 144ee30cf14SThomas Huth case 0x4c: /* POWER8NVL */ 145ee30cf14SThomas Huth case 0x4d: /* POWER8 */ 146ee30cf14SThomas Huth set_sprs_book3s_207(val); 147ee30cf14SThomas Huth break; 14825a302cbSThomas Huth case 0x4e: /* POWER9 */ 14925a302cbSThomas Huth set_sprs_book3s_300(val); 15025a302cbSThomas Huth break; 151ee30cf14SThomas Huth default: 152ee30cf14SThomas Huth puts("Warning: Unknown processor version!\n"); 153ee30cf14SThomas Huth } 154ee30cf14SThomas Huth } 155ee30cf14SThomas Huth 156ee30cf14SThomas Huth static void get_sprs_common(uint64_t *v) 157ee30cf14SThomas Huth { 158ee30cf14SThomas Huth v[9] = mfspr(9); /* CTR */ 159ee30cf14SThomas Huth // v[273] = mfspr(273); /* SPRG1 */ /* Used by our exception handler */ 160ee30cf14SThomas Huth v[274] = mfspr(274); /* SPRG2 */ 161ee30cf14SThomas Huth v[275] = mfspr(275); /* SPRG3 */ 162ee30cf14SThomas Huth } 163ee30cf14SThomas Huth 164ee30cf14SThomas Huth static void get_sprs_book3s_201(uint64_t *v) 165ee30cf14SThomas Huth { 166ee30cf14SThomas Huth v[18] = mfspr(18); /* DSISR */ 167ee30cf14SThomas Huth v[19] = mfspr(19); /* DAR */ 168ee30cf14SThomas Huth v[136] = mfspr(136); /* CTRL */ 169ee30cf14SThomas Huth v[256] = mfspr(256); /* VRSAVE */ 170ee30cf14SThomas Huth v[786] = mfspr(786); /* MMCRA */ 171ee30cf14SThomas Huth v[795] = mfspr(795); /* MMCR0 */ 172ee30cf14SThomas Huth v[798] = mfspr(798); /* MMCR1 */ 173ee30cf14SThomas Huth } 174ee30cf14SThomas Huth 175ee30cf14SThomas Huth static void get_sprs_book3s_207(uint64_t *v) 176ee30cf14SThomas Huth { 177ee30cf14SThomas Huth v[3] = mfspr(3); /* DSCR */ 178ee30cf14SThomas Huth v[13] = mfspr(13); /* AMR */ 179ee30cf14SThomas Huth v[17] = mfspr(17); /* DSCR */ 180ee30cf14SThomas Huth v[18] = mfspr(18); /* DSISR */ 181ee30cf14SThomas Huth v[19] = mfspr(19); /* DAR */ 182ee30cf14SThomas Huth v[29] = mfspr(29); /* AMR */ 183ee30cf14SThomas Huth v[61] = mfspr(61); /* IAMR */ 184ee30cf14SThomas Huth // v[136] = mfspr(136); /* CTRL */ /* TODO: Needs a fix in KVM */ 185ee30cf14SThomas Huth v[153] = mfspr(153); /* FSCR */ 186ee30cf14SThomas Huth v[157] = mfspr(157); /* UAMOR */ 187ee30cf14SThomas Huth v[159] = mfspr(159); /* PSPB */ 188ee30cf14SThomas Huth v[256] = mfspr(256); /* VRSAVE */ 189ee30cf14SThomas Huth v[259] = mfspr(259); /* SPRG3 (read only) */ 190ee30cf14SThomas Huth // v[272] = mfspr(272); /* SPRG0 */ /* Used by our exception handler */ 191ee30cf14SThomas Huth v[769] = mfspr(769); /* MMCR2 */ 192ee30cf14SThomas Huth v[770] = mfspr(770); /* MMCRA */ 193ee30cf14SThomas Huth v[771] = mfspr(771); /* PMC1 */ 194ee30cf14SThomas Huth v[772] = mfspr(772); /* PMC2 */ 195ee30cf14SThomas Huth v[773] = mfspr(773); /* PMC3 */ 196ee30cf14SThomas Huth v[774] = mfspr(774); /* PMC4 */ 197ee30cf14SThomas Huth v[775] = mfspr(775); /* PMC5 */ 198ee30cf14SThomas Huth v[776] = mfspr(776); /* PMC6 */ 199ee30cf14SThomas Huth v[779] = mfspr(779); /* MMCR0 */ 200ee30cf14SThomas Huth v[780] = mfspr(780); /* SIAR (read only) */ 201ee30cf14SThomas Huth v[781] = mfspr(781); /* SDAR (read only) */ 202ee30cf14SThomas Huth v[782] = mfspr(782); /* MMCR1 (read only) */ 203ee30cf14SThomas Huth v[784] = mfspr(784); /* SIER */ 204ee30cf14SThomas Huth v[785] = mfspr(785); /* MMCR2 */ 205ee30cf14SThomas Huth v[786] = mfspr(786); /* MMCRA */ 206ee30cf14SThomas Huth v[787] = mfspr(787); /* PMC1 */ 207ee30cf14SThomas Huth v[788] = mfspr(788); /* PMC2 */ 208ee30cf14SThomas Huth v[789] = mfspr(789); /* PMC3 */ 209ee30cf14SThomas Huth v[790] = mfspr(790); /* PMC4 */ 210ee30cf14SThomas Huth v[791] = mfspr(791); /* PMC5 */ 211ee30cf14SThomas Huth v[792] = mfspr(792); /* PMC6 */ 212ee30cf14SThomas Huth v[795] = mfspr(795); /* MMCR0 */ 213ee30cf14SThomas Huth v[796] = mfspr(796); /* SIAR */ 214ee30cf14SThomas Huth v[797] = mfspr(797); /* SDAR */ 215ee30cf14SThomas Huth v[798] = mfspr(798); /* MMCR1 */ 216ee30cf14SThomas Huth v[800] = mfspr(800); /* BESCRS */ 217ee30cf14SThomas Huth v[801] = mfspr(801); /* BESCCRSU */ 218ee30cf14SThomas Huth v[802] = mfspr(802); /* BESCRR */ 219ee30cf14SThomas Huth v[803] = mfspr(803); /* BESCRRU */ 220ee30cf14SThomas Huth v[804] = mfspr(804); /* EBBHR */ 221ee30cf14SThomas Huth v[805] = mfspr(805); /* EBBRR */ 222ee30cf14SThomas Huth v[806] = mfspr(806); /* BESCR */ 223ee30cf14SThomas Huth v[815] = mfspr(815); /* TAR */ 224ee30cf14SThomas Huth } 225ee30cf14SThomas Huth 22625a302cbSThomas Huth static void get_sprs_book3s_300(uint64_t *v) 22725a302cbSThomas Huth { 22825a302cbSThomas Huth get_sprs_book3s_207(v); 22925a302cbSThomas Huth v[48] = mfspr(48); /* PIDR */ 23025a302cbSThomas Huth v[144] = mfspr(144); /* TIDR */ 23125a302cbSThomas Huth v[823] = mfspr(823); /* PSSCR */ 23225a302cbSThomas Huth } 23325a302cbSThomas Huth 234ee30cf14SThomas Huth static void get_sprs(uint64_t *v) 235ee30cf14SThomas Huth { 236ee30cf14SThomas Huth uint32_t pvr = mfspr(287); /* Processor Version Register */ 237ee30cf14SThomas Huth 238ee30cf14SThomas Huth get_sprs_common(v); 239ee30cf14SThomas Huth 240ee30cf14SThomas Huth switch (pvr >> 16) { 241ee30cf14SThomas Huth case 0x39: /* PPC970 */ 242ee30cf14SThomas Huth case 0x3C: /* PPC970FX */ 243ee30cf14SThomas Huth case 0x44: /* PPC970MP */ 244ee30cf14SThomas Huth get_sprs_book3s_201(v); 245ee30cf14SThomas Huth break; 246ee30cf14SThomas Huth case 0x4b: /* POWER8E */ 247ee30cf14SThomas Huth case 0x4c: /* POWER8NVL */ 248ee30cf14SThomas Huth case 0x4d: /* POWER8 */ 249ee30cf14SThomas Huth get_sprs_book3s_207(v); 250ee30cf14SThomas Huth break; 25125a302cbSThomas Huth case 0x4e: /* POWER9 */ 25225a302cbSThomas Huth get_sprs_book3s_300(v); 25325a302cbSThomas Huth break; 254ee30cf14SThomas Huth } 255ee30cf14SThomas Huth } 256ee30cf14SThomas Huth 257ee30cf14SThomas Huth int main(int argc, char **argv) 258ee30cf14SThomas Huth { 259ee30cf14SThomas Huth int i; 260ee30cf14SThomas Huth bool pause = false; 261ee30cf14SThomas Huth uint64_t pat = 0xcafefacec0debabeULL; 262ee30cf14SThomas Huth const uint64_t patterns[] = { 263ee30cf14SThomas Huth 0xcafefacec0debabeULL, ~0xcafefacec0debabeULL, 264ee30cf14SThomas Huth 0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL, 265ee30cf14SThomas Huth 0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL, 266ee30cf14SThomas Huth -1ULL, 267ee30cf14SThomas Huth }; 268ee30cf14SThomas Huth 269ee30cf14SThomas Huth for (i = 1; i < argc; i++) { 270ee30cf14SThomas Huth if (!strcmp(argv[i], "-w")) { 271ee30cf14SThomas Huth pause = true; 272ee30cf14SThomas Huth } else if (!strcmp(argv[i], "-p")) { 273ee30cf14SThomas Huth i += 1; 274ee30cf14SThomas Huth if (i >= argc || *argv[i] < '0' 275ee30cf14SThomas Huth || *argv[i] >= '0' + ARRAY_SIZE(patterns)) 276ee30cf14SThomas Huth report_abort("Error: bad value for -p"); 277ee30cf14SThomas Huth pat ^= patterns[*argv[i] - '0']; 278ee30cf14SThomas Huth } else if (!strcmp(argv[i], "-t")) { 279ee30cf14SThomas Huth /* Randomize with timebase register */ 280ee30cf14SThomas Huth asm volatile("mftb %0" : "=r"(i)); 281ee30cf14SThomas Huth pat ^= i; 282ee30cf14SThomas Huth asm volatile("mftb %0" : "=r"(i)); 283ee30cf14SThomas Huth pat ^= ~(uint64_t)i << 32; 284ee30cf14SThomas Huth } else { 285ee30cf14SThomas Huth report_abort("Warning: Unsupported argument: %s", 286ee30cf14SThomas Huth argv[i]); 287ee30cf14SThomas Huth } 288ee30cf14SThomas Huth } 289ee30cf14SThomas Huth 290fd6aada0SRadim Krčmář printf("Settings SPRs to %#lx...\n", pat); 291ee30cf14SThomas Huth set_sprs(pat); 292ee30cf14SThomas Huth 293ee30cf14SThomas Huth memset(before, 0, sizeof(before)); 294ee30cf14SThomas Huth memset(after, 0, sizeof(after)); 295ee30cf14SThomas Huth 296ee30cf14SThomas Huth get_sprs(before); 297ee30cf14SThomas Huth 298ee30cf14SThomas Huth if (pause) { 299*ffd9da55SAndrew Jones puts("Now migrate the VM, then press a key to continue...\n"); 300*ffd9da55SAndrew Jones while (h_get_term_char(0) == 0) 301ee30cf14SThomas Huth cpu_relax(); 302ee30cf14SThomas Huth } else { 303ee30cf14SThomas Huth puts("Sleeping...\n"); 304ee30cf14SThomas Huth handle_exception(0x900, &dec_except_handler, NULL); 305ee30cf14SThomas Huth asm volatile ("mtdec %0" : : "r" (0x3FFFFFFF)); 306ee30cf14SThomas Huth hcall(H_CEDE); 307ee30cf14SThomas Huth } 308ee30cf14SThomas Huth 309ee30cf14SThomas Huth get_sprs(after); 310ee30cf14SThomas Huth 311ee30cf14SThomas Huth puts("Checking SPRs...\n"); 312ee30cf14SThomas Huth for (i = 0; i < 1024; i++) { 313ee30cf14SThomas Huth if (before[i] != 0 || after[i] != 0) 314fd6aada0SRadim Krčmář report("SPR %d:\t%#018lx <==> %#018lx", 315ee30cf14SThomas Huth before[i] == after[i], i, before[i], after[i]); 316ee30cf14SThomas Huth } 317ee30cf14SThomas Huth 318ee30cf14SThomas Huth return report_summary(); 319ee30cf14SThomas Huth } 320