master
c 401 lines 10.9 KB
Raw
1 /*
2 * s390 storage attributes device
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 "qemu/units.h"
14 #include "exec/target_page.h"
15 #include "system/ram_addr.h"
16 #include "migration/qemu-file.h"
17 #include "migration/register.h"
18 #include "monitor/hmp.h"
19 #include "monitor/monitor.h"
20 #include "hw/core/qdev-properties.h"
21 #include "hw/s390x/storage-attributes.h"
22 #include "qemu/error-report.h"
23 #include "qapi/error.h"
24 #include "qobject/qdict.h"
25 #include "target/s390x/cpu.h"
26
27 /* 512KiB cover 2GB of guest memory */
28 #define CMMA_BLOCK_SIZE (512 * KiB)
29
30 #define STATTR_FLAG_EOS 0x01ULL
31 #define STATTR_FLAG_MORE 0x02ULL
32 #define STATTR_FLAG_ERROR 0x04ULL
33 #define STATTR_FLAG_DONE 0x08ULL
34
35 #ifdef CONFIG_HMP
36 static S390StAttribState *s390_get_stattrib_device(void)
37 {
38 S390StAttribState *sas;
39
40 sas = S390_STATTRIB(object_resolve_path_type("", TYPE_S390_STATTRIB, NULL));
41 assert(sas);
42 return sas;
43 }
44 #endif
45
46 void s390_stattrib_init(void)
47 {
48 Object *obj;
49
50 obj = kvm_s390_stattrib_create();
51 if (!obj) {
52 obj = object_new(TYPE_QEMU_S390_STATTRIB);
53 }
54
55 object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB,
56 obj);
57 object_unref(obj);
58
59 qdev_realize(DEVICE(obj), NULL, &error_fatal);
60 }
61
62 /* Console commands: */
63
64 #ifdef CONFIG_HMP
65 void hmp_migrationmode(MonitorHMP *hmp, const QDict *qdict)
66 {
67 S390StAttribState *sas = s390_get_stattrib_device();
68 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
69 uint64_t what = qdict_get_int(qdict, "mode");
70 Error *local_err = NULL;
71 int r;
72
73 r = sac->set_migrationmode(sas, what, &local_err);
74 if (r < 0) {
75 monitor_hmp_printf(hmp, "Error: %s", error_get_pretty(local_err));
76 error_free(local_err);
77 }
78 }
79
80 void hmp_info_cmma(MonitorHMP *hmp, const QDict *qdict)
81 {
82 S390StAttribState *sas = s390_get_stattrib_device();
83 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
84 uint64_t addr = qdict_get_int(qdict, "addr");
85 uint64_t buflen = qdict_get_try_int(qdict, "count", 8);
86 uint8_t *vals;
87 int cx, len;
88
89 vals = g_try_malloc(buflen);
90 if (!vals) {
91 monitor_hmp_printf(hmp, "Error: %s\n", strerror(errno));
92 return;
93 }
94
95 len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals);
96 if (len < 0) {
97 monitor_hmp_printf(hmp, "Error: %s", strerror(-len));
98 goto out;
99 }
100
101 monitor_hmp_printf(hmp, " CMMA attributes, "
102 "pages %" PRIu64 "+%d (0x%" PRIx64 "):\n",
103 addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK);
104 for (cx = 0; cx < len; cx++) {
105 if (cx % 8 == 7) {
106 monitor_hmp_printf(hmp, "%02x\n", vals[cx]);
107 } else {
108 monitor_hmp_printf(hmp, "%02x", vals[cx]);
109 }
110 }
111 monitor_hmp_printf(hmp, "\n");
112
113 out:
114 g_free(vals);
115 }
116 #endif
117
118 /* Migration support: */
119
120 static int cmma_load(QEMUFile *f, void *opaque, int version_id)
121 {
122 S390StAttribState *sas = S390_STATTRIB(opaque);
123 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
124 uint64_t count, cur_gfn;
125 int flags, ret = 0;
126 ram_addr_t addr;
127 uint8_t *buf;
128
129 while (!ret) {
130 addr = qemu_get_be64(f);
131 flags = addr & ~TARGET_PAGE_MASK;
132 addr &= TARGET_PAGE_MASK;
133
134 switch (flags) {
135 case STATTR_FLAG_MORE: {
136 cur_gfn = addr / TARGET_PAGE_SIZE;
137 count = qemu_get_be64(f);
138 buf = g_try_malloc(count);
139 if (!buf) {
140 error_report("cmma_load could not allocate memory");
141 ret = -ENOMEM;
142 break;
143 }
144
145 qemu_get_buffer(f, buf, count);
146 ret = sac->set_stattr(sas, cur_gfn, count, buf);
147 if (ret < 0) {
148 error_report("Error %d while setting storage attributes", ret);
149 }
150 g_free(buf);
151 break;
152 }
153 case STATTR_FLAG_ERROR: {
154 error_report("Storage attributes data is incomplete");
155 ret = -EINVAL;
156 break;
157 }
158 case STATTR_FLAG_DONE:
159 /* This is after the last pre-copied value has been sent, nothing
160 * more will be sent after this. Pre-copy has finished, and we
161 * are done flushing all the remaining values. Now the target
162 * system is about to take over. We synchronize the buffer to
163 * apply the actual correct values where needed.
164 */
165 sac->synchronize(sas);
166 break;
167 case STATTR_FLAG_EOS:
168 /* Normal exit */
169 return 0;
170 default:
171 error_report("Unexpected storage attribute flag data: %#x", flags);
172 ret = -EINVAL;
173 }
174 }
175
176 return ret;
177 }
178
179 static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp)
180 {
181 S390StAttribState *sas = S390_STATTRIB(opaque);
182 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
183 int res;
184 /*
185 * Signal that we want to start a migration, thus needing PGSTE dirty
186 * tracking.
187 */
188 res = sac->set_migrationmode(sas, true, errp);
189 if (res) {
190 return res;
191 }
192 qemu_put_be64(f, STATTR_FLAG_EOS);
193 return 0;
194 }
195
196 static void cmma_state_pending(void *opaque, MigPendingData *pending,
197 bool exact, bool final)
198 {
199 S390StAttribState *sas = S390_STATTRIB(opaque);
200 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
201 long long res = sac->get_dirtycount(sas);
202
203 if (res >= 0) {
204 pending->precopy_bytes += res;
205 }
206 }
207
208 static int cmma_save(QEMUFile *f, void *opaque, int final)
209 {
210 S390StAttribState *sas = S390_STATTRIB(opaque);
211 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
212 uint8_t *buf;
213 int r, cx, reallen = 0, ret = 0;
214 uint32_t buflen = CMMA_BLOCK_SIZE;
215 uint64_t start_gfn = sas->migration_cur_gfn;
216
217 buf = g_try_malloc(buflen);
218 if (!buf) {
219 error_report("Could not allocate memory to save storage attributes");
220 return -ENOMEM;
221 }
222
223 while (final ? 1 : migration_rate_exceeded(f) == 0) {
224 reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
225 if (reallen < 0) {
226 g_free(buf);
227 return reallen;
228 }
229
230 ret = 1;
231 if (!reallen) {
232 break;
233 }
234 qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE);
235 qemu_put_be64(f, reallen);
236 for (cx = 0; cx < reallen; cx++) {
237 qemu_put_byte(f, buf[cx]);
238 }
239 if (!sac->get_dirtycount(sas)) {
240 break;
241 }
242 }
243
244 sas->migration_cur_gfn = start_gfn + reallen;
245 g_free(buf);
246 if (final) {
247 qemu_put_be64(f, STATTR_FLAG_DONE);
248 }
249 qemu_put_be64(f, STATTR_FLAG_EOS);
250
251 r = qemu_file_get_error(f);
252 if (r < 0) {
253 return r;
254 }
255
256 return ret;
257 }
258
259 static int cmma_save_iterate(QEMUFile *f, void *opaque)
260 {
261 return cmma_save(f, opaque, 0);
262 }
263
264 static int cmma_save_complete(QEMUFile *f, void *opaque)
265 {
266 return cmma_save(f, opaque, 1);
267 }
268
269 static void cmma_save_cleanup(void *opaque)
270 {
271 S390StAttribState *sas = S390_STATTRIB(opaque);
272 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
273 sac->set_migrationmode(sas, false, NULL);
274 }
275
276 static bool cmma_active(void *opaque)
277 {
278 S390StAttribState *sas = S390_STATTRIB(opaque);
279 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
280 return sac->get_active(sas);
281 }
282
283 /* QEMU object: */
284
285 static void qemu_s390_stattrib_instance_init(Object *obj)
286 {
287 }
288
289 static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn,
290 uint32_t count, uint8_t *values)
291 {
292 return 0;
293 }
294 static void qemu_s390_synchronize_stub(S390StAttribState *sa)
295 {
296 }
297 static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn,
298 uint32_t count, uint8_t *values)
299 {
300 return 0;
301 }
302 static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
303 {
304 return 0;
305 }
306 static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value,
307 Error **errp)
308 {
309 return 0;
310 }
311
312 static int qemu_s390_get_active(S390StAttribState *sa)
313 {
314 return true;
315 }
316
317 static void qemu_s390_stattrib_class_init(ObjectClass *oc, const void *data)
318 {
319 S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc);
320 DeviceClass *dc = DEVICE_CLASS(oc);
321
322 sa_cl->synchronize = qemu_s390_synchronize_stub;
323 sa_cl->get_stattr = qemu_s390_get_stattr_stub;
324 sa_cl->set_stattr = qemu_s390_peek_stattr_stub;
325 sa_cl->peek_stattr = qemu_s390_peek_stattr_stub;
326 sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub;
327 sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub;
328 sa_cl->get_active = qemu_s390_get_active;
329
330 /* Reason: Can only be instantiated one time (internally) */
331 dc->user_creatable = false;
332 }
333
334 static const TypeInfo qemu_s390_stattrib_info = {
335 .name = TYPE_QEMU_S390_STATTRIB,
336 .parent = TYPE_S390_STATTRIB,
337 .instance_init = qemu_s390_stattrib_instance_init,
338 .instance_size = sizeof(QEMUS390StAttribState),
339 .class_init = qemu_s390_stattrib_class_init,
340 .class_size = sizeof(S390StAttribClass),
341 };
342
343 /* Generic abstract object: */
344
345 static SaveVMHandlers savevm_s390_stattrib_handlers = {
346 .save_setup = cmma_save_setup,
347 .save_live_iterate = cmma_save_iterate,
348 .save_complete = cmma_save_complete,
349 .save_query_pending = cmma_state_pending,
350 .save_cleanup = cmma_save_cleanup,
351 .load_state = cmma_load,
352 .is_active = cmma_active,
353 };
354
355 static void s390_stattrib_realize(DeviceState *dev, Error **errp)
356 {
357 bool ambiguous = false;
358
359 object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous);
360 if (ambiguous) {
361 error_setg(errp, "storage_attributes device already exists");
362 return;
363 }
364
365 register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
366 &savevm_s390_stattrib_handlers, dev);
367 }
368
369 static void s390_stattrib_class_init(ObjectClass *oc, const void *data)
370 {
371 DeviceClass *dc = DEVICE_CLASS(oc);
372
373 dc->hotpluggable = false;
374 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
375 dc->realize = s390_stattrib_realize;
376 }
377
378 static void s390_stattrib_instance_init(Object *obj)
379 {
380 S390StAttribState *sas = S390_STATTRIB(obj);
381
382 sas->migration_cur_gfn = 0;
383 }
384
385 static const TypeInfo s390_stattrib_info = {
386 .name = TYPE_S390_STATTRIB,
387 .parent = TYPE_DEVICE,
388 .instance_init = s390_stattrib_instance_init,
389 .instance_size = sizeof(S390StAttribState),
390 .class_init = s390_stattrib_class_init,
391 .class_size = sizeof(S390StAttribClass),
392 .abstract = true,
393 };
394
395 static void s390_stattrib_register_types(void)
396 {
397 type_register_static(&s390_stattrib_info);
398 type_register_static(&qemu_s390_stattrib_info);
399 }
400
401 type_init(s390_stattrib_register_types)