xref: /kvm-unit-tests/powerpc/sprs.c (revision 25a302cbb6c3f2cc95418291280ef8e3a378257c)
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 /* SPRs from PowerISA 3.00 Book III */
130 static void set_sprs_book3s_300(uint64_t val)
131 {
132 	set_sprs_book3s_207(val);
133 	mtspr(48, val);		/* PIDR */
134 	mtspr(144, val);	/* TIDR */
135 	mtspr(823, val);	/* PSSCR */
136 }
137 
138 static void set_sprs(uint64_t val)
139 {
140 	uint32_t pvr = mfspr(287);	/* Processor Version Register */
141 
142 	set_sprs_common(val);
143 
144 	switch (pvr >> 16) {
145 	case 0x39:			/* PPC970 */
146 	case 0x3C:			/* PPC970FX */
147 	case 0x44:			/* PPC970MP */
148 		set_sprs_book3s_201(val);
149 		break;
150 	case 0x4b:			/* POWER8E */
151 	case 0x4c:			/* POWER8NVL */
152 	case 0x4d:			/* POWER8 */
153 		set_sprs_book3s_207(val);
154 		break;
155 	case 0x4e:			/* POWER9 */
156 		set_sprs_book3s_300(val);
157 		break;
158 	default:
159 		puts("Warning: Unknown processor version!\n");
160 	}
161 }
162 
163 static void get_sprs_common(uint64_t *v)
164 {
165 	v[9] = mfspr(9);	/* CTR */
166 	// v[273] = mfspr(273);	/* SPRG1 */ /* Used by our exception handler */
167 	v[274] = mfspr(274);	/* SPRG2 */
168 	v[275] = mfspr(275);	/* SPRG3 */
169 }
170 
171 static void get_sprs_book3s_201(uint64_t *v)
172 {
173 	v[18] = mfspr(18);	/* DSISR */
174 	v[19] = mfspr(19);	/* DAR */
175 	v[136] = mfspr(136);	/* CTRL */
176 	v[256] = mfspr(256);	/* VRSAVE */
177 	v[786] = mfspr(786);	/* MMCRA */
178 	v[795] = mfspr(795);	/* MMCR0 */
179 	v[798] = mfspr(798);	/* MMCR1 */
180 }
181 
182 static void get_sprs_book3s_207(uint64_t *v)
183 {
184 	v[3] = mfspr(3);	/* DSCR */
185 	v[13] = mfspr(13);	/* AMR */
186 	v[17] = mfspr(17);	/* DSCR */
187 	v[18] = mfspr(18);	/* DSISR */
188 	v[19] = mfspr(19);	/* DAR */
189 	v[29] = mfspr(29);	/* AMR */
190 	v[61] = mfspr(61);	/* IAMR */
191 	// v[136] = mfspr(136);	/* CTRL */  /* TODO: Needs a fix in KVM */
192 	v[153] = mfspr(153);	/* FSCR */
193 	v[157] = mfspr(157);	/* UAMOR */
194 	v[159] = mfspr(159);	/* PSPB */
195 	v[256] = mfspr(256);	/* VRSAVE */
196 	v[259] = mfspr(259);	/* SPRG3 (read only) */
197 	// v[272] = mfspr(272);	/* SPRG0 */  /* Used by our exception handler */
198 	v[769] = mfspr(769);	/* MMCR2 */
199 	v[770] = mfspr(770);	/* MMCRA */
200 	v[771] = mfspr(771);	/* PMC1 */
201 	v[772] = mfspr(772);	/* PMC2 */
202 	v[773] = mfspr(773);	/* PMC3 */
203 	v[774] = mfspr(774);	/* PMC4 */
204 	v[775] = mfspr(775);	/* PMC5 */
205 	v[776] = mfspr(776);	/* PMC6 */
206 	v[779] = mfspr(779);	/* MMCR0 */
207 	v[780] = mfspr(780);	/* SIAR (read only) */
208 	v[781] = mfspr(781);	/* SDAR (read only) */
209 	v[782] = mfspr(782);	/* MMCR1 (read only) */
210 	v[784] = mfspr(784);	/* SIER */
211 	v[785] = mfspr(785);	/* MMCR2 */
212 	v[786] = mfspr(786);	/* MMCRA */
213 	v[787] = mfspr(787);	/* PMC1 */
214 	v[788] = mfspr(788);	/* PMC2 */
215 	v[789] = mfspr(789);	/* PMC3 */
216 	v[790] = mfspr(790);	/* PMC4 */
217 	v[791] = mfspr(791);	/* PMC5 */
218 	v[792] = mfspr(792);	/* PMC6 */
219 	v[795] = mfspr(795);	/* MMCR0 */
220 	v[796] = mfspr(796);	/* SIAR */
221 	v[797] = mfspr(797);	/* SDAR */
222 	v[798] = mfspr(798);	/* MMCR1 */
223 	v[800] = mfspr(800);	/* BESCRS */
224 	v[801] = mfspr(801);	/* BESCCRSU */
225 	v[802] = mfspr(802);	/* BESCRR */
226 	v[803] = mfspr(803);	/* BESCRRU */
227 	v[804] = mfspr(804);	/* EBBHR */
228 	v[805] = mfspr(805);	/* EBBRR */
229 	v[806] = mfspr(806);	/* BESCR */
230 	v[815] = mfspr(815);	/* TAR */
231 }
232 
233 static void get_sprs_book3s_300(uint64_t *v)
234 {
235 	get_sprs_book3s_207(v);
236 	v[48] = mfspr(48);	/* PIDR */
237 	v[144] = mfspr(144);	/* TIDR */
238 	v[823] = mfspr(823);	/* PSSCR */
239 }
240 
241 static void get_sprs(uint64_t *v)
242 {
243 	uint32_t pvr = mfspr(287);	/* Processor Version Register */
244 
245 	get_sprs_common(v);
246 
247 	switch (pvr >> 16) {
248 	case 0x39:			/* PPC970 */
249 	case 0x3C:			/* PPC970FX */
250 	case 0x44:			/* PPC970MP */
251 		get_sprs_book3s_201(v);
252 		break;
253 	case 0x4b:			/* POWER8E */
254 	case 0x4c:			/* POWER8NVL */
255 	case 0x4d:			/* POWER8 */
256 		get_sprs_book3s_207(v);
257 		break;
258 	case 0x4e:			/* POWER9 */
259 		get_sprs_book3s_300(v);
260 		break;
261 	}
262 }
263 
264 int main(int argc, char **argv)
265 {
266 	int i;
267 	bool pause = false;
268 	uint64_t pat = 0xcafefacec0debabeULL;
269 	const uint64_t patterns[] = {
270 		0xcafefacec0debabeULL, ~0xcafefacec0debabeULL,
271 		0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL,
272 		0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL,
273 		-1ULL,
274 	};
275 
276 	for (i = 1; i < argc; i++) {
277 		if (!strcmp(argv[i], "-w")) {
278 			pause = true;
279 		} else if (!strcmp(argv[i], "-p")) {
280 			i += 1;
281 			if (i >= argc || *argv[i] < '0'
282 			    || *argv[i] >= '0' + ARRAY_SIZE(patterns))
283 				report_abort("Error: bad value for -p");
284 			pat ^= patterns[*argv[i] - '0'];
285 		} else if (!strcmp(argv[i], "-t")) {
286 			/* Randomize with timebase register */
287 			asm volatile("mftb %0" : "=r"(i));
288 			pat ^= i;
289 			asm volatile("mftb %0" : "=r"(i));
290 			pat ^= ~(uint64_t)i << 32;
291 		} else {
292 			report_abort("Warning: Unsupported argument: %s",
293 			             argv[i]);
294 		}
295 	}
296 
297 	printf("Settings SPRs to %#lx...\n", pat);
298 	set_sprs(pat);
299 
300 	memset(before, 0, sizeof(before));
301 	memset(after, 0, sizeof(after));
302 
303 	get_sprs(before);
304 
305 	if (pause) {
306 		handle_exception(0x100, &nmi_handler, NULL);
307 		puts("Now migrate the VM, then press a key or send NMI...\n");
308 		while (!nmi_occurred && h_get_term_char(0) == 0)
309 			cpu_relax();
310 	} else {
311 		puts("Sleeping...\n");
312 		handle_exception(0x900, &dec_except_handler, NULL);
313 		asm volatile ("mtdec %0" : : "r" (0x3FFFFFFF));
314 		hcall(H_CEDE);
315 	}
316 
317 	get_sprs(after);
318 
319 	puts("Checking SPRs...\n");
320 	for (i = 0; i < 1024; i++) {
321 		if (before[i] != 0 || after[i] != 0)
322 			report("SPR %d:\t%#018lx <==> %#018lx",
323 				before[i] == after[i], i, before[i], after[i]);
324 	}
325 
326 	return report_summary();
327 }
328