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