xref: /qemu/backends/cryptodev.c (revision e7a775fd9fc08550c4525bc331b1cda342b459dd)
1 /*
2  * QEMU Crypto Device Implementation
3  *
4  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5  *
6  * Authors:
7  *    Gonglei <arei.gonglei@huawei.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include "qemu/osdep.h"
25 #include "sysemu/cryptodev.h"
26 #include "qapi/error.h"
27 #include "qapi/qapi-commands-cryptodev.h"
28 #include "qapi/visitor.h"
29 #include "qemu/config-file.h"
30 #include "qemu/error-report.h"
31 #include "qom/object_interfaces.h"
32 #include "hw/virtio/virtio-crypto.h"
33 
34 
35 static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
36 
37 static int qmp_query_cryptodev_foreach(Object *obj, void *data)
38 {
39     CryptoDevBackend *backend;
40     QCryptodevInfoList **infolist = data;
41     uint32_t services, i;
42 
43     if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
44         return 0;
45     }
46 
47     QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
48     info->id = g_strdup(object_get_canonical_path_component(obj));
49 
50     backend = CRYPTODEV_BACKEND(obj);
51     services = backend->conf.crypto_services;
52     for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
53         if (services & (1 << i)) {
54             QAPI_LIST_PREPEND(info->service, i);
55         }
56     }
57 
58     for (i = 0; i < backend->conf.peers.queues; i++) {
59         CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
60         QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
61 
62         client->queue = cc->queue_index;
63         client->type = cc->type;
64         QAPI_LIST_PREPEND(info->client, client);
65     }
66 
67     QAPI_LIST_PREPEND(*infolist, info);
68 
69     return 0;
70 }
71 
72 QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
73 {
74     QCryptodevInfoList *list = NULL;
75     Object *objs = container_get(object_get_root(), "/objects");
76 
77     object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
78 
79     return list;
80 }
81 
82 CryptoDevBackendClient *cryptodev_backend_new_client(void)
83 {
84     CryptoDevBackendClient *cc;
85 
86     cc = g_new0(CryptoDevBackendClient, 1);
87     QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
88 
89     return cc;
90 }
91 
92 void cryptodev_backend_free_client(
93                   CryptoDevBackendClient *cc)
94 {
95     QTAILQ_REMOVE(&crypto_clients, cc, next);
96     g_free(cc->info_str);
97     g_free(cc);
98 }
99 
100 void cryptodev_backend_cleanup(
101              CryptoDevBackend *backend,
102              Error **errp)
103 {
104     CryptoDevBackendClass *bc =
105                   CRYPTODEV_BACKEND_GET_CLASS(backend);
106 
107     if (bc->cleanup) {
108         bc->cleanup(backend, errp);
109     }
110 
111     g_free(backend->sym_stat);
112     g_free(backend->asym_stat);
113 }
114 
115 int cryptodev_backend_create_session(
116            CryptoDevBackend *backend,
117            CryptoDevBackendSessionInfo *sess_info,
118            uint32_t queue_index,
119            CryptoDevCompletionFunc cb,
120            void *opaque)
121 {
122     CryptoDevBackendClass *bc =
123                       CRYPTODEV_BACKEND_GET_CLASS(backend);
124 
125     if (bc->create_session) {
126         return bc->create_session(backend, sess_info, queue_index, cb, opaque);
127     }
128     return -VIRTIO_CRYPTO_NOTSUPP;
129 }
130 
131 int cryptodev_backend_close_session(
132            CryptoDevBackend *backend,
133            uint64_t session_id,
134            uint32_t queue_index,
135            CryptoDevCompletionFunc cb,
136            void *opaque)
137 {
138     CryptoDevBackendClass *bc =
139                       CRYPTODEV_BACKEND_GET_CLASS(backend);
140 
141     if (bc->close_session) {
142         return bc->close_session(backend, session_id, queue_index, cb, opaque);
143     }
144     return -VIRTIO_CRYPTO_NOTSUPP;
145 }
146 
147 static int cryptodev_backend_operation(
148                  CryptoDevBackend *backend,
149                  CryptoDevBackendOpInfo *op_info)
150 {
151     CryptoDevBackendClass *bc =
152                       CRYPTODEV_BACKEND_GET_CLASS(backend);
153 
154     if (bc->do_op) {
155         return bc->do_op(backend, op_info);
156     }
157     return -VIRTIO_CRYPTO_NOTSUPP;
158 }
159 
160 static int cryptodev_backend_account(CryptoDevBackend *backend,
161                  CryptoDevBackendOpInfo *op_info)
162 {
163     enum QCryptodevBackendAlgType algtype = op_info->algtype;
164     int len;
165 
166     if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
167         CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
168         len = asym_op_info->src_len;
169         switch (op_info->op_code) {
170         case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
171             CryptodevAsymStatIncEncrypt(backend, len);
172             break;
173         case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
174             CryptodevAsymStatIncDecrypt(backend, len);
175             break;
176         case VIRTIO_CRYPTO_AKCIPHER_SIGN:
177             CryptodevAsymStatIncSign(backend, len);
178             break;
179         case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
180             CryptodevAsymStatIncVerify(backend, len);
181             break;
182         default:
183             return -VIRTIO_CRYPTO_NOTSUPP;
184         }
185     } else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
186         CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
187         len = sym_op_info->src_len;
188         switch (op_info->op_code) {
189         case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
190             CryptodevSymStatIncEncrypt(backend, len);
191             break;
192         case VIRTIO_CRYPTO_CIPHER_DECRYPT:
193             CryptodevSymStatIncDecrypt(backend, len);
194             break;
195         default:
196             return -VIRTIO_CRYPTO_NOTSUPP;
197         }
198     } else {
199         error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
200         return -VIRTIO_CRYPTO_NOTSUPP;
201     }
202 
203     return len;
204 }
205 
206 int cryptodev_backend_crypto_operation(
207                  CryptoDevBackend *backend,
208                  CryptoDevBackendOpInfo *op_info)
209 {
210     int ret;
211 
212     ret = cryptodev_backend_account(backend, op_info);
213     if (ret < 0) {
214         return ret;
215     }
216 
217     return cryptodev_backend_operation(backend, op_info);
218 }
219 
220 static void
221 cryptodev_backend_get_queues(Object *obj, Visitor *v, const char *name,
222                              void *opaque, Error **errp)
223 {
224     CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
225     uint32_t value = backend->conf.peers.queues;
226 
227     visit_type_uint32(v, name, &value, errp);
228 }
229 
230 static void
231 cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
232                              void *opaque, Error **errp)
233 {
234     CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
235     uint32_t value;
236 
237     if (!visit_type_uint32(v, name, &value, errp)) {
238         return;
239     }
240     if (!value) {
241         error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
242                    object_get_typename(obj), name, value);
243         return;
244     }
245     backend->conf.peers.queues = value;
246 }
247 
248 static void
249 cryptodev_backend_complete(UserCreatable *uc, Error **errp)
250 {
251     CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
252     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
253     uint32_t services;
254 
255     if (bc->init) {
256         bc->init(backend, errp);
257     }
258 
259     services = backend->conf.crypto_services;
260     if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
261         backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
262     }
263 
264     if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
265         backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
266     }
267 }
268 
269 void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
270 {
271     backend->is_used = used;
272 }
273 
274 bool cryptodev_backend_is_used(CryptoDevBackend *backend)
275 {
276     return backend->is_used;
277 }
278 
279 void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
280 {
281     backend->ready = ready;
282 }
283 
284 bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
285 {
286     return backend->ready;
287 }
288 
289 static bool
290 cryptodev_backend_can_be_deleted(UserCreatable *uc)
291 {
292     return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
293 }
294 
295 static void cryptodev_backend_instance_init(Object *obj)
296 {
297     /* Initialize devices' queues property to 1 */
298     object_property_set_int(obj, "queues", 1, NULL);
299 }
300 
301 static void cryptodev_backend_finalize(Object *obj)
302 {
303     CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
304 
305     cryptodev_backend_cleanup(backend, NULL);
306 }
307 
308 static void
309 cryptodev_backend_class_init(ObjectClass *oc, void *data)
310 {
311     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
312 
313     ucc->complete = cryptodev_backend_complete;
314     ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
315 
316     QTAILQ_INIT(&crypto_clients);
317     object_class_property_add(oc, "queues", "uint32",
318                               cryptodev_backend_get_queues,
319                               cryptodev_backend_set_queues,
320                               NULL, NULL);
321 }
322 
323 static const TypeInfo cryptodev_backend_info = {
324     .name = TYPE_CRYPTODEV_BACKEND,
325     .parent = TYPE_OBJECT,
326     .instance_size = sizeof(CryptoDevBackend),
327     .instance_init = cryptodev_backend_instance_init,
328     .instance_finalize = cryptodev_backend_finalize,
329     .class_size = sizeof(CryptoDevBackendClass),
330     .class_init = cryptodev_backend_class_init,
331     .interfaces = (InterfaceInfo[]) {
332         { TYPE_USER_CREATABLE },
333         { }
334     }
335 };
336 
337 static void
338 cryptodev_backend_register_types(void)
339 {
340     type_register_static(&cryptodev_backend_info);
341 }
342 
343 type_init(cryptodev_backend_register_types);
344