xref: /kvm-unit-tests/s390x/skrf.c (revision 787d1bcc814bdb69f847e3d804df8587d58035ef)
147df95c7SJanosch Frank /*
247df95c7SJanosch Frank  * Storage key removal facility tests
347df95c7SJanosch Frank  *
447df95c7SJanosch Frank  * Copyright (c) 2019 IBM Corp
547df95c7SJanosch Frank  *
647df95c7SJanosch Frank  * Authors:
747df95c7SJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
847df95c7SJanosch Frank  *
947df95c7SJanosch Frank  * This code is free software; you can redistribute it and/or modify it
1047df95c7SJanosch Frank  * under the terms of the GNU General Public License version 2.
1147df95c7SJanosch Frank  */
1247df95c7SJanosch Frank #include <libcflat.h>
1347df95c7SJanosch Frank #include <asm/asm-offsets.h>
14*787d1bccSJanosch Frank #include <asm-generic/barrier.h>
1547df95c7SJanosch Frank #include <asm/interrupt.h>
1647df95c7SJanosch Frank #include <asm/page.h>
1747df95c7SJanosch Frank #include <asm/facility.h>
1847df95c7SJanosch Frank #include <asm/mem.h>
19*787d1bccSJanosch Frank #include <asm/sigp.h>
20*787d1bccSJanosch Frank #include <smp.h>
2147df95c7SJanosch Frank 
2247df95c7SJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
23*787d1bccSJanosch Frank static int testflag = 0;
2447df95c7SJanosch Frank 
2547df95c7SJanosch Frank static void test_facilities(void)
2647df95c7SJanosch Frank {
2747df95c7SJanosch Frank 	report_prefix_push("facilities");
28a299895bSThomas Huth 	report(!test_facility(10), "!10");
29a299895bSThomas Huth 	report(!test_facility(14), "!14");
30a299895bSThomas Huth 	report(!test_facility(66), "!66");
31a299895bSThomas Huth 	report(!test_facility(145), "!145");
32a299895bSThomas Huth 	report(!test_facility(140), "!149");
3347df95c7SJanosch Frank 	report_prefix_pop();
3447df95c7SJanosch Frank }
3547df95c7SJanosch Frank 
3647df95c7SJanosch Frank static void test_skey(void)
3747df95c7SJanosch Frank {
3847df95c7SJanosch Frank 	report_prefix_push("sske");
3947df95c7SJanosch Frank 	expect_pgm_int();
4047df95c7SJanosch Frank 	set_storage_key(pagebuf, 0x30, 0);
4147df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
4247df95c7SJanosch Frank 	expect_pgm_int();
4347df95c7SJanosch Frank 	report_prefix_pop();
4447df95c7SJanosch Frank 	report_prefix_push("iske");
4547df95c7SJanosch Frank 	get_storage_key(pagebuf);
4647df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
4747df95c7SJanosch Frank 	report_prefix_pop();
4847df95c7SJanosch Frank }
4947df95c7SJanosch Frank 
5047df95c7SJanosch Frank static void test_pfmf(void)
5147df95c7SJanosch Frank {
5247df95c7SJanosch Frank 	union pfmf_r1 r1;
5347df95c7SJanosch Frank 
5447df95c7SJanosch Frank 	report_prefix_push("pfmf");
5547df95c7SJanosch Frank 	r1.val = 0;
5647df95c7SJanosch Frank 	r1.reg.sk = 1;
5747df95c7SJanosch Frank 	r1.reg.fsc = PFMF_FSC_4K;
5847df95c7SJanosch Frank 	r1.reg.key = 0x30;
5947df95c7SJanosch Frank 	expect_pgm_int();
6047df95c7SJanosch Frank 	pfmf(r1.val, pagebuf);
6147df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
6247df95c7SJanosch Frank 	report_prefix_pop();
6347df95c7SJanosch Frank }
6447df95c7SJanosch Frank 
6547df95c7SJanosch Frank static void test_psw_key(void)
6647df95c7SJanosch Frank {
6747df95c7SJanosch Frank 	uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL;
6847df95c7SJanosch Frank 
6947df95c7SJanosch Frank 	report_prefix_push("psw key");
7047df95c7SJanosch Frank 	expect_pgm_int();
7147df95c7SJanosch Frank 	load_psw_mask(psw_mask);
7247df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
7347df95c7SJanosch Frank 	report_prefix_pop();
7447df95c7SJanosch Frank }
7547df95c7SJanosch Frank 
7647df95c7SJanosch Frank static void test_mvcos(void)
7747df95c7SJanosch Frank {
7847df95c7SJanosch Frank 	uint64_t r3 = 64;
7947df95c7SJanosch Frank 	uint8_t *src = pagebuf;
8047df95c7SJanosch Frank 	uint8_t *dst = pagebuf + PAGE_SIZE;
8147df95c7SJanosch Frank 	/* K bit set, as well as keys */
8247df95c7SJanosch Frank 	register unsigned long oac asm("0") = 0xf002f002;
8347df95c7SJanosch Frank 
8447df95c7SJanosch Frank 	report_prefix_push("mvcos");
8547df95c7SJanosch Frank 	expect_pgm_int();
8647df95c7SJanosch Frank 	asm volatile("mvcos	%[dst],%[src],%[len]"
8747df95c7SJanosch Frank 		     : [dst] "+Q" (*(dst))
8847df95c7SJanosch Frank 		     : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac)
8947df95c7SJanosch Frank 		     : "cc", "memory");
9047df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
9147df95c7SJanosch Frank 	report_prefix_pop();
9247df95c7SJanosch Frank }
9347df95c7SJanosch Frank 
9447df95c7SJanosch Frank static void test_spka(void)
9547df95c7SJanosch Frank {
9647df95c7SJanosch Frank 	report_prefix_push("spka");
9747df95c7SJanosch Frank 	expect_pgm_int();
9847df95c7SJanosch Frank 	asm volatile("spka	0xf0(0)\n");
9947df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
10047df95c7SJanosch Frank 	report_prefix_pop();
10147df95c7SJanosch Frank }
10247df95c7SJanosch Frank 
10347df95c7SJanosch Frank static void test_tprot(void)
10447df95c7SJanosch Frank {
10547df95c7SJanosch Frank 	report_prefix_push("tprot");
10647df95c7SJanosch Frank 	expect_pgm_int();
10747df95c7SJanosch Frank 	asm volatile("tprot	%[addr],0xf0(0)\n"
10847df95c7SJanosch Frank 		     : : [addr] "a" (pagebuf) : );
10947df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
11047df95c7SJanosch Frank 	report_prefix_pop();
11147df95c7SJanosch Frank }
11247df95c7SJanosch Frank 
113*787d1bccSJanosch Frank static void wait_for_flag(void)
114*787d1bccSJanosch Frank {
115*787d1bccSJanosch Frank 	while (!testflag)
116*787d1bccSJanosch Frank 		mb();
117*787d1bccSJanosch Frank }
118*787d1bccSJanosch Frank 
119*787d1bccSJanosch Frank static void set_flag(int val)
120*787d1bccSJanosch Frank {
121*787d1bccSJanosch Frank 	mb();
122*787d1bccSJanosch Frank 	testflag = val;
123*787d1bccSJanosch Frank 	mb();
124*787d1bccSJanosch Frank }
125*787d1bccSJanosch Frank 
126*787d1bccSJanosch Frank static void ecall_cleanup(void)
127*787d1bccSJanosch Frank {
128*787d1bccSJanosch Frank 	struct lowcore *lc = (void *)0x0;
129*787d1bccSJanosch Frank 
130*787d1bccSJanosch Frank 	lc->ext_new_psw.mask = 0x0000000180000000UL;
131*787d1bccSJanosch Frank 	lc->sw_int_crs[0] = 0x0000000000040000;
132*787d1bccSJanosch Frank 
133*787d1bccSJanosch Frank 	/*
134*787d1bccSJanosch Frank 	 * PGM old contains the ext new PSW, we need to clean it up,
135*787d1bccSJanosch Frank 	 * so we don't get a special operation exception on the lpswe
136*787d1bccSJanosch Frank 	 * of pgm old.
137*787d1bccSJanosch Frank 	 */
138*787d1bccSJanosch Frank 	lc->pgm_old_psw.mask = 0x0000000180000000UL;
139*787d1bccSJanosch Frank 
140*787d1bccSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
141*787d1bccSJanosch Frank 	set_flag(1);
142*787d1bccSJanosch Frank }
143*787d1bccSJanosch Frank 
144*787d1bccSJanosch Frank /* Set a key into the external new psw mask and open external call masks */
145*787d1bccSJanosch Frank static void ecall_setup(void)
146*787d1bccSJanosch Frank {
147*787d1bccSJanosch Frank 	struct lowcore *lc = (void *)0x0;
148*787d1bccSJanosch Frank 	uint64_t mask;
149*787d1bccSJanosch Frank 
150*787d1bccSJanosch Frank 	register_pgm_cleanup_func(ecall_cleanup);
151*787d1bccSJanosch Frank 	expect_pgm_int();
152*787d1bccSJanosch Frank 	/* Put a skey into the ext new psw */
153*787d1bccSJanosch Frank 	lc->ext_new_psw.mask = 0x00F0000180000000UL;
154*787d1bccSJanosch Frank 	/* Open up ext masks */
155*787d1bccSJanosch Frank 	ctl_set_bit(0, 13);
156*787d1bccSJanosch Frank 	mask = extract_psw_mask();
157*787d1bccSJanosch Frank 	mask |= PSW_MASK_EXT;
158*787d1bccSJanosch Frank 	load_psw_mask(mask);
159*787d1bccSJanosch Frank 	/* Tell cpu 0 that we're ready */
160*787d1bccSJanosch Frank 	set_flag(1);
161*787d1bccSJanosch Frank }
162*787d1bccSJanosch Frank 
163*787d1bccSJanosch Frank static void test_exception_ext_new(void)
164*787d1bccSJanosch Frank {
165*787d1bccSJanosch Frank 	struct psw psw = {
166*787d1bccSJanosch Frank 		.mask = extract_psw_mask(),
167*787d1bccSJanosch Frank 		.addr = (unsigned long)ecall_setup
168*787d1bccSJanosch Frank 	};
169*787d1bccSJanosch Frank 
170*787d1bccSJanosch Frank 	report_prefix_push("exception external new");
171*787d1bccSJanosch Frank 	if (smp_query_num_cpus() < 2) {
172*787d1bccSJanosch Frank 		report_skip("Need second cpu for exception external new test.");
173*787d1bccSJanosch Frank 		report_prefix_pop();
174*787d1bccSJanosch Frank 		return;
175*787d1bccSJanosch Frank 	}
176*787d1bccSJanosch Frank 
177*787d1bccSJanosch Frank 	smp_cpu_setup(1, psw);
178*787d1bccSJanosch Frank 	wait_for_flag();
179*787d1bccSJanosch Frank 	set_flag(0);
180*787d1bccSJanosch Frank 
181*787d1bccSJanosch Frank 	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
182*787d1bccSJanosch Frank 	wait_for_flag();
183*787d1bccSJanosch Frank 	smp_cpu_stop(1);
184*787d1bccSJanosch Frank 	report_prefix_pop();
185*787d1bccSJanosch Frank }
186*787d1bccSJanosch Frank 
18747df95c7SJanosch Frank int main(void)
18847df95c7SJanosch Frank {
18947df95c7SJanosch Frank 	report_prefix_push("skrf");
19047df95c7SJanosch Frank 	if (!test_facility(169)) {
19147df95c7SJanosch Frank 		report_skip("storage key removal facility not available\n");
19247df95c7SJanosch Frank 		goto done;
19347df95c7SJanosch Frank 	}
19447df95c7SJanosch Frank 
19547df95c7SJanosch Frank 	test_facilities();
19647df95c7SJanosch Frank 	test_skey();
19747df95c7SJanosch Frank 	test_pfmf();
19847df95c7SJanosch Frank 	test_psw_key();
19947df95c7SJanosch Frank 	test_mvcos();
20047df95c7SJanosch Frank 	test_spka();
20147df95c7SJanosch Frank 	test_tprot();
202*787d1bccSJanosch Frank 	test_exception_ext_new();
20347df95c7SJanosch Frank 
20447df95c7SJanosch Frank done:
20547df95c7SJanosch Frank 	report_prefix_pop();
20647df95c7SJanosch Frank 	return report_summary();
20747df95c7SJanosch Frank }
208