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 static void test_priv(void) 69 { 70 union skey skey; 71 72 memset(pagebuf, 0, PAGE_SIZE * 2); 73 report_prefix_push("privileged"); 74 report_prefix_push("sske"); 75 expect_pgm_int(); 76 enter_pstate(); 77 set_storage_key(pagebuf, 0x30, 0); 78 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 79 report_prefix_pop(); 80 81 skey.val = get_storage_key(pagebuf); 82 report(skey.str.acc != 3, "skey did not change on exception"); 83 84 report_prefix_push("iske"); 85 expect_pgm_int(); 86 enter_pstate(); 87 get_storage_key(pagebuf); 88 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 89 report_prefix_pop(); 90 91 report_prefix_pop(); 92 } 93 94 static void test_invalid_address(void) 95 { 96 void *inv_addr = (void *)-1ull; 97 98 report_prefix_push("invalid address"); 99 100 report_prefix_push("sske"); 101 expect_pgm_int(); 102 set_storage_key(inv_addr, 0, 0); 103 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 104 report_prefix_pop(); 105 106 report_prefix_push("iske"); 107 expect_pgm_int(); 108 get_storage_key(inv_addr); 109 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 110 report_prefix_pop(); 111 112 report_prefix_push("rrbe"); 113 expect_pgm_int(); 114 reset_reference_bit(inv_addr); 115 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 116 report_prefix_pop(); 117 118 report_prefix_pop(); 119 } 120 121 int main(void) 122 { 123 report_prefix_push("skey"); 124 if (test_facility(169)) { 125 report_skip("storage key removal facility is active"); 126 goto done; 127 } 128 test_priv(); 129 test_invalid_address(); 130 test_set(); 131 test_set_mb(); 132 test_chg(); 133 done: 134 report_prefix_pop(); 135 return report_summary(); 136 } 137