diff mbox

[v1,05/14] crypto: add cryptodev-linux as a cryptodev backend

Message ID 1473306156-176628-6-git-send-email-arei.gonglei@huawei.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gonglei (Arei) Sept. 8, 2016, 3:42 a.m. UTC
Cryptodev-linux is a device that allows access to Linux
kernel cryptographic drivers; thus allowing of userspace
applications to take advantage of hardware accelerators.
Cryptodev-linux is implemented as a standalone module
that requires no dependencies other than a stock linux kernel.

The Cryptodev-linux project website is:
  http://cryptodev-linux.org/

Meanwile, I introdue the virtio_crypto.h which follows
virtio-crypto specification bacause cryptodev-linux.c include it.

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
 configure                                      |  16 +
 crypto/Makefile.objs                           |   1 +
 crypto/crypto.c                                |   8 +-
 crypto/cryptodev-linux.c                       | 419 +++++++++++++++++++++++
 include/crypto/crypto-clients.h                |  39 +++
 include/standard-headers/linux/virtio_crypto.h | 448 +++++++++++++++++++++++++
 qapi-schema.json                               |  17 +-
 qemu-options.hx                                |  18 +-
 8 files changed, 963 insertions(+), 3 deletions(-)
 create mode 100644 crypto/cryptodev-linux.c
 create mode 100644 include/crypto/crypto-clients.h
 create mode 100644 include/standard-headers/linux/virtio_crypto.h
diff mbox

Patch

diff --git a/configure b/configure
index 5a9bda1..0fbead7 100755
--- a/configure
+++ b/configure
@@ -320,6 +320,7 @@  vhdx=""
 numa=""
 tcmalloc="no"
 jemalloc="no"
+cryptodev_linux="no"
 
 # parse CC options first
 for opt do
@@ -3616,6 +3617,16 @@  EOF
 fi
 
 ##########################################
+# cryptodev-linux header probe
+cat > $TMPC << EOF
+#include <crypto/cryptodev.h>
+int main(void) { return 0; }
+EOF
+if compile_prog "" "" ; then
+    cryptodev_linux="yes"
+fi
+
+##########################################
 # signalfd probe
 signalfd="no"
 cat > $TMPC << EOF
@@ -4920,6 +4931,7 @@  echo "NUMA host support $numa"
 echo "tcmalloc support  $tcmalloc"
 echo "jemalloc support  $jemalloc"
 echo "avx2 optimization $avx2_opt"
+echo "cryptodev-linux support $cryptodev_linux"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -5321,6 +5333,10 @@  if test "$avx2_opt" = "yes" ; then
   echo "CONFIG_AVX2_OPT=y" >> $config_host_mak
 fi
 
+if test "$cryptodev_linux" = "yes" ; then
+  echo "CONFIG_CRYPTODEV_LINUX=y" >> $config_host_mak
+fi
+
 if test "$lzo" = "yes" ; then
   echo "CONFIG_LZO=y" >> $config_host_mak
 fi
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 652b429..1f2ec24 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -28,6 +28,7 @@  crypto-obj-y += block-qcow.o
 crypto-obj-y += block-luks.o
 crypto-obj-y += crypto.o
 crypto-obj-y += crypto-queue.o
+crypto-obj-$(CONFIG_CRYPTODEV_LINUX) += cryptodev-linux.o
 
 # Let the userspace emulators avoid linking gnutls/etc
 crypto-aes-obj-y = aes.o
diff --git a/crypto/crypto.c b/crypto/crypto.c
index 958a959..1d3d1d3 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -34,6 +34,7 @@ 
 #include "crypto/crypto.h"
 #include "qemu/config-file.h"
 #include "monitor/monitor.h"
+#include "crypto/crypto-clients.h"
 
 
 static QTAILQ_HEAD(, CryptoClientState) crypto_clients;
@@ -81,7 +82,12 @@  int crypto_init_clients(void)
 static int (* const crypto_client_init_fun[CRYPTO_CLIENT_OPTIONS_KIND__MAX])(
     const CryptoClientOptions *opts,
     const char *name,
-    CryptoClientState *peer, Error **errp);
+    CryptoClientState *peer, Error **errp) = {
+#ifdef CONFIG_CRYPTODEV_LINUX
+        [CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX] =
+                                             crypto_init_cryptodev_linux,
+#endif
+};
 
 static int crypto_client_init1(const void *object, Error **errp)
 {
diff --git a/crypto/cryptodev-linux.c b/crypto/cryptodev-linux.c
new file mode 100644
index 0000000..ae2dcdb
--- /dev/null
+++ b/crypto/cryptodev-linux.c
@@ -0,0 +1,419 @@ 
+/*
+ * cryptodev-linux backend support
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.  See the COPYING file in the
+ * top-level directory.
+ */
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <crypto/cryptodev.h>
+
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qemu/iov.h"
+#include "qapi-visit.h"
+#include "qapi/opts-visitor.h"
+#include "qemu/error-report.h"
+
+#include "crypto/crypto.h"
+#include "crypto/crypto-clients.h"
+#include "standard-headers/linux/virtio_crypto.h"
+
+
+#define CRYPTO_CHARDEV_PATH "/dev/crypto"
+
+
+typedef struct CryptodevLinuxSession {
+    struct session_op *sess;
+    uint8_t direction; /* encryption or decryption */
+    uint8_t type; /* cipher? hash? aead? */
+    QTAILQ_ENTRY(CryptodevLinuxSession) next;
+} CryptodevLinuxSession;
+
+typedef struct CryptodevLinuxState {
+    CryptoClientState cc;
+    int fd;
+    bool read_poll;
+    bool write_poll;
+    bool enabled;
+    QTAILQ_HEAD(, CryptodevLinuxSession) sessions;
+} CryptodevLinuxState;
+
+static int
+cryptodev_linux_open(int *gfd, Error **errp)
+{
+    int fd = -1;
+
+    /* Open the crypto device */
+    fd = open(CRYPTO_CHARDEV_PATH, O_RDWR, 0);
+    if (fd < 0) {
+        error_setg_errno(errp, errno, "Cannot open %s",
+                         CRYPTO_CHARDEV_PATH);
+        return -1;
+    }
+
+    /* Set close-on-exec (not really neede here) */
+    if (fcntl(fd, F_SETFD, 1) == -1) {
+        perror("fcntl(F_SETFD)");
+        error_setg_errno(errp, errno,
+                        "Failed to fcntl(F_SETFD) %s",
+                         CRYPTO_CHARDEV_PATH);
+        close(fd);
+        return -1;
+    }
+
+    *gfd = fd;
+
+    return 0;
+}
+
+static int
+cryptodev_linux_handle_cipher_sess(CryptodevLinuxState *s,
+                              CryptoSymSessionInfo *session_info,
+                              struct session_op *sess,
+                              uint8_t *direction)
+{
+    switch (session_info->cipher_alg) {
+    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
+        sess->cipher = CRYPTO_AES_CBC;
+        break;
+    default:
+        error_report("Unsupported cipher alg: %u",
+                     session_info->cipher_alg);
+        return -1;
+    }
+    /* Get crypto session for assinged algorithm */
+    sess->keylen = session_info->key_len;
+    sess->key = session_info->cipher_key;
+    *direction = session_info->direction;
+    return 0;
+}
+
+static int
+cryptodev_linux_handle_hash_sess(CryptodevLinuxState *s,
+                              CryptoSymSessionInfo *session_info,
+                              struct session_op *sess)
+{
+    switch (session_info->hash_alg) {
+    case VIRTIO_CRYPTO_HASH_SHA1:
+        sess->mac = CRYPTO_SHA1_HMAC;
+        break;
+    default:
+        error_report("Unsupported hash alg: %u",
+                     session_info->hash_alg);
+        return -1;
+    }
+
+    sess->mackeylen = session_info->auth_key_len;
+    sess->mackey = session_info->auth_key;
+    return 0;
+}
+
+static int
+cryptodev_linux_handle_chaining_sess(CryptodevLinuxState *s,
+                              CryptoSymSessionInfo *session_info,
+                              struct session_op *sess,
+                              uint8_t *direction)
+{
+    int ret;
+
+    ret = cryptodev_linux_handle_cipher_sess(s, session_info,
+                                             sess, direction);
+    if (ret == 0) {
+        ret = cryptodev_linux_handle_hash_sess(s,
+                                         session_info, sess);
+    }
+    return ret;
+}
+
+static int
+cryptodev_linux_create_session(CryptoClientState *cc,
+                               CryptoSymSessionInfo *session_info,
+                               uint64_t *session_id)
+{
+    CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+    int fd = s->fd;
+    int ret = -1;
+    CryptodevLinuxSession *session = NULL;
+    uint8_t direction = 0;
+    struct session_op *sess;
+#ifdef CIOCGSESSINFO
+    struct session_info_op siop;
+#endif
+
+    sess = g_new0(struct session_op, 1);
+    /* Setup session Parameters */
+    switch (session_info->op_type) {
+    case VIRTIO_CRYPTO_SYM_OP_CIPHER:
+        ret = cryptodev_linux_handle_cipher_sess(s, session_info,
+                                               sess, &direction);
+        if (ret < 0) {
+            goto err;
+        }
+        break;
+    case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING:
+        ret = cryptodev_linux_handle_chaining_sess(s, session_info,
+                                          sess, &direction);
+        if (ret < 0) {
+            goto err;
+        }
+        break;
+    default:
+        error_report("Unsupported type: %u", session_info->op_type);
+        goto err;
+    }
+
+    if (ioctl(fd, CIOCGSESSION, sess)) {
+        perror("ioctl(CIOCGSESSION)");
+        ret = -1;
+        goto err;
+    }
+
+#ifdef CIOCGSESSINFO
+    siop.ses = sess->ses;
+    if (ioctl(fd, CIOCGSESSINFO, &siop)) {
+        perror("ioctl(CIOCGSESSINFO)");
+        ret = -1;
+        goto err;
+    }
+    printf("got %s with driver %s\n",
+          siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
+#endif
+
+    *session_id = sess->ses;
+
+    session = g_new0(CryptodevLinuxSession, 1);
+    session->sess = sess;
+    session->type = session_info->op_type;
+    switch (direction) {
+    case VIRTIO_CRYPTO_OP_ENCRYPT:
+        session->direction = COP_ENCRYPT;
+        break;
+    case VIRTIO_CRYPTO_OP_DECRYPT:
+        session->direction = COP_DECRYPT;
+        break;
+    default:
+        error_report("Unsupported direction: %u", direction);
+        goto err;
+    }
+
+    QTAILQ_INSERT_TAIL(&s->sessions, session, next);
+
+    return 0;
+err:
+    g_free(sess);
+    g_free(session);
+    return ret;
+}
+
+static CryptodevLinuxSession *
+cryptodev_linux_find_session(CryptodevLinuxState *s,
+                             uint64_t session_id)
+{
+    CryptodevLinuxSession *session, *tmp;
+
+    QTAILQ_FOREACH_SAFE(session, &s->sessions, next, tmp) {
+        if (session->sess->ses == session_id) {
+            return session;
+        }
+    }
+
+    return NULL;
+}
+
+static int
+cryptodev_linux_close_session(CryptoClientState *cc,
+                               uint64_t session_id)
+{
+    CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+    int fd = s->fd;
+    CryptodevLinuxSession *session;
+
+    session = cryptodev_linux_find_session(s, session_id);
+    if (session == NULL) {
+        error_report("Cannot find the session: %" PRIu64 "",
+                      session_id);
+        return -1;
+    }
+
+    if (ioctl(fd, CIOCFSESSION, &session_id)) {
+        perror("ioctl(CIOCFSESSION)");
+        return -1;
+    }
+
+    QTAILQ_REMOVE(&s->sessions, session, next);
+    g_free(session->sess);
+    g_free(session);
+    return 0;
+}
+
+static int
+cryptodev_linux_handle_cipher_op(CryptoSymOpInfo *op_info,
+                                   CryptodevLinuxSession *session,
+                                   int fd)
+{
+    struct crypt_op cryp;
+
+    cryp.ses = op_info->session_id;
+    cryp.len = op_info->src_len;
+    cryp.src = op_info->src;
+    cryp.dst = op_info->dst;
+    cryp.iv = op_info->iv;
+    cryp.op = session->direction;
+
+    if (ioctl(fd, CIOCCRYPT, &cryp)) {
+        perror("ioctl(CIOCCRYPT)");
+        return -1;
+    }
+
+    return 1;
+}
+
+static int
+cryptodev_linux_handle_chaining_op(CryptoSymOpInfo *op_info,
+                                   CryptodevLinuxSession *session,
+                                   int fd)
+{
+    struct crypt_auth_op cao;
+
+    cao.ses = op_info->session_id;
+    cao.len = op_info->src_len;
+    cao.src = op_info->src;
+    cao.dst = op_info->dst;
+    cao.iv = op_info->iv;
+    cao.op = session->direction;
+
+    if (op_info->aad_len > 0) {
+        cao.auth_len = op_info->aad_len;
+        cao.auth_src = op_info->aad_data;
+    }
+
+    /* We only support TLS mode at present, the hash result is
+       stored at the end of cipher text, the frontend driver
+       should allocate enough memory. */
+    cao.flags = COP_FLAG_AEAD_TLS_TYPE;
+
+    if (ioctl(fd, CIOCAUTHCRYPT, &cao)) {
+        perror("ioctl(CIOCCRYPT)");
+        return -1;
+    }
+
+    return 1;
+}
+
+
+static int
+cryptodev_linux_do_sym_op(CryptoClientState *cc,
+                              CryptoSymOpInfo *op_info)
+{
+    CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+    CryptodevLinuxSession *session;
+
+    session = cryptodev_linux_find_session(s, op_info->session_id);
+    if (session == NULL) {
+        error_report("Cannot find the session: %" PRIu64 "",
+                      op_info->session_id);
+        return -VIRTIO_CRYPTO_OP_INVSESS;
+    }
+
+    switch (session->type) {
+    case VIRTIO_CRYPTO_SYM_OP_CIPHER:
+        return cryptodev_linux_handle_cipher_op(op_info, session, s->fd);
+    case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING:
+        return cryptodev_linux_handle_chaining_op(op_info, session, s->fd);
+    default:
+        error_report("Unsupported type: %u", session->type);
+        return -1;
+    }
+}
+
+static void
+cryptodev_linux_cleanup(CryptoClientState *cc)
+{
+    CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+    CryptodevLinuxSession *session;
+    uint64_t session_id;
+
+    QTAILQ_FOREACH(session, &s->sessions, next) {
+        session_id = session->sess->ses;
+        if (ioctl(s->fd, CIOCFSESSION, &session_id)) {
+            perror("ioctl(CIOCFSESSION)");
+        }
+        g_free(session->sess);
+        g_free(session);
+    }
+
+    close(s->fd);
+    s->fd = -1;
+    s->enabled = false;
+}
+
+static void
+cryptodev_linux_poll(CryptoClientState *cc, bool enable)
+{
+
+}
+
+static CryptoClientInfo crypto_cryptodev_info = {
+    .type = CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX,
+    .size = sizeof(CryptodevLinuxState),
+    .create_session = cryptodev_linux_create_session,
+    .close_session = cryptodev_linux_close_session,
+    .do_sym_op = cryptodev_linux_do_sym_op,
+    .cleanup = cryptodev_linux_cleanup,
+    .poll = cryptodev_linux_poll,
+};
+
+int crypto_init_cryptodev_linux(const CryptoClientOptions *opts,
+                                const char *name,
+                                CryptoClientState *peer, Error **errp)
+{
+    const CryptodevLinuxOptions *cryptodev;
+    int fd, ret;
+    CryptoClientState *cc;
+    CryptodevLinuxState *s;
+
+    assert(opts->type == CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX);
+
+    cryptodev = opts->u.cryptodev_linux.data;
+    if (cryptodev->has_fd) {
+        if (cryptodev->fd < 0) {
+            error_setg(errp, "Invaild fd: %" PRId64 "", cryptodev->fd);
+            return -1;
+        } else {
+            fd = cryptodev->fd;
+        }
+    } else {
+        ret = cryptodev_linux_open(&fd, errp);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    cc = new_crypto_client(&crypto_cryptodev_info, peer,
+                           "cryptodev-linux", name);
+
+    cc->crypto_services = 1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
+                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
+                         1u << VIRTIO_CRYPTO_SERVICE_AEAD;
+    cc->cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
+    cc->hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+
+    /* the cryptodev backend is ready for work */
+    cc->ready = true;
+    s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+
+    s->fd = fd;
+    s->enabled = true;
+    QTAILQ_INIT(&s->sessions);
+
+    return 0;
+}
diff --git a/include/crypto/crypto-clients.h b/include/crypto/crypto-clients.h
new file mode 100644
index 0000000..dea5748
--- /dev/null
+++ b/include/crypto/crypto-clients.h
@@ -0,0 +1,39 @@ 
+/*
+ * Crypto clients header
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef QEMU_CRYPTO_CLIENTS_H
+#define QEMU_CRYPTO_CLIENTS_H
+
+#include "crypto/crypto.h"
+#include "qapi-types.h"
+
+#ifdef CONFIG_CRYPTODEV_LINUX
+int crypto_init_cryptodev_linux(const CryptoClientOptions *opts,
+                                const char *name,
+                                CryptoClientState *peer, Error **errp);
+#endif
+
+#endif /* QEMU_CRYPTO_CLIENTS_H */
diff --git a/include/standard-headers/linux/virtio_crypto.h b/include/standard-headers/linux/virtio_crypto.h
new file mode 100644
index 0000000..443b2a8
--- /dev/null
+++ b/include/standard-headers/linux/virtio_crypto.h
@@ -0,0 +1,448 @@ 
+#ifndef _VIRTIO_CRYPTO_H
+#define _VIRTIO_CRYPTO_H
+
+#include "standard-headers/linux/types.h"
+#include "standard-headers/linux/virtio_config.h"
+#include "standard-headers/linux/virtio_types.h"
+
+
+#define VIRTIO_CRYPTO_SERVICE_CIPHER (0)
+#define VIRTIO_CRYPTO_SERVICE_HASH (1)
+#define VIRTIO_CRYPTO_SERVICE_MAC  (2)
+#define VIRTIO_CRYPTO_SERVICE_AEAD (3)
+
+#define VIRTIO_CRYPTO_OPCODE(service, op)   ((service << 8) | (op))
+
+struct virtio_crypto_ctrl_header{
+#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x02)
+#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x03)
+#define VIRTIO_CRYPTO_HASH_CREATE_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x02)
+#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x03)
+#define VIRTIO_CRYPTO_MAC_CREATE_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x02)
+#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x03)
+#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02)
+#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \
+       VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03)
+    __virtio32 opcode;
+    __virtio32 algo;
+    __virtio32 flag;
+    /* data virtqueue id */
+    __virtio32 queue_id;
+};
+
+struct virtio_crypto_cipher_session_para {
+#define VIRTIO_CRYPTO_NO_CIPHER                 0
+#define VIRTIO_CRYPTO_CIPHER_ARC4               1
+#define VIRTIO_CRYPTO_CIPHER_AES_ECB            2
+#define VIRTIO_CRYPTO_CIPHER_AES_CBC            3
+#define VIRTIO_CRYPTO_CIPHER_AES_CTR            4
+#define VIRTIO_CRYPTO_CIPHER_DES_ECB            5
+#define VIRTIO_CRYPTO_CIPHER_DES_CBC            6
+#define VIRTIO_CRYPTO_CIPHER_3DES_ECB           7
+#define VIRTIO_CRYPTO_CIPHER_3DES_CBC           8
+#define VIRTIO_CRYPTO_CIPHER_3DES_CTR           9
+#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8          10
+#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2        11
+#define VIRTIO_CRYPTO_CIPHER_AES_F8             12
+#define VIRTIO_CRYPTO_CIPHER_AES_XTS            13
+#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3           14
+    __virtio32 algo;
+    /* length of key */
+    __virtio32 keylen;
+
+#define VIRTIO_CRYPTO_OP_ENCRYPT  1
+#define VIRTIO_CRYPTO_OP_DECRYPT  2
+    /* encrypt or decrypt */
+    __virtio32 op;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_session_input {
+    // Device-writable part
+    __virtio64 session_id;
+    __virtio32 status;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_session_output {
+    __virtio64 key_addr; /* guest key phycial address */
+};
+
+struct virtio_crypto_cipher_session_req {
+    struct virtio_crypto_cipher_session_para para;
+    struct virtio_crypto_cipher_session_output out;
+    struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_hash_session_para {
+#define VIRTIO_CRYPTO_NO_HASH            0
+#define VIRTIO_CRYPTO_HASH_MD5           1
+#define VIRTIO_CRYPTO_HASH_SHA1          2
+#define VIRTIO_CRYPTO_HASH_SHA_224       3
+#define VIRTIO_CRYPTO_HASH_SHA_256       4
+#define VIRTIO_CRYPTO_HASH_SHA_384       5
+#define VIRTIO_CRYPTO_HASH_SHA_512       6
+#define VIRTIO_CRYPTO_HASH_SHA3_224      7
+#define VIRTIO_CRYPTO_HASH_SHA3_256      8
+#define VIRTIO_CRYPTO_HASH_SHA3_384      9
+#define VIRTIO_CRYPTO_HASH_SHA3_512      10
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128      11
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256      12
+    __virtio32 algo;
+    /* hash result length */
+    __virtio32 hash_result_len;
+};
+
+struct virtio_crypto_hash_create_session_req {
+    struct virtio_crypto_hash_session_para para;
+    struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_mac_session_para {
+#define VIRTIO_CRYPTO_NO_MAC                       0
+#define VIRTIO_CRYPTO_MAC_HMAC_MD5                 1
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA1                2
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224             3
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256             4
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384             5
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512             6
+#define VIRTIO_CRYPTO_MAC_CMAC_3DES                25
+#define VIRTIO_CRYPTO_MAC_CMAC_AES                 26
+#define VIRTIO_CRYPTO_MAC_KASUMI_F9                27
+#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2              28
+#define VIRTIO_CRYPTO_MAC_GMAC_AES                 41
+#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH             42
+#define VIRTIO_CRYPTO_MAC_CBCMAC_AES               49
+#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9         50
+#define VIRTIO_CRYPTO_MAC_XCBC_AES                 53
+    __virtio32 algo;
+    /* hash result length */
+    __virtio32 hash_result_len;
+    /* length of authenticated key */
+    __virtio32 auth_key_len;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_mac_session_output {
+    __virtio64 auth_key_addr; /* guest key phyical address */
+};
+
+struct virtio_crypto_mac_create_session_req {
+    struct virtio_crypto_mac_session_para para;
+    struct virtio_crypto_mac_session_output out;
+    struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_aead_session_para {
+#define VIRTIO_CRYPTO_NO_AEAD     0
+#define VIRTIO_CRYPTO_AEAD_GCM    1
+#define VIRTIO_CRYPTO_AEAD_CCM    2
+#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305  3
+    __virtio32 algo;
+    /* length of key */
+    __virtio32 key_len;
+    /* digest result length */
+    __virtio32 digest_result_len;
+    /* length of the additional authenticated data (AAD) in bytes */
+    __virtio32 aad_len;
+    /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */
+    __virtio32 op;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_aead_session_output {
+    __virtio64 key_addr; /* guest key phycial address */
+};
+
+struct virtio_crypto_aead_create_session_req {
+    struct virtio_crypto_aead_session_para para;
+    struct virtio_crypto_aead_session_output out;
+    struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_alg_chain_session_para {
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER  1
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH  2
+    __virtio32 alg_chain_order;
+/* Plain hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN    1
+/* Authenticated hash (mac) */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH     2
+/* Nested hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED   3
+    __virtio32 hash_mode;
+    struct virtio_crypto_cipher_session_para cipher_param;
+    union {
+        struct virtio_crypto_hash_session_para hash_param;
+        struct virtio_crypto_mac_session_para mac_param;
+    } u;
+    /* length of the additional authenticated data (AAD) in bytes */
+    __virtio32 aad_len;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_alg_chain_session_output {
+    struct virtio_crypto_cipher_session_output cipher;
+    struct virtio_crypto_mac_session_output mac;
+};
+
+struct virtio_crypto_alg_chain_session_req {
+    struct virtio_crypto_alg_chain_session_para para;
+    struct virtio_crypto_alg_chain_session_output out;
+    struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_sym_create_session_req {
+    union {
+        struct virtio_crypto_cipher_session_req cipher;
+        struct virtio_crypto_alg_chain_session_req chain;
+    } u;
+
+    // Device-readable part
+
+/* No operation */
+#define VIRTIO_CRYPTO_SYM_OP_NONE  0
+/* Cipher only operation on the data */
+#define VIRTIO_CRYPTO_SYM_OP_CIPHER  1
+/* Chain any cipher with any hash or mac operation. The order
+   depends on the value of alg_chain_order param */
+#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING  2
+    __virtio32 op_type;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_destroy_session_req {
+    // Device-readable part
+    __virtio64  session_id;
+    // Device-writable part
+    __virtio32  status;
+    __virtio32  padding;
+};
+
+/* The request of the control viritqueue's packet */
+struct virtio_crypto_op_ctrl_req {
+    struct virtio_crypto_ctrl_header header;
+
+    union {
+        struct virtio_crypto_sym_create_session_req   sym_create_session;
+        struct virtio_crypto_hash_create_session_req  hash_create_session;
+        struct virtio_crypto_mac_create_session_req   mac_create_session;
+        struct virtio_crypto_aead_create_session_req  aead_create_session;
+        struct virtio_crypto_destroy_session_req      destroy_session;
+    } u;
+};
+
+struct virtio_crypto_op_header {
+#define VIRTIO_CRYPTO_CIPHER_ENCRYPT \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x00)
+#define VIRTIO_CRYPTO_CIPHER_DECRYPT \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x01)
+#define VIRTIO_CRYPTO_HASH \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x00)
+#define VIRTIO_CRYPTO_MAC \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x00)
+#define VIRTIO_CRYPTO_AEAD_ENCRYPT \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00)
+#define VIRTIO_CRYPTO_AEAD_DECRYPT \
+    VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01)
+    __virtio32 opcode;
+    /* algo should be service-specific algorithms */
+    __virtio32 algo;
+    /* session_id should be service-specific algorithms */
+    __virtio64 session_id;
+    /* control flag to control the request */
+    __virtio32 flag;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_sym_input {
+    /* destination data guest address, it's useless for plain HASH and MAC */
+    __virtio64 dst_data_addr;
+    /* digest result guest address, it's useless for plain cipher algos */
+    __virtio64 digest_result_addr;
+
+    __virtio32 status;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_para {
+    __virtio32 iv_len;
+    /* length of source data */
+    __virtio32 src_data_len;
+    /* length of dst data */
+    __virtio32 dst_data_len;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_input {
+    struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_cipher_output {
+    __virtio64 iv_addr; /* iv guest address */
+    __virtio64 src_data_addr; /* source data guest address */
+};
+
+struct virtio_crypto_hash_input {
+    struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_hash_output {
+    /* source data guest address */
+    __virtio64 src_data_addr;
+    /* length of source data */
+    __virtio32 src_data_len;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_mac_input {
+    struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_mac_output {
+    struct virtio_crypto_hash_output hash_output;
+};
+
+struct virtio_crypto_aead_para {
+    __virtio32 iv_len;
+    /* length of additional auth data */
+    __virtio32 aad_len;
+    /* length of source data */
+    __virtio32 src_data_len;
+    /* length of dst data */
+    __virtio32 dst_data_len;
+};
+
+struct virtio_crypto_aead_input {
+    struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_aead_output {
+    __virtio64 iv_addr; /* iv guest address */
+    __virtio64 src_data_addr; /* source data guest address */
+    __virtio64 add_data_addr; /* additional auth data guest address */
+};
+
+struct virtio_crypto_cipher_data_req {
+    // Device-readable part
+    struct virtio_crypto_cipher_para para;
+    struct virtio_crypto_cipher_output odata;
+    // Device-writable part
+    struct virtio_crypto_cipher_input idata;
+};
+
+struct virtio_crypto_hash_data_req {
+    // Device-readable part
+    struct virtio_crypto_hash_output odata;
+    // Device-writable part
+    struct virtio_crypto_hash_input idata;
+};
+
+struct virtio_crypto_mac_data_req {
+    // Device-readable part
+    struct virtio_crypto_mac_output odata;
+    // Device-writable part
+    struct virtio_crypto_mac_input idata;
+};
+
+struct virtio_crypto_alg_chain_data_para {
+    struct virtio_crypto_cipher_para cipher;
+};
+
+struct virtio_crypto_alg_chain_data_output {
+    struct virtio_crypto_cipher_output cipher;
+
+    // Device-readable part
+    __virtio64 aad_data_addr; /* additional auth data guest address */
+    __virtio32 aad_len; /* length of additional auth data */
+    __virtio32 padding;
+};
+
+struct virtio_crypto_alg_chain_data_input {
+    struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_alg_chain_data_req {
+    // Device-readable part
+    struct virtio_crypto_alg_chain_data_para para;
+    struct virtio_crypto_alg_chain_data_output odata;
+    // Device-writable part
+    struct virtio_crypto_alg_chain_data_input idata;
+};
+
+struct virtio_crypto_sym_data_req {
+    union {
+        struct virtio_crypto_cipher_data_req cipher;
+        struct virtio_crypto_alg_chain_data_req chain;
+    } u;
+
+    // Device-readable part
+
+    /* See above VIRTIO_CRYPTO_SYM_OP_* */
+    __virtio32 op_type;
+    __virtio32 padding;
+};
+
+struct virtio_crypto_aead_data_req {
+    // Device-readable part
+    struct virtio_crypto_aead_para para;
+    struct virtio_crypto_aead_output odata;
+    // Device-writable part
+    struct virtio_crypto_aead_input idata;
+};
+
+/* The request of the data viritqueue's packet */
+struct virtio_crypto_op_data_req {
+    struct virtio_crypto_op_header header;
+
+    union {
+        struct virtio_crypto_sym_data_req  sym_req;
+        struct virtio_crypto_hash_data_req hash_req;
+        struct virtio_crypto_mac_data_req mac_req;
+        struct virtio_crypto_aead_data_req aead_req;
+    } u;
+};
+
+#define VIRTIO_CRYPTO_OP_OK        0
+#define VIRTIO_CRYPTO_OP_ERR       1
+#define VIRTIO_CRYPTO_OP_BADMSG    2
+#define VIRTIO_CRYPTO_OP_NOTSUPP   3
+#define VIRTIO_CRYPTO_OP_INVSESS   4 /* Invaild session id */
+
+/* The accelerator hardware is ready */
+#define VIRTIO_CRYPTO_S_HW_READY  (1 << 0)
+#define VIRTIO_CRYPTO_S_STARTED  (1 << 1)
+
+struct virtio_crypto_config {
+    /* See VIRTIO_CRYPTO_OP_* above */
+    __virtio32  status;
+
+    /*
+     * Maximum number of data queue legal values are between 1 and 0x8000
+     */
+    __virtio32  max_dataqueues;
+
+    /* Specifies the services mask which the devcie support,
+       see VIRTIO_CRYPTO_SERVICE_* above */
+    __virtio32 crypto_services;
+
+    /* Detailed algorithms mask */
+    __virtio32 cipher_algo_l;
+    __virtio32 cipher_algo_h;
+    __virtio32 hash_algo;
+    __virtio32 mac_algo_l;
+    __virtio32 mac_algo_h;
+    __virtio32 asym_algo;
+    __virtio32 kdf_algo;
+    __virtio32 aead_algo;
+    __virtio32 primitive_algo;
+};
+
+#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 1b411b6..0330964 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4603,6 +4603,20 @@ 
     '*vectors': 'uint32' } }
 
 ##
+# @CryptodevLinuxOptions
+#
+# Cryptodev-linux cryptodev backend. Cryptodev-linux is a device that
+# allows access to Linux kernel cryptographic drivers; thus allowing
+# of userspace applications to take advantage of hardware accelerators.
+#
+# @fd: #optional file descriptor of an already opened cryptodev chardev
+#
+# Since 2.7
+##
+{ 'struct': 'CryptodevLinuxOptions',
+  'data': {
+    '*fd':    'int' } }
+##
 # @CryptoClientOptions
 #
 # A discriminated record of crypto device traits.
@@ -4611,7 +4625,8 @@ 
 #
 ##
 { 'union': 'CryptoClientOptions',
-  'data': {'legacy-hw':   'CryptoLegacyHWOptions'} }
+  'data': {'legacy-hw':   'CryptoLegacyHWOptions',
+           'cryptodev-linux': 'CryptodevLinuxOptions'} }
 
 ##
 # @Cryptodev
diff --git a/qemu-options.hx b/qemu-options.hx
index a64ce25..0f7c662 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3969,9 +3969,25 @@  contents of @code{iv.b64} to the second secret
 ETEXI
 
 DEF("cryptodev", HAS_ARG, QEMU_OPTION_cryptodev,
-    "",
+    "-cryptodev cryptodev-linux,id=str[,fd=h]\n"
+    "           configure a cryptodev-linux cryptodev backend with ID 'str'\n"
+    "           use 'fd=h' to connect to an already opened '/dev/crypto' fd\n",
     QEMU_ARCH_ALL)
 
+STEXI
+@item -cryptodev cryptodev-linux,id=@var{id}[,fd=@var{h}]
+configure a cryptodev backend with ID @var{id}.
+
+Example:
+@example
+#launch a QEMU instance with one virtio-crypto device,
+#which connected a cryptodev-linux backend device.
+qemu-system-x86_64 linux.img -cryptodev cryptodev-linux,id=cryptodev0 \
+                  -device virtio-crypto-pci,cryptodev=cryptodev0
+
+@end example
+ETEXI
+
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
 @end table