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