summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/net/e1000.c103
-rw-r--r--hw/s390x/ipl.c112
-rw-r--r--hw/vfio/ccw.c2
-rw-r--r--include/hw/compat.h4
-rw-r--r--linux-user/syscall.c27
-rw-r--r--pc-bios/s390-ccw.imgbin30568 -> 30520 bytes
-rw-r--r--pc-bios/s390-ccw/bootmap.c7
-rw-r--r--pc-bios/s390-ccw/iplb.h15
-rw-r--r--pc-bios/s390-netboot.imgbin83776 -> 83856 bytes
-rw-r--r--target/s390x/helper.c10
-rw-r--r--target/s390x/kvm.c2
-rw-r--r--target/s390x/mmu_helper.c2
12 files changed, 220 insertions, 64 deletions
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index c7f1695f57..13a9494a8d 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -123,10 +123,15 @@ typedef struct E1000State_st {
#define E1000_FLAG_AUTONEG_BIT 0
#define E1000_FLAG_MIT_BIT 1
#define E1000_FLAG_MAC_BIT 2
+#define E1000_FLAG_TSO_BIT 3
#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT)
#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
+#define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT)
uint32_t compat_flags;
+ bool received_tx_tso;
+ bool use_tso_for_migration;
+ e1000x_txd_props mig_props;
} E1000State;
#define chkflag(x) (s->compat_flags & E1000_FLAG_##x)
@@ -618,9 +623,11 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) {
e1000x_read_tx_ctx_descr(xp, &tp->tso_props);
+ s->use_tso_for_migration = 1;
tp->tso_frames = 0;
} else {
e1000x_read_tx_ctx_descr(xp, &tp->props);
+ s->use_tso_for_migration = 0;
}
return;
} else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
@@ -1362,6 +1369,20 @@ static int e1000_pre_save(void *opaque)
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
}
+ /* Decide which set of props to migrate in the main structure */
+ if (chkflag(TSO) || !s->use_tso_for_migration) {
+ /* Either we're migrating with the extra subsection, in which
+ * case the mig_props is always 'props' OR
+ * we've not got the subsection, but 'props' was the last
+ * updated.
+ */
+ s->mig_props = s->tx.props;
+ } else {
+ /* We're not using the subsection, and 'tso_props' was
+ * the last updated.
+ */
+ s->mig_props = s->tx.tso_props;
+ }
return 0;
}
@@ -1390,6 +1411,21 @@ static int e1000_post_load(void *opaque, int version_id)
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
}
+ s->tx.props = s->mig_props;
+ if (!s->received_tx_tso) {
+ /* We received only one set of offload data (tx.props)
+ * and haven't got tx.tso_props. The best we can do
+ * is dupe the data.
+ */
+ s->tx.tso_props = s->mig_props;
+ }
+ return 0;
+}
+
+static int e1000_tx_tso_post_load(void *opaque, int version_id)
+{
+ E1000State *s = opaque;
+ s->received_tx_tso = true;
return 0;
}
@@ -1407,6 +1443,13 @@ static bool e1000_full_mac_needed(void *opaque)
return chkflag(MAC);
}
+static bool e1000_tso_state_needed(void *opaque)
+{
+ E1000State *s = opaque;
+
+ return chkflag(TSO);
+}
+
static const VMStateDescription vmstate_e1000_mit_state = {
.name = "e1000/mit_state",
.version_id = 1,
@@ -1433,9 +1476,31 @@ static const VMStateDescription vmstate_e1000_full_mac_state = {
}
};
+static const VMStateDescription vmstate_e1000_tx_tso_state = {
+ .name = "e1000/tx_tso_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = e1000_tso_state_needed,
+ .post_load = e1000_tx_tso_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(tx.tso_props.ipcss, E1000State),
+ VMSTATE_UINT8(tx.tso_props.ipcso, E1000State),
+ VMSTATE_UINT16(tx.tso_props.ipcse, E1000State),
+ VMSTATE_UINT8(tx.tso_props.tucss, E1000State),
+ VMSTATE_UINT8(tx.tso_props.tucso, E1000State),
+ VMSTATE_UINT16(tx.tso_props.tucse, E1000State),
+ VMSTATE_UINT32(tx.tso_props.paylen, E1000State),
+ VMSTATE_UINT8(tx.tso_props.hdr_len, E1000State),
+ VMSTATE_UINT16(tx.tso_props.mss, E1000State),
+ VMSTATE_INT8(tx.tso_props.ip, E1000State),
+ VMSTATE_INT8(tx.tso_props.tcp, E1000State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_e1000 = {
.name = "e1000",
- .version_id = 3,
+ .version_id = 2,
.minimum_version_id = 1,
.pre_save = e1000_pre_save,
.post_load = e1000_post_load,
@@ -1450,20 +1515,20 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
VMSTATE_UINT16(eecd_state.reading, E1000State),
VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
- VMSTATE_UINT8(tx.props.ipcss, E1000State),
- VMSTATE_UINT8(tx.props.ipcso, E1000State),
- VMSTATE_UINT16(tx.props.ipcse, E1000State),
- VMSTATE_UINT8(tx.props.tucss, E1000State),
- VMSTATE_UINT8(tx.props.tucso, E1000State),
- VMSTATE_UINT16(tx.props.tucse, E1000State),
- VMSTATE_UINT32(tx.props.paylen, E1000State),
- VMSTATE_UINT8(tx.props.hdr_len, E1000State),
- VMSTATE_UINT16(tx.props.mss, E1000State),
+ VMSTATE_UINT8(mig_props.ipcss, E1000State),
+ VMSTATE_UINT8(mig_props.ipcso, E1000State),
+ VMSTATE_UINT16(mig_props.ipcse, E1000State),
+ VMSTATE_UINT8(mig_props.tucss, E1000State),
+ VMSTATE_UINT8(mig_props.tucso, E1000State),
+ VMSTATE_UINT16(mig_props.tucse, E1000State),
+ VMSTATE_UINT32(mig_props.paylen, E1000State),
+ VMSTATE_UINT8(mig_props.hdr_len, E1000State),
+ VMSTATE_UINT16(mig_props.mss, E1000State),
VMSTATE_UINT16(tx.size, E1000State),
VMSTATE_UINT16(tx.tso_frames, E1000State),
VMSTATE_UINT8(tx.sum_needed, E1000State),
- VMSTATE_INT8(tx.props.ip, E1000State),
- VMSTATE_INT8(tx.props.tcp, E1000State),
+ VMSTATE_INT8(mig_props.ip, E1000State),
+ VMSTATE_INT8(mig_props.tcp, E1000State),
VMSTATE_BUFFER(tx.header, E1000State),
VMSTATE_BUFFER(tx.data, E1000State),
VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
@@ -1508,22 +1573,12 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
- VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3),
- VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3),
- VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3),
- VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3),
- VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3),
- VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3),
- VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3),
- VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3),
- VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3),
- VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3),
- VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
&vmstate_e1000_mit_state,
&vmstate_e1000_full_mac_state,
+ &vmstate_e1000_tx_tso_state,
NULL
}
};
@@ -1651,6 +1706,8 @@ static Property e1000_properties[] = {
compat_flags, E1000_FLAG_MIT_BIT, true),
DEFINE_PROP_BIT("extra_mac_registers", E1000State,
compat_flags, E1000_FLAG_MAC_BIT, true),
+ DEFINE_PROP_BIT("migrate_tso_props", E1000State,
+ compat_flags, E1000_FLAG_TSO_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index fdeaec3a58..fb554ab156 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -279,44 +279,52 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
*timeout = cpu_to_be32(splash_time);
}
+static CcwDevice *s390_get_ccw_device(DeviceState *dev_st)
+{
+ CcwDevice *ccw_dev = NULL;
+
+ if (dev_st) {
+ VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
+ object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
+ TYPE_VIRTIO_CCW_DEVICE);
+ if (virtio_ccw_dev) {
+ ccw_dev = CCW_DEVICE(virtio_ccw_dev);
+ } else {
+ SCSIDevice *sd = (SCSIDevice *)
+ object_dynamic_cast(OBJECT(dev_st),
+ TYPE_SCSI_DEVICE);
+ if (sd) {
+ SCSIBus *bus = scsi_bus_from_device(sd);
+ VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
+ VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw,
+ vdev);
+
+ ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
+ TYPE_CCW_DEVICE);
+ }
+ }
+ }
+ return ccw_dev;
+}
+
static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
DeviceState *dev_st;
+ CcwDevice *ccw_dev = NULL;
dev_st = get_boot_device(0);
if (dev_st) {
- VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
- object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
- TYPE_VIRTIO_CCW_DEVICE);
+ ccw_dev = s390_get_ccw_device(dev_st);
+ }
+
+ /*
+ * Currently allow IPL only from CCW devices.
+ */
+ if (ccw_dev) {
SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
TYPE_SCSI_DEVICE);
- VirtIONet *vn = (VirtIONet *) object_dynamic_cast(OBJECT(dev_st),
- TYPE_VIRTIO_NET);
-
- if (vn) {
- ipl->netboot = true;
- }
- if (virtio_ccw_dev) {
- CcwDevice *ccw_dev = CCW_DEVICE(virtio_ccw_dev);
-
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
- ipl->iplb.blk0_len =
- cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_CCW;
- ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
- } else if (sd) {
- SCSIBus *bus = scsi_bus_from_device(sd);
- VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
- VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
- CcwDevice *ccw_dev;
-
- ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
- TYPE_CCW_DEVICE);
- if (!ccw_dev) { /* It might be a PCI device instead */
- return false;
- }
+ if (sd) {
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
ipl->iplb.blk0_len =
cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
@@ -327,12 +335,25 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
} else {
- return false; /* unknown device */
+ VirtIONet *vn = (VirtIONet *) object_dynamic_cast(OBJECT(dev_st),
+ TYPE_VIRTIO_NET);
+
+ ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+ ipl->iplb.blk0_len =
+ cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
+ ipl->iplb.pbt = S390_IPL_TYPE_CCW;
+ ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+ ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+
+ if (vn) {
+ ipl->netboot = true;
+ }
}
if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
}
+
return true;
}
@@ -406,7 +427,8 @@ unref_mr:
return img_size;
}
-static bool is_virtio_net_device(IplParameterBlock *iplb)
+static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
+ int virtio_id)
{
uint8_t cssid;
uint8_t ssid;
@@ -426,13 +448,23 @@ static bool is_virtio_net_device(IplParameterBlock *iplb)
sch = css_find_subch(1, cssid, ssid, schid);
if (sch && sch->devno == devno) {
- return sch->id.cu_model == VIRTIO_ID_NET;
+ return sch->id.cu_model == virtio_id;
}
}
}
return false;
}
+static bool is_virtio_net_device(IplParameterBlock *iplb)
+{
+ return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
+}
+
+static bool is_virtio_scsi_device(IplParameterBlock *iplb)
+{
+ return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
+}
+
void s390_ipl_update_diag308(IplParameterBlock *iplb)
{
S390IPLState *ipl = get_ipl_device();
@@ -457,6 +489,22 @@ void s390_reipl_request(void)
S390IPLState *ipl = get_ipl_device();
ipl->reipl_requested = true;
+ if (ipl->iplb_valid &&
+ !ipl->netboot &&
+ ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
+ is_virtio_scsi_device(&ipl->iplb)) {
+ CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0));
+
+ if (ccw_dev &&
+ cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
+ (ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
+ /*
+ * this is the original boot device's SCSI
+ * so restore IPL parameter info from it
+ */
+ ipl->iplb_valid = s390_gen_initial_iplb(ipl);
+ }
+ }
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
}
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 4e5855741a..fe34b50769 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -357,11 +357,13 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
if (strcmp(vbasedev->name, vcdev->vdev.name) == 0) {
error_setg(&err, "vfio: subchannel %s has already been attached",
vcdev->vdev.name);
+ g_free(vcdev->vdev.name);
goto out_device_err;
}
}
if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) {
+ g_free(vcdev->vdev.name);
goto out_device_err;
}
diff --git a/include/hw/compat.h b/include/hw/compat.h
index bc9e3a6627..13242b831a 100644
--- a/include/hw/compat.h
+++ b/include/hw/compat.h
@@ -14,6 +14,10 @@
.driver = "vhost-user-blk-pci",\
.property = "vectors",\
.value = "2",\
+ },{\
+ .driver = "e1000",\
+ .property = "migrate_tso_props",\
+ .value = "off",\
},
#define HW_COMPAT_2_10 \
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8671447aca..643b8833de 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3386,6 +3386,23 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
return ret;
}
+/* Convert target low/high pair representing file offset into the host
+ * low/high pair. This function doesn't handle offsets bigger than 64 bits
+ * as the kernel doesn't handle them either.
+ */
+static void target_to_host_low_high(abi_ulong tlow,
+ abi_ulong thigh,
+ unsigned long *hlow,
+ unsigned long *hhigh)
+{
+ uint64_t off = tlow |
+ ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
+ TARGET_LONG_BITS / 2;
+
+ *hlow = off;
+ *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
+}
+
static struct iovec *lock_iovec(int type, abi_ulong target_addr,
abi_ulong count, int copy)
{
@@ -10452,7 +10469,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
if (vec != NULL) {
- ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
+ unsigned long low, high;
+
+ target_to_host_low_high(arg4, arg5, &low, &high);
+ ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
unlock_iovec(vec, arg2, arg3, 1);
} else {
ret = -host_to_target_errno(errno);
@@ -10465,7 +10485,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
if (vec != NULL) {
- ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
+ unsigned long low, high;
+
+ target_to_host_low_high(arg4, arg5, &low, &high);
+ ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
unlock_iovec(vec, arg2, arg3, 0);
} else {
ret = -host_to_target_errno(errno);
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index d17e85995d..fdd6809c70 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index fc2a9fe33b..9287b7a70f 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -70,6 +70,13 @@ static void jump_to_IPL_code(uint64_t address)
{
/* store the subsystem information _after_ the bootmap was loaded */
write_subsystem_identification();
+
+ /* prevent unknown IPL types in the guest */
+ if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
+ iplb.pbt = S390_IPL_TYPE_CCW;
+ set_iplb(&iplb);
+ }
+
/*
* The IPL PSW is at address 0. We also must not overwrite the
* content of non-BIOS memory after we loaded the guest, so we
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 7dfce4fbcf..5357a36d51 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -97,16 +97,27 @@ extern QemuIplParameters qipl;
#define S390_IPL_TYPE_CCW 0x02
#define S390_IPL_TYPE_QEMU_SCSI 0xff
-static inline bool store_iplb(IplParameterBlock *iplb)
+static inline bool manage_iplb(IplParameterBlock *iplb, bool store)
{
register unsigned long addr asm("0") = (unsigned long) iplb;
register unsigned long rc asm("1") = 0;
asm volatile ("diag %0,%2,0x308\n"
: "+d" (addr), "+d" (rc)
- : "d" (6)
+ : "d" (store ? 6 : 5)
: "memory", "cc");
return rc == 0x01;
}
+
+static inline bool store_iplb(IplParameterBlock *iplb)
+{
+ return manage_iplb(iplb, true);
+}
+
+static inline bool set_iplb(IplParameterBlock *iplb)
+{
+ return manage_iplb(iplb, false);
+}
+
#endif /* IPLB_H */
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index 9f5926b534..31f3d141cd 100644
--- a/pc-bios/s390-netboot.img
+++ b/pc-bios/s390-netboot.img
Binary files differ
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index 615fa24ab9..e8548f340a 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -103,16 +103,18 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
env->psw.addr = addr;
env->psw.mask = mask;
- if (tcg_enabled()) {
- env->cc_op = (mask >> 44) & 3;
+
+ /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
+ if (!tcg_enabled()) {
+ return;
}
+ env->cc_op = (mask >> 44) & 3;
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env)));
}
- /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
- if (tcg_enabled() && (mask & PSW_MASK_WAIT)) {
+ if (mask & PSW_MASK_WAIT) {
s390_handle_wait(s390_env_get_cpu(env));
}
}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index f570896dc1..fb59d92def 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -1778,6 +1778,8 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
qemu_mutex_lock_iothread();
+ cpu_synchronize_state(cs);
+
switch (run->exit_reason) {
case KVM_EXIT_S390_SIEIC:
ret = handle_intercept(cpu);
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 1deeb6e6e4..a25deef5dd 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -325,7 +325,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
r = mmu_translate_region(env, vaddr, asc, asce, level, raddr, flags, rw,
exc);
- if (rw == MMU_DATA_STORE && !(*flags & PAGE_WRITE)) {
+ if (!r && rw == MMU_DATA_STORE && !(*flags & PAGE_WRITE)) {
trigger_prot_fault(env, vaddr, asc, rw, exc);
return -1;
}