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/s390x/s390-virtio-ccw.h" 14 #include "migration/qemu-file.h" 15 #include "hw/s390x/storage-attributes.h" 16 #include "qemu/error-report.h" 17 #include "system/kvm.h" 18 #include "system/memory_mapping.h" 19 #include "exec/ram_addr.h" 20 #include "kvm/kvm_s390x.h" 21 #include "qapi/error.h" 22 23 Object *kvm_s390_stattrib_create(void) 24 { 25 if (kvm_enabled() && 26 kvm_check_extension(kvm_state, KVM_CAP_S390_CMMA_MIGRATION)) { 27 return object_new(TYPE_KVM_S390_STATTRIB); 28 } 29 return NULL; 30 } 31 32 static void kvm_s390_stattrib_instance_init(Object *obj) 33 { 34 KVMS390StAttribState *sas = KVM_S390_STATTRIB(obj); 35 36 sas->still_dirty = 0; 37 } 38 39 static int kvm_s390_stattrib_read_helper(S390StAttribState *sa, 40 uint64_t *start_gfn, 41 uint32_t count, 42 uint8_t *values, 43 uint32_t flags) 44 { 45 KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); 46 int r; 47 struct kvm_s390_cmma_log clog = { 48 .values = (uint64_t)values, 49 .start_gfn = *start_gfn, 50 .count = count, 51 .flags = flags, 52 }; 53 54 r = kvm_vm_ioctl(kvm_state, KVM_S390_GET_CMMA_BITS, &clog); 55 if (r < 0) { 56 error_report("KVM_S390_GET_CMMA_BITS failed: %s", strerror(-r)); 57 return r; 58 } 59 60 *start_gfn = clog.start_gfn; 61 sas->still_dirty = clog.remaining; 62 return clog.count; 63 } 64 65 static int kvm_s390_stattrib_get_stattr(S390StAttribState *sa, 66 uint64_t *start_gfn, 67 uint32_t count, 68 uint8_t *values) 69 { 70 return kvm_s390_stattrib_read_helper(sa, start_gfn, count, values, 0); 71 } 72 73 static int kvm_s390_stattrib_peek_stattr(S390StAttribState *sa, 74 uint64_t start_gfn, 75 uint32_t count, 76 uint8_t *values) 77 { 78 return kvm_s390_stattrib_read_helper(sa, &start_gfn, count, values, 79 KVM_S390_CMMA_PEEK); 80 } 81 82 static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa, 83 uint64_t start_gfn, 84 uint32_t count, 85 uint8_t *values) 86 { 87 KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); 88 S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); 89 unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE; 90 91 if (start_gfn + count > max) { 92 error_report("Out of memory bounds when setting storage attributes"); 93 return -1; 94 } 95 if (!sas->incoming_buffer) { 96 sas->incoming_buffer = g_malloc0(max); 97 } 98 99 memcpy(sas->incoming_buffer + start_gfn, values, count); 100 101 return 0; 102 } 103 104 static void kvm_s390_stattrib_synchronize(S390StAttribState *sa) 105 { 106 KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); 107 S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine()); 108 unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE; 109 unsigned long start_gfn, end_gfn, pages; 110 GuestPhysBlockList guest_phys_blocks; 111 GuestPhysBlock *block; 112 int r; 113 struct kvm_s390_cmma_log clog = { 114 .flags = 0, 115 .mask = ~0ULL, 116 }; 117 118 if (!sas->incoming_buffer) { 119 return; 120 } 121 guest_phys_blocks_init(&guest_phys_blocks); 122 guest_phys_blocks_append(&guest_phys_blocks); 123 124 QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { 125 assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE)); 126 assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE)); 127 128 start_gfn = block->target_start / TARGET_PAGE_SIZE; 129 end_gfn = block->target_end / TARGET_PAGE_SIZE; 130 131 while (start_gfn < end_gfn) { 132 /* Don't exceed the maximum buffer size. */ 133 pages = MIN(end_gfn - start_gfn, KVM_S390_SKEYS_MAX / 2); 134 135 /* 136 * If we ever get guest physical memory beyond the configured 137 * memory limit, something went very wrong. 138 */ 139 assert(start_gfn + pages <= max); 140 141 clog.start_gfn = start_gfn; 142 clog.count = pages; 143 clog.values = (uint64_t)(sas->incoming_buffer + start_gfn); 144 r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog); 145 if (r) { 146 error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r)); 147 goto out; 148 } 149 150 start_gfn += pages; 151 } 152 } 153 154 out: 155 guest_phys_blocks_free(&guest_phys_blocks); 156 g_free(sas->incoming_buffer); 157 sas->incoming_buffer = NULL; 158 } 159 160 static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val, 161 Error **errp) 162 { 163 struct kvm_device_attr attr = { 164 .group = KVM_S390_VM_MIGRATION, 165 .attr = val, 166 .addr = 0, 167 }; 168 int r; 169 170 r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); 171 if (r) { 172 error_setg_errno(errp, -r, "setting KVM_S390_VM_MIGRATION failed"); 173 } 174 return r; 175 } 176 177 static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa) 178 { 179 KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa); 180 uint8_t val[8]; 181 182 kvm_s390_stattrib_peek_stattr(sa, 0, 1, val); 183 return sas->still_dirty; 184 } 185 186 static int kvm_s390_stattrib_get_active(S390StAttribState *sa) 187 { 188 return kvm_s390_cmma_active() && sa->migration_enabled; 189 } 190 191 static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) 192 { 193 S390StAttribClass *sac = S390_STATTRIB_CLASS(oc); 194 DeviceClass *dc = DEVICE_CLASS(oc); 195 196 sac->get_stattr = kvm_s390_stattrib_get_stattr; 197 sac->peek_stattr = kvm_s390_stattrib_peek_stattr; 198 sac->set_stattr = kvm_s390_stattrib_set_stattr; 199 sac->set_migrationmode = kvm_s390_stattrib_set_migrationmode; 200 sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount; 201 sac->synchronize = kvm_s390_stattrib_synchronize; 202 sac->get_active = kvm_s390_stattrib_get_active; 203 204 /* Reason: Can only be instantiated one time (internally) */ 205 dc->user_creatable = false; 206 } 207 208 static const TypeInfo kvm_s390_stattrib_info = { 209 .name = TYPE_KVM_S390_STATTRIB, 210 .parent = TYPE_S390_STATTRIB, 211 .instance_init = kvm_s390_stattrib_instance_init, 212 .instance_size = sizeof(KVMS390StAttribState), 213 .class_init = kvm_s390_stattrib_class_init, 214 .class_size = sizeof(S390StAttribClass), 215 }; 216 217 static void kvm_s390_stattrib_register_types(void) 218 { 219 type_register_static(&kvm_s390_stattrib_info); 220 } 221 222 type_init(kvm_s390_stattrib_register_types) 223