summary refs log tree commit diff stats
path: root/target-s390x/misc_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-s390x/misc_helper.c')
-rw-r--r--target-s390x/misc_helper.c33
1 files changed, 31 insertions, 2 deletions
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index ef9758a96a..1c3df8e018 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include "sysemu/kvm.h"
 #include "qemu/timer.h"
+#include "exec/address-spaces.h"
 #ifdef CONFIG_KVM
 #include <linux/kvm.h>
 #endif
@@ -34,6 +35,7 @@
 #include "sysemu/cpus.h"
 #include "sysemu/sysemu.h"
 #include "hw/s390x/ebcdic.h"
+#include "hw/s390x/ipl.h"
 #endif
 
 /* #define DEBUG_HELPER */
@@ -151,12 +153,15 @@ static int load_normal_reset(S390CPU *cpu)
     return 0;
 }
 
+#define DIAG_308_RC_OK              0x0001
 #define DIAG_308_RC_NO_CONF         0x0102
 #define DIAG_308_RC_INVALID         0x0402
+
 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
 {
     uint64_t addr =  env->regs[r1];
     uint64_t subcode = env->regs[r3];
+    IplParameterBlock *iplb;
 
     if (env->psw.mask & PSW_MASK_PSTATE) {
         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
@@ -180,14 +185,38 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
             return;
         }
-        env->regs[r1+1] = DIAG_308_RC_INVALID;
+        if (!address_space_access_valid(&address_space_memory, addr,
+                                        sizeof(IplParameterBlock), false)) {
+            program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
+            return;
+        }
+        iplb = g_malloc0(sizeof(struct IplParameterBlock));
+        cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock));
+        if (!s390_ipl_update_diag308(iplb)) {
+            env->regs[r1 + 1] = DIAG_308_RC_OK;
+        } else {
+            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
+        }
+        g_free(iplb);
         return;
     case 6:
         if ((r1 & 1) || (addr & 0x0fffULL)) {
             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
             return;
         }
-        env->regs[r1+1] = DIAG_308_RC_NO_CONF;
+        if (!address_space_access_valid(&address_space_memory, addr,
+                                        sizeof(IplParameterBlock), true)) {
+            program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
+            return;
+        }
+        iplb = s390_ipl_get_iplb();
+        if (iplb) {
+            cpu_physical_memory_write(addr, iplb,
+                                      sizeof(struct IplParameterBlock));
+            env->regs[r1 + 1] = DIAG_308_RC_OK;
+        } else {
+            env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
+        }
         return;
     default:
         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);