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 report_prefix_push("psw key"); 67 expect_pgm_int(); 68 psw_mask_set_bits(PSW_MASK_KEY); 69 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 70 report_prefix_pop(); 71 } 72 73 static void test_mvcos(void) 74 { 75 uint64_t r3 = 64; 76 uint8_t *src = pagebuf; 77 uint8_t *dst = pagebuf + PAGE_SIZE; 78 /* K bit set, as well as keys */ 79 register unsigned long oac asm("0") = 0xf002f002; 80 81 report_prefix_push("mvcos"); 82 expect_pgm_int(); 83 asm volatile("mvcos %[dst],%[src],%[len]" 84 : [dst] "+Q" (*(dst)) 85 : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) 86 : "cc", "memory"); 87 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 88 report_prefix_pop(); 89 } 90 91 static void test_spka(void) 92 { 93 report_prefix_push("spka"); 94 expect_pgm_int(); 95 asm volatile("spka 0xf0(0)\n"); 96 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 97 report_prefix_pop(); 98 } 99 100 static void test_tprot(void) 101 { 102 report_prefix_push("tprot"); 103 expect_pgm_int(); 104 tprot((unsigned long)pagebuf, 0xf); 105 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 106 report_prefix_pop(); 107 } 108 109 static void wait_for_flag(void) 110 { 111 while (!testflag) 112 mb(); 113 } 114 115 static void set_flag(int val) 116 { 117 mb(); 118 testflag = val; 119 mb(); 120 } 121 122 static void ecall_cleanup(struct stack_frame_int *stack) 123 { 124 lowcore.ext_new_psw.mask = PSW_MASK_64; 125 lowcore.sw_int_crs[0] = BIT_ULL(CTL0_AFP); 126 127 /* 128 * PGM old contains the ext new PSW, we need to clean it up, 129 * so we don't get a special operation exception on the lpswe 130 * of pgm old. 131 */ 132 lowcore.pgm_old_psw.mask = PSW_MASK_64; 133 134 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 135 set_flag(1); 136 } 137 138 /* Set a key into the external new psw mask and open external call masks */ 139 static void ecall_setup(void) 140 { 141 register_pgm_cleanup_func(ecall_cleanup); 142 expect_pgm_int(); 143 /* Put a skey into the ext new psw */ 144 lowcore.ext_new_psw.mask = PSW_MASK_KEY | PSW_MASK_64; 145 /* Open up ext masks */ 146 ctl_set_bit(0, CTL0_EXTERNAL_CALL); 147 psw_mask_set_bits(PSW_MASK_EXT); 148 /* Tell cpu 0 that we're ready */ 149 set_flag(1); 150 } 151 152 static void test_exception_ext_new(void) 153 { 154 report_prefix_push("exception external new"); 155 if (smp_query_num_cpus() < 2) { 156 report_skip("Need second cpu for exception external new test."); 157 report_prefix_pop(); 158 return; 159 } 160 161 smp_cpu_setup(1, PSW_WITH_CUR_MASK(ecall_setup)); 162 wait_for_flag(); 163 set_flag(0); 164 165 smp_sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); 166 wait_for_flag(); 167 smp_cpu_stop(1); 168 report_prefix_pop(); 169 } 170 171 int main(void) 172 { 173 report_prefix_push("skrf"); 174 if (!test_facility(169)) { 175 report_skip("storage key removal facility not available\n"); 176 goto done; 177 } 178 179 test_facilities(); 180 test_skey(); 181 test_pfmf(); 182 test_psw_key(); 183 test_mvcos(); 184 test_spka(); 185 test_tprot(); 186 test_exception_ext_new(); 187 188 done: 189 report_prefix_pop(); 190 return report_summary(); 191 } 192