xref: /kvm-unit-tests/s390x/pv-diags.c (revision 1d0f08f40d53daa39566842ec46a112db5f7e524)
12c96b77eSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
22c96b77eSJanosch Frank /*
32c96b77eSJanosch Frank  * PV virtualization interception tests for diagnose instructions.
42c96b77eSJanosch Frank  *
52c96b77eSJanosch Frank  * Copyright (c) 2021 IBM Corp
62c96b77eSJanosch Frank  *
72c96b77eSJanosch Frank  * Authors:
82c96b77eSJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
92c96b77eSJanosch Frank  */
102c96b77eSJanosch Frank #include <libcflat.h>
112c96b77eSJanosch Frank #include <snippet.h>
12617f251fSJanosch Frank #include <pv_icptdata.h>
132c96b77eSJanosch Frank #include <sie.h>
14c4082444SJanosch Frank #include <sclp.h>
15c4082444SJanosch Frank #include <asm/facility.h>
162c96b77eSJanosch Frank 
172c96b77eSJanosch Frank static struct vm vm;
182c96b77eSJanosch Frank 
192c96b77eSJanosch Frank static void test_diag_500(void)
202c96b77eSJanosch Frank {
21*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_START(asm, pv_diag_500)[];
22*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_END(asm, pv_diag_500)[];
23*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_START(asm, pv_diag_500)[];
24*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_END(asm, pv_diag_500)[];
25*1d0f08f4SJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_500);
26*1d0f08f4SJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, pv_diag_500);
272c96b77eSJanosch Frank 
282c96b77eSJanosch Frank 	report_prefix_push("diag 0x500");
292c96b77eSJanosch Frank 
30*1d0f08f4SJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_500),
31*1d0f08f4SJanosch Frank 			SNIPPET_HDR_START(asm, pv_diag_500),
32b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
332c96b77eSJanosch Frank 
342c96b77eSJanosch Frank 	sie(&vm);
35617f251fSJanosch Frank 	report(pv_icptdata_check_diag(&vm, 0x500),
362c96b77eSJanosch Frank 	       "intercept values");
372c96b77eSJanosch Frank 	report(vm.save_area.guest.grs[1] == 1 &&
382c96b77eSJanosch Frank 	       vm.save_area.guest.grs[2] == 2 &&
392c96b77eSJanosch Frank 	       vm.save_area.guest.grs[3] == 3 &&
402c96b77eSJanosch Frank 	       vm.save_area.guest.grs[4] == 4,
412c96b77eSJanosch Frank 	       "register values");
422c96b77eSJanosch Frank 	/*
432c96b77eSJanosch Frank 	 * Check if we can inject a PGM operand which we are always
442c96b77eSJanosch Frank 	 * allowed to do after a diag500 exit.
452c96b77eSJanosch Frank 	 */
462c96b77eSJanosch Frank 	vm.sblk->iictl = IICTL_CODE_OPERAND;
472c96b77eSJanosch Frank 	sie(&vm);
48617f251fSJanosch Frank 	report(pv_icptdata_check_diag(&vm, 0x9c) &&
49617f251fSJanosch Frank 	       vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND,
502c96b77eSJanosch Frank 	       "operand exception");
512c96b77eSJanosch Frank 
522c96b77eSJanosch Frank 	/*
532c96b77eSJanosch Frank 	 * Check if we can inject a PGM specification which we are always
542c96b77eSJanosch Frank 	 * allowed to do after a diag500 exit.
552c96b77eSJanosch Frank 	 */
562c96b77eSJanosch Frank 	sie(&vm);
572c96b77eSJanosch Frank 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
582c96b77eSJanosch Frank 	/* Inject PGM, next exit should be 9c */
592c96b77eSJanosch Frank 	sie(&vm);
60617f251fSJanosch Frank 	report(pv_icptdata_check_diag(&vm, 0x9c) &&
61617f251fSJanosch Frank 	       vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
622c96b77eSJanosch Frank 	       "specification exception");
632c96b77eSJanosch Frank 
642c96b77eSJanosch Frank 	/* No need for cleanup, just tear down the VM */
652c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
662c96b77eSJanosch Frank 
672c96b77eSJanosch Frank 	report_prefix_pop();
682c96b77eSJanosch Frank }
692c96b77eSJanosch Frank 
702c96b77eSJanosch Frank 
712c96b77eSJanosch Frank static void test_diag_288(void)
722c96b77eSJanosch Frank {
73*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_START(asm, pv_diag_288)[];
74*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_END(asm, pv_diag_288)[];
75*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_START(asm, pv_diag_288)[];
76*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_END(asm, pv_diag_288)[];
77*1d0f08f4SJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_288);
78*1d0f08f4SJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, pv_diag_288);
792c96b77eSJanosch Frank 
802c96b77eSJanosch Frank 	report_prefix_push("diag 0x288");
812c96b77eSJanosch Frank 
82*1d0f08f4SJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_288),
83*1d0f08f4SJanosch Frank 			SNIPPET_HDR_START(asm, pv_diag_288),
84b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
852c96b77eSJanosch Frank 
862c96b77eSJanosch Frank 	sie(&vm);
872c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
882c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288,
892c96b77eSJanosch Frank 	       "intercept values");
902c96b77eSJanosch Frank 	report(vm.save_area.guest.grs[0] == 1 &&
912c96b77eSJanosch Frank 	       vm.save_area.guest.grs[1] == 2 &&
922c96b77eSJanosch Frank 	       vm.save_area.guest.grs[2] == 3,
932c96b77eSJanosch Frank 	       "register values");
942c96b77eSJanosch Frank 
952c96b77eSJanosch Frank 	/*
962c96b77eSJanosch Frank 	 * Check if we can inject a PGM spec which we are always
972c96b77eSJanosch Frank 	 * allowed to do after a diag288 exit.
982c96b77eSJanosch Frank 	 */
992c96b77eSJanosch Frank 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
1002c96b77eSJanosch Frank 	sie(&vm);
1012c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1022c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
1032c96b77eSJanosch Frank 	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
1042c96b77eSJanosch Frank 	       "specification exception");
1052c96b77eSJanosch Frank 
1062c96b77eSJanosch Frank 	/* No need for cleanup, just tear down the VM */
1072c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
1082c96b77eSJanosch Frank 
1092c96b77eSJanosch Frank 	report_prefix_pop();
1102c96b77eSJanosch Frank }
1112c96b77eSJanosch Frank 
1122c96b77eSJanosch Frank static void test_diag_yield(void)
1132c96b77eSJanosch Frank {
114*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_START(asm, pv_diag_yield)[];
115*1d0f08f4SJanosch Frank 	extern const char SNIPPET_NAME_END(asm, pv_diag_yield)[];
116*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_START(asm, pv_diag_yield)[];
117*1d0f08f4SJanosch Frank 	extern const char SNIPPET_HDR_END(asm, pv_diag_yield)[];
118*1d0f08f4SJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_yield);
119*1d0f08f4SJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, pv_diag_yield);
1202c96b77eSJanosch Frank 
1212c96b77eSJanosch Frank 	report_prefix_push("diag yield");
1222c96b77eSJanosch Frank 
123*1d0f08f4SJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_yield),
124*1d0f08f4SJanosch Frank 			SNIPPET_HDR_START(asm, pv_diag_yield),
125b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
1262c96b77eSJanosch Frank 
1272c96b77eSJanosch Frank 	/* 0x44 */
1282c96b77eSJanosch Frank 	report_prefix_push("0x44");
1292c96b77eSJanosch Frank 	sie(&vm);
1302c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1312c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44,
1322c96b77eSJanosch Frank 	       "intercept values");
1332c96b77eSJanosch Frank 	report_prefix_pop();
1342c96b77eSJanosch Frank 
1352c96b77eSJanosch Frank 	/* 0x9c */
1362c96b77eSJanosch Frank 	report_prefix_push("0x9c");
1372c96b77eSJanosch Frank 	sie(&vm);
1382c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1392c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c,
1402c96b77eSJanosch Frank 	       "intercept values");
1412c96b77eSJanosch Frank 	report(vm.save_area.guest.grs[0] == 42, "r1 correct");
1422c96b77eSJanosch Frank 	report_prefix_pop();
1432c96b77eSJanosch Frank 
1442c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
1452c96b77eSJanosch Frank 	report_prefix_pop();
1462c96b77eSJanosch Frank }
1472c96b77eSJanosch Frank 
1482c96b77eSJanosch Frank 
1492c96b77eSJanosch Frank int main(void)
1502c96b77eSJanosch Frank {
1512c96b77eSJanosch Frank 	report_prefix_push("pv-diags");
1522c96b77eSJanosch Frank 	if (!test_facility(158)) {
1532c96b77eSJanosch Frank 		report_skip("UV Call facility unavailable");
1542c96b77eSJanosch Frank 		goto done;
1552c96b77eSJanosch Frank 	}
1562c96b77eSJanosch Frank 	if (!sclp_facilities.has_sief2) {
1572c96b77eSJanosch Frank 		report_skip("SIEF2 facility unavailable");
1582c96b77eSJanosch Frank 		goto done;
1592c96b77eSJanosch Frank 	}
1602c96b77eSJanosch Frank 
1612c96b77eSJanosch Frank 	uv_setup_asces();
1622c96b77eSJanosch Frank 	snippet_setup_guest(&vm, true);
1632c96b77eSJanosch Frank 	test_diag_yield();
1642c96b77eSJanosch Frank 	test_diag_288();
1652c96b77eSJanosch Frank 	test_diag_500();
1662c96b77eSJanosch Frank 	sie_guest_destroy(&vm);
1672c96b77eSJanosch Frank 
1682c96b77eSJanosch Frank done:
1692c96b77eSJanosch Frank 	report_prefix_pop();
1702c96b77eSJanosch Frank 	return report_summary();
1712c96b77eSJanosch Frank }
172