aboutsummaryrefslogtreecommitdiff
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);