1 /* 2 * Storage key removal facility tests 3 * 4 * Copyright (c) 2019 IBM Corp 5 * 6 * Authors: 7 * Janosch Frank <frankja@linux.ibm.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2. 11 */ 12 #include <libcflat.h> 13 #include <asm/asm-offsets.h> 14 #include <asm-generic/barrier.h> 15 #include <asm/interrupt.h> 16 #include <asm/page.h> 17 #include <asm/facility.h> 18 #include <asm/mem.h> 19 #include <asm/sigp.h> 20 #include <smp.h> 21 22 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 23 static int testflag = 0; 24 25 static void test_facilities(void) 26 { 27 report_prefix_push("facilities"); 28 report(!test_facility(10), "!10"); 29 report(!test_facility(14), "!14"); 30 report(!test_facility(66), "!66"); 31 report(!test_facility(145), "!145"); 32 report(!test_facility(140), "!149"); 33 report_prefix_pop(); 34 } 35 36 static void test_skey(void) 37 { 38 report_prefix_push("sske"); 39 expect_pgm_int(); 40 set_storage_key(pagebuf, 0x30, 0); 41 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 42 expect_pgm_int(); 43 report_prefix_pop(); 44 report_prefix_push("iske"); 45 get_storage_key(pagebuf); 46 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 47 report_prefix_pop(); 48 } 49 50 static void test_pfmf(void) 51 { 52 union pfmf_r1 r1; 53 54 report_prefix_push("pfmf"); 55 r1.val = 0; 56 r1.reg.sk = 1; 57 r1.reg.fsc = PFMF_FSC_4K; 58 r1.reg.key = 0x30; 59 expect_pgm_int(); 60 pfmf(r1.val, pagebuf); 61 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 62 report_prefix_pop(); 63 } 64 65 static void test_psw_key(void) 66 { 67 uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL; 68 69 report_prefix_push("psw key"); 70 expect_pgm_int(); 71 load_psw_mask(psw_mask); 72 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 73 report_prefix_pop(); 74 } 75 76 static void test_mvcos(void) 77 { 78 uint64_t r3 = 64; 79 uint8_t *src = pagebuf; 80 uint8_t *dst = pagebuf + PAGE_SIZE; 81 /* K bit set, as well as keys */ 82 register unsigned long oac asm("0") = 0xf002f002; 83 84 report_prefix_push("mvcos"); 85 expect_pgm_int(); 86 asm volatile("mvcos %[dst],%[src],%[len]" 87 : [dst] "+Q" (*(dst)) 88 : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) 89 : "cc", "memory"); 90 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 91 report_prefix_pop(); 92 } 93 94 static void test_spka(void) 95 { 96 report_prefix_push("spka"); 97 expect_pgm_int(); 98 asm volatile("spka 0xf0(0)\n"); 99 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 100 report_prefix_pop(); 101 } 102 103 static void test_tprot(void) 104 { 105 report_prefix_push("tprot"); 106 expect_pgm_int(); 107 asm volatile("tprot %[addr],0xf0(0)\n" 108 : : [addr] "a" (pagebuf) : ); 109 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 110 report_prefix_pop(); 111 } 112 113 static void wait_for_flag(void) 114 { 115 while (!testflag) 116 mb(); 117 } 118 119 static void set_flag(int val) 120 { 121 mb(); 122 testflag = val; 123 mb(); 124 } 125 126 static void ecall_cleanup(void) 127 { 128 struct lowcore *lc = (void *)0x0; 129 130 lc->ext_new_psw.mask = 0x0000000180000000UL; 131 lc->sw_int_crs[0] = 0x0000000000040000; 132 133 /* 134 * PGM old contains the ext new PSW, we need to clean it up, 135 * so we don't get a special operation exception on the lpswe 136 * of pgm old. 137 */ 138 lc->pgm_old_psw.mask = 0x0000000180000000UL; 139 140 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 141 set_flag(1); 142 } 143 144 /* Set a key into the external new psw mask and open external call masks */ 145 static void ecall_setup(void) 146 { 147 struct lowcore *lc = (void *)0x0; 148 uint64_t mask; 149 150 register_pgm_cleanup_func(ecall_cleanup); 151 expect_pgm_int(); 152 /* Put a skey into the ext new psw */ 153 lc->ext_new_psw.mask = 0x00F0000180000000UL; 154 /* Open up ext masks */ 155 ctl_set_bit(0, 13); 156 mask = extract_psw_mask(); 157 mask |= PSW_MASK_EXT; 158 load_psw_mask(mask); 159 /* Tell cpu 0 that we're ready */ 160 set_flag(1); 161 } 162 163 static void test_exception_ext_new(void) 164 { 165 struct psw psw = { 166 .mask = extract_psw_mask(), 167 .addr = (unsigned long)ecall_setup 168 }; 169 170 report_prefix_push("exception external new"); 171 if (smp_query_num_cpus() < 2) { 172 report_skip("Need second cpu for exception external new test."); 173 report_prefix_pop(); 174 return; 175 } 176 177 smp_cpu_setup(1, psw); 178 wait_for_flag(); 179 set_flag(0); 180 181 sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); 182 wait_for_flag(); 183 smp_cpu_stop(1); 184 report_prefix_pop(); 185 } 186 187 int main(void) 188 { 189 report_prefix_push("skrf"); 190 if (!test_facility(169)) { 191 report_skip("storage key removal facility not available\n"); 192 goto done; 193 } 194 195 test_facilities(); 196 test_skey(); 197 test_pfmf(); 198 test_psw_key(); 199 test_mvcos(); 200 test_spka(); 201 test_tprot(); 202 test_exception_ext_new(); 203 204 done: 205 report_prefix_pop(); 206 return report_summary(); 207 } 208