xref: /openbmc/qemu/hw/s390x/s390-stattrib-kvm.c (revision 0b1183e3)
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 
21 Object *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 
30 static void kvm_s390_stattrib_instance_init(Object *obj)
31 {
32     KVMS390StAttribState *sas = KVM_S390_STATTRIB(obj);
33 
34     sas->still_dirty = 0;
35 }
36 
37 static 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 
63 static 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 
71 static 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 
80 static 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 
102 static 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 
139 static 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 
149 static 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 
158 static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
159 {
160     return kvm_s390_cmma_active() && sa->migration_enabled;
161 }
162 
163 static 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 
176 static 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 
185 static void kvm_s390_stattrib_register_types(void)
186 {
187     type_register_static(&kvm_s390_stattrib_info);
188 }
189 
190 type_init(kvm_s390_stattrib_register_types)
191