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