diff options
Diffstat (limited to 'target-s390x/misc_helper.c')
-rw-r--r-- | target-s390x/misc_helper.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 454960aa01..9b4423a031 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -179,6 +179,46 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) return r; } +#ifndef CONFIG_USER_ONLY +#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]; + + if (env->psw.mask & PSW_MASK_PSTATE) { + program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); + return; + } + + if ((subcode & ~0x0ffffULL) || (subcode > 6)) { + program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); + return; + } + + switch (subcode) { + case 5: + if ((r1 & 1) || (addr & 0x0fffULL)) { + program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); + return; + } + env->regs[r1+1] = DIAG_308_RC_INVALID; + 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; + return; + default: + hw_error("Unhandled diag308 subcode %" PRIx64, subcode); + break; + } +} +#endif + /* DIAG */ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, uint64_t code) |