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("multi block", 39 ret1.val == ret2.val && ret1.val == skey.val); 40 } 41 42 static void test_chg(void) 43 { 44 union skey skey1, skey2; 45 46 skey1.val = 0x30; 47 set_storage_key(pagebuf, skey1.val, 0); 48 skey1.val = get_storage_key(pagebuf); 49 pagebuf[0] = 3; 50 skey2.val = get_storage_key(pagebuf); 51 report("chg bit test", !skey1.str.ch && skey2.str.ch); 52 } 53 54 static void test_set(void) 55 { 56 union skey skey, ret; 57 58 skey.val = 0x30; 59 ret.val = get_storage_key(pagebuf); 60 set_storage_key(pagebuf, skey.val, 0); 61 ret.val = get_storage_key(pagebuf); 62 /* 63 * For all set tests we only test the ACC and FP bits. RF and 64 * CH are set by the machine for memory references and changes 65 * and hence might change between a set and a get. 66 */ 67 report("set key test", 68 skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp); 69 } 70 71 /* Returns true if we are running under z/VM 6.x */ 72 static bool check_for_zvm6(void) 73 { 74 int dcbt; /* Descriptor block count */ 75 int nr; 76 static const unsigned char zvm6[] = { 77 /* This is "z/VM 6" in EBCDIC */ 78 0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6 79 }; 80 81 if (stsi(pagebuf, 3, 2, 2)) 82 return false; 83 84 dcbt = pagebuf[31] & 0xf; 85 86 for (nr = 0; nr < dcbt; nr++) { 87 if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6))) 88 return true; 89 } 90 91 return false; 92 } 93 94 static void test_priv(void) 95 { 96 union skey skey; 97 bool is_zvm6 = check_for_zvm6(); 98 99 memset(pagebuf, 0, PAGE_SIZE * 2); 100 report_prefix_push("privileged"); 101 report_prefix_push("sske"); 102 expect_pgm_int(); 103 enter_pstate(); 104 set_storage_key(pagebuf, 0x30, 0); 105 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 106 report_prefix_pop(); 107 108 skey.val = get_storage_key(pagebuf); 109 report("skey did not change on exception", skey.str.acc != 3); 110 111 report_prefix_push("iske"); 112 if (is_zvm6) { 113 /* There is a known bug with z/VM 6, so skip the test there */ 114 report_skip("not working on z/VM 6"); 115 } else { 116 expect_pgm_int(); 117 enter_pstate(); 118 get_storage_key(pagebuf); 119 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 120 } 121 report_prefix_pop(); 122 123 report_prefix_pop(); 124 } 125 126 int main(void) 127 { 128 report_prefix_push("skey"); 129 if (test_facility(169)) { 130 report_skip("storage key removal facility is active"); 131 goto done; 132 } 133 test_priv(); 134 test_set(); 135 test_set_mb(); 136 test_chg(); 137 done: 138 report_prefix_pop(); 139 return report_summary(); 140 } 141