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