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