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 <bitops.h> 12 #include <asm/asm-offsets.h> 13 #include <asm-generic/barrier.h> 14 #include <asm/interrupt.h> 15 #include <asm/page.h> 16 #include <asm/facility.h> 17 #include <asm/mem.h> 18 #include <asm/sigp.h> 19 #include <smp.h> 20 21 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 22 static int testflag = 0; 23 24 static void test_facilities(void) 25 { 26 report_prefix_push("facilities"); 27 report(!test_facility(10), "!10"); 28 report(!test_facility(14), "!14"); 29 report(!test_facility(66), "!66"); 30 report(!test_facility(145), "!145"); 31 report(!test_facility(140), "!149"); 32 report_prefix_pop(); 33 } 34 35 static void test_skey(void) 36 { 37 report_prefix_push("sske"); 38 expect_pgm_int(); 39 set_storage_key(pagebuf, 0x30, 0); 40 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 41 expect_pgm_int(); 42 report_prefix_pop(); 43 report_prefix_push("iske"); 44 get_storage_key(pagebuf); 45 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 46 report_prefix_pop(); 47 } 48 49 static void test_pfmf(void) 50 { 51 union pfmf_r1 r1; 52 53 report_prefix_push("pfmf"); 54 r1.val = 0; 55 r1.reg.sk = 1; 56 r1.reg.fsc = PFMF_FSC_4K; 57 r1.reg.key = 0x30; 58 expect_pgm_int(); 59 pfmf(r1.val, pagebuf); 60 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 61 report_prefix_pop(); 62 } 63 64 static void test_psw_key(void) 65 { 66 uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL; 67 68 report_prefix_push("psw key"); 69 expect_pgm_int(); 70 load_psw_mask(psw_mask); 71 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 72 report_prefix_pop(); 73 } 74 75 static void test_mvcos(void) 76 { 77 uint64_t r3 = 64; 78 uint8_t *src = pagebuf; 79 uint8_t *dst = pagebuf + PAGE_SIZE; 80 /* K bit set, as well as keys */ 81 register unsigned long oac asm("0") = 0xf002f002; 82 83 report_prefix_push("mvcos"); 84 expect_pgm_int(); 85 asm volatile("mvcos %[dst],%[src],%[len]" 86 : [dst] "+Q" (*(dst)) 87 : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) 88 : "cc", "memory"); 89 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 90 report_prefix_pop(); 91 } 92 93 static void test_spka(void) 94 { 95 report_prefix_push("spka"); 96 expect_pgm_int(); 97 asm volatile("spka 0xf0(0)\n"); 98 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 99 report_prefix_pop(); 100 } 101 102 static void test_tprot(void) 103 { 104 report_prefix_push("tprot"); 105 expect_pgm_int(); 106 tprot((unsigned long)pagebuf, 0xf); 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->ext_new_psw.mask = PSW_MASK_64; 129 lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP); 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 smp_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