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

null.c (9405B)


      1/*
      2 * Null block driver
      3 *
      4 * Authors:
      5 *  Fam Zheng <famz@redhat.com>
      6 *
      7 * Copyright (C) 2014 Red Hat, Inc.
      8 *
      9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10 * See the COPYING file in the top-level directory.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qapi/error.h"
     15#include "qapi/qmp/qdict.h"
     16#include "qapi/qmp/qstring.h"
     17#include "qemu/module.h"
     18#include "qemu/option.h"
     19#include "block/block_int.h"
     20#include "sysemu/replay.h"
     21
     22#define NULL_OPT_LATENCY "latency-ns"
     23#define NULL_OPT_ZEROES  "read-zeroes"
     24
     25typedef struct {
     26    int64_t length;
     27    int64_t latency_ns;
     28    bool read_zeroes;
     29} BDRVNullState;
     30
     31static QemuOptsList runtime_opts = {
     32    .name = "null",
     33    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
     34    .desc = {
     35        {
     36            .name = BLOCK_OPT_SIZE,
     37            .type = QEMU_OPT_SIZE,
     38            .help = "size of the null block",
     39        },
     40        {
     41            .name = NULL_OPT_LATENCY,
     42            .type = QEMU_OPT_NUMBER,
     43            .help = "nanoseconds (approximated) to wait "
     44                    "before completing request",
     45        },
     46        {
     47            .name = NULL_OPT_ZEROES,
     48            .type = QEMU_OPT_BOOL,
     49            .help = "return zeroes when read",
     50        },
     51        { /* end of list */ }
     52    },
     53};
     54
     55static void null_co_parse_filename(const char *filename, QDict *options,
     56                                   Error **errp)
     57{
     58    /* This functions only exists so that a null-co:// filename is accepted
     59     * with the null-co driver. */
     60    if (strcmp(filename, "null-co://")) {
     61        error_setg(errp, "The only allowed filename for this driver is "
     62                         "'null-co://'");
     63        return;
     64    }
     65}
     66
     67static void null_aio_parse_filename(const char *filename, QDict *options,
     68                                    Error **errp)
     69{
     70    /* This functions only exists so that a null-aio:// filename is accepted
     71     * with the null-aio driver. */
     72    if (strcmp(filename, "null-aio://")) {
     73        error_setg(errp, "The only allowed filename for this driver is "
     74                         "'null-aio://'");
     75        return;
     76    }
     77}
     78
     79static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
     80                          Error **errp)
     81{
     82    QemuOpts *opts;
     83    BDRVNullState *s = bs->opaque;
     84    int ret = 0;
     85
     86    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     87    qemu_opts_absorb_qdict(opts, options, &error_abort);
     88    s->length =
     89        qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
     90    s->latency_ns =
     91        qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
     92    if (s->latency_ns < 0) {
     93        error_setg(errp, "latency-ns is invalid");
     94        ret = -EINVAL;
     95    }
     96    s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
     97    qemu_opts_del(opts);
     98    bs->supported_write_flags = BDRV_REQ_FUA;
     99    return ret;
    100}
    101
    102static int64_t null_getlength(BlockDriverState *bs)
    103{
    104    BDRVNullState *s = bs->opaque;
    105    return s->length;
    106}
    107
    108static coroutine_fn int null_co_common(BlockDriverState *bs)
    109{
    110    BDRVNullState *s = bs->opaque;
    111
    112    if (s->latency_ns) {
    113        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
    114    }
    115    return 0;
    116}
    117
    118static coroutine_fn int null_co_preadv(BlockDriverState *bs,
    119                                       int64_t offset, int64_t bytes,
    120                                       QEMUIOVector *qiov,
    121                                       BdrvRequestFlags flags)
    122{
    123    BDRVNullState *s = bs->opaque;
    124
    125    if (s->read_zeroes) {
    126        qemu_iovec_memset(qiov, 0, 0, bytes);
    127    }
    128
    129    return null_co_common(bs);
    130}
    131
    132static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
    133                                        int64_t offset, int64_t bytes,
    134                                        QEMUIOVector *qiov,
    135                                        BdrvRequestFlags flags)
    136{
    137    return null_co_common(bs);
    138}
    139
    140static coroutine_fn int null_co_flush(BlockDriverState *bs)
    141{
    142    return null_co_common(bs);
    143}
    144
    145typedef struct {
    146    BlockAIOCB common;
    147    QEMUTimer timer;
    148} NullAIOCB;
    149
    150static const AIOCBInfo null_aiocb_info = {
    151    .aiocb_size = sizeof(NullAIOCB),
    152};
    153
    154static void null_bh_cb(void *opaque)
    155{
    156    NullAIOCB *acb = opaque;
    157    acb->common.cb(acb->common.opaque, 0);
    158    qemu_aio_unref(acb);
    159}
    160
    161static void null_timer_cb(void *opaque)
    162{
    163    NullAIOCB *acb = opaque;
    164    acb->common.cb(acb->common.opaque, 0);
    165    timer_deinit(&acb->timer);
    166    qemu_aio_unref(acb);
    167}
    168
    169static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
    170                                          BlockCompletionFunc *cb,
    171                                          void *opaque)
    172{
    173    NullAIOCB *acb;
    174    BDRVNullState *s = bs->opaque;
    175
    176    acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
    177    /* Only emulate latency after vcpu is running. */
    178    if (s->latency_ns) {
    179        aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
    180                       QEMU_CLOCK_REALTIME, SCALE_NS,
    181                       null_timer_cb, acb);
    182        timer_mod_ns(&acb->timer,
    183                     qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
    184    } else {
    185        replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
    186                                         null_bh_cb, acb);
    187    }
    188    return &acb->common;
    189}
    190
    191static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
    192                                   int64_t offset, int64_t bytes,
    193                                   QEMUIOVector *qiov, BdrvRequestFlags flags,
    194                                   BlockCompletionFunc *cb,
    195                                   void *opaque)
    196{
    197    BDRVNullState *s = bs->opaque;
    198
    199    if (s->read_zeroes) {
    200        qemu_iovec_memset(qiov, 0, 0, bytes);
    201    }
    202
    203    return null_aio_common(bs, cb, opaque);
    204}
    205
    206static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
    207                                    int64_t offset, int64_t bytes,
    208                                    QEMUIOVector *qiov, BdrvRequestFlags flags,
    209                                    BlockCompletionFunc *cb,
    210                                    void *opaque)
    211{
    212    return null_aio_common(bs, cb, opaque);
    213}
    214
    215static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
    216                                  BlockCompletionFunc *cb,
    217                                  void *opaque)
    218{
    219    return null_aio_common(bs, cb, opaque);
    220}
    221
    222static int null_reopen_prepare(BDRVReopenState *reopen_state,
    223                               BlockReopenQueue *queue, Error **errp)
    224{
    225    return 0;
    226}
    227
    228static int coroutine_fn null_co_block_status(BlockDriverState *bs,
    229                                             bool want_zero, int64_t offset,
    230                                             int64_t bytes, int64_t *pnum,
    231                                             int64_t *map,
    232                                             BlockDriverState **file)
    233{
    234    BDRVNullState *s = bs->opaque;
    235    int ret = BDRV_BLOCK_OFFSET_VALID;
    236
    237    *pnum = bytes;
    238    *map = offset;
    239    *file = bs;
    240
    241    if (s->read_zeroes) {
    242        ret |= BDRV_BLOCK_ZERO;
    243    }
    244    return ret;
    245}
    246
    247static void null_refresh_filename(BlockDriverState *bs)
    248{
    249    const QDictEntry *e;
    250
    251    for (e = qdict_first(bs->full_open_options); e;
    252         e = qdict_next(bs->full_open_options, e))
    253    {
    254        /* These options can be ignored */
    255        if (strcmp(qdict_entry_key(e), "filename") &&
    256            strcmp(qdict_entry_key(e), "driver") &&
    257            strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
    258        {
    259            return;
    260        }
    261    }
    262
    263    snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
    264             bs->drv->format_name);
    265}
    266
    267static int64_t null_allocated_file_size(BlockDriverState *bs)
    268{
    269    return 0;
    270}
    271
    272static const char *const null_strong_runtime_opts[] = {
    273    BLOCK_OPT_SIZE,
    274    NULL_OPT_ZEROES,
    275
    276    NULL
    277};
    278
    279static BlockDriver bdrv_null_co = {
    280    .format_name            = "null-co",
    281    .protocol_name          = "null-co",
    282    .instance_size          = sizeof(BDRVNullState),
    283
    284    .bdrv_file_open         = null_file_open,
    285    .bdrv_parse_filename    = null_co_parse_filename,
    286    .bdrv_getlength         = null_getlength,
    287    .bdrv_get_allocated_file_size = null_allocated_file_size,
    288
    289    .bdrv_co_preadv         = null_co_preadv,
    290    .bdrv_co_pwritev        = null_co_pwritev,
    291    .bdrv_co_flush_to_disk  = null_co_flush,
    292    .bdrv_reopen_prepare    = null_reopen_prepare,
    293
    294    .bdrv_co_block_status   = null_co_block_status,
    295
    296    .bdrv_refresh_filename  = null_refresh_filename,
    297    .strong_runtime_opts    = null_strong_runtime_opts,
    298};
    299
    300static BlockDriver bdrv_null_aio = {
    301    .format_name            = "null-aio",
    302    .protocol_name          = "null-aio",
    303    .instance_size          = sizeof(BDRVNullState),
    304
    305    .bdrv_file_open         = null_file_open,
    306    .bdrv_parse_filename    = null_aio_parse_filename,
    307    .bdrv_getlength         = null_getlength,
    308    .bdrv_get_allocated_file_size = null_allocated_file_size,
    309
    310    .bdrv_aio_preadv        = null_aio_preadv,
    311    .bdrv_aio_pwritev       = null_aio_pwritev,
    312    .bdrv_aio_flush         = null_aio_flush,
    313    .bdrv_reopen_prepare    = null_reopen_prepare,
    314
    315    .bdrv_co_block_status   = null_co_block_status,
    316
    317    .bdrv_refresh_filename  = null_refresh_filename,
    318    .strong_runtime_opts    = null_strong_runtime_opts,
    319};
    320
    321static void bdrv_null_init(void)
    322{
    323    bdrv_register(&bdrv_null_co);
    324    bdrv_register(&bdrv_null_aio);
    325}
    326
    327block_init(bdrv_null_init);