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