diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/s390x/cpu.c | 45 | ||||
-rw-r--r-- | target/s390x/cpu.h | 2 | ||||
-rw-r--r-- | target/s390x/helper.c | 5 | ||||
-rw-r--r-- | target/s390x/kvm.c | 15 |
4 files changed, 58 insertions, 9 deletions
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index a665b9e60e..3e1be56536 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -35,6 +35,8 @@ #include "qemu/error-report.h" #include "trace.h" #include "qapi/visitor.h" +#include "qapi-visit.h" +#include "sysemu/hw_accel.h" #include "exec/exec-all.h" #include "hw/qdev-properties.h" #ifndef CONFIG_USER_ONLY @@ -228,6 +230,46 @@ out: error_propagate(errp, err); } +static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs) +{ + GuestPanicInformation *panic_info; + S390CPU *cpu = S390_CPU(cs); + + cpu_synchronize_state(cs); + panic_info = g_malloc0(sizeof(GuestPanicInformation)); + + panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390; +#if !defined(CONFIG_USER_ONLY) + panic_info->u.s390.core = cpu->env.core_id; +#else + panic_info->u.s390.core = 0; /* sane default for non system emulation */ +#endif + panic_info->u.s390.psw_mask = cpu->env.psw.mask; + panic_info->u.s390.psw_addr = cpu->env.psw.addr; + panic_info->u.s390.reason = cpu->env.crash_reason; + + return panic_info; +} + +static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CPUState *cs = CPU(obj); + GuestPanicInformation *panic_info; + + if (!cs->crash_occurred) { + error_setg(errp, "No crash occurred"); + return; + } + + panic_info = s390_cpu_get_crash_info(cs); + + visit_type_GuestPanicInformation(v, "crash-information", &panic_info, + errp); + qapi_free_GuestPanicInformation(panic_info); +} + static void s390_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -240,6 +282,8 @@ static void s390_cpu_initfn(Object *obj) cs->env_ptr = env; cs->halted = 1; cs->exception_index = EXCP_HLT; + object_property_add(obj, "crash-information", "GuestPanicInformation", + s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); s390_cpu_model_register_props(obj); #if !defined(CONFIG_USER_ONLY) qemu_get_timedate(&tm, 0); @@ -473,6 +517,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->do_interrupt = s390_cpu_do_interrupt; #endif cc->dump_state = s390_cpu_dump_state; + cc->get_crash_info = s390_cpu_get_crash_info; cc->set_pc = s390_cpu_set_pc; cc->gdb_read_register = s390_cpu_gdb_read_register; cc->gdb_write_register = s390_cpu_gdb_write_register; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 96df2fe5c9..09ec8a9b76 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -83,6 +83,8 @@ struct CPUS390XState { PSW psw; + S390CrashReason crash_reason; + uint64_t cc_src; uint64_t cc_dst; uint64_t cc_vr; diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 84aaef3a53..615fa24ab9 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -83,12 +83,15 @@ static inline bool is_special_wait_psw(uint64_t psw_addr) void s390_handle_wait(S390CPU *cpu) { + CPUState *cs = CPU(cpu); + if (s390_cpu_halt(cpu) == 0) { #ifndef CONFIG_USER_ONLY if (is_special_wait_psw(cpu->env.psw.addr)) { qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } else { - qemu_system_guest_panicked(NULL); + cpu->env.crash_reason = S390_CRASH_REASON_DISABLED_WAIT; + qemu_system_guest_panicked(cpu_get_crash_info(cs)); } #endif } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index e13c8907df..83e4eaf45d 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1541,15 +1541,14 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) return r; } -static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) +static void unmanageable_intercept(S390CPU *cpu, S390CrashReason reason, + int pswoffset) { CPUState *cs = CPU(cpu); - error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx", - str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), - ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); s390_cpu_halt(cpu); - qemu_system_guest_panicked(NULL); + cpu->env.crash_reason = reason; + qemu_system_guest_panicked(cpu_get_crash_info(cs)); } /* try to detect pgm check loops */ @@ -1579,7 +1578,7 @@ static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run) !(oldpsw.mask & PSW_MASK_PSTATE) && (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) && (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) { - unmanageable_intercept(cpu, "operation exception loop", + unmanageable_intercept(cpu, S390_CRASH_REASON_OPINT_LOOP, offsetof(LowCore, program_new_psw)); return EXCP_HALTED; } @@ -1600,12 +1599,12 @@ static int handle_intercept(S390CPU *cpu) r = handle_instruction(cpu, run); break; case ICPT_PROGRAM: - unmanageable_intercept(cpu, "program interrupt", + unmanageable_intercept(cpu, S390_CRASH_REASON_PGMINT_LOOP, offsetof(LowCore, program_new_psw)); r = EXCP_HALTED; break; case ICPT_EXT_INT: - unmanageable_intercept(cpu, "external interrupt", + unmanageable_intercept(cpu, S390_CRASH_REASON_EXTINT_LOOP, offsetof(LowCore, external_new_psw)); r = EXCP_HALTED; break; |