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