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 "cpu.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->maxram_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->maxram_size / TARGET_PAGE_SIZE;
 107    unsigned long cx, len = 1 << 19;
 108    int r;
 109    struct kvm_s390_cmma_log clog = {
 110        .flags = 0,
 111        .mask = ~0ULL,
 112    };
 113
 114    if (sas->incoming_buffer) {
 115        for (cx = 0; cx + len <= max; cx += len) {
 116            clog.start_gfn = cx;
 117            clog.count = len;
 118            clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
 119            r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
 120            if (r) {
 121                error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
 122                return;
 123            }
 124        }
 125        if (cx < max) {
 126            clog.start_gfn = cx;
 127            clog.count = max - cx;
 128            clog.values = (uint64_t)(sas->incoming_buffer + cx * len);
 129            r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
 130            if (r) {
 131                error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
 132            }
 133        }
 134        g_free(sas->incoming_buffer);
 135        sas->incoming_buffer = NULL;
 136    }
 137}
 138
 139static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
 140{
 141    struct kvm_device_attr attr = {
 142        .group = KVM_S390_VM_MIGRATION,
 143        .attr = val,
 144        .addr = 0,
 145    };
 146    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
 147}
 148
 149static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
 150{
 151    KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
 152    uint8_t val[8];
 153
 154    kvm_s390_stattrib_peek_stattr(sa, 0, 1, val);
 155    return sas->still_dirty;
 156}
 157
 158static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
 159{
 160    return kvm_s390_cmma_active() && sa->migration_enabled;
 161}
 162
 163static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data)
 164{
 165    S390StAttribClass *sac = S390_STATTRIB_CLASS(oc);
 166
 167    sac->get_stattr = kvm_s390_stattrib_get_stattr;
 168    sac->peek_stattr = kvm_s390_stattrib_peek_stattr;
 169    sac->set_stattr = kvm_s390_stattrib_set_stattr;
 170    sac->set_migrationmode = kvm_s390_stattrib_set_migrationmode;
 171    sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount;
 172    sac->synchronize = kvm_s390_stattrib_synchronize;
 173    sac->get_active = kvm_s390_stattrib_get_active;
 174}
 175
 176static const TypeInfo kvm_s390_stattrib_info = {
 177    .name          = TYPE_KVM_S390_STATTRIB,
 178    .parent        = TYPE_S390_STATTRIB,
 179    .instance_init = kvm_s390_stattrib_instance_init,
 180    .instance_size = sizeof(KVMS390StAttribState),
 181    .class_init    = kvm_s390_stattrib_class_init,
 182    .class_size    = sizeof(S390StAttribClass),
 183};
 184
 185static void kvm_s390_stattrib_register_types(void)
 186{
 187    type_register_static(&kvm_s390_stattrib_info);
 188}
 189
 190type_init(kvm_s390_stattrib_register_types)
 191