xref: /kvm-unit-tests/s390x/skrf.c (revision e3c5c3ef2524c58023073c0fadde2e8ae3c04ec6)
1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
247df95c7SJanosch Frank /*
347df95c7SJanosch Frank  * Storage key removal facility tests
447df95c7SJanosch Frank  *
547df95c7SJanosch Frank  * Copyright (c) 2019 IBM Corp
647df95c7SJanosch Frank  *
747df95c7SJanosch Frank  * Authors:
847df95c7SJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
947df95c7SJanosch Frank  */
1047df95c7SJanosch Frank #include <libcflat.h>
11d34d3250SJanosch Frank #include <bitops.h>
1247df95c7SJanosch Frank #include <asm/asm-offsets.h>
13787d1bccSJanosch Frank #include <asm-generic/barrier.h>
1447df95c7SJanosch Frank #include <asm/interrupt.h>
1547df95c7SJanosch Frank #include <asm/page.h>
1647df95c7SJanosch Frank #include <asm/facility.h>
1747df95c7SJanosch Frank #include <asm/mem.h>
18787d1bccSJanosch Frank #include <asm/sigp.h>
19787d1bccSJanosch Frank #include <smp.h>
2047df95c7SJanosch Frank 
2147df95c7SJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
22787d1bccSJanosch Frank static int testflag = 0;
2347df95c7SJanosch Frank 
test_facilities(void)2447df95c7SJanosch Frank static void test_facilities(void)
2547df95c7SJanosch Frank {
2647df95c7SJanosch Frank 	report_prefix_push("facilities");
27a299895bSThomas Huth 	report(!test_facility(10), "!10");
28a299895bSThomas Huth 	report(!test_facility(14), "!14");
29a299895bSThomas Huth 	report(!test_facility(66), "!66");
30a299895bSThomas Huth 	report(!test_facility(145), "!145");
31a299895bSThomas Huth 	report(!test_facility(140), "!149");
3247df95c7SJanosch Frank 	report_prefix_pop();
3347df95c7SJanosch Frank }
3447df95c7SJanosch Frank 
test_skey(void)3547df95c7SJanosch Frank static void test_skey(void)
3647df95c7SJanosch Frank {
3747df95c7SJanosch Frank 	report_prefix_push("sske");
3847df95c7SJanosch Frank 	expect_pgm_int();
3947df95c7SJanosch Frank 	set_storage_key(pagebuf, 0x30, 0);
4047df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
4147df95c7SJanosch Frank 	expect_pgm_int();
4247df95c7SJanosch Frank 	report_prefix_pop();
4347df95c7SJanosch Frank 	report_prefix_push("iske");
4447df95c7SJanosch Frank 	get_storage_key(pagebuf);
4547df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
4647df95c7SJanosch Frank 	report_prefix_pop();
4747df95c7SJanosch Frank }
4847df95c7SJanosch Frank 
test_pfmf(void)4947df95c7SJanosch Frank static void test_pfmf(void)
5047df95c7SJanosch Frank {
5147df95c7SJanosch Frank 	union pfmf_r1 r1;
5247df95c7SJanosch Frank 
5347df95c7SJanosch Frank 	report_prefix_push("pfmf");
5447df95c7SJanosch Frank 	r1.val = 0;
5547df95c7SJanosch Frank 	r1.reg.sk = 1;
5647df95c7SJanosch Frank 	r1.reg.fsc = PFMF_FSC_4K;
5747df95c7SJanosch Frank 	r1.reg.key = 0x30;
5847df95c7SJanosch Frank 	expect_pgm_int();
5947df95c7SJanosch Frank 	pfmf(r1.val, pagebuf);
6047df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
6147df95c7SJanosch Frank 	report_prefix_pop();
6247df95c7SJanosch Frank }
6347df95c7SJanosch Frank 
test_psw_key(void)6447df95c7SJanosch Frank static void test_psw_key(void)
6547df95c7SJanosch Frank {
6647df95c7SJanosch Frank 	report_prefix_push("psw key");
6747df95c7SJanosch Frank 	expect_pgm_int();
68086985a3SClaudio Imbrenda 	psw_mask_set_bits(PSW_MASK_KEY);
6947df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
7047df95c7SJanosch Frank 	report_prefix_pop();
7147df95c7SJanosch Frank }
7247df95c7SJanosch Frank 
test_mvcos(void)7347df95c7SJanosch Frank static void test_mvcos(void)
7447df95c7SJanosch Frank {
7547df95c7SJanosch Frank 	uint64_t r3 = 64;
7647df95c7SJanosch Frank 	uint8_t *src = pagebuf;
7747df95c7SJanosch Frank 	uint8_t *dst = pagebuf + PAGE_SIZE;
7847df95c7SJanosch Frank 	/* K bit set, as well as keys */
7947df95c7SJanosch Frank 	register unsigned long oac asm("0") = 0xf002f002;
8047df95c7SJanosch Frank 
8147df95c7SJanosch Frank 	report_prefix_push("mvcos");
8247df95c7SJanosch Frank 	expect_pgm_int();
8347df95c7SJanosch Frank 	asm volatile("mvcos	%[dst],%[src],%[len]"
8447df95c7SJanosch Frank 		     : [dst] "+Q" (*(dst))
8547df95c7SJanosch Frank 		     : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac)
8647df95c7SJanosch Frank 		     : "cc", "memory");
8747df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
8847df95c7SJanosch Frank 	report_prefix_pop();
8947df95c7SJanosch Frank }
9047df95c7SJanosch Frank 
test_spka(void)9147df95c7SJanosch Frank static void test_spka(void)
9247df95c7SJanosch Frank {
9347df95c7SJanosch Frank 	report_prefix_push("spka");
9447df95c7SJanosch Frank 	expect_pgm_int();
9547df95c7SJanosch Frank 	asm volatile("spka	0xf0(0)\n");
9647df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
9747df95c7SJanosch Frank 	report_prefix_pop();
9847df95c7SJanosch Frank }
9947df95c7SJanosch Frank 
test_tprot(void)10047df95c7SJanosch Frank static void test_tprot(void)
10147df95c7SJanosch Frank {
10247df95c7SJanosch Frank 	report_prefix_push("tprot");
10347df95c7SJanosch Frank 	expect_pgm_int();
104443987a6SJanis Schoetterl-Glausch 	tprot((unsigned long)pagebuf, 0xf);
10547df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
10647df95c7SJanosch Frank 	report_prefix_pop();
10747df95c7SJanosch Frank }
10847df95c7SJanosch Frank 
wait_for_flag(void)109787d1bccSJanosch Frank static void wait_for_flag(void)
110787d1bccSJanosch Frank {
111787d1bccSJanosch Frank 	while (!testflag)
112787d1bccSJanosch Frank 		mb();
113787d1bccSJanosch Frank }
114787d1bccSJanosch Frank 
set_flag(int val)115787d1bccSJanosch Frank static void set_flag(int val)
116787d1bccSJanosch Frank {
117787d1bccSJanosch Frank 	mb();
118787d1bccSJanosch Frank 	testflag = val;
119787d1bccSJanosch Frank 	mb();
120787d1bccSJanosch Frank }
121787d1bccSJanosch Frank 
ecall_cleanup(struct stack_frame_int * stack)1224e5dd758SClaudio Imbrenda static void ecall_cleanup(struct stack_frame_int *stack)
123787d1bccSJanosch Frank {
124cd719531SJanis Schoetterl-Glausch 	lowcore.ext_new_psw.mask = PSW_MASK_64;
125cd719531SJanis Schoetterl-Glausch 	lowcore.sw_int_crs[0] = BIT_ULL(CTL0_AFP);
126787d1bccSJanosch Frank 
127787d1bccSJanosch Frank 	/*
128787d1bccSJanosch Frank 	 * PGM old contains the ext new PSW, we need to clean it up,
129787d1bccSJanosch Frank 	 * so we don't get a special operation exception on the lpswe
130787d1bccSJanosch Frank 	 * of pgm old.
131787d1bccSJanosch Frank 	 */
132cd719531SJanis Schoetterl-Glausch 	lowcore.pgm_old_psw.mask = PSW_MASK_64;
133787d1bccSJanosch Frank 
134787d1bccSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
135787d1bccSJanosch Frank 	set_flag(1);
136787d1bccSJanosch Frank }
137787d1bccSJanosch Frank 
138787d1bccSJanosch Frank /* Set a key into the external new psw mask and open external call masks */
ecall_setup(void)139787d1bccSJanosch Frank static void ecall_setup(void)
140787d1bccSJanosch Frank {
141787d1bccSJanosch Frank 	register_pgm_cleanup_func(ecall_cleanup);
142787d1bccSJanosch Frank 	expect_pgm_int();
143787d1bccSJanosch Frank 	/* Put a skey into the ext new psw */
144086985a3SClaudio Imbrenda 	lowcore.ext_new_psw.mask = PSW_MASK_KEY | PSW_MASK_64;
145787d1bccSJanosch Frank 	/* Open up ext masks */
1461b2c0437SClaudio Imbrenda 	ctl_set_bit(0, CTL0_EXTERNAL_CALL);
147086985a3SClaudio Imbrenda 	psw_mask_set_bits(PSW_MASK_EXT);
148787d1bccSJanosch Frank 	/* Tell cpu 0 that we're ready */
149787d1bccSJanosch Frank 	set_flag(1);
150787d1bccSJanosch Frank }
151787d1bccSJanosch Frank 
test_exception_ext_new(void)152787d1bccSJanosch Frank static void test_exception_ext_new(void)
153787d1bccSJanosch Frank {
154787d1bccSJanosch Frank 	report_prefix_push("exception external new");
155787d1bccSJanosch Frank 	if (smp_query_num_cpus() < 2) {
156787d1bccSJanosch Frank 		report_skip("Need second cpu for exception external new test.");
157787d1bccSJanosch Frank 		report_prefix_pop();
158787d1bccSJanosch Frank 		return;
159787d1bccSJanosch Frank 	}
160787d1bccSJanosch Frank 
161*f514b4f7SClaudio Imbrenda 	smp_cpu_setup(1, PSW_WITH_CUR_MASK(ecall_setup));
162787d1bccSJanosch Frank 	wait_for_flag();
163787d1bccSJanosch Frank 	set_flag(0);
164787d1bccSJanosch Frank 
165962129d2SClaudio Imbrenda 	smp_sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
166787d1bccSJanosch Frank 	wait_for_flag();
167787d1bccSJanosch Frank 	smp_cpu_stop(1);
168787d1bccSJanosch Frank 	report_prefix_pop();
169787d1bccSJanosch Frank }
170787d1bccSJanosch Frank 
main(void)17147df95c7SJanosch Frank int main(void)
17247df95c7SJanosch Frank {
17347df95c7SJanosch Frank 	report_prefix_push("skrf");
17447df95c7SJanosch Frank 	if (!test_facility(169)) {
17547df95c7SJanosch Frank 		report_skip("storage key removal facility not available\n");
17647df95c7SJanosch Frank 		goto done;
17747df95c7SJanosch Frank 	}
17847df95c7SJanosch Frank 
17947df95c7SJanosch Frank 	test_facilities();
18047df95c7SJanosch Frank 	test_skey();
18147df95c7SJanosch Frank 	test_pfmf();
18247df95c7SJanosch Frank 	test_psw_key();
18347df95c7SJanosch Frank 	test_mvcos();
18447df95c7SJanosch Frank 	test_spka();
18547df95c7SJanosch Frank 	test_tprot();
186787d1bccSJanosch Frank 	test_exception_ext_new();
18747df95c7SJanosch Frank 
18847df95c7SJanosch Frank done:
18947df95c7SJanosch Frank 	report_prefix_pop();
19047df95c7SJanosch Frank 	return report_summary();
19147df95c7SJanosch Frank }
192