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