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