xref: /kvm-unit-tests/s390x/migration.c (revision e6e1a20143625acb08a3f8ae25ec06846356d891)
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