xref: /kvm-unit-tests/powerpc/sprs.c (revision 8f6290f0e63e81ac08ea19f7e33f563e378a6e61)
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>
269c5e1913SNicholas 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 
33*8f6290f0SNicholas Piggin /* "Indirect" mfspr/mtspr which accept a non-constant spr number */
34*8f6290f0SNicholas Piggin static uint64_t __mfspr(unsigned spr)
35ee30cf14SThomas Huth {
36*8f6290f0SNicholas Piggin 	uint64_t tmp;
37*8f6290f0SNicholas Piggin 	uint64_t ret;
38*8f6290f0SNicholas Piggin 
39*8f6290f0SNicholas Piggin 	asm volatile(
40*8f6290f0SNicholas Piggin "	bcl	20, 31, 1f		\n"
41*8f6290f0SNicholas Piggin "1:	mflr	%0			\n"
42*8f6290f0SNicholas Piggin "	addi	%0, %0, (2f-1b)		\n"
43*8f6290f0SNicholas Piggin "	add	%0, %0, %2		\n"
44*8f6290f0SNicholas Piggin "	mtctr	%0			\n"
45*8f6290f0SNicholas Piggin "	bctr				\n"
46*8f6290f0SNicholas Piggin "2:					\n"
47*8f6290f0SNicholas Piggin ".LSPR=0				\n"
48*8f6290f0SNicholas Piggin ".rept 1024				\n"
49*8f6290f0SNicholas Piggin "	mfspr	%1, .LSPR		\n"
50*8f6290f0SNicholas Piggin "	b	3f			\n"
51*8f6290f0SNicholas Piggin "	.LSPR=.LSPR+1			\n"
52*8f6290f0SNicholas Piggin ".endr					\n"
53*8f6290f0SNicholas Piggin "3:					\n"
54*8f6290f0SNicholas Piggin 	: "=&r"(tmp),
55*8f6290f0SNicholas Piggin 	  "=r"(ret)
56*8f6290f0SNicholas Piggin 	: "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
57*8f6290f0SNicholas Piggin 	: "lr", "ctr");
58*8f6290f0SNicholas Piggin 
59*8f6290f0SNicholas Piggin 	return ret;
60ee30cf14SThomas Huth }
61ee30cf14SThomas Huth 
62*8f6290f0SNicholas Piggin static void __mtspr(unsigned spr, uint64_t val)
63*8f6290f0SNicholas Piggin {
64*8f6290f0SNicholas Piggin 	uint64_t tmp;
65*8f6290f0SNicholas Piggin 
66*8f6290f0SNicholas Piggin 	asm volatile(
67*8f6290f0SNicholas Piggin "	bcl	20, 31, 1f		\n"
68*8f6290f0SNicholas Piggin "1:	mflr	%0			\n"
69*8f6290f0SNicholas Piggin "	addi	%0, %0, (2f-1b)		\n"
70*8f6290f0SNicholas Piggin "	add	%0, %0, %2		\n"
71*8f6290f0SNicholas Piggin "	mtctr	%0			\n"
72*8f6290f0SNicholas Piggin "	bctr				\n"
73*8f6290f0SNicholas Piggin "2:					\n"
74*8f6290f0SNicholas Piggin ".LSPR=0				\n"
75*8f6290f0SNicholas Piggin ".rept 1024				\n"
76*8f6290f0SNicholas Piggin "	mtspr	.LSPR, %1		\n"
77*8f6290f0SNicholas Piggin "	b	3f			\n"
78*8f6290f0SNicholas Piggin "	.LSPR=.LSPR+1			\n"
79*8f6290f0SNicholas Piggin ".endr					\n"
80*8f6290f0SNicholas Piggin "3:					\n"
81*8f6290f0SNicholas Piggin 	: "=&r"(tmp)
82*8f6290f0SNicholas Piggin 	: "r"(val),
83*8f6290f0SNicholas Piggin 	  "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
84*8f6290f0SNicholas Piggin 	: "lr", "ctr", "xer");
85*8f6290f0SNicholas Piggin }
86*8f6290f0SNicholas Piggin 
87*8f6290f0SNicholas Piggin static uint64_t before[1024], after[1024];
88*8f6290f0SNicholas Piggin 
89*8f6290f0SNicholas Piggin #define SPR_PR_READ	0x0001
90*8f6290f0SNicholas Piggin #define SPR_PR_WRITE	0x0002
91*8f6290f0SNicholas Piggin #define SPR_OS_READ	0x0010
92*8f6290f0SNicholas Piggin #define SPR_OS_WRITE	0x0020
93*8f6290f0SNicholas Piggin #define SPR_HV_READ	0x0100
94*8f6290f0SNicholas Piggin #define SPR_HV_WRITE	0x0200
95*8f6290f0SNicholas Piggin 
96*8f6290f0SNicholas Piggin #define RW		0x333
97*8f6290f0SNicholas Piggin #define RO		0x111
98*8f6290f0SNicholas Piggin #define WO		0x222
99*8f6290f0SNicholas Piggin #define OS_RW		0x330
100*8f6290f0SNicholas Piggin #define OS_RO		0x110
101*8f6290f0SNicholas Piggin #define OS_WO		0x220
102*8f6290f0SNicholas Piggin #define HV_RW		0x300
103*8f6290f0SNicholas Piggin #define HV_RO		0x100
104*8f6290f0SNicholas Piggin #define HV_WO		0x200
105*8f6290f0SNicholas Piggin 
106*8f6290f0SNicholas Piggin #define SPR_ASYNC	0x1000	/* May be updated asynchronously */
107*8f6290f0SNicholas Piggin #define SPR_INT		0x2000	/* May be updated by synchronous interrupt */
108*8f6290f0SNicholas Piggin #define SPR_HARNESS	0x4000	/* Test harness uses the register */
109*8f6290f0SNicholas Piggin 
110*8f6290f0SNicholas Piggin struct spr {
111*8f6290f0SNicholas Piggin 	const char	*name;
112*8f6290f0SNicholas Piggin 	uint8_t		width;
113*8f6290f0SNicholas Piggin 	uint16_t	access;
114*8f6290f0SNicholas Piggin 	uint16_t	type;
115*8f6290f0SNicholas Piggin };
116*8f6290f0SNicholas Piggin 
117*8f6290f0SNicholas Piggin /* SPRs common denominator back to PowerPC Operating Environment Architecture */
118*8f6290f0SNicholas Piggin static const struct spr sprs_common[1024] = {
119*8f6290f0SNicholas Piggin   [1] = { "XER",	64,	RW,		SPR_HARNESS, }, /* Used by compiler */
120*8f6290f0SNicholas Piggin   [8] = { "LR", 	64,	RW,		SPR_HARNESS, }, /* Compiler, mfspr/mtspr */
121*8f6290f0SNicholas Piggin   [9] = { "CTR",	64,	RW,		SPR_HARNESS, }, /* Compiler, mfspr/mtspr */
122*8f6290f0SNicholas Piggin  [18] = { "DSISR",	32,	OS_RW,		SPR_INT, },
123*8f6290f0SNicholas Piggin  [19] = { "DAR",	64,	OS_RW,		SPR_INT, },
124*8f6290f0SNicholas Piggin  [26] = { "SRR0",	64,	OS_RW,		SPR_INT, },
125*8f6290f0SNicholas Piggin  [27] = { "SRR1",	64,	OS_RW,		SPR_INT, },
126*8f6290f0SNicholas Piggin [268] = { "TB",		64,	RO	,	SPR_ASYNC, },
127*8f6290f0SNicholas Piggin [269] = { "TBU",	32,	RO,		SPR_ASYNC, },
128*8f6290f0SNicholas Piggin [272] = { "SPRG0",	64,	OS_RW,		SPR_HARNESS, }, /* Interrupt stacr */
129*8f6290f0SNicholas Piggin [273] = { "SPRG1",	64,	OS_RW,		SPR_HARNESS, }, /* Interrupt Scratch */
130*8f6290f0SNicholas Piggin [274] = { "SPRG2",	64,	OS_RW, },
131*8f6290f0SNicholas Piggin [275] = { "SPRG3",	64,	OS_RW, },
132*8f6290f0SNicholas Piggin [287] = { "PVR",	32,	OS_RO, },
133*8f6290f0SNicholas Piggin };
134*8f6290f0SNicholas Piggin 
135ee30cf14SThomas Huth /* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */
136*8f6290f0SNicholas Piggin static const struct spr sprs_201[1024] = {
137*8f6290f0SNicholas Piggin  [22] = { "DEC",	32,	OS_RW,		SPR_ASYNC, },
138*8f6290f0SNicholas Piggin  [25] = { "SDR1",	64,	HV_RW | OS_RO, },
139*8f6290f0SNicholas Piggin  [29] = { "ACCR",	64,	OS_RW, },
140*8f6290f0SNicholas Piggin [136] = { "CTRL",	32,	RO, },
141*8f6290f0SNicholas Piggin [152] = { "CTRL",	32,	OS_WO, },
142*8f6290f0SNicholas Piggin [259] = { "SPRG3",	64,	RO, },
143*8f6290f0SNicholas Piggin /* ASR, EAR omitted */
144*8f6290f0SNicholas Piggin [284] = { "TBL",	32,	HV_WO, },
145*8f6290f0SNicholas Piggin [285] = { "TBU",	32,	HV_WO, },
146*8f6290f0SNicholas Piggin [310] = { "HDEC",	32,	HV_RW,		SPR_ASYNC, },
147*8f6290f0SNicholas Piggin [1013]= { "DABR",	64,	HV_RW | OS_RO, },
148*8f6290f0SNicholas Piggin [1023]= { "PIR",	32,	OS_RO,		SPR_ASYNC, }, /* Can't be virtualised, appears to be async */
149*8f6290f0SNicholas Piggin };
150*8f6290f0SNicholas Piggin 
151*8f6290f0SNicholas Piggin static const struct spr sprs_970_pmu[1024] = {
152*8f6290f0SNicholas Piggin /* POWER4+ PMU, should confirm with PPC970 */
153*8f6290f0SNicholas Piggin [770] = { "MMCRA",	64,	RO, },
154*8f6290f0SNicholas Piggin [771] = { "PMC1",	32,	RO, },
155*8f6290f0SNicholas Piggin [772] = { "PMC2",	32,	RO, },
156*8f6290f0SNicholas Piggin [773] = { "PMC3",	32,	RO, },
157*8f6290f0SNicholas Piggin [774] = { "PMC4",	32,	RO, },
158*8f6290f0SNicholas Piggin [775] = { "PMC5",	32,	RO, },
159*8f6290f0SNicholas Piggin [776] = { "PMC6",	32,	RO, },
160*8f6290f0SNicholas Piggin [777] = { "PMC7",	32,	RO, },
161*8f6290f0SNicholas Piggin [778] = { "PMC8",	32,	RO, },
162*8f6290f0SNicholas Piggin [779] = { "MMCR0",	64,	RO, },
163*8f6290f0SNicholas Piggin [780] = { "SIAR",	64,	RO, },
164*8f6290f0SNicholas Piggin [781] = { "SDAR",	64,	RO, },
165*8f6290f0SNicholas Piggin [782] = { "MMCR1",	64,	RO, },
166*8f6290f0SNicholas Piggin [786] = { "MMCRA",	64,	OS_RW, },
167*8f6290f0SNicholas Piggin [787] = { "PMC1",	32,	OS_RW, },
168*8f6290f0SNicholas Piggin [788] = { "PMC2",	32,	OS_RW, },
169*8f6290f0SNicholas Piggin [789] = { "PMC3",	32,	OS_RW, },
170*8f6290f0SNicholas Piggin [790] = { "PMC4",	32,	OS_RW, },
171*8f6290f0SNicholas Piggin [791] = { "PMC5",	32,	OS_RW, },
172*8f6290f0SNicholas Piggin [792] = { "PMC6",	32,	OS_RW, },
173*8f6290f0SNicholas Piggin [793] = { "PMC7",	32,	OS_RW, },
174*8f6290f0SNicholas Piggin [794] = { "PMC8",	32,	OS_RW, },
175*8f6290f0SNicholas Piggin [795] = { "MMCR0",	64,	OS_RW, },
176*8f6290f0SNicholas Piggin [796] = { "SIAR",	64,	OS_RW, },
177*8f6290f0SNicholas Piggin [797] = { "SDAR",	64,	OS_RW, },
178*8f6290f0SNicholas Piggin [798] = { "MMCR1",	64,	OS_RW, },
179*8f6290f0SNicholas Piggin };
180*8f6290f0SNicholas Piggin 
181*8f6290f0SNicholas Piggin /* These are common SPRs from 2.07S onward (POWER CPUs that support KVM HV) */
182*8f6290f0SNicholas Piggin static const struct spr sprs_power_common[1024] = {
183*8f6290f0SNicholas Piggin   [3] = { "DSCR",	64,	RW, },
184*8f6290f0SNicholas Piggin  [13] = { "AMR",	64,	RW, },
185*8f6290f0SNicholas Piggin  [17] = { "DSCR",	64,	OS_RW, },
186*8f6290f0SNicholas Piggin  [28] = { "CFAR",	64,	OS_RW,		SPR_ASYNC, }, /* Effectively async */
187*8f6290f0SNicholas Piggin  [29] = { "AMR",	64,	OS_RW, },
188*8f6290f0SNicholas Piggin  [61] = { "IAMR",	64,	OS_RW, },
189*8f6290f0SNicholas Piggin [136] = { "CTRL",	32,	RO, },
190*8f6290f0SNicholas Piggin [152] = { "CTRL",	32,	OS_WO, },
191*8f6290f0SNicholas Piggin [153] = { "FSCR",	64,	OS_RW, },
192*8f6290f0SNicholas Piggin [157] = { "UAMOR",	64,	OS_RW, },
193*8f6290f0SNicholas Piggin [159] = { "PSPB",	32,	OS_RW, },
194*8f6290f0SNicholas Piggin [176] = { "DPDES",	64,	HV_RW | OS_RO, },
195*8f6290f0SNicholas Piggin [180] = { "DAWR0",	64,	HV_RW, },
196*8f6290f0SNicholas Piggin [186] = { "RPR",	64,	HV_RW, },
197*8f6290f0SNicholas Piggin [187] = { "CIABR",	64,	HV_RW, },
198*8f6290f0SNicholas Piggin [188] = { "DAWRX0",	32,	HV_RW, },
199*8f6290f0SNicholas Piggin [190] = { "HFSCR",	64,	HV_RW, },
200*8f6290f0SNicholas Piggin [256] = { "VRSAVE",	32,	RW, },
201*8f6290f0SNicholas Piggin [259] = { "SPRG3",	64,	RO, },
202*8f6290f0SNicholas Piggin [284] = { "TBL",	32,	HV_WO, },
203*8f6290f0SNicholas Piggin [285] = { "TBU",	32,	HV_WO, },
204*8f6290f0SNicholas Piggin [286] = { "TBU40",	64,	HV_WO, },
205*8f6290f0SNicholas Piggin [304] = { "HSPRG0",	64,	HV_RW, },
206*8f6290f0SNicholas Piggin [305] = { "HSPRG1",	64,	HV_RW, },
207*8f6290f0SNicholas Piggin [306] = { "HDSISR",	32,	HV_RW,		SPR_INT, },
208*8f6290f0SNicholas Piggin [307] = { "HDAR",	64,	HV_RW,		SPR_INT, },
209*8f6290f0SNicholas Piggin [308] = { "SPURR",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
210*8f6290f0SNicholas Piggin [309] = { "PURR",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
211*8f6290f0SNicholas Piggin [313] = { "HRMOR",	64,	HV_RW, },
212*8f6290f0SNicholas Piggin [314] = { "HSRR0",	64,	HV_RW,		SPR_INT, },
213*8f6290f0SNicholas Piggin [315] = { "HSRR1",	64,	HV_RW,		SPR_INT, },
214*8f6290f0SNicholas Piggin [318] = { "LPCR",	64,	HV_RW, },
215*8f6290f0SNicholas Piggin [319] = { "LPIDR",	32,	HV_RW, },
216*8f6290f0SNicholas Piggin [336] = { "HMER",	64,	HV_RW, },
217*8f6290f0SNicholas Piggin [337] = { "HMEER",	64,	HV_RW, },
218*8f6290f0SNicholas Piggin [338] = { "PCR",	64,	HV_RW, },
219*8f6290f0SNicholas Piggin [349] = { "AMOR",	64,	HV_RW, },
220*8f6290f0SNicholas Piggin [446] = { "TIR",	64,	OS_RO, },
221*8f6290f0SNicholas Piggin [800] = { "BESCRS",	64,	RW, },
222*8f6290f0SNicholas Piggin [801] = { "BESCRSU",	32,	RW, },
223*8f6290f0SNicholas Piggin [802] = { "BESCRR",	64,	RW, },
224*8f6290f0SNicholas Piggin [803] = { "BESCRRU",	32,	RW, },
225*8f6290f0SNicholas Piggin [804] = { "EBBHR",	64,	RW, },
226*8f6290f0SNicholas Piggin [805] = { "EBBRR",	64,	RW, },
227*8f6290f0SNicholas Piggin [806] = { "BESCR",	64,	RW, },
228*8f6290f0SNicholas Piggin [815] = { "TAR",	64,	RW, },
229*8f6290f0SNicholas Piggin [848] = { "IC",		64,	HV_RW | OS_RO,	SPR_ASYNC, },
230*8f6290f0SNicholas Piggin [849] = { "VTB",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
231*8f6290f0SNicholas Piggin [896] = { "PPR",	64,	RW, },
232*8f6290f0SNicholas Piggin [898] = { "PPR32",	32,	RW, },
233*8f6290f0SNicholas Piggin [1023]= { "PIR",	32,	OS_RO,		SPR_ASYNC, }, /* Can't be virtualised, appears to be async */
234*8f6290f0SNicholas Piggin };
235*8f6290f0SNicholas Piggin 
236*8f6290f0SNicholas Piggin static const struct spr sprs_tm[1024] = {
237*8f6290f0SNicholas Piggin #if 0
238*8f6290f0SNicholas Piggin 	/* XXX: leave these out until enabling TM facility (and more testing) */
239*8f6290f0SNicholas Piggin [128] = { "TFHAR",	64,	RW, },
240*8f6290f0SNicholas Piggin [129] = { "TFIAR",	64,	RW, },
241*8f6290f0SNicholas Piggin [130] = { "TEXASR",	64,	RW, },
242*8f6290f0SNicholas Piggin [131] = { "TEXASRU",	32,	RW, },
243*8f6290f0SNicholas Piggin #endif
244*8f6290f0SNicholas Piggin };
245ee30cf14SThomas Huth 
246ee30cf14SThomas Huth /* SPRs from PowerISA 2.07 Book III-S */
247*8f6290f0SNicholas Piggin static const struct spr sprs_207[1024] = {
248*8f6290f0SNicholas Piggin  [22] = { "DEC",	32,	OS_RW,		SPR_ASYNC, },
249*8f6290f0SNicholas Piggin  [25] = { "SDR1",	64,	HV_RW, },
250*8f6290f0SNicholas Piggin [177] = { "DHDES",	64,	HV_RW, },
251*8f6290f0SNicholas Piggin [283] = { "CIR",	32,	OS_RO, },
252*8f6290f0SNicholas Piggin [310] = { "HDEC",	32,	HV_RW,		SPR_ASYNC, },
253*8f6290f0SNicholas Piggin [312] = { "RMOR",	64,	HV_RW, },
254*8f6290f0SNicholas Piggin [339] = { "HEIR",	32,	HV_RW,		SPR_INT, },
255*8f6290f0SNicholas Piggin };
256ee30cf14SThomas Huth 
25725a302cbSThomas Huth /* SPRs from PowerISA 3.00 Book III */
258*8f6290f0SNicholas Piggin static const struct spr sprs_300[1024] = {
259*8f6290f0SNicholas Piggin  [22] = { "DEC",	64,	OS_RW,		SPR_ASYNC, },
260*8f6290f0SNicholas Piggin  [48] = { "PIDR",	32,	OS_RW, },
261*8f6290f0SNicholas Piggin [144] = { "TIDR",	64,	OS_RW, },
262*8f6290f0SNicholas Piggin [283] = { "CIR",	32,	OS_RO, },
263*8f6290f0SNicholas Piggin [310] = { "HDEC",	64,	HV_RW,		SPR_ASYNC, },
264*8f6290f0SNicholas Piggin [339] = { "HEIR",	32,	HV_RW,		SPR_INT, },
265*8f6290f0SNicholas Piggin [464] = { "PTCR",	64,	HV_RW, },
266*8f6290f0SNicholas Piggin [816] = { "ASDR",	64,	HV_RW,		SPR_INT, },
267*8f6290f0SNicholas Piggin [823] = { "PSSCR",	64,	OS_RW, },
268*8f6290f0SNicholas Piggin [855] = { "PSSCR",	64,	HV_RW, },
269*8f6290f0SNicholas Piggin };
27025a302cbSThomas Huth 
271*8f6290f0SNicholas Piggin /* SPRs from PowerISA 3.1B Book III */
272*8f6290f0SNicholas Piggin static const struct spr sprs_31[1024] = {
273*8f6290f0SNicholas Piggin  [22] = { "DEC",	64,	OS_RW,		SPR_ASYNC, },
274*8f6290f0SNicholas Piggin  [48] = { "PIDR",	32,	OS_RW, },
275*8f6290f0SNicholas Piggin [181] = { "DAWR1",	64,	HV_RW, },
276*8f6290f0SNicholas Piggin [189] = { "DAWRX1",	32,	HV_RW, },
277*8f6290f0SNicholas Piggin [310] = { "HDEC",	64,	HV_RW,		SPR_ASYNC, },
278*8f6290f0SNicholas Piggin [339] = { "HEIR",	64,	HV_RW,		SPR_INT, },
279*8f6290f0SNicholas Piggin [455] = { "HDEXCR",	32,	RO, },
280*8f6290f0SNicholas Piggin [464] = { "PTCR",	64,	HV_RW, },
281*8f6290f0SNicholas Piggin [468] = { "HASHKEYR",	64,	OS_RW, },
282*8f6290f0SNicholas Piggin [469] = { "HASHPKEYR",	64,	HV_RW, },
283*8f6290f0SNicholas Piggin [471] = { "HDEXCR",	64,	HV_RW, },
284*8f6290f0SNicholas Piggin [812] = { "DEXCR",	32,	RO, },
285*8f6290f0SNicholas Piggin [816] = { "ASDR",	64,	HV_RW,		SPR_INT, },
286*8f6290f0SNicholas Piggin [823] = { "PSSCR",	64,	OS_RW, },
287*8f6290f0SNicholas Piggin [828] = { "DEXCR",	64,	OS_RW, },
288*8f6290f0SNicholas Piggin [855] = { "PSSCR",	64,	HV_RW, },
289*8f6290f0SNicholas Piggin };
290faaddcb0SNicholas Piggin 
291*8f6290f0SNicholas Piggin /* SPRs POWER9, POWER10 User Manual */
292*8f6290f0SNicholas Piggin static const struct spr sprs_power9_10[1024] = {
293*8f6290f0SNicholas Piggin [276] = { "SPRC",	64,	HV_RW, },
294*8f6290f0SNicholas Piggin [277] = { "SPRD",	64,	HV_RW, },
295*8f6290f0SNicholas Piggin [317] = { "TFMR",	64,	HV_RW, },
296*8f6290f0SNicholas Piggin [799] = { "IMC",	64,	HV_RW, },
297*8f6290f0SNicholas Piggin [850] = { "LDBAR",	64,	HV_RO, },
298*8f6290f0SNicholas Piggin [851] = { "MMCRC",	32,	HV_RW, },
299*8f6290f0SNicholas Piggin [853] = { "PMSR",	32,	HV_RO, },
300*8f6290f0SNicholas Piggin [861] = { "L2QOSR",	64,	HV_WO, },
301*8f6290f0SNicholas Piggin [881] = { "TRIG1",	64,	OS_WO, },
302*8f6290f0SNicholas Piggin [882] = { "TRIG2",	64,	OS_WO, },
303*8f6290f0SNicholas Piggin [884] = { "PMCR",	64,	HV_RW, },
304*8f6290f0SNicholas Piggin [885] = { "RWMR",	64,	HV_RW, },
305*8f6290f0SNicholas Piggin [895] = { "WORT",	64,	OS_RW, }, /* UM says 18-bits! */
306*8f6290f0SNicholas Piggin [921] = { "TSCR",	32,	HV_RW, },
307*8f6290f0SNicholas Piggin [922] = { "TTR",	64,	HV_RW, },
308*8f6290f0SNicholas Piggin [1006]= { "TRACE",	64,	WO, },
309*8f6290f0SNicholas Piggin [1008]= { "HID",	64,	HV_RW, },
310*8f6290f0SNicholas Piggin };
311*8f6290f0SNicholas Piggin 
312*8f6290f0SNicholas Piggin /* This covers POWER8 and POWER9 PMUs */
313*8f6290f0SNicholas Piggin static const struct spr sprs_power_common_pmu[1024] = {
314*8f6290f0SNicholas Piggin [768] = { "SIER",	64,	RO, },
315*8f6290f0SNicholas Piggin [769] = { "MMCR2",	64,	RW, },
316*8f6290f0SNicholas Piggin [770] = { "MMCRA",	64,	RW, },
317*8f6290f0SNicholas Piggin [771] = { "PMC1",	32,	RW, },
318*8f6290f0SNicholas Piggin [772] = { "PMC2",	32,	RW, },
319*8f6290f0SNicholas Piggin [773] = { "PMC3",	32,	RW, },
320*8f6290f0SNicholas Piggin [774] = { "PMC4",	32,	RW, },
321*8f6290f0SNicholas Piggin [775] = { "PMC5",	32,	RW, },
322*8f6290f0SNicholas Piggin [776] = { "PMC6",	32,	RW, },
323*8f6290f0SNicholas Piggin [779] = { "MMCR0",	64,	RW, },
324*8f6290f0SNicholas Piggin [780] = { "SIAR",	64,	RO, },
325*8f6290f0SNicholas Piggin [781] = { "SDAR",	64,	RO, },
326*8f6290f0SNicholas Piggin [782] = { "MMCR1",	64,	RO, },
327*8f6290f0SNicholas Piggin [784] = { "SIER",	64,	OS_RW, },
328*8f6290f0SNicholas Piggin [785] = { "MMCR2",	64,	OS_RW, },
329*8f6290f0SNicholas Piggin [786] = { "MMCRA",	64,	OS_RW, },
330*8f6290f0SNicholas Piggin [787] = { "PMC1",	32,	OS_RW, },
331*8f6290f0SNicholas Piggin [788] = { "PMC2",	32,	OS_RW, },
332*8f6290f0SNicholas Piggin [789] = { "PMC3",	32,	OS_RW, },
333*8f6290f0SNicholas Piggin [790] = { "PMC4",	32,	OS_RW, },
334*8f6290f0SNicholas Piggin [791] = { "PMC5",	32,	OS_RW, },
335*8f6290f0SNicholas Piggin [792] = { "PMC6",	32,	OS_RW, },
336*8f6290f0SNicholas Piggin [795] = { "MMCR0",	64,	OS_RW, },
337*8f6290f0SNicholas Piggin [796] = { "SIAR",	64,	OS_RW, },
338*8f6290f0SNicholas Piggin [797] = { "SDAR",	64,	OS_RW, },
339*8f6290f0SNicholas Piggin [798] = { "MMCR1",	64,	OS_RW, },
340*8f6290f0SNicholas Piggin };
341*8f6290f0SNicholas Piggin 
342*8f6290f0SNicholas Piggin static const struct spr sprs_power10_pmu[1024] = {
343*8f6290f0SNicholas Piggin [736] = { "SIER2",	64,	RO, },
344*8f6290f0SNicholas Piggin [737] = { "SIER3",	64,	RO, },
345*8f6290f0SNicholas Piggin [738] = { "MMCR3",	64,	RO, },
346*8f6290f0SNicholas Piggin [752] = { "SIER2",	64,	OS_RW, },
347*8f6290f0SNicholas Piggin [753] = { "SIER3",	64,	OS_RW, },
348*8f6290f0SNicholas Piggin [754] = { "MMCR3",	64,	OS_RW, },
349*8f6290f0SNicholas Piggin };
350*8f6290f0SNicholas Piggin 
351*8f6290f0SNicholas Piggin static struct spr sprs[1024];
352*8f6290f0SNicholas Piggin 
353*8f6290f0SNicholas Piggin static void setup_sprs(void)
354ee30cf14SThomas Huth {
355*8f6290f0SNicholas Piggin 	int i;
356*8f6290f0SNicholas Piggin 
357*8f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
358*8f6290f0SNicholas Piggin 		if (sprs_common[i].name) {
359*8f6290f0SNicholas Piggin 			memcpy(&sprs[i], &sprs_common[i], sizeof(struct spr));
360*8f6290f0SNicholas Piggin 		}
361*8f6290f0SNicholas Piggin 	}
362ee30cf14SThomas Huth 
3639c5e1913SNicholas Piggin 	switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
3649c5e1913SNicholas Piggin 	case PVR_VER_970:
3659c5e1913SNicholas Piggin 	case PVR_VER_970FX:
3669c5e1913SNicholas Piggin 	case PVR_VER_970MP:
367*8f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
368*8f6290f0SNicholas Piggin 			if (sprs_201[i].name) {
369*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
370*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_201[i], sizeof(struct spr));
371*8f6290f0SNicholas Piggin 			}
372*8f6290f0SNicholas Piggin 			if (sprs_970_pmu[i].name) {
373*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
374*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
375*8f6290f0SNicholas Piggin 			}
376*8f6290f0SNicholas Piggin 		}
377ee30cf14SThomas Huth 		break;
378*8f6290f0SNicholas Piggin 
3799c5e1913SNicholas Piggin 	case PVR_VER_POWER8E:
3809c5e1913SNicholas Piggin 	case PVR_VER_POWER8NVL:
3819c5e1913SNicholas Piggin 	case PVR_VER_POWER8:
382*8f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
383*8f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
384*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
385*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
386*8f6290f0SNicholas Piggin 			}
387*8f6290f0SNicholas Piggin 			if (sprs_207[i].name) {
388*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
389*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_207[i], sizeof(struct spr));
390*8f6290f0SNicholas Piggin 			}
391*8f6290f0SNicholas Piggin 			if (sprs_tm[i].name) {
392*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
393*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_tm[i], sizeof(struct spr));
394*8f6290f0SNicholas Piggin 			}
395*8f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
396*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
397*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
398*8f6290f0SNicholas Piggin 			}
399*8f6290f0SNicholas Piggin 		}
400ee30cf14SThomas Huth 		break;
401*8f6290f0SNicholas Piggin 
4029c5e1913SNicholas Piggin 	case PVR_VER_POWER9:
403*8f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
404*8f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
405*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
406*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
407*8f6290f0SNicholas Piggin 			}
408*8f6290f0SNicholas Piggin 			if (sprs_300[i].name) {
409*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
410*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_300[i], sizeof(struct spr));
411*8f6290f0SNicholas Piggin 			}
412*8f6290f0SNicholas Piggin 			if (sprs_tm[i].name) {
413*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
414*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_tm[i], sizeof(struct spr));
415*8f6290f0SNicholas Piggin 			}
416*8f6290f0SNicholas Piggin 			if (sprs_power9_10[i].name) {
417*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
418*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power9_10[i], sizeof(struct spr));
419*8f6290f0SNicholas Piggin 			}
420*8f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
421*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
422*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
423*8f6290f0SNicholas Piggin 			}
424*8f6290f0SNicholas Piggin 		}
42525a302cbSThomas Huth 		break;
426*8f6290f0SNicholas Piggin 
4279c5e1913SNicholas Piggin 	case PVR_VER_POWER10:
428*8f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
429*8f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
430*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
431*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
432*8f6290f0SNicholas Piggin 			}
433*8f6290f0SNicholas Piggin 			if (sprs_31[i].name) {
434*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
435*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_31[i], sizeof(struct spr));
436*8f6290f0SNicholas Piggin 			}
437*8f6290f0SNicholas Piggin 			if (sprs_power9_10[i].name) {
438*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
439*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power9_10[i], sizeof(struct spr));
440*8f6290f0SNicholas Piggin 			}
441*8f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
442*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
443*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
444*8f6290f0SNicholas Piggin 			}
445*8f6290f0SNicholas Piggin 			if (sprs_power10_pmu[i].name) {
446*8f6290f0SNicholas Piggin 				assert(!sprs[i].name);
447*8f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power10_pmu[i], sizeof(struct spr));
448*8f6290f0SNicholas Piggin 			}
449*8f6290f0SNicholas Piggin 		}
450faaddcb0SNicholas Piggin 		break;
451*8f6290f0SNicholas Piggin 
452ee30cf14SThomas Huth 	default:
453*8f6290f0SNicholas Piggin 		memcpy(sprs, sprs_common, sizeof(sprs));
454*8f6290f0SNicholas Piggin 		puts("Warning: Unknown processor version, falling back to common SPRs!\n");
455*8f6290f0SNicholas Piggin 		break;
456ee30cf14SThomas Huth 	}
457ee30cf14SThomas Huth }
458ee30cf14SThomas Huth 
459ee30cf14SThomas Huth static void get_sprs(uint64_t *v)
460ee30cf14SThomas Huth {
461*8f6290f0SNicholas Piggin 	int i;
462ee30cf14SThomas Huth 
463*8f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
464*8f6290f0SNicholas Piggin 		if (!(sprs[i].access & SPR_OS_READ))
465*8f6290f0SNicholas Piggin 			continue;
466*8f6290f0SNicholas Piggin 		v[i] = __mfspr(i);
467*8f6290f0SNicholas Piggin 	}
468*8f6290f0SNicholas Piggin }
469ee30cf14SThomas Huth 
470*8f6290f0SNicholas Piggin static void set_sprs(uint64_t val)
471*8f6290f0SNicholas Piggin {
472*8f6290f0SNicholas Piggin 	int i;
473*8f6290f0SNicholas Piggin 
474*8f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
475*8f6290f0SNicholas Piggin 		if (!(sprs[i].access & SPR_OS_WRITE))
476*8f6290f0SNicholas Piggin 			continue;
477*8f6290f0SNicholas Piggin 		if (sprs[i].type & SPR_HARNESS)
478*8f6290f0SNicholas Piggin 			continue;
479*8f6290f0SNicholas Piggin 		if (!strcmp(sprs[i].name, "MMCR0")) {
480*8f6290f0SNicholas Piggin 			/* XXX: could use a comment or better abstraction! */
481*8f6290f0SNicholas Piggin 			__mtspr(i, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070);
482*8f6290f0SNicholas Piggin 		} else {
483*8f6290f0SNicholas Piggin 			__mtspr(i, val);
484*8f6290f0SNicholas Piggin 		}
485ee30cf14SThomas Huth 	}
486ee30cf14SThomas Huth }
487ee30cf14SThomas Huth 
488ee30cf14SThomas Huth int main(int argc, char **argv)
489ee30cf14SThomas Huth {
490ee30cf14SThomas Huth 	int i;
491ee30cf14SThomas Huth 	bool pause = false;
492ee30cf14SThomas Huth 	uint64_t pat = 0xcafefacec0debabeULL;
493ee30cf14SThomas Huth 	const uint64_t patterns[] = {
494ee30cf14SThomas Huth 		0xcafefacec0debabeULL, ~0xcafefacec0debabeULL,
495ee30cf14SThomas Huth 		0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL,
496ee30cf14SThomas Huth 		0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL,
497ee30cf14SThomas Huth 		-1ULL,
498ee30cf14SThomas Huth 	};
499ee30cf14SThomas Huth 
500ee30cf14SThomas Huth 	for (i = 1; i < argc; i++) {
501ee30cf14SThomas Huth 		if (!strcmp(argv[i], "-w")) {
502ee30cf14SThomas Huth 			pause = true;
503ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-p")) {
504ee30cf14SThomas Huth 			i += 1;
505ee30cf14SThomas Huth 			if (i >= argc || *argv[i] < '0'
506ee30cf14SThomas Huth 			    || *argv[i] >= '0' + ARRAY_SIZE(patterns))
507ee30cf14SThomas Huth 				report_abort("Error: bad value for -p");
508ee30cf14SThomas Huth 			pat ^= patterns[*argv[i] - '0'];
509ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-t")) {
510ee30cf14SThomas Huth 			/* Randomize with timebase register */
511ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
512ee30cf14SThomas Huth 			pat ^= i;
513ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
514ee30cf14SThomas Huth 			pat ^= ~(uint64_t)i << 32;
515ee30cf14SThomas Huth 		} else {
516ee30cf14SThomas Huth 			report_abort("Warning: Unsupported argument: %s",
517ee30cf14SThomas Huth 			             argv[i]);
518ee30cf14SThomas Huth 		}
519ee30cf14SThomas Huth 	}
520ee30cf14SThomas Huth 
521*8f6290f0SNicholas Piggin 	setup_sprs();
522*8f6290f0SNicholas Piggin 
523*8f6290f0SNicholas Piggin 	printf("Setting SPRs to 0x%lx...\n", pat);
524ee30cf14SThomas Huth 	set_sprs(pat);
525ee30cf14SThomas Huth 
526ee30cf14SThomas Huth 	memset(before, 0, sizeof(before));
527ee30cf14SThomas Huth 	memset(after, 0, sizeof(after));
528ee30cf14SThomas Huth 
529ee30cf14SThomas Huth 	get_sprs(before);
530ee30cf14SThomas Huth 
531ee30cf14SThomas Huth 	if (pause) {
53277a59d17SNico Boehr 		migrate_once();
533*8f6290f0SNicholas Piggin 		/* Reload regs changed by getchar/putchar hcalls */
534*8f6290f0SNicholas Piggin 		before[SPR_SRR0] = mfspr(SPR_SRR0);
535*8f6290f0SNicholas Piggin 		before[SPR_SRR1] = mfspr(SPR_SRR1);
536*8f6290f0SNicholas Piggin 
537*8f6290f0SNicholas Piggin 		/* WORT seems to go to 0 after KVM switch, perhaps CPU idle */
538*8f6290f0SNicholas Piggin 		if (sprs[895].name)
539*8f6290f0SNicholas Piggin 			before[895] = mfspr(895);
540ee30cf14SThomas Huth 	} else {
541ba33a96fSNicholas Piggin 		msleep(2000);
542*8f6290f0SNicholas Piggin 
543*8f6290f0SNicholas Piggin 		/* Reload regs changed by dec interrupt */
544*8f6290f0SNicholas Piggin 		before[SPR_SRR0] = mfspr(SPR_SRR0);
545*8f6290f0SNicholas Piggin 		before[SPR_SRR1] = mfspr(SPR_SRR1);
546*8f6290f0SNicholas Piggin 		before[SPR_SPRG1] = mfspr(SPR_SPRG1);
547*8f6290f0SNicholas Piggin 
548*8f6290f0SNicholas Piggin 		/* WORT seems to go to 0 after KVM switch, perhaps CPU idle */
549*8f6290f0SNicholas Piggin 		if (sprs[895].name)
550*8f6290f0SNicholas Piggin 			before[895] = mfspr(895);
551ee30cf14SThomas Huth 	}
552ee30cf14SThomas Huth 
553ee30cf14SThomas Huth 	get_sprs(after);
554ee30cf14SThomas Huth 
555ee30cf14SThomas Huth 	puts("Checking SPRs...\n");
556ee30cf14SThomas Huth 	for (i = 0; i < 1024; i++) {
557*8f6290f0SNicholas Piggin 		bool pass = true;
558*8f6290f0SNicholas Piggin 
559*8f6290f0SNicholas Piggin 		if (!(sprs[i].access & SPR_OS_READ))
560*8f6290f0SNicholas Piggin 			continue;
561*8f6290f0SNicholas Piggin 
562*8f6290f0SNicholas Piggin 		if (sprs[i].width == 32) {
563*8f6290f0SNicholas Piggin 			if (before[i] >> 32)
564*8f6290f0SNicholas Piggin 				pass = false;
565*8f6290f0SNicholas Piggin 		}
566*8f6290f0SNicholas Piggin 		if (!(sprs[i].type & (SPR_HARNESS|SPR_ASYNC)) && (before[i] != after[i]))
567*8f6290f0SNicholas Piggin 			pass = false;
568*8f6290f0SNicholas Piggin 
569*8f6290f0SNicholas Piggin 		if (sprs[i].width == 32 && !(before[i] >> 32) && !(after[i] >> 32)) {
570*8f6290f0SNicholas Piggin 			/* known failure KVM migration of CTRL */
571*8f6290f0SNicholas Piggin 			report_kfail(true && i == 136,
572*8f6290f0SNicholas Piggin 				"%-10s(%4d):\t        0x%08lx <==>         0x%08lx",
573*8f6290f0SNicholas Piggin 				sprs[i].name, i,
574*8f6290f0SNicholas Piggin 				before[i], after[i]);
575*8f6290f0SNicholas Piggin 		} else {
576*8f6290f0SNicholas Piggin 			report(pass, "%-10s(%4d):\t0x%016lx <==> 0x%016lx",
577*8f6290f0SNicholas Piggin 				sprs[i].name, i,
578*8f6290f0SNicholas Piggin 				before[i], after[i]);
579*8f6290f0SNicholas Piggin 		}
580ee30cf14SThomas Huth 	}
581ee30cf14SThomas Huth 
582ee30cf14SThomas Huth 	return report_summary();
583ee30cf14SThomas Huth }
584