]>
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 | ||
a08aaff8 | 637 | max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; |
04b9b37e GA |
638 | if (unlikely(max_len > vcrypto->conf.max_size)) { |
639 | virtio_error(vdev, "virtio-crypto too big length"); | |
640 | return NULL; | |
641 | } | |
642 | ||
643 | op_info = g_malloc0(sizeof(CryptoDevBackendSymOpInfo) + max_len); | |
644 | op_info->iv_len = iv_len; | |
645 | op_info->src_len = src_len; | |
646 | op_info->dst_len = dst_len; | |
647 | op_info->aad_len = aad_len; | |
648 | op_info->digest_result_len = hash_result_len; | |
649 | op_info->hash_start_src_offset = hash_start_src_offset; | |
650 | op_info->len_to_hash = len_to_hash; | |
651 | op_info->cipher_start_src_offset = cipher_start_src_offset; | |
652 | op_info->len_to_cipher = len_to_cipher; | |
653 | /* Handle the initilization vector */ | |
654 | if (op_info->iv_len > 0) { | |
655 | DPRINTF("iv_len=%" PRIu32 "\n", op_info->iv_len); | |
656 | op_info->iv = op_info->data + curr_size; | |
657 | ||
658 | s = iov_to_buf(iov, out_num, 0, op_info->iv, op_info->iv_len); | |
659 | if (unlikely(s != op_info->iv_len)) { | |
660 | virtio_error(vdev, "virtio-crypto iv incorrect"); | |
661 | goto err; | |
662 | } | |
663 | iov_discard_front(&iov, &out_num, op_info->iv_len); | |
664 | curr_size += op_info->iv_len; | |
665 | } | |
666 | ||
667 | /* Handle additional authentication data if exists */ | |
668 | if (op_info->aad_len > 0) { | |
669 | DPRINTF("aad_len=%" PRIu32 "\n", op_info->aad_len); | |
670 | op_info->aad_data = op_info->data + curr_size; | |
671 | ||
672 | s = iov_to_buf(iov, out_num, 0, op_info->aad_data, op_info->aad_len); | |
673 | if (unlikely(s != op_info->aad_len)) { | |
674 | virtio_error(vdev, "virtio-crypto additional auth data incorrect"); | |
675 | goto err; | |
676 | } | |
677 | iov_discard_front(&iov, &out_num, op_info->aad_len); | |
678 | ||
679 | curr_size += op_info->aad_len; | |
680 | } | |
681 | ||
682 | /* Handle the source data */ | |
683 | if (op_info->src_len > 0) { | |
684 | DPRINTF("src_len=%" PRIu32 "\n", op_info->src_len); | |
685 | op_info->src = op_info->data + curr_size; | |
686 | ||
687 | s = iov_to_buf(iov, out_num, 0, op_info->src, op_info->src_len); | |
688 | if (unlikely(s != op_info->src_len)) { | |
689 | virtio_error(vdev, "virtio-crypto source data incorrect"); | |
690 | goto err; | |
691 | } | |
692 | iov_discard_front(&iov, &out_num, op_info->src_len); | |
693 | ||
694 | curr_size += op_info->src_len; | |
695 | } | |
696 | ||
697 | /* Handle the destination data */ | |
698 | op_info->dst = op_info->data + curr_size; | |
699 | curr_size += op_info->dst_len; | |
700 | ||
701 | DPRINTF("dst_len=%" PRIu32 "\n", op_info->dst_len); | |
702 | ||
703 | /* Handle the hash digest result */ | |
704 | if (hash_result_len > 0) { | |
705 | DPRINTF("hash_result_len=%" PRIu32 "\n", hash_result_len); | |
706 | op_info->digest_result = op_info->data + curr_size; | |
707 | } | |
708 | ||
709 | return op_info; | |
710 | ||
711 | err: | |
712 | g_free(op_info); | |
713 | return NULL; | |
714 | } | |
715 | ||
716 | static int | |
717 | virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto, | |
718 | struct virtio_crypto_sym_data_req *req, | |
0e660a6f | 719 | CryptoDevBackendOpInfo *op_info, |
04b9b37e GA |
720 | struct iovec *iov, unsigned int out_num) |
721 | { | |
722 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
0e660a6f | 723 | CryptoDevBackendSymOpInfo *sym_op_info; |
04b9b37e | 724 | uint32_t op_type; |
04b9b37e GA |
725 | |
726 | op_type = ldl_le_p(&req->op_type); | |
04b9b37e | 727 | if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { |
0e660a6f | 728 | sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, |
04b9b37e | 729 | NULL, iov, out_num); |
0e660a6f | 730 | if (!sym_op_info) { |
04b9b37e GA |
731 | return -EFAULT; |
732 | } | |
04b9b37e | 733 | } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { |
0e660a6f | 734 | sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL, |
04b9b37e GA |
735 | &req->u.chain.para, |
736 | iov, out_num); | |
0e660a6f | 737 | if (!sym_op_info) { |
04b9b37e GA |
738 | return -EFAULT; |
739 | } | |
04b9b37e GA |
740 | } else { |
741 | /* VIRTIO_CRYPTO_SYM_OP_NONE */ | |
742 | error_report("virtio-crypto unsupported cipher type"); | |
743 | return -VIRTIO_CRYPTO_NOTSUPP; | |
744 | } | |
745 | ||
0e660a6f ZP |
746 | sym_op_info->op_type = op_type; |
747 | op_info->u.sym_op_info = sym_op_info; | |
04b9b37e GA |
748 | |
749 | return 0; | |
750 | } | |
751 | ||
0e660a6f ZP |
752 | static int |
753 | virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto, | |
754 | struct virtio_crypto_akcipher_data_req *req, | |
755 | CryptoDevBackendOpInfo *op_info, | |
756 | struct iovec *iov, unsigned int out_num) | |
757 | { | |
758 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
759 | CryptoDevBackendAsymOpInfo *asym_op_info; | |
760 | uint32_t src_len; | |
761 | uint32_t dst_len; | |
762 | uint32_t len; | |
763 | uint8_t *src = NULL; | |
764 | uint8_t *dst = NULL; | |
765 | ||
c5e8d518 | 766 | asym_op_info = g_new0(CryptoDevBackendAsymOpInfo, 1); |
0e660a6f ZP |
767 | src_len = ldl_le_p(&req->para.src_data_len); |
768 | dst_len = ldl_le_p(&req->para.dst_data_len); | |
769 | ||
770 | if (src_len > 0) { | |
771 | src = g_malloc0(src_len); | |
772 | len = iov_to_buf(iov, out_num, 0, src, src_len); | |
773 | if (unlikely(len != src_len)) { | |
774 | virtio_error(vdev, "virtio-crypto asym src data incorrect" | |
775 | "expected %u, actual %u", src_len, len); | |
776 | goto err; | |
777 | } | |
778 | ||
779 | iov_discard_front(&iov, &out_num, src_len); | |
780 | } | |
781 | ||
782 | if (dst_len > 0) { | |
783 | dst = g_malloc0(dst_len); | |
784 | ||
785 | if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { | |
786 | len = iov_to_buf(iov, out_num, 0, dst, dst_len); | |
787 | if (unlikely(len != dst_len)) { | |
788 | virtio_error(vdev, "virtio-crypto asym dst data incorrect" | |
789 | "expected %u, actual %u", dst_len, len); | |
790 | goto err; | |
791 | } | |
792 | ||
793 | iov_discard_front(&iov, &out_num, dst_len); | |
794 | } | |
795 | } | |
796 | ||
797 | asym_op_info->src_len = src_len; | |
798 | asym_op_info->dst_len = dst_len; | |
799 | asym_op_info->src = src; | |
800 | asym_op_info->dst = dst; | |
801 | op_info->u.asym_op_info = asym_op_info; | |
802 | ||
803 | return 0; | |
804 | ||
805 | err: | |
806 | g_free(asym_op_info); | |
807 | g_free(src); | |
808 | g_free(dst); | |
809 | ||
810 | return -EFAULT; | |
811 | } | |
812 | ||
04b9b37e GA |
813 | static int |
814 | virtio_crypto_handle_request(VirtIOCryptoReq *request) | |
815 | { | |
816 | VirtIOCrypto *vcrypto = request->vcrypto; | |
817 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
818 | VirtQueueElement *elem = &request->elem; | |
819 | int queue_index = virtio_crypto_vq2q(virtio_get_queue_index(request->vq)); | |
820 | struct virtio_crypto_op_data_req req; | |
821 | int ret; | |
80807477 SH |
822 | g_autofree struct iovec *in_iov_copy = NULL; |
823 | g_autofree struct iovec *out_iov_copy = NULL; | |
04b9b37e GA |
824 | struct iovec *in_iov; |
825 | struct iovec *out_iov; | |
826 | unsigned in_num; | |
827 | unsigned out_num; | |
828 | uint32_t opcode; | |
0e660a6f | 829 | CryptoDevBackendOpInfo *op_info = &request->op_info; |
04b9b37e GA |
830 | |
831 | if (elem->out_num < 1 || elem->in_num < 1) { | |
832 | virtio_error(vdev, "virtio-crypto dataq missing headers"); | |
833 | return -1; | |
834 | } | |
835 | ||
836 | out_num = elem->out_num; | |
d792199d | 837 | out_iov_copy = g_memdup2(elem->out_sg, sizeof(out_iov[0]) * out_num); |
80807477 SH |
838 | out_iov = out_iov_copy; |
839 | ||
04b9b37e | 840 | in_num = elem->in_num; |
d792199d | 841 | in_iov_copy = g_memdup2(elem->in_sg, sizeof(in_iov[0]) * in_num); |
80807477 SH |
842 | in_iov = in_iov_copy; |
843 | ||
04b9b37e GA |
844 | if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req)) |
845 | != sizeof(req))) { | |
846 | virtio_error(vdev, "virtio-crypto request outhdr too short"); | |
847 | return -1; | |
848 | } | |
849 | iov_discard_front(&out_iov, &out_num, sizeof(req)); | |
850 | ||
851 | if (in_iov[in_num - 1].iov_len < | |
852 | sizeof(struct virtio_crypto_inhdr)) { | |
853 | virtio_error(vdev, "virtio-crypto request inhdr too short"); | |
854 | return -1; | |
855 | } | |
856 | /* We always touch the last byte, so just see how big in_iov is. */ | |
857 | request->in_len = iov_size(in_iov, in_num); | |
858 | request->in = (void *)in_iov[in_num - 1].iov_base | |
859 | + in_iov[in_num - 1].iov_len | |
860 | - sizeof(struct virtio_crypto_inhdr); | |
861 | iov_discard_back(in_iov, &in_num, sizeof(struct virtio_crypto_inhdr)); | |
862 | ||
863 | /* | |
864 | * The length of operation result, including dest_data | |
865 | * and digest_result if exists. | |
866 | */ | |
867 | request->in_num = in_num; | |
868 | request->in_iov = in_iov; | |
2fda101d LH |
869 | /* now, we free the in_iov_copy inside virtio_crypto_free_request */ |
870 | in_iov_copy = NULL; | |
04b9b37e GA |
871 | |
872 | opcode = ldl_le_p(&req.header.opcode); | |
0e660a6f ZP |
873 | op_info->session_id = ldq_le_p(&req.header.session_id); |
874 | op_info->op_code = opcode; | |
2cb06927 ZP |
875 | op_info->queue_index = queue_index; |
876 | op_info->cb = virtio_crypto_req_complete; | |
877 | op_info->opaque = request; | |
04b9b37e GA |
878 | |
879 | switch (opcode) { | |
880 | case VIRTIO_CRYPTO_CIPHER_ENCRYPT: | |
881 | case VIRTIO_CRYPTO_CIPHER_DECRYPT: | |
999c789f | 882 | op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_SYM; |
04b9b37e | 883 | ret = virtio_crypto_handle_sym_req(vcrypto, |
0e660a6f ZP |
884 | &req.u.sym_req, op_info, |
885 | out_iov, out_num); | |
886 | goto check_result; | |
887 | ||
888 | case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: | |
889 | case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: | |
890 | case VIRTIO_CRYPTO_AKCIPHER_SIGN: | |
891 | case VIRTIO_CRYPTO_AKCIPHER_VERIFY: | |
999c789f | 892 | op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_ASYM; |
0e660a6f ZP |
893 | ret = virtio_crypto_handle_asym_req(vcrypto, |
894 | &req.u.akcipher_req, op_info, | |
04b9b37e | 895 | out_iov, out_num); |
0e660a6f ZP |
896 | |
897 | check_result: | |
04b9b37e GA |
898 | /* Serious errors, need to reset virtio crypto device */ |
899 | if (ret == -EFAULT) { | |
900 | return -1; | |
901 | } else if (ret == -VIRTIO_CRYPTO_NOTSUPP) { | |
2fda101d | 902 | virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); |
04b9b37e | 903 | } else { |
d6634ac0 | 904 | ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev, |
2cb06927 | 905 | op_info); |
04b9b37e | 906 | if (ret < 0) { |
2fda101d | 907 | virtio_crypto_req_complete(request, ret); |
04b9b37e | 908 | } |
04b9b37e GA |
909 | } |
910 | break; | |
0e660a6f | 911 | |
04b9b37e GA |
912 | case VIRTIO_CRYPTO_HASH: |
913 | case VIRTIO_CRYPTO_MAC: | |
914 | case VIRTIO_CRYPTO_AEAD_ENCRYPT: | |
915 | case VIRTIO_CRYPTO_AEAD_DECRYPT: | |
916 | default: | |
917 | error_report("virtio-crypto unsupported dataq opcode: %u", | |
918 | opcode); | |
2fda101d | 919 | virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP); |
04b9b37e GA |
920 | } |
921 | ||
922 | return 0; | |
923 | } | |
924 | ||
925 | static void virtio_crypto_handle_dataq(VirtIODevice *vdev, VirtQueue *vq) | |
926 | { | |
927 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
928 | VirtIOCryptoReq *req; | |
929 | ||
930 | while ((req = virtio_crypto_get_request(vcrypto, vq))) { | |
931 | if (virtio_crypto_handle_request(req) < 0) { | |
932 | virtqueue_detach_element(req->vq, &req->elem, 0); | |
933 | virtio_crypto_free_request(req); | |
934 | break; | |
935 | } | |
936 | } | |
937 | } | |
938 | ||
20cb2ffd GA |
939 | static void virtio_crypto_dataq_bh(void *opaque) |
940 | { | |
941 | VirtIOCryptoQueue *q = opaque; | |
942 | VirtIOCrypto *vcrypto = q->vcrypto; | |
943 | VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); | |
944 | ||
945 | /* This happens when device was stopped but BH wasn't. */ | |
946 | if (!vdev->vm_running) { | |
947 | return; | |
948 | } | |
949 | ||
950 | /* Just in case the driver is not ready on more */ | |
951 | if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) { | |
952 | return; | |
953 | } | |
954 | ||
600f5ce3 SH |
955 | for (;;) { |
956 | virtio_crypto_handle_dataq(vdev, q->dataq); | |
957 | virtio_queue_set_notification(q->dataq, 1); | |
958 | ||
959 | /* Are we done or did the guest add more buffers? */ | |
960 | if (virtio_queue_empty(q->dataq)) { | |
961 | break; | |
962 | } | |
963 | ||
964 | virtio_queue_set_notification(q->dataq, 0); | |
965 | } | |
20cb2ffd GA |
966 | } |
967 | ||
968 | static void | |
969 | virtio_crypto_handle_dataq_bh(VirtIODevice *vdev, VirtQueue *vq) | |
970 | { | |
971 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
972 | VirtIOCryptoQueue *q = | |
973 | &vcrypto->vqs[virtio_crypto_vq2q(virtio_get_queue_index(vq))]; | |
974 | ||
975 | /* This happens when device was stopped but VCPU wasn't. */ | |
976 | if (!vdev->vm_running) { | |
977 | return; | |
978 | } | |
979 | virtio_queue_set_notification(vq, 0); | |
980 | qemu_bh_schedule(q->dataq_bh); | |
981 | } | |
982 | ||
ea4d8ac2 GA |
983 | static uint64_t virtio_crypto_get_features(VirtIODevice *vdev, |
984 | uint64_t features, | |
985 | Error **errp) | |
986 | { | |
987 | return features; | |
988 | } | |
989 | ||
990 | static void virtio_crypto_reset(VirtIODevice *vdev) | |
991 | { | |
992 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
993 | /* multiqueue is disabled by default */ | |
994 | vcrypto->curr_queues = 1; | |
6138dbda | 995 | if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { |
ea4d8ac2 GA |
996 | vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; |
997 | } else { | |
998 | vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; | |
999 | } | |
1000 | } | |
1001 | ||
bc304a64 ZP |
1002 | static uint32_t virtio_crypto_init_services(uint32_t qservices) |
1003 | { | |
1004 | uint32_t vservices = 0; | |
1005 | ||
1006 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) { | |
1007 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_CIPHER); | |
1008 | } | |
1009 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_HASH)) { | |
1010 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_HASH); | |
1011 | } | |
1012 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_MAC)) { | |
1013 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_MAC); | |
1014 | } | |
1015 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AEAD)) { | |
1016 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AEAD); | |
1017 | } | |
1018 | if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) { | |
1019 | vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER); | |
1020 | } | |
1021 | ||
1022 | return vservices; | |
1023 | } | |
1024 | ||
050652d9 GA |
1025 | static void virtio_crypto_init_config(VirtIODevice *vdev) |
1026 | { | |
1027 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1028 | ||
bc304a64 ZP |
1029 | vcrypto->conf.crypto_services = virtio_crypto_init_services( |
1030 | vcrypto->conf.cryptodev->conf.crypto_services); | |
050652d9 GA |
1031 | vcrypto->conf.cipher_algo_l = |
1032 | vcrypto->conf.cryptodev->conf.cipher_algo_l; | |
1033 | vcrypto->conf.cipher_algo_h = | |
1034 | vcrypto->conf.cryptodev->conf.cipher_algo_h; | |
1035 | vcrypto->conf.hash_algo = vcrypto->conf.cryptodev->conf.hash_algo; | |
1036 | vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l; | |
1037 | vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h; | |
1038 | vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo; | |
0e660a6f | 1039 | vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo; |
050652d9 GA |
1040 | vcrypto->conf.max_cipher_key_len = |
1041 | vcrypto->conf.cryptodev->conf.max_cipher_key_len; | |
1042 | vcrypto->conf.max_auth_key_len = | |
1043 | vcrypto->conf.cryptodev->conf.max_auth_key_len; | |
1044 | vcrypto->conf.max_size = vcrypto->conf.cryptodev->conf.max_size; | |
1045 | } | |
1046 | ||
ea4d8ac2 GA |
1047 | static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) |
1048 | { | |
1049 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
1050 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev); | |
1051 | int i; | |
1052 | ||
1053 | vcrypto->cryptodev = vcrypto->conf.cryptodev; | |
1054 | if (vcrypto->cryptodev == NULL) { | |
1055 | error_setg(errp, "'cryptodev' parameter expects a valid object"); | |
1056 | return; | |
aa8f057e | 1057 | } else if (cryptodev_backend_is_used(vcrypto->cryptodev)) { |
7a309cc9 MA |
1058 | error_setg(errp, "can't use already used cryptodev backend: %s", |
1059 | object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev))); | |
aa8f057e | 1060 | return; |
ea4d8ac2 GA |
1061 | } |
1062 | ||
1063 | vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1); | |
1064 | if (vcrypto->max_queues + 1 > VIRTIO_QUEUE_MAX) { | |
1065 | error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " | |
b12227af | 1066 | "must be a positive integer less than %d.", |
ea4d8ac2 GA |
1067 | vcrypto->max_queues, VIRTIO_QUEUE_MAX); |
1068 | return; | |
1069 | } | |
1070 | ||
3857cd5c | 1071 | virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size); |
ea4d8ac2 | 1072 | vcrypto->curr_queues = 1; |
b21e2380 | 1073 | vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues); |
ea4d8ac2 | 1074 | for (i = 0; i < vcrypto->max_queues; i++) { |
20cb2ffd GA |
1075 | vcrypto->vqs[i].dataq = |
1076 | virtio_add_queue(vdev, 1024, virtio_crypto_handle_dataq_bh); | |
1077 | vcrypto->vqs[i].dataq_bh = | |
f63192b0 AB |
1078 | qemu_bh_new_guarded(virtio_crypto_dataq_bh, &vcrypto->vqs[i], |
1079 | &dev->mem_reentrancy_guard); | |
20cb2ffd | 1080 | vcrypto->vqs[i].vcrypto = vcrypto; |
ea4d8ac2 GA |
1081 | } |
1082 | ||
2fda101d | 1083 | vcrypto->ctrl_vq = virtio_add_queue(vdev, 1024, virtio_crypto_handle_ctrl); |
6138dbda | 1084 | if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { |
ea4d8ac2 GA |
1085 | vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; |
1086 | } else { | |
1087 | vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; | |
1088 | } | |
050652d9 GA |
1089 | |
1090 | virtio_crypto_init_config(vdev); | |
46fd1705 | 1091 | cryptodev_backend_set_used(vcrypto->cryptodev, true); |
ea4d8ac2 GA |
1092 | } |
1093 | ||
b69c3c21 | 1094 | static void virtio_crypto_device_unrealize(DeviceState *dev) |
ea4d8ac2 GA |
1095 | { |
1096 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
20cb2ffd GA |
1097 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev); |
1098 | VirtIOCryptoQueue *q; | |
1099 | int i, max_queues; | |
1100 | ||
1101 | max_queues = vcrypto->multiqueue ? vcrypto->max_queues : 1; | |
1102 | for (i = 0; i < max_queues; i++) { | |
d56e1c82 | 1103 | virtio_delete_queue(vcrypto->vqs[i].dataq); |
20cb2ffd GA |
1104 | q = &vcrypto->vqs[i]; |
1105 | qemu_bh_delete(q->dataq_bh); | |
1106 | } | |
1107 | ||
1108 | g_free(vcrypto->vqs); | |
d56e1c82 | 1109 | virtio_delete_queue(vcrypto->ctrl_vq); |
ea4d8ac2 GA |
1110 | |
1111 | virtio_cleanup(vdev); | |
46fd1705 | 1112 | cryptodev_backend_set_used(vcrypto->cryptodev, false); |
ea4d8ac2 GA |
1113 | } |
1114 | ||
1115 | static const VMStateDescription vmstate_virtio_crypto = { | |
1116 | .name = "virtio-crypto", | |
6e724d9d | 1117 | .unmigratable = 1, |
ea4d8ac2 GA |
1118 | .minimum_version_id = VIRTIO_CRYPTO_VM_VERSION, |
1119 | .version_id = VIRTIO_CRYPTO_VM_VERSION, | |
1120 | .fields = (VMStateField[]) { | |
1121 | VMSTATE_VIRTIO_DEVICE, | |
1122 | VMSTATE_END_OF_LIST() | |
1123 | }, | |
1124 | }; | |
1125 | ||
1126 | static Property virtio_crypto_properties[] = { | |
aa8f057e FZ |
1127 | DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev, |
1128 | TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *), | |
ea4d8ac2 GA |
1129 | DEFINE_PROP_END_OF_LIST(), |
1130 | }; | |
1131 | ||
1132 | static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config) | |
1133 | { | |
050652d9 | 1134 | VirtIOCrypto *c = VIRTIO_CRYPTO(vdev); |
9730280d | 1135 | struct virtio_crypto_config crypto_cfg = {}; |
050652d9 GA |
1136 | |
1137 | /* | |
1138 | * Virtio-crypto device conforms to VIRTIO 1.0 which is always LE, | |
1139 | * so we can use LE accessors directly. | |
1140 | */ | |
1141 | stl_le_p(&crypto_cfg.status, c->status); | |
1142 | stl_le_p(&crypto_cfg.max_dataqueues, c->max_queues); | |
1143 | stl_le_p(&crypto_cfg.crypto_services, c->conf.crypto_services); | |
1144 | stl_le_p(&crypto_cfg.cipher_algo_l, c->conf.cipher_algo_l); | |
1145 | stl_le_p(&crypto_cfg.cipher_algo_h, c->conf.cipher_algo_h); | |
1146 | stl_le_p(&crypto_cfg.hash_algo, c->conf.hash_algo); | |
1147 | stl_le_p(&crypto_cfg.mac_algo_l, c->conf.mac_algo_l); | |
1148 | stl_le_p(&crypto_cfg.mac_algo_h, c->conf.mac_algo_h); | |
1149 | stl_le_p(&crypto_cfg.aead_algo, c->conf.aead_algo); | |
1150 | stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len); | |
1151 | stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len); | |
1152 | stq_le_p(&crypto_cfg.max_size, c->conf.max_size); | |
0e660a6f | 1153 | stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo); |
050652d9 GA |
1154 | |
1155 | memcpy(config, &crypto_cfg, c->config_size); | |
ea4d8ac2 GA |
1156 | } |
1157 | ||
5da73dab GA |
1158 | static bool virtio_crypto_started(VirtIOCrypto *c, uint8_t status) |
1159 | { | |
1160 | VirtIODevice *vdev = VIRTIO_DEVICE(c); | |
1161 | return (status & VIRTIO_CONFIG_S_DRIVER_OK) && | |
1162 | (c->status & VIRTIO_CRYPTO_S_HW_READY) && vdev->vm_running; | |
1163 | } | |
1164 | ||
1165 | static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status) | |
1166 | { | |
1167 | VirtIODevice *vdev = VIRTIO_DEVICE(c); | |
1168 | int queues = c->multiqueue ? c->max_queues : 1; | |
1169 | CryptoDevBackend *b = c->cryptodev; | |
1170 | CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; | |
1171 | ||
1172 | if (!cryptodev_get_vhost(cc, b, 0)) { | |
1173 | return; | |
1174 | } | |
1175 | ||
1176 | if ((virtio_crypto_started(c, status)) == !!c->vhost_started) { | |
1177 | return; | |
1178 | } | |
1179 | ||
1180 | if (!c->vhost_started) { | |
1181 | int r; | |
1182 | ||
1183 | c->vhost_started = 1; | |
1184 | r = cryptodev_vhost_start(vdev, queues); | |
1185 | if (r < 0) { | |
1186 | error_report("unable to start vhost crypto: %d: " | |
1187 | "falling back on userspace virtio", -r); | |
1188 | c->vhost_started = 0; | |
1189 | } | |
1190 | } else { | |
1191 | cryptodev_vhost_stop(vdev, queues); | |
1192 | c->vhost_started = 0; | |
1193 | } | |
1194 | } | |
1195 | ||
1196 | static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status) | |
1197 | { | |
1198 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1199 | ||
1200 | virtio_crypto_vhost_status(vcrypto, status); | |
1201 | } | |
1202 | ||
1203 | static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, | |
1204 | bool mask) | |
1205 | { | |
1206 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1207 | int queue = virtio_crypto_vq2q(idx); | |
1208 | ||
1209 | assert(vcrypto->vhost_started); | |
1210 | ||
544f0278 CL |
1211 | /* |
1212 | * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 | |
7e8094f0 | 1213 | * as the macro of configure interrupt's IDX, If this driver does not |
544f0278 CL |
1214 | * support, the function will return |
1215 | */ | |
1216 | ||
1217 | if (idx == VIRTIO_CONFIG_IRQ_IDX) { | |
1218 | return; | |
1219 | } | |
5da73dab GA |
1220 | cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); |
1221 | } | |
1222 | ||
1223 | static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) | |
1224 | { | |
1225 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1226 | int queue = virtio_crypto_vq2q(idx); | |
1227 | ||
1228 | assert(vcrypto->vhost_started); | |
1229 | ||
544f0278 CL |
1230 | /* |
1231 | * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 | |
7e8094f0 | 1232 | * as the macro of configure interrupt's IDX, If this driver does not |
544f0278 CL |
1233 | * support, the function will return |
1234 | */ | |
1235 | ||
1236 | if (idx == VIRTIO_CONFIG_IRQ_IDX) { | |
1237 | return false; | |
1238 | } | |
5da73dab GA |
1239 | return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); |
1240 | } | |
1241 | ||
c255488d JP |
1242 | static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) |
1243 | { | |
1244 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); | |
1245 | CryptoDevBackend *b = vcrypto->cryptodev; | |
1246 | CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; | |
1247 | CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); | |
1248 | return &vhost_crypto->dev; | |
1249 | } | |
1250 | ||
ea4d8ac2 GA |
1251 | static void virtio_crypto_class_init(ObjectClass *klass, void *data) |
1252 | { | |
1253 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1254 | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); | |
1255 | ||
4f67d30b | 1256 | device_class_set_props(dc, virtio_crypto_properties); |
ea4d8ac2 GA |
1257 | dc->vmsd = &vmstate_virtio_crypto; |
1258 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); | |
1259 | vdc->realize = virtio_crypto_device_realize; | |
1260 | vdc->unrealize = virtio_crypto_device_unrealize; | |
1261 | vdc->get_config = virtio_crypto_get_config; | |
1262 | vdc->get_features = virtio_crypto_get_features; | |
1263 | vdc->reset = virtio_crypto_reset; | |
5da73dab GA |
1264 | vdc->set_status = virtio_crypto_set_status; |
1265 | vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; | |
1266 | vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; | |
c255488d | 1267 | vdc->get_vhost = virtio_crypto_get_vhost; |
ea4d8ac2 GA |
1268 | } |
1269 | ||
1270 | static void virtio_crypto_instance_init(Object *obj) | |
1271 | { | |
1272 | VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj); | |
1273 | ||
1274 | /* | |
1275 | * The default config_size is sizeof(struct virtio_crypto_config). | |
1276 | * Can be overriden with virtio_crypto_set_config_size. | |
1277 | */ | |
1278 | vcrypto->config_size = sizeof(struct virtio_crypto_config); | |
ea4d8ac2 GA |
1279 | } |
1280 | ||
1281 | static const TypeInfo virtio_crypto_info = { | |
1282 | .name = TYPE_VIRTIO_CRYPTO, | |
1283 | .parent = TYPE_VIRTIO_DEVICE, | |
1284 | .instance_size = sizeof(VirtIOCrypto), | |
1285 | .instance_init = virtio_crypto_instance_init, | |
1286 | .class_init = virtio_crypto_class_init, | |
1287 | }; | |
1288 | ||
1289 | static void virtio_register_types(void) | |
1290 | { | |
1291 | type_register_static(&virtio_crypto_info); | |
1292 | } | |
1293 | ||
1294 | type_init(virtio_register_types) |