aboutsummaryrefslogtreecommitdiff
path: root/target/s390x/excp_helper.c
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2019-02-22 09:11:53 +0100
committerCornelia Huck <cohuck@redhat.com>2019-03-04 11:49:31 +0100
commit9693379ba25631422709c09b48bfbbedfb602bae (patch)
treeef5f1d43a9a2e78b232acb19f6006f313969068e /target/s390x/excp_helper.c
parent257619be4243d9b7f12b619027d9a5c2f2270350 (diff)
s390x/tcg: Save vregs to extended mchk save area
If we have vector registers and the designation is not zero, we have to try to write the vector registers. If the designation is zero or if storing fails, we must not indicate validity. s390_build_validity_mcic() automatically already sets validity if the vector instruction facility is installed. As long as we don't support the guarded-storage facility, the alignment and size of the area is always 1024 bytes. Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20190222081153.14206-4-david@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'target/s390x/excp_helper.c')
-rw-r--r--target/s390x/excp_helper.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index a758649f47..f84bfb1284 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -347,10 +347,41 @@ static void do_io_interrupt(CPUS390XState *env)
load_psw(env, mask, addr);
}
+typedef struct MchkExtSaveArea {
+ uint64_t vregs[32][2]; /* 0x0000 */
+ uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */
+} MchkExtSaveArea;
+QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
+
+static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
+{
+ hwaddr len = sizeof(MchkExtSaveArea);
+ MchkExtSaveArea *sa;
+ int i;
+
+ sa = cpu_physical_memory_map(mcesao, &len, 1);
+ if (!sa) {
+ return -EFAULT;
+ }
+ if (len != sizeof(MchkExtSaveArea)) {
+ cpu_physical_memory_unmap(sa, len, 1, 0);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < 32; i++) {
+ sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0].ll);
+ sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1].ll);
+ }
+
+ cpu_physical_memory_unmap(sa, len, 1, len);
+ return 0;
+}
+
static void do_mchk_interrupt(CPUS390XState *env)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
- uint64_t mask, addr;
+ uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
+ uint64_t mask, addr, mcesao = 0;
LowCore *lowcore;
int i;
@@ -362,6 +393,17 @@ static void do_mchk_interrupt(CPUS390XState *env)
lowcore = cpu_map_lowcore(env);
+ /* extended save area */
+ if (mcic & MCIC_VB_VR) {
+ /* length and alignment is 1024 bytes */
+ mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
+ }
+
+ /* try to store vector registers */
+ if (!mcesao || mchk_store_vregs(env, mcesao)) {
+ mcic &= ~MCIC_VB_VR;
+ }
+
/* we are always in z/Architecture mode */
lowcore->ar_access_id = 1;
@@ -377,7 +419,7 @@ static void do_mchk_interrupt(CPUS390XState *env)
lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
- lowcore->mcic = cpu_to_be64(s390_build_validity_mcic() | MCIC_SC_CP);
+ lowcore->mcic = cpu_to_be64(mcic);
lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->mcck_new_psw.mask);