cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cryptodev-vhost-user.c (10718B)


      1/*
      2 * QEMU Cryptodev backend for QEMU cipher APIs
      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 "qapi/error.h"
     26#include "qapi/qmp/qerror.h"
     27#include "qemu/error-report.h"
     28#include "hw/virtio/vhost-user.h"
     29#include "standard-headers/linux/virtio_crypto.h"
     30#include "sysemu/cryptodev-vhost.h"
     31#include "chardev/char-fe.h"
     32#include "sysemu/cryptodev-vhost-user.h"
     33#include "qom/object.h"
     34
     35
     36/**
     37 * @TYPE_CRYPTODEV_BACKEND_VHOST_USER:
     38 * name of backend that uses vhost user server
     39 */
     40#define TYPE_CRYPTODEV_BACKEND_VHOST_USER "cryptodev-vhost-user"
     41
     42OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendVhostUser, CRYPTODEV_BACKEND_VHOST_USER)
     43
     44
     45struct CryptoDevBackendVhostUser {
     46    CryptoDevBackend parent_obj;
     47
     48    VhostUserState vhost_user;
     49    CharBackend chr;
     50    char *chr_name;
     51    bool opened;
     52    CryptoDevBackendVhost *vhost_crypto[MAX_CRYPTO_QUEUE_NUM];
     53};
     54
     55static int
     56cryptodev_vhost_user_running(
     57             CryptoDevBackendVhost *crypto)
     58{
     59    return crypto ? 1 : 0;
     60}
     61
     62CryptoDevBackendVhost *
     63cryptodev_vhost_user_get_vhost(
     64                         CryptoDevBackendClient *cc,
     65                         CryptoDevBackend *b,
     66                         uint16_t queue)
     67{
     68    CryptoDevBackendVhostUser *s =
     69                      CRYPTODEV_BACKEND_VHOST_USER(b);
     70    assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
     71    assert(queue < MAX_CRYPTO_QUEUE_NUM);
     72
     73    return s->vhost_crypto[queue];
     74}
     75
     76static void cryptodev_vhost_user_stop(int queues,
     77                          CryptoDevBackendVhostUser *s)
     78{
     79    size_t i;
     80
     81    for (i = 0; i < queues; i++) {
     82        if (!cryptodev_vhost_user_running(s->vhost_crypto[i])) {
     83            continue;
     84        }
     85
     86        cryptodev_vhost_cleanup(s->vhost_crypto[i]);
     87        s->vhost_crypto[i] = NULL;
     88    }
     89}
     90
     91static int
     92cryptodev_vhost_user_start(int queues,
     93                         CryptoDevBackendVhostUser *s)
     94{
     95    CryptoDevBackendVhostOptions options;
     96    CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
     97    int max_queues;
     98    size_t i;
     99
    100    for (i = 0; i < queues; i++) {
    101        if (cryptodev_vhost_user_running(s->vhost_crypto[i])) {
    102            continue;
    103        }
    104
    105        options.opaque = &s->vhost_user;
    106        options.backend_type = VHOST_BACKEND_TYPE_USER;
    107        options.cc = b->conf.peers.ccs[i];
    108        s->vhost_crypto[i] = cryptodev_vhost_init(&options);
    109        if (!s->vhost_crypto[i]) {
    110            error_report("failed to init vhost_crypto for queue %zu", i);
    111            goto err;
    112        }
    113
    114        if (i == 0) {
    115            max_queues =
    116              cryptodev_vhost_get_max_queues(s->vhost_crypto[i]);
    117            if (queues > max_queues) {
    118                error_report("you are asking more queues than supported: %d",
    119                             max_queues);
    120                goto err;
    121            }
    122        }
    123    }
    124
    125    return 0;
    126
    127err:
    128    cryptodev_vhost_user_stop(i + 1, s);
    129    return -1;
    130}
    131
    132static Chardev *
    133cryptodev_vhost_claim_chardev(CryptoDevBackendVhostUser *s,
    134                                    Error **errp)
    135{
    136    Chardev *chr;
    137
    138    if (s->chr_name == NULL) {
    139        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
    140                   "chardev", "a valid character device");
    141        return NULL;
    142    }
    143
    144    chr = qemu_chr_find(s->chr_name);
    145    if (chr == NULL) {
    146        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
    147                  "Device '%s' not found", s->chr_name);
    148        return NULL;
    149    }
    150
    151    return chr;
    152}
    153
    154static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
    155{
    156    CryptoDevBackendVhostUser *s = opaque;
    157    CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
    158    int queues = b->conf.peers.queues;
    159
    160    assert(queues < MAX_CRYPTO_QUEUE_NUM);
    161
    162    switch (event) {
    163    case CHR_EVENT_OPENED:
    164        if (cryptodev_vhost_user_start(queues, s) < 0) {
    165            exit(1);
    166        }
    167        b->ready = true;
    168        break;
    169    case CHR_EVENT_CLOSED:
    170        b->ready = false;
    171        cryptodev_vhost_user_stop(queues, s);
    172        break;
    173    case CHR_EVENT_BREAK:
    174    case CHR_EVENT_MUX_IN:
    175    case CHR_EVENT_MUX_OUT:
    176        /* Ignore */
    177        break;
    178    }
    179}
    180
    181static void cryptodev_vhost_user_init(
    182             CryptoDevBackend *backend, Error **errp)
    183{
    184    int queues = backend->conf.peers.queues;
    185    size_t i;
    186    Error *local_err = NULL;
    187    Chardev *chr;
    188    CryptoDevBackendClient *cc;
    189    CryptoDevBackendVhostUser *s =
    190                      CRYPTODEV_BACKEND_VHOST_USER(backend);
    191
    192    chr = cryptodev_vhost_claim_chardev(s, &local_err);
    193    if (local_err) {
    194        error_propagate(errp, local_err);
    195        return;
    196    }
    197
    198    s->opened = true;
    199
    200    for (i = 0; i < queues; i++) {
    201        cc = cryptodev_backend_new_client(
    202                  "cryptodev-vhost-user", NULL);
    203        cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
    204                                       i, chr->label);
    205        cc->queue_index = i;
    206        cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
    207
    208        backend->conf.peers.ccs[i] = cc;
    209
    210        if (i == 0) {
    211            if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
    212                return;
    213            }
    214        }
    215    }
    216
    217    if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) {
    218        return;
    219    }
    220
    221    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
    222                     cryptodev_vhost_user_event, NULL, s, NULL, true);
    223
    224    backend->conf.crypto_services =
    225                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
    226                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
    227                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
    228    backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
    229    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
    230
    231    backend->conf.max_size = UINT64_MAX;
    232    backend->conf.max_cipher_key_len = VHOST_USER_MAX_CIPHER_KEY_LEN;
    233    backend->conf.max_auth_key_len = VHOST_USER_MAX_AUTH_KEY_LEN;
    234}
    235
    236static int64_t cryptodev_vhost_user_sym_create_session(
    237           CryptoDevBackend *backend,
    238           CryptoDevBackendSymSessionInfo *sess_info,
    239           uint32_t queue_index, Error **errp)
    240{
    241    CryptoDevBackendClient *cc =
    242                   backend->conf.peers.ccs[queue_index];
    243    CryptoDevBackendVhost *vhost_crypto;
    244    uint64_t session_id = 0;
    245    int ret;
    246
    247    vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
    248    if (vhost_crypto) {
    249        struct vhost_dev *dev = &(vhost_crypto->dev);
    250        ret = dev->vhost_ops->vhost_crypto_create_session(dev,
    251                                                          sess_info,
    252                                                          &session_id);
    253        if (ret < 0) {
    254            return -1;
    255        } else {
    256            return session_id;
    257        }
    258    }
    259    return -1;
    260}
    261
    262static int cryptodev_vhost_user_sym_close_session(
    263           CryptoDevBackend *backend,
    264           uint64_t session_id,
    265           uint32_t queue_index, Error **errp)
    266{
    267    CryptoDevBackendClient *cc =
    268                  backend->conf.peers.ccs[queue_index];
    269    CryptoDevBackendVhost *vhost_crypto;
    270    int ret;
    271
    272    vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
    273    if (vhost_crypto) {
    274        struct vhost_dev *dev = &(vhost_crypto->dev);
    275        ret = dev->vhost_ops->vhost_crypto_close_session(dev,
    276                                                         session_id);
    277        if (ret < 0) {
    278            return -1;
    279        } else {
    280            return 0;
    281        }
    282    }
    283    return -1;
    284}
    285
    286static void cryptodev_vhost_user_cleanup(
    287             CryptoDevBackend *backend,
    288             Error **errp)
    289{
    290    CryptoDevBackendVhostUser *s =
    291                      CRYPTODEV_BACKEND_VHOST_USER(backend);
    292    size_t i;
    293    int queues = backend->conf.peers.queues;
    294    CryptoDevBackendClient *cc;
    295
    296    cryptodev_vhost_user_stop(queues, s);
    297
    298    for (i = 0; i < queues; i++) {
    299        cc = backend->conf.peers.ccs[i];
    300        if (cc) {
    301            cryptodev_backend_free_client(cc);
    302            backend->conf.peers.ccs[i] = NULL;
    303        }
    304    }
    305
    306    vhost_user_cleanup(&s->vhost_user);
    307}
    308
    309static void cryptodev_vhost_user_set_chardev(Object *obj,
    310                                    const char *value, Error **errp)
    311{
    312    CryptoDevBackendVhostUser *s =
    313                      CRYPTODEV_BACKEND_VHOST_USER(obj);
    314
    315    if (s->opened) {
    316        error_setg(errp, QERR_PERMISSION_DENIED);
    317    } else {
    318        g_free(s->chr_name);
    319        s->chr_name = g_strdup(value);
    320    }
    321}
    322
    323static char *
    324cryptodev_vhost_user_get_chardev(Object *obj, Error **errp)
    325{
    326    CryptoDevBackendVhostUser *s =
    327                      CRYPTODEV_BACKEND_VHOST_USER(obj);
    328    Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
    329
    330    if (chr && chr->label) {
    331        return g_strdup(chr->label);
    332    }
    333
    334    return NULL;
    335}
    336
    337static void cryptodev_vhost_user_finalize(Object *obj)
    338{
    339    CryptoDevBackendVhostUser *s =
    340                      CRYPTODEV_BACKEND_VHOST_USER(obj);
    341
    342    qemu_chr_fe_deinit(&s->chr, false);
    343
    344    g_free(s->chr_name);
    345}
    346
    347static void
    348cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
    349{
    350    CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
    351
    352    bc->init = cryptodev_vhost_user_init;
    353    bc->cleanup = cryptodev_vhost_user_cleanup;
    354    bc->create_session = cryptodev_vhost_user_sym_create_session;
    355    bc->close_session = cryptodev_vhost_user_sym_close_session;
    356    bc->do_sym_op = NULL;
    357
    358    object_class_property_add_str(oc, "chardev",
    359                                  cryptodev_vhost_user_get_chardev,
    360                                  cryptodev_vhost_user_set_chardev);
    361
    362}
    363
    364static const TypeInfo cryptodev_vhost_user_info = {
    365    .name = TYPE_CRYPTODEV_BACKEND_VHOST_USER,
    366    .parent = TYPE_CRYPTODEV_BACKEND,
    367    .class_init = cryptodev_vhost_user_class_init,
    368    .instance_finalize = cryptodev_vhost_user_finalize,
    369    .instance_size = sizeof(CryptoDevBackendVhostUser),
    370};
    371
    372static void
    373cryptodev_vhost_user_register_types(void)
    374{
    375    type_register_static(&cryptodev_vhost_user_info);
    376}
    377
    378type_init(cryptodev_vhost_user_register_types);