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