xref: /kvm-unit-tests/powerpc/sprs.c (revision 851ef5165069857e56e35b01c8ed43b115c2737e)
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 
338f6290f0SNicholas Piggin /* "Indirect" mfspr/mtspr which accept a non-constant spr number */
__mfspr(unsigned spr)348f6290f0SNicholas Piggin static uint64_t __mfspr(unsigned spr)
35ee30cf14SThomas Huth {
368f6290f0SNicholas Piggin 	uint64_t tmp;
378f6290f0SNicholas Piggin 	uint64_t ret;
388f6290f0SNicholas Piggin 
398f6290f0SNicholas Piggin 	asm volatile(
408f6290f0SNicholas Piggin "	bcl	20, 31, 1f		\n"
418f6290f0SNicholas Piggin "1:	mflr	%0			\n"
428f6290f0SNicholas Piggin "	addi	%0, %0, (2f-1b)		\n"
438f6290f0SNicholas Piggin "	add	%0, %0, %2		\n"
448f6290f0SNicholas Piggin "	mtctr	%0			\n"
458f6290f0SNicholas Piggin "	bctr				\n"
468f6290f0SNicholas Piggin "2:					\n"
478f6290f0SNicholas Piggin ".LSPR=0				\n"
488f6290f0SNicholas Piggin ".rept 1024				\n"
498f6290f0SNicholas Piggin "	mfspr	%1, .LSPR		\n"
508f6290f0SNicholas Piggin "	b	3f			\n"
518f6290f0SNicholas Piggin "	.LSPR=.LSPR+1			\n"
528f6290f0SNicholas Piggin ".endr					\n"
538f6290f0SNicholas Piggin "3:					\n"
548f6290f0SNicholas Piggin 	: "=&r"(tmp),
558f6290f0SNicholas Piggin 	  "=r"(ret)
568f6290f0SNicholas Piggin 	: "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
578f6290f0SNicholas Piggin 	: "lr", "ctr");
588f6290f0SNicholas Piggin 
598f6290f0SNicholas Piggin 	return ret;
60ee30cf14SThomas Huth }
61ee30cf14SThomas Huth 
__mtspr(unsigned spr,uint64_t val)628f6290f0SNicholas Piggin static void __mtspr(unsigned spr, uint64_t val)
638f6290f0SNicholas Piggin {
648f6290f0SNicholas Piggin 	uint64_t tmp;
658f6290f0SNicholas Piggin 
668f6290f0SNicholas Piggin 	asm volatile(
678f6290f0SNicholas Piggin "	bcl	20, 31, 1f		\n"
688f6290f0SNicholas Piggin "1:	mflr	%0			\n"
698f6290f0SNicholas Piggin "	addi	%0, %0, (2f-1b)		\n"
708f6290f0SNicholas Piggin "	add	%0, %0, %2		\n"
718f6290f0SNicholas Piggin "	mtctr	%0			\n"
728f6290f0SNicholas Piggin "	bctr				\n"
738f6290f0SNicholas Piggin "2:					\n"
748f6290f0SNicholas Piggin ".LSPR=0				\n"
758f6290f0SNicholas Piggin ".rept 1024				\n"
768f6290f0SNicholas Piggin "	mtspr	.LSPR, %1		\n"
778f6290f0SNicholas Piggin "	b	3f			\n"
788f6290f0SNicholas Piggin "	.LSPR=.LSPR+1			\n"
798f6290f0SNicholas Piggin ".endr					\n"
808f6290f0SNicholas Piggin "3:					\n"
818f6290f0SNicholas Piggin 	: "=&r"(tmp)
828f6290f0SNicholas Piggin 	: "r"(val),
838f6290f0SNicholas Piggin 	  "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
848f6290f0SNicholas Piggin 	: "lr", "ctr", "xer");
858f6290f0SNicholas Piggin }
868f6290f0SNicholas Piggin 
878f6290f0SNicholas Piggin static uint64_t before[1024], after[1024];
888f6290f0SNicholas Piggin 
898f6290f0SNicholas Piggin #define SPR_PR_READ	0x0001
908f6290f0SNicholas Piggin #define SPR_PR_WRITE	0x0002
918f6290f0SNicholas Piggin #define SPR_OS_READ	0x0010
928f6290f0SNicholas Piggin #define SPR_OS_WRITE	0x0020
938f6290f0SNicholas Piggin #define SPR_HV_READ	0x0100
948f6290f0SNicholas Piggin #define SPR_HV_WRITE	0x0200
958f6290f0SNicholas Piggin 
968f6290f0SNicholas Piggin #define RW		0x333
978f6290f0SNicholas Piggin #define RO		0x111
988f6290f0SNicholas Piggin #define WO		0x222
998f6290f0SNicholas Piggin #define OS_RW		0x330
1008f6290f0SNicholas Piggin #define OS_RO		0x110
1018f6290f0SNicholas Piggin #define OS_WO		0x220
1028f6290f0SNicholas Piggin #define HV_RW		0x300
1038f6290f0SNicholas Piggin #define HV_RO		0x100
1048f6290f0SNicholas Piggin #define HV_WO		0x200
1058f6290f0SNicholas Piggin 
1068f6290f0SNicholas Piggin #define SPR_ASYNC	0x1000	/* May be updated asynchronously */
1078f6290f0SNicholas Piggin #define SPR_INT		0x2000	/* May be updated by synchronous interrupt */
1088f6290f0SNicholas Piggin #define SPR_HARNESS	0x4000	/* Test harness uses the register */
1098f6290f0SNicholas Piggin 
1108f6290f0SNicholas Piggin struct spr {
1118f6290f0SNicholas Piggin 	const char	*name;
1128f6290f0SNicholas Piggin 	uint8_t		width;
1138f6290f0SNicholas Piggin 	uint16_t	access;
1148f6290f0SNicholas Piggin 	uint16_t	type;
1158f6290f0SNicholas Piggin };
1168f6290f0SNicholas Piggin 
1178f6290f0SNicholas Piggin /* SPRs common denominator back to PowerPC Operating Environment Architecture */
1188f6290f0SNicholas Piggin static const struct spr sprs_common[1024] = {
1198f6290f0SNicholas Piggin   [1] = { "XER",	64,	RW,		SPR_HARNESS, }, /* Used by compiler */
1208f6290f0SNicholas Piggin   [8] = { "LR", 	64,	RW,		SPR_HARNESS, }, /* Compiler, mfspr/mtspr */
1218f6290f0SNicholas Piggin   [9] = { "CTR",	64,	RW,		SPR_HARNESS, }, /* Compiler, mfspr/mtspr */
1228f6290f0SNicholas Piggin  [18] = { "DSISR",	32,	OS_RW,		SPR_INT, },
1238f6290f0SNicholas Piggin  [19] = { "DAR",	64,	OS_RW,		SPR_INT, },
1248f6290f0SNicholas Piggin  [26] = { "SRR0",	64,	OS_RW,		SPR_INT, },
1258f6290f0SNicholas Piggin  [27] = { "SRR1",	64,	OS_RW,		SPR_INT, },
1268f6290f0SNicholas Piggin [268] = { "TB",		64,	RO	,	SPR_ASYNC, },
1278f6290f0SNicholas Piggin [269] = { "TBU",	32,	RO,		SPR_ASYNC, },
1288f6290f0SNicholas Piggin [272] = { "SPRG0",	64,	OS_RW,		SPR_HARNESS, }, /* Interrupt stacr */
1298f6290f0SNicholas Piggin [273] = { "SPRG1",	64,	OS_RW,		SPR_HARNESS, }, /* Interrupt Scratch */
1308f6290f0SNicholas Piggin [274] = { "SPRG2",	64,	OS_RW, },
1318f6290f0SNicholas Piggin [275] = { "SPRG3",	64,	OS_RW, },
1328f6290f0SNicholas Piggin [287] = { "PVR",	32,	OS_RO, },
1338f6290f0SNicholas Piggin };
1348f6290f0SNicholas Piggin 
135ee30cf14SThomas Huth /* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */
1368f6290f0SNicholas Piggin static const struct spr sprs_201[1024] = {
1378f6290f0SNicholas Piggin  [22] = { "DEC",	32,	OS_RW,		SPR_ASYNC, },
1388f6290f0SNicholas Piggin  [25] = { "SDR1",	64,	HV_RW | OS_RO, },
1398f6290f0SNicholas Piggin  [29] = { "ACCR",	64,	OS_RW, },
1408f6290f0SNicholas Piggin [136] = { "CTRL",	32,	RO, },
1418f6290f0SNicholas Piggin [152] = { "CTRL",	32,	OS_WO, },
1428f6290f0SNicholas Piggin [259] = { "SPRG3",	64,	RO, },
1438f6290f0SNicholas Piggin /* ASR, EAR omitted */
1448f6290f0SNicholas Piggin [284] = { "TBL",	32,	HV_WO, },
1458f6290f0SNicholas Piggin [285] = { "TBU",	32,	HV_WO, },
1468f6290f0SNicholas Piggin [310] = { "HDEC",	32,	HV_RW,		SPR_ASYNC, },
1478f6290f0SNicholas Piggin [1013]= { "DABR",	64,	HV_RW | OS_RO, },
1488f6290f0SNicholas Piggin [1023]= { "PIR",	32,	OS_RO,		SPR_ASYNC, }, /* Can't be virtualised, appears to be async */
1498f6290f0SNicholas Piggin };
1508f6290f0SNicholas Piggin 
1518f6290f0SNicholas Piggin static const struct spr sprs_970_pmu[1024] = {
1528f6290f0SNicholas Piggin /* POWER4+ PMU, should confirm with PPC970 */
1538f6290f0SNicholas Piggin [770] = { "MMCRA",	64,	RO, },
1548f6290f0SNicholas Piggin [771] = { "PMC1",	32,	RO, },
1558f6290f0SNicholas Piggin [772] = { "PMC2",	32,	RO, },
1568f6290f0SNicholas Piggin [773] = { "PMC3",	32,	RO, },
1578f6290f0SNicholas Piggin [774] = { "PMC4",	32,	RO, },
1588f6290f0SNicholas Piggin [775] = { "PMC5",	32,	RO, },
1598f6290f0SNicholas Piggin [776] = { "PMC6",	32,	RO, },
1608f6290f0SNicholas Piggin [777] = { "PMC7",	32,	RO, },
1618f6290f0SNicholas Piggin [778] = { "PMC8",	32,	RO, },
1628f6290f0SNicholas Piggin [779] = { "MMCR0",	64,	RO, },
1638f6290f0SNicholas Piggin [780] = { "SIAR",	64,	RO, },
1648f6290f0SNicholas Piggin [781] = { "SDAR",	64,	RO, },
1658f6290f0SNicholas Piggin [782] = { "MMCR1",	64,	RO, },
1668f6290f0SNicholas Piggin [786] = { "MMCRA",	64,	OS_RW, },
1678f6290f0SNicholas Piggin [787] = { "PMC1",	32,	OS_RW, },
1688f6290f0SNicholas Piggin [788] = { "PMC2",	32,	OS_RW, },
1698f6290f0SNicholas Piggin [789] = { "PMC3",	32,	OS_RW, },
1708f6290f0SNicholas Piggin [790] = { "PMC4",	32,	OS_RW, },
1718f6290f0SNicholas Piggin [791] = { "PMC5",	32,	OS_RW, },
1728f6290f0SNicholas Piggin [792] = { "PMC6",	32,	OS_RW, },
1738f6290f0SNicholas Piggin [793] = { "PMC7",	32,	OS_RW, },
1748f6290f0SNicholas Piggin [794] = { "PMC8",	32,	OS_RW, },
1758f6290f0SNicholas Piggin [795] = { "MMCR0",	64,	OS_RW, },
1768f6290f0SNicholas Piggin [796] = { "SIAR",	64,	OS_RW, },
1778f6290f0SNicholas Piggin [797] = { "SDAR",	64,	OS_RW, },
1788f6290f0SNicholas Piggin [798] = { "MMCR1",	64,	OS_RW, },
1798f6290f0SNicholas Piggin };
1808f6290f0SNicholas Piggin 
1818f6290f0SNicholas Piggin /* These are common SPRs from 2.07S onward (POWER CPUs that support KVM HV) */
1828f6290f0SNicholas Piggin static const struct spr sprs_power_common[1024] = {
1838f6290f0SNicholas Piggin   [3] = { "DSCR",	64,	RW, },
1848f6290f0SNicholas Piggin  [13] = { "AMR",	64,	RW, },
1858f6290f0SNicholas Piggin  [17] = { "DSCR",	64,	OS_RW, },
1868f6290f0SNicholas Piggin  [28] = { "CFAR",	64,	OS_RW,		SPR_ASYNC, }, /* Effectively async */
1878f6290f0SNicholas Piggin  [29] = { "AMR",	64,	OS_RW, },
1888f6290f0SNicholas Piggin  [61] = { "IAMR",	64,	OS_RW, },
1898f6290f0SNicholas Piggin [136] = { "CTRL",	32,	RO, },
1908f6290f0SNicholas Piggin [152] = { "CTRL",	32,	OS_WO, },
1918f6290f0SNicholas Piggin [153] = { "FSCR",	64,	OS_RW, },
1928f6290f0SNicholas Piggin [157] = { "UAMOR",	64,	OS_RW, },
1938f6290f0SNicholas Piggin [159] = { "PSPB",	32,	OS_RW, },
1948f6290f0SNicholas Piggin [176] = { "DPDES",	64,	HV_RW | OS_RO, },
1958f6290f0SNicholas Piggin [180] = { "DAWR0",	64,	HV_RW, },
1968f6290f0SNicholas Piggin [186] = { "RPR",	64,	HV_RW, },
1978f6290f0SNicholas Piggin [187] = { "CIABR",	64,	HV_RW, },
1988f6290f0SNicholas Piggin [188] = { "DAWRX0",	32,	HV_RW, },
1998f6290f0SNicholas Piggin [190] = { "HFSCR",	64,	HV_RW, },
2008f6290f0SNicholas Piggin [256] = { "VRSAVE",	32,	RW, },
2018f6290f0SNicholas Piggin [259] = { "SPRG3",	64,	RO, },
202584c6ad4SNicholas Piggin [284] = { "TBL",	32,	HV_WO, }, /* Things can go a bit wonky with */
203584c6ad4SNicholas Piggin [285] = { "TBU",	32,	HV_WO, }, /* Timebase changing. Should save */
204584c6ad4SNicholas Piggin [286] = { "TBU40",	64,	HV_WO, }, /* and restore it. */
2058f6290f0SNicholas Piggin [304] = { "HSPRG0",	64,	HV_RW, },
2068f6290f0SNicholas Piggin [305] = { "HSPRG1",	64,	HV_RW, },
2078f6290f0SNicholas Piggin [306] = { "HDSISR",	32,	HV_RW,		SPR_INT, },
2088f6290f0SNicholas Piggin [307] = { "HDAR",	64,	HV_RW,		SPR_INT, },
2098f6290f0SNicholas Piggin [308] = { "SPURR",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
2108f6290f0SNicholas Piggin [309] = { "PURR",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
211584c6ad4SNicholas Piggin [313] = { "HRMOR",	64,	HV_RW,		SPR_HARNESS, }, /* Harness can't cope with HRMOR changing */
2128f6290f0SNicholas Piggin [314] = { "HSRR0",	64,	HV_RW,		SPR_INT, },
2138f6290f0SNicholas Piggin [315] = { "HSRR1",	64,	HV_RW,		SPR_INT, },
2148f6290f0SNicholas Piggin [318] = { "LPCR",	64,	HV_RW, },
2158f6290f0SNicholas Piggin [319] = { "LPIDR",	32,	HV_RW, },
2168f6290f0SNicholas Piggin [336] = { "HMER",	64,	HV_RW, },
2178f6290f0SNicholas Piggin [337] = { "HMEER",	64,	HV_RW, },
2188f6290f0SNicholas Piggin [338] = { "PCR",	64,	HV_RW, },
2198f6290f0SNicholas Piggin [349] = { "AMOR",	64,	HV_RW, },
2208f6290f0SNicholas Piggin [446] = { "TIR",	64,	OS_RO, },
2218f6290f0SNicholas Piggin [800] = { "BESCRS",	64,	RW, },
2228f6290f0SNicholas Piggin [801] = { "BESCRSU",	32,	RW, },
2238f6290f0SNicholas Piggin [802] = { "BESCRR",	64,	RW, },
2248f6290f0SNicholas Piggin [803] = { "BESCRRU",	32,	RW, },
2258f6290f0SNicholas Piggin [804] = { "EBBHR",	64,	RW, },
2268f6290f0SNicholas Piggin [805] = { "EBBRR",	64,	RW, },
2278f6290f0SNicholas Piggin [806] = { "BESCR",	64,	RW, },
2288f6290f0SNicholas Piggin [815] = { "TAR",	64,	RW, },
2298f6290f0SNicholas Piggin [848] = { "IC",		64,	HV_RW | OS_RO,	SPR_ASYNC, },
2308f6290f0SNicholas Piggin [849] = { "VTB",	64,	HV_RW | OS_RO,	SPR_ASYNC, },
231cc2ece41SNicholas Piggin [896] = { "PPR",	64,	RW,		SPR_ASYNC, }, /* PPR(32) is changed by cpu_relax(), appears to be async */
232cc2ece41SNicholas Piggin [898] = { "PPR32",	32,	RW,		SPR_ASYNC, },
2338f6290f0SNicholas Piggin [1023]= { "PIR",	32,	OS_RO,		SPR_ASYNC, }, /* Can't be virtualised, appears to be async */
2348f6290f0SNicholas Piggin };
2358f6290f0SNicholas Piggin 
2368f6290f0SNicholas Piggin static const struct spr sprs_tm[1024] = {
2378f6290f0SNicholas Piggin #if 0
2388f6290f0SNicholas Piggin 	/* XXX: leave these out until enabling TM facility (and more testing) */
2398f6290f0SNicholas Piggin [128] = { "TFHAR",	64,	RW, },
2408f6290f0SNicholas Piggin [129] = { "TFIAR",	64,	RW, },
2418f6290f0SNicholas Piggin [130] = { "TEXASR",	64,	RW, },
2428f6290f0SNicholas Piggin [131] = { "TEXASRU",	32,	RW, },
2438f6290f0SNicholas Piggin #endif
2448f6290f0SNicholas Piggin };
245ee30cf14SThomas Huth 
246ee30cf14SThomas Huth /* SPRs from PowerISA 2.07 Book III-S */
2478f6290f0SNicholas Piggin static const struct spr sprs_207[1024] = {
2488f6290f0SNicholas Piggin  [22] = { "DEC",	32,	OS_RW,		SPR_ASYNC, },
2498f6290f0SNicholas Piggin  [25] = { "SDR1",	64,	HV_RW, },
2508f6290f0SNicholas Piggin [177] = { "DHDES",	64,	HV_RW, },
2518f6290f0SNicholas Piggin [283] = { "CIR",	32,	OS_RO, },
2528f6290f0SNicholas Piggin [310] = { "HDEC",	32,	HV_RW,		SPR_ASYNC, },
2538f6290f0SNicholas Piggin [312] = { "RMOR",	64,	HV_RW, },
2548f6290f0SNicholas Piggin [339] = { "HEIR",	32,	HV_RW,		SPR_INT, },
2558f6290f0SNicholas Piggin };
256ee30cf14SThomas Huth 
25725a302cbSThomas Huth /* SPRs from PowerISA 3.00 Book III */
2588f6290f0SNicholas Piggin static const struct spr sprs_300[1024] = {
2598f6290f0SNicholas Piggin  [22] = { "DEC",	64,	OS_RW,		SPR_ASYNC, },
2608f6290f0SNicholas Piggin  [48] = { "PIDR",	32,	OS_RW, },
2618f6290f0SNicholas Piggin [144] = { "TIDR",	64,	OS_RW, },
2628f6290f0SNicholas Piggin [283] = { "CIR",	32,	OS_RO, },
2638f6290f0SNicholas Piggin [310] = { "HDEC",	64,	HV_RW,		SPR_ASYNC, },
2648f6290f0SNicholas Piggin [339] = { "HEIR",	32,	HV_RW,		SPR_INT, },
2658f6290f0SNicholas Piggin [464] = { "PTCR",	64,	HV_RW, },
2668f6290f0SNicholas Piggin [816] = { "ASDR",	64,	HV_RW,		SPR_INT, },
2678f6290f0SNicholas Piggin [823] = { "PSSCR",	64,	OS_RW, },
2688f6290f0SNicholas Piggin [855] = { "PSSCR",	64,	HV_RW, },
2698f6290f0SNicholas Piggin };
27025a302cbSThomas Huth 
2718f6290f0SNicholas Piggin /* SPRs from PowerISA 3.1B Book III */
2728f6290f0SNicholas Piggin static const struct spr sprs_31[1024] = {
2738f6290f0SNicholas Piggin  [22] = { "DEC",	64,	OS_RW,		SPR_ASYNC, },
2748f6290f0SNicholas Piggin  [48] = { "PIDR",	32,	OS_RW, },
2758f6290f0SNicholas Piggin [181] = { "DAWR1",	64,	HV_RW, },
2768f6290f0SNicholas Piggin [189] = { "DAWRX1",	32,	HV_RW, },
2778f6290f0SNicholas Piggin [310] = { "HDEC",	64,	HV_RW,		SPR_ASYNC, },
2788f6290f0SNicholas Piggin [339] = { "HEIR",	64,	HV_RW,		SPR_INT, },
2798f6290f0SNicholas Piggin [455] = { "HDEXCR",	32,	RO, },
2808f6290f0SNicholas Piggin [464] = { "PTCR",	64,	HV_RW, },
2818f6290f0SNicholas Piggin [468] = { "HASHKEYR",	64,	OS_RW, },
2828f6290f0SNicholas Piggin [469] = { "HASHPKEYR",	64,	HV_RW, },
2838f6290f0SNicholas Piggin [471] = { "HDEXCR",	64,	HV_RW, },
2848f6290f0SNicholas Piggin [812] = { "DEXCR",	32,	RO, },
2858f6290f0SNicholas Piggin [816] = { "ASDR",	64,	HV_RW,		SPR_INT, },
2868f6290f0SNicholas Piggin [823] = { "PSSCR",	64,	OS_RW, },
2878f6290f0SNicholas Piggin [828] = { "DEXCR",	64,	OS_RW, },
2888f6290f0SNicholas Piggin [855] = { "PSSCR",	64,	HV_RW, },
2898f6290f0SNicholas Piggin };
290faaddcb0SNicholas Piggin 
2918f6290f0SNicholas Piggin /* SPRs POWER9, POWER10 User Manual */
2928f6290f0SNicholas Piggin static const struct spr sprs_power9_10[1024] = {
2938f6290f0SNicholas Piggin [276] = { "SPRC",	64,	HV_RW, },
2948f6290f0SNicholas Piggin [277] = { "SPRD",	64,	HV_RW, },
2958f6290f0SNicholas Piggin [317] = { "TFMR",	64,	HV_RW, },
2968f6290f0SNicholas Piggin [799] = { "IMC",	64,	HV_RW, },
2978f6290f0SNicholas Piggin [850] = { "LDBAR",	64,	HV_RO, },
2988f6290f0SNicholas Piggin [851] = { "MMCRC",	32,	HV_RW, },
2998f6290f0SNicholas Piggin [853] = { "PMSR",	32,	HV_RO, },
3008f6290f0SNicholas Piggin [861] = { "L2QOSR",	64,	HV_WO, },
3018f6290f0SNicholas Piggin [881] = { "TRIG1",	64,	OS_WO, },
3028f6290f0SNicholas Piggin [882] = { "TRIG2",	64,	OS_WO, },
3038f6290f0SNicholas Piggin [884] = { "PMCR",	64,	HV_RW, },
3048f6290f0SNicholas Piggin [885] = { "RWMR",	64,	HV_RW, },
3058f6290f0SNicholas Piggin [895] = { "WORT",	64,	OS_RW, }, /* UM says 18-bits! */
3068f6290f0SNicholas Piggin [921] = { "TSCR",	32,	HV_RW, },
3078f6290f0SNicholas Piggin [922] = { "TTR",	64,	HV_RW, },
3088f6290f0SNicholas Piggin [1006]= { "TRACE",	64,	WO, },
309584c6ad4SNicholas Piggin [1008]= { "HID",	64,	HV_RW,		SPR_HARNESS, }, /* HILE would be unhelpful to change */
3108f6290f0SNicholas Piggin };
3118f6290f0SNicholas Piggin 
3128f6290f0SNicholas Piggin /* This covers POWER8 and POWER9 PMUs */
3138f6290f0SNicholas Piggin static const struct spr sprs_power_common_pmu[1024] = {
3148f6290f0SNicholas Piggin [768] = { "SIER",	64,	RO, },
3158f6290f0SNicholas Piggin [769] = { "MMCR2",	64,	RW, },
3168f6290f0SNicholas Piggin [770] = { "MMCRA",	64,	RW, },
3178f6290f0SNicholas Piggin [771] = { "PMC1",	32,	RW, },
3188f6290f0SNicholas Piggin [772] = { "PMC2",	32,	RW, },
3198f6290f0SNicholas Piggin [773] = { "PMC3",	32,	RW, },
3208f6290f0SNicholas Piggin [774] = { "PMC4",	32,	RW, },
3218f6290f0SNicholas Piggin [775] = { "PMC5",	32,	RW, },
3228f6290f0SNicholas Piggin [776] = { "PMC6",	32,	RW, },
3238f6290f0SNicholas Piggin [779] = { "MMCR0",	64,	RW, },
3248f6290f0SNicholas Piggin [780] = { "SIAR",	64,	RO, },
3258f6290f0SNicholas Piggin [781] = { "SDAR",	64,	RO, },
3268f6290f0SNicholas Piggin [782] = { "MMCR1",	64,	RO, },
3278f6290f0SNicholas Piggin [784] = { "SIER",	64,	OS_RW, },
3288f6290f0SNicholas Piggin [785] = { "MMCR2",	64,	OS_RW, },
3298f6290f0SNicholas Piggin [786] = { "MMCRA",	64,	OS_RW, },
3308f6290f0SNicholas Piggin [787] = { "PMC1",	32,	OS_RW, },
3318f6290f0SNicholas Piggin [788] = { "PMC2",	32,	OS_RW, },
3328f6290f0SNicholas Piggin [789] = { "PMC3",	32,	OS_RW, },
3338f6290f0SNicholas Piggin [790] = { "PMC4",	32,	OS_RW, },
3348f6290f0SNicholas Piggin [791] = { "PMC5",	32,	OS_RW, },
3358f6290f0SNicholas Piggin [792] = { "PMC6",	32,	OS_RW, },
3368f6290f0SNicholas Piggin [795] = { "MMCR0",	64,	OS_RW, },
3378f6290f0SNicholas Piggin [796] = { "SIAR",	64,	OS_RW, },
3388f6290f0SNicholas Piggin [797] = { "SDAR",	64,	OS_RW, },
3398f6290f0SNicholas Piggin [798] = { "MMCR1",	64,	OS_RW, },
3408f6290f0SNicholas Piggin };
3418f6290f0SNicholas Piggin 
3428f6290f0SNicholas Piggin static const struct spr sprs_power10_pmu[1024] = {
3438f6290f0SNicholas Piggin [736] = { "SIER2",	64,	RO, },
3448f6290f0SNicholas Piggin [737] = { "SIER3",	64,	RO, },
3458f6290f0SNicholas Piggin [738] = { "MMCR3",	64,	RO, },
3468f6290f0SNicholas Piggin [752] = { "SIER2",	64,	OS_RW, },
3478f6290f0SNicholas Piggin [753] = { "SIER3",	64,	OS_RW, },
3488f6290f0SNicholas Piggin [754] = { "MMCR3",	64,	OS_RW, },
3498f6290f0SNicholas Piggin };
3508f6290f0SNicholas Piggin 
3518f6290f0SNicholas Piggin static struct spr sprs[1024];
3528f6290f0SNicholas Piggin 
spr_read_perms(int spr)353584c6ad4SNicholas Piggin static bool spr_read_perms(int spr)
354584c6ad4SNicholas Piggin {
355584c6ad4SNicholas Piggin 	if (cpu_has_hv)
356584c6ad4SNicholas Piggin 		return !!(sprs[spr].access & SPR_HV_READ);
357584c6ad4SNicholas Piggin 	else
358584c6ad4SNicholas Piggin 		return !!(sprs[spr].access & SPR_OS_READ);
359584c6ad4SNicholas Piggin }
360584c6ad4SNicholas Piggin 
spr_write_perms(int spr)361584c6ad4SNicholas Piggin static bool spr_write_perms(int spr)
362584c6ad4SNicholas Piggin {
363584c6ad4SNicholas Piggin 	if (cpu_has_hv)
364584c6ad4SNicholas Piggin 		return !!(sprs[spr].access & SPR_HV_WRITE);
365584c6ad4SNicholas Piggin 	else
366584c6ad4SNicholas Piggin 		return !!(sprs[spr].access & SPR_OS_WRITE);
367584c6ad4SNicholas Piggin }
368584c6ad4SNicholas Piggin 
setup_sprs(void)3698f6290f0SNicholas Piggin static void setup_sprs(void)
370ee30cf14SThomas Huth {
3718f6290f0SNicholas Piggin 	int i;
3728f6290f0SNicholas Piggin 
3738f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
3748f6290f0SNicholas Piggin 		if (sprs_common[i].name) {
3758f6290f0SNicholas Piggin 			memcpy(&sprs[i], &sprs_common[i], sizeof(struct spr));
3768f6290f0SNicholas Piggin 		}
3778f6290f0SNicholas Piggin 	}
378ee30cf14SThomas Huth 
3799c5e1913SNicholas Piggin 	switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
3809c5e1913SNicholas Piggin 	case PVR_VER_970:
3819c5e1913SNicholas Piggin 	case PVR_VER_970FX:
3829c5e1913SNicholas Piggin 	case PVR_VER_970MP:
3838f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
3848f6290f0SNicholas Piggin 			if (sprs_201[i].name) {
3858f6290f0SNicholas Piggin 				assert(!sprs[i].name);
3868f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_201[i], sizeof(struct spr));
3878f6290f0SNicholas Piggin 			}
3888f6290f0SNicholas Piggin 			if (sprs_970_pmu[i].name) {
3898f6290f0SNicholas Piggin 				assert(!sprs[i].name);
3908f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
3918f6290f0SNicholas Piggin 			}
3928f6290f0SNicholas Piggin 		}
393ee30cf14SThomas Huth 		break;
3948f6290f0SNicholas Piggin 
3959c5e1913SNicholas Piggin 	case PVR_VER_POWER8E:
3969c5e1913SNicholas Piggin 	case PVR_VER_POWER8NVL:
3979c5e1913SNicholas Piggin 	case PVR_VER_POWER8:
3988f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
3998f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
4008f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4018f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
4028f6290f0SNicholas Piggin 			}
4038f6290f0SNicholas Piggin 			if (sprs_207[i].name) {
4048f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4058f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_207[i], sizeof(struct spr));
4068f6290f0SNicholas Piggin 			}
4078f6290f0SNicholas Piggin 			if (sprs_tm[i].name) {
4088f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4098f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_tm[i], sizeof(struct spr));
4108f6290f0SNicholas Piggin 			}
4118f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
4128f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4138f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
4148f6290f0SNicholas Piggin 			}
4158f6290f0SNicholas Piggin 		}
416ee30cf14SThomas Huth 		break;
4178f6290f0SNicholas Piggin 
4189c5e1913SNicholas Piggin 	case PVR_VER_POWER9:
4198f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
4208f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
4218f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4228f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
4238f6290f0SNicholas Piggin 			}
4248f6290f0SNicholas Piggin 			if (sprs_300[i].name) {
4258f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4268f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_300[i], sizeof(struct spr));
4278f6290f0SNicholas Piggin 			}
4288f6290f0SNicholas Piggin 			if (sprs_tm[i].name) {
4298f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4308f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_tm[i], sizeof(struct spr));
4318f6290f0SNicholas Piggin 			}
4328f6290f0SNicholas Piggin 			if (sprs_power9_10[i].name) {
4338f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4348f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power9_10[i], sizeof(struct spr));
4358f6290f0SNicholas Piggin 			}
4368f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
4378f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4388f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
4398f6290f0SNicholas Piggin 			}
4408f6290f0SNicholas Piggin 		}
44125a302cbSThomas Huth 		break;
4428f6290f0SNicholas Piggin 
4439c5e1913SNicholas Piggin 	case PVR_VER_POWER10:
4448f6290f0SNicholas Piggin 		for (i = 0; i < 1024; i++) {
4458f6290f0SNicholas Piggin 			if (sprs_power_common[i].name) {
4468f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4478f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common[i], sizeof(struct spr));
4488f6290f0SNicholas Piggin 			}
4498f6290f0SNicholas Piggin 			if (sprs_31[i].name) {
4508f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4518f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_31[i], sizeof(struct spr));
4528f6290f0SNicholas Piggin 			}
4538f6290f0SNicholas Piggin 			if (sprs_power9_10[i].name) {
4548f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4558f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power9_10[i], sizeof(struct spr));
4568f6290f0SNicholas Piggin 			}
4578f6290f0SNicholas Piggin 			if (sprs_power_common_pmu[i].name) {
4588f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4598f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power_common_pmu[i], sizeof(struct spr));
4608f6290f0SNicholas Piggin 			}
4618f6290f0SNicholas Piggin 			if (sprs_power10_pmu[i].name) {
4628f6290f0SNicholas Piggin 				assert(!sprs[i].name);
4638f6290f0SNicholas Piggin 				memcpy(&sprs[i], &sprs_power10_pmu[i], sizeof(struct spr));
4648f6290f0SNicholas Piggin 			}
4658f6290f0SNicholas Piggin 		}
466faaddcb0SNicholas Piggin 		break;
4678f6290f0SNicholas Piggin 
468ee30cf14SThomas Huth 	default:
4698f6290f0SNicholas Piggin 		memcpy(sprs, sprs_common, sizeof(sprs));
4708f6290f0SNicholas Piggin 		puts("Warning: Unknown processor version, falling back to common SPRs!\n");
4718f6290f0SNicholas Piggin 		break;
472ee30cf14SThomas Huth 	}
473ee30cf14SThomas Huth }
474ee30cf14SThomas Huth 
get_sprs(uint64_t * v)475ee30cf14SThomas Huth static void get_sprs(uint64_t *v)
476ee30cf14SThomas Huth {
4778f6290f0SNicholas Piggin 	int i;
478ee30cf14SThomas Huth 
4798f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
480584c6ad4SNicholas Piggin 		if (!spr_read_perms(i))
4818f6290f0SNicholas Piggin 			continue;
4828f6290f0SNicholas Piggin 		v[i] = __mfspr(i);
4838f6290f0SNicholas Piggin 	}
4848f6290f0SNicholas Piggin }
485ee30cf14SThomas Huth 
set_sprs(uint64_t val)4868f6290f0SNicholas Piggin static void set_sprs(uint64_t val)
4878f6290f0SNicholas Piggin {
4888f6290f0SNicholas Piggin 	int i;
4898f6290f0SNicholas Piggin 
4908f6290f0SNicholas Piggin 	for (i = 0; i < 1024; i++) {
491584c6ad4SNicholas Piggin 		if (!spr_write_perms(i))
4928f6290f0SNicholas Piggin 			continue;
493584c6ad4SNicholas Piggin 
4948f6290f0SNicholas Piggin 		if (sprs[i].type & SPR_HARNESS)
4958f6290f0SNicholas Piggin 			continue;
4968f6290f0SNicholas Piggin 		__mtspr(i, val);
4978f6290f0SNicholas Piggin 	}
498ee30cf14SThomas Huth }
499ee30cf14SThomas Huth 
main(int argc,char ** argv)500ee30cf14SThomas Huth int main(int argc, char **argv)
501ee30cf14SThomas Huth {
502ee30cf14SThomas Huth 	int i;
503ee30cf14SThomas Huth 	bool pause = false;
504ee30cf14SThomas Huth 	uint64_t pat = 0xcafefacec0debabeULL;
505ee30cf14SThomas Huth 	const uint64_t patterns[] = {
506ee30cf14SThomas Huth 		0xcafefacec0debabeULL, ~0xcafefacec0debabeULL,
507ee30cf14SThomas Huth 		0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL,
508ee30cf14SThomas Huth 		0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL,
509ee30cf14SThomas Huth 		-1ULL,
510ee30cf14SThomas Huth 	};
511ee30cf14SThomas Huth 
512ee30cf14SThomas Huth 	for (i = 1; i < argc; i++) {
513ee30cf14SThomas Huth 		if (!strcmp(argv[i], "-w")) {
514ee30cf14SThomas Huth 			pause = true;
515ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-p")) {
516ee30cf14SThomas Huth 			i += 1;
517ee30cf14SThomas Huth 			if (i >= argc || *argv[i] < '0'
518ee30cf14SThomas Huth 			    || *argv[i] >= '0' + ARRAY_SIZE(patterns))
519ee30cf14SThomas Huth 				report_abort("Error: bad value for -p");
520ee30cf14SThomas Huth 			pat ^= patterns[*argv[i] - '0'];
521ee30cf14SThomas Huth 		} else if (!strcmp(argv[i], "-t")) {
522ee30cf14SThomas Huth 			/* Randomize with timebase register */
523ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
524ee30cf14SThomas Huth 			pat ^= i;
525ee30cf14SThomas Huth 			asm volatile("mftb %0" : "=r"(i));
526ee30cf14SThomas Huth 			pat ^= ~(uint64_t)i << 32;
527ee30cf14SThomas Huth 		} else {
528ee30cf14SThomas Huth 			report_abort("Warning: Unsupported argument: %s",
529ee30cf14SThomas Huth 			             argv[i]);
530ee30cf14SThomas Huth 		}
531ee30cf14SThomas Huth 	}
532ee30cf14SThomas Huth 
5338f6290f0SNicholas Piggin 	setup_sprs();
5348f6290f0SNicholas Piggin 
5358f6290f0SNicholas Piggin 	printf("Setting SPRs to 0x%lx...\n", pat);
536ee30cf14SThomas Huth 	set_sprs(pat);
537ee30cf14SThomas Huth 
538ee30cf14SThomas Huth 	memset(before, 0, sizeof(before));
539ee30cf14SThomas Huth 	memset(after, 0, sizeof(after));
540ee30cf14SThomas Huth 
541ee30cf14SThomas Huth 	get_sprs(before);
542ee30cf14SThomas Huth 
543ee30cf14SThomas Huth 	if (pause) {
54477a59d17SNico Boehr 		migrate_once();
5458f6290f0SNicholas Piggin 		/* Reload regs changed by getchar/putchar hcalls */
5468f6290f0SNicholas Piggin 		before[SPR_SRR0] = mfspr(SPR_SRR0);
5478f6290f0SNicholas Piggin 		before[SPR_SRR1] = mfspr(SPR_SRR1);
5488f6290f0SNicholas Piggin 
5498f6290f0SNicholas Piggin 		/* WORT seems to go to 0 after KVM switch, perhaps CPU idle */
5508f6290f0SNicholas Piggin 		if (sprs[895].name)
5518f6290f0SNicholas Piggin 			before[895] = mfspr(895);
552ee30cf14SThomas Huth 	} else {
553d499b05fSNicholas Piggin 		/*
554d499b05fSNicholas Piggin 		 * msleep will enable MSR[EE] and take a decrementer
555d499b05fSNicholas Piggin 		 * interrupt. Must account for changed registers and
556d499b05fSNicholas Piggin 		 * prevent taking unhandled interrupts.
557d499b05fSNicholas Piggin 		 */
558d499b05fSNicholas Piggin 		/* Prevent PMU interrupt */
559d499b05fSNicholas Piggin 		mtspr(SPR_MMCR0, (mfspr(SPR_MMCR0) | MMCR0_FC) &
560d499b05fSNicholas Piggin 					~(MMCR0_PMAO | MMCR0_PMAE));
561d499b05fSNicholas Piggin 		before[SPR_MMCR0] = mfspr(SPR_MMCR0);
562d499b05fSNicholas Piggin 		before[779] = mfspr(SPR_MMCR0);
563ba33a96fSNicholas Piggin 		msleep(2000);
5648f6290f0SNicholas Piggin 
5658f6290f0SNicholas Piggin 		/* Reload regs changed by dec interrupt */
5668f6290f0SNicholas Piggin 		before[SPR_SRR0] = mfspr(SPR_SRR0);
5678f6290f0SNicholas Piggin 		before[SPR_SRR1] = mfspr(SPR_SRR1);
5688f6290f0SNicholas Piggin 		before[SPR_SPRG1] = mfspr(SPR_SPRG1);
5698f6290f0SNicholas Piggin 
5708f6290f0SNicholas Piggin 		/* WORT seems to go to 0 after KVM switch, perhaps CPU idle */
5718f6290f0SNicholas Piggin 		if (sprs[895].name)
5728f6290f0SNicholas Piggin 			before[895] = mfspr(895);
573ee30cf14SThomas Huth 	}
574ee30cf14SThomas Huth 
575ee30cf14SThomas Huth 	get_sprs(after);
576ee30cf14SThomas Huth 
577ee30cf14SThomas Huth 	puts("Checking SPRs...\n");
578ee30cf14SThomas Huth 	for (i = 0; i < 1024; i++) {
5798f6290f0SNicholas Piggin 		bool pass = true;
5808f6290f0SNicholas Piggin 
581584c6ad4SNicholas Piggin 		if (!spr_read_perms(i))
5828f6290f0SNicholas Piggin 			continue;
5838f6290f0SNicholas Piggin 
5848f6290f0SNicholas Piggin 		if (sprs[i].width == 32) {
5858f6290f0SNicholas Piggin 			if (before[i] >> 32)
5868f6290f0SNicholas Piggin 				pass = false;
5878f6290f0SNicholas Piggin 		}
5888f6290f0SNicholas Piggin 		if (!(sprs[i].type & (SPR_HARNESS|SPR_ASYNC)) && (before[i] != after[i]))
5898f6290f0SNicholas Piggin 			pass = false;
5908f6290f0SNicholas Piggin 
5918f6290f0SNicholas Piggin 		if (sprs[i].width == 32 && !(before[i] >> 32) && !(after[i] >> 32)) {
5928f6290f0SNicholas Piggin 			/* known failure KVM migration of CTRL */
593*851ef516SNicholas Piggin 			report_kfail(host_is_kvm && i == 136, pass,
5948f6290f0SNicholas Piggin 				"%-10s(%4d):\t        0x%08lx <==>         0x%08lx",
5958f6290f0SNicholas Piggin 				sprs[i].name, i,
5968f6290f0SNicholas Piggin 				before[i], after[i]);
5978f6290f0SNicholas Piggin 		} else {
5988f6290f0SNicholas Piggin 			report(pass, "%-10s(%4d):\t0x%016lx <==> 0x%016lx",
5998f6290f0SNicholas Piggin 				sprs[i].name, i,
6008f6290f0SNicholas Piggin 				before[i], after[i]);
6018f6290f0SNicholas Piggin 		}
602ee30cf14SThomas Huth 	}
603ee30cf14SThomas Huth 
604ee30cf14SThomas Huth 	return report_summary();
605ee30cf14SThomas Huth }
606