xref: /kvm-unit-tests/s390x/skrf.c (revision b4667f4ca26aea926a2ddecfcb5669e0e4e7cbf4)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Storage key removal facility tests
4  *
5  * Copyright (c) 2019 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 #include <libcflat.h>
11 #include <asm/asm-offsets.h>
12 #include <asm-generic/barrier.h>
13 #include <asm/interrupt.h>
14 #include <asm/page.h>
15 #include <asm/facility.h>
16 #include <asm/mem.h>
17 #include <asm/sigp.h>
18 #include <smp.h>
19 
20 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
21 static int testflag = 0;
22 
23 static void test_facilities(void)
24 {
25 	report_prefix_push("facilities");
26 	report(!test_facility(10), "!10");
27 	report(!test_facility(14), "!14");
28 	report(!test_facility(66), "!66");
29 	report(!test_facility(145), "!145");
30 	report(!test_facility(140), "!149");
31 	report_prefix_pop();
32 }
33 
34 static void test_skey(void)
35 {
36 	report_prefix_push("sske");
37 	expect_pgm_int();
38 	set_storage_key(pagebuf, 0x30, 0);
39 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
40 	expect_pgm_int();
41 	report_prefix_pop();
42 	report_prefix_push("iske");
43 	get_storage_key(pagebuf);
44 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
45 	report_prefix_pop();
46 }
47 
48 static void test_pfmf(void)
49 {
50 	union pfmf_r1 r1;
51 
52 	report_prefix_push("pfmf");
53 	r1.val = 0;
54 	r1.reg.sk = 1;
55 	r1.reg.fsc = PFMF_FSC_4K;
56 	r1.reg.key = 0x30;
57 	expect_pgm_int();
58 	pfmf(r1.val, pagebuf);
59 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
60 	report_prefix_pop();
61 }
62 
63 static void test_psw_key(void)
64 {
65 	uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL;
66 
67 	report_prefix_push("psw key");
68 	expect_pgm_int();
69 	load_psw_mask(psw_mask);
70 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
71 	report_prefix_pop();
72 }
73 
74 static void test_mvcos(void)
75 {
76 	uint64_t r3 = 64;
77 	uint8_t *src = pagebuf;
78 	uint8_t *dst = pagebuf + PAGE_SIZE;
79 	/* K bit set, as well as keys */
80 	register unsigned long oac asm("0") = 0xf002f002;
81 
82 	report_prefix_push("mvcos");
83 	expect_pgm_int();
84 	asm volatile("mvcos	%[dst],%[src],%[len]"
85 		     : [dst] "+Q" (*(dst))
86 		     : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac)
87 		     : "cc", "memory");
88 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
89 	report_prefix_pop();
90 }
91 
92 static void test_spka(void)
93 {
94 	report_prefix_push("spka");
95 	expect_pgm_int();
96 	asm volatile("spka	0xf0(0)\n");
97 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
98 	report_prefix_pop();
99 }
100 
101 static void test_tprot(void)
102 {
103 	report_prefix_push("tprot");
104 	expect_pgm_int();
105 	asm volatile("tprot	%[addr],0xf0(0)\n"
106 		     : : [addr] "a" (pagebuf) : );
107 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
108 	report_prefix_pop();
109 }
110 
111 static void wait_for_flag(void)
112 {
113 	while (!testflag)
114 		mb();
115 }
116 
117 static void set_flag(int val)
118 {
119 	mb();
120 	testflag = val;
121 	mb();
122 }
123 
124 static void ecall_cleanup(void)
125 {
126 	struct lowcore *lc = (void *)0x0;
127 
128 	lc->sw_int_crs[0] = 0x0000000000040000;
129 	lc->ext_new_psw.mask = PSW_MASK_64;
130 
131 	/*
132 	 * PGM old contains the ext new PSW, we need to clean it up,
133 	 * so we don't get a special operation exception on the lpswe
134 	 * of pgm old.
135 	 */
136 	lc->pgm_old_psw.mask = PSW_MASK_64;
137 
138 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
139 	set_flag(1);
140 }
141 
142 /* Set a key into the external new psw mask and open external call masks */
143 static void ecall_setup(void)
144 {
145 	struct lowcore *lc = (void *)0x0;
146 	uint64_t mask;
147 
148 	register_pgm_cleanup_func(ecall_cleanup);
149 	expect_pgm_int();
150 	/* Put a skey into the ext new psw */
151 	lc->ext_new_psw.mask = 0x00F0000000000000UL | PSW_MASK_64;
152 	/* Open up ext masks */
153 	ctl_set_bit(0, CTL0_EXTERNAL_CALL);
154 	mask = extract_psw_mask();
155 	mask |= PSW_MASK_EXT;
156 	load_psw_mask(mask);
157 	/* Tell cpu 0 that we're ready */
158 	set_flag(1);
159 }
160 
161 static void test_exception_ext_new(void)
162 {
163 	struct psw psw = {
164 		.mask = extract_psw_mask(),
165 		.addr = (unsigned long)ecall_setup
166 	};
167 
168 	report_prefix_push("exception external new");
169 	if (smp_query_num_cpus() < 2) {
170 		report_skip("Need second cpu for exception external new test.");
171 		report_prefix_pop();
172 		return;
173 	}
174 
175 	smp_cpu_setup(1, psw);
176 	wait_for_flag();
177 	set_flag(0);
178 
179 	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
180 	wait_for_flag();
181 	smp_cpu_stop(1);
182 	report_prefix_pop();
183 }
184 
185 int main(void)
186 {
187 	report_prefix_push("skrf");
188 	if (!test_facility(169)) {
189 		report_skip("storage key removal facility not available\n");
190 		goto done;
191 	}
192 
193 	test_facilities();
194 	test_skey();
195 	test_pfmf();
196 	test_psw_key();
197 	test_mvcos();
198 	test_spka();
199 	test_tprot();
200 	test_exception_ext_new();
201 
202 done:
203 	report_prefix_pop();
204 	return report_summary();
205 }
206