xref: /kvm-unit-tests/s390x/pv-diags.c (revision b36f35a82ff4cec5f71a68aa782332e2bc3488f7)
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>
122c96b77eSJanosch Frank #include <sie.h>
13c4082444SJanosch Frank #include <sclp.h>
14c4082444SJanosch Frank #include <asm/facility.h>
152c96b77eSJanosch Frank 
162c96b77eSJanosch Frank static struct vm vm;
172c96b77eSJanosch Frank 
182c96b77eSJanosch Frank static void test_diag_500(void)
192c96b77eSJanosch Frank {
202c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_500)[];
212c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_500)[];
222c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_500)[];
232c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_500)[];
242c96b77eSJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_500);
252c96b77eSJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_500);
262c96b77eSJanosch Frank 
272c96b77eSJanosch Frank 	report_prefix_push("diag 0x500");
282c96b77eSJanosch Frank 
292c96b77eSJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_500),
302c96b77eSJanosch Frank 			SNIPPET_HDR_START(asm, snippet_pv_diag_500),
31*b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
322c96b77eSJanosch Frank 
332c96b77eSJanosch Frank 	sie(&vm);
342c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
352c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 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);
482c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
492c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
502c96b77eSJanosch Frank 	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND,
512c96b77eSJanosch Frank 	       "operand exception");
522c96b77eSJanosch Frank 
532c96b77eSJanosch Frank 	/*
542c96b77eSJanosch Frank 	 * Check if we can inject a PGM specification which we are always
552c96b77eSJanosch Frank 	 * allowed to do after a diag500 exit.
562c96b77eSJanosch Frank 	 */
572c96b77eSJanosch Frank 	sie(&vm);
582c96b77eSJanosch Frank 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
592c96b77eSJanosch Frank 	/* Inject PGM, next exit should be 9c */
602c96b77eSJanosch Frank 	sie(&vm);
612c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
622c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
632c96b77eSJanosch Frank 	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
642c96b77eSJanosch Frank 	       "specification exception");
652c96b77eSJanosch Frank 
662c96b77eSJanosch Frank 	/* No need for cleanup, just tear down the VM */
672c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
682c96b77eSJanosch Frank 
692c96b77eSJanosch Frank 	report_prefix_pop();
702c96b77eSJanosch Frank }
712c96b77eSJanosch Frank 
722c96b77eSJanosch Frank 
732c96b77eSJanosch Frank static void test_diag_288(void)
742c96b77eSJanosch Frank {
752c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_288)[];
762c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_288)[];
772c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_288)[];
782c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_288)[];
792c96b77eSJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_288);
802c96b77eSJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_288);
812c96b77eSJanosch Frank 
822c96b77eSJanosch Frank 	report_prefix_push("diag 0x288");
832c96b77eSJanosch Frank 
842c96b77eSJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_288),
852c96b77eSJanosch Frank 			SNIPPET_HDR_START(asm, snippet_pv_diag_288),
86*b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
872c96b77eSJanosch Frank 
882c96b77eSJanosch Frank 	sie(&vm);
892c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
902c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288,
912c96b77eSJanosch Frank 	       "intercept values");
922c96b77eSJanosch Frank 	report(vm.save_area.guest.grs[0] == 1 &&
932c96b77eSJanosch Frank 	       vm.save_area.guest.grs[1] == 2 &&
942c96b77eSJanosch Frank 	       vm.save_area.guest.grs[2] == 3,
952c96b77eSJanosch Frank 	       "register values");
962c96b77eSJanosch Frank 
972c96b77eSJanosch Frank 	/*
982c96b77eSJanosch Frank 	 * Check if we can inject a PGM spec which we are always
992c96b77eSJanosch Frank 	 * allowed to do after a diag288 exit.
1002c96b77eSJanosch Frank 	 */
1012c96b77eSJanosch Frank 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
1022c96b77eSJanosch Frank 	sie(&vm);
1032c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1042c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
1052c96b77eSJanosch Frank 	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
1062c96b77eSJanosch Frank 	       "specification exception");
1072c96b77eSJanosch Frank 
1082c96b77eSJanosch Frank 	/* No need for cleanup, just tear down the VM */
1092c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
1102c96b77eSJanosch Frank 
1112c96b77eSJanosch Frank 	report_prefix_pop();
1122c96b77eSJanosch Frank }
1132c96b77eSJanosch Frank 
1142c96b77eSJanosch Frank static void test_diag_yield(void)
1152c96b77eSJanosch Frank {
1162c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_yield)[];
1172c96b77eSJanosch Frank 	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_yield)[];
1182c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_yield)[];
1192c96b77eSJanosch Frank 	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_yield)[];
1202c96b77eSJanosch Frank 	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_yield);
1212c96b77eSJanosch Frank 	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_yield);
1222c96b77eSJanosch Frank 
1232c96b77eSJanosch Frank 	report_prefix_push("diag yield");
1242c96b77eSJanosch Frank 
1252c96b77eSJanosch Frank 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_yield),
1262c96b77eSJanosch Frank 			SNIPPET_HDR_START(asm, snippet_pv_diag_yield),
127*b36f35a8SJanosch Frank 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
1282c96b77eSJanosch Frank 
1292c96b77eSJanosch Frank 	/* 0x44 */
1302c96b77eSJanosch Frank 	report_prefix_push("0x44");
1312c96b77eSJanosch Frank 	sie(&vm);
1322c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1332c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44,
1342c96b77eSJanosch Frank 	       "intercept values");
1352c96b77eSJanosch Frank 	report_prefix_pop();
1362c96b77eSJanosch Frank 
1372c96b77eSJanosch Frank 	/* 0x9c */
1382c96b77eSJanosch Frank 	report_prefix_push("0x9c");
1392c96b77eSJanosch Frank 	sie(&vm);
1402c96b77eSJanosch Frank 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
1412c96b77eSJanosch Frank 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c,
1422c96b77eSJanosch Frank 	       "intercept values");
1432c96b77eSJanosch Frank 	report(vm.save_area.guest.grs[0] == 42, "r1 correct");
1442c96b77eSJanosch Frank 	report_prefix_pop();
1452c96b77eSJanosch Frank 
1462c96b77eSJanosch Frank 	uv_destroy_guest(&vm);
1472c96b77eSJanosch Frank 	report_prefix_pop();
1482c96b77eSJanosch Frank }
1492c96b77eSJanosch Frank 
1502c96b77eSJanosch Frank 
1512c96b77eSJanosch Frank int main(void)
1522c96b77eSJanosch Frank {
1532c96b77eSJanosch Frank 	report_prefix_push("pv-diags");
1542c96b77eSJanosch Frank 	if (!test_facility(158)) {
1552c96b77eSJanosch Frank 		report_skip("UV Call facility unavailable");
1562c96b77eSJanosch Frank 		goto done;
1572c96b77eSJanosch Frank 	}
1582c96b77eSJanosch Frank 	if (!sclp_facilities.has_sief2) {
1592c96b77eSJanosch Frank 		report_skip("SIEF2 facility unavailable");
1602c96b77eSJanosch Frank 		goto done;
1612c96b77eSJanosch Frank 	}
1622c96b77eSJanosch Frank 
1632c96b77eSJanosch Frank 	uv_setup_asces();
1642c96b77eSJanosch Frank 	snippet_setup_guest(&vm, true);
1652c96b77eSJanosch Frank 	test_diag_yield();
1662c96b77eSJanosch Frank 	test_diag_288();
1672c96b77eSJanosch Frank 	test_diag_500();
1682c96b77eSJanosch Frank 	sie_guest_destroy(&vm);
1692c96b77eSJanosch Frank 
1702c96b77eSJanosch Frank done:
1712c96b77eSJanosch Frank 	report_prefix_pop();
1722c96b77eSJanosch Frank 	return report_summary();
1732c96b77eSJanosch Frank }
174