1914ba236SNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */ 2914ba236SNico Boehr /* 3914ba236SNico Boehr * Migration Test for s390x 4914ba236SNico Boehr * 5914ba236SNico Boehr * Copyright IBM Corp. 2022 6914ba236SNico Boehr * 7914ba236SNico Boehr * Authors: 8914ba236SNico Boehr * Nico Boehr <nrb@linux.ibm.com> 9914ba236SNico Boehr */ 10914ba236SNico Boehr #include <libcflat.h> 11*eef2cdb5SNico Boehr #include <migrate.h> 12914ba236SNico Boehr #include <asm/arch_def.h> 13914ba236SNico Boehr #include <asm/vector.h> 14914ba236SNico Boehr #include <asm/barrier.h> 15914ba236SNico Boehr #include <asm/facility.h> 16914ba236SNico Boehr #include <gs.h> 17914ba236SNico Boehr #include <bitops.h> 18914ba236SNico Boehr #include <smp.h> 19914ba236SNico Boehr 20914ba236SNico Boehr static struct gs_cb gs_cb; 21914ba236SNico Boehr static struct gs_epl gs_epl; 22914ba236SNico Boehr 23914ba236SNico Boehr /* set by CPU1 to signal it has completed */ 24914ba236SNico Boehr static int flag_thread_complete; 25914ba236SNico Boehr /* set by CPU0 to signal migration has completed */ 26914ba236SNico Boehr static int flag_migration_complete; 27914ba236SNico Boehr 28914ba236SNico Boehr static void write_gs_regs(void) 29914ba236SNico Boehr { 30914ba236SNico Boehr const unsigned long gs_area = 0x2000000; 31914ba236SNico Boehr const unsigned long gsc = 25; /* align = 32 M, section size = 512K */ 32914ba236SNico Boehr 33914ba236SNico Boehr gs_cb.gsd = gs_area | gsc; 34914ba236SNico Boehr gs_cb.gssm = 0xfeedc0ffe; 35914ba236SNico Boehr gs_cb.gs_epl_a = (uint64_t) &gs_epl; 36914ba236SNico Boehr 37914ba236SNico Boehr load_gs_cb(&gs_cb); 38914ba236SNico Boehr } 39914ba236SNico Boehr 40914ba236SNico Boehr static void check_gs_regs(void) 41914ba236SNico Boehr { 42914ba236SNico Boehr struct gs_cb gs_cb_after_migration; 43914ba236SNico Boehr 44914ba236SNico Boehr store_gs_cb(&gs_cb_after_migration); 45914ba236SNico Boehr 46914ba236SNico Boehr report_prefix_push("guarded-storage registers"); 47914ba236SNico Boehr 48914ba236SNico Boehr report(gs_cb_after_migration.gsd == gs_cb.gsd, "gsd matches"); 49914ba236SNico Boehr report(gs_cb_after_migration.gssm == gs_cb.gssm, "gssm matches"); 50914ba236SNico Boehr report(gs_cb_after_migration.gs_epl_a == gs_cb.gs_epl_a, "gs_epl_a matches"); 51914ba236SNico Boehr 52914ba236SNico Boehr report_prefix_pop(); 53914ba236SNico Boehr } 54914ba236SNico Boehr 55914ba236SNico Boehr static bool have_vector_facility(void) 56914ba236SNico Boehr { 57914ba236SNico Boehr return test_facility(129); 58914ba236SNico Boehr } 59914ba236SNico Boehr 60914ba236SNico Boehr static bool have_guarded_storage_facility(void) 61914ba236SNico Boehr { 62914ba236SNico Boehr return test_facility(133); 63914ba236SNico Boehr } 64914ba236SNico Boehr 65914ba236SNico Boehr static void test_func(void) 66914ba236SNico Boehr { 67914ba236SNico Boehr uint8_t expected_vec_contents[VEC_REGISTER_NUM][VEC_REGISTER_SIZE]; 68914ba236SNico Boehr uint8_t actual_vec_contents[VEC_REGISTER_NUM][VEC_REGISTER_SIZE]; 69914ba236SNico Boehr uint8_t *vec_reg; 70914ba236SNico Boehr int i; 71914ba236SNico Boehr int vec_result = 0; 72914ba236SNico Boehr 73914ba236SNico Boehr if (have_guarded_storage_facility()) { 74914ba236SNico Boehr ctl_set_bit(2, CTL2_GUARDED_STORAGE); 75914ba236SNico Boehr 76914ba236SNico Boehr write_gs_regs(); 77914ba236SNico Boehr } 78914ba236SNico Boehr 79914ba236SNico Boehr if (have_vector_facility()) { 80914ba236SNico Boehr for (i = 0; i < VEC_REGISTER_NUM; i++) { 81914ba236SNico Boehr vec_reg = &expected_vec_contents[i][0]; 82914ba236SNico Boehr /* i+1 to avoid zero content */ 83914ba236SNico Boehr memset(vec_reg, i + 1, VEC_REGISTER_SIZE); 84914ba236SNico Boehr } 85914ba236SNico Boehr 86914ba236SNico Boehr ctl_set_bit(0, CTL0_VECTOR); 87914ba236SNico Boehr 88914ba236SNico Boehr /* 89914ba236SNico Boehr * It is important loading the vector/floating point registers and 90914ba236SNico Boehr * comparing their contents occurs in the same inline assembly block. 91914ba236SNico Boehr * Otherwise, the compiler is allowed to re-use the registers for 92914ba236SNico Boehr * something else in between. 93914ba236SNico Boehr * For this very reason, this also runs on a second CPU, so all the 94914ba236SNico Boehr * complex console stuff can be done in C on the first CPU and here we 95914ba236SNico Boehr * just need to wait for it to set the flag. 96914ba236SNico Boehr */ 97914ba236SNico Boehr asm inline( 98914ba236SNico Boehr " .machine z13\n" 99914ba236SNico Boehr /* load vector registers: vlm handles at most 16 registers at a time */ 100914ba236SNico Boehr " vlm 0,15, 0(%[expected_vec_reg])\n" 101914ba236SNico Boehr " vlm 16,31, 256(%[expected_vec_reg])\n" 102914ba236SNico Boehr /* inform CPU0 we are done, it will request migration */ 103914ba236SNico Boehr " mvhi %[flag_thread_complete], 1\n" 104914ba236SNico Boehr /* wait for migration to finish */ 105914ba236SNico Boehr "0: clfhsi %[flag_migration_complete], 1\n" 106914ba236SNico Boehr " jnz 0b\n" 107914ba236SNico Boehr /* 108914ba236SNico Boehr * store vector register contents in actual_vec_reg: vstm 109914ba236SNico Boehr * handles at most 16 registers at a time 110914ba236SNico Boehr */ 111914ba236SNico Boehr " vstm 0,15, 0(%[actual_vec_reg])\n" 112914ba236SNico Boehr " vstm 16,31, 256(%[actual_vec_reg])\n" 113914ba236SNico Boehr /* 114914ba236SNico Boehr * compare the contents in expected_vec_reg with actual_vec_reg: 115914ba236SNico Boehr * clc handles at most 256 bytes at a time 116914ba236SNico Boehr */ 117914ba236SNico Boehr " clc 0(256, %[expected_vec_reg]), 0(%[actual_vec_reg])\n" 118914ba236SNico Boehr " jnz 1f\n" 119914ba236SNico Boehr " clc 256(256, %[expected_vec_reg]), 256(%[actual_vec_reg])\n" 120914ba236SNico Boehr " jnz 1f\n" 121914ba236SNico Boehr /* success */ 122914ba236SNico Boehr " mvhi %[vec_result], 1\n" 123914ba236SNico Boehr "1:" 124914ba236SNico Boehr : 125914ba236SNico Boehr : [expected_vec_reg] "a"(expected_vec_contents), 126914ba236SNico Boehr [actual_vec_reg] "a"(actual_vec_contents), 127914ba236SNico Boehr [flag_thread_complete] "Q"(flag_thread_complete), 128914ba236SNico Boehr [flag_migration_complete] "Q"(flag_migration_complete), 129914ba236SNico Boehr [vec_result] "Q"(vec_result) 130914ba236SNico Boehr : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", 131914ba236SNico Boehr "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", 132914ba236SNico Boehr "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", 133914ba236SNico Boehr "v28", "v29", "v30", "v31", "cc", "memory" 134914ba236SNico Boehr ); 135914ba236SNico Boehr 136914ba236SNico Boehr report(vec_result, "vector contents match"); 137914ba236SNico Boehr 138914ba236SNico Boehr report(stctg(0) & BIT(CTL0_VECTOR), "ctl0 vector bit set"); 139914ba236SNico Boehr 140914ba236SNico Boehr ctl_clear_bit(0, CTL0_VECTOR); 141914ba236SNico Boehr } else { 142914ba236SNico Boehr flag_thread_complete = 1; 143914ba236SNico Boehr while(!flag_migration_complete) 144914ba236SNico Boehr mb(); 145914ba236SNico Boehr } 146914ba236SNico Boehr 147914ba236SNico Boehr report_pass("Migrated"); 148914ba236SNico Boehr 149914ba236SNico Boehr if (have_guarded_storage_facility()) { 150914ba236SNico Boehr check_gs_regs(); 151914ba236SNico Boehr 152914ba236SNico Boehr report(stctg(2) & BIT(CTL2_GUARDED_STORAGE), "ctl2 guarded-storage bit set"); 153914ba236SNico Boehr 154914ba236SNico Boehr ctl_clear_bit(2, CTL2_GUARDED_STORAGE); 155914ba236SNico Boehr } 156914ba236SNico Boehr 157914ba236SNico Boehr flag_thread_complete = 1; 158914ba236SNico Boehr } 159914ba236SNico Boehr 160914ba236SNico Boehr int main(void) 161914ba236SNico Boehr { 162914ba236SNico Boehr struct psw psw; 163914ba236SNico Boehr 164914ba236SNico Boehr /* don't say migrate here otherwise we will migrate right away */ 165914ba236SNico Boehr report_prefix_push("migration"); 166914ba236SNico Boehr 167914ba236SNico Boehr if (smp_query_num_cpus() == 1) { 168914ba236SNico Boehr report_skip("need at least 2 cpus for this test"); 169914ba236SNico Boehr goto done; 170914ba236SNico Boehr } 171914ba236SNico Boehr 172914ba236SNico Boehr /* Second CPU does the actual tests */ 173914ba236SNico Boehr psw.mask = extract_psw_mask(); 174914ba236SNico Boehr psw.addr = (unsigned long)test_func; 175914ba236SNico Boehr smp_cpu_setup(1, psw); 176914ba236SNico Boehr 177914ba236SNico Boehr /* wait for thread setup */ 178914ba236SNico Boehr while(!flag_thread_complete) 179914ba236SNico Boehr mb(); 180914ba236SNico Boehr flag_thread_complete = 0; 181914ba236SNico Boehr 182*eef2cdb5SNico Boehr migrate_once(); 183914ba236SNico Boehr 184914ba236SNico Boehr flag_migration_complete = 1; 185914ba236SNico Boehr 186914ba236SNico Boehr /* wait for thread to complete assertions */ 187914ba236SNico Boehr while(!flag_thread_complete) 188914ba236SNico Boehr mb(); 189914ba236SNico Boehr 190914ba236SNico Boehr smp_cpu_destroy(1); 191914ba236SNico Boehr 192914ba236SNico Boehr done: 193914ba236SNico Boehr report_prefix_pop(); 194914ba236SNico Boehr return report_summary(); 195914ba236SNico Boehr } 196