1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Storage key tests 4 * 5 * Copyright (c) 2018 IBM Corp 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.vnet.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <asm/asm-offsets.h> 12 #include <asm/interrupt.h> 13 #include <asm/page.h> 14 #include <asm/facility.h> 15 #include <asm/mem.h> 16 17 18 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 19 20 static void test_set_mb(void) 21 { 22 union skey skey, ret1, ret2; 23 void *addr = (void *)0x10000 - 2 * PAGE_SIZE; 24 void *end = (void *)0x10000; 25 26 /* Multi block support came with EDAT 1 */ 27 if (!test_facility(8)) 28 return; 29 30 skey.val = 0x30; 31 while (addr < end) 32 addr = set_storage_key_mb(addr, skey.val); 33 34 ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP); 35 ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP); 36 report(ret1.val == ret2.val && ret1.val == skey.val, "multi block"); 37 } 38 39 static void test_chg(void) 40 { 41 union skey skey1, skey2; 42 43 skey1.val = 0x30; 44 set_storage_key(pagebuf, skey1.val, 0); 45 skey1.val = get_storage_key(pagebuf); 46 pagebuf[0] = 3; 47 skey2.val = get_storage_key(pagebuf); 48 report(!skey1.str.ch && skey2.str.ch, "chg bit test"); 49 } 50 51 static void test_set(void) 52 { 53 union skey skey, ret; 54 55 skey.val = 0x30; 56 ret.val = get_storage_key(pagebuf); 57 set_storage_key(pagebuf, skey.val, 0); 58 ret.val = get_storage_key(pagebuf); 59 /* 60 * For all set tests we only test the ACC and FP bits. RF and 61 * CH are set by the machine for memory references and changes 62 * and hence might change between a set and a get. 63 */ 64 report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp, 65 "set key test"); 66 } 67 68 /* Returns true if we are running under z/VM 6.x */ 69 static bool check_for_zvm6(void) 70 { 71 int dcbt; /* Descriptor block count */ 72 int nr; 73 static const unsigned char zvm6[] = { 74 /* This is "z/VM 6" in EBCDIC */ 75 0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6 76 }; 77 78 if (stsi(pagebuf, 3, 2, 2)) 79 return false; 80 81 dcbt = pagebuf[31] & 0xf; 82 83 for (nr = 0; nr < dcbt; nr++) { 84 if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6))) 85 return true; 86 } 87 88 return false; 89 } 90 91 static void test_priv(void) 92 { 93 union skey skey; 94 bool is_zvm6 = check_for_zvm6(); 95 96 memset(pagebuf, 0, PAGE_SIZE * 2); 97 report_prefix_push("privileged"); 98 report_prefix_push("sske"); 99 expect_pgm_int(); 100 enter_pstate(); 101 set_storage_key(pagebuf, 0x30, 0); 102 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 103 report_prefix_pop(); 104 105 skey.val = get_storage_key(pagebuf); 106 report(skey.str.acc != 3, "skey did not change on exception"); 107 108 report_prefix_push("iske"); 109 if (is_zvm6) { 110 /* There is a known bug with z/VM 6, so skip the test there */ 111 report_skip("not working on z/VM 6"); 112 } else { 113 expect_pgm_int(); 114 enter_pstate(); 115 get_storage_key(pagebuf); 116 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 117 } 118 report_prefix_pop(); 119 120 report_prefix_pop(); 121 } 122 123 int main(void) 124 { 125 report_prefix_push("skey"); 126 if (test_facility(169)) { 127 report_skip("storage key removal facility is active"); 128 goto done; 129 } 130 test_priv(); 131 test_set(); 132 test_set_mb(); 133 test_chg(); 134 done: 135 report_prefix_pop(); 136 return report_summary(); 137 } 138