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