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