xref: /openbmc/qemu/hw/s390x/s390-stattrib-kvm.c (revision b91a0fa7)
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 
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->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 
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->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 
140 static 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 
150 static 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 
159 static int kvm_s390_stattrib_get_active(S390StAttribState *sa)
160 {
161     return kvm_s390_cmma_active() && sa->migration_enabled;
162 }
163 
164 static 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 
181 static 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 
190 static void kvm_s390_stattrib_register_types(void)
191 {
192     type_register_static(&kvm_s390_stattrib_info);
193 }
194 
195 type_init(kvm_s390_stattrib_register_types)
196