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> 156c3882f6SJanis 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 306*965e38a0SJanis Schoetterl-Glausch static void test_diag_308(void) 307*965e38a0SJanis Schoetterl-Glausch { 308*965e38a0SJanis Schoetterl-Glausch uint16_t response; 309*965e38a0SJanis Schoetterl-Glausch uint32_t *ipib = (uint32_t *)pagebuf; 310*965e38a0SJanis Schoetterl-Glausch 311*965e38a0SJanis Schoetterl-Glausch report_prefix_push("DIAG 308"); 312*965e38a0SJanis Schoetterl-Glausch WRITE_ONCE(ipib[0], 0); /* Invalid length */ 313*965e38a0SJanis Schoetterl-Glausch set_storage_key(ipib, 0x28, 0); 314*965e38a0SJanis Schoetterl-Glausch /* key-controlled protection does not apply */ 315*965e38a0SJanis Schoetterl-Glausch asm volatile ( 316*965e38a0SJanis Schoetterl-Glausch "lr %%r2,%[ipib]\n\t" 317*965e38a0SJanis Schoetterl-Glausch "spka 0x10\n\t" 318*965e38a0SJanis Schoetterl-Glausch "diag %%r2,%[code],0x308\n\t" 319*965e38a0SJanis Schoetterl-Glausch "spka 0\n\t" 320*965e38a0SJanis Schoetterl-Glausch "lr %[response],%%r3\n" 321*965e38a0SJanis Schoetterl-Glausch : [response] "=d" (response) 322*965e38a0SJanis Schoetterl-Glausch : [ipib] "d" (ipib), 323*965e38a0SJanis Schoetterl-Glausch [code] "d" (5) 324*965e38a0SJanis Schoetterl-Glausch : "%r2", "%r3" 325*965e38a0SJanis Schoetterl-Glausch ); 326*965e38a0SJanis Schoetterl-Glausch report(response == 0x402, "no exception on fetch, response: invalid IPIB"); 327*965e38a0SJanis Schoetterl-Glausch set_storage_key(ipib, 0x00, 0); 328*965e38a0SJanis Schoetterl-Glausch report_prefix_pop(); 329*965e38a0SJanis Schoetterl-Glausch } 330*965e38a0SJanis Schoetterl-Glausch 33166abce92SJanis Schoetterl-Glausch /* 3326c3882f6SJanis Schoetterl-Glausch * Perform CHANNEL SUBSYSTEM CALL (CHSC) instruction while temporarily executing 3336c3882f6SJanis Schoetterl-Glausch * with access key 1. 3346c3882f6SJanis Schoetterl-Glausch */ 3356c3882f6SJanis Schoetterl-Glausch static unsigned int chsc_key_1(void *comm_block) 3366c3882f6SJanis Schoetterl-Glausch { 3376c3882f6SJanis Schoetterl-Glausch uint32_t program_mask; 3386c3882f6SJanis Schoetterl-Glausch 3396c3882f6SJanis Schoetterl-Glausch asm volatile ( 3406c3882f6SJanis Schoetterl-Glausch "spka 0x10\n\t" 3416c3882f6SJanis Schoetterl-Glausch ".insn rre,0xb25f0000,%[comm_block],0\n\t" 3426c3882f6SJanis Schoetterl-Glausch "spka 0\n\t" 3436c3882f6SJanis Schoetterl-Glausch "ipm %[program_mask]\n" 3446c3882f6SJanis Schoetterl-Glausch : [program_mask] "=d" (program_mask) 3456c3882f6SJanis Schoetterl-Glausch : [comm_block] "d" (comm_block) 3466c3882f6SJanis Schoetterl-Glausch : "memory" 3476c3882f6SJanis Schoetterl-Glausch ); 3486c3882f6SJanis Schoetterl-Glausch return program_mask >> 28; 3496c3882f6SJanis Schoetterl-Glausch } 3506c3882f6SJanis Schoetterl-Glausch 3516c3882f6SJanis Schoetterl-Glausch static const char chsc_msg[] = "Performed store-channel-subsystem-characteristics"; 3526c3882f6SJanis Schoetterl-Glausch static void init_comm_block(uint16_t *comm_block) 3536c3882f6SJanis Schoetterl-Glausch { 3546c3882f6SJanis Schoetterl-Glausch memset(comm_block, 0, PAGE_SIZE); 3556c3882f6SJanis Schoetterl-Glausch /* store-channel-subsystem-characteristics command */ 3566c3882f6SJanis Schoetterl-Glausch comm_block[0] = 0x10; 3576c3882f6SJanis Schoetterl-Glausch comm_block[1] = 0x10; 3586c3882f6SJanis Schoetterl-Glausch comm_block[9] = 0; 3596c3882f6SJanis Schoetterl-Glausch } 3606c3882f6SJanis Schoetterl-Glausch 3616c3882f6SJanis Schoetterl-Glausch static void test_channel_subsystem_call(void) 3626c3882f6SJanis Schoetterl-Glausch { 3636c3882f6SJanis Schoetterl-Glausch uint16_t *comm_block = (uint16_t *)&pagebuf; 3646c3882f6SJanis Schoetterl-Glausch unsigned int cc; 3656c3882f6SJanis Schoetterl-Glausch 3666c3882f6SJanis Schoetterl-Glausch report_prefix_push("CHANNEL SUBSYSTEM CALL"); 3676c3882f6SJanis Schoetterl-Glausch 3686c3882f6SJanis Schoetterl-Glausch report_prefix_push("zero key"); 3696c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 3706c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x10, 0); 3716c3882f6SJanis Schoetterl-Glausch asm volatile ( 3726c3882f6SJanis Schoetterl-Glausch ".insn rre,0xb25f0000,%[comm_block],0\n\t" 3736c3882f6SJanis Schoetterl-Glausch "ipm %[cc]\n" 3746c3882f6SJanis Schoetterl-Glausch : [cc] "=d" (cc) 3756c3882f6SJanis Schoetterl-Glausch : [comm_block] "d" (comm_block) 3766c3882f6SJanis Schoetterl-Glausch : "memory" 3776c3882f6SJanis Schoetterl-Glausch ); 3786c3882f6SJanis Schoetterl-Glausch cc = cc >> 28; 3796c3882f6SJanis Schoetterl-Glausch report(cc == 0 && comm_block[9], chsc_msg); 3806c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 3816c3882f6SJanis Schoetterl-Glausch 3826c3882f6SJanis Schoetterl-Glausch report_prefix_push("matching key"); 3836c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 3846c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x10, 0); 3856c3882f6SJanis Schoetterl-Glausch cc = chsc_key_1(comm_block); 3866c3882f6SJanis Schoetterl-Glausch report(cc == 0 && comm_block[9], chsc_msg); 3876c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 3886c3882f6SJanis Schoetterl-Glausch 3896c3882f6SJanis Schoetterl-Glausch report_prefix_push("mismatching key"); 3906c3882f6SJanis Schoetterl-Glausch 3916c3882f6SJanis Schoetterl-Glausch report_prefix_push("no fetch protection"); 3926c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 3936c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x20, 0); 3946c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 3956c3882f6SJanis Schoetterl-Glausch chsc_key_1(comm_block); 3966c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_UPDATE, PROT_STORE); 3976c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 3986c3882f6SJanis Schoetterl-Glausch 3996c3882f6SJanis Schoetterl-Glausch report_prefix_push("fetch protection"); 4006c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 4016c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x28, 0); 4026c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 4036c3882f6SJanis Schoetterl-Glausch chsc_key_1(comm_block); 4046c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_UPDATE, PROT_FETCH_STORE); 4056c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4066c3882f6SJanis Schoetterl-Glausch 4076c3882f6SJanis Schoetterl-Glausch ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE); 4086c3882f6SJanis Schoetterl-Glausch 4096c3882f6SJanis Schoetterl-Glausch report_prefix_push("storage-protection override, invalid key"); 4106c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x20, 0); 4116c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 4126c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 4136c3882f6SJanis Schoetterl-Glausch chsc_key_1(comm_block); 4146c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_UPDATE, PROT_STORE); 4156c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4166c3882f6SJanis Schoetterl-Glausch 4176c3882f6SJanis Schoetterl-Glausch report_prefix_push("storage-protection override, override key"); 4186c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 4196c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x90, 0); 4206c3882f6SJanis Schoetterl-Glausch cc = chsc_key_1(comm_block); 4216c3882f6SJanis Schoetterl-Glausch report(cc == 0 && comm_block[9], chsc_msg); 4226c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4236c3882f6SJanis Schoetterl-Glausch 4246c3882f6SJanis Schoetterl-Glausch ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE); 4256c3882f6SJanis Schoetterl-Glausch 4266c3882f6SJanis Schoetterl-Glausch report_prefix_push("storage-protection override disabled, override key"); 4276c3882f6SJanis Schoetterl-Glausch init_comm_block(comm_block); 4286c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x90, 0); 4296c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 4306c3882f6SJanis Schoetterl-Glausch chsc_key_1(comm_block); 4316c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_UPDATE, PROT_STORE); 4326c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4336c3882f6SJanis Schoetterl-Glausch 4346c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4356c3882f6SJanis Schoetterl-Glausch 4366c3882f6SJanis Schoetterl-Glausch set_storage_key(comm_block, 0x00, 0); 4376c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 4386c3882f6SJanis Schoetterl-Glausch } 4396c3882f6SJanis Schoetterl-Glausch 4406c3882f6SJanis Schoetterl-Glausch /* 44166abce92SJanis Schoetterl-Glausch * Perform SET PREFIX (SPX) instruction while temporarily executing 44266abce92SJanis Schoetterl-Glausch * with access key 1. 44366abce92SJanis Schoetterl-Glausch */ 44466abce92SJanis Schoetterl-Glausch static void set_prefix_key_1(uint32_t *prefix_ptr) 44566abce92SJanis Schoetterl-Glausch { 44666abce92SJanis Schoetterl-Glausch asm volatile ( 44766abce92SJanis Schoetterl-Glausch "spka 0x10\n\t" 44866abce92SJanis Schoetterl-Glausch "spx %0\n\t" 44966abce92SJanis Schoetterl-Glausch "spka 0\n" 45066abce92SJanis Schoetterl-Glausch :: "Q" (*prefix_ptr) 45166abce92SJanis Schoetterl-Glausch ); 45266abce92SJanis Schoetterl-Glausch } 45366abce92SJanis Schoetterl-Glausch 45466abce92SJanis Schoetterl-Glausch /* 45566abce92SJanis Schoetterl-Glausch * We remapped page 0, making the lowcore inaccessible, which breaks the normal 45666abce92SJanis Schoetterl-Glausch * handler and breaks skipping the faulting instruction. 45766abce92SJanis Schoetterl-Glausch * Just disable dynamic address translation to make things work. 45866abce92SJanis Schoetterl-Glausch */ 45966abce92SJanis Schoetterl-Glausch static void dat_fixup_pgm_int(void) 46066abce92SJanis Schoetterl-Glausch { 46166abce92SJanis Schoetterl-Glausch uint64_t psw_mask = extract_psw_mask(); 46266abce92SJanis Schoetterl-Glausch 46366abce92SJanis Schoetterl-Glausch psw_mask &= ~PSW_MASK_DAT; 46466abce92SJanis Schoetterl-Glausch load_psw_mask(psw_mask); 46566abce92SJanis Schoetterl-Glausch } 46666abce92SJanis Schoetterl-Glausch 46766abce92SJanis Schoetterl-Glausch #define PREFIX_AREA_SIZE (PAGE_SIZE * 2) 46866abce92SJanis Schoetterl-Glausch static char lowcore_tmp[PREFIX_AREA_SIZE] __attribute__((aligned(PREFIX_AREA_SIZE))); 46966abce92SJanis Schoetterl-Glausch 47066abce92SJanis Schoetterl-Glausch /* 47166abce92SJanis Schoetterl-Glausch * Test accessibility of the operand to SET PREFIX given different configurations 47266abce92SJanis Schoetterl-Glausch * with regards to storage keys. That is, check the accessibility of the location 47366abce92SJanis Schoetterl-Glausch * holding the new prefix, not that of the new prefix area. The new prefix area 47466abce92SJanis Schoetterl-Glausch * is a valid lowcore, so that the test does not crash on failure. 47566abce92SJanis Schoetterl-Glausch */ 47666abce92SJanis Schoetterl-Glausch static void test_set_prefix(void) 47766abce92SJanis Schoetterl-Glausch { 47866abce92SJanis Schoetterl-Glausch uint32_t *prefix_ptr = (uint32_t *)pagebuf; 47966abce92SJanis Schoetterl-Glausch uint32_t *no_override_prefix_ptr; 48066abce92SJanis Schoetterl-Glausch uint32_t old_prefix; 48166abce92SJanis Schoetterl-Glausch pgd_t *root; 48266abce92SJanis Schoetterl-Glausch 48366abce92SJanis Schoetterl-Glausch report_prefix_push("SET PREFIX"); 48466abce92SJanis Schoetterl-Glausch root = (pgd_t *)(stctg(1) & PAGE_MASK); 48566abce92SJanis Schoetterl-Glausch old_prefix = get_prefix(); 48666abce92SJanis Schoetterl-Glausch memcpy(lowcore_tmp, 0, sizeof(lowcore_tmp)); 48766abce92SJanis Schoetterl-Glausch assert(((uint64_t)&lowcore_tmp >> 31) == 0); 48866abce92SJanis Schoetterl-Glausch *prefix_ptr = (uint32_t)(uint64_t)&lowcore_tmp; 48966abce92SJanis Schoetterl-Glausch 49066abce92SJanis Schoetterl-Glausch report_prefix_push("zero key"); 49166abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 49266abce92SJanis Schoetterl-Glausch set_storage_key(prefix_ptr, 0x20, 0); 49366abce92SJanis Schoetterl-Glausch set_prefix(*prefix_ptr); 49466abce92SJanis Schoetterl-Glausch report(get_prefix() == *prefix_ptr, "set prefix"); 49566abce92SJanis Schoetterl-Glausch report_prefix_pop(); 49666abce92SJanis Schoetterl-Glausch 49766abce92SJanis Schoetterl-Glausch report_prefix_push("matching key"); 49866abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 49966abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x10, 0); 50066abce92SJanis Schoetterl-Glausch set_prefix_key_1(prefix_ptr); 50166abce92SJanis Schoetterl-Glausch report(get_prefix() == *prefix_ptr, "set prefix"); 50266abce92SJanis Schoetterl-Glausch report_prefix_pop(); 50366abce92SJanis Schoetterl-Glausch 50466abce92SJanis Schoetterl-Glausch report_prefix_push("mismatching key"); 50566abce92SJanis Schoetterl-Glausch 50666abce92SJanis Schoetterl-Glausch report_prefix_push("no fetch protection"); 50766abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 50866abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x20, 0); 50966abce92SJanis Schoetterl-Glausch set_prefix_key_1(prefix_ptr); 51066abce92SJanis Schoetterl-Glausch report(get_prefix() == *prefix_ptr, "set prefix"); 51166abce92SJanis Schoetterl-Glausch report_prefix_pop(); 51266abce92SJanis Schoetterl-Glausch 51366abce92SJanis Schoetterl-Glausch report_prefix_push("fetch protection"); 51466abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 51566abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 51666abce92SJanis Schoetterl-Glausch expect_pgm_int(); 51766abce92SJanis Schoetterl-Glausch set_prefix_key_1(prefix_ptr); 518b02598aeSJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 51966abce92SJanis Schoetterl-Glausch report(get_prefix() == old_prefix, "did not set prefix"); 52066abce92SJanis Schoetterl-Glausch report_prefix_pop(); 52166abce92SJanis Schoetterl-Glausch 52266abce92SJanis Schoetterl-Glausch register_pgm_cleanup_func(dat_fixup_pgm_int); 52366abce92SJanis Schoetterl-Glausch 52466abce92SJanis Schoetterl-Glausch report_prefix_push("remapped page, fetch protection"); 52566abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 52666abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 52766abce92SJanis Schoetterl-Glausch expect_pgm_int(); 52866abce92SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 52966abce92SJanis Schoetterl-Glausch set_prefix_key_1((uint32_t *)0); 53066abce92SJanis Schoetterl-Glausch install_page(root, 0, 0); 531b02598aeSJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 53266abce92SJanis Schoetterl-Glausch report(get_prefix() == old_prefix, "did not set prefix"); 53366abce92SJanis Schoetterl-Glausch report_prefix_pop(); 53466abce92SJanis Schoetterl-Glausch 53566abce92SJanis Schoetterl-Glausch ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE); 53666abce92SJanis Schoetterl-Glausch 53766abce92SJanis Schoetterl-Glausch report_prefix_push("fetch protection override applies"); 53866abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 53966abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 54066abce92SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 54166abce92SJanis Schoetterl-Glausch set_prefix_key_1((uint32_t *)0); 54266abce92SJanis Schoetterl-Glausch install_page(root, 0, 0); 54366abce92SJanis Schoetterl-Glausch report(get_prefix() == *prefix_ptr, "set prefix"); 54466abce92SJanis Schoetterl-Glausch report_prefix_pop(); 54566abce92SJanis Schoetterl-Glausch 54666abce92SJanis Schoetterl-Glausch no_override_prefix_ptr = (uint32_t *)(pagebuf + 2048); 54766abce92SJanis Schoetterl-Glausch WRITE_ONCE(*no_override_prefix_ptr, (uint32_t)(uint64_t)&lowcore_tmp); 54866abce92SJanis Schoetterl-Glausch report_prefix_push("fetch protection override does not apply"); 54966abce92SJanis Schoetterl-Glausch set_prefix(old_prefix); 55066abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 55166abce92SJanis Schoetterl-Glausch expect_pgm_int(); 55266abce92SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 5535af83aa8SJanis Schoetterl-Glausch set_prefix_key_1(OPAQUE_PTR(2048)); 55466abce92SJanis Schoetterl-Glausch install_page(root, 0, 0); 555b02598aeSJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 55666abce92SJanis Schoetterl-Glausch report(get_prefix() == old_prefix, "did not set prefix"); 55766abce92SJanis Schoetterl-Glausch report_prefix_pop(); 55866abce92SJanis Schoetterl-Glausch 55966abce92SJanis Schoetterl-Glausch ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE); 56066abce92SJanis Schoetterl-Glausch register_pgm_cleanup_func(NULL); 56166abce92SJanis Schoetterl-Glausch report_prefix_pop(); 56266abce92SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x00, 0); 56366abce92SJanis Schoetterl-Glausch report_prefix_pop(); 56466abce92SJanis Schoetterl-Glausch } 56566abce92SJanis Schoetterl-Glausch 5666c3882f6SJanis Schoetterl-Glausch /* 5676c3882f6SJanis Schoetterl-Glausch * Perform MODIFY SUBCHANNEL (MSCH) instruction while temporarily executing 5686c3882f6SJanis Schoetterl-Glausch * with access key 1. 5696c3882f6SJanis Schoetterl-Glausch */ 5706c3882f6SJanis Schoetterl-Glausch static uint32_t modify_subchannel_key_1(uint32_t sid, struct schib *schib) 5716c3882f6SJanis Schoetterl-Glausch { 5726c3882f6SJanis Schoetterl-Glausch uint32_t program_mask; 5736c3882f6SJanis Schoetterl-Glausch 5746c3882f6SJanis Schoetterl-Glausch asm volatile ( 5756c3882f6SJanis Schoetterl-Glausch "lr %%r1,%[sid]\n\t" 5766c3882f6SJanis Schoetterl-Glausch "spka 0x10\n\t" 5776c3882f6SJanis Schoetterl-Glausch "msch %[schib]\n\t" 5786c3882f6SJanis Schoetterl-Glausch "spka 0\n\t" 5796c3882f6SJanis Schoetterl-Glausch "ipm %[program_mask]\n" 5806c3882f6SJanis Schoetterl-Glausch : [program_mask] "=d" (program_mask) 5816c3882f6SJanis Schoetterl-Glausch : [sid] "d" (sid), 5826c3882f6SJanis Schoetterl-Glausch [schib] "Q" (*schib) 5836c3882f6SJanis Schoetterl-Glausch : "%r1" 5846c3882f6SJanis Schoetterl-Glausch ); 5856c3882f6SJanis Schoetterl-Glausch return program_mask >> 28; 5866c3882f6SJanis Schoetterl-Glausch } 5876c3882f6SJanis Schoetterl-Glausch 5886c3882f6SJanis Schoetterl-Glausch static void test_msch(void) 5896c3882f6SJanis Schoetterl-Glausch { 5906c3882f6SJanis Schoetterl-Glausch struct schib *schib = (struct schib *)pagebuf; 5916c3882f6SJanis Schoetterl-Glausch struct schib *no_override_schib; 5926c3882f6SJanis Schoetterl-Glausch int test_device_sid; 5936c3882f6SJanis Schoetterl-Glausch pgd_t *root; 5946c3882f6SJanis Schoetterl-Glausch int cc; 5956c3882f6SJanis Schoetterl-Glausch 5966c3882f6SJanis Schoetterl-Glausch report_prefix_push("MSCH"); 5976c3882f6SJanis Schoetterl-Glausch root = (pgd_t *)(stctg(1) & PAGE_MASK); 5986c3882f6SJanis Schoetterl-Glausch test_device_sid = css_enumerate(); 5996c3882f6SJanis Schoetterl-Glausch 6006c3882f6SJanis Schoetterl-Glausch if (!(test_device_sid & SCHID_ONE)) { 6016c3882f6SJanis Schoetterl-Glausch report_fail("no I/O device found"); 6026c3882f6SJanis Schoetterl-Glausch return; 6036c3882f6SJanis Schoetterl-Glausch } 6046c3882f6SJanis Schoetterl-Glausch 6056c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6066c3882f6SJanis Schoetterl-Glausch if (cc) { 6076c3882f6SJanis Schoetterl-Glausch report_fail("could not store SCHIB"); 6086c3882f6SJanis Schoetterl-Glausch return; 6096c3882f6SJanis Schoetterl-Glausch } 6106c3882f6SJanis Schoetterl-Glausch 6116c3882f6SJanis Schoetterl-Glausch report_prefix_push("zero key"); 6126c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 100; 6136c3882f6SJanis Schoetterl-Glausch set_storage_key(schib, 0x28, 0); 6146c3882f6SJanis Schoetterl-Glausch cc = msch(test_device_sid, schib); 6156c3882f6SJanis Schoetterl-Glausch if (!cc) { 6166c3882f6SJanis Schoetterl-Glausch WRITE_ONCE(schib->pmcw.intparm, 0); 6176c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6186c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 100, "fetched from SCHIB"); 6196c3882f6SJanis Schoetterl-Glausch } else { 6206c3882f6SJanis Schoetterl-Glausch report_fail("MSCH cc != 0"); 6216c3882f6SJanis Schoetterl-Glausch } 6226c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 6236c3882f6SJanis Schoetterl-Glausch 6246c3882f6SJanis Schoetterl-Glausch report_prefix_push("matching key"); 6256c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 200; 6266c3882f6SJanis Schoetterl-Glausch set_storage_key(schib, 0x18, 0); 6276c3882f6SJanis Schoetterl-Glausch cc = modify_subchannel_key_1(test_device_sid, schib); 6286c3882f6SJanis Schoetterl-Glausch if (!cc) { 6296c3882f6SJanis Schoetterl-Glausch WRITE_ONCE(schib->pmcw.intparm, 0); 6306c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6316c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 200, "fetched from SCHIB"); 6326c3882f6SJanis Schoetterl-Glausch } else { 6336c3882f6SJanis Schoetterl-Glausch report_fail("MSCH cc != 0"); 6346c3882f6SJanis Schoetterl-Glausch } 6356c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 6366c3882f6SJanis Schoetterl-Glausch 6376c3882f6SJanis Schoetterl-Glausch report_prefix_push("mismatching key"); 6386c3882f6SJanis Schoetterl-Glausch 6396c3882f6SJanis Schoetterl-Glausch report_prefix_push("no fetch protection"); 6406c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 300; 6416c3882f6SJanis Schoetterl-Glausch set_storage_key(schib, 0x20, 0); 6426c3882f6SJanis Schoetterl-Glausch cc = modify_subchannel_key_1(test_device_sid, schib); 6436c3882f6SJanis Schoetterl-Glausch if (!cc) { 6446c3882f6SJanis Schoetterl-Glausch WRITE_ONCE(schib->pmcw.intparm, 0); 6456c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6466c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 300, "fetched from SCHIB"); 6476c3882f6SJanis Schoetterl-Glausch } else { 6486c3882f6SJanis Schoetterl-Glausch report_fail("MSCH cc != 0"); 6496c3882f6SJanis Schoetterl-Glausch } 6506c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 6516c3882f6SJanis Schoetterl-Glausch 6526c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 0; 6536c3882f6SJanis Schoetterl-Glausch if (!msch(test_device_sid, schib)) { 6546c3882f6SJanis Schoetterl-Glausch report_prefix_push("fetch protection"); 6556c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 400; 6566c3882f6SJanis Schoetterl-Glausch set_storage_key(schib, 0x28, 0); 6576c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 6586c3882f6SJanis Schoetterl-Glausch modify_subchannel_key_1(test_device_sid, schib); 6596c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 6606c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6616c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel"); 6626c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 6636c3882f6SJanis Schoetterl-Glausch } else { 6646c3882f6SJanis Schoetterl-Glausch report_fail("could not reset SCHIB"); 6656c3882f6SJanis Schoetterl-Glausch } 6666c3882f6SJanis Schoetterl-Glausch 6676c3882f6SJanis Schoetterl-Glausch register_pgm_cleanup_func(dat_fixup_pgm_int); 6686c3882f6SJanis Schoetterl-Glausch 6696c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 0; 6706c3882f6SJanis Schoetterl-Glausch if (!msch(test_device_sid, schib)) { 6716c3882f6SJanis Schoetterl-Glausch report_prefix_push("remapped page, fetch protection"); 6726c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 500; 6736c3882f6SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 6746c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 6756c3882f6SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 6766c3882f6SJanis Schoetterl-Glausch modify_subchannel_key_1(test_device_sid, (struct schib *)0); 6776c3882f6SJanis Schoetterl-Glausch install_page(root, 0, 0); 6786c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 6796c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6806c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel"); 6816c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 6826c3882f6SJanis Schoetterl-Glausch } else { 6836c3882f6SJanis Schoetterl-Glausch report_fail("could not reset SCHIB"); 6846c3882f6SJanis Schoetterl-Glausch } 6856c3882f6SJanis Schoetterl-Glausch 6866c3882f6SJanis Schoetterl-Glausch ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE); 6876c3882f6SJanis Schoetterl-Glausch 6886c3882f6SJanis Schoetterl-Glausch report_prefix_push("fetch-protection override applies"); 6896c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 600; 6906c3882f6SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 6916c3882f6SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 6926c3882f6SJanis Schoetterl-Glausch cc = modify_subchannel_key_1(test_device_sid, (struct schib *)0); 6936c3882f6SJanis Schoetterl-Glausch install_page(root, 0, 0); 6946c3882f6SJanis Schoetterl-Glausch if (!cc) { 6956c3882f6SJanis Schoetterl-Glausch WRITE_ONCE(schib->pmcw.intparm, 0); 6966c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 6976c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 600, "fetched from SCHIB"); 6986c3882f6SJanis Schoetterl-Glausch } else { 6996c3882f6SJanis Schoetterl-Glausch report_fail("MSCH cc != 0"); 7006c3882f6SJanis Schoetterl-Glausch } 7016c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 7026c3882f6SJanis Schoetterl-Glausch 7036c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 0; 7046c3882f6SJanis Schoetterl-Glausch if (!msch(test_device_sid, schib)) { 7056c3882f6SJanis Schoetterl-Glausch report_prefix_push("fetch-protection override does not apply"); 7066c3882f6SJanis Schoetterl-Glausch schib->pmcw.intparm = 700; 7076c3882f6SJanis Schoetterl-Glausch no_override_schib = (struct schib *)(pagebuf + 2048); 7086c3882f6SJanis Schoetterl-Glausch memcpy(no_override_schib, schib, sizeof(struct schib)); 7096c3882f6SJanis Schoetterl-Glausch set_storage_key(pagebuf, 0x28, 0); 7106c3882f6SJanis Schoetterl-Glausch expect_pgm_int(); 7116c3882f6SJanis Schoetterl-Glausch install_page(root, virt_to_pte_phys(root, pagebuf), 0); 7126c3882f6SJanis Schoetterl-Glausch modify_subchannel_key_1(test_device_sid, OPAQUE_PTR(2048)); 7136c3882f6SJanis Schoetterl-Glausch install_page(root, 0, 0); 7146c3882f6SJanis Schoetterl-Glausch check_key_prot_exc(ACC_FETCH, PROT_FETCH_STORE); 7156c3882f6SJanis Schoetterl-Glausch cc = stsch(test_device_sid, schib); 7166c3882f6SJanis Schoetterl-Glausch report(!cc && schib->pmcw.intparm == 0, "did not modify subchannel"); 7176c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 7186c3882f6SJanis Schoetterl-Glausch } else { 7196c3882f6SJanis Schoetterl-Glausch report_fail("could not reset SCHIB"); 7206c3882f6SJanis Schoetterl-Glausch } 7216c3882f6SJanis Schoetterl-Glausch 7226c3882f6SJanis Schoetterl-Glausch ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE); 7236c3882f6SJanis Schoetterl-Glausch register_pgm_cleanup_func(NULL); 7246c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 7256c3882f6SJanis Schoetterl-Glausch set_storage_key(schib, 0x00, 0); 7266c3882f6SJanis Schoetterl-Glausch report_prefix_pop(); 7276c3882f6SJanis Schoetterl-Glausch } 7286c3882f6SJanis Schoetterl-Glausch 729f6b354fbSJanosch Frank int main(void) 730f6b354fbSJanosch Frank { 731f6b354fbSJanosch Frank report_prefix_push("skey"); 73247df95c7SJanosch Frank if (test_facility(169)) { 73347df95c7SJanosch Frank report_skip("storage key removal facility is active"); 73447df95c7SJanosch Frank goto done; 73547df95c7SJanosch Frank } 736f6b354fbSJanosch Frank test_priv(); 737429c9cc2SDavid Hildenbrand test_invalid_address(); 738f6b354fbSJanosch Frank test_set(); 739f6b354fbSJanosch Frank test_set_mb(); 740f6b354fbSJanosch Frank test_chg(); 74166abce92SJanis Schoetterl-Glausch test_test_protection(); 74266abce92SJanis Schoetterl-Glausch test_store_cpu_address(); 743*965e38a0SJanis Schoetterl-Glausch test_diag_308(); 7446c3882f6SJanis Schoetterl-Glausch test_channel_subsystem_call(); 74566abce92SJanis Schoetterl-Glausch 74666abce92SJanis Schoetterl-Glausch setup_vm(); 74766abce92SJanis Schoetterl-Glausch test_set_prefix(); 7486c3882f6SJanis Schoetterl-Glausch test_msch(); 74947df95c7SJanosch Frank done: 750f6b354fbSJanosch Frank report_prefix_pop(); 751f6b354fbSJanosch Frank return report_summary(); 752f6b354fbSJanosch Frank } 753