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

s390-stattrib-kvm.c (6245B)


      1/*
      2 * s390 storage attributes device -- KVM object
      3 *
      4 * Copyright 2016 IBM Corp.
      5 * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
      6 *
      7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
      8 * your option) any later version. See the COPYING file in the top-level
      9 * directory.
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "hw/boards.h"
     14#include "migration/qemu-file.h"
     15#include "hw/s390x/storage-attributes.h"
     16#include "qemu/error-report.h"
     17#include "sysemu/kvm.h"
     18#include "exec/ram_addr.h"
     19#include "kvm/kvm_s390x.h"
     20
     21Object *kvm_s390_stattrib_create(void)
     22{
     23    if (kvm_enabled() &&
     24                kvm_check_extension(kvm_state, KVM_CAP_S390_CMMA_MIGRATION)) {
     25        return object_new(TYPE_KVM_S390_STATTRIB);
     26    }
     27    return NULL;
     28}
     29
     30static void kvm_s390_stattrib_instance_init(Object *obj)
     31{
     32    KVMS390StAttribState *sas = KVM_S390_STATTRIB(obj);
     33
     34    sas->still_dirty = 0;
     35}
     36
     37static int kvm_s390_stattrib_read_helper(S390StAttribState *sa,
     38                                         uint64_t *start_gfn,
     39                                         uint32_t count,
     40                                         uint8_t *values,
     41                                         uint32_t flags)
     42{
     43    KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
     44    int r;
     45    struct kvm_s390_cmma_log clog = {
     46        .values = (uint64_t)values,
     47        .start_gfn = *start_gfn,
     48        .count = count,
     49        .flags = flags,
     50    };
     51
     52    r = kvm_vm_ioctl(kvm_state, KVM_S390_GET_CMMA_BITS, &clog);
     53    if (r < 0) {
     54        error_report("KVM_S390_GET_CMMA_BITS failed: %s", strerror(-r));
     55        return r;
     56    }
     57
     58    *start_gfn = clog.start_gfn;
     59    sas->still_dirty = clog.remaining;
     60    return clog.count;
     61}
     62
     63static int kvm_s390_stattrib_get_stattr(S390StAttribState *sa,
     64                                        uint64_t *start_gfn,
     65                                        uint32_t count,
     66                                        uint8_t *values)
     67{
     68    return kvm_s390_stattrib_read_helper(sa, start_gfn, count, values, 0);
     69}
     70
     71static int kvm_s390_stattrib_peek_stattr(S390StAttribState *sa,
     72                                         uint64_t start_gfn,
     73                                         uint32_t count,
     74                                         uint8_t *values)
     75{
     76    return kvm_s390_stattrib_read_helper(sa, &start_gfn, count, values,
     77                                         KVM_S390_CMMA_PEEK);
     78}
     79
     80static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
     81                                        uint64_t start_gfn,
     82                                        uint32_t count,
     83                                        uint8_t *values)
     84{
     85    KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
     86    MachineState *machine = MACHINE(qdev_get_machine());
     87    unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
     88
     89    if (start_gfn + count > max) {
     90        error_report("Out of memory bounds when setting storage attributes");
     91        return -1;
     92    }
     93    if (!sas->incoming_buffer) {
     94        sas->incoming_buffer = g_malloc0(max);
     95    }
     96
     97    memcpy(sas->incoming_buffer + start_gfn, values, count);
     98
     99    return 0;
    100}
    101
    102static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
    103{
    104    KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
    105    MachineState *machine = MACHINE(qdev_get_machine());
    106    unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
    107    /* We do not need to reach the maximum buffer size allowed */
    108    unsigned long cx, len = KVM_S390_SKEYS_MAX / 2;
    109    int r;
    110    struct kvm_s390_cmma_log clog = {
    111        .flags = 0,
    112        .mask = ~0ULL,
    113    };
    114
    115    if (sas->incoming_buffer) {
    116        for (cx = 0; cx + len <= max; cx += len) {
    117            clog.start_gfn = cx;
    118            clog.count = len;
    119            clog.values = (uint64_t)(sas->incoming_buffer + cx);
    120            r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
    121            if (r) {
    122                error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
    123                return;
    124            }
    125        }
    126        if (cx < max) {
    127            clog.start_gfn = cx;
    128            clog.count = max - cx;
    129            clog.values = (uint64_t)(sas->incoming_buffer + cx);
    130            r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
    131            if (r) {
    132                error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
    133            }
    134        }
    135        g_free(sas->incoming_buffer);
    136        sas->incoming_buffer = NULL;
    137    }
    138}
    139
    140static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
    141{
    142    struct kvm_device_attr attr = {
    143        .group = KVM_S390_VM_MIGRATION,
    144        .attr = val,
    145        .addr = 0,
    146    };
    147    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
    148}
    149
    150static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
    151{
    152    KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
    153    uint8_t val[8];
    154
    155    kvm_s390_stattrib_peek_stattr(sa, 0, 1, val);
    156    return sas->still_dirty;
    157}
    158
    159static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
    160{
    161    return kvm_s390_cmma_active() && sa->migration_enabled;
    162}
    163
    164static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data)
    165{
    166    S390StAttribClass *sac = S390_STATTRIB_CLASS(oc);
    167    DeviceClass *dc = DEVICE_CLASS(oc);
    168
    169    sac->get_stattr = kvm_s390_stattrib_get_stattr;
    170    sac->peek_stattr = kvm_s390_stattrib_peek_stattr;
    171    sac->set_stattr = kvm_s390_stattrib_set_stattr;
    172    sac->set_migrationmode = kvm_s390_stattrib_set_migrationmode;
    173    sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount;
    174    sac->synchronize = kvm_s390_stattrib_synchronize;
    175    sac->get_active = kvm_s390_stattrib_get_active;
    176
    177    /* Reason: Can only be instantiated one time (internally) */
    178    dc->user_creatable = false;
    179}
    180
    181static const TypeInfo kvm_s390_stattrib_info = {
    182    .name          = TYPE_KVM_S390_STATTRIB,
    183    .parent        = TYPE_S390_STATTRIB,
    184    .instance_init = kvm_s390_stattrib_instance_init,
    185    .instance_size = sizeof(KVMS390StAttribState),
    186    .class_init    = kvm_s390_stattrib_class_init,
    187    .class_size    = sizeof(S390StAttribClass),
    188};
    189
    190static void kvm_s390_stattrib_register_types(void)
    191{
    192    type_register_static(&kvm_s390_stattrib_info);
    193}
    194
    195type_init(kvm_s390_stattrib_register_types)