xref: /kvm-unit-tests/s390x/pv-diags.c (revision 1d0f08f40d53daa39566842ec46a112db5f7e524)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * PV virtualization interception tests for diagnose instructions.
4  *
5  * Copyright (c) 2021 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 #include <libcflat.h>
11 #include <snippet.h>
12 #include <pv_icptdata.h>
13 #include <sie.h>
14 #include <sclp.h>
15 #include <asm/facility.h>
16 
17 static struct vm vm;
18 
19 static void test_diag_500(void)
20 {
21 	extern const char SNIPPET_NAME_START(asm, pv_diag_500)[];
22 	extern const char SNIPPET_NAME_END(asm, pv_diag_500)[];
23 	extern const char SNIPPET_HDR_START(asm, pv_diag_500)[];
24 	extern const char SNIPPET_HDR_END(asm, pv_diag_500)[];
25 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_500);
26 	int size_gbin = SNIPPET_LEN(asm, pv_diag_500);
27 
28 	report_prefix_push("diag 0x500");
29 
30 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_500),
31 			SNIPPET_HDR_START(asm, pv_diag_500),
32 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
33 
34 	sie(&vm);
35 	report(pv_icptdata_check_diag(&vm, 0x500),
36 	       "intercept values");
37 	report(vm.save_area.guest.grs[1] == 1 &&
38 	       vm.save_area.guest.grs[2] == 2 &&
39 	       vm.save_area.guest.grs[3] == 3 &&
40 	       vm.save_area.guest.grs[4] == 4,
41 	       "register values");
42 	/*
43 	 * Check if we can inject a PGM operand which we are always
44 	 * allowed to do after a diag500 exit.
45 	 */
46 	vm.sblk->iictl = IICTL_CODE_OPERAND;
47 	sie(&vm);
48 	report(pv_icptdata_check_diag(&vm, 0x9c) &&
49 	       vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND,
50 	       "operand exception");
51 
52 	/*
53 	 * Check if we can inject a PGM specification which we are always
54 	 * allowed to do after a diag500 exit.
55 	 */
56 	sie(&vm);
57 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
58 	/* Inject PGM, next exit should be 9c */
59 	sie(&vm);
60 	report(pv_icptdata_check_diag(&vm, 0x9c) &&
61 	       vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
62 	       "specification exception");
63 
64 	/* No need for cleanup, just tear down the VM */
65 	uv_destroy_guest(&vm);
66 
67 	report_prefix_pop();
68 }
69 
70 
71 static void test_diag_288(void)
72 {
73 	extern const char SNIPPET_NAME_START(asm, pv_diag_288)[];
74 	extern const char SNIPPET_NAME_END(asm, pv_diag_288)[];
75 	extern const char SNIPPET_HDR_START(asm, pv_diag_288)[];
76 	extern const char SNIPPET_HDR_END(asm, pv_diag_288)[];
77 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_288);
78 	int size_gbin = SNIPPET_LEN(asm, pv_diag_288);
79 
80 	report_prefix_push("diag 0x288");
81 
82 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_288),
83 			SNIPPET_HDR_START(asm, pv_diag_288),
84 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
85 
86 	sie(&vm);
87 	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
88 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288,
89 	       "intercept values");
90 	report(vm.save_area.guest.grs[0] == 1 &&
91 	       vm.save_area.guest.grs[1] == 2 &&
92 	       vm.save_area.guest.grs[2] == 3,
93 	       "register values");
94 
95 	/*
96 	 * Check if we can inject a PGM spec which we are always
97 	 * allowed to do after a diag288 exit.
98 	 */
99 	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
100 	sie(&vm);
101 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
102 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
103 	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
104 	       "specification exception");
105 
106 	/* No need for cleanup, just tear down the VM */
107 	uv_destroy_guest(&vm);
108 
109 	report_prefix_pop();
110 }
111 
112 static void test_diag_yield(void)
113 {
114 	extern const char SNIPPET_NAME_START(asm, pv_diag_yield)[];
115 	extern const char SNIPPET_NAME_END(asm, pv_diag_yield)[];
116 	extern const char SNIPPET_HDR_START(asm, pv_diag_yield)[];
117 	extern const char SNIPPET_HDR_END(asm, pv_diag_yield)[];
118 	int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_yield);
119 	int size_gbin = SNIPPET_LEN(asm, pv_diag_yield);
120 
121 	report_prefix_push("diag yield");
122 
123 	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_yield),
124 			SNIPPET_HDR_START(asm, pv_diag_yield),
125 			size_gbin, size_hdr, SNIPPET_UNPACK_OFF);
126 
127 	/* 0x44 */
128 	report_prefix_push("0x44");
129 	sie(&vm);
130 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
131 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44,
132 	       "intercept values");
133 	report_prefix_pop();
134 
135 	/* 0x9c */
136 	report_prefix_push("0x9c");
137 	sie(&vm);
138 	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
139 	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c,
140 	       "intercept values");
141 	report(vm.save_area.guest.grs[0] == 42, "r1 correct");
142 	report_prefix_pop();
143 
144 	uv_destroy_guest(&vm);
145 	report_prefix_pop();
146 }
147 
148 
149 int main(void)
150 {
151 	report_prefix_push("pv-diags");
152 	if (!test_facility(158)) {
153 		report_skip("UV Call facility unavailable");
154 		goto done;
155 	}
156 	if (!sclp_facilities.has_sief2) {
157 		report_skip("SIEF2 facility unavailable");
158 		goto done;
159 	}
160 
161 	uv_setup_asces();
162 	snippet_setup_guest(&vm, true);
163 	test_diag_yield();
164 	test_diag_288();
165 	test_diag_500();
166 	sie_guest_destroy(&vm);
167 
168 done:
169 	report_prefix_pop();
170 	return report_summary();
171 }
172