147df95c7SJanosch Frank /* 247df95c7SJanosch Frank * Storage key removal facility tests 347df95c7SJanosch Frank * 447df95c7SJanosch Frank * Copyright (c) 2019 IBM Corp 547df95c7SJanosch Frank * 647df95c7SJanosch Frank * Authors: 747df95c7SJanosch Frank * Janosch Frank <frankja@linux.ibm.com> 847df95c7SJanosch Frank * 947df95c7SJanosch Frank * This code is free software; you can redistribute it and/or modify it 1047df95c7SJanosch Frank * under the terms of the GNU General Public License version 2. 1147df95c7SJanosch Frank */ 1247df95c7SJanosch Frank #include <libcflat.h> 1347df95c7SJanosch Frank #include <asm/asm-offsets.h> 14*787d1bccSJanosch Frank #include <asm-generic/barrier.h> 1547df95c7SJanosch Frank #include <asm/interrupt.h> 1647df95c7SJanosch Frank #include <asm/page.h> 1747df95c7SJanosch Frank #include <asm/facility.h> 1847df95c7SJanosch Frank #include <asm/mem.h> 19*787d1bccSJanosch Frank #include <asm/sigp.h> 20*787d1bccSJanosch Frank #include <smp.h> 2147df95c7SJanosch Frank 2247df95c7SJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 23*787d1bccSJanosch Frank static int testflag = 0; 2447df95c7SJanosch Frank 2547df95c7SJanosch Frank static void test_facilities(void) 2647df95c7SJanosch Frank { 2747df95c7SJanosch Frank report_prefix_push("facilities"); 28a299895bSThomas Huth report(!test_facility(10), "!10"); 29a299895bSThomas Huth report(!test_facility(14), "!14"); 30a299895bSThomas Huth report(!test_facility(66), "!66"); 31a299895bSThomas Huth report(!test_facility(145), "!145"); 32a299895bSThomas Huth report(!test_facility(140), "!149"); 3347df95c7SJanosch Frank report_prefix_pop(); 3447df95c7SJanosch Frank } 3547df95c7SJanosch Frank 3647df95c7SJanosch Frank static void test_skey(void) 3747df95c7SJanosch Frank { 3847df95c7SJanosch Frank report_prefix_push("sske"); 3947df95c7SJanosch Frank expect_pgm_int(); 4047df95c7SJanosch Frank set_storage_key(pagebuf, 0x30, 0); 4147df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 4247df95c7SJanosch Frank expect_pgm_int(); 4347df95c7SJanosch Frank report_prefix_pop(); 4447df95c7SJanosch Frank report_prefix_push("iske"); 4547df95c7SJanosch Frank get_storage_key(pagebuf); 4647df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 4747df95c7SJanosch Frank report_prefix_pop(); 4847df95c7SJanosch Frank } 4947df95c7SJanosch Frank 5047df95c7SJanosch Frank static void test_pfmf(void) 5147df95c7SJanosch Frank { 5247df95c7SJanosch Frank union pfmf_r1 r1; 5347df95c7SJanosch Frank 5447df95c7SJanosch Frank report_prefix_push("pfmf"); 5547df95c7SJanosch Frank r1.val = 0; 5647df95c7SJanosch Frank r1.reg.sk = 1; 5747df95c7SJanosch Frank r1.reg.fsc = PFMF_FSC_4K; 5847df95c7SJanosch Frank r1.reg.key = 0x30; 5947df95c7SJanosch Frank expect_pgm_int(); 6047df95c7SJanosch Frank pfmf(r1.val, pagebuf); 6147df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 6247df95c7SJanosch Frank report_prefix_pop(); 6347df95c7SJanosch Frank } 6447df95c7SJanosch Frank 6547df95c7SJanosch Frank static void test_psw_key(void) 6647df95c7SJanosch Frank { 6747df95c7SJanosch Frank uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL; 6847df95c7SJanosch Frank 6947df95c7SJanosch Frank report_prefix_push("psw key"); 7047df95c7SJanosch Frank expect_pgm_int(); 7147df95c7SJanosch Frank load_psw_mask(psw_mask); 7247df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 7347df95c7SJanosch Frank report_prefix_pop(); 7447df95c7SJanosch Frank } 7547df95c7SJanosch Frank 7647df95c7SJanosch Frank static void test_mvcos(void) 7747df95c7SJanosch Frank { 7847df95c7SJanosch Frank uint64_t r3 = 64; 7947df95c7SJanosch Frank uint8_t *src = pagebuf; 8047df95c7SJanosch Frank uint8_t *dst = pagebuf + PAGE_SIZE; 8147df95c7SJanosch Frank /* K bit set, as well as keys */ 8247df95c7SJanosch Frank register unsigned long oac asm("0") = 0xf002f002; 8347df95c7SJanosch Frank 8447df95c7SJanosch Frank report_prefix_push("mvcos"); 8547df95c7SJanosch Frank expect_pgm_int(); 8647df95c7SJanosch Frank asm volatile("mvcos %[dst],%[src],%[len]" 8747df95c7SJanosch Frank : [dst] "+Q" (*(dst)) 8847df95c7SJanosch Frank : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) 8947df95c7SJanosch Frank : "cc", "memory"); 9047df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 9147df95c7SJanosch Frank report_prefix_pop(); 9247df95c7SJanosch Frank } 9347df95c7SJanosch Frank 9447df95c7SJanosch Frank static void test_spka(void) 9547df95c7SJanosch Frank { 9647df95c7SJanosch Frank report_prefix_push("spka"); 9747df95c7SJanosch Frank expect_pgm_int(); 9847df95c7SJanosch Frank asm volatile("spka 0xf0(0)\n"); 9947df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 10047df95c7SJanosch Frank report_prefix_pop(); 10147df95c7SJanosch Frank } 10247df95c7SJanosch Frank 10347df95c7SJanosch Frank static void test_tprot(void) 10447df95c7SJanosch Frank { 10547df95c7SJanosch Frank report_prefix_push("tprot"); 10647df95c7SJanosch Frank expect_pgm_int(); 10747df95c7SJanosch Frank asm volatile("tprot %[addr],0xf0(0)\n" 10847df95c7SJanosch Frank : : [addr] "a" (pagebuf) : ); 10947df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 11047df95c7SJanosch Frank report_prefix_pop(); 11147df95c7SJanosch Frank } 11247df95c7SJanosch Frank 113*787d1bccSJanosch Frank static void wait_for_flag(void) 114*787d1bccSJanosch Frank { 115*787d1bccSJanosch Frank while (!testflag) 116*787d1bccSJanosch Frank mb(); 117*787d1bccSJanosch Frank } 118*787d1bccSJanosch Frank 119*787d1bccSJanosch Frank static void set_flag(int val) 120*787d1bccSJanosch Frank { 121*787d1bccSJanosch Frank mb(); 122*787d1bccSJanosch Frank testflag = val; 123*787d1bccSJanosch Frank mb(); 124*787d1bccSJanosch Frank } 125*787d1bccSJanosch Frank 126*787d1bccSJanosch Frank static void ecall_cleanup(void) 127*787d1bccSJanosch Frank { 128*787d1bccSJanosch Frank struct lowcore *lc = (void *)0x0; 129*787d1bccSJanosch Frank 130*787d1bccSJanosch Frank lc->ext_new_psw.mask = 0x0000000180000000UL; 131*787d1bccSJanosch Frank lc->sw_int_crs[0] = 0x0000000000040000; 132*787d1bccSJanosch Frank 133*787d1bccSJanosch Frank /* 134*787d1bccSJanosch Frank * PGM old contains the ext new PSW, we need to clean it up, 135*787d1bccSJanosch Frank * so we don't get a special operation exception on the lpswe 136*787d1bccSJanosch Frank * of pgm old. 137*787d1bccSJanosch Frank */ 138*787d1bccSJanosch Frank lc->pgm_old_psw.mask = 0x0000000180000000UL; 139*787d1bccSJanosch Frank 140*787d1bccSJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 141*787d1bccSJanosch Frank set_flag(1); 142*787d1bccSJanosch Frank } 143*787d1bccSJanosch Frank 144*787d1bccSJanosch Frank /* Set a key into the external new psw mask and open external call masks */ 145*787d1bccSJanosch Frank static void ecall_setup(void) 146*787d1bccSJanosch Frank { 147*787d1bccSJanosch Frank struct lowcore *lc = (void *)0x0; 148*787d1bccSJanosch Frank uint64_t mask; 149*787d1bccSJanosch Frank 150*787d1bccSJanosch Frank register_pgm_cleanup_func(ecall_cleanup); 151*787d1bccSJanosch Frank expect_pgm_int(); 152*787d1bccSJanosch Frank /* Put a skey into the ext new psw */ 153*787d1bccSJanosch Frank lc->ext_new_psw.mask = 0x00F0000180000000UL; 154*787d1bccSJanosch Frank /* Open up ext masks */ 155*787d1bccSJanosch Frank ctl_set_bit(0, 13); 156*787d1bccSJanosch Frank mask = extract_psw_mask(); 157*787d1bccSJanosch Frank mask |= PSW_MASK_EXT; 158*787d1bccSJanosch Frank load_psw_mask(mask); 159*787d1bccSJanosch Frank /* Tell cpu 0 that we're ready */ 160*787d1bccSJanosch Frank set_flag(1); 161*787d1bccSJanosch Frank } 162*787d1bccSJanosch Frank 163*787d1bccSJanosch Frank static void test_exception_ext_new(void) 164*787d1bccSJanosch Frank { 165*787d1bccSJanosch Frank struct psw psw = { 166*787d1bccSJanosch Frank .mask = extract_psw_mask(), 167*787d1bccSJanosch Frank .addr = (unsigned long)ecall_setup 168*787d1bccSJanosch Frank }; 169*787d1bccSJanosch Frank 170*787d1bccSJanosch Frank report_prefix_push("exception external new"); 171*787d1bccSJanosch Frank if (smp_query_num_cpus() < 2) { 172*787d1bccSJanosch Frank report_skip("Need second cpu for exception external new test."); 173*787d1bccSJanosch Frank report_prefix_pop(); 174*787d1bccSJanosch Frank return; 175*787d1bccSJanosch Frank } 176*787d1bccSJanosch Frank 177*787d1bccSJanosch Frank smp_cpu_setup(1, psw); 178*787d1bccSJanosch Frank wait_for_flag(); 179*787d1bccSJanosch Frank set_flag(0); 180*787d1bccSJanosch Frank 181*787d1bccSJanosch Frank sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); 182*787d1bccSJanosch Frank wait_for_flag(); 183*787d1bccSJanosch Frank smp_cpu_stop(1); 184*787d1bccSJanosch Frank report_prefix_pop(); 185*787d1bccSJanosch Frank } 186*787d1bccSJanosch Frank 18747df95c7SJanosch Frank int main(void) 18847df95c7SJanosch Frank { 18947df95c7SJanosch Frank report_prefix_push("skrf"); 19047df95c7SJanosch Frank if (!test_facility(169)) { 19147df95c7SJanosch Frank report_skip("storage key removal facility not available\n"); 19247df95c7SJanosch Frank goto done; 19347df95c7SJanosch Frank } 19447df95c7SJanosch Frank 19547df95c7SJanosch Frank test_facilities(); 19647df95c7SJanosch Frank test_skey(); 19747df95c7SJanosch Frank test_pfmf(); 19847df95c7SJanosch Frank test_psw_key(); 19947df95c7SJanosch Frank test_mvcos(); 20047df95c7SJanosch Frank test_spka(); 20147df95c7SJanosch Frank test_tprot(); 202*787d1bccSJanosch Frank test_exception_ext_new(); 20347df95c7SJanosch Frank 20447df95c7SJanosch Frank done: 20547df95c7SJanosch Frank report_prefix_pop(); 20647df95c7SJanosch Frank return report_summary(); 20747df95c7SJanosch Frank } 208