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