diff options
author | Jason J. Herne <jjherne@linux.vnet.ibm.com> | 2015-06-26 11:54:51 -0400 |
---|---|---|
committer | Cornelia Huck <cornelia.huck@de.ibm.com> | 2015-09-03 12:17:54 +0200 |
commit | 0efe406cac8a4d9f0b52eada4c6c2a768fe4b7d2 (patch) | |
tree | 4f229ab4793b66ee1132d7a004c8b6b4d0987a89 /hw/s390x/s390-skeys.c | |
parent | 84b48ad63ba1da6345c3f22da7cdefc93fbc07f0 (diff) |
s390x: Create QOM device for s390 storage keys
A new QOM style device is provided to back guest storage keys. A special
version for KVM is created, which handles the storage key access via
KVM_S390_GET_SKEYS and KVM_S390_SET_SKEYS ioctl.
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'hw/s390x/s390-skeys.c')
-rw-r--r-- | hw/s390x/s390-skeys.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c new file mode 100644 index 0000000000..77c42ff3c8 --- /dev/null +++ b/hw/s390x/s390-skeys.c @@ -0,0 +1,141 @@ +/* + * s390 storage key device + * + * Copyright 2015 IBM Corp. + * Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "hw/boards.h" +#include "hw/s390x/storage-keys.h" +#include "qemu/error-report.h" + +S390SKeysState *s390_get_skeys_device(void) +{ + S390SKeysState *ss; + + ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL)); + assert(ss); + return ss; +} + +void s390_skeys_init(void) +{ + Object *obj; + + if (kvm_enabled()) { + obj = object_new(TYPE_KVM_S390_SKEYS); + } else { + obj = object_new(TYPE_QEMU_S390_SKEYS); + } + object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS, + obj, NULL); + object_unref(obj); + + qdev_init_nofail(DEVICE(obj)); +} + +static void qemu_s390_skeys_init(Object *obj) +{ + QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj); + MachineState *machine = MACHINE(qdev_get_machine()); + + skeys->key_count = machine->maxram_size / TARGET_PAGE_SIZE; + skeys->keydata = g_malloc0(skeys->key_count); +} + +static int qemu_s390_skeys_enabled(S390SKeysState *ss) +{ + return 1; +} + +/* + * TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get + * will have to make sure that the given gfn belongs to a memory region and not + * a memory hole. + */ +static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, + uint64_t count, uint8_t *keys) +{ + QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); + int i; + + /* Check for uint64 overflow and access beyond end of key data */ + if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { + error_report("Error: Setting storage keys for page beyond the end " + "of memory. gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn, + count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + skeydev->keydata[start_gfn + i] = keys[i]; + } + return 0; +} + +static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, + uint64_t count, uint8_t *keys) +{ + QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); + int i; + + /* Check for uint64 overflow and access beyond end of key data */ + if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { + error_report("Error: Getting storage keys for page beyond the end " + "of memory. gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn, + count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + keys[i] = skeydev->keydata[start_gfn + i]; + } + return 0; +} + +static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) +{ + S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); + + skeyclass->skeys_enabled = qemu_s390_skeys_enabled; + skeyclass->get_skeys = qemu_s390_skeys_get; + skeyclass->set_skeys = qemu_s390_skeys_set; +} + +static const TypeInfo qemu_s390_skeys_info = { + .name = TYPE_QEMU_S390_SKEYS, + .parent = TYPE_S390_SKEYS, + .instance_init = qemu_s390_skeys_init, + .instance_size = sizeof(QEMUS390SKeysState), + .class_init = qemu_s390_skeys_class_init, + .instance_size = sizeof(S390SKeysClass), +}; + +static void s390_skeys_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo s390_skeys_info = { + .name = TYPE_S390_SKEYS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(S390SKeysState), + .class_init = s390_skeys_class_init, + .class_size = sizeof(S390SKeysClass), + .abstract = true, +}; + +static void qemu_s390_skeys_register_types(void) +{ + type_register_static(&s390_skeys_info); + type_register_static(&qemu_s390_skeys_info); +} + +type_init(qemu_s390_skeys_register_types) |