xref: /kvm-unit-tests/s390x/sthyi.c (revision 6ca8c283190847bd2ff648232f98f70e4e6d3d0d)
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 R1");
56 	expect_pgm_int();
57 	sthyi((uint64_t)pagebuf, 0, NULL, 1, 2);
58 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
59 	report_prefix_pop();
60 	report_prefix_push("Register check odd R2");
61 	expect_pgm_int();
62 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 3);
63 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
64 	report_prefix_pop();
65 }
66 
67 static void test_exception_reg_equal(void)
68 {
69 	report_prefix_push("Register check equal");
70 	expect_pgm_int();
71 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 0);
72 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
73 	report_prefix_pop();
74 }
75 
76 static void test_function_code(uint64_t addr)
77 {
78 	uint64_t urc = 0;
79 	int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2);
80 
81 	report("Illegal fcode", cc == 3 && urc == CODE_UNSUPP);
82 }
83 
84 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr)
85 {
86 	report_prefix_push("Header");
87 
88 	report("length", hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8));
89 	report("Machine sctn length", (hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn)
90 				       && !(hdr->INFMLEN % 8)));
91 	report("Partition section length", (hdr->INFPLEN >= sizeof(struct sthyi_par_sctn)
92 					    && !(hdr->INFPLEN % 8)));
93 
94 	report("Machine offset", hdr->INFMOFF >= hdr->INFHDLN);
95 	report("Partition offset", hdr->INFPOFF >= hdr->INFHDLN);
96 	report_prefix_pop();
97 }
98 
99 static void test_fcode0_mach(struct sthyi_mach_sctn *mach)
100 {
101 	int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL;
102 
103 	report_prefix_push("Machine");
104 	if (mach->INFMVAL1 & MACH_ID_VLD) {
105 		report("type", memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)));
106 		report("manufacturer", memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)));
107 		report("sequence", memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)));
108 		report("plant", memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)));
109 	}
110 
111 	if (mach->INFMVAL1 & MACH_NAME_VLD)
112 		report("name", memcmp(mach->INFMNAME, null_buf,
113 				      sizeof(mach->INFMNAME)));
114 
115 	if (mach->INFMVAL1 & MACH_CNT_VLD)
116 		report("core counts", sum);
117 	report_prefix_pop();
118 }
119 
120 static void test_fcode0_par(struct sthyi_par_sctn *par)
121 {
122 	int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL;
123 
124 	report_prefix_push("Partition");
125 	if (par->INFPVAL1 & PART_CNT_VLD)
126 		report("core counts", sum);
127 
128 	if (par->INFPVAL1 & PART_STSI_SUC) {
129 		report("number", par->INFPPNUM);
130 		report("name", memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)));
131 	}
132 	report_prefix_pop();
133 }
134 
135 static void test_fcode0(void)
136 {
137 	struct sthyi_hdr_sctn *hdr;
138 	struct sthyi_mach_sctn *mach;
139 	struct sthyi_par_sctn *par;
140 
141 	/* Zero destination memory. */
142 	memset(pagebuf, 0, PAGE_SIZE);
143 
144 	report_prefix_push("fcode 0");
145 	sthyi((uint64_t)pagebuf, 0, NULL, 0, 2);
146 	hdr = (void *)pagebuf;
147 	mach = (void *)pagebuf + hdr->INFMOFF;
148 	par = (void *)pagebuf + hdr->INFPOFF;
149 
150 	test_fcode0_hdr(hdr);
151 	test_fcode0_mach(mach);
152 	test_fcode0_par(par);
153 	report_prefix_pop();
154 }
155 
156 int main(void)
157 {
158 	bool has_sthyi = test_facility(74);
159 
160 	report_prefix_push("sthyi");
161 
162 	/* Test for availability */
163 	if (!has_sthyi) {
164 		report_skip("STHYI is not available");
165 		goto done;
166 	}
167 
168 	/* Test register/argument checking. */
169 	report_prefix_push("Instruction");
170 	test_exception_addr();
171 	test_exception_reg_odd();
172 	test_exception_reg_equal();
173 	test_function_code((uint64_t) pagebuf);
174 	report_prefix_pop();
175 
176 	/* Test function code 0 - CP and IFL Capacity Information */
177 	test_fcode0();
178 
179 done:
180 	report_prefix_pop();
181 	return report_summary();
182 }
183