]>
Commit | Line | Data |
---|---|---|
ea4d8ac2 GA |
1 | /* |
2 | * Virtio crypto Support | |
3 | * | |
4 | * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. | |
5 | * | |
6 | * Authors: | |
7 | * Gonglei <arei.gonglei@huawei.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or | |
10 | * (at your option) any later version. See the COPYING file in the | |
11 | * top-level directory. | |
12 | */ | |
0b8fa32f | 13 | |
ea4d8ac2 GA |
14 | #include "qemu/osdep.h" |
15 | #include "qemu/iov.h" | |
db725815 | 16 | #include "qemu/main-loop.h" |
0b8fa32f | 17 | #include "qemu/module.h" |
ea4d8ac2 GA |
18 | #include "qapi/error.h" |
19 | #include "qemu/error-report.h" | |
20 | ||
21 | #include "hw/virtio/virtio.h" | |
22 | #include "hw/virtio/virtio-crypto.h" | |
a27bd6c7 | 23 | #include "hw/qdev-properties.h" |
ea4d8ac2 | 24 | #include "standard-headers/linux/virtio_ids.h" |
5da73dab | 25 | #include "sysemu/cryptodev-vhost.h" |
ea4d8ac2 GA |
26 | |
27 | #define VIRTIO_CRYPTO_VM_VERSION 1 | |
28 | ||
2fda101d LH |
29 | typedef struct VirtIOCryptoSessionReq { |
30 | VirtIODevice *vdev; | |
31 | VirtQueue *vq; | |
32 | VirtQueueElement *elem; | |
33 | CryptoDevBackendSessionInfo info; | |
34 | CryptoDevCompletionFunc cb; | |
35 | } VirtIOCryptoSessionReq; | |
36 | ||
37 | static void virtio_crypto_free_create_session_req(VirtIOCryptoSessionReq *sreq) | |
38 | { | |
39 | switch (sreq->info.op_code) { | |
40 | case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: | |
41 | g_free(sreq->info.u.sym_sess_info.cipher_key); | |
42 | g_free(sreq->info.u.sym_sess_info.auth_key); | |
43 | break; | |
44 | ||
45 | case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: | |
46 | g_free(sreq->info.u.asym_sess_info.key); | |
47 | break; | |
48 | ||
49 | case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: | |
50 | case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: | |
51 | case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: | |
52 | case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: | |
53 | case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION: | |
54 | break; | |
55 | ||
56 | default: | |
57 | error_report("Unknown opcode: %u", sreq->info.op_code); | |
58 | } | |
59 | g_free(sreq); | |
60 | } | |
61 | ||
59c360ca GA |
62 | /* |
63 | * Transfer virtqueue index to crypto queue index. | |
64 | * The control virtqueue is after the data virtqueues | |
65 | * so the input value doesn't need to be adjusted | |
66 | */ | |
67 | static inline int virtio_crypto_vq2q(int queue_index) | |
68 | { | |
69 | return queue_index; | |
70 | } | |
71 | ||
72 | static int | |
73 | virtio_crypto_cipher_session_helper(VirtIODevice *vdev, | |
74 | CryptoDevBackendSymSessionInfo *info, | |
75 | struct virtio_crypto_cipher_session_para *cipher_para, | |
76 | struct iovec **iov, unsigned int *out_num) | |
77 | { | |
78 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
79 | unsigned int num = *out_num; | |
80 | ||
81 | info->cipher_alg = ldl_le_p(&cipher_para->algo); | |
82 | info->key_len = ldl_le_p(&cipher_para->keylen); | |
83 | info->direction = ldl_le_p(&cipher_para->op); | |
84 | DPRINTF("cipher_alg=%" PRIu32 ", info->direction=%" PRIu32 "\n", | |
85 | info->cipher_alg, info->direction); | |
86 | ||
87 | if (info->key_len > vcrypto->conf.max_cipher_key_len) { | |
88 | error_report("virtio-crypto length of cipher key is too big: %u", | |
89 | info->key_len); | |
90 | return -VIRTIO_CRYPTO_ERR; | |
91 | } | |
92 | /* Get cipher key */ | |
93 | if (info->key_len > 0) { | |
94 | size_t s; | |
95 | DPRINTF("keylen=%" PRIu32 "\n", info->key_len); | |
96 | ||
97 | info->cipher_key = g_malloc(info->key_len); | |
98 | s = iov_to_buf(*iov, num, 0, info->cipher_key, info->key_len); | |
99 | if (unlikely(s != info->key_len)) { | |
100 | virtio_error(vdev, "virtio-crypto cipher key incorrect"); | |
101 | return -EFAULT; | |
102 | } | |
103 | iov_discard_front(iov, &num, info->key_len); | |
104 | *out_num = num; | |
105 | } | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
2fda101d | 110 | static int |
59c360ca GA |
111 | virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, |
112 | struct virtio_crypto_sym_create_session_req *sess_req, | |
113 | uint32_t queue_id, | |
114 | uint32_t opcode, | |
2fda101d LH |
115 | struct iovec *iov, unsigned int out_num, |
116 | VirtIOCryptoSessionReq *sreq) | |
59c360ca GA |
117 | { |
118 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
2fda101d | 119 | CryptoDevBackendSymSessionInfo *sym_info = &sreq->info.u.sym_sess_info; |
59c360ca GA |
120 | int queue_index; |
121 | uint32_t op_type; | |
59c360ca GA |
122 | int ret; |
123 | ||
59c360ca | 124 | op_type = ldl_le_p(&sess_req->op_type); |
2fda101d | 125 | sreq->info.op_code = opcode; |
59c360ca | 126 | |
2fda101d | 127 | sym_info = &sreq->info.u.sym_sess_info; |
0e660a6f ZP |
128 | sym_info->op_type = op_type; |
129 | ||
59c360ca | 130 | if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { |
0e660a6f | 131 | ret = virtio_crypto_cipher_session_helper(vdev, sym_info, |
59c360ca GA |
132 | &sess_req->u.cipher.para, |
133 | &iov, &out_num); | |
134 | if (ret < 0) { | |
2fda101d | 135 | return ret; |
59c360ca GA |
136 | } |
137 | } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { | |
138 | size_t s; | |
139 | /* cipher part */ | |
0e660a6f | 140 | ret = virtio_crypto_cipher_session_helper(vdev, sym_info, |
59c360ca GA |
141 | &sess_req->u.chain.para.cipher_param, |
142 | &iov, &out_num); | |
143 | if (ret < 0) { | |
2fda101d | 144 | return ret; |
59c360ca GA |
145 | } |
146 | /* hash part */ | |
0e660a6f | 147 | sym_info->alg_chain_order = ldl_le_p( |
59c360ca | 148 | &sess_req->u.chain.para.alg_chain_order); |
0e660a6f ZP |
149 | sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len); |
150 | sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode); | |
151 | if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { | |
152 | sym_info->hash_alg = | |
153 | ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo); | |
154 | sym_info->auth_key_len = ldl_le_p( | |
59c360ca | 155 | &sess_req->u.chain.para.u.mac_param.auth_key_len); |
0e660a6f | 156 | sym_info->hash_result_len = ldl_le_p( |
59c360ca | 157 | &sess_req->u.chain.para.u.mac_param.hash_result_len); |
0e660a6f | 158 | if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) { |
59c360ca | 159 | error_report("virtio-crypto length of auth key is too big: %u", |
0e660a6f | 160 | sym_info->auth_key_len); |
2fda101d | 161 | return -VIRTIO_CRYPTO_ERR; |
59c360ca GA |
162 | } |
163 | /* get auth key */ | |
0e660a6f ZP |
164 | if (sym_info->auth_key_len > 0) { |
165 | sym_info->auth_key = g_malloc(sym_info->auth_key_len); | |
166 | s = iov_to_buf(iov, out_num, 0, sym_info->auth_key, | |
167 | sym_info->auth_key_len); | |
168 | if (unlikely(s != sym_info->auth_key_len)) { | |
59c360ca GA |
169 | virtio_error(vdev, |
170 | "virtio-crypto authenticated key incorrect"); | |
2fda101d | 171 | return -EFAULT; |
59c360ca | 172 | } |
0e660a6f | 173 | iov_discard_front(&iov, &out_num, sym_info->auth_key_len); |
59c360ca | 174 | } |
0e660a6f ZP |
175 | } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { |
176 | sym_info->hash_alg = ldl_le_p( | |
59c360ca | 177 | &sess_req->u.chain.para.u.hash_param.algo); |
0e660a6f | 178 | sym_info->hash_result_len = ldl_le_p( |
59c360ca GA |
179 | &sess_req->u.chain.para.u.hash_param.hash_result_len); |
180 | } else { | |
181 | /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */ | |
182 | error_report("unsupported hash mode"); | |
2fda101d | 183 | return -VIRTIO_CRYPTO_NOTSUPP; |
59c360ca GA |
184 | } |
185 | } else { | |
186 | /* VIRTIO_CRYPTO_SYM_OP_NONE */ | |
187 | error_report("unsupported cipher op_type: VIRTIO_CRYPTO_SYM_OP_NONE"); | |
2fda101d | 188 | return -VIRTIO_CRYPTO_NOTSUPP; |
59c360ca GA |
189 | } |
190 | ||
191 | queue_index = virtio_crypto_vq2q(queue_id); | |
2fda101d LH |
192 | return cryptodev_backend_create_session(vcrypto->cryptodev, &sreq->info, |
193 | queue_index, sreq->cb, sreq); | |
59c360ca GA |
194 | } |
195 | ||
2fda101d | 196 | static int |
0e660a6f ZP |
197 | virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto, |
198 | struct virtio_crypto_akcipher_create_session_req *sess_req, | |
199 | uint32_t queue_id, uint32_t opcode, | |
2fda101d LH |
200 | struct iovec *iov, unsigned int out_num, |
201 | VirtIOCryptoSessionReq *sreq) | |
0e660a6f ZP |
202 | { |
203 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
2fda101d | 204 | CryptoDevBackendAsymSessionInfo *asym_info = &sreq->info.u.asym_sess_info; |
0e660a6f ZP |
205 | int queue_index; |
206 | uint32_t algo, keytype, keylen; | |
0e660a6f ZP |
207 | |
208 | algo = ldl_le_p(&sess_req->para.algo); | |
209 | keytype = ldl_le_p(&sess_req->para.keytype); | |
210 | keylen = ldl_le_p(&sess_req->para.keylen); | |
211 | ||
212 | if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC) | |
213 | && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) { | |
214 | error_report("unsupported asym keytype: %d", keytype); | |
215 | return -VIRTIO_CRYPTO_NOTSUPP; | |
216 | } | |
217 | ||
218 | if (keylen) { | |
2fda101d LH |
219 | asym_info->key = g_malloc(keylen); |
220 | if (iov_to_buf(iov, out_num, 0, asym_info->key, keylen) != keylen) { | |
0e660a6f ZP |
221 | virtio_error(vdev, "virtio-crypto asym key incorrect"); |
222 | return -EFAULT; | |
223 | } | |
224 | iov_discard_front(&iov, &out_num, keylen); | |
225 | } | |
226 | ||
2fda101d LH |
227 | sreq->info.op_code = opcode; |
228 | asym_info = &sreq->info.u.asym_sess_info; | |
0e660a6f ZP |
229 | asym_info->algo = algo; |
230 | asym_info->keytype = keytype; | |
231 | asym_info->keylen = keylen; | |
0e660a6f ZP |
232 | switch (asym_info->algo) { |
233 | case VIRTIO_CRYPTO_AKCIPHER_RSA: | |
234 | asym_info->u.rsa.padding_algo = | |
235 | ldl_le_p(&sess_req->para.u.rsa.padding_algo); | |
236 | asym_info->u.rsa.hash_algo = | |
237 | ldl_le_p(&sess_req->para.u.rsa.hash_algo); | |
238 | break; | |
239 | ||
240 | /* TODO DSA&ECDSA handling */ | |
241 | ||
242 | default: | |
243 | return -VIRTIO_CRYPTO_ERR; | |
244 | } | |
245 | ||
246 | queue_index = virtio_crypto_vq2q(queue_id); | |
2fda101d LH |
247 | return cryptodev_backend_create_session(vcrypto->cryptodev, &sreq->info, |
248 | queue_index, sreq->cb, sreq); | |
0e660a6f ZP |
249 | } |
250 | ||
2fda101d | 251 | static int |
59c360ca GA |
252 | virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto, |
253 | struct virtio_crypto_destroy_session_req *close_sess_req, | |
2fda101d LH |
254 | uint32_t queue_id, |
255 | VirtIOCryptoSessionReq *sreq) | |
59c360ca | 256 | { |
59c360ca | 257 | uint64_t session_id; |
59c360ca GA |
258 | |
259 | session_id = ldq_le_p(&close_sess_req->session_id); | |
260 | DPRINTF("close session, id=%" PRIu64 "\n", session_id); | |
261 | ||
2fda101d LH |
262 | return cryptodev_backend_close_session( |
263 | vcrypto->cryptodev, session_id, queue_id, sreq->cb, sreq); | |
264 | } | |
265 | ||
266 | static void virtio_crypto_create_session_completion(void *opaque, int ret) | |
267 | { | |
268 | VirtIOCryptoSessionReq *sreq = (VirtIOCryptoSessionReq *)opaque; | |
269 | VirtQueue *vq = sreq->vq; | |
270 | VirtQueueElement *elem = sreq->elem; | |
271 | VirtIODevice *vdev = sreq->vdev; | |
272 | struct virtio_crypto_session_input input; | |
273 | struct iovec *in_iov = elem->in_sg; | |
274 | unsigned in_num = elem->in_num; | |
275 | size_t s; | |
276 | ||
277 | memset(&input, 0, sizeof(input)); | |
278 | /* Serious errors, need to reset virtio crypto device */ | |
279 | if (ret == -EFAULT) { | |
280 | virtqueue_detach_element(vq, elem, 0); | |
281 | goto out; | |
282 | } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) { | |
283 | stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); | |
284 | } else if (ret == -VIRTIO_CRYPTO_KEY_REJECTED) { | |
285 | stl_le_p(&input.status, VIRTIO_CRYPTO_KEY_REJECTED); | |
286 | } else if (ret != VIRTIO_CRYPTO_OK) { | |
287 | stl_le_p(&input.status, VIRTIO_CRYPTO_ERR); | |
59c360ca | 288 | } else { |
2fda101d LH |
289 | /* Set the session id */ |
290 | stq_le_p(&input.session_id, sreq->info.session_id); | |
291 | stl_le_p(&input.status, VIRTIO_CRYPTO_OK); | |
292 | } | |
293 | ||
294 | s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); | |
295 | if (unlikely(s != sizeof(input))) { | |
296 | virtio_error(vdev, "virtio-crypto input incorrect"); | |
297 | virtqueue_detach_element(vq, elem, 0); | |
298 | goto out; | |
299 | } | |
300 | virtqueue_push(vq, elem, sizeof(input)); | |
301 | virtio_notify(vdev, vq); | |
302 | ||
303 | out: | |
304 | g_free(elem); | |
305 | virtio_crypto_free_create_session_req(sreq); | |
306 | } | |
307 | ||
308 | static void virtio_crypto_destroy_session_completion(void *opaque, int ret) | |
309 | { | |
310 | VirtIOCryptoSessionReq *sreq = (VirtIOCryptoSessionReq *)opaque; | |
311 | VirtQueue *vq = sreq->vq; | |
312 | VirtQueueElement *elem = sreq->elem; | |
313 | VirtIODevice *vdev = sreq->vdev; | |
314 | struct iovec *in_iov = elem->in_sg; | |
315 | unsigned in_num = elem->in_num; | |
316 | uint8_t status; | |
317 | size_t s; | |
318 | ||
319 | if (ret < 0) { | |
59c360ca | 320 | status = VIRTIO_CRYPTO_ERR; |
2fda101d LH |
321 | } else { |
322 | status = VIRTIO_CRYPTO_OK; | |
323 | } | |
324 | s = iov_from_buf(in_iov, in_num, 0, &status, sizeof(status)); | |
325 | if (unlikely(s != sizeof(status))) { | |
326 | virtio_error(vdev, "virtio-crypto status incorrect"); | |
327 | virtqueue_detach_element(vq, elem, 0); | |
328 | goto out; | |
59c360ca | 329 | } |
2fda101d LH |
330 | virtqueue_push(vq, elem, sizeof(status)); |
331 | virtio_notify(vdev, vq); | |
59c360ca | 332 | |
2fda101d LH |
333 | out: |
334 | g_free(elem); | |
335 | g_free(sreq); | |
59c360ca GA |
336 | } |
337 | ||
338 | static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) | |
339 | { | |
340 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
341 | struct virtio_crypto_op_ctrl_req ctrl; | |
342 | VirtQueueElement *elem; | |
2fda101d | 343 | VirtIOCryptoSessionReq *sreq; |
59c360ca | 344 | unsigned out_num; |
2fda101d | 345 | unsigned in_num; |
59c360ca GA |
346 | uint32_t queue_id; |
347 | uint32_t opcode; | |
348 | struct virtio_crypto_session_input input; | |
59c360ca | 349 | size_t s; |
2fda101d LH |
350 | int ret; |
351 | struct iovec *out_iov; | |
352 | struct iovec *in_iov; | |
59c360ca GA |
353 | |
354 | for (;;) { | |
80807477 SH |
355 | g_autofree struct iovec *out_iov_copy = NULL; |
356 | ||
59c360ca GA |
357 | elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); |
358 | if (!elem) { | |
359 | break; | |
360 | } | |
361 | if (elem->out_num < 1 || elem->in_num < 1) { | |
362 | virtio_error(vdev, "virtio-crypto ctrl missing headers"); | |
363 | virtqueue_detach_element(vq, elem, 0); | |
364 | g_free(elem); | |
365 | break; | |
366 | } | |
367 | ||
368 | out_num = elem->out_num; | |
d792199d | 369 | out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); |
80807477 SH |
370 | out_iov = out_iov_copy; |
371 | ||
59c360ca GA |
372 | in_num = elem->in_num; |
373 | in_iov = elem->in_sg; | |
80807477 | 374 | |
59c360ca GA |
375 | if (unlikely(iov_to_buf(out_iov, out_num, 0, &ctrl, sizeof(ctrl)) |
376 | != sizeof(ctrl))) { | |
377 | virtio_error(vdev, "virtio-crypto request ctrl_hdr too short"); | |
378 | virtqueue_detach_element(vq, elem, 0); | |
379 | g_free(elem); | |
380 | break; | |
381 | } | |
382 | iov_discard_front(&out_iov, &out_num, sizeof(ctrl)); | |
383 | ||
384 | opcode = ldl_le_p(&ctrl.header.opcode); | |
385 | queue_id = ldl_le_p(&ctrl.header.queue_id); | |
386 | ||
2fda101d LH |
387 | sreq = g_new0(VirtIOCryptoSessionReq, 1); |
388 | sreq->vdev = vdev; | |
389 | sreq->vq = vq; | |
390 | sreq->elem = elem; | |
391 | ||
59c360ca GA |
392 | switch (opcode) { |
393 | case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: | |
2fda101d LH |
394 | sreq->cb = virtio_crypto_create_session_completion; |
395 | ret = virtio_crypto_create_sym_session(vcrypto, | |
396 | &ctrl.u.sym_create_session, | |
397 | queue_id, opcode, | |
398 | out_iov, out_num, | |
399 | sreq); | |
400 | if (ret < 0) { | |
401 | virtio_crypto_create_session_completion(sreq, ret); | |
402 | } | |
403 | break; | |
0e660a6f ZP |
404 | |
405 | case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: | |
2fda101d LH |
406 | sreq->cb = virtio_crypto_create_session_completion; |
407 | ret = virtio_crypto_create_asym_session(vcrypto, | |
0e660a6f ZP |
408 | &ctrl.u.akcipher_create_session, |
409 | queue_id, opcode, | |
2fda101d LH |
410 | out_iov, out_num, |
411 | sreq); | |
412 | if (ret < 0) { | |
413 | virtio_crypto_create_session_completion(sreq, ret); | |
59c360ca | 414 | } |
59c360ca | 415 | break; |
0e660a6f | 416 | |
59c360ca GA |
417 | case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: |
418 | case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: | |
419 | case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: | |
420 | case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: | |
0e660a6f | 421 | case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION: |
2fda101d LH |
422 | sreq->cb = virtio_crypto_destroy_session_completion; |
423 | ret = virtio_crypto_handle_close_session(vcrypto, | |
424 | &ctrl.u.destroy_session, queue_id, | |
425 | sreq); | |
426 | if (ret < 0) { | |
427 | virtio_crypto_destroy_session_completion(sreq, ret); | |
59c360ca | 428 | } |
59c360ca | 429 | break; |
2fda101d | 430 | |
59c360ca GA |
431 | case VIRTIO_CRYPTO_HASH_CREATE_SESSION: |
432 | case VIRTIO_CRYPTO_MAC_CREATE_SESSION: | |
433 | case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: | |
434 | default: | |
2fda101d | 435 | memset(&input, 0, sizeof(input)); |
59c360ca | 436 | error_report("virtio-crypto unsupported ctrl opcode: %d", opcode); |
59c360ca GA |
437 | stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); |
438 | s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); | |
439 | if (unlikely(s != sizeof(input))) { | |
440 | virtio_error(vdev, "virtio-crypto input incorrect"); | |
441 | virtqueue_detach_element(vq, elem, 0); | |
2fda101d LH |
442 | } else { |
443 | virtqueue_push(vq, elem, sizeof(input)); | |
444 | virtio_notify(vdev, vq); | |
59c360ca | 445 | } |
2fda101d LH |
446 | g_free(sreq); |
447 | g_free(elem); | |
59c360ca GA |
448 | |
449 | break; | |
450 | } /* end switch case */ | |
451 | ||
59c360ca GA |
452 | } /* end for loop */ |
453 | } | |
454 | ||
04b9b37e GA |
455 | static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq, |
456 | VirtIOCryptoReq *req) | |
457 | { | |
458 | req->vcrypto = vcrypto; | |
459 | req->vq = vq; | |
460 | req->in = NULL; | |
461 | req->in_iov = NULL; | |
462 | req->in_num = 0; | |
463 | req->in_len = 0; | |
999c789f | 464 | req->flags = QCRYPTODEV_BACKEND_ALG__MAX; |
0e660a6f | 465 | memset(&req->op_info, 0x00, sizeof(req->op_info)); |
04b9b37e GA |
466 | } |
467 | ||
468 | static void virtio_crypto_free_request(VirtIOCryptoReq *req) | |
469 | { | |
0e660a6f ZP |
470 | if (!req) { |
471 | return; | |
472 | } | |
473 | ||
999c789f | 474 | if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) { |
0e660a6f ZP |
475 | size_t max_len; |
476 | CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info; | |
477 | ||
3e699089 MMC |
478 | if (op_info) { |
479 | max_len = op_info->iv_len + | |
480 | op_info->aad_len + | |
481 | op_info->src_len + | |
482 | op_info->dst_len + | |
483 | op_info->digest_result_len; | |
484 | ||
485 | /* Zeroize and free request data structure */ | |
486 | memset(op_info, 0, sizeof(*op_info) + max_len); | |
487 | g_free(op_info); | |
488 | } | |
999c789f | 489 | } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) { |
0e660a6f ZP |
490 | CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info; |
491 | if (op_info) { | |
492 | g_free(op_info->src); | |
493 | g_free(op_info->dst); | |
494 | memset(op_info, 0, sizeof(*op_info)); | |
02ed3e7c | 495 | g_free(op_info); |
04b9b37e | 496 | } |
04b9b37e | 497 | } |
0e660a6f | 498 | |
2fda101d | 499 | g_free(req->in_iov); |
0e660a6f | 500 | g_free(req); |
04b9b37e GA |
501 | } |
502 | ||
503 | static void | |
504 | virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, | |
505 | VirtIOCryptoReq *req, | |
506 | uint32_t status, | |
507 | CryptoDevBackendSymOpInfo *sym_op_info) | |
508 | { | |
509 | size_t s, len; | |
2fda101d | 510 | struct iovec *in_iov = req->in_iov; |
04b9b37e GA |
511 | |
512 | if (status != VIRTIO_CRYPTO_OK) { | |
513 | return; | |
514 | } | |
515 | ||
c159a4d1 | 516 | len = sym_op_info->src_len; |
04b9b37e | 517 | /* Save the cipher result */ |
2fda101d | 518 | s = iov_from_buf(in_iov, req->in_num, 0, sym_op_info->dst, len); |
04b9b37e GA |
519 | if (s != len) { |
520 | virtio_error(vdev, "virtio-crypto dest data incorrect"); | |
521 | return; | |
522 | } | |
523 | ||
2fda101d | 524 | iov_discard_front(&in_iov, &req->in_num, len); |
04b9b37e GA |
525 | |
526 | if (sym_op_info->op_type == | |
527 | VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { | |
528 | /* Save the digest result */ | |
2fda101d | 529 | s = iov_from_buf(in_iov, req->in_num, 0, |
04b9b37e GA |
530 | sym_op_info->digest_result, |
531 | sym_op_info->digest_result_len); | |
532 | if (s != sym_op_info->digest_result_len) { | |
533 | virtio_error(vdev, "virtio-crypto digest result incorrect"); | |
534 | } | |
535 | } | |
536 | } | |
537 | ||
0e660a6f ZP |
538 | static void |
539 | virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev, | |
540 | VirtIOCryptoReq *req, int32_t status, | |
541 | CryptoDevBackendAsymOpInfo *asym_op_info) | |
542 | { | |
543 | size_t s, len; | |
2fda101d | 544 | struct iovec *in_iov = req->in_iov; |
0e660a6f ZP |
545 | |
546 | if (status != VIRTIO_CRYPTO_OK) { | |
547 | return; | |
548 | } | |
549 | ||
550 | len = asym_op_info->dst_len; | |
551 | if (!len) { | |
552 | return; | |
553 | } | |
554 | ||
2fda101d | 555 | s = iov_from_buf(in_iov, req->in_num, 0, asym_op_info->dst, len); |
0e660a6f ZP |
556 | if (s != len) { |
557 | virtio_error(vdev, "virtio-crypto asym dest data incorrect"); | |
558 | return; | |
559 | } | |
560 | ||
2fda101d | 561 | iov_discard_front(&in_iov, &req->in_num, len); |
0e660a6f ZP |
562 | |
563 | /* For akcipher, dst_len may be changed after operation */ | |
564 | req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len; | |
565 | } | |
566 | ||
2fda101d | 567 | static void virtio_crypto_req_complete(void *opaque, int ret) |
04b9b37e | 568 | { |
2fda101d | 569 | VirtIOCryptoReq *req = (VirtIOCryptoReq *)opaque; |
04b9b37e GA |
570 | VirtIOCrypto *vcrypto = req->vcrypto; |
571 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
2fda101d | 572 | uint8_t status = -ret; |
04b9b37e | 573 | |
999c789f | 574 | if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) { |
04b9b37e | 575 | virtio_crypto_sym_input_data_helper(vdev, req, status, |
0e660a6f | 576 | req->op_info.u.sym_op_info); |
999c789f | 577 | } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) { |
0e660a6f ZP |
578 | virtio_crypto_akcipher_input_data_helper(vdev, req, status, |
579 | req->op_info.u.asym_op_info); | |
04b9b37e GA |
580 | } |
581 | stb_p(&req->in->status, status); | |
582 | virtqueue_push(req->vq, &req->elem, req->in_len); | |
583 | virtio_notify(vdev, req->vq); | |
2fda101d | 584 | virtio_crypto_free_request(req); |
04b9b37e GA |
585 | } |
586 | ||
587 | static VirtIOCryptoReq * | |
588 | virtio_crypto_get_request(VirtIOCrypto *s, VirtQueue *vq) | |
589 | { | |
590 | VirtIOCryptoReq *req = virtqueue_pop(vq, sizeof(VirtIOCryptoReq)); | |
591 | ||
592 | if (req) { | |
593 | virtio_crypto_init_request(s, vq, req); | |
594 | } | |
595 | return req; | |
596 | } | |
597 | ||
598 | static CryptoDevBackendSymOpInfo * | |
599 | virtio_crypto_sym_op_helper(VirtIODevice *vdev, | |
600 | struct virtio_crypto_cipher_para *cipher_para, | |
601 | struct virtio_crypto_alg_chain_data_para *alg_chain_para, | |
602 | struct iovec *iov, unsigned int out_num) | |
603 | { | |
604 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
605 | CryptoDevBackendSymOpInfo *op_info; | |
606 | uint32_t src_len = 0, dst_len = 0; | |
607 | uint32_t iv_len = 0; | |
608 | uint32_t aad_len = 0, hash_result_len = 0; | |
609 | uint32_t hash_start_src_offset = 0, len_to_hash = 0; | |
610 | uint32_t cipher_start_src_offset = 0, len_to_cipher = 0; | |
611 | ||
a08aaff8 | 612 | uint64_t max_len, curr_size = 0; |
04b9b37e GA |
613 | size_t s; |
614 | ||
615 | /* Plain cipher */ | |
616 | if (cipher_para) { | |
617 | iv_len = ldl_le_p(&cipher_para->iv_len); | |
618 | src_len = ldl_le_p(&cipher_para->src_data_len); | |
619 | dst_len = ldl_le_p(&cipher_para->dst_data_len); | |
620 | } else if (alg_chain_para) { /* Algorithm chain */ | |
621 | iv_len = ldl_le_p(&alg_chain_para->iv_len); | |
622 | src_len = ldl_le_p(&alg_chain_para->src_data_len); | |
623 | dst_len = ldl_le_p(&alg_chain_para->dst_data_len); | |
624 | ||
625 | aad_len = ldl_le_p(&alg_chain_para->aad_len); | |
626 | hash_result_len = ldl_le_p(&alg_chain_para->hash_result_len); | |
627 | hash_start_src_offset = ldl_le_p( | |
628 | &alg_chain_para->hash_start_src_offset); | |
629 | cipher_start_src_offset = ldl_le_p( | |
630 | &alg_chain_para->cipher_start_src_offset); | |
631 | len_to_cipher = ldl_le_p(&alg_chain_para->len_to_cipher); | |
632 | len_to_hash = ldl_le_p(&alg_chain_para->len_to_hash); | |
633 | } else { | |
634 | return NULL; | |
635 | } | |
636 | ||
9d38a843 ZP |
637 | if (unlikely(src_len != dst_len)) { |
638 | virtio_error(vdev, "sym request src len is different from dst len"); | |
639 | return NULL; | |
640 | } | |
641 | ||
a08aaff8 | 642 | max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; |
04b9b37e GA |
643 | if (unlikely(max_len > vcrypto->conf.max_size)) { |
644 | virtio_error(vdev, "virtio-crypto too big length"); | |
645 | return NULL; | |
646 | } | |
647 | ||
648 | op_info = g_malloc0(sizeof(CryptoDevBackendSymOpInfo) + max_len); | |
649 | op_info->iv_len = iv_len; | |
650 | op_info->src_len = src_len; | |
651 | op_info->dst_len = dst_len; | |
652 | op_info->aad_len = aad_len; | |
653 | op_info->digest_result_len = hash_result_len; | |
654 | op_info->hash_start_src_offset = hash_start_src_offset; | |
655 | op_info->len_to_hash = len_to_hash; | |
656 | op_info->cipher_start_src_offset = cipher_start_src_offset; | |
657 | op_info->len_to_cipher = len_to_cipher; | |
9b4b4e51 | 658 | /* Handle the initialization vector */ |
04b9b37e GA |
659 | if (op_info->iv_len > 0) { |
660 | DPRINTF("iv_len=%" PRIu32 "\n", op_info->iv_len); | |
661 | op_info->iv = op_info->data + curr_size; | |
662 | ||
663 | s = iov_to_buf(iov, out_num, 0, op_info->iv, op_info->iv_len); | |
664 | if (unlikely(s != op_info->iv_len)) { | |
665 | virtio_error(vdev, "virtio-crypto iv incorrect"); | |
666 | goto err; | |
667 | } | |
668 | iov_discard_front(&iov, &out_num, op_info->iv_len); | |
669 | curr_size += op_info->iv_len; | |
670 | } | |
671 | ||
672 | /* Handle additional authentication data if exists */ | |
673 | if (op_info->aad_len > 0) { | |
674 | DPRINTF("aad_len=%" PRIu32 "\n", op_info->aad_len); | |
675 | op_info->aad_data = op_info->data + curr_size; | |
676 | ||
677 | s = iov_to_buf(iov, out_num, 0, op_info->aad_data, op_info->aad_len); | |
678 | if (unlikely(s != op_info->aad_len)) { | |
679 | virtio_error(vdev, "virtio-crypto additional auth data incorrect"); | |
680 | goto err; | |
681 | } | |
682 | iov_discard_front(&iov, &out_num, op_info->aad_len); | |
683 | ||
684 | curr_size += op_info->aad_len; | |
685 | } | |
686 | ||
687 | /* Handle the source data */ | |
688 | if (op_info->src_len > 0) { | |
689 | DPRINTF("src_len=%" PRIu32 "\n", op_info->src_len); | |
690 | op_info->src = op_info->data + curr_size; | |
691 | ||
692 | s = iov_to_buf(iov, out_num, 0, op_info->src, op_info->src_len); | |
693 | if (unlikely(s != op_info->src_len)) { | |
694 | virtio_error(vdev, "virtio-crypto source data incorrect"); | |
695 | goto err; | |
696 | } | |
697 | iov_discard_front(&iov, &out_num, op_info->src_len); | |
698 | ||
699 | curr_size += op_info->src_len; | |
700 | } | |
701 | ||
702 | /* Handle the destination data */ | |
703 | op_info->dst = op_info->data + curr_size; | |
704 | curr_size += op_info->dst_len; | |
705 | ||
706 | DPRINTF("dst_len=%" PRIu32 "\n", op_info->dst_len); | |
707 | ||
708 | /* Handle the hash digest result */ | |
709 | if (hash_result_len > 0) { | |
710 | DPRINTF("hash_result_len=%" PRIu32 "\n", hash_result_len); | |
711 | op_info->digest_result = op_info->data + curr_size; | |
712 | } | |
713 | ||
714 | return op_info; | |
715 | ||
716 | err: | |
717 | g_free(op_info); | |
718 | return NULL; | |
719 | } | |
720 | ||
721 | static int | |
722 | virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto, | |
723 | struct virtio_crypto_sym_data_req *req, | |
0e660a6f | 724 | CryptoDevBackendOpInfo *op_info, |
04b9b37e GA |
725 | struct iovec *iov, unsigned int out_num) |
726 | { | |
727 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
0e660a6f | 728 | CryptoDevBackendSymOpInfo *sym_op_info; |
04b9b37e | 729 | uint32_t op_type; |
04b9b37e GA |
730 | |
731 | op_type = ldl_le_p(&req->op_type); | |
04b9b37e | 732 | if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { |
0e660a6f | 733 | sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, |
04b9b37e | 734 | NULL, iov, out_num); |
0e660a6f | 735 | if (!sym_op_info) { |
04b9b37e GA |
736 | return -EFAULT; |
737 | } | |
04b9b37e | 738 | } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { |
0e660a6f | 739 | sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL, |
04b9b37e GA |
740 | &req->u.chain.para, |
741 | iov, out_num); | |
0e660a6f | 742 | if (!sym_op_info) { |
04b9b37e GA |
743 | return -EFAULT; |
744 | } | |
04b9b37e GA |
745 | } else { |
746 | /* VIRTIO_CRYPTO_SYM_OP_NONE */ | |
747 | error_report("virtio-crypto unsupported cipher type"); | |
748 | return -VIRTIO_CRYPTO_NOTSUPP; | |
749 | } | |
750 | ||
0e660a6f ZP |
751 | sym_op_info->op_type = op_type; |
752 | op_info->u.sym_op_info = sym_op_info; | |
04b9b37e GA |
753 | |
754 | return 0; | |
755 | } | |
756 | ||
0e660a6f ZP |
757 | static int |
758 | virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto, | |
759 | struct virtio_crypto_akcipher_data_req *req, | |
760 | CryptoDevBackendOpInfo *op_info, | |
761 | struct iovec *iov, unsigned int out_num) | |
762 | { | |
763 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
764 | CryptoDevBackendAsymOpInfo *asym_op_info; | |
765 | uint32_t src_len; | |
766 | uint32_t dst_len; | |
767 | uint32_t len; | |
768 | uint8_t *src = NULL; | |
769 | uint8_t *dst = NULL; | |
770 | ||
c5e8d518 | 771 | asym_op_info = g_new0(CryptoDevBackendAsymOpInfo, 1); |
0e660a6f ZP |
772 | src_len = ldl_le_p(&req->para.src_data_len); |
773 | dst_len = ldl_le_p(&req->para.dst_data_len); | |
774 | ||
775 | if (src_len > 0) { | |
776 | src = g_malloc0(src_len); | |
777 | len = iov_to_buf(iov, out_num, 0, src, src_len); | |
778 | if (unlikely(len != src_len)) { | |
779 | virtio_error(vdev, "virtio-crypto asym src data incorrect" | |
780 | "expected %u, actual %u", src_len, len); | |
781 | goto err; | |
782 | } | |
783 | ||
784 | iov_discard_front(&iov, &out_num, src_len); | |
785 | } | |
786 | ||
787 | if (dst_len > 0) { | |
788 | dst = g_malloc0(dst_len); | |
789 | ||
790 | if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { | |
791 | len = iov_to_buf(iov, out_num, 0, dst, dst_len); | |
792 | if (unlikely(len != dst_len)) { | |
793 | virtio_error(vdev, "virtio-crypto asym dst data incorrect" | |
794 | "expected %u, actual %u", dst_len, len); | |
795 | goto err; | |
796 | } | |
797 | ||
798 | iov_discard_front(&iov, &out_num, dst_len); | |
799 | } | |
800 | } | |
801 | ||
802 | asym_op_info->src_len = src_len; | |
803 | asym_op_info->dst_len = dst_len; | |
804 | asym_op_info->src = src; | |
805 | asym_op_info->dst = dst; | |
806 | op_info->u.asym_op_info = asym_op_info; | |
807 | ||
808 | return 0; | |
809 | ||
810 | err: | |
811 | g_free(asym_op_info); | |
812 | g_free(src); | |
813 | g_free(dst); | |
814 | ||
815 | return -EFAULT; | |
816 | } | |
817 | ||
04b9b37e GA |
818 | static int |
819 | virtio_crypto_handle_request(VirtIOCryptoReq *request) | |
820 | { | |
821 | VirtIOCrypto *vcrypto = request->vcrypto; | |
822 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
823 | VirtQueueElement *elem = &request->elem; | |
824 | int queue_index = virtio_crypto_vq2q(virtio_get_queue_index(request->vq)); | |
825 | struct virtio_crypto_op_data_req req; | |
826 | int ret; | |
80807477 SH |
827 | g_autofree struct iovec *in_iov_copy = NULL; |
828 | g_autofree struct iovec *out_iov_copy = NULL; | |
04b9b37e GA |
829 | struct iovec *in_iov; |
830 | struct iovec *out_iov; | |
831 | unsigned in_num; | |
832 | unsigned out_num; | |
833 | uint32_t opcode; | |
0e660a6f | 834 | CryptoDevBackendOpInfo *op_info = &request->op_info; |
04b9b37e GA |
835 | |
836 | if (elem->out_num < 1 || elem->in_num < 1) { | |
837 | virtio_error(vdev, "virtio-crypto dataq missing headers"); | |
838 | return -1; | |
839 | } | |
840 | ||
841 | out_num = elem->out_num; | |
d792199d | 842 | out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); |
80807477 SH |
843 | out_iov = out_iov_copy; |
844 | ||
04b9b37e | 845 | in_num = elem->in_num; |
d792199d | 846 | in_iov_copy = g_memdup2(elem->in_sg, sizeof(in_iov[0]) * in_num); |
80807477 SH |
847 | in_iov = in_iov_copy; |
848 | ||
04b9b37e GA |
849 | if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req)) |
850 | != sizeof(req))) { | |
851 | virtio_error(vdev, "virtio-crypto request outhdr too short"); | |
852 | return -1; | |
853 | } | |
854 | iov_discard_front(&out_iov, &out_num, sizeof(req)); | |
855 | ||
856 | if (in_iov[in_num - 1].iov_len < | |
857 | sizeof(struct virtio_crypto_inhdr)) { | |
858 | virtio_error(vdev, "virtio-crypto request inhdr too short"); | |
859 | return -1; | |
860 | } | |
861 | /* We always touch the last byte, so just see how big in_iov is. */ | |
862 | request->in_len = iov_size(in_iov, in_num); | |
863 | request->in = (void *)in_iov[in_num - 1].iov_base | |
864 | + in_iov[in_num - 1].iov_len | |
865 | - sizeof(struct virtio_crypto_inhdr); | |
866 | iov_discard_back(in_iov, &in_num, sizeof(struct virtio_crypto_inhdr)); | |
867 | ||
868 | /* | |
869 | * The length of operation result, including dest_data | |
870 | * and digest_result if exists. | |
871 | */ | |
872 | request->in_num = in_num; | |
873 | request->in_iov = in_iov; | |
2fda101d LH |
874 | /* now, we free the in_iov_copy inside virtio_crypto_free_request */ |
875 | in_iov_copy = NULL; | |
04b9b37e GA |
876 | |
877 | opcode = ldl_le_p(&req.header.opcode); | |
0e660a6f ZP |
878 | op_info->session_id = ldq_le_p(&req.header.session_id); |
879 | op_info->op_code = opcode; | |
2cb06927 ZP |
880 | op_info->queue_index = queue_index; |
881 | op_info->cb = virtio_crypto_req_complete; | |
882 | op_info->opaque = request; | |
04b9b37e GA |
883 | |
884 | switch (opcode) { | |
885 | case VIRTIO_CRYPTO_CIPHER_ENCRYPT: | |
886 | case VIRTIO_CRYPTO_CIPHER_DECRYPT: | |
999c789f | 887 | op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_SYM; |
04b9b37e | 888 | ret = virtio_crypto_handle_sym_req(vcrypto, |
0e660a6f ZP |
889 | &req.u.sym_req, op_info, |
890 | out_iov, out_num); | |
891 | goto check_result; | |
892 | ||
893 | case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: | |
894 | case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: | |
895 | case VIRTIO_CRYPTO_AKCIPHER_SIGN: | |
896 | case VIRTIO_CRYPTO_AKCIPHER_VERIFY: | |
999c789f | 897 | op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_ASYM; |
0e660a6f ZP |
898 | ret = virtio_crypto_handle_asym_req(vcrypto, |
899 | &req.u.akcipher_req, op_info, | |
04b9b37e | 900 | out_iov, out_num); |
0e660a6f ZP |
901 | |
902 | check_result: | |
04b9b37e GA |
903 | /* Serious errors, need to reset virtio crypto device */ |
904 | if (ret == -EFAULT) { | |
905 | return -1; | |
906 | } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) { | |
2fda101d | 907 | virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); |
04b9b37e | 908 | } else { |
d6634ac0 | 909 | ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev, |
2cb06927 | 910 | op_info); |
04b9b37e | 911 | if (ret < 0) { |
2fda101d | 912 | virtio_crypto_req_complete(request, ret); |
04b9b37e | 913 | } |
04b9b37e GA |
914 | } |
915 | break; | |
0e660a6f | 916 | |
04b9b37e GA |
917 | case VIRTIO_CRYPTO_HASH: |
918 | case VIRTIO_CRYPTO_MAC: | |
919 | case VIRTIO_CRYPTO_AEAD_ENCRYPT: | |
920 | case VIRTIO_CRYPTO_AEAD_DECRYPT: | |
921 | default: | |
922 | error_report("virtio-crypto unsupported dataq opcode: %u", | |
923 | opcode); | |
2fda101d | 924 | virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); |
04b9b37e GA |
925 | } |
926 | ||
927 | return 0; | |
928 | } | |
929 | ||
930 | static void virtio_crypto_handle_dataq(VirtIODevice *vdev, VirtQueue *vq) | |
931 | { | |
932 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
933 | VirtIOCryptoReq *req; | |
934 | ||
935 | while ((req = virtio_crypto_get_request(vcrypto, vq))) { | |
936 | if (virtio_crypto_handle_request(req) < 0) { | |
937 | virtqueue_detach_element(req->vq, &req->elem, 0); | |
938 | virtio_crypto_free_request(req); | |
939 | break; | |
940 | } | |
941 | } | |
942 | } | |
943 | ||
20cb2ffd GA |
944 | static void virtio_crypto_dataq_bh(void *opaque) |
945 | { | |
946 | VirtIOCryptoQueue *q = opaque; | |
947 | VirtIOCrypto *vcrypto = q->vcrypto; | |
948 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
949 | ||
950 | /* This happens when device was stopped but BH wasn't. */ | |
951 | if (!vdev->vm_running) { | |
952 | return; | |
953 | } | |
954 | ||
955 | /* Just in case the driver is not ready on more */ | |
956 | if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) { | |
957 | return; | |
958 | } | |
959 | ||
600f5ce3 SH |
960 | for (;;) { |
961 | virtio_crypto_handle_dataq(vdev, q->dataq); | |
962 | virtio_queue_set_notification(q->dataq, 1); | |
963 | ||
964 | /* Are we done or did the guest add more buffers? */ | |
965 | if (virtio_queue_empty(q->dataq)) { | |
966 | break; | |
967 | } | |
968 | ||
969 | virtio_queue_set_notification(q->dataq, 0); | |
970 | } | |
20cb2ffd GA |
971 | } |
972 | ||
973 | static void | |
974 | virtio_crypto_handle_dataq_bh(VirtIODevice *vdev, VirtQueue *vq) | |
975 | { | |
976 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
977 | VirtIOCryptoQueue *q = | |
978 | &vcrypto->vqs[virtio_crypto_vq2q(virtio_get_queue_index(vq))]; | |
979 | ||
980 | /* This happens when device was stopped but VCPU wasn't. */ | |
981 | if (!vdev->vm_running) { | |
982 | return; | |
983 | } | |
984 | virtio_queue_set_notification(vq, 0); | |
985 | qemu_bh_schedule(q->dataq_bh); | |
986 | } | |
987 | ||
ea4d8ac2 GA |
988 | static uint64_t virtio_crypto_get_features(VirtIODevice *vdev, |
989 | uint64_t features, | |
990 | Error **errp) | |
991 | { | |
992 | return features; | |
993 | } | |
994 | ||
995 | static void virtio_crypto_reset(VirtIODevice *vdev) | |
996 | { | |
997 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
998 | /* multiqueue is disabled by default */ | |
999 | vcrypto->curr_queues = 1; | |
6138dbda | 1000 | if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { |
ea4d8ac2 GA |
1001 | vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; |
1002 | } else { | |
1003 | vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; | |
1004 | } | |
1005 | } | |
1006 | ||
bc304a64 ZP |
1007 | static uint32_t virtio_crypto_init_services(uint32_t qservices) |
1008 | { | |
1009 | uint32_t vservices = 0; | |
1010 | ||
1011 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) { | |
1012 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_CIPHER); | |
1013 | } | |
1014 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_HASH)) { | |
1015 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_HASH); | |
1016 | } | |
1017 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_MAC)) { | |
1018 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_MAC); | |
1019 | } | |
1020 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AEAD)) { | |
1021 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AEAD); | |
1022 | } | |
1023 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) { | |
1024 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER); | |
1025 | } | |
1026 | ||
1027 | return vservices; | |
1028 | } | |
1029 | ||
050652d9 GA |
1030 | static void virtio_crypto_init_config(VirtIODevice *vdev) |
1031 | { | |
1032 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1033 | ||
bc304a64 ZP |
1034 | vcrypto->conf.crypto_services = virtio_crypto_init_services( |
1035 | vcrypto->conf.cryptodev->conf.crypto_services); | |
050652d9 GA |
1036 | vcrypto->conf.cipher_algo_l = |
1037 | vcrypto->conf.cryptodev->conf.cipher_algo_l; | |
1038 | vcrypto->conf.cipher_algo_h = | |
1039 | vcrypto->conf.cryptodev->conf.cipher_algo_h; | |
1040 | vcrypto->conf.hash_algo = vcrypto->conf.cryptodev->conf.hash_algo; | |
1041 | vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l; | |
1042 | vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h; | |
1043 | vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo; | |
0e660a6f | 1044 | vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo; |
050652d9 GA |
1045 | vcrypto->conf.max_cipher_key_len = |
1046 | vcrypto->conf.cryptodev->conf.max_cipher_key_len; | |
1047 | vcrypto->conf.max_auth_key_len = | |
1048 | vcrypto->conf.cryptodev->conf.max_auth_key_len; | |
1049 | vcrypto->conf.max_size = vcrypto->conf.cryptodev->conf.max_size; | |
1050 | } | |
1051 | ||
ea4d8ac2 GA |
1052 | static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) |
1053 | { | |
1054 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
1055 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev); | |
1056 | int i; | |
1057 | ||
1058 | vcrypto->cryptodev = vcrypto->conf.cryptodev; | |
1059 | if (vcrypto->cryptodev == NULL) { | |
1060 | error_setg(errp, "'cryptodev' parameter expects a valid object"); | |
1061 | return; | |
aa8f057e | 1062 | } else if (cryptodev_backend_is_used(vcrypto->cryptodev)) { |
7a309cc9 MA |
1063 | error_setg(errp, "can't use already used cryptodev backend: %s", |
1064 | object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev))); | |
aa8f057e | 1065 | return; |
ea4d8ac2 GA |
1066 | } |
1067 | ||
1068 | vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1); | |
1069 | if (vcrypto->max_queues + 1 > VIRTIO_QUEUE_MAX) { | |
1070 | error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " | |
b12227af | 1071 | "must be a positive integer less than %d.", |
ea4d8ac2 GA |
1072 | vcrypto->max_queues, VIRTIO_QUEUE_MAX); |
1073 | return; | |
1074 | } | |
1075 | ||
3857cd5c | 1076 | virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size); |
ea4d8ac2 | 1077 | vcrypto->curr_queues = 1; |
b21e2380 | 1078 | vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues); |
ea4d8ac2 | 1079 | for (i = 0; i < vcrypto->max_queues; i++) { |
20cb2ffd GA |
1080 | vcrypto->vqs[i].dataq = |
1081 | virtio_add_queue(vdev, 1024, virtio_crypto_handle_dataq_bh); | |
1082 | vcrypto->vqs[i].dataq_bh = | |
f4729ec3 PMD |
1083 | virtio_bh_new_guarded(dev, virtio_crypto_dataq_bh, |
1084 | &vcrypto->vqs[i]); | |
20cb2ffd | 1085 | vcrypto->vqs[i].vcrypto = vcrypto; |
ea4d8ac2 GA |
1086 | } |
1087 | ||
2fda101d | 1088 | vcrypto->ctrl_vq = virtio_add_queue(vdev, 1024, virtio_crypto_handle_ctrl); |
6138dbda | 1089 | if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { |
ea4d8ac2 GA |
1090 | vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; |
1091 | } else { | |
1092 | vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; | |
1093 | } | |
050652d9 GA |
1094 | |
1095 | virtio_crypto_init_config(vdev); | |
46fd1705 | 1096 | cryptodev_backend_set_used(vcrypto->cryptodev, true); |
ea4d8ac2 GA |
1097 | } |
1098 | ||
b69c3c21 | 1099 | static void virtio_crypto_device_unrealize(DeviceState *dev) |
ea4d8ac2 GA |
1100 | { |
1101 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
20cb2ffd GA |
1102 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev); |
1103 | VirtIOCryptoQueue *q; | |
1104 | int i, max_queues; | |
1105 | ||
1106 | max_queues = vcrypto->multiqueue ? vcrypto->max_queues : 1; | |
1107 | for (i = 0; i < max_queues; i++) { | |
d56e1c82 | 1108 | virtio_delete_queue(vcrypto->vqs[i].dataq); |
20cb2ffd GA |
1109 | q = &vcrypto->vqs[i]; |
1110 | qemu_bh_delete(q->dataq_bh); | |
1111 | } | |
1112 | ||
1113 | g_free(vcrypto->vqs); | |
d56e1c82 | 1114 | virtio_delete_queue(vcrypto->ctrl_vq); |
ea4d8ac2 GA |
1115 | |
1116 | virtio_cleanup(vdev); | |
46fd1705 | 1117 | cryptodev_backend_set_used(vcrypto->cryptodev, false); |
ea4d8ac2 GA |
1118 | } |
1119 | ||
1120 | static const VMStateDescription vmstate_virtio_crypto = { | |
1121 | .name = "virtio-crypto", | |
6e724d9d | 1122 | .unmigratable = 1, |
ea4d8ac2 GA |
1123 | .minimum_version_id = VIRTIO_CRYPTO_VM_VERSION, |
1124 | .version_id = VIRTIO_CRYPTO_VM_VERSION, | |
ca02a170 | 1125 | .fields = (const VMStateField[]) { |
ea4d8ac2 GA |
1126 | VMSTATE_VIRTIO_DEVICE, |
1127 | VMSTATE_END_OF_LIST() | |
1128 | }, | |
1129 | }; | |
1130 | ||
1131 | static Property virtio_crypto_properties[] = { | |
aa8f057e FZ |
1132 | DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev, |
1133 | TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *), | |
ea4d8ac2 GA |
1134 | DEFINE_PROP_END_OF_LIST(), |
1135 | }; | |
1136 | ||
1137 | static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config) | |
1138 | { | |
050652d9 | 1139 | VirtIOCrypto *c = VIRTIO_CRYPTO(vdev); |
9730280d | 1140 | struct virtio_crypto_config crypto_cfg = {}; |
050652d9 GA |
1141 | |
1142 | /* | |
1143 | * Virtio-crypto device conforms to VIRTIO 1.0 which is always LE, | |
1144 | * so we can use LE accessors directly. | |
1145 | */ | |
1146 | stl_le_p(&crypto_cfg.status, c->status); | |
1147 | stl_le_p(&crypto_cfg.max_dataqueues, c->max_queues); | |
1148 | stl_le_p(&crypto_cfg.crypto_services, c->conf.crypto_services); | |
1149 | stl_le_p(&crypto_cfg.cipher_algo_l, c->conf.cipher_algo_l); | |
1150 | stl_le_p(&crypto_cfg.cipher_algo_h, c->conf.cipher_algo_h); | |
1151 | stl_le_p(&crypto_cfg.hash_algo, c->conf.hash_algo); | |
1152 | stl_le_p(&crypto_cfg.mac_algo_l, c->conf.mac_algo_l); | |
1153 | stl_le_p(&crypto_cfg.mac_algo_h, c->conf.mac_algo_h); | |
1154 | stl_le_p(&crypto_cfg.aead_algo, c->conf.aead_algo); | |
1155 | stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len); | |
1156 | stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len); | |
1157 | stq_le_p(&crypto_cfg.max_size, c->conf.max_size); | |
0e660a6f | 1158 | stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo); |
050652d9 GA |
1159 | |
1160 | memcpy(config, &crypto_cfg, c->config_size); | |
ea4d8ac2 GA |
1161 | } |
1162 | ||
5da73dab GA |
1163 | static bool virtio_crypto_started(VirtIOCrypto *c, uint8_t status) |
1164 | { | |
1165 | VirtIODevice *vdev = VIRTIO_DEVICE(c); | |
1166 | return (status & VIRTIO_CONFIG_S_DRIVER_OK) && | |
1167 | (c->status & VIRTIO_CRYPTO_S_HW_READY) && vdev->vm_running; | |
1168 | } | |
1169 | ||
1170 | static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status) | |
1171 | { | |
1172 | VirtIODevice *vdev = VIRTIO_DEVICE(c); | |
1173 | int queues = c->multiqueue ? c->max_queues : 1; | |
1174 | CryptoDevBackend *b = c->cryptodev; | |
1175 | CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; | |
1176 | ||
1177 | if (!cryptodev_get_vhost(cc, b, 0)) { | |
1178 | return; | |
1179 | } | |
1180 | ||
1181 | if ((virtio_crypto_started(c, status)) == !!c->vhost_started) { | |
1182 | return; | |
1183 | } | |
1184 | ||
1185 | if (!c->vhost_started) { | |
1186 | int r; | |
1187 | ||
1188 | c->vhost_started = 1; | |
1189 | r = cryptodev_vhost_start(vdev, queues); | |
1190 | if (r < 0) { | |
1191 | error_report("unable to start vhost crypto: %d: " | |
1192 | "falling back on userspace virtio", -r); | |
1193 | c->vhost_started = 0; | |
1194 | } | |
1195 | } else { | |
1196 | cryptodev_vhost_stop(vdev, queues); | |
1197 | c->vhost_started = 0; | |
1198 | } | |
1199 | } | |
1200 | ||
1201 | static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status) | |
1202 | { | |
1203 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1204 | ||
1205 | virtio_crypto_vhost_status(vcrypto, status); | |
1206 | } | |
1207 | ||
1208 | static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, | |
1209 | bool mask) | |
1210 | { | |
1211 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1212 | int queue = virtio_crypto_vq2q(idx); | |
1213 | ||
1214 | assert(vcrypto->vhost_started); | |
1215 | ||
544f0278 CL |
1216 | /* |
1217 | * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 | |
7e8094f0 | 1218 | * as the macro of configure interrupt's IDX, If this driver does not |
544f0278 CL |
1219 | * support, the function will return |
1220 | */ | |
1221 | ||
1222 | if (idx == VIRTIO_CONFIG_IRQ_IDX) { | |
1223 | return; | |
1224 | } | |
5da73dab GA |
1225 | cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); |
1226 | } | |
1227 | ||
1228 | static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) | |
1229 | { | |
1230 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1231 | int queue = virtio_crypto_vq2q(idx); | |
1232 | ||
1233 | assert(vcrypto->vhost_started); | |
1234 | ||
544f0278 CL |
1235 | /* |
1236 | * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 | |
7e8094f0 | 1237 | * as the macro of configure interrupt's IDX, If this driver does not |
544f0278 CL |
1238 | * support, the function will return |
1239 | */ | |
1240 | ||
1241 | if (idx == VIRTIO_CONFIG_IRQ_IDX) { | |
1242 | return false; | |
1243 | } | |
5da73dab GA |
1244 | return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); |
1245 | } | |
1246 | ||
c255488d JP |
1247 | static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) |
1248 | { | |
1249 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1250 | CryptoDevBackend *b = vcrypto->cryptodev; | |
1251 | CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; | |
1252 | CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); | |
1253 | return &vhost_crypto->dev; | |
1254 | } | |
1255 | ||
ea4d8ac2 GA |
1256 | static void virtio_crypto_class_init(ObjectClass *klass, void *data) |
1257 | { | |
1258 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1259 | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); | |
1260 | ||
4f67d30b | 1261 | device_class_set_props(dc, virtio_crypto_properties); |
ea4d8ac2 GA |
1262 | dc->vmsd = &vmstate_virtio_crypto; |
1263 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); | |
1264 | vdc->realize = virtio_crypto_device_realize; | |
1265 | vdc->unrealize = virtio_crypto_device_unrealize; | |
1266 | vdc->get_config = virtio_crypto_get_config; | |
1267 | vdc->get_features = virtio_crypto_get_features; | |
1268 | vdc->reset = virtio_crypto_reset; | |
5da73dab GA |
1269 | vdc->set_status = virtio_crypto_set_status; |
1270 | vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; | |
1271 | vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; | |
c255488d | 1272 | vdc->get_vhost = virtio_crypto_get_vhost; |
ea4d8ac2 GA |
1273 | } |
1274 | ||
1275 | static void virtio_crypto_instance_init(Object *obj) | |
1276 | { | |
1277 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj); | |
1278 | ||
1279 | /* | |
1280 | * The default config_size is sizeof(struct virtio_crypto_config). | |
9b4b4e51 | 1281 | * Can be overridden with virtio_crypto_set_config_size. |
ea4d8ac2 GA |
1282 | */ |
1283 | vcrypto->config_size = sizeof(struct virtio_crypto_config); | |
ea4d8ac2 GA |
1284 | } |
1285 | ||
1286 | static const TypeInfo virtio_crypto_info = { | |
1287 | .name = TYPE_VIRTIO_CRYPTO, | |
1288 | .parent = TYPE_VIRTIO_DEVICE, | |
1289 | .instance_size = sizeof(VirtIOCrypto), | |
1290 | .instance_init = virtio_crypto_instance_init, | |
1291 | .class_init = virtio_crypto_class_init, | |
1292 | }; | |
1293 | ||
1294 | static void virtio_register_types(void) | |
1295 | { | |
1296 | type_register_static(&virtio_crypto_info); | |
1297 | } | |
1298 | ||
1299 | type_init(virtio_register_types) |