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 112 int cryptodev_backend_create_session( 113 CryptoDevBackend *backend, 114 CryptoDevBackendSessionInfo *sess_info, 115 uint32_t queue_index, 116 CryptoDevCompletionFunc cb, 117 void *opaque) 118 { 119 CryptoDevBackendClass *bc = 120 CRYPTODEV_BACKEND_GET_CLASS(backend); 121 122 if (bc->create_session) { 123 return bc->create_session(backend, sess_info, queue_index, cb, opaque); 124 } 125 return -VIRTIO_CRYPTO_NOTSUPP; 126 } 127 128 int cryptodev_backend_close_session( 129 CryptoDevBackend *backend, 130 uint64_t session_id, 131 uint32_t queue_index, 132 CryptoDevCompletionFunc cb, 133 void *opaque) 134 { 135 CryptoDevBackendClass *bc = 136 CRYPTODEV_BACKEND_GET_CLASS(backend); 137 138 if (bc->close_session) { 139 return bc->close_session(backend, session_id, queue_index, cb, opaque); 140 } 141 return -VIRTIO_CRYPTO_NOTSUPP; 142 } 143 144 static int cryptodev_backend_operation( 145 CryptoDevBackend *backend, 146 CryptoDevBackendOpInfo *op_info, 147 uint32_t queue_index, 148 CryptoDevCompletionFunc cb, 149 void *opaque) 150 { 151 CryptoDevBackendClass *bc = 152 CRYPTODEV_BACKEND_GET_CLASS(backend); 153 154 if (bc->do_op) { 155 return bc->do_op(backend, op_info, queue_index, cb, opaque); 156 } 157 return -VIRTIO_CRYPTO_NOTSUPP; 158 } 159 160 int cryptodev_backend_crypto_operation( 161 CryptoDevBackend *backend, 162 void *opaque1, 163 uint32_t queue_index, 164 CryptoDevCompletionFunc cb, void *opaque2) 165 { 166 VirtIOCryptoReq *req = opaque1; 167 CryptoDevBackendOpInfo *op_info = &req->op_info; 168 QCryptodevBackendAlgType algtype = req->flags; 169 170 if ((algtype != QCRYPTODEV_BACKEND_ALG_SYM) 171 && (algtype != QCRYPTODEV_BACKEND_ALG_ASYM)) { 172 error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype); 173 return -VIRTIO_CRYPTO_NOTSUPP; 174 } 175 176 return cryptodev_backend_operation(backend, op_info, queue_index, 177 cb, opaque2); 178 } 179 180 static void 181 cryptodev_backend_get_queues(Object *obj, Visitor *v, const char *name, 182 void *opaque, Error **errp) 183 { 184 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj); 185 uint32_t value = backend->conf.peers.queues; 186 187 visit_type_uint32(v, name, &value, errp); 188 } 189 190 static void 191 cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name, 192 void *opaque, Error **errp) 193 { 194 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj); 195 uint32_t value; 196 197 if (!visit_type_uint32(v, name, &value, errp)) { 198 return; 199 } 200 if (!value) { 201 error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'", 202 object_get_typename(obj), name, value); 203 return; 204 } 205 backend->conf.peers.queues = value; 206 } 207 208 static void 209 cryptodev_backend_complete(UserCreatable *uc, Error **errp) 210 { 211 CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc); 212 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc); 213 214 if (bc->init) { 215 bc->init(backend, errp); 216 } 217 } 218 219 void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used) 220 { 221 backend->is_used = used; 222 } 223 224 bool cryptodev_backend_is_used(CryptoDevBackend *backend) 225 { 226 return backend->is_used; 227 } 228 229 void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready) 230 { 231 backend->ready = ready; 232 } 233 234 bool cryptodev_backend_is_ready(CryptoDevBackend *backend) 235 { 236 return backend->ready; 237 } 238 239 static bool 240 cryptodev_backend_can_be_deleted(UserCreatable *uc) 241 { 242 return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc)); 243 } 244 245 static void cryptodev_backend_instance_init(Object *obj) 246 { 247 /* Initialize devices' queues property to 1 */ 248 object_property_set_int(obj, "queues", 1, NULL); 249 } 250 251 static void cryptodev_backend_finalize(Object *obj) 252 { 253 CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj); 254 255 cryptodev_backend_cleanup(backend, NULL); 256 } 257 258 static void 259 cryptodev_backend_class_init(ObjectClass *oc, void *data) 260 { 261 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 262 263 ucc->complete = cryptodev_backend_complete; 264 ucc->can_be_deleted = cryptodev_backend_can_be_deleted; 265 266 QTAILQ_INIT(&crypto_clients); 267 object_class_property_add(oc, "queues", "uint32", 268 cryptodev_backend_get_queues, 269 cryptodev_backend_set_queues, 270 NULL, NULL); 271 } 272 273 static const TypeInfo cryptodev_backend_info = { 274 .name = TYPE_CRYPTODEV_BACKEND, 275 .parent = TYPE_OBJECT, 276 .instance_size = sizeof(CryptoDevBackend), 277 .instance_init = cryptodev_backend_instance_init, 278 .instance_finalize = cryptodev_backend_finalize, 279 .class_size = sizeof(CryptoDevBackendClass), 280 .class_init = cryptodev_backend_class_init, 281 .interfaces = (InterfaceInfo[]) { 282 { TYPE_USER_CREATABLE }, 283 { } 284 } 285 }; 286 287 static void 288 cryptodev_backend_register_types(void) 289 { 290 type_register_static(&cryptodev_backend_info); 291 } 292 293 type_init(cryptodev_backend_register_types); 294