1*914ba236SNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */ 2*914ba236SNico Boehr /* 3*914ba236SNico Boehr * Migration Test for s390x 4*914ba236SNico Boehr * 5*914ba236SNico Boehr * Copyright IBM Corp. 2022 6*914ba236SNico Boehr * 7*914ba236SNico Boehr * Authors: 8*914ba236SNico Boehr * Nico Boehr <nrb@linux.ibm.com> 9*914ba236SNico Boehr */ 10*914ba236SNico Boehr #include <libcflat.h> 11*914ba236SNico Boehr #include <asm/arch_def.h> 12*914ba236SNico Boehr #include <asm/vector.h> 13*914ba236SNico Boehr #include <asm/barrier.h> 14*914ba236SNico Boehr #include <asm/facility.h> 15*914ba236SNico Boehr #include <gs.h> 16*914ba236SNico Boehr #include <bitops.h> 17*914ba236SNico Boehr #include <smp.h> 18*914ba236SNico Boehr 19*914ba236SNico Boehr static struct gs_cb gs_cb; 20*914ba236SNico Boehr static struct gs_epl gs_epl; 21*914ba236SNico Boehr 22*914ba236SNico Boehr /* set by CPU1 to signal it has completed */ 23*914ba236SNico Boehr static int flag_thread_complete; 24*914ba236SNico Boehr /* set by CPU0 to signal migration has completed */ 25*914ba236SNico Boehr static int flag_migration_complete; 26*914ba236SNico Boehr 27*914ba236SNico Boehr static void write_gs_regs(void) 28*914ba236SNico Boehr { 29*914ba236SNico Boehr const unsigned long gs_area = 0x2000000; 30*914ba236SNico Boehr const unsigned long gsc = 25; /* align = 32 M, section size = 512K */ 31*914ba236SNico Boehr 32*914ba236SNico Boehr gs_cb.gsd = gs_area | gsc; 33*914ba236SNico Boehr gs_cb.gssm = 0xfeedc0ffe; 34*914ba236SNico Boehr gs_cb.gs_epl_a = (uint64_t) &gs_epl; 35*914ba236SNico Boehr 36*914ba236SNico Boehr load_gs_cb(&gs_cb); 37*914ba236SNico Boehr } 38*914ba236SNico Boehr 39*914ba236SNico Boehr static void check_gs_regs(void) 40*914ba236SNico Boehr { 41*914ba236SNico Boehr struct gs_cb gs_cb_after_migration; 42*914ba236SNico Boehr 43*914ba236SNico Boehr store_gs_cb(&gs_cb_after_migration); 44*914ba236SNico Boehr 45*914ba236SNico Boehr report_prefix_push("guarded-storage registers"); 46*914ba236SNico Boehr 47*914ba236SNico Boehr report(gs_cb_after_migration.gsd == gs_cb.gsd, "gsd matches"); 48*914ba236SNico Boehr report(gs_cb_after_migration.gssm == gs_cb.gssm, "gssm matches"); 49*914ba236SNico Boehr report(gs_cb_after_migration.gs_epl_a == gs_cb.gs_epl_a, "gs_epl_a matches"); 50*914ba236SNico Boehr 51*914ba236SNico Boehr report_prefix_pop(); 52*914ba236SNico Boehr } 53*914ba236SNico Boehr 54*914ba236SNico Boehr static bool have_vector_facility(void) 55*914ba236SNico Boehr { 56*914ba236SNico Boehr return test_facility(129); 57*914ba236SNico Boehr } 58*914ba236SNico Boehr 59*914ba236SNico Boehr static bool have_guarded_storage_facility(void) 60*914ba236SNico Boehr { 61*914ba236SNico Boehr return test_facility(133); 62*914ba236SNico Boehr } 63*914ba236SNico Boehr 64*914ba236SNico Boehr static void test_func(void) 65*914ba236SNico Boehr { 66*914ba236SNico Boehr uint8_t expected_vec_contents[VEC_REGISTER_NUM][VEC_REGISTER_SIZE]; 67*914ba236SNico Boehr uint8_t actual_vec_contents[VEC_REGISTER_NUM][VEC_REGISTER_SIZE]; 68*914ba236SNico Boehr uint8_t *vec_reg; 69*914ba236SNico Boehr int i; 70*914ba236SNico Boehr int vec_result = 0; 71*914ba236SNico Boehr 72*914ba236SNico Boehr if (have_guarded_storage_facility()) { 73*914ba236SNico Boehr ctl_set_bit(2, CTL2_GUARDED_STORAGE); 74*914ba236SNico Boehr 75*914ba236SNico Boehr write_gs_regs(); 76*914ba236SNico Boehr } 77*914ba236SNico Boehr 78*914ba236SNico Boehr if (have_vector_facility()) { 79*914ba236SNico Boehr for (i = 0; i < VEC_REGISTER_NUM; i++) { 80*914ba236SNico Boehr vec_reg = &expected_vec_contents[i][0]; 81*914ba236SNico Boehr /* i+1 to avoid zero content */ 82*914ba236SNico Boehr memset(vec_reg, i + 1, VEC_REGISTER_SIZE); 83*914ba236SNico Boehr } 84*914ba236SNico Boehr 85*914ba236SNico Boehr ctl_set_bit(0, CTL0_VECTOR); 86*914ba236SNico Boehr 87*914ba236SNico Boehr /* 88*914ba236SNico Boehr * It is important loading the vector/floating point registers and 89*914ba236SNico Boehr * comparing their contents occurs in the same inline assembly block. 90*914ba236SNico Boehr * Otherwise, the compiler is allowed to re-use the registers for 91*914ba236SNico Boehr * something else in between. 92*914ba236SNico Boehr * For this very reason, this also runs on a second CPU, so all the 93*914ba236SNico Boehr * complex console stuff can be done in C on the first CPU and here we 94*914ba236SNico Boehr * just need to wait for it to set the flag. 95*914ba236SNico Boehr */ 96*914ba236SNico Boehr asm inline( 97*914ba236SNico Boehr " .machine z13\n" 98*914ba236SNico Boehr /* load vector registers: vlm handles at most 16 registers at a time */ 99*914ba236SNico Boehr " vlm 0,15, 0(%[expected_vec_reg])\n" 100*914ba236SNico Boehr " vlm 16,31, 256(%[expected_vec_reg])\n" 101*914ba236SNico Boehr /* inform CPU0 we are done, it will request migration */ 102*914ba236SNico Boehr " mvhi %[flag_thread_complete], 1\n" 103*914ba236SNico Boehr /* wait for migration to finish */ 104*914ba236SNico Boehr "0: clfhsi %[flag_migration_complete], 1\n" 105*914ba236SNico Boehr " jnz 0b\n" 106*914ba236SNico Boehr /* 107*914ba236SNico Boehr * store vector register contents in actual_vec_reg: vstm 108*914ba236SNico Boehr * handles at most 16 registers at a time 109*914ba236SNico Boehr */ 110*914ba236SNico Boehr " vstm 0,15, 0(%[actual_vec_reg])\n" 111*914ba236SNico Boehr " vstm 16,31, 256(%[actual_vec_reg])\n" 112*914ba236SNico Boehr /* 113*914ba236SNico Boehr * compare the contents in expected_vec_reg with actual_vec_reg: 114*914ba236SNico Boehr * clc handles at most 256 bytes at a time 115*914ba236SNico Boehr */ 116*914ba236SNico Boehr " clc 0(256, %[expected_vec_reg]), 0(%[actual_vec_reg])\n" 117*914ba236SNico Boehr " jnz 1f\n" 118*914ba236SNico Boehr " clc 256(256, %[expected_vec_reg]), 256(%[actual_vec_reg])\n" 119*914ba236SNico Boehr " jnz 1f\n" 120*914ba236SNico Boehr /* success */ 121*914ba236SNico Boehr " mvhi %[vec_result], 1\n" 122*914ba236SNico Boehr "1:" 123*914ba236SNico Boehr : 124*914ba236SNico Boehr : [expected_vec_reg] "a"(expected_vec_contents), 125*914ba236SNico Boehr [actual_vec_reg] "a"(actual_vec_contents), 126*914ba236SNico Boehr [flag_thread_complete] "Q"(flag_thread_complete), 127*914ba236SNico Boehr [flag_migration_complete] "Q"(flag_migration_complete), 128*914ba236SNico Boehr [vec_result] "Q"(vec_result) 129*914ba236SNico Boehr : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", 130*914ba236SNico Boehr "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", 131*914ba236SNico Boehr "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", 132*914ba236SNico Boehr "v28", "v29", "v30", "v31", "cc", "memory" 133*914ba236SNico Boehr ); 134*914ba236SNico Boehr 135*914ba236SNico Boehr report(vec_result, "vector contents match"); 136*914ba236SNico Boehr 137*914ba236SNico Boehr report(stctg(0) & BIT(CTL0_VECTOR), "ctl0 vector bit set"); 138*914ba236SNico Boehr 139*914ba236SNico Boehr ctl_clear_bit(0, CTL0_VECTOR); 140*914ba236SNico Boehr } else { 141*914ba236SNico Boehr flag_thread_complete = 1; 142*914ba236SNico Boehr while(!flag_migration_complete) 143*914ba236SNico Boehr mb(); 144*914ba236SNico Boehr } 145*914ba236SNico Boehr 146*914ba236SNico Boehr report_pass("Migrated"); 147*914ba236SNico Boehr 148*914ba236SNico Boehr if (have_guarded_storage_facility()) { 149*914ba236SNico Boehr check_gs_regs(); 150*914ba236SNico Boehr 151*914ba236SNico Boehr report(stctg(2) & BIT(CTL2_GUARDED_STORAGE), "ctl2 guarded-storage bit set"); 152*914ba236SNico Boehr 153*914ba236SNico Boehr ctl_clear_bit(2, CTL2_GUARDED_STORAGE); 154*914ba236SNico Boehr } 155*914ba236SNico Boehr 156*914ba236SNico Boehr flag_thread_complete = 1; 157*914ba236SNico Boehr } 158*914ba236SNico Boehr 159*914ba236SNico Boehr int main(void) 160*914ba236SNico Boehr { 161*914ba236SNico Boehr struct psw psw; 162*914ba236SNico Boehr 163*914ba236SNico Boehr /* don't say migrate here otherwise we will migrate right away */ 164*914ba236SNico Boehr report_prefix_push("migration"); 165*914ba236SNico Boehr 166*914ba236SNico Boehr if (smp_query_num_cpus() == 1) { 167*914ba236SNico Boehr report_skip("need at least 2 cpus for this test"); 168*914ba236SNico Boehr goto done; 169*914ba236SNico Boehr } 170*914ba236SNico Boehr 171*914ba236SNico Boehr /* Second CPU does the actual tests */ 172*914ba236SNico Boehr psw.mask = extract_psw_mask(); 173*914ba236SNico Boehr psw.addr = (unsigned long)test_func; 174*914ba236SNico Boehr smp_cpu_setup(1, psw); 175*914ba236SNico Boehr 176*914ba236SNico Boehr /* wait for thread setup */ 177*914ba236SNico Boehr while(!flag_thread_complete) 178*914ba236SNico Boehr mb(); 179*914ba236SNico Boehr flag_thread_complete = 0; 180*914ba236SNico Boehr 181*914ba236SNico Boehr /* ask migrate_cmd to migrate (it listens for 'migrate') */ 182*914ba236SNico Boehr puts("Please migrate me, then press return\n"); 183*914ba236SNico Boehr 184*914ba236SNico Boehr /* wait for migration to finish, we will read a newline */ 185*914ba236SNico Boehr (void)getchar(); 186*914ba236SNico Boehr 187*914ba236SNico Boehr flag_migration_complete = 1; 188*914ba236SNico Boehr 189*914ba236SNico Boehr /* wait for thread to complete assertions */ 190*914ba236SNico Boehr while(!flag_thread_complete) 191*914ba236SNico Boehr mb(); 192*914ba236SNico Boehr 193*914ba236SNico Boehr smp_cpu_destroy(1); 194*914ba236SNico Boehr 195*914ba236SNico Boehr done: 196*914ba236SNico Boehr report_prefix_pop(); 197*914ba236SNico Boehr return report_summary(); 198*914ba236SNico Boehr } 199