qemu/hw/s390x/s390-stattrib-kvm.c
<<
>>
Prefs
   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)
 196