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