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