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