xref: /kvm-unit-tests/s390x/skrf.c (revision d34d3250c6cabef0dbd19d06c67ce51635f88c78)
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>
11*d34d3250SJanosch 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 
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 
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 
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 
6447df95c7SJanosch Frank static void test_psw_key(void)
6547df95c7SJanosch Frank {
6647df95c7SJanosch Frank 	uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL;
6747df95c7SJanosch Frank 
6847df95c7SJanosch Frank 	report_prefix_push("psw key");
6947df95c7SJanosch Frank 	expect_pgm_int();
7047df95c7SJanosch Frank 	load_psw_mask(psw_mask);
7147df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
7247df95c7SJanosch Frank 	report_prefix_pop();
7347df95c7SJanosch Frank }
7447df95c7SJanosch Frank 
7547df95c7SJanosch Frank static void test_mvcos(void)
7647df95c7SJanosch Frank {
7747df95c7SJanosch Frank 	uint64_t r3 = 64;
7847df95c7SJanosch Frank 	uint8_t *src = pagebuf;
7947df95c7SJanosch Frank 	uint8_t *dst = pagebuf + PAGE_SIZE;
8047df95c7SJanosch Frank 	/* K bit set, as well as keys */
8147df95c7SJanosch Frank 	register unsigned long oac asm("0") = 0xf002f002;
8247df95c7SJanosch Frank 
8347df95c7SJanosch Frank 	report_prefix_push("mvcos");
8447df95c7SJanosch Frank 	expect_pgm_int();
8547df95c7SJanosch Frank 	asm volatile("mvcos	%[dst],%[src],%[len]"
8647df95c7SJanosch Frank 		     : [dst] "+Q" (*(dst))
8747df95c7SJanosch Frank 		     : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac)
8847df95c7SJanosch Frank 		     : "cc", "memory");
8947df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
9047df95c7SJanosch Frank 	report_prefix_pop();
9147df95c7SJanosch Frank }
9247df95c7SJanosch Frank 
9347df95c7SJanosch Frank static void test_spka(void)
9447df95c7SJanosch Frank {
9547df95c7SJanosch Frank 	report_prefix_push("spka");
9647df95c7SJanosch Frank 	expect_pgm_int();
9747df95c7SJanosch Frank 	asm volatile("spka	0xf0(0)\n");
9847df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
9947df95c7SJanosch Frank 	report_prefix_pop();
10047df95c7SJanosch Frank }
10147df95c7SJanosch Frank 
10247df95c7SJanosch Frank static void test_tprot(void)
10347df95c7SJanosch Frank {
10447df95c7SJanosch Frank 	report_prefix_push("tprot");
10547df95c7SJanosch Frank 	expect_pgm_int();
10647df95c7SJanosch Frank 	asm volatile("tprot	%[addr],0xf0(0)\n"
10747df95c7SJanosch Frank 		     : : [addr] "a" (pagebuf) : );
10847df95c7SJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
10947df95c7SJanosch Frank 	report_prefix_pop();
11047df95c7SJanosch Frank }
11147df95c7SJanosch Frank 
112787d1bccSJanosch Frank static void wait_for_flag(void)
113787d1bccSJanosch Frank {
114787d1bccSJanosch Frank 	while (!testflag)
115787d1bccSJanosch Frank 		mb();
116787d1bccSJanosch Frank }
117787d1bccSJanosch Frank 
118787d1bccSJanosch Frank static void set_flag(int val)
119787d1bccSJanosch Frank {
120787d1bccSJanosch Frank 	mb();
121787d1bccSJanosch Frank 	testflag = val;
122787d1bccSJanosch Frank 	mb();
123787d1bccSJanosch Frank }
124787d1bccSJanosch Frank 
125787d1bccSJanosch Frank static void ecall_cleanup(void)
126787d1bccSJanosch Frank {
127787d1bccSJanosch Frank 	struct lowcore *lc = (void *)0x0;
128787d1bccSJanosch Frank 
12944026818SJanosch Frank 	lc->ext_new_psw.mask = PSW_MASK_64;
130*d34d3250SJanosch Frank 	lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP);
131787d1bccSJanosch Frank 
132787d1bccSJanosch Frank 	/*
133787d1bccSJanosch Frank 	 * PGM old contains the ext new PSW, we need to clean it up,
134787d1bccSJanosch Frank 	 * so we don't get a special operation exception on the lpswe
135787d1bccSJanosch Frank 	 * of pgm old.
136787d1bccSJanosch Frank 	 */
13744026818SJanosch Frank 	lc->pgm_old_psw.mask = PSW_MASK_64;
138787d1bccSJanosch Frank 
139787d1bccSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
140787d1bccSJanosch Frank 	set_flag(1);
141787d1bccSJanosch Frank }
142787d1bccSJanosch Frank 
143787d1bccSJanosch Frank /* Set a key into the external new psw mask and open external call masks */
144787d1bccSJanosch Frank static void ecall_setup(void)
145787d1bccSJanosch Frank {
146787d1bccSJanosch Frank 	struct lowcore *lc = (void *)0x0;
147787d1bccSJanosch Frank 	uint64_t mask;
148787d1bccSJanosch Frank 
149787d1bccSJanosch Frank 	register_pgm_cleanup_func(ecall_cleanup);
150787d1bccSJanosch Frank 	expect_pgm_int();
151787d1bccSJanosch Frank 	/* Put a skey into the ext new psw */
15244026818SJanosch Frank 	lc->ext_new_psw.mask = 0x00F0000000000000UL | PSW_MASK_64;
153787d1bccSJanosch Frank 	/* Open up ext masks */
1541b2c0437SClaudio Imbrenda 	ctl_set_bit(0, CTL0_EXTERNAL_CALL);
155787d1bccSJanosch Frank 	mask = extract_psw_mask();
156787d1bccSJanosch Frank 	mask |= PSW_MASK_EXT;
157787d1bccSJanosch Frank 	load_psw_mask(mask);
158787d1bccSJanosch Frank 	/* Tell cpu 0 that we're ready */
159787d1bccSJanosch Frank 	set_flag(1);
160787d1bccSJanosch Frank }
161787d1bccSJanosch Frank 
162787d1bccSJanosch Frank static void test_exception_ext_new(void)
163787d1bccSJanosch Frank {
164787d1bccSJanosch Frank 	struct psw psw = {
165787d1bccSJanosch Frank 		.mask = extract_psw_mask(),
166787d1bccSJanosch Frank 		.addr = (unsigned long)ecall_setup
167787d1bccSJanosch Frank 	};
168787d1bccSJanosch Frank 
169787d1bccSJanosch Frank 	report_prefix_push("exception external new");
170787d1bccSJanosch Frank 	if (smp_query_num_cpus() < 2) {
171787d1bccSJanosch Frank 		report_skip("Need second cpu for exception external new test.");
172787d1bccSJanosch Frank 		report_prefix_pop();
173787d1bccSJanosch Frank 		return;
174787d1bccSJanosch Frank 	}
175787d1bccSJanosch Frank 
176787d1bccSJanosch Frank 	smp_cpu_setup(1, psw);
177787d1bccSJanosch Frank 	wait_for_flag();
178787d1bccSJanosch Frank 	set_flag(0);
179787d1bccSJanosch Frank 
180787d1bccSJanosch Frank 	sigp(1, SIGP_EXTERNAL_CALL, 0, NULL);
181787d1bccSJanosch Frank 	wait_for_flag();
182787d1bccSJanosch Frank 	smp_cpu_stop(1);
183787d1bccSJanosch Frank 	report_prefix_pop();
184787d1bccSJanosch Frank }
185787d1bccSJanosch Frank 
18647df95c7SJanosch Frank int main(void)
18747df95c7SJanosch Frank {
18847df95c7SJanosch Frank 	report_prefix_push("skrf");
18947df95c7SJanosch Frank 	if (!test_facility(169)) {
19047df95c7SJanosch Frank 		report_skip("storage key removal facility not available\n");
19147df95c7SJanosch Frank 		goto done;
19247df95c7SJanosch Frank 	}
19347df95c7SJanosch Frank 
19447df95c7SJanosch Frank 	test_facilities();
19547df95c7SJanosch Frank 	test_skey();
19647df95c7SJanosch Frank 	test_pfmf();
19747df95c7SJanosch Frank 	test_psw_key();
19847df95c7SJanosch Frank 	test_mvcos();
19947df95c7SJanosch Frank 	test_spka();
20047df95c7SJanosch Frank 	test_tprot();
201787d1bccSJanosch Frank 	test_exception_ext_new();
20247df95c7SJanosch Frank 
20347df95c7SJanosch Frank done:
20447df95c7SJanosch Frank 	report_prefix_pop();
20547df95c7SJanosch Frank 	return report_summary();
20647df95c7SJanosch Frank }
207