From df75a4e2c607836eee044d7e6b0d94724d6ebf21 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 12 Feb 2015 18:02:14 +0100 Subject: s390x/ipl: support diagnose 308 subcodes 5 and 6 To support dynamically updating the IPL device from inside the KVM guest on the s390 platform, DIAG 308 instruction is intercepted in QEMU to handle the request. Subcode 5 allows to specify a new boot device, which is saved for later in the s390_ipl device. This also allows to switch from an external kernel to a boot device. Subcode 6 retrieves boot device configuration that has been previously set. Reviewed-by: Cornelia Huck Reviewed-by: David Hildenbrand Acked-by: Christian Borntraeger Signed-off-by: Jens Freimann Signed-off-by: Fan Zhang Signed-off-by: Christian Borntraeger --- target-s390x/misc_helper.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'target-s390x') 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 #include "sysemu/kvm.h" #include "qemu/timer.h" +#include "exec/address-spaces.h" #ifdef CONFIG_KVM #include #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); -- cgit v1.2.3