xref: /kvm-unit-tests/powerpc/sprs.c (revision 9c5e19134a2eb35a2f2d7684a66875eca8f3a373)
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
11ffd9da55SAndrew Jones  * all bits might be retained in the SPRs), then wait for migration to complete
12ffd9da55SAndrew Jones  * (if the '-w' option has been specified) so that the user has a chance to
13ffd9da55SAndrew Jones  * migrate the VM. Alternatively, the test can also simply sleep a little bit
14ffd9da55SAndrew Jones  * with the H_CEDE hypercall, in the hope that we'll get scheduled to another
15ffd9da55SAndrew Jones  * host CPU and thus register contents might have changed, too (in case of
16ffd9da55SAndrew Jones  * bugs). Finally, we read back the values from the SPRs and compare them with
17ffd9da55SAndrew 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>
2477a59d17SNico Boehr #include <migrate.h>
25ee30cf14SThomas Huth #include <alloc.h>
26*9c5e1913SNicholas Piggin #include <asm/ppc_asm.h>
27ee30cf14SThomas Huth #include <asm/handlers.h>
28ee30cf14SThomas Huth #include <asm/hcall.h>
29ee30cf14SThomas Huth #include <asm/processor.h>
308b10d4faSNicholas Piggin #include <asm/time.h>
31ee30cf14SThomas Huth #include <asm/barrier.h>
32ee30cf14SThomas Huth 
33ee30cf14SThomas Huth uint64_t before[1024], after[1024];
34ee30cf14SThomas Huth 
35ee30cf14SThomas Huth /* Common SPRs for all PowerPC CPUs */
36ee30cf14SThomas Huth static void set_sprs_common(uint64_t val)
37ee30cf14SThomas Huth {
38ee30cf14SThomas Huth 	mtspr(9, val);		/* CTR */
39ee30cf14SThomas Huth 	// mtspr(273, val);	/* SPRG1 */  /* Used by our exception handler */
40ee30cf14SThomas Huth 	mtspr(274, val);	/* SPRG2 */
41ee30cf14SThomas Huth 	mtspr(275, val);	/* SPRG3 */
42ee30cf14SThomas Huth }
43ee30cf14SThomas Huth 
44ee30cf14SThomas Huth /* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */
45ee30cf14SThomas Huth static void set_sprs_book3s_201(uint64_t val)
46ee30cf14SThomas Huth {
47ee30cf14SThomas Huth 	mtspr(18, val);		/* DSISR */
48ee30cf14SThomas Huth 	mtspr(19, val);		/* DAR */
49ee30cf14SThomas Huth 	mtspr(152, val);	/* CTRL */
50ee30cf14SThomas Huth 	mtspr(256, val);	/* VRSAVE */
51ee30cf14SThomas Huth 	mtspr(786, val);	/* MMCRA */
52ee30cf14SThomas Huth 	mtspr(795, val);	/* MMCR0 */
53ee30cf14SThomas Huth 	mtspr(798, val);	/* MMCR1 */
54ee30cf14SThomas Huth }
55ee30cf14SThomas Huth 
56ee30cf14SThomas Huth /* SPRs from PowerISA 2.07 Book III-S */
57ee30cf14SThomas Huth static void set_sprs_book3s_207(uint64_t val)
58ee30cf14SThomas Huth {
59ee30cf14SThomas Huth 	mtspr(3, val);		/* DSCR */
60ee30cf14SThomas Huth 	mtspr(13, val);		/* AMR */
61ee30cf14SThomas Huth 	mtspr(17, val);		/* DSCR */
62ee30cf14SThomas Huth 	mtspr(18, val);		/* DSISR */
63ee30cf14SThomas Huth 	mtspr(19, val);		/* DAR */
64ee30cf14SThomas Huth 	mtspr(29, val);		/* AMR */
65ee30cf14SThomas Huth 	mtspr(61, val);		/* IAMR */
66ee30cf14SThomas Huth 	// mtspr(152, val);	/* CTRL */  /* TODO: Needs a fix in KVM */
67ee30cf14SThomas Huth 	mtspr(153, val);	/* FSCR */
68ee30cf14SThomas Huth 	mtspr(157, val);	/* UAMOR */
69ee30cf14SThomas Huth 	mtspr(159, val);	/* PSPB */
70ee30cf14SThomas Huth 	mtspr(256, val);	/* VRSAVE */
71ee30cf14SThomas Huth 	// mtspr(272, val);	/* SPRG0 */ /* Used by our exception handler */
72ee30cf14SThomas Huth 	mtspr(769, val);	/* MMCR2 */
73ee30cf14SThomas Huth 	mtspr(770, val);	/* MMCRA */
74ee30cf14SThomas Huth 	mtspr(771, val);	/* PMC1 */
75ee30cf14SThomas Huth 	mtspr(772, val);	/* PMC2 */
76ee30cf14SThomas Huth 	mtspr(773, val);	/* PMC3 */
77ee30cf14SThomas Huth 	mtspr(774, val);	/* PMC4 */
78ee30cf14SThomas Huth 	mtspr(775, val);	/* PMC5 */
79ee30cf14SThomas Huth 	mtspr(776, val);	/* PMC6 */
80ee30cf14SThomas Huth 	mtspr(779, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070);	/* MMCR0 */
81ee30cf14SThomas Huth 	mtspr(784, val);	/* SIER */
82ee30cf14SThomas Huth 	mtspr(785, val);	/* MMCR2 */
83ee30cf14SThomas Huth 	mtspr(786, val);	/* MMCRA */
84ee30cf14SThomas Huth 	mtspr(787, val);	/* PMC1 */
85ee30cf14SThomas Huth 	mtspr(788, val);	/* PMC2 */
86ee30cf14SThomas Huth 	mtspr(789, val);	/* PMC3 */
87ee30cf14SThomas Huth 	mtspr(790, val);	/* PMC4 */
88ee30cf14SThomas Huth 	mtspr(791, val);	/* PMC5 */
89ee30cf14SThomas Huth 	mtspr(792, val);	/* PMC6 */
90ee30cf14SThomas Huth 	mtspr(795, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070);	/* MMCR0 */
91ee30cf14SThomas Huth 	mtspr(796, val);	/* SIAR */
92ee30cf14SThomas Huth 	mtspr(797, val);	/* SDAR */
93ee30cf14SThomas Huth 	mtspr(798, val);	/* MMCR1 */
94ee30cf14SThomas Huth 	mtspr(800, val);	/* BESCRS */
95ee30cf14SThomas Huth 	mtspr(801, val);	/* BESCCRSU */
96ee30cf14SThomas Huth 	mtspr(802, val);	/* BESCRR */
97ee30cf14SThomas Huth 	mtspr(803, val);	/* BESCRRU */
98ee30cf14SThomas Huth 	mtspr(804, val);	/* EBBHR */
99ee30cf14SThomas Huth 	mtspr(805, val);	/* EBBRR */
100ee30cf14SThomas Huth 	mtspr(806, val);	/* BESCR */
101ee30cf14SThomas Huth 	mtspr(815, val);	/* TAR */
102ee30cf14SThomas Huth }
103ee30cf14SThomas Huth 
10425a302cbSThomas Huth /* SPRs from PowerISA 3.00 Book III */
10525a302cbSThomas Huth static void set_sprs_book3s_300(uint64_t val)
10625a302cbSThomas Huth {
10725a302cbSThomas Huth 	set_sprs_book3s_207(val);
10825a302cbSThomas Huth 	mtspr(48, val);		/* PIDR */
10925a302cbSThomas Huth 	mtspr(144, val);	/* TIDR */
11025a302cbSThomas Huth 	mtspr(823, val);	/* PSSCR */
11125a302cbSThomas Huth }
11225a302cbSThomas Huth 
113faaddcb0SNicholas Piggin /* SPRs from Power ISA Version 3.1B */
114faaddcb0SNicholas Piggin static void set_sprs_book3s_31(uint64_t val)
115faaddcb0SNicholas Piggin {
116faaddcb0SNicholas Piggin 	set_sprs_book3s_207(val);
117faaddcb0SNicholas Piggin 	mtspr(48, val);		/* PIDR */
118faaddcb0SNicholas Piggin 	/* 3.1 removes TIDR */
119faaddcb0SNicholas Piggin 	mtspr(823, val);	/* PSSCR */
120faaddcb0SNicholas Piggin }
121faaddcb0SNicholas Piggin 
122ee30cf14SThomas Huth static void set_sprs(uint64_t val)
123ee30cf14SThomas Huth {
124ee30cf14SThomas Huth 	set_sprs_common(val);
125ee30cf14SThomas Huth 
126*9c5e1913SNicholas Piggin 	switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
127*9c5e1913SNicholas Piggin 	case PVR_VER_970:
128*9c5e1913SNicholas Piggin 	case PVR_VER_970FX:
129*9c5e1913SNicholas Piggin 	case PVR_VER_970MP:
130ee30cf14SThomas Huth 		set_sprs_book3s_201(val);
131ee30cf14SThomas Huth 		break;
132*9c5e1913SNicholas Piggin 	case PVR_VER_POWER8E:
133*9c5e1913SNicholas Piggin 	case PVR_VER_POWER8NVL:
134*9c5e1913SNicholas Piggin 	case PVR_VER_POWER8:
135ee30cf14SThomas Huth 		set_sprs_book3s_207(val);
136ee30cf14SThomas Huth 		break;
137*9c5e1913SNicholas Piggin 	case PVR_VER_POWER9:
13825a302cbSThomas Huth 		set_sprs_book3s_300(val);
13925a302cbSThomas Huth 		break;
140*9c5e1913SNicholas Piggin 	case PVR_VER_POWER10:
141faaddcb0SNicholas Piggin 		set_sprs_book3s_31(val);
142faaddcb0SNicholas Piggin 		break;
143ee30cf14SThomas Huth 	default:
144ee30cf14SThomas Huth 		puts("Warning: Unknown processor version!\n");
145ee30cf14SThomas Huth 	}
146ee30cf14SThomas Huth }
147ee30cf14SThomas Huth 
148ee30cf14SThomas Huth static void get_sprs_common(uint64_t *v)
149ee30cf14SThomas Huth {
150ee30cf14SThomas Huth 	v[9] = mfspr(9);	/* CTR */
151ee30cf14SThomas Huth 	// v[273] = mfspr(273);	/* SPRG1 */ /* Used by our exception handler */
152ee30cf14SThomas Huth 	v[274] = mfspr(274);	/* SPRG2 */
153ee30cf14SThomas Huth 	v[275] = mfspr(275);	/* SPRG3 */
154ee30cf14SThomas Huth }
155ee30cf14SThomas Huth 
156ee30cf14SThomas Huth static void get_sprs_book3s_201(uint64_t *v)
157ee30cf14SThomas Huth {
158ee30cf14SThomas Huth 	v[18] = mfspr(18);	/* DSISR */
159ee30cf14SThomas Huth 	v[19] = mfspr(19);	/* DAR */
160ee30cf14SThomas Huth 	v[136] = mfspr(136);	/* CTRL */
161ee30cf14SThomas Huth 	v[256] = mfspr(256);	/* VRSAVE */
162ee30cf14SThomas Huth 	v[786] = mfspr(786);	/* MMCRA */
163ee30cf14SThomas Huth 	v[795] = mfspr(795);	/* MMCR0 */
164ee30cf14SThomas Huth 	v[798] = mfspr(798);	/* MMCR1 */
165ee30cf14SThomas Huth }
166ee30cf14SThomas Huth 
167ee30cf14SThomas Huth static void get_sprs_book3s_207(uint64_t *v)
168ee30cf14SThomas Huth {
169ee30cf14SThomas Huth 	v[3] = mfspr(3);	/* DSCR */
170ee30cf14SThomas Huth 	v[13] = mfspr(13);	/* AMR */
171ee30cf14SThomas Huth 	v[17] = mfspr(17);	/* DSCR */
172ee30cf14SThomas Huth 	v[18] = mfspr(18);	/* DSISR */
173ee30cf14SThomas Huth 	v[19] = mfspr(19);	/* DAR */
174ee30cf14SThomas Huth 	v[29] = mfspr(29);	/* AMR */
175ee30cf14SThomas Huth 	v[61] = mfspr(61);	/* IAMR */
176ee30cf14SThomas Huth 	// v[136] = mfspr(136);	/* CTRL */  /* TODO: Needs a fix in KVM */
177ee30cf14SThomas Huth 	v[153] = mfspr(153);	/* FSCR */
178ee30cf14SThomas Huth 	v[157] = mfspr(157);	/* UAMOR */
179ee30cf14SThomas Huth 	v[159] = mfspr(159);	/* PSPB */
180ee30cf14SThomas Huth 	v[256] = mfspr(256);	/* VRSAVE */
181ee30cf14SThomas Huth 	v[259] = mfspr(259);	/* SPRG3 (read only) */
182ee30cf14SThomas Huth 	// v[272] = mfspr(272);	/* SPRG0 */  /* Used by our exception handler */
183ee30cf14SThomas Huth 	v[769] = mfspr(769);	/* MMCR2 */
184ee30cf14SThomas Huth 	v[770] = mfspr(770);	/* MMCRA */
185ee30cf14SThomas Huth 	v[771] = mfspr(771);	/* PMC1 */
186ee30cf14SThomas Huth 	v[772] = mfspr(772);	/* PMC2 */
187ee30cf14SThomas Huth 	v[773] = mfspr(773);	/* PMC3 */
188ee30cf14SThomas Huth 	v[774] = mfspr(774);	/* PMC4 */
189ee30cf14SThomas Huth 	v[775] = mfspr(775);	/* PMC5 */
190ee30cf14SThomas Huth 	v[776] = mfspr(776);	/* PMC6 */
191ee30cf14SThomas Huth 	v[779] = mfspr(779);	/* MMCR0 */
192ee30cf14SThomas Huth 	v[780] = mfspr(780);	/* SIAR (read only) */
193ee30cf14SThomas Huth 	v[781] = mfspr(781);	/* SDAR (read only) */
194ee30cf14SThomas Huth 	v[782] = mfspr(782);	/* MMCR1 (read only) */
195ee30cf14SThomas Huth 	v[784] = mfspr(784);	/* SIER */
196ee30cf14SThomas Huth 	v[785] = mfspr(785);	/* MMCR2 */
197ee30cf14SThomas Huth 	v[786] = mfspr(786);	/* MMCRA */
198ee30cf14SThomas Huth 	v[787] = mfspr(787);	/* PMC1 */
199ee30cf14SThomas Huth 	v[788] = mfspr(788);	/* PMC2 */
200ee30cf14SThomas Huth 	v[789] = mfspr(789);	/* PMC3 */
201ee30cf14SThomas Huth 	v[790] = mfspr(790);	/* PMC4 */
202ee30cf14SThomas Huth 	v[791] = mfspr(791);	/* PMC5 */
203ee30cf14SThomas Huth 	v[792] = mfspr(792);	/* PMC6 */
204ee30cf14SThomas Huth 	v[795] = mfspr(795);	/* MMCR0 */
205ee30cf14SThomas Huth 	v[796] = mfspr(796);	/* SIAR */
206ee30cf14SThomas Huth 	v[797] = mfspr(797);	/* SDAR */
207ee30cf14SThomas Huth 	v[798] = mfspr(798);	/* MMCR1 */
208ee30cf14SThomas Huth 	v[800] = mfspr(800);	/* BESCRS */
209ee30cf14SThomas Huth 	v[801] = mfspr(801);	/* BESCCRSU */
210ee30cf14SThomas Huth 	v[802] = mfspr(802);	/* BESCRR */
211ee30cf14SThomas Huth 	v[803] = mfspr(803);	/* BESCRRU */
212ee30cf14SThomas Huth 	v[804] = mfspr(804);	/* EBBHR */
213ee30cf14SThomas Huth 	v[805] = mfspr(805);	/* EBBRR */
214ee30cf14SThomas Huth 	v[806] = mfspr(806);	/* BESCR */
215ee30cf14SThomas Huth 	v[815] = mfspr(815);	/* TAR */
216ee30cf14SThomas Huth }
217ee30cf14SThomas Huth 
21825a302cbSThomas Huth static void get_sprs_book3s_300(uint64_t *v)
21925a302cbSThomas Huth {
22025a302cbSThomas Huth 	get_sprs_book3s_207(v);
22125a302cbSThomas Huth 	v[48] = mfspr(48);	/* PIDR */
22225a302cbSThomas Huth 	v[144] = mfspr(144);	/* TIDR */
22325a302cbSThomas Huth 	v[823] = mfspr(823);	/* PSSCR */
22425a302cbSThomas Huth }
22525a302cbSThomas Huth 
226faaddcb0SNicholas Piggin static void get_sprs_book3s_31(uint64_t *v)
227faaddcb0SNicholas Piggin {
228faaddcb0SNicholas Piggin 	get_sprs_book3s_207(v);
229faaddcb0SNicholas Piggin 	v[48] = mfspr(48);	/* PIDR */
230faaddcb0SNicholas Piggin 	v[823] = mfspr(823);	/* PSSCR */
231faaddcb0SNicholas Piggin }
232faaddcb0SNicholas Piggin 
233ee30cf14SThomas Huth static void get_sprs(uint64_t *v)
234ee30cf14SThomas Huth {
235ee30cf14SThomas Huth 	uint32_t pvr = mfspr(287);	/* Processor Version Register */
236ee30cf14SThomas Huth 
237ee30cf14SThomas Huth 	get_sprs_common(v);
238ee30cf14SThomas Huth 
239ee30cf14SThomas Huth 	switch (pvr >> 16) {
240ee30cf14SThomas Huth 	case 0x39:			/* PPC970 */
241ee30cf14SThomas Huth 	case 0x3C:			/* PPC970FX */
242ee30cf14SThomas Huth 	case 0x44:			/* PPC970MP */
243ee30cf14SThomas Huth 		get_sprs_book3s_201(v);
244ee30cf14SThomas Huth 		break;
245ee30cf14SThomas Huth 	case 0x4b:			/* POWER8E */
246ee30cf14SThomas Huth 	case 0x4c:			/* POWER8NVL */
247ee30cf14SThomas Huth 	case 0x4d:			/* POWER8 */
248ee30cf14SThomas Huth 		get_sprs_book3s_207(v);
249ee30cf14SThomas Huth 		break;
25025a302cbSThomas Huth 	case 0x4e:			/* POWER9 */
25125a302cbSThomas Huth 		get_sprs_book3s_300(v);
25225a302cbSThomas Huth 		break;
253faaddcb0SNicholas Piggin 	case 0x80:                      /* POWER10 */
254faaddcb0SNicholas Piggin 		get_sprs_book3s_31(v);
255faaddcb0SNicholas Piggin 		break;
256ee30cf14SThomas Huth 	}
257ee30cf14SThomas Huth }
258ee30cf14SThomas Huth 
259ee30cf14SThomas Huth int main(int argc, char **argv)
260ee30cf14SThomas Huth {
261ee30cf14SThomas Huth 	int i;
262ee30cf14SThomas Huth 	bool pause = false;
263ee30cf14SThomas Huth 	uint64_t pat = 0xcafefacec0debabeULL;
264ee30cf14SThomas Huth 	const uint64_t patterns[] = {
265ee30cf14SThomas Huth 		0xcafefacec0debabeULL, ~0xcafefacec0debabeULL,
266ee30cf14SThomas Huth 		0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL,
267ee30cf14SThomas Huth 		0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL,
268ee30cf14SThomas Huth 		-1ULL,
269ee30cf14SThomas Huth 	};
270ee30cf14SThomas Huth 
271ee30cf14SThomas Huth 	for (i = 1; i < argc; i++) {
272ee30cf14SThomas Huth 		if (!strcmp(argv[i], "-w")) {
273ee30cf14SThomas Huth 			pause = true;
274ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-p")) {
275ee30cf14SThomas Huth 			i += 1;
276ee30cf14SThomas Huth 			if (i >= argc || *argv[i] < '0'
277ee30cf14SThomas Huth 			    || *argv[i] >= '0' + ARRAY_SIZE(patterns))
278ee30cf14SThomas Huth 				report_abort("Error: bad value for -p");
279ee30cf14SThomas Huth 			pat ^= patterns[*argv[i] - '0'];
280ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-t")) {
281ee30cf14SThomas Huth 			/* Randomize with timebase register */
282ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
283ee30cf14SThomas Huth 			pat ^= i;
284ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
285ee30cf14SThomas Huth 			pat ^= ~(uint64_t)i << 32;
286ee30cf14SThomas Huth 		} else {
287ee30cf14SThomas Huth 			report_abort("Warning: Unsupported argument: %s",
288ee30cf14SThomas Huth 			             argv[i]);
289ee30cf14SThomas Huth 		}
290ee30cf14SThomas Huth 	}
291ee30cf14SThomas Huth 
292fd6aada0SRadim Krčmář 	printf("Settings SPRs to %#lx...\n", pat);
293ee30cf14SThomas Huth 	set_sprs(pat);
294ee30cf14SThomas Huth 
295ee30cf14SThomas Huth 	memset(before, 0, sizeof(before));
296ee30cf14SThomas Huth 	memset(after, 0, sizeof(after));
297ee30cf14SThomas Huth 
298ee30cf14SThomas Huth 	get_sprs(before);
299ee30cf14SThomas Huth 
300ee30cf14SThomas Huth 	if (pause) {
30177a59d17SNico Boehr 		migrate_once();
302ee30cf14SThomas Huth 	} else {
303ba33a96fSNicholas Piggin 		msleep(2000);
304ee30cf14SThomas Huth 	}
305ee30cf14SThomas Huth 
306ee30cf14SThomas Huth 	get_sprs(after);
307ee30cf14SThomas Huth 
308ee30cf14SThomas Huth 	puts("Checking SPRs...\n");
309ee30cf14SThomas Huth 	for (i = 0; i < 1024; i++) {
310ee30cf14SThomas Huth 		if (before[i] != 0 || after[i] != 0)
311a299895bSThomas Huth 			report(before[i] == after[i],
312a299895bSThomas Huth 			       "SPR %d:\t%#018lx <==> %#018lx", i, before[i],
313a299895bSThomas Huth 			       after[i]);
314ee30cf14SThomas Huth 	}
315ee30cf14SThomas Huth 
316ee30cf14SThomas Huth 	return report_summary();
317ee30cf14SThomas Huth }
318