xref: /kvm-unit-tests/s390x/sthyi.c (revision 728e71ee457384eb1cf2d5111d1e4329498581db)
1 /*
2  * Tests exceptions and data validity for the emulated sthyi
3  * instruction.
4  *
5  * Copyright 2018 IBM Corp.
6  *
7  * Authors:
8  *    Janosch Frank <frankja@linux.vnet.ibm.com>
9  *
10  * This code is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Library General Public License version 2.
12  */
13 #include <libcflat.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/interrupt.h>
16 #include <asm/page.h>
17 #include <asm/facility.h>
18 
19 #include "sthyi.h"
20 
21 static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
22 static char null_buf[32] = {};
23 
24 static inline int sthyi(uint64_t vaddr, uint64_t fcode, uint64_t *rc,
25 			unsigned int r1, unsigned int r2)
26 {
27 	register uint64_t code asm("0") = fcode;
28 	register uint64_t addr asm("2") = vaddr;
29 	register uint64_t rc3 asm("3") = 0;
30 	int cc = 0;
31 
32 	asm volatile(".insn rre,0xB2560000,%[r1],%[r2]\n"
33 		     "ipm	 %[cc]\n"
34 		     "srl	 %[cc],28\n"
35 		     : [cc] "=d" (cc)
36 		     : [code] "d" (code), [addr] "a" (addr), [r1] "i" (r1),
37 		       [r2] "i" (r2)
38 		     : "memory", "cc", "r3");
39 	if (rc)
40 		*rc = rc3;
41 	return cc;
42 }
43 
44 static void test_exception_addr(void)
45 {
46 	report_prefix_push("Illegal address check");
47 	expect_pgm_int();
48 	sthyi(42042, 0, NULL, 0, 2);
49 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
50 	report_prefix_pop();
51 }
52 
53 static void test_exception_reg_odd(void)
54 {
55 	report_prefix_push("Register check odd");
56 	expect_pgm_int();
57 	sthyi((uint64_t)pagebuf, 0, NULL, 1, 2);
58 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
59 	expect_pgm_int();
60 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 3);
61 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
62 	report_prefix_pop();
63 }
64 
65 static void test_exception_reg_equal(void)
66 {
67 	report_prefix_push("Register check equal");
68 	expect_pgm_int();
69 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 0);
70 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
71 	report_prefix_pop();
72 }
73 
74 static void test_function_code(uint64_t addr)
75 {
76 	uint64_t urc = 0;
77 	int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2);
78 
79 	report("Ill. fcode", cc == 3 && urc == CODE_UNSUPP);
80 }
81 
82 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr)
83 {
84 	report("HDR length", (hdr->INFHDLN >= sizeof(*hdr)
85 			      && !(hdr->INFHDLN % 8)));
86 	report("MACH sctn length", (hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn)
87 				    && !(hdr->INFMLEN % 8)));
88 	report("PAR sctn length", (hdr->INFPLEN >= sizeof(struct sthyi_par_sctn)
89 				   && !(hdr->INFPLEN % 8)));
90 
91 	report("MACH offset", hdr->INFMOFF >= hdr->INFHDLN);
92 	report("PAR offset", hdr->INFPOFF >= hdr->INFHDLN);
93 }
94 
95 static void test_fcode0_mach(struct sthyi_mach_sctn *mach)
96 {
97 	int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL;
98 
99 	if (mach->INFMVAL1 & MACH_ID_VLD) {
100 		report("MACH type", memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)));
101 		report("MACH manu", memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)));
102 		report("MACH seq", memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)));
103 		report("MACH plant", memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)));
104 	}
105 
106 	if (mach->INFMVAL1 & MACH_NAME_VLD)
107 		report("MACH name", memcmp(mach->INFMNAME, null_buf,
108 					   sizeof(mach->INFMNAME)));
109 
110 	if (mach->INFMVAL1 & MACH_CNT_VLD)
111 		report("MACH core counts", sum);
112 }
113 
114 static void test_fcode0_par(struct sthyi_par_sctn *par)
115 {
116 	int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL;
117 
118 	if (par->INFPVAL1 & PART_CNT_VLD)
119 		report("PAR core counts", sum);
120 
121 	if (par->INFPVAL1 & PART_STSI_SUC) {
122 		report("PAR number", par->INFPPNUM);
123 		report("PAR name", memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)));
124 	}
125 }
126 
127 static void test_fcode0(void)
128 {
129 	struct sthyi_hdr_sctn *hdr;
130 	struct sthyi_mach_sctn *mach;
131 	struct sthyi_par_sctn *par;
132 
133 	/* Zero destination memory. */
134 	memset(pagebuf, 0, PAGE_SIZE);
135 
136 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 2);
137 	hdr = (void *)pagebuf;
138 	mach = (void *)pagebuf + hdr->INFMOFF;
139 	par = (void *)pagebuf + hdr->INFPOFF;
140 
141 	test_fcode0_hdr(hdr);
142 	test_fcode0_mach(mach);
143 	test_fcode0_par(par);
144 }
145 
146 int main(void)
147 {
148 	bool has_sthyi = test_facility(74);
149 
150 	report_prefix_push("sthyi");
151 
152 	/* Test for availability */
153 	if (!has_sthyi) {
154 		report_skip("STHYI is not available");
155 		goto done;
156 	}
157 
158 	/* Test register/argument checking. */
159 	test_exception_addr();
160 	test_exception_reg_odd();
161 	test_exception_reg_equal();
162 	test_function_code((uint64_t) pagebuf);
163 
164 	/* Test function code 0 - CP and IFL Capacity Information */
165 	test_fcode0();
166 
167 done:
168 	report_prefix_pop();
169 	return report_summary();
170 }
171