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