xref: /kvm-unit-tests/s390x/epsw.c (revision c315f52b88b967cfb4cd58f3b4e1987378c47f3b)
148e9236cSNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */
248e9236cSNico Boehr /*
348e9236cSNico Boehr  * EPSW Interception Tests
448e9236cSNico Boehr  *
548e9236cSNico Boehr  * Copyright IBM Corp. 2022
648e9236cSNico Boehr  *
748e9236cSNico Boehr  * Authors:
848e9236cSNico Boehr  *  Nico Boehr <nrb@linux.ibm.com>
948e9236cSNico Boehr  */
1048e9236cSNico Boehr #include <libcflat.h>
1148e9236cSNico Boehr #include <css.h>
12f489dfa5SClaudio Imbrenda #include <hardware.h>
1348e9236cSNico Boehr 
zero_out_cc_from_epsw_op1(uint32_t epsw_op1)1448e9236cSNico Boehr static uint32_t zero_out_cc_from_epsw_op1(uint32_t epsw_op1)
1548e9236cSNico Boehr {
1648e9236cSNico Boehr 	return epsw_op1 & ~GENMASK(31 - 18, 31 - 20);
1748e9236cSNico Boehr }
1848e9236cSNico Boehr 
generate_crw(void)1948e9236cSNico Boehr static void generate_crw(void)
2048e9236cSNico Boehr {
2148e9236cSNico Boehr 	int test_device_sid = css_enumerate();
2248e9236cSNico Boehr 	int cc, ret;
2348e9236cSNico Boehr 
2448e9236cSNico Boehr 	if (!(test_device_sid & SCHID_ONE)) {
2548e9236cSNico Boehr 		report_fail("No I/O device found");
2648e9236cSNico Boehr 		return;
2748e9236cSNico Boehr 	}
2848e9236cSNico Boehr 
2948e9236cSNico Boehr 	cc = css_enable(test_device_sid, IO_SCH_ISC);
3048e9236cSNico Boehr 	report(cc == 0, "Enable subchannel %08x", test_device_sid);
3148e9236cSNico Boehr 
3248e9236cSNico Boehr 	ret = css_generate_crw(test_device_sid);
3348e9236cSNico Boehr 	if (ret)
3448e9236cSNico Boehr 		report_fail("Couldn't generate CRW");
3548e9236cSNico Boehr }
3648e9236cSNico Boehr 
test_epsw(void)3748e9236cSNico Boehr static void test_epsw(void)
3848e9236cSNico Boehr {
3948e9236cSNico Boehr 	const uint64_t MAGIC1 = 0x1234567890abcdefUL;
4048e9236cSNico Boehr 	const uint64_t MAGIC2 = 0xcafedeadbeeffaceUL;
4148e9236cSNico Boehr 
4248e9236cSNico Boehr 	uint64_t op1 = MAGIC1;
4348e9236cSNico Boehr 	uint64_t op2 = MAGIC2;
4448e9236cSNico Boehr 	uint32_t prev_epsw_op1;
4548e9236cSNico Boehr 
4648e9236cSNico Boehr 	/*
4748e9236cSNico Boehr 	 * having machine check interrupts masked and pending CRW ensures
4848e9236cSNico Boehr 	 * EPSW is intercepted under KVM
4948e9236cSNico Boehr 	 */
5048e9236cSNico Boehr 	generate_crw();
5148e9236cSNico Boehr 
5248e9236cSNico Boehr 	report_prefix_push("both operands given");
5348e9236cSNico Boehr 	asm volatile(
5448e9236cSNico Boehr 		"epsw %0, %1\n"
5548e9236cSNico Boehr 		: "+&d" (op1), "+&a" (op2));
5648e9236cSNico Boehr 	report(upper_32_bits(op1) == upper_32_bits(MAGIC1) &&
5748e9236cSNico Boehr 	       upper_32_bits(op2) == upper_32_bits(MAGIC2),
5848e9236cSNico Boehr 	       "upper 32 bits unmodified");
5948e9236cSNico Boehr 	report(lower_32_bits(op1) != lower_32_bits(MAGIC1) &&
6048e9236cSNico Boehr 	       lower_32_bits(op2) != lower_32_bits(MAGIC2),
6148e9236cSNico Boehr 	       "lower 32 bits modified");
6248e9236cSNico Boehr 	prev_epsw_op1 = zero_out_cc_from_epsw_op1(lower_32_bits(op1));
6348e9236cSNico Boehr 	report_prefix_pop();
6448e9236cSNico Boehr 
6548e9236cSNico Boehr 	report_prefix_push("second operand 0");
6648e9236cSNico Boehr 	op1 = MAGIC1;
6748e9236cSNico Boehr 	op2 = MAGIC2;
6848e9236cSNico Boehr 	asm volatile(
6948e9236cSNico Boehr 		"	lgr 0,%[op2]\n"
7048e9236cSNico Boehr 		"	epsw %[op1], 0\n"
7148e9236cSNico Boehr 		"	lgr %[op2],0\n"
7248e9236cSNico Boehr 		: [op2] "+&d" (op2), [op1] "+&a" (op1)
7348e9236cSNico Boehr 		:
7448e9236cSNico Boehr 		: "0");
7548e9236cSNico Boehr 	report(upper_32_bits(op1) == upper_32_bits(MAGIC1),
7648e9236cSNico Boehr 	       "upper 32 bits of first operand unmodified");
7748e9236cSNico Boehr 	report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1,
7848e9236cSNico Boehr 	       "first operand matches previous reading");
7948e9236cSNico Boehr 	report(op2 == MAGIC2, "r0 unmodified");
8048e9236cSNico Boehr 	report_prefix_pop();
8148e9236cSNico Boehr 
8248e9236cSNico Boehr 	report_prefix_push("both operands 0");
8348e9236cSNico Boehr 	op1 = MAGIC1;
8448e9236cSNico Boehr 	asm volatile(
8548e9236cSNico Boehr 		"	lgr 0,%[op1]\n"
8648e9236cSNico Boehr 		"	epsw 0, 0\n"
8748e9236cSNico Boehr 		"	lgr %[op1],0\n"
8848e9236cSNico Boehr 		: [op1] "+&d" (op1)
8948e9236cSNico Boehr 		:
9048e9236cSNico Boehr 		: "0");
9148e9236cSNico Boehr 	report(upper_32_bits(op1) == upper_32_bits(MAGIC1),
9248e9236cSNico Boehr 	       "upper 32 bits of first operand unmodified");
9348e9236cSNico Boehr 	report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1,
9448e9236cSNico Boehr 	       "first operand matches previous reading");
9548e9236cSNico Boehr 	report_prefix_pop();
9648e9236cSNico Boehr }
9748e9236cSNico Boehr 
main(int argc,char ** argv)9848e9236cSNico Boehr int main(int argc, char **argv)
9948e9236cSNico Boehr {
100*fc0d9b41SNico Boehr 	report_prefix_push("epsw");
101*fc0d9b41SNico Boehr 
102f489dfa5SClaudio Imbrenda 	if (!host_is_kvm() && !host_is_tcg()) {
10348e9236cSNico Boehr 		report_skip("Not running under QEMU");
10448e9236cSNico Boehr 		goto done;
10548e9236cSNico Boehr 	}
10648e9236cSNico Boehr 
10748e9236cSNico Boehr 	test_epsw();
10848e9236cSNico Boehr 
10948e9236cSNico Boehr done:
11048e9236cSNico Boehr 	report_prefix_pop();
11148e9236cSNico Boehr 
11248e9236cSNico Boehr 	return report_summary();
11348e9236cSNico Boehr }
114