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>
11eef2cdb5SNico 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
write_gs_regs(void)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
check_gs_regs(void)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
have_vector_facility(void)55914ba236SNico Boehr static bool have_vector_facility(void)
56914ba236SNico Boehr {
57914ba236SNico Boehr return test_facility(129);
58914ba236SNico Boehr }
59914ba236SNico Boehr
have_guarded_storage_facility(void)60914ba236SNico Boehr static bool have_guarded_storage_facility(void)
61914ba236SNico Boehr {
62914ba236SNico Boehr return test_facility(133);
63914ba236SNico Boehr }
64914ba236SNico Boehr
test_func(void)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
main(void)160914ba236SNico Boehr int main(void)
161914ba236SNico Boehr {
162914ba236SNico Boehr /* don't say migrate here otherwise we will migrate right away */
163914ba236SNico Boehr report_prefix_push("migration");
164914ba236SNico Boehr
165914ba236SNico Boehr if (smp_query_num_cpus() == 1) {
166914ba236SNico Boehr report_skip("need at least 2 cpus for this test");
167*e6e1a201SNicholas Piggin migrate_skip();
168914ba236SNico Boehr goto done;
169914ba236SNico Boehr }
170914ba236SNico Boehr
171914ba236SNico Boehr /* Second CPU does the actual tests */
172f514b4f7SClaudio Imbrenda smp_cpu_setup(1, PSW_WITH_CUR_MASK(test_func));
173914ba236SNico Boehr
174914ba236SNico Boehr /* wait for thread setup */
175914ba236SNico Boehr while(!flag_thread_complete)
176914ba236SNico Boehr mb();
177914ba236SNico Boehr flag_thread_complete = 0;
178914ba236SNico Boehr
179eef2cdb5SNico Boehr migrate_once();
180914ba236SNico Boehr
181914ba236SNico Boehr flag_migration_complete = 1;
182914ba236SNico Boehr
183914ba236SNico Boehr /* wait for thread to complete assertions */
184914ba236SNico Boehr while(!flag_thread_complete)
185914ba236SNico Boehr mb();
186914ba236SNico Boehr
187914ba236SNico Boehr smp_cpu_destroy(1);
188914ba236SNico Boehr
189914ba236SNico Boehr done:
190914ba236SNico Boehr report_prefix_pop();
191914ba236SNico Boehr return report_summary();
192914ba236SNico Boehr }
193