aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-09-07 17:46:13 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-09-07 17:46:13 +0100
commitabf7aee72ea66944a62962603e4c2381f5e473e7 (patch)
treed1ac53b1c2fc78c6b77ad3fee67b9b433f91bd0e /hw
parentf9128631fbeb40a55f7bc145397981c963d40909 (diff)
parent30e398f796d882d829162a16ab7c920f7422da3b (diff)
downloadqemu-abf7aee72ea66944a62962603e4c2381f5e473e7.zip
qemu-abf7aee72ea66944a62962603e4c2381f5e473e7.tar.gz
qemu-abf7aee72ea66944a62962603e4c2381f5e473e7.tar.bz2
Merge remote-tracking branch 'remotes/thuth-gitlab/tags/s390x-pull-request-2021-09-07' into staging
* Some CSS related fixes * Storage key related fixes * Test SIGILL and SIGSEGV handling in usermode emulation * Fix SETPREFIX instruction * Replace PAGE_SIZE, PAGE_SHIFT and PAGE_MASK to fix Alpine compilation * Add more feature to gen16 default model # gpg: Signature made Tue 07 Sep 2021 14:07:38 BST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * remotes/thuth-gitlab/tags/s390x-pull-request-2021-09-07: s390x/cpumodel: Add more feature to gen16 default model s390x: Replace PAGE_SIZE, PAGE_SHIFT and PAGE_MASK hw/s390x/s390-skeys: lazy storage key enablement under TCG hw/s390x/s390-skeys: rename skeys_enabled to skeys_are_enabled hw/s390x/s390-skeys: check if an address is valid before dumping the key hw/s390x/s390-skeys: use memory mapping to detect which storage keys to dump hw/s390x/s390-skeys: use memory mapping to detect which storage keys to migrate s390x/mmu_helper: avoid setting the storage key if nothing changed s390x/mmu_helper: move address validation into mmu_translate*() s390x/mmu_helper: fixup mmu_translate() documentation s390x/mmu_helper: no need to pass access type to mmu_translate_asce() s390x/tcg: check for addressing exceptions for RRBE, SSKE and ISKE s390x/tcg: convert real to absolute address for RRBE, SSKE and ISKE s390x/tcg: fix ignoring bit 63 when setting the storage key in SSKE s390x/tcg: wrap address for RRBE s390x/ioinst: Fix wrong MSCH alignment check on little endian s390x/tcg: fix and optimize SPX (SET PREFIX) tests/tcg/s390x: Test SIGILL and SIGSEGV handling css: fix actl handling for unit exceptions vfio-ccw: forward halt/clear errors Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/s390x/css.c38
-rw-r--r--hw/s390x/s390-pci-bus.c10
-rw-r--r--hw/s390x/s390-pci-inst.c8
-rw-r--r--hw/s390x/s390-skeys-kvm.c4
-rw-r--r--hw/s390x/s390-skeys.c206
-rw-r--r--hw/s390x/s390-virtio-ccw.c5
-rw-r--r--hw/s390x/sclp.c2
-rw-r--r--hw/vfio/ccw.c4
8 files changed, 189 insertions, 88 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 133ddea..7d9523f 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -1206,23 +1206,53 @@ static void sch_handle_start_func_virtual(SubchDev *sch)
}
-static void sch_handle_halt_func_passthrough(SubchDev *sch)
+static IOInstEnding sch_handle_halt_func_passthrough(SubchDev *sch)
{
int ret;
ret = s390_ccw_halt(sch);
if (ret == -ENOSYS) {
sch_handle_halt_func(sch);
+ return IOINST_CC_EXPECTED;
+ }
+ /*
+ * Some conditions may have been detected prior to starting the halt
+ * function; map them to the correct cc.
+ * Note that we map both -ENODEV and -EACCES to cc 3 (there's not really
+ * anything else we can do.)
+ */
+ switch (ret) {
+ case -EBUSY:
+ return IOINST_CC_BUSY;
+ case -ENODEV:
+ case -EACCES:
+ return IOINST_CC_NOT_OPERATIONAL;
+ default:
+ return IOINST_CC_EXPECTED;
}
}
-static void sch_handle_clear_func_passthrough(SubchDev *sch)
+static IOInstEnding sch_handle_clear_func_passthrough(SubchDev *sch)
{
int ret;
ret = s390_ccw_clear(sch);
if (ret == -ENOSYS) {
sch_handle_clear_func(sch);
+ return IOINST_CC_EXPECTED;
+ }
+ /*
+ * Some conditions may have been detected prior to starting the clear
+ * function; map them to the correct cc.
+ * Note that we map both -ENODEV and -EACCES to cc 3 (there's not really
+ * anything else we can do.)
+ */
+ switch (ret) {
+ case -ENODEV:
+ case -EACCES:
+ return IOINST_CC_NOT_OPERATIONAL;
+ default:
+ return IOINST_CC_EXPECTED;
}
}
@@ -1265,9 +1295,9 @@ IOInstEnding do_subchannel_work_passthrough(SubchDev *sch)
SCHIB *schib = &sch->curr_status;
if (schib->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
- sch_handle_clear_func_passthrough(sch);
+ return sch_handle_clear_func_passthrough(sch);
} else if (schib->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
- sch_handle_halt_func_passthrough(sch);
+ return sch_handle_halt_func_passthrough(sch);
} else if (schib->scsw.ctrl & SCSW_FCTL_START_FUNC) {
return sch_handle_start_func_passthrough(sch);
}
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 7db1c59..6c0225c 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -330,7 +330,7 @@ static unsigned int calc_sx(dma_addr_t ptr)
static unsigned int calc_px(dma_addr_t ptr)
{
- return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK;
+ return ((unsigned long) ptr >> TARGET_PAGE_BITS) & ZPCI_PT_MASK;
}
static uint64_t get_rt_sto(uint64_t entry)
@@ -506,7 +506,7 @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr,
int8_t ett = 1;
uint16_t error = 0;
- entry->iova = addr & PAGE_MASK;
+ entry->iova = addr & TARGET_PAGE_MASK;
entry->translated_addr = 0;
entry->perm = IOMMU_RW;
@@ -526,7 +526,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
{
S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
S390IOTLBEntry *entry;
- uint64_t iova = addr & PAGE_MASK;
+ uint64_t iova = addr & TARGET_PAGE_MASK;
uint16_t error = 0;
IOMMUTLBEntry ret = {
.target_as = &address_space_memory,
@@ -562,7 +562,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
ret.perm = entry->perm;
} else {
ret.iova = iova;
- ret.addr_mask = ~PAGE_MASK;
+ ret.addr_mask = ~TARGET_PAGE_MASK;
ret.perm = IOMMU_NONE;
}
@@ -868,7 +868,7 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
- &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
+ &s390_msi_ctrl_ops, pbdev, name, TARGET_PAGE_SIZE);
memory_region_add_subregion(&pbdev->iommu->mr,
pbdev->pci_group->zpci_group.msia,
&pbdev->msix_notify_mr);
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 9ec277d..1c8ad91 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -613,7 +613,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
.iova = entry->iova,
.translated_addr = entry->translated_addr,
.perm = entry->perm,
- .addr_mask = ~PAGE_MASK,
+ .addr_mask = ~TARGET_PAGE_MASK,
},
};
@@ -640,7 +640,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
cache = g_new(S390IOTLBEntry, 1);
cache->iova = entry->iova;
cache->translated_addr = entry->translated_addr;
- cache->len = PAGE_SIZE;
+ cache->len = TARGET_PAGE_SIZE;
cache->perm = entry->perm;
g_hash_table_replace(iommu->iotlb, &cache->iova, cache);
dec_dma_avail(iommu);
@@ -725,8 +725,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
while (entry.iova < start && entry.iova < end &&
(dma_avail > 0 || entry.perm == IOMMU_NONE)) {
dma_avail = s390_pci_update_iotlb(iommu, &entry);
- entry.iova += PAGE_SIZE;
- entry.translated_addr += PAGE_SIZE;
+ entry.iova += TARGET_PAGE_SIZE;
+ entry.translated_addr += TARGET_PAGE_SIZE;
}
}
err:
diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c
index 1c4d805..3ff9d94 100644
--- a/hw/s390x/s390-skeys-kvm.c
+++ b/hw/s390x/s390-skeys-kvm.c
@@ -15,7 +15,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
-static int kvm_s390_skeys_enabled(S390SKeysState *ss)
+static bool kvm_s390_skeys_are_enabled(S390SKeysState *ss)
{
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
uint8_t single_key;
@@ -57,7 +57,7 @@ static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data)
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
- skeyclass->skeys_enabled = kvm_s390_skeys_enabled;
+ skeyclass->skeys_are_enabled = kvm_s390_skeys_are_enabled;
skeyclass->get_skeys = kvm_s390_skeys_get;
skeyclass->set_skeys = kvm_s390_skeys_set;
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 9a8d60d..5024faf 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -17,6 +17,8 @@
#include "qapi/qapi-commands-misc-target.h"
#include "qapi/qmp/qdict.h"
#include "qemu/error-report.h"
+#include "sysemu/memory_mapping.h"
+#include "exec/address-spaces.h"
#include "sysemu/kvm.h"
#include "migration/qemu-file-types.h"
#include "migration/register.h"
@@ -80,11 +82,18 @@ void hmp_info_skeys(Monitor *mon, const QDict *qdict)
int r;
/* Quick check to see if guest is using storage keys*/
- if (!skeyclass->skeys_enabled(ss)) {
+ if (!skeyclass->skeys_are_enabled(ss)) {
monitor_printf(mon, "Error: This guest is not using storage keys\n");
return;
}
+ if (!address_space_access_valid(&address_space_memory,
+ addr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE,
+ false, MEMTXATTRS_UNSPECIFIED)) {
+ monitor_printf(mon, "Error: The given address is not valid\n");
+ return;
+ }
+
r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
if (r < 0) {
monitor_printf(mon, "Error: %s\n", strerror(-r));
@@ -109,18 +118,17 @@ void qmp_dump_skeys(const char *filename, Error **errp)
{
S390SKeysState *ss = s390_get_skeys_device();
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- MachineState *ms = MACHINE(qdev_get_machine());
- const uint64_t total_count = ms->ram_size / TARGET_PAGE_SIZE;
- uint64_t handled_count = 0, cur_count;
+ GuestPhysBlockList guest_phys_blocks;
+ GuestPhysBlock *block;
+ uint64_t pages, gfn;
Error *lerr = NULL;
- vaddr cur_gfn = 0;
uint8_t *buf;
int ret;
int fd;
FILE *f;
/* Quick check to see if guest is using storage keys*/
- if (!skeyclass->skeys_enabled(ss)) {
+ if (!skeyclass->skeys_are_enabled(ss)) {
error_setg(errp, "This guest is not using storage keys - "
"nothing to dump");
return;
@@ -144,53 +152,86 @@ void qmp_dump_skeys(const char *filename, Error **errp)
goto out;
}
- /* we'll only dump initial memory for now */
- while (handled_count < total_count) {
- /* Calculate how many keys to ask for & handle overflow case */
- cur_count = MIN(total_count - handled_count, S390_SKEYS_BUFFER_SIZE);
+ assert(qemu_mutex_iothread_locked());
+ guest_phys_blocks_init(&guest_phys_blocks);
+ guest_phys_blocks_append(&guest_phys_blocks);
- ret = skeyclass->get_skeys(ss, cur_gfn, cur_count, buf);
- if (ret < 0) {
- error_setg(errp, "get_keys error %d", ret);
- goto out_free;
- }
+ QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
+ assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
+ assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
- /* write keys to stream */
- write_keys(f, buf, cur_gfn, cur_count, &lerr);
- if (lerr) {
- goto out_free;
- }
+ gfn = block->target_start / TARGET_PAGE_SIZE;
+ pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
+
+ while (pages) {
+ const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
- cur_gfn += cur_count;
- handled_count += cur_count;
+ ret = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "get_keys error");
+ goto out_free;
+ }
+
+ /* write keys to stream */
+ write_keys(f, buf, gfn, cur_pages, &lerr);
+ if (lerr) {
+ goto out_free;
+ }
+
+ gfn += cur_pages;
+ pages -= cur_pages;
+ }
}
out_free:
+ guest_phys_blocks_free(&guest_phys_blocks);
error_propagate(errp, lerr);
g_free(buf);
out:
fclose(f);
}
-static void qemu_s390_skeys_init(Object *obj)
+static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss)
{
- QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
- MachineState *machine = MACHINE(qdev_get_machine());
+ QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
- skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
- skeys->keydata = g_malloc0(skeys->key_count);
+ /* Lockless check is sufficient. */
+ return !!skeys->keydata;
}
-static int qemu_s390_skeys_enabled(S390SKeysState *ss)
+static bool qemu_s390_enable_skeys(S390SKeysState *ss)
{
- return 1;
+ QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
+ static gsize initialized;
+
+ if (likely(skeys->keydata)) {
+ return true;
+ }
+
+ /*
+ * TODO: Modern Linux doesn't use storage keys unless running KVM guests
+ * that use storage keys. Therefore, we keep it simple for now.
+ *
+ * 1) We should initialize to "referenced+changed" for an initial
+ * over-indication. Let's avoid touching megabytes of data for now and
+ * assume that any sane user will issue a storage key instruction before
+ * actually relying on this data.
+ * 2) Relying on ram_size and allocating a big array is ugly. We should
+ * allocate and manage storage key data per RAMBlock or optimally using
+ * some sparse data structure.
+ * 3) We only ever have a single S390SKeysState, so relying on
+ * g_once_init_enter() is good enough.
+ */
+ if (g_once_init_enter(&initialized)) {
+ MachineState *machine = MACHINE(qdev_get_machine());
+
+ skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
+ skeys->keydata = g_malloc0(skeys->key_count);
+ g_once_init_leave(&initialized, 1);
+ }
+ return false;
}
-/*
- * 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)
{
@@ -198,9 +239,10 @@ static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
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,
+ if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
+ start_gfn + count < count)) {
+ error_report("Error: Setting storage keys for pages with unallocated "
+ "storage key memory: gfn=%" PRIx64 " count=%" PRId64,
start_gfn, count);
return -EINVAL;
}
@@ -218,9 +260,10 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
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,
+ if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
+ start_gfn + count < count)) {
+ error_report("Error: Getting storage keys for pages with unallocated "
+ "storage key memory: gfn=%" PRIx64 " count=%" PRId64,
start_gfn, count);
return -EINVAL;
}
@@ -236,7 +279,8 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
- skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
+ skeyclass->skeys_are_enabled = qemu_s390_skeys_are_enabled;
+ skeyclass->enable_skeys = qemu_s390_enable_skeys;
skeyclass->get_skeys = qemu_s390_skeys_get;
skeyclass->set_skeys = qemu_s390_skeys_set;
@@ -247,7 +291,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
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,
.class_size = sizeof(S390SKeysClass),
@@ -257,14 +300,13 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
{
S390SKeysState *ss = S390_SKEYS(opaque);
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
- MachineState *ms = MACHINE(qdev_get_machine());
- uint64_t pages_left = ms->ram_size / TARGET_PAGE_SIZE;
- uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS;
- vaddr cur_gfn = 0;
+ GuestPhysBlockList guest_phys_blocks;
+ GuestPhysBlock *block;
+ uint64_t pages, gfn;
int error = 0;
uint8_t *buf;
- if (!skeyclass->skeys_enabled(ss)) {
+ if (!skeyclass->skeys_are_enabled(ss)) {
goto end_stream;
}
@@ -274,36 +316,52 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
goto end_stream;
}
- /* We only support initial memory. Standby memory is not handled yet. */
- qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS);
- qemu_put_be64(f, pages_left);
-
- while (pages_left) {
- read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE);
-
- if (!error) {
- error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf);
- if (error) {
- /*
- * If error: we want to fill the stream with valid data instead
- * of stopping early so we pad the stream with 0x00 values and
- * use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
- * reading side.
- */
- error_report("S390_GET_KEYS error %d", error);
- memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
- eos = S390_SKEYS_SAVE_FLAG_ERROR;
+ guest_phys_blocks_init(&guest_phys_blocks);
+ guest_phys_blocks_append(&guest_phys_blocks);
+
+ /* Send each contiguous physical memory range separately. */
+ QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
+ assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
+ assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
+
+ gfn = block->target_start / TARGET_PAGE_SIZE;
+ pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
+ qemu_put_be64(f, block->target_start | S390_SKEYS_SAVE_FLAG_SKEYS);
+ qemu_put_be64(f, pages);
+
+ while (pages) {
+ const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
+
+ if (!error) {
+ error = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
+ if (error) {
+ /*
+ * Create a valid stream with all 0x00 and indicate
+ * S390_SKEYS_SAVE_FLAG_ERROR to the destination.
+ */
+ error_report("S390_GET_KEYS error %d", error);
+ memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
+ }
}
+
+ qemu_put_buffer(f, buf, cur_pages);
+ gfn += cur_pages;
+ pages -= cur_pages;
}
- qemu_put_buffer(f, buf, read_count);
- cur_gfn += read_count;
- pages_left -= read_count;
+ if (error) {
+ break;
+ }
}
+ guest_phys_blocks_free(&guest_phys_blocks);
g_free(buf);
end_stream:
- qemu_put_be64(f, eos);
+ if (error) {
+ qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_ERROR);
+ } else {
+ qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_EOS);
+ }
}
static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
@@ -312,6 +370,14 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
int ret = 0;
+ /*
+ * Make sure to lazy-enable if required to be done explicitly. No need to
+ * flush any TLB as the VM is not running yet.
+ */
+ if (skeyclass->enable_skeys) {
+ skeyclass->enable_skeys(ss);
+ }
+
while (!ret) {
ram_addr_t addr;
int flags;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 4d25278..61aeccb 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -803,6 +803,11 @@ DEFINE_CCW_MACHINE(6_2, "6.2", true);
static void ccw_machine_6_1_instance_options(MachineState *machine)
{
ccw_machine_6_2_instance_options(machine);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_NNPA);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_BEAR_ENH);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_RDP);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_PAI);
}
static void ccw_machine_6_1_class_options(MachineClass *mc)
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index edb6e3e..89c30a8 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -51,7 +51,7 @@ static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len,
uint32_t code)
{
uint64_t sccb_max_addr = sccb_addr + sccb_len - 1;
- uint64_t sccb_boundary = (sccb_addr & PAGE_MASK) + PAGE_SIZE;
+ uint64_t sccb_boundary = (sccb_addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 000992f..0354737 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -199,7 +199,7 @@ again:
case 0:
case -ENODEV:
case -EACCES:
- return 0;
+ return ret;
case -EFAULT:
default:
sch_gen_unit_exception(sch);
@@ -240,7 +240,7 @@ again:
case -EBUSY:
case -ENODEV:
case -EACCES:
- return 0;
+ return ret;
case -EFAULT:
default:
sch_gen_unit_exception(sch);