Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright IBM Corp. 2024
4 *
5 * Authors:
6 * Hariharan Mari <hari55@linux.ibm.com>
7 *
8 * The tests compare the result of the KVM ioctl for obtaining CPU subfunction data with those
9 * from an ASM block performing the same CPU subfunction. Currently KVM doesn't mask instruction
10 * query data reported via the CPU Model, allowing us to directly compare it with the data
11 * acquired through executing the queries in the test.
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include "facility.h"
19
20#include "kvm_util.h"
21
22#define PLO_FUNCTION_MAX 256
23
24/* Query available CPU subfunctions */
25struct kvm_s390_vm_cpu_subfunc cpu_subfunc;
26
27static void get_cpu_machine_subfuntions(struct kvm_vm *vm,
28 struct kvm_s390_vm_cpu_subfunc *cpu_subfunc)
29{
30 int r;
31
32 r = __kvm_device_attr_get(vm->fd, KVM_S390_VM_CPU_MODEL,
33 KVM_S390_VM_CPU_MACHINE_SUBFUNC, cpu_subfunc);
34
35 TEST_ASSERT(!r, "Get cpu subfunctions failed r=%d errno=%d", r, errno);
36}
37
38static inline int plo_test_bit(unsigned char nr)
39{
40 unsigned long function = nr | 0x100;
41 int cc;
42
43 asm volatile(" lgr 0,%[function]\n"
44 /* Parameter registers are ignored for "test bit" */
45 " plo 0,0,0,0(0)\n"
46 " ipm %0\n"
47 " srl %0,28\n"
48 : "=d" (cc)
49 : [function] "d" (function)
50 : "cc", "0");
51 return cc == 0;
52}
53
54/* Testing Perform Locked Operation (PLO) CPU subfunction's ASM block */
55static void test_plo_asm_block(u8 (*query)[32])
56{
57 for (int i = 0; i < PLO_FUNCTION_MAX; ++i) {
58 if (plo_test_bit(i))
59 (*query)[i >> 3] |= 0x80 >> (i & 7);
60 }
61}
62
63/* Testing Crypto Compute Message Authentication Code (KMAC) CPU subfunction's ASM block */
64static void test_kmac_asm_block(u8 (*query)[16])
65{
66 asm volatile(" la %%r1,%[query]\n"
67 " xgr %%r0,%%r0\n"
68 " .insn rre,0xb91e0000,0,2\n"
69 : [query] "=R" (*query)
70 :
71 : "cc", "r0", "r1");
72}
73
74/* Testing Crypto Cipher Message with Chaining (KMC) CPU subfunction's ASM block */
75static void test_kmc_asm_block(u8 (*query)[16])
76{
77 asm volatile(" la %%r1,%[query]\n"
78 " xgr %%r0,%%r0\n"
79 " .insn rre,0xb92f0000,2,4\n"
80 : [query] "=R" (*query)
81 :
82 : "cc", "r0", "r1");
83}
84
85/* Testing Crypto Cipher Message (KM) CPU subfunction's ASM block */
86static void test_km_asm_block(u8 (*query)[16])
87{
88 asm volatile(" la %%r1,%[query]\n"
89 " xgr %%r0,%%r0\n"
90 " .insn rre,0xb92e0000,2,4\n"
91 : [query] "=R" (*query)
92 :
93 : "cc", "r0", "r1");
94}
95
96/* Testing Crypto Compute Intermediate Message Digest (KIMD) CPU subfunction's ASM block */
97static void test_kimd_asm_block(u8 (*query)[16])
98{
99 asm volatile(" la %%r1,%[query]\n"
100 " xgr %%r0,%%r0\n"
101 " .insn rre,0xb93e0000,0,2\n"
102 : [query] "=R" (*query)
103 :
104 : "cc", "r0", "r1");
105}
106
107/* Testing Crypto Compute Last Message Digest (KLMD) CPU subfunction's ASM block */
108static void test_klmd_asm_block(u8 (*query)[16])
109{
110 asm volatile(" la %%r1,%[query]\n"
111 " xgr %%r0,%%r0\n"
112 " .insn rre,0xb93f0000,0,2\n"
113 : [query] "=R" (*query)
114 :
115 : "cc", "r0", "r1");
116}
117
118/* Testing Crypto Cipher Message with Counter (KMCTR) CPU subfunction's ASM block */
119static void test_kmctr_asm_block(u8 (*query)[16])
120{
121 asm volatile(" la %%r1,%[query]\n"
122 " xgr %%r0,%%r0\n"
123 " .insn rrf,0xb92d0000,2,4,6,0\n"
124 : [query] "=R" (*query)
125 :
126 : "cc", "r0", "r1");
127}
128
129/* Testing Crypto Cipher Message with Cipher Feedback (KMF) CPU subfunction's ASM block */
130static void test_kmf_asm_block(u8 (*query)[16])
131{
132 asm volatile(" la %%r1,%[query]\n"
133 " xgr %%r0,%%r0\n"
134 " .insn rre,0xb92a0000,2,4\n"
135 : [query] "=R" (*query)
136 :
137 : "cc", "r0", "r1");
138}
139
140/* Testing Crypto Cipher Message with Output Feedback (KMO) CPU subfunction's ASM block */
141static void test_kmo_asm_block(u8 (*query)[16])
142{
143 asm volatile(" la %%r1,%[query]\n"
144 " xgr %%r0,%%r0\n"
145 " .insn rre,0xb92b0000,2,4\n"
146 : [query] "=R" (*query)
147 :
148 : "cc", "r0", "r1");
149}
150
151/* Testing Crypto Perform Cryptographic Computation (PCC) CPU subfunction's ASM block */
152static void test_pcc_asm_block(u8 (*query)[16])
153{
154 asm volatile(" la %%r1,%[query]\n"
155 " xgr %%r0,%%r0\n"
156 " .insn rre,0xb92c0000,0,0\n"
157 : [query] "=R" (*query)
158 :
159 : "cc", "r0", "r1");
160}
161
162/* Testing Crypto Perform Random Number Operation (PRNO) CPU subfunction's ASM block */
163static void test_prno_asm_block(u8 (*query)[16])
164{
165 asm volatile(" la %%r1,%[query]\n"
166 " xgr %%r0,%%r0\n"
167 " .insn rre,0xb93c0000,2,4\n"
168 : [query] "=R" (*query)
169 :
170 : "cc", "r0", "r1");
171}
172
173/* Testing Crypto Cipher Message with Authentication (KMA) CPU subfunction's ASM block */
174static void test_kma_asm_block(u8 (*query)[16])
175{
176 asm volatile(" la %%r1,%[query]\n"
177 " xgr %%r0,%%r0\n"
178 " .insn rrf,0xb9290000,2,4,6,0\n"
179 : [query] "=R" (*query)
180 :
181 : "cc", "r0", "r1");
182}
183
184/* Testing Crypto Compute Digital Signature Authentication (KDSA) CPU subfunction's ASM block */
185static void test_kdsa_asm_block(u8 (*query)[16])
186{
187 asm volatile(" la %%r1,%[query]\n"
188 " xgr %%r0,%%r0\n"
189 " .insn rre,0xb93a0000,0,2\n"
190 : [query] "=R" (*query)
191 :
192 : "cc", "r0", "r1");
193}
194
195/* Testing Sort Lists (SORTL) CPU subfunction's ASM block */
196static void test_sortl_asm_block(u8 (*query)[32])
197{
198 asm volatile(" lghi 0,0\n"
199 " la 1,%[query]\n"
200 " .insn rre,0xb9380000,2,4\n"
201 : [query] "=R" (*query)
202 :
203 : "cc", "0", "1");
204}
205
206/* Testing Deflate Conversion Call (DFLTCC) CPU subfunction's ASM block */
207static void test_dfltcc_asm_block(u8 (*query)[32])
208{
209 asm volatile(" lghi 0,0\n"
210 " la 1,%[query]\n"
211 " .insn rrf,0xb9390000,2,4,6,0\n"
212 : [query] "=R" (*query)
213 :
214 : "cc", "0", "1");
215}
216
217/*
218 * Testing Perform Function with Concurrent Results (PFCR)
219 * CPU subfunctions's ASM block
220 */
221static void test_pfcr_asm_block(u8 (*query)[16])
222{
223 asm volatile(" lghi 0,0\n"
224 " .insn rsy,0xeb0000000016,0,0,%[query]\n"
225 : [query] "=QS" (*query)
226 :
227 : "cc", "0");
228}
229
230typedef void (*testfunc_t)(u8 (*array)[]);
231
232struct testdef {
233 const char *subfunc_name;
234 u8 *subfunc_array;
235 size_t array_size;
236 testfunc_t test;
237 int facility_bit;
238} testlist[] = {
239 /*
240 * PLO was introduced in the very first 64-bit machine generation.
241 * Hence it is assumed PLO is always installed in Z Arch.
242 */
243 { "PLO", cpu_subfunc.plo, sizeof(cpu_subfunc.plo), test_plo_asm_block, 1 },
244 /* MSA - Facility bit 17 */
245 { "KMAC", cpu_subfunc.kmac, sizeof(cpu_subfunc.kmac), test_kmac_asm_block, 17 },
246 { "KMC", cpu_subfunc.kmc, sizeof(cpu_subfunc.kmc), test_kmc_asm_block, 17 },
247 { "KM", cpu_subfunc.km, sizeof(cpu_subfunc.km), test_km_asm_block, 17 },
248 { "KIMD", cpu_subfunc.kimd, sizeof(cpu_subfunc.kimd), test_kimd_asm_block, 17 },
249 { "KLMD", cpu_subfunc.klmd, sizeof(cpu_subfunc.klmd), test_klmd_asm_block, 17 },
250 /* MSA - Facility bit 77 */
251 { "KMCTR", cpu_subfunc.kmctr, sizeof(cpu_subfunc.kmctr), test_kmctr_asm_block, 77 },
252 { "KMF", cpu_subfunc.kmf, sizeof(cpu_subfunc.kmf), test_kmf_asm_block, 77 },
253 { "KMO", cpu_subfunc.kmo, sizeof(cpu_subfunc.kmo), test_kmo_asm_block, 77 },
254 { "PCC", cpu_subfunc.pcc, sizeof(cpu_subfunc.pcc), test_pcc_asm_block, 77 },
255 /* MSA5 - Facility bit 57 */
256 { "PPNO", cpu_subfunc.ppno, sizeof(cpu_subfunc.ppno), test_prno_asm_block, 57 },
257 /* MSA8 - Facility bit 146 */
258 { "KMA", cpu_subfunc.kma, sizeof(cpu_subfunc.kma), test_kma_asm_block, 146 },
259 /* MSA9 - Facility bit 155 */
260 { "KDSA", cpu_subfunc.kdsa, sizeof(cpu_subfunc.kdsa), test_kdsa_asm_block, 155 },
261 /* SORTL - Facility bit 150 */
262 { "SORTL", cpu_subfunc.sortl, sizeof(cpu_subfunc.sortl), test_sortl_asm_block, 150 },
263 /* DFLTCC - Facility bit 151 */
264 { "DFLTCC", cpu_subfunc.dfltcc, sizeof(cpu_subfunc.dfltcc), test_dfltcc_asm_block, 151 },
265 /* Concurrent-function facility - Facility bit 201 */
266 { "PFCR", cpu_subfunc.pfcr, sizeof(cpu_subfunc.pfcr), test_pfcr_asm_block, 201 },
267};
268
269int main(int argc, char *argv[])
270{
271 struct kvm_vm *vm;
272 int idx;
273
274 ksft_print_header();
275
276 vm = vm_create(1);
277
278 memset(&cpu_subfunc, 0, sizeof(cpu_subfunc));
279 get_cpu_machine_subfuntions(vm, &cpu_subfunc);
280
281 ksft_set_plan(ARRAY_SIZE(testlist));
282 for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
283 if (test_facility(testlist[idx].facility_bit)) {
284 u8 *array = malloc(testlist[idx].array_size);
285
286 testlist[idx].test((u8 (*)[testlist[idx].array_size])array);
287
288 TEST_ASSERT_EQ(memcmp(testlist[idx].subfunc_array,
289 array, testlist[idx].array_size), 0);
290
291 ksft_test_result_pass("%s\n", testlist[idx].subfunc_name);
292 free(array);
293 } else {
294 ksft_test_result_skip("%s feature is not available\n",
295 testlist[idx].subfunc_name);
296 }
297 }
298
299 kvm_vm_free(vm);
300 ksft_finished();
301}