xref: /qemu/hw/s390x/s390-skeys.c (revision d2e9b78162e31b1eaf20f3a4f563da82da56908d)
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