xref: /kvm-unit-tests/s390x/skey.c (revision 6c3882f69fe90b563cb0efce1ad67868109ef775)
1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2f6b354fbSJanosch Frank /*
3f6b354fbSJanosch Frank  * Storage key tests
4f6b354fbSJanosch Frank  *
5f6b354fbSJanosch Frank  * Copyright (c) 2018 IBM Corp
6f6b354fbSJanosch Frank  *
7f6b354fbSJanosch Frank  * Authors:
8f6b354fbSJanosch Frank  *  Janosch Frank <frankja@linux.vnet.ibm.com>
9f6b354fbSJanosch Frank  */
10f6b354fbSJanosch Frank #include <libcflat.h>
11b02598aeSJanis Schoetterl-Glausch #include <asm/arch_def.h>
12f6b354fbSJanosch Frank #include <asm/asm-offsets.h>
13f6b354fbSJanosch Frank #include <asm/interrupt.h>
1466abce92SJanis Schoetterl-Glausch #include <vmalloc.h>
15*6c3882f6SJanis Schoetterl-Glausch #include <css.h>
16f6b354fbSJanosch Frank #include <asm/page.h>
17f6b354fbSJanosch Frank #include <asm/facility.h>
18f6b354fbSJanosch Frank #include <asm/mem.h>
19f6b354fbSJanosch Frank 
20f6b354fbSJanosch Frank 
21f6b354fbSJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
22f6b354fbSJanosch Frank 
23f6b354fbSJanosch Frank static void test_set_mb(void)
24f6b354fbSJanosch Frank {
25f6b354fbSJanosch Frank 	union skey skey, ret1, ret2;
267b9ca995SJanosch Frank 	void *addr = (void *)0x10000 - 2 * PAGE_SIZE;
277b9ca995SJanosch Frank 	void *end = (void *)0x10000;
28f6b354fbSJanosch Frank 
29f6b354fbSJanosch Frank 	/* Multi block support came with EDAT 1 */
30f6b354fbSJanosch Frank 	if (!test_facility(8))
31f6b354fbSJanosch Frank 		return;
32f6b354fbSJanosch Frank 
33f6b354fbSJanosch Frank 	skey.val = 0x30;
34f6b354fbSJanosch Frank 	while (addr < end)
35f6b354fbSJanosch Frank 		addr = set_storage_key_mb(addr, skey.val);
36f6b354fbSJanosch Frank 
37d0bfafdfSJanosch Frank 	ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP);
38d0bfafdfSJanosch Frank 	ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP);
39a299895bSThomas Huth 	report(ret1.val == ret2.val && ret1.val == skey.val, "multi block");
40f6b354fbSJanosch Frank }
41f6b354fbSJanosch Frank 
42f6b354fbSJanosch Frank static void test_chg(void)
43f6b354fbSJanosch Frank {
44f6b354fbSJanosch Frank 	union skey skey1, skey2;
45f6b354fbSJanosch Frank 
46f6b354fbSJanosch Frank 	skey1.val = 0x30;
477b9ca995SJanosch Frank 	set_storage_key(pagebuf, skey1.val, 0);
487b9ca995SJanosch Frank 	skey1.val = get_storage_key(pagebuf);
49f6b354fbSJanosch Frank 	pagebuf[0] = 3;
507b9ca995SJanosch Frank 	skey2.val = get_storage_key(pagebuf);
51a299895bSThomas Huth 	report(!skey1.str.ch && skey2.str.ch, "chg bit test");
52f6b354fbSJanosch Frank }
53f6b354fbSJanosch Frank 
54f6b354fbSJanosch Frank static void test_set(void)
55f6b354fbSJanosch Frank {
56f6b354fbSJanosch Frank 	union skey skey, ret;
57f6b354fbSJanosch Frank 
58f6b354fbSJanosch Frank 	skey.val = 0x30;
597b9ca995SJanosch Frank 	ret.val = get_storage_key(pagebuf);
607b9ca995SJanosch Frank 	set_storage_key(pagebuf, skey.val, 0);
617b9ca995SJanosch Frank 	ret.val = get_storage_key(pagebuf);
62d0bfafdfSJanosch Frank 	/*
63d0bfafdfSJanosch Frank 	 * For all set tests we only test the ACC and FP bits. RF and
64d0bfafdfSJanosch Frank 	 * CH are set by the machine for memory references and changes
65d0bfafdfSJanosch Frank 	 * and hence might change between a set and a get.
66d0bfafdfSJanosch Frank 	 */
67a299895bSThomas Huth 	report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp,
68a299895bSThomas Huth 	       "set key test");
69f6b354fbSJanosch Frank }
70f6b354fbSJanosch Frank 
71f6b354fbSJanosch Frank static void test_priv(void)
72f6b354fbSJanosch Frank {
73f6b354fbSJanosch Frank 	union skey skey;
74f6b354fbSJanosch Frank 
75f6b354fbSJanosch Frank 	memset(pagebuf, 0, PAGE_SIZE * 2);
76e4654a1bSJanosch Frank 	report_prefix_push("privileged");
77e4654a1bSJanosch Frank 	report_prefix_push("sske");
78f6b354fbSJanosch Frank 	expect_pgm_int();
79f6b354fbSJanosch Frank 	enter_pstate();
807b9ca995SJanosch Frank 	set_storage_key(pagebuf, 0x30, 0);
81f6b354fbSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
82e4654a1bSJanosch Frank 	report_prefix_pop();
83f6b354fbSJanosch Frank 
847b9ca995SJanosch Frank 	skey.val = get_storage_key(pagebuf);
85a299895bSThomas Huth 	report(skey.str.acc != 3, "skey did not change on exception");
86f6b354fbSJanosch Frank 
87e4654a1bSJanosch Frank 	report_prefix_push("iske");
88f6b354fbSJanosch Frank 	expect_pgm_int();
89f6b354fbSJanosch Frank 	enter_pstate();
907b9ca995SJanosch Frank 	get_storage_key(pagebuf);
91f6b354fbSJanosch Frank 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
92e4654a1bSJanosch Frank 	report_prefix_pop();
93e4654a1bSJanosch Frank 
94e4654a1bSJanosch Frank 	report_prefix_pop();
95f6b354fbSJanosch Frank }
96f6b354fbSJanosch Frank 
97429c9cc2SDavid Hildenbrand static void test_invalid_address(void)
98429c9cc2SDavid Hildenbrand {
99429c9cc2SDavid Hildenbrand 	void *inv_addr = (void *)-1ull;
100429c9cc2SDavid Hildenbrand 
101429c9cc2SDavid Hildenbrand 	report_prefix_push("invalid address");
102429c9cc2SDavid Hildenbrand 
103429c9cc2SDavid Hildenbrand 	report_prefix_push("sske");
104429c9cc2SDavid Hildenbrand 	expect_pgm_int();
105429c9cc2SDavid Hildenbrand 	set_storage_key(inv_addr, 0, 0);
106429c9cc2SDavid Hildenbrand 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
107429c9cc2SDavid Hildenbrand 	report_prefix_pop();
108429c9cc2SDavid Hildenbrand 
109429c9cc2SDavid Hildenbrand 	report_prefix_push("iske");
110429c9cc2SDavid Hildenbrand 	expect_pgm_int();
111429c9cc2SDavid Hildenbrand 	get_storage_key(inv_addr);
112429c9cc2SDavid Hildenbrand 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
113429c9cc2SDavid Hildenbrand 	report_prefix_pop();
114429c9cc2SDavid Hildenbrand 
115429c9cc2SDavid Hildenbrand 	report_prefix_push("rrbe");
116429c9cc2SDavid Hildenbrand 	expect_pgm_int();
117429c9cc2SDavid Hildenbrand 	reset_reference_bit(inv_addr);
118429c9cc2SDavid Hildenbrand 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
119429c9cc2SDavid Hildenbrand 	report_prefix_pop();
120429c9cc2SDavid Hildenbrand 
121429c9cc2SDavid Hildenbrand 	report_prefix_pop();
122429c9cc2SDavid Hildenbrand }
123429c9cc2SDavid Hildenbrand 
12466abce92SJanis Schoetterl-Glausch static void test_test_protection(void)
12566abce92SJanis Schoetterl-Glausch {
12666abce92SJanis Schoetterl-Glausch 	unsigned long addr = (unsigned long)pagebuf;
12766abce92SJanis Schoetterl-Glausch 
12866abce92SJanis Schoetterl-Glausch 	report_prefix_push("TPROT");
12966abce92SJanis Schoetterl-Glausch 
13066abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x10, 0);
13166abce92SJanis Schoetterl-Glausch 	report(tprot(addr, 0) == TPROT_READ_WRITE, "zero key: no protection");
13266abce92SJanis Schoetterl-Glausch 	report(tprot(addr, 1) == TPROT_READ_WRITE, "matching key: no protection");
13366abce92SJanis Schoetterl-Glausch 
13466abce92SJanis Schoetterl-Glausch 	report_prefix_push("mismatching key");
13566abce92SJanis Schoetterl-Glausch 
13666abce92SJanis Schoetterl-Glausch 	report(tprot(addr, 2) == TPROT_READ, "no fetch protection: store protection");
13766abce92SJanis Schoetterl-Glausch 
13866abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x18, 0);
13966abce92SJanis Schoetterl-Glausch 	report(tprot(addr, 2) == TPROT_RW_PROTECTED,
14066abce92SJanis Schoetterl-Glausch 	       "fetch protection: fetch & store protection");
14166abce92SJanis Schoetterl-Glausch 
14266abce92SJanis Schoetterl-Glausch 	report_prefix_push("fetch-protection override");
14366abce92SJanis Schoetterl-Glausch 	set_storage_key(0, 0x18, 0);
14466abce92SJanis Schoetterl-Glausch 	report(tprot(0, 2) == TPROT_RW_PROTECTED, "disabled: fetch & store protection");
14566abce92SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
14666abce92SJanis Schoetterl-Glausch 	report(tprot(0, 2) == TPROT_READ, "enabled: store protection");
14766abce92SJanis Schoetterl-Glausch 	report(tprot(2048, 2) == TPROT_RW_PROTECTED, "invalid: fetch & store protection");
14866abce92SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
14966abce92SJanis Schoetterl-Glausch 	set_storage_key(0, 0x00, 0);
15066abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
15166abce92SJanis Schoetterl-Glausch 
15266abce92SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
15366abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x90, 0);
15466abce92SJanis Schoetterl-Glausch 	report(tprot(addr, 2) == TPROT_READ_WRITE,
15566abce92SJanis Schoetterl-Glausch 	       "storage-protection override: no protection");
15666abce92SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
15766abce92SJanis Schoetterl-Glausch 
15866abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
15966abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x00, 0);
16066abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
16166abce92SJanis Schoetterl-Glausch }
16266abce92SJanis Schoetterl-Glausch 
163b02598aeSJanis Schoetterl-Glausch enum access {
164b02598aeSJanis Schoetterl-Glausch 	ACC_STORE = 1,
165b02598aeSJanis Schoetterl-Glausch 	ACC_FETCH = 2,
166b02598aeSJanis Schoetterl-Glausch 	ACC_UPDATE = 3,
167b02598aeSJanis Schoetterl-Glausch };
168b02598aeSJanis Schoetterl-Glausch 
169b02598aeSJanis Schoetterl-Glausch enum protection {
170b02598aeSJanis Schoetterl-Glausch 	PROT_STORE = 1,
171b02598aeSJanis Schoetterl-Glausch 	PROT_FETCH_STORE = 3,
172b02598aeSJanis Schoetterl-Glausch };
173b02598aeSJanis Schoetterl-Glausch 
174b02598aeSJanis Schoetterl-Glausch static void check_key_prot_exc(enum access access, enum protection prot)
175b02598aeSJanis Schoetterl-Glausch {
176b02598aeSJanis Schoetterl-Glausch 	union teid teid;
177b02598aeSJanis Schoetterl-Glausch 	int access_code;
178b02598aeSJanis Schoetterl-Glausch 
179b02598aeSJanis Schoetterl-Glausch 	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
180b02598aeSJanis Schoetterl-Glausch 	report_prefix_push("TEID");
181b02598aeSJanis Schoetterl-Glausch 	teid.val = lowcore.trans_exc_id;
182b02598aeSJanis Schoetterl-Glausch 	switch (get_supp_on_prot_facility()) {
183b02598aeSJanis Schoetterl-Glausch 	case SOP_NONE:
184b02598aeSJanis Schoetterl-Glausch 	case SOP_BASIC:
185b02598aeSJanis Schoetterl-Glausch 		/* let's ignore ancient/irrelevant machines */
186b02598aeSJanis Schoetterl-Glausch 		break;
187b02598aeSJanis Schoetterl-Glausch 	case SOP_ENHANCED_1:
188b02598aeSJanis Schoetterl-Glausch 		report(!teid.sop_teid_predictable, "valid protection code");
189b02598aeSJanis Schoetterl-Glausch 		/* no access code in case of key protection */
190b02598aeSJanis Schoetterl-Glausch 		break;
191b02598aeSJanis Schoetterl-Glausch 	case SOP_ENHANCED_2:
192b02598aeSJanis Schoetterl-Glausch 		switch (teid_esop2_prot_code(teid)) {
193b02598aeSJanis Schoetterl-Glausch 		case PROT_KEY:
194b02598aeSJanis Schoetterl-Glausch 			/* ESOP-2: no need to check facility */
195b02598aeSJanis Schoetterl-Glausch 			access_code = teid.acc_exc_fetch_store;
196b02598aeSJanis Schoetterl-Glausch 
197b02598aeSJanis Schoetterl-Glausch 			switch (access_code) {
198b02598aeSJanis Schoetterl-Glausch 			case 0:
199b02598aeSJanis Schoetterl-Glausch 				report_pass("valid access code");
200b02598aeSJanis Schoetterl-Glausch 				break;
201b02598aeSJanis Schoetterl-Glausch 			case 1:
202b02598aeSJanis Schoetterl-Glausch 			case 2:
203b02598aeSJanis Schoetterl-Glausch 				report((access & access_code) && (prot & access_code),
204b02598aeSJanis Schoetterl-Glausch 				       "valid access code");
205b02598aeSJanis Schoetterl-Glausch 				break;
206b02598aeSJanis Schoetterl-Glausch 			case 3:
207b02598aeSJanis Schoetterl-Glausch 				/*
208b02598aeSJanis Schoetterl-Glausch 				 * This is incorrect in that reserved values
209b02598aeSJanis Schoetterl-Glausch 				 * should be ignored, but kvm should not return
210b02598aeSJanis Schoetterl-Glausch 				 * a reserved value and having a test for that
211b02598aeSJanis Schoetterl-Glausch 				 * is more valuable.
212b02598aeSJanis Schoetterl-Glausch 				 */
213b02598aeSJanis Schoetterl-Glausch 				report_fail("valid access code");
214b02598aeSJanis Schoetterl-Glausch 				break;
215b02598aeSJanis Schoetterl-Glausch 			}
216b02598aeSJanis Schoetterl-Glausch 			/* fallthrough */
217b02598aeSJanis Schoetterl-Glausch 		case PROT_KEY_OR_LAP:
218b02598aeSJanis Schoetterl-Glausch 			report_pass("valid protection code");
219b02598aeSJanis Schoetterl-Glausch 			break;
220b02598aeSJanis Schoetterl-Glausch 		default:
221b02598aeSJanis Schoetterl-Glausch 			report_fail("valid protection code");
222b02598aeSJanis Schoetterl-Glausch 		}
223b02598aeSJanis Schoetterl-Glausch 		break;
224b02598aeSJanis Schoetterl-Glausch 	}
225b02598aeSJanis Schoetterl-Glausch 	report_prefix_pop();
226b02598aeSJanis Schoetterl-Glausch }
227b02598aeSJanis Schoetterl-Glausch 
22866abce92SJanis Schoetterl-Glausch /*
22966abce92SJanis Schoetterl-Glausch  * Perform STORE CPU ADDRESS (STAP) instruction while temporarily executing
23066abce92SJanis Schoetterl-Glausch  * with access key 1.
23166abce92SJanis Schoetterl-Glausch  */
23266abce92SJanis Schoetterl-Glausch static void store_cpu_address_key_1(uint16_t *out)
23366abce92SJanis Schoetterl-Glausch {
23466abce92SJanis Schoetterl-Glausch 	asm volatile (
23566abce92SJanis Schoetterl-Glausch 		"spka	0x10\n\t"
23666abce92SJanis Schoetterl-Glausch 		"stap	%0\n\t"
23766abce92SJanis Schoetterl-Glausch 		"spka	0\n"
23866abce92SJanis Schoetterl-Glausch 	     : "+Q" (*out) /* exception: old value remains in out -> + constraint */
23966abce92SJanis Schoetterl-Glausch 	);
24066abce92SJanis Schoetterl-Glausch }
24166abce92SJanis Schoetterl-Glausch 
24266abce92SJanis Schoetterl-Glausch static void test_store_cpu_address(void)
24366abce92SJanis Schoetterl-Glausch {
24466abce92SJanis Schoetterl-Glausch 	uint16_t *out = (uint16_t *)pagebuf;
24566abce92SJanis Schoetterl-Glausch 	uint16_t cpu_addr;
24666abce92SJanis Schoetterl-Glausch 
24766abce92SJanis Schoetterl-Glausch 	report_prefix_push("STORE CPU ADDRESS");
24866abce92SJanis Schoetterl-Glausch 	asm ("stap %0" : "=Q" (cpu_addr));
24966abce92SJanis Schoetterl-Glausch 
25066abce92SJanis Schoetterl-Glausch 	report_prefix_push("zero key");
25166abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x20, 0);
25266abce92SJanis Schoetterl-Glausch 	WRITE_ONCE(*out, 0xbeef);
25366abce92SJanis Schoetterl-Glausch 	asm ("stap %0" : "=Q" (*out));
25466abce92SJanis Schoetterl-Glausch 	report(*out == cpu_addr, "store occurred");
25566abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
25666abce92SJanis Schoetterl-Glausch 
25766abce92SJanis Schoetterl-Glausch 	report_prefix_push("matching key");
25866abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x10, 0);
25966abce92SJanis Schoetterl-Glausch 	*out = 0xbeef;
26066abce92SJanis Schoetterl-Glausch 	store_cpu_address_key_1(out);
26166abce92SJanis Schoetterl-Glausch 	report(*out == cpu_addr, "store occurred");
26266abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
26366abce92SJanis Schoetterl-Glausch 
26466abce92SJanis Schoetterl-Glausch 	report_prefix_push("mismatching key");
26566abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x20, 0);
26666abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
26766abce92SJanis Schoetterl-Glausch 	*out = 0xbeef;
26866abce92SJanis Schoetterl-Glausch 	store_cpu_address_key_1(out);
269b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_STORE, PROT_STORE);
27066abce92SJanis Schoetterl-Glausch 	report(*out == 0xbeef, "no store occurred");
27166abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
27266abce92SJanis Schoetterl-Glausch 
27366abce92SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
27466abce92SJanis Schoetterl-Glausch 
27566abce92SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override, invalid key");
27666abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x20, 0);
27766abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
27866abce92SJanis Schoetterl-Glausch 	*out = 0xbeef;
27966abce92SJanis Schoetterl-Glausch 	store_cpu_address_key_1(out);
280b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_STORE, PROT_STORE);
28166abce92SJanis Schoetterl-Glausch 	report(*out == 0xbeef, "no store occurred");
28266abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
28366abce92SJanis Schoetterl-Glausch 
28466abce92SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override, override key");
28566abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x90, 0);
28666abce92SJanis Schoetterl-Glausch 	*out = 0xbeef;
28766abce92SJanis Schoetterl-Glausch 	store_cpu_address_key_1(out);
28866abce92SJanis Schoetterl-Glausch 	report(*out == cpu_addr, "override occurred");
28966abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
29066abce92SJanis Schoetterl-Glausch 
29166abce92SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
29266abce92SJanis Schoetterl-Glausch 
29366abce92SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override disabled, override key");
29466abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x90, 0);
29566abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
29666abce92SJanis Schoetterl-Glausch 	*out = 0xbeef;
29766abce92SJanis Schoetterl-Glausch 	store_cpu_address_key_1(out);
298b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_STORE, PROT_STORE);
29966abce92SJanis Schoetterl-Glausch 	report(*out == 0xbeef, "no store occurred");
30066abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
30166abce92SJanis Schoetterl-Glausch 
30266abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x00, 0);
30366abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
30466abce92SJanis Schoetterl-Glausch }
30566abce92SJanis Schoetterl-Glausch 
30666abce92SJanis Schoetterl-Glausch /*
307*6c3882f6SJanis Schoetterl-Glausch  * Perform CHANNEL SUBSYSTEM CALL (CHSC)  instruction while temporarily executing
308*6c3882f6SJanis Schoetterl-Glausch  * with access key 1.
309*6c3882f6SJanis Schoetterl-Glausch  */
310*6c3882f6SJanis Schoetterl-Glausch static unsigned int chsc_key_1(void *comm_block)
311*6c3882f6SJanis Schoetterl-Glausch {
312*6c3882f6SJanis Schoetterl-Glausch 	uint32_t program_mask;
313*6c3882f6SJanis Schoetterl-Glausch 
314*6c3882f6SJanis Schoetterl-Glausch 	asm volatile (
315*6c3882f6SJanis Schoetterl-Glausch 		"spka	0x10\n\t"
316*6c3882f6SJanis Schoetterl-Glausch 		".insn	rre,0xb25f0000,%[comm_block],0\n\t"
317*6c3882f6SJanis Schoetterl-Glausch 		"spka	0\n\t"
318*6c3882f6SJanis Schoetterl-Glausch 		"ipm	%[program_mask]\n"
319*6c3882f6SJanis Schoetterl-Glausch 		: [program_mask] "=d" (program_mask)
320*6c3882f6SJanis Schoetterl-Glausch 		: [comm_block] "d" (comm_block)
321*6c3882f6SJanis Schoetterl-Glausch 		: "memory"
322*6c3882f6SJanis Schoetterl-Glausch 	);
323*6c3882f6SJanis Schoetterl-Glausch 	return program_mask >> 28;
324*6c3882f6SJanis Schoetterl-Glausch }
325*6c3882f6SJanis Schoetterl-Glausch 
326*6c3882f6SJanis Schoetterl-Glausch static const char chsc_msg[] = "Performed store-channel-subsystem-characteristics";
327*6c3882f6SJanis Schoetterl-Glausch static void init_comm_block(uint16_t *comm_block)
328*6c3882f6SJanis Schoetterl-Glausch {
329*6c3882f6SJanis Schoetterl-Glausch 	memset(comm_block, 0, PAGE_SIZE);
330*6c3882f6SJanis Schoetterl-Glausch 	/* store-channel-subsystem-characteristics command */
331*6c3882f6SJanis Schoetterl-Glausch 	comm_block[0] = 0x10;
332*6c3882f6SJanis Schoetterl-Glausch 	comm_block[1] = 0x10;
333*6c3882f6SJanis Schoetterl-Glausch 	comm_block[9] = 0;
334*6c3882f6SJanis Schoetterl-Glausch }
335*6c3882f6SJanis Schoetterl-Glausch 
336*6c3882f6SJanis Schoetterl-Glausch static void test_channel_subsystem_call(void)
337*6c3882f6SJanis Schoetterl-Glausch {
338*6c3882f6SJanis Schoetterl-Glausch 	uint16_t *comm_block = (uint16_t *)&pagebuf;
339*6c3882f6SJanis Schoetterl-Glausch 	unsigned int cc;
340*6c3882f6SJanis Schoetterl-Glausch 
341*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("CHANNEL SUBSYSTEM CALL");
342*6c3882f6SJanis Schoetterl-Glausch 
343*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("zero key");
344*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
345*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x10, 0);
346*6c3882f6SJanis Schoetterl-Glausch 	asm volatile (
347*6c3882f6SJanis Schoetterl-Glausch 		".insn	rre,0xb25f0000,%[comm_block],0\n\t"
348*6c3882f6SJanis Schoetterl-Glausch 		"ipm	%[cc]\n"
349*6c3882f6SJanis Schoetterl-Glausch 		: [cc] "=d" (cc)
350*6c3882f6SJanis Schoetterl-Glausch 		: [comm_block] "d" (comm_block)
351*6c3882f6SJanis Schoetterl-Glausch 		: "memory"
352*6c3882f6SJanis Schoetterl-Glausch 	);
353*6c3882f6SJanis Schoetterl-Glausch 	cc = cc >> 28;
354*6c3882f6SJanis Schoetterl-Glausch 	report(cc == 0 && comm_block[9], chsc_msg);
355*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
356*6c3882f6SJanis Schoetterl-Glausch 
357*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("matching key");
358*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
359*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x10, 0);
360*6c3882f6SJanis Schoetterl-Glausch 	cc = chsc_key_1(comm_block);
361*6c3882f6SJanis Schoetterl-Glausch 	report(cc == 0 && comm_block[9], chsc_msg);
362*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
363*6c3882f6SJanis Schoetterl-Glausch 
364*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("mismatching key");
365*6c3882f6SJanis Schoetterl-Glausch 
366*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("no fetch protection");
367*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
368*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x20, 0);
369*6c3882f6SJanis Schoetterl-Glausch 	expect_pgm_int();
370*6c3882f6SJanis Schoetterl-Glausch 	chsc_key_1(comm_block);
371*6c3882f6SJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_UPDATE, PROT_STORE);
372*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
373*6c3882f6SJanis Schoetterl-Glausch 
374*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("fetch protection");
375*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
376*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x28, 0);
377*6c3882f6SJanis Schoetterl-Glausch 	expect_pgm_int();
378*6c3882f6SJanis Schoetterl-Glausch 	chsc_key_1(comm_block);
379*6c3882f6SJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_UPDATE, PROT_FETCH_STORE);
380*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
381*6c3882f6SJanis Schoetterl-Glausch 
382*6c3882f6SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
383*6c3882f6SJanis Schoetterl-Glausch 
384*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override, invalid key");
385*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x20, 0);
386*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
387*6c3882f6SJanis Schoetterl-Glausch 	expect_pgm_int();
388*6c3882f6SJanis Schoetterl-Glausch 	chsc_key_1(comm_block);
389*6c3882f6SJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_UPDATE, PROT_STORE);
390*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
391*6c3882f6SJanis Schoetterl-Glausch 
392*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override, override key");
393*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
394*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x90, 0);
395*6c3882f6SJanis Schoetterl-Glausch 	cc = chsc_key_1(comm_block);
396*6c3882f6SJanis Schoetterl-Glausch 	report(cc == 0 && comm_block[9], chsc_msg);
397*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
398*6c3882f6SJanis Schoetterl-Glausch 
399*6c3882f6SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
400*6c3882f6SJanis Schoetterl-Glausch 
401*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("storage-protection override disabled, override key");
402*6c3882f6SJanis Schoetterl-Glausch 	init_comm_block(comm_block);
403*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x90, 0);
404*6c3882f6SJanis Schoetterl-Glausch 	expect_pgm_int();
405*6c3882f6SJanis Schoetterl-Glausch 	chsc_key_1(comm_block);
406*6c3882f6SJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_UPDATE, PROT_STORE);
407*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
408*6c3882f6SJanis Schoetterl-Glausch 
409*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
410*6c3882f6SJanis Schoetterl-Glausch 
411*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(comm_block, 0x00, 0);
412*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
413*6c3882f6SJanis Schoetterl-Glausch }
414*6c3882f6SJanis Schoetterl-Glausch 
415*6c3882f6SJanis Schoetterl-Glausch /*
41666abce92SJanis Schoetterl-Glausch  * Perform SET PREFIX (SPX) instruction while temporarily executing
41766abce92SJanis Schoetterl-Glausch  * with access key 1.
41866abce92SJanis Schoetterl-Glausch  */
41966abce92SJanis Schoetterl-Glausch static void set_prefix_key_1(uint32_t *prefix_ptr)
42066abce92SJanis Schoetterl-Glausch {
42166abce92SJanis Schoetterl-Glausch 	asm volatile (
42266abce92SJanis Schoetterl-Glausch 		"spka	0x10\n\t"
42366abce92SJanis Schoetterl-Glausch 		"spx	%0\n\t"
42466abce92SJanis Schoetterl-Glausch 		"spka	0\n"
42566abce92SJanis Schoetterl-Glausch 	     :: "Q" (*prefix_ptr)
42666abce92SJanis Schoetterl-Glausch 	);
42766abce92SJanis Schoetterl-Glausch }
42866abce92SJanis Schoetterl-Glausch 
42966abce92SJanis Schoetterl-Glausch /*
43066abce92SJanis Schoetterl-Glausch  * We remapped page 0, making the lowcore inaccessible, which breaks the normal
43166abce92SJanis Schoetterl-Glausch  * handler and breaks skipping the faulting instruction.
43266abce92SJanis Schoetterl-Glausch  * Just disable dynamic address translation to make things work.
43366abce92SJanis Schoetterl-Glausch  */
43466abce92SJanis Schoetterl-Glausch static void dat_fixup_pgm_int(void)
43566abce92SJanis Schoetterl-Glausch {
43666abce92SJanis Schoetterl-Glausch 	uint64_t psw_mask = extract_psw_mask();
43766abce92SJanis Schoetterl-Glausch 
43866abce92SJanis Schoetterl-Glausch 	psw_mask &= ~PSW_MASK_DAT;
43966abce92SJanis Schoetterl-Glausch 	load_psw_mask(psw_mask);
44066abce92SJanis Schoetterl-Glausch }
44166abce92SJanis Schoetterl-Glausch 
44266abce92SJanis Schoetterl-Glausch #define PREFIX_AREA_SIZE (PAGE_SIZE * 2)
44366abce92SJanis Schoetterl-Glausch static char lowcore_tmp[PREFIX_AREA_SIZE] __attribute__((aligned(PREFIX_AREA_SIZE)));
44466abce92SJanis Schoetterl-Glausch 
44566abce92SJanis Schoetterl-Glausch /*
44666abce92SJanis Schoetterl-Glausch  * Test accessibility of the operand to SET PREFIX given different configurations
44766abce92SJanis Schoetterl-Glausch  * with regards to storage keys. That is, check the accessibility of the location
44866abce92SJanis Schoetterl-Glausch  * holding the new prefix, not that of the new prefix area. The new prefix area
44966abce92SJanis Schoetterl-Glausch  * is a valid lowcore, so that the test does not crash on failure.
45066abce92SJanis Schoetterl-Glausch  */
45166abce92SJanis Schoetterl-Glausch static void test_set_prefix(void)
45266abce92SJanis Schoetterl-Glausch {
45366abce92SJanis Schoetterl-Glausch 	uint32_t *prefix_ptr = (uint32_t *)pagebuf;
45466abce92SJanis Schoetterl-Glausch 	uint32_t *no_override_prefix_ptr;
45566abce92SJanis Schoetterl-Glausch 	uint32_t old_prefix;
45666abce92SJanis Schoetterl-Glausch 	pgd_t *root;
45766abce92SJanis Schoetterl-Glausch 
45866abce92SJanis Schoetterl-Glausch 	report_prefix_push("SET PREFIX");
45966abce92SJanis Schoetterl-Glausch 	root = (pgd_t *)(stctg(1) & PAGE_MASK);
46066abce92SJanis Schoetterl-Glausch 	old_prefix = get_prefix();
46166abce92SJanis Schoetterl-Glausch 	memcpy(lowcore_tmp, 0, sizeof(lowcore_tmp));
46266abce92SJanis Schoetterl-Glausch 	assert(((uint64_t)&lowcore_tmp >> 31) == 0);
46366abce92SJanis Schoetterl-Glausch 	*prefix_ptr = (uint32_t)(uint64_t)&lowcore_tmp;
46466abce92SJanis Schoetterl-Glausch 
46566abce92SJanis Schoetterl-Glausch 	report_prefix_push("zero key");
46666abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
46766abce92SJanis Schoetterl-Glausch 	set_storage_key(prefix_ptr, 0x20, 0);
46866abce92SJanis Schoetterl-Glausch 	set_prefix(*prefix_ptr);
46966abce92SJanis Schoetterl-Glausch 	report(get_prefix() == *prefix_ptr, "set prefix");
47066abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
47166abce92SJanis Schoetterl-Glausch 
47266abce92SJanis Schoetterl-Glausch 	report_prefix_push("matching key");
47366abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
47466abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x10, 0);
47566abce92SJanis Schoetterl-Glausch 	set_prefix_key_1(prefix_ptr);
47666abce92SJanis Schoetterl-Glausch 	report(get_prefix() == *prefix_ptr, "set prefix");
47766abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
47866abce92SJanis Schoetterl-Glausch 
47966abce92SJanis Schoetterl-Glausch 	report_prefix_push("mismatching key");
48066abce92SJanis Schoetterl-Glausch 
48166abce92SJanis Schoetterl-Glausch 	report_prefix_push("no fetch protection");
48266abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
48366abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x20, 0);
48466abce92SJanis Schoetterl-Glausch 	set_prefix_key_1(prefix_ptr);
48566abce92SJanis Schoetterl-Glausch 	report(get_prefix() == *prefix_ptr, "set prefix");
48666abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
48766abce92SJanis Schoetterl-Glausch 
48866abce92SJanis Schoetterl-Glausch 	report_prefix_push("fetch protection");
48966abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
49066abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x28, 0);
49166abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
49266abce92SJanis Schoetterl-Glausch 	set_prefix_key_1(prefix_ptr);
493b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
49466abce92SJanis Schoetterl-Glausch 	report(get_prefix() == old_prefix, "did not set prefix");
49566abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
49666abce92SJanis Schoetterl-Glausch 
49766abce92SJanis Schoetterl-Glausch 	register_pgm_cleanup_func(dat_fixup_pgm_int);
49866abce92SJanis Schoetterl-Glausch 
49966abce92SJanis Schoetterl-Glausch 	report_prefix_push("remapped page, fetch protection");
50066abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
50166abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x28, 0);
50266abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
50366abce92SJanis Schoetterl-Glausch 	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
50466abce92SJanis Schoetterl-Glausch 	set_prefix_key_1((uint32_t *)0);
50566abce92SJanis Schoetterl-Glausch 	install_page(root, 0, 0);
506b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
50766abce92SJanis Schoetterl-Glausch 	report(get_prefix() == old_prefix, "did not set prefix");
50866abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
50966abce92SJanis Schoetterl-Glausch 
51066abce92SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
51166abce92SJanis Schoetterl-Glausch 
51266abce92SJanis Schoetterl-Glausch 	report_prefix_push("fetch protection override applies");
51366abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
51466abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x28, 0);
51566abce92SJanis Schoetterl-Glausch 	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
51666abce92SJanis Schoetterl-Glausch 	set_prefix_key_1((uint32_t *)0);
51766abce92SJanis Schoetterl-Glausch 	install_page(root, 0, 0);
51866abce92SJanis Schoetterl-Glausch 	report(get_prefix() == *prefix_ptr, "set prefix");
51966abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
52066abce92SJanis Schoetterl-Glausch 
52166abce92SJanis Schoetterl-Glausch 	no_override_prefix_ptr = (uint32_t *)(pagebuf + 2048);
52266abce92SJanis Schoetterl-Glausch 	WRITE_ONCE(*no_override_prefix_ptr, (uint32_t)(uint64_t)&lowcore_tmp);
52366abce92SJanis Schoetterl-Glausch 	report_prefix_push("fetch protection override does not apply");
52466abce92SJanis Schoetterl-Glausch 	set_prefix(old_prefix);
52566abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x28, 0);
52666abce92SJanis Schoetterl-Glausch 	expect_pgm_int();
52766abce92SJanis Schoetterl-Glausch 	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
5285af83aa8SJanis Schoetterl-Glausch 	set_prefix_key_1(OPAQUE_PTR(2048));
52966abce92SJanis Schoetterl-Glausch 	install_page(root, 0, 0);
530b02598aeSJanis Schoetterl-Glausch 	check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
53166abce92SJanis Schoetterl-Glausch 	report(get_prefix() == old_prefix, "did not set prefix");
53266abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
53366abce92SJanis Schoetterl-Glausch 
53466abce92SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
53566abce92SJanis Schoetterl-Glausch 	register_pgm_cleanup_func(NULL);
53666abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
53766abce92SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x00, 0);
53866abce92SJanis Schoetterl-Glausch 	report_prefix_pop();
53966abce92SJanis Schoetterl-Glausch }
54066abce92SJanis Schoetterl-Glausch 
541*6c3882f6SJanis Schoetterl-Glausch /*
542*6c3882f6SJanis Schoetterl-Glausch  * Perform MODIFY SUBCHANNEL (MSCH) instruction while temporarily executing
543*6c3882f6SJanis Schoetterl-Glausch  * with access key 1.
544*6c3882f6SJanis Schoetterl-Glausch  */
545*6c3882f6SJanis Schoetterl-Glausch static uint32_t modify_subchannel_key_1(uint32_t sid, struct schib *schib)
546*6c3882f6SJanis Schoetterl-Glausch {
547*6c3882f6SJanis Schoetterl-Glausch 	uint32_t program_mask;
548*6c3882f6SJanis Schoetterl-Glausch 
549*6c3882f6SJanis Schoetterl-Glausch 	asm volatile (
550*6c3882f6SJanis Schoetterl-Glausch 		"lr %%r1,%[sid]\n\t"
551*6c3882f6SJanis Schoetterl-Glausch 		"spka	0x10\n\t"
552*6c3882f6SJanis Schoetterl-Glausch 		"msch	%[schib]\n\t"
553*6c3882f6SJanis Schoetterl-Glausch 		"spka	0\n\t"
554*6c3882f6SJanis Schoetterl-Glausch 		"ipm	%[program_mask]\n"
555*6c3882f6SJanis Schoetterl-Glausch 		: [program_mask] "=d" (program_mask)
556*6c3882f6SJanis Schoetterl-Glausch 		: [sid] "d" (sid),
557*6c3882f6SJanis Schoetterl-Glausch 		  [schib] "Q" (*schib)
558*6c3882f6SJanis Schoetterl-Glausch 		: "%r1"
559*6c3882f6SJanis Schoetterl-Glausch 	);
560*6c3882f6SJanis Schoetterl-Glausch 	return program_mask >> 28;
561*6c3882f6SJanis Schoetterl-Glausch }
562*6c3882f6SJanis Schoetterl-Glausch 
563*6c3882f6SJanis Schoetterl-Glausch static void test_msch(void)
564*6c3882f6SJanis Schoetterl-Glausch {
565*6c3882f6SJanis Schoetterl-Glausch 	struct schib *schib = (struct schib *)pagebuf;
566*6c3882f6SJanis Schoetterl-Glausch 	struct schib *no_override_schib;
567*6c3882f6SJanis Schoetterl-Glausch 	int test_device_sid;
568*6c3882f6SJanis Schoetterl-Glausch 	pgd_t *root;
569*6c3882f6SJanis Schoetterl-Glausch 	int cc;
570*6c3882f6SJanis Schoetterl-Glausch 
571*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("MSCH");
572*6c3882f6SJanis Schoetterl-Glausch 	root = (pgd_t *)(stctg(1) & PAGE_MASK);
573*6c3882f6SJanis Schoetterl-Glausch 	test_device_sid = css_enumerate();
574*6c3882f6SJanis Schoetterl-Glausch 
575*6c3882f6SJanis Schoetterl-Glausch 	if (!(test_device_sid & SCHID_ONE)) {
576*6c3882f6SJanis Schoetterl-Glausch 		report_fail("no I/O device found");
577*6c3882f6SJanis Schoetterl-Glausch 		return;
578*6c3882f6SJanis Schoetterl-Glausch 	}
579*6c3882f6SJanis Schoetterl-Glausch 
580*6c3882f6SJanis Schoetterl-Glausch 	cc = stsch(test_device_sid, schib);
581*6c3882f6SJanis Schoetterl-Glausch 	if (cc) {
582*6c3882f6SJanis Schoetterl-Glausch 		report_fail("could not store SCHIB");
583*6c3882f6SJanis Schoetterl-Glausch 		return;
584*6c3882f6SJanis Schoetterl-Glausch 	}
585*6c3882f6SJanis Schoetterl-Glausch 
586*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("zero key");
587*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 100;
588*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(schib, 0x28, 0);
589*6c3882f6SJanis Schoetterl-Glausch 	cc = msch(test_device_sid, schib);
590*6c3882f6SJanis Schoetterl-Glausch 	if (!cc) {
591*6c3882f6SJanis Schoetterl-Glausch 		WRITE_ONCE(schib->pmcw.intparm, 0);
592*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
593*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 100, "fetched from SCHIB");
594*6c3882f6SJanis Schoetterl-Glausch 	} else {
595*6c3882f6SJanis Schoetterl-Glausch 		report_fail("MSCH cc != 0");
596*6c3882f6SJanis Schoetterl-Glausch 	}
597*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
598*6c3882f6SJanis Schoetterl-Glausch 
599*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("matching key");
600*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 200;
601*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(schib, 0x18, 0);
602*6c3882f6SJanis Schoetterl-Glausch 	cc = modify_subchannel_key_1(test_device_sid, schib);
603*6c3882f6SJanis Schoetterl-Glausch 	if (!cc) {
604*6c3882f6SJanis Schoetterl-Glausch 		WRITE_ONCE(schib->pmcw.intparm, 0);
605*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
606*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 200, "fetched from SCHIB");
607*6c3882f6SJanis Schoetterl-Glausch 	} else {
608*6c3882f6SJanis Schoetterl-Glausch 		report_fail("MSCH cc != 0");
609*6c3882f6SJanis Schoetterl-Glausch 	}
610*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
611*6c3882f6SJanis Schoetterl-Glausch 
612*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("mismatching key");
613*6c3882f6SJanis Schoetterl-Glausch 
614*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("no fetch protection");
615*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 300;
616*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(schib, 0x20, 0);
617*6c3882f6SJanis Schoetterl-Glausch 	cc = modify_subchannel_key_1(test_device_sid, schib);
618*6c3882f6SJanis Schoetterl-Glausch 	if (!cc) {
619*6c3882f6SJanis Schoetterl-Glausch 		WRITE_ONCE(schib->pmcw.intparm, 0);
620*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
621*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 300, "fetched from SCHIB");
622*6c3882f6SJanis Schoetterl-Glausch 	} else {
623*6c3882f6SJanis Schoetterl-Glausch 		report_fail("MSCH cc != 0");
624*6c3882f6SJanis Schoetterl-Glausch 	}
625*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
626*6c3882f6SJanis Schoetterl-Glausch 
627*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 0;
628*6c3882f6SJanis Schoetterl-Glausch 	if (!msch(test_device_sid, schib)) {
629*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_push("fetch protection");
630*6c3882f6SJanis Schoetterl-Glausch 		schib->pmcw.intparm = 400;
631*6c3882f6SJanis Schoetterl-Glausch 		set_storage_key(schib, 0x28, 0);
632*6c3882f6SJanis Schoetterl-Glausch 		expect_pgm_int();
633*6c3882f6SJanis Schoetterl-Glausch 		modify_subchannel_key_1(test_device_sid, schib);
634*6c3882f6SJanis Schoetterl-Glausch 		check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
635*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
636*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel");
637*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_pop();
638*6c3882f6SJanis Schoetterl-Glausch 	} else {
639*6c3882f6SJanis Schoetterl-Glausch 		report_fail("could not reset SCHIB");
640*6c3882f6SJanis Schoetterl-Glausch 	}
641*6c3882f6SJanis Schoetterl-Glausch 
642*6c3882f6SJanis Schoetterl-Glausch 	register_pgm_cleanup_func(dat_fixup_pgm_int);
643*6c3882f6SJanis Schoetterl-Glausch 
644*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 0;
645*6c3882f6SJanis Schoetterl-Glausch 	if (!msch(test_device_sid, schib)) {
646*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_push("remapped page, fetch protection");
647*6c3882f6SJanis Schoetterl-Glausch 		schib->pmcw.intparm = 500;
648*6c3882f6SJanis Schoetterl-Glausch 		set_storage_key(pagebuf, 0x28, 0);
649*6c3882f6SJanis Schoetterl-Glausch 		expect_pgm_int();
650*6c3882f6SJanis Schoetterl-Glausch 		install_page(root, virt_to_pte_phys(root, pagebuf), 0);
651*6c3882f6SJanis Schoetterl-Glausch 		modify_subchannel_key_1(test_device_sid, (struct schib *)0);
652*6c3882f6SJanis Schoetterl-Glausch 		install_page(root, 0, 0);
653*6c3882f6SJanis Schoetterl-Glausch 		check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
654*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
655*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel");
656*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_pop();
657*6c3882f6SJanis Schoetterl-Glausch 	} else {
658*6c3882f6SJanis Schoetterl-Glausch 		report_fail("could not reset SCHIB");
659*6c3882f6SJanis Schoetterl-Glausch 	}
660*6c3882f6SJanis Schoetterl-Glausch 
661*6c3882f6SJanis Schoetterl-Glausch 	ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
662*6c3882f6SJanis Schoetterl-Glausch 
663*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_push("fetch-protection override applies");
664*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 600;
665*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(pagebuf, 0x28, 0);
666*6c3882f6SJanis Schoetterl-Glausch 	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
667*6c3882f6SJanis Schoetterl-Glausch 	cc = modify_subchannel_key_1(test_device_sid, (struct schib *)0);
668*6c3882f6SJanis Schoetterl-Glausch 	install_page(root, 0, 0);
669*6c3882f6SJanis Schoetterl-Glausch 	if (!cc) {
670*6c3882f6SJanis Schoetterl-Glausch 		WRITE_ONCE(schib->pmcw.intparm, 0);
671*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
672*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 600, "fetched from SCHIB");
673*6c3882f6SJanis Schoetterl-Glausch 	} else {
674*6c3882f6SJanis Schoetterl-Glausch 		report_fail("MSCH cc != 0");
675*6c3882f6SJanis Schoetterl-Glausch 	}
676*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
677*6c3882f6SJanis Schoetterl-Glausch 
678*6c3882f6SJanis Schoetterl-Glausch 	schib->pmcw.intparm = 0;
679*6c3882f6SJanis Schoetterl-Glausch 	if (!msch(test_device_sid, schib)) {
680*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_push("fetch-protection override does not apply");
681*6c3882f6SJanis Schoetterl-Glausch 		schib->pmcw.intparm = 700;
682*6c3882f6SJanis Schoetterl-Glausch 		no_override_schib = (struct schib *)(pagebuf + 2048);
683*6c3882f6SJanis Schoetterl-Glausch 		memcpy(no_override_schib, schib, sizeof(struct schib));
684*6c3882f6SJanis Schoetterl-Glausch 		set_storage_key(pagebuf, 0x28, 0);
685*6c3882f6SJanis Schoetterl-Glausch 		expect_pgm_int();
686*6c3882f6SJanis Schoetterl-Glausch 		install_page(root, virt_to_pte_phys(root, pagebuf), 0);
687*6c3882f6SJanis Schoetterl-Glausch 		modify_subchannel_key_1(test_device_sid, OPAQUE_PTR(2048));
688*6c3882f6SJanis Schoetterl-Glausch 		install_page(root, 0, 0);
689*6c3882f6SJanis Schoetterl-Glausch 		check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE);
690*6c3882f6SJanis Schoetterl-Glausch 		cc = stsch(test_device_sid, schib);
691*6c3882f6SJanis Schoetterl-Glausch 		report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel");
692*6c3882f6SJanis Schoetterl-Glausch 		report_prefix_pop();
693*6c3882f6SJanis Schoetterl-Glausch 	} else {
694*6c3882f6SJanis Schoetterl-Glausch 		report_fail("could not reset SCHIB");
695*6c3882f6SJanis Schoetterl-Glausch 	}
696*6c3882f6SJanis Schoetterl-Glausch 
697*6c3882f6SJanis Schoetterl-Glausch 	ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
698*6c3882f6SJanis Schoetterl-Glausch 	register_pgm_cleanup_func(NULL);
699*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
700*6c3882f6SJanis Schoetterl-Glausch 	set_storage_key(schib, 0x00, 0);
701*6c3882f6SJanis Schoetterl-Glausch 	report_prefix_pop();
702*6c3882f6SJanis Schoetterl-Glausch }
703*6c3882f6SJanis Schoetterl-Glausch 
704f6b354fbSJanosch Frank int main(void)
705f6b354fbSJanosch Frank {
706f6b354fbSJanosch Frank 	report_prefix_push("skey");
70747df95c7SJanosch Frank 	if (test_facility(169)) {
70847df95c7SJanosch Frank 		report_skip("storage key removal facility is active");
70947df95c7SJanosch Frank 		goto done;
71047df95c7SJanosch Frank 	}
711f6b354fbSJanosch Frank 	test_priv();
712429c9cc2SDavid Hildenbrand 	test_invalid_address();
713f6b354fbSJanosch Frank 	test_set();
714f6b354fbSJanosch Frank 	test_set_mb();
715f6b354fbSJanosch Frank 	test_chg();
71666abce92SJanis Schoetterl-Glausch 	test_test_protection();
71766abce92SJanis Schoetterl-Glausch 	test_store_cpu_address();
718*6c3882f6SJanis Schoetterl-Glausch 	test_channel_subsystem_call();
71966abce92SJanis Schoetterl-Glausch 
72066abce92SJanis Schoetterl-Glausch 	setup_vm();
72166abce92SJanis Schoetterl-Glausch 	test_set_prefix();
722*6c3882f6SJanis Schoetterl-Glausch 	test_msch();
72347df95c7SJanosch Frank done:
724f6b354fbSJanosch Frank 	report_prefix_pop();
725f6b354fbSJanosch Frank 	return report_summary();
726f6b354fbSJanosch Frank }
727