1 /*
2 * s390 storage key device
3 *
4 * Copyright 2015 IBM Corp.
5 * Author(s): Jason J. Herne <jjherne@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 "hw/s390x/s390-virtio-ccw.h"
16 #include "hw/qdev-properties.h"
17 #include "hw/s390x/storage-keys.h"
18 #include "qapi/error.h"
19 #include "qapi/qapi-commands-machine.h"
20 #include "qobject/qdict.h"
21 #include "qemu/error-report.h"
22 #include "system/memory_mapping.h"
23 #include "system/address-spaces.h"
24 #include "system/kvm.h"
25 #include "migration/qemu-file-types.h"
26 #include "migration/register.h"
27 #include "trace.h"
28
29 #define S390_SKEYS_BUFFER_SIZE (128 * KiB) /* Room for 128k storage keys */
30 #define S390_SKEYS_SAVE_FLAG_EOS 0x01
31 #define S390_SKEYS_SAVE_FLAG_SKEYS 0x02
32 #define S390_SKEYS_SAVE_FLAG_ERROR 0x04
33
s390_get_skeys_device(void)34 S390SKeysState *s390_get_skeys_device(void)
35 {
36 S390SKeysState *ss;
37
38 ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL));
39 assert(ss);
40 return ss;
41 }
42
s390_skeys_init(void)43 void s390_skeys_init(void)
44 {
45 Object *obj;
46
47 if (kvm_enabled()) {
48 obj = object_new(TYPE_KVM_S390_SKEYS);
49 } else {
50 obj = object_new(TYPE_QEMU_S390_SKEYS);
51 }
52 object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS,
53 obj);
54 object_unref(obj);
55
56 qdev_realize(DEVICE(obj), NULL, &error_fatal);
57 }
58
s390_skeys_get(S390SKeysState * ks,uint64_t start_gfn,uint64_t count,uint8_t * keys)59 int s390_skeys_get(S390SKeysState *ks, uint64_t start_gfn,
60 uint64_t count, uint8_t *keys)
61 {
62 S390SKeysClass *kc = S390_SKEYS_GET_CLASS(ks);
63 int rc;
64
65 rc = kc->get_skeys(ks, start_gfn, count, keys);
66 if (rc) {
67 trace_s390_skeys_get_nonzero(rc);
68 }
69 return rc;
70 }
71
s390_skeys_set(S390SKeysState * ks,uint64_t start_gfn,uint64_t count,uint8_t * keys)72 int s390_skeys_set(S390SKeysState *ks, uint64_t start_gfn,
73 uint64_t count, uint8_t *keys)
74 {
75 S390SKeysClass *kc = S390_SKEYS_GET_CLASS(ks);
76 int rc;
77
78 rc = kc->set_skeys(ks, start_gfn, count, keys);
79 if (rc) {
80 trace_s390_skeys_set_nonzero(rc);
81 }
82 return rc;
83 }
84
write_keys(FILE * f,uint8_t * keys,uint64_t startgfn,uint64_t count,Error ** errp)85 static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn,
86 uint64_t count, Error **errp)
87 {
88 uint64_t curpage = startgfn;
89 uint64_t maxpage = curpage + count - 1;
90
91 for (; curpage <= maxpage; curpage++) {
92 uint8_t acc = (*keys & 0xF0) >> 4;
93 int fp = (*keys & 0x08);
94 int ref = (*keys & 0x04);
95 int ch = (*keys & 0x02);
96 int res = (*keys & 0x01);
97
98 fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
99 " ch=%d, reserved=%d\n",
100 curpage, *keys, acc, fp, ref, ch, res);
101 keys++;
102 }
103 }
104
hmp_info_skeys(Monitor * mon,const QDict * qdict)105 void hmp_info_skeys(Monitor *mon, const QDict *qdict)
106 {
107 S390SKeysState *ss = s390_get_skeys_device();
108 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
109 uint64_t addr = qdict_get_int(qdict, "addr");
110 uint8_t key;
111 int r;
112
113 /* Quick check to see if guest is using storage keys*/
114 if (!skeyclass->skeys_are_enabled(ss)) {
115 monitor_printf(mon, "Error: This guest is not using storage keys\n");
116 return;
117 }
118
119 if (!address_space_access_valid(&address_space_memory,
120 addr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE,
121 false, MEMTXATTRS_UNSPECIFIED)) {
122 monitor_printf(mon, "Error: The given address is not valid\n");
123 return;
124 }
125
126 r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
127 if (r < 0) {
128 monitor_printf(mon, "Error: %s\n", strerror(-r));
129 return;
130 }
131
132 monitor_printf(mon, " key: 0x%X\n", key);
133 }
134
hmp_dump_skeys(Monitor * mon,const QDict * qdict)135 void hmp_dump_skeys(Monitor *mon, const QDict *qdict)
136 {
137 const char *filename = qdict_get_str(qdict, "filename");
138 Error *err = NULL;
139
140 qmp_dump_skeys(filename, &err);
141 if (err) {
142 error_report_err(err);
143 }
144 }
145
s390_qmp_dump_skeys(const char * filename,Error ** errp)146 void s390_qmp_dump_skeys(const char *filename, Error **errp)
147 {
148 S390SKeysState *ss = s390_get_skeys_device();
149 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
150 GuestPhysBlockList guest_phys_blocks;
151 GuestPhysBlock *block;
152 uint64_t pages, gfn;
153 Error *lerr = NULL;
154 uint8_t *buf;
155 int ret;
156 int fd;
157 FILE *f;
158
159 /* Quick check to see if guest is using storage keys*/
160 if (!skeyclass->skeys_are_enabled(ss)) {
161 error_setg(errp, "This guest is not using storage keys - "
162 "nothing to dump");
163 return;
164 }
165
166 fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
167 if (fd < 0) {
168 error_setg_file_open(errp, errno, filename);
169 return;
170 }
171 f = fdopen(fd, "wb");
172 if (!f) {
173 close(fd);
174 error_setg_file_open(errp, errno, filename);
175 return;
176 }
177
178 buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
179 if (!buf) {
180 error_setg(errp, "Could not allocate memory");
181 goto out;
182 }
183
184 assert(bql_locked());
185 guest_phys_blocks_init(&guest_phys_blocks);
186 guest_phys_blocks_append(&guest_phys_blocks);
187
188 QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
189 assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
190 assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
191
192 gfn = block->target_start / TARGET_PAGE_SIZE;
193 pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
194
195 while (pages) {
196 const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
197
198 ret = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
199 if (ret < 0) {
200 error_setg_errno(errp, -ret, "get_keys error");
201 goto out_free;
202 }
203
204 /* write keys to stream */
205 write_keys(f, buf, gfn, cur_pages, &lerr);
206 if (lerr) {
207 goto out_free;
208 }
209
210 gfn += cur_pages;
211 pages -= cur_pages;
212 }
213 }
214
215 out_free:
216 guest_phys_blocks_free(&guest_phys_blocks);
217 error_propagate(errp, lerr);
218 g_free(buf);
219 out:
220 fclose(f);
221 }
222
qemu_s390_skeys_are_enabled(S390SKeysState * ss)223 static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss)
224 {
225 QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
226
227 /* Lockless check is sufficient. */
228 return !!skeys->keydata;
229 }
230
qemu_s390_enable_skeys(S390SKeysState * ss)231 static bool qemu_s390_enable_skeys(S390SKeysState *ss)
232 {
233 QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
234 static gsize initialized;
235
236 if (likely(skeys->keydata)) {
237 return true;
238 }
239
240 /*
241 * TODO: Modern Linux doesn't use storage keys unless running KVM guests
242 * that use storage keys. Therefore, we keep it simple for now.
243 *
244 * 1) We should initialize to "referenced+changed" for an initial
245 * over-indication. Let's avoid touching megabytes of data for now and
246 * assume that any sane user will issue a storage key instruction before
247 * actually relying on this data.
248 * 2) Relying on ram_size and allocating a big array is ugly. We should
249 * allocate and manage storage key data per RAMBlock or optimally using
250 * some sparse data structure.
251 * 3) We only ever have a single S390SKeysState, so relying on
252 * g_once_init_enter() is good enough.
253 */
254 if (g_once_init_enter(&initialized)) {
255 S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
256
257 skeys->key_count = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
258 skeys->keydata = g_malloc0(skeys->key_count);
259 g_once_init_leave(&initialized, 1);
260 }
261 return false;
262 }
263
qemu_s390_skeys_set(S390SKeysState * ss,uint64_t start_gfn,uint64_t count,uint8_t * keys)264 static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
265 uint64_t count, uint8_t *keys)
266 {
267 QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
268 int i;
269
270 /* Check for uint64 overflow and access beyond end of key data */
271 if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
272 start_gfn + count < count)) {
273 error_report("Error: Setting storage keys for pages with unallocated "
274 "storage key memory: gfn=%" PRIx64 " count=%" PRId64,
275 start_gfn, count);
276 return -EINVAL;
277 }
278
279 for (i = 0; i < count; i++) {
280 skeydev->keydata[start_gfn + i] = keys[i];
281 }
282 return 0;
283 }
284
qemu_s390_skeys_get(S390SKeysState * ss,uint64_t start_gfn,uint64_t count,uint8_t * keys)285 static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
286 uint64_t count, uint8_t *keys)
287 {
288 QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
289 int i;
290
291 /* Check for uint64 overflow and access beyond end of key data */
292 if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
293 start_gfn + count < count)) {
294 error_report("Error: Getting storage keys for pages with unallocated "
295 "storage key memory: gfn=%" PRIx64 " count=%" PRId64,
296 start_gfn, count);
297 return -EINVAL;
298 }
299
300 for (i = 0; i < count; i++) {
301 keys[i] = skeydev->keydata[start_gfn + i];
302 }
303 return 0;
304 }
305
qemu_s390_skeys_class_init(ObjectClass * oc,const void * data)306 static void qemu_s390_skeys_class_init(ObjectClass *oc, const void *data)
307 {
308 S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
309 DeviceClass *dc = DEVICE_CLASS(oc);
310
311 skeyclass->skeys_are_enabled = qemu_s390_skeys_are_enabled;
312 skeyclass->enable_skeys = qemu_s390_enable_skeys;
313 skeyclass->get_skeys = qemu_s390_skeys_get;
314 skeyclass->set_skeys = qemu_s390_skeys_set;
315
316 /* Reason: Internal device (only one skeys device for the whole memory) */
317 dc->user_creatable = false;
318 }
319
s390_storage_keys_save(QEMUFile * f,void * opaque)320 static void s390_storage_keys_save(QEMUFile *f, void *opaque)
321 {
322 S390SKeysState *ss = S390_SKEYS(opaque);
323 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
324 GuestPhysBlockList guest_phys_blocks;
325 GuestPhysBlock *block;
326 uint64_t pages, gfn;
327 int error = 0;
328 uint8_t *buf;
329
330 if (!skeyclass->skeys_are_enabled(ss)) {
331 goto end_stream;
332 }
333
334 buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
335 if (!buf) {
336 error_report("storage key save could not allocate memory");
337 goto end_stream;
338 }
339
340 guest_phys_blocks_init(&guest_phys_blocks);
341 guest_phys_blocks_append(&guest_phys_blocks);
342
343 /* Send each contiguous physical memory range separately. */
344 QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
345 assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
346 assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
347
348 gfn = block->target_start / TARGET_PAGE_SIZE;
349 pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
350 qemu_put_be64(f, block->target_start | S390_SKEYS_SAVE_FLAG_SKEYS);
351 qemu_put_be64(f, pages);
352
353 while (pages) {
354 const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
355
356 if (!error) {
357 error = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
358 if (error) {
359 /*
360 * Create a valid stream with all 0x00 and indicate
361 * S390_SKEYS_SAVE_FLAG_ERROR to the destination.
362 */
363 error_report("S390_GET_KEYS error %d", error);
364 memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
365 }
366 }
367
368 qemu_put_buffer(f, buf, cur_pages);
369 gfn += cur_pages;
370 pages -= cur_pages;
371 }
372
373 if (error) {
374 break;
375 }
376 }
377
378 guest_phys_blocks_free(&guest_phys_blocks);
379 g_free(buf);
380 end_stream:
381 if (error) {
382 qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_ERROR);
383 } else {
384 qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_EOS);
385 }
386 }
387
s390_storage_keys_load(QEMUFile * f,void * opaque,int version_id)388 static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
389 {
390 S390SKeysState *ss = S390_SKEYS(opaque);
391 S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
392 int ret = 0;
393
394 /*
395 * Make sure to lazy-enable if required to be done explicitly. No need to
396 * flush any TLB as the VM is not running yet.
397 */
398 if (skeyclass->enable_skeys) {
399 skeyclass->enable_skeys(ss);
400 }
401
402 while (!ret) {
403 ram_addr_t addr;
404 int flags;
405
406 addr = qemu_get_be64(f);
407 flags = addr & ~TARGET_PAGE_MASK;
408 addr &= TARGET_PAGE_MASK;
409
410 switch (flags) {
411 case S390_SKEYS_SAVE_FLAG_SKEYS: {
412 const uint64_t total_count = qemu_get_be64(f);
413 uint64_t handled_count = 0, cur_count;
414 uint64_t cur_gfn = addr / TARGET_PAGE_SIZE;
415 uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
416
417 if (!buf) {
418 error_report("storage key load could not allocate memory");
419 ret = -ENOMEM;
420 break;
421 }
422
423 while (handled_count < total_count) {
424 cur_count = MIN(total_count - handled_count,
425 S390_SKEYS_BUFFER_SIZE);
426 qemu_get_buffer(f, buf, cur_count);
427
428 ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf);
429 if (ret < 0) {
430 error_report("S390_SET_KEYS error %d", ret);
431 break;
432 }
433 handled_count += cur_count;
434 cur_gfn += cur_count;
435 }
436 g_free(buf);
437 break;
438 }
439 case S390_SKEYS_SAVE_FLAG_ERROR: {
440 error_report("Storage key data is incomplete");
441 ret = -EINVAL;
442 break;
443 }
444 case S390_SKEYS_SAVE_FLAG_EOS:
445 /* normal exit */
446 return 0;
447 default:
448 error_report("Unexpected storage key flag data: %#x", flags);
449 ret = -EINVAL;
450 }
451 }
452
453 return ret;
454 }
455
456 static SaveVMHandlers savevm_s390_storage_keys = {
457 .save_state = s390_storage_keys_save,
458 .load_state = s390_storage_keys_load,
459 };
460
s390_skeys_realize(DeviceState * dev,Error ** errp)461 static void s390_skeys_realize(DeviceState *dev, Error **errp)
462 {
463 S390SKeysState *ss = S390_SKEYS(dev);
464
465 register_savevm_live(TYPE_S390_SKEYS, 0, 1, &savevm_s390_storage_keys, ss);
466 }
467
s390_skeys_class_init(ObjectClass * oc,const void * data)468 static void s390_skeys_class_init(ObjectClass *oc, const void *data)
469 {
470 DeviceClass *dc = DEVICE_CLASS(oc);
471
472 dc->hotpluggable = false;
473 dc->realize = s390_skeys_realize;
474 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
475 }
476
477 static const TypeInfo s390_skeys_types[] = {
478 {
479 .name = TYPE_DUMP_SKEYS_INTERFACE,
480 .parent = TYPE_INTERFACE,
481 .class_size = sizeof(DumpSKeysInterface),
482 },
483 {
484 .name = TYPE_S390_SKEYS,
485 .parent = TYPE_DEVICE,
486 .instance_size = sizeof(S390SKeysState),
487 .class_init = s390_skeys_class_init,
488 .class_size = sizeof(S390SKeysClass),
489 .abstract = true,
490 },
491 {
492 .name = TYPE_QEMU_S390_SKEYS,
493 .parent = TYPE_S390_SKEYS,
494 .instance_size = sizeof(QEMUS390SKeysState),
495 .class_init = qemu_s390_skeys_class_init,
496 .class_size = sizeof(S390SKeysClass),
497 },
498 };
499
500 DEFINE_TYPES(s390_skeys_types)
501