1fa624cc2SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */ 247df95c7SJanosch Frank /* 347df95c7SJanosch Frank * Storage key removal facility tests 447df95c7SJanosch Frank * 547df95c7SJanosch Frank * Copyright (c) 2019 IBM Corp 647df95c7SJanosch Frank * 747df95c7SJanosch Frank * Authors: 847df95c7SJanosch Frank * Janosch Frank <frankja@linux.ibm.com> 947df95c7SJanosch Frank */ 1047df95c7SJanosch Frank #include <libcflat.h> 11*d34d3250SJanosch Frank #include <bitops.h> 1247df95c7SJanosch Frank #include <asm/asm-offsets.h> 13787d1bccSJanosch Frank #include <asm-generic/barrier.h> 1447df95c7SJanosch Frank #include <asm/interrupt.h> 1547df95c7SJanosch Frank #include <asm/page.h> 1647df95c7SJanosch Frank #include <asm/facility.h> 1747df95c7SJanosch Frank #include <asm/mem.h> 18787d1bccSJanosch Frank #include <asm/sigp.h> 19787d1bccSJanosch Frank #include <smp.h> 2047df95c7SJanosch Frank 2147df95c7SJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 22787d1bccSJanosch Frank static int testflag = 0; 2347df95c7SJanosch Frank 2447df95c7SJanosch Frank static void test_facilities(void) 2547df95c7SJanosch Frank { 2647df95c7SJanosch Frank report_prefix_push("facilities"); 27a299895bSThomas Huth report(!test_facility(10), "!10"); 28a299895bSThomas Huth report(!test_facility(14), "!14"); 29a299895bSThomas Huth report(!test_facility(66), "!66"); 30a299895bSThomas Huth report(!test_facility(145), "!145"); 31a299895bSThomas Huth report(!test_facility(140), "!149"); 3247df95c7SJanosch Frank report_prefix_pop(); 3347df95c7SJanosch Frank } 3447df95c7SJanosch Frank 3547df95c7SJanosch Frank static void test_skey(void) 3647df95c7SJanosch Frank { 3747df95c7SJanosch Frank report_prefix_push("sske"); 3847df95c7SJanosch Frank expect_pgm_int(); 3947df95c7SJanosch Frank set_storage_key(pagebuf, 0x30, 0); 4047df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 4147df95c7SJanosch Frank expect_pgm_int(); 4247df95c7SJanosch Frank report_prefix_pop(); 4347df95c7SJanosch Frank report_prefix_push("iske"); 4447df95c7SJanosch Frank get_storage_key(pagebuf); 4547df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 4647df95c7SJanosch Frank report_prefix_pop(); 4747df95c7SJanosch Frank } 4847df95c7SJanosch Frank 4947df95c7SJanosch Frank static void test_pfmf(void) 5047df95c7SJanosch Frank { 5147df95c7SJanosch Frank union pfmf_r1 r1; 5247df95c7SJanosch Frank 5347df95c7SJanosch Frank report_prefix_push("pfmf"); 5447df95c7SJanosch Frank r1.val = 0; 5547df95c7SJanosch Frank r1.reg.sk = 1; 5647df95c7SJanosch Frank r1.reg.fsc = PFMF_FSC_4K; 5747df95c7SJanosch Frank r1.reg.key = 0x30; 5847df95c7SJanosch Frank expect_pgm_int(); 5947df95c7SJanosch Frank pfmf(r1.val, pagebuf); 6047df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 6147df95c7SJanosch Frank report_prefix_pop(); 6247df95c7SJanosch Frank } 6347df95c7SJanosch Frank 6447df95c7SJanosch Frank static void test_psw_key(void) 6547df95c7SJanosch Frank { 6647df95c7SJanosch Frank uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL; 6747df95c7SJanosch Frank 6847df95c7SJanosch Frank report_prefix_push("psw key"); 6947df95c7SJanosch Frank expect_pgm_int(); 7047df95c7SJanosch Frank load_psw_mask(psw_mask); 7147df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 7247df95c7SJanosch Frank report_prefix_pop(); 7347df95c7SJanosch Frank } 7447df95c7SJanosch Frank 7547df95c7SJanosch Frank static void test_mvcos(void) 7647df95c7SJanosch Frank { 7747df95c7SJanosch Frank uint64_t r3 = 64; 7847df95c7SJanosch Frank uint8_t *src = pagebuf; 7947df95c7SJanosch Frank uint8_t *dst = pagebuf + PAGE_SIZE; 8047df95c7SJanosch Frank /* K bit set, as well as keys */ 8147df95c7SJanosch Frank register unsigned long oac asm("0") = 0xf002f002; 8247df95c7SJanosch Frank 8347df95c7SJanosch Frank report_prefix_push("mvcos"); 8447df95c7SJanosch Frank expect_pgm_int(); 8547df95c7SJanosch Frank asm volatile("mvcos %[dst],%[src],%[len]" 8647df95c7SJanosch Frank : [dst] "+Q" (*(dst)) 8747df95c7SJanosch Frank : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) 8847df95c7SJanosch Frank : "cc", "memory"); 8947df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 9047df95c7SJanosch Frank report_prefix_pop(); 9147df95c7SJanosch Frank } 9247df95c7SJanosch Frank 9347df95c7SJanosch Frank static void test_spka(void) 9447df95c7SJanosch Frank { 9547df95c7SJanosch Frank report_prefix_push("spka"); 9647df95c7SJanosch Frank expect_pgm_int(); 9747df95c7SJanosch Frank asm volatile("spka 0xf0(0)\n"); 9847df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 9947df95c7SJanosch Frank report_prefix_pop(); 10047df95c7SJanosch Frank } 10147df95c7SJanosch Frank 10247df95c7SJanosch Frank static void test_tprot(void) 10347df95c7SJanosch Frank { 10447df95c7SJanosch Frank report_prefix_push("tprot"); 10547df95c7SJanosch Frank expect_pgm_int(); 10647df95c7SJanosch Frank asm volatile("tprot %[addr],0xf0(0)\n" 10747df95c7SJanosch Frank : : [addr] "a" (pagebuf) : ); 10847df95c7SJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); 10947df95c7SJanosch Frank report_prefix_pop(); 11047df95c7SJanosch Frank } 11147df95c7SJanosch Frank 112787d1bccSJanosch Frank static void wait_for_flag(void) 113787d1bccSJanosch Frank { 114787d1bccSJanosch Frank while (!testflag) 115787d1bccSJanosch Frank mb(); 116787d1bccSJanosch Frank } 117787d1bccSJanosch Frank 118787d1bccSJanosch Frank static void set_flag(int val) 119787d1bccSJanosch Frank { 120787d1bccSJanosch Frank mb(); 121787d1bccSJanosch Frank testflag = val; 122787d1bccSJanosch Frank mb(); 123787d1bccSJanosch Frank } 124787d1bccSJanosch Frank 125787d1bccSJanosch Frank static void ecall_cleanup(void) 126787d1bccSJanosch Frank { 127787d1bccSJanosch Frank struct lowcore *lc = (void *)0x0; 128787d1bccSJanosch Frank 12944026818SJanosch Frank lc->ext_new_psw.mask = PSW_MASK_64; 130*d34d3250SJanosch Frank lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP); 131787d1bccSJanosch Frank 132787d1bccSJanosch Frank /* 133787d1bccSJanosch Frank * PGM old contains the ext new PSW, we need to clean it up, 134787d1bccSJanosch Frank * so we don't get a special operation exception on the lpswe 135787d1bccSJanosch Frank * of pgm old. 136787d1bccSJanosch Frank */ 13744026818SJanosch Frank lc->pgm_old_psw.mask = PSW_MASK_64; 138787d1bccSJanosch Frank 139787d1bccSJanosch Frank check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 140787d1bccSJanosch Frank set_flag(1); 141787d1bccSJanosch Frank } 142787d1bccSJanosch Frank 143787d1bccSJanosch Frank /* Set a key into the external new psw mask and open external call masks */ 144787d1bccSJanosch Frank static void ecall_setup(void) 145787d1bccSJanosch Frank { 146787d1bccSJanosch Frank struct lowcore *lc = (void *)0x0; 147787d1bccSJanosch Frank uint64_t mask; 148787d1bccSJanosch Frank 149787d1bccSJanosch Frank register_pgm_cleanup_func(ecall_cleanup); 150787d1bccSJanosch Frank expect_pgm_int(); 151787d1bccSJanosch Frank /* Put a skey into the ext new psw */ 15244026818SJanosch Frank lc->ext_new_psw.mask = 0x00F0000000000000UL | PSW_MASK_64; 153787d1bccSJanosch Frank /* Open up ext masks */ 1541b2c0437SClaudio Imbrenda ctl_set_bit(0, CTL0_EXTERNAL_CALL); 155787d1bccSJanosch Frank mask = extract_psw_mask(); 156787d1bccSJanosch Frank mask |= PSW_MASK_EXT; 157787d1bccSJanosch Frank load_psw_mask(mask); 158787d1bccSJanosch Frank /* Tell cpu 0 that we're ready */ 159787d1bccSJanosch Frank set_flag(1); 160787d1bccSJanosch Frank } 161787d1bccSJanosch Frank 162787d1bccSJanosch Frank static void test_exception_ext_new(void) 163787d1bccSJanosch Frank { 164787d1bccSJanosch Frank struct psw psw = { 165787d1bccSJanosch Frank .mask = extract_psw_mask(), 166787d1bccSJanosch Frank .addr = (unsigned long)ecall_setup 167787d1bccSJanosch Frank }; 168787d1bccSJanosch Frank 169787d1bccSJanosch Frank report_prefix_push("exception external new"); 170787d1bccSJanosch Frank if (smp_query_num_cpus() < 2) { 171787d1bccSJanosch Frank report_skip("Need second cpu for exception external new test."); 172787d1bccSJanosch Frank report_prefix_pop(); 173787d1bccSJanosch Frank return; 174787d1bccSJanosch Frank } 175787d1bccSJanosch Frank 176787d1bccSJanosch Frank smp_cpu_setup(1, psw); 177787d1bccSJanosch Frank wait_for_flag(); 178787d1bccSJanosch Frank set_flag(0); 179787d1bccSJanosch Frank 180787d1bccSJanosch Frank sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); 181787d1bccSJanosch Frank wait_for_flag(); 182787d1bccSJanosch Frank smp_cpu_stop(1); 183787d1bccSJanosch Frank report_prefix_pop(); 184787d1bccSJanosch Frank } 185787d1bccSJanosch Frank 18647df95c7SJanosch Frank int main(void) 18747df95c7SJanosch Frank { 18847df95c7SJanosch Frank report_prefix_push("skrf"); 18947df95c7SJanosch Frank if (!test_facility(169)) { 19047df95c7SJanosch Frank report_skip("storage key removal facility not available\n"); 19147df95c7SJanosch Frank goto done; 19247df95c7SJanosch Frank } 19347df95c7SJanosch Frank 19447df95c7SJanosch Frank test_facilities(); 19547df95c7SJanosch Frank test_skey(); 19647df95c7SJanosch Frank test_pfmf(); 19747df95c7SJanosch Frank test_psw_key(); 19847df95c7SJanosch Frank test_mvcos(); 19947df95c7SJanosch Frank test_spka(); 20047df95c7SJanosch Frank test_tprot(); 201787d1bccSJanosch Frank test_exception_ext_new(); 20247df95c7SJanosch Frank 20347df95c7SJanosch Frank done: 20447df95c7SJanosch Frank report_prefix_pop(); 20547df95c7SJanosch Frank return report_summary(); 20647df95c7SJanosch Frank } 207