xref: /qemu/backends/cryptodev.c (revision 118d4ed0453c325828e3678608cf32fd9c4a8c49)
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/visitor.h"
28  #include "qemu/config-file.h"
29  #include "qom/object_interfaces.h"
30  #include "hw/virtio/virtio-crypto.h"
31  
32  
33  static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
34  
35  
36  CryptoDevBackendClient *
37  cryptodev_backend_new_client(const char *model,
38                                      const char *name)
39  {
40      CryptoDevBackendClient *cc;
41  
42      cc = g_new0(CryptoDevBackendClient, 1);
43      cc->model = g_strdup(model);
44      if (name) {
45          cc->name = g_strdup(name);
46      }
47  
48      QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
49  
50      return cc;
51  }
52  
53  void cryptodev_backend_free_client(
54                    CryptoDevBackendClient *cc)
55  {
56      QTAILQ_REMOVE(&crypto_clients, cc, next);
57      g_free(cc->name);
58      g_free(cc->model);
59      g_free(cc->info_str);
60      g_free(cc);
61  }
62  
63  void cryptodev_backend_cleanup(
64               CryptoDevBackend *backend,
65               Error **errp)
66  {
67      CryptoDevBackendClass *bc =
68                    CRYPTODEV_BACKEND_GET_CLASS(backend);
69  
70      if (bc->cleanup) {
71          bc->cleanup(backend, errp);
72      }
73  }
74  
75  int64_t cryptodev_backend_create_session(
76             CryptoDevBackend *backend,
77             CryptoDevBackendSessionInfo *sess_info,
78             uint32_t queue_index, Error **errp)
79  {
80      CryptoDevBackendClass *bc =
81                        CRYPTODEV_BACKEND_GET_CLASS(backend);
82  
83      if (bc->create_session) {
84          return bc->create_session(backend, sess_info, queue_index, errp);
85      }
86  
87      return -1;
88  }
89  
90  int cryptodev_backend_close_session(
91             CryptoDevBackend *backend,
92             uint64_t session_id,
93             uint32_t queue_index, Error **errp)
94  {
95      CryptoDevBackendClass *bc =
96                        CRYPTODEV_BACKEND_GET_CLASS(backend);
97  
98      if (bc->close_session) {
99          return bc->close_session(backend, session_id, queue_index, errp);
100      }
101  
102      return -1;
103  }
104  
105  static int cryptodev_backend_operation(
106                   CryptoDevBackend *backend,
107                   CryptoDevBackendOpInfo *op_info,
108                   uint32_t queue_index, Error **errp)
109  {
110      CryptoDevBackendClass *bc =
111                        CRYPTODEV_BACKEND_GET_CLASS(backend);
112  
113      if (bc->do_op) {
114          return bc->do_op(backend, op_info, queue_index, errp);
115      }
116  
117      return -VIRTIO_CRYPTO_ERR;
118  }
119  
120  int cryptodev_backend_crypto_operation(
121                   CryptoDevBackend *backend,
122                   void *opaque,
123                   uint32_t queue_index, Error **errp)
124  {
125      VirtIOCryptoReq *req = opaque;
126      CryptoDevBackendOpInfo *op_info = &req->op_info;
127      enum CryptoDevBackendAlgType algtype = req->flags;
128  
129      if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
130          && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
131          error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
132                     algtype);
133  
134          return -VIRTIO_CRYPTO_NOTSUPP;
135      }
136  
137      return cryptodev_backend_operation(backend, op_info, queue_index, errp);
138  }
139  
140  static void
141  cryptodev_backend_get_queues(Object *obj, Visitor *v, const char *name,
142                               void *opaque, Error **errp)
143  {
144      CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
145      uint32_t value = backend->conf.peers.queues;
146  
147      visit_type_uint32(v, name, &value, errp);
148  }
149  
150  static void
151  cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
152                               void *opaque, Error **errp)
153  {
154      CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
155      uint32_t value;
156  
157      if (!visit_type_uint32(v, name, &value, errp)) {
158          return;
159      }
160      if (!value) {
161          error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
162                     object_get_typename(obj), name, value);
163          return;
164      }
165      backend->conf.peers.queues = value;
166  }
167  
168  static void
169  cryptodev_backend_complete(UserCreatable *uc, Error **errp)
170  {
171      CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
172      CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
173  
174      if (bc->init) {
175          bc->init(backend, errp);
176      }
177  }
178  
179  void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
180  {
181      backend->is_used = used;
182  }
183  
184  bool cryptodev_backend_is_used(CryptoDevBackend *backend)
185  {
186      return backend->is_used;
187  }
188  
189  void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
190  {
191      backend->ready = ready;
192  }
193  
194  bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
195  {
196      return backend->ready;
197  }
198  
199  static bool
200  cryptodev_backend_can_be_deleted(UserCreatable *uc)
201  {
202      return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
203  }
204  
205  static void cryptodev_backend_instance_init(Object *obj)
206  {
207      /* Initialize devices' queues property to 1 */
208      object_property_set_int(obj, "queues", 1, NULL);
209  }
210  
211  static void cryptodev_backend_finalize(Object *obj)
212  {
213      CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
214  
215      cryptodev_backend_cleanup(backend, NULL);
216  }
217  
218  static void
219  cryptodev_backend_class_init(ObjectClass *oc, void *data)
220  {
221      UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
222  
223      ucc->complete = cryptodev_backend_complete;
224      ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
225  
226      QTAILQ_INIT(&crypto_clients);
227      object_class_property_add(oc, "queues", "uint32",
228                                cryptodev_backend_get_queues,
229                                cryptodev_backend_set_queues,
230                                NULL, NULL);
231  }
232  
233  static const TypeInfo cryptodev_backend_info = {
234      .name = TYPE_CRYPTODEV_BACKEND,
235      .parent = TYPE_OBJECT,
236      .instance_size = sizeof(CryptoDevBackend),
237      .instance_init = cryptodev_backend_instance_init,
238      .instance_finalize = cryptodev_backend_finalize,
239      .class_size = sizeof(CryptoDevBackendClass),
240      .class_init = cryptodev_backend_class_init,
241      .interfaces = (InterfaceInfo[]) {
242          { TYPE_USER_CREATABLE },
243          { }
244      }
245  };
246  
247  static void
248  cryptodev_backend_register_types(void)
249  {
250      type_register_static(&cryptodev_backend_info);
251  }
252  
253  type_init(cryptodev_backend_register_types);
254