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