From 39fbc5c62ce83f34e7f5b62238305d83ce8b4489 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 30 Aug 2013 11:06:56 +0200 Subject: [PATCH 1/7] s390x/kvm: Fix switch/case indentation for handle_diag This alignes case statements to switch statements in the handle_diag function as mandated by coding style. Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 26d18e3bc..ed80154e0 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -583,16 +583,16 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) int r = 0; switch (ipb_code) { - case DIAG_KVM_HYPERCALL: - r = handle_hypercall(cpu, run); - break; - case DIAG_KVM_BREAKPOINT: - sleep(10); - break; - default: - DPRINTF("KVM: unknown DIAG: 0x%x\n", ipb_code); - r = -1; - break; + case DIAG_KVM_HYPERCALL: + r = handle_hypercall(cpu, run); + break; + case DIAG_KVM_BREAKPOINT: + sleep(10); + break; + default: + DPRINTF("KVM: unknown DIAG: 0x%x\n", ipb_code); + r = -1; + break; } return r; From 268846ba93de2529630d623b6ded72cee1221106 Mon Sep 17 00:00:00 2001 From: "Eugene (jno) Dvurechenski" Date: Wed, 19 Jun 2013 17:27:15 +0200 Subject: [PATCH 2/7] s390/kvm: basic implementation of diagnose 308 subcode 6 Linux uses a check for subcode 6 to decide if other subcodes are available. Provide a minimal implementation for subcode 6, as well as for subcode 5. Signed-off-by: Eugene (jno) Dvurechenski Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger [Move code from kvm.c into misc_helper.c] --- target-s390x/cpu.h | 3 +++ target-s390x/kvm.c | 14 +++++++++++++ target-s390x/misc_helper.c | 40 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 65bef8625..0878ab667 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1047,6 +1047,9 @@ uint32_t set_cc_nz_f64(float64 v); uint32_t set_cc_nz_f128(float128 v); /* misc_helper.c */ +#ifndef CONFIG_USER_ONLY +void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); +#endif void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index ed80154e0..c7fcdfa88 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -72,6 +72,7 @@ #define PRIV_XSCH 0x76 #define PRIV_SQBS 0x8a #define PRIV_EQBS 0x9c +#define DIAG_IPL 0x308 #define DIAG_KVM_HYPERCALL 0x500 #define DIAG_KVM_BREAKPOINT 0x501 @@ -578,11 +579,24 @@ static int handle_hypercall(S390CPU *cpu, struct kvm_run *run) return 0; } +static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run) +{ + uint64_t r1, r3; + + cpu_synchronize_state(CPU(cpu)); + r1 = (run->s390_sieic.ipa & 0x00f0) >> 8; + r3 = run->s390_sieic.ipa & 0x000f; + handle_diag_308(&cpu->env, r1, r3); +} + static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) { int r = 0; switch (ipb_code) { + case DIAG_IPL: + kvm_handle_diag_308(cpu, run); + break; case DIAG_KVM_HYPERCALL: r = handle_hypercall(cpu, run); break; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 454960aa0..9b4423a03 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) From 4e872a3fb024f0d742ef6b48be3afaab2c4453fc Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 25 Jul 2013 16:37:37 +0200 Subject: [PATCH 3/7] s390: provide I/O subsystem reset Provide a function that resets the I/O subsystem. Signed-off-by: Christian Borntraeger Acked-by: Alexander Graf --- hw/s390x/s390-virtio-ccw.c | 15 +++++++++++++++ target-s390x/cpu.h | 1 + 2 files changed, 16 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index aebbbf175..8fd46a92c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -17,6 +17,21 @@ #include "css.h" #include "virtio-ccw.h" +void io_subsystem_reset(void) +{ + DeviceState *css, *sclp; + + css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL)); + if (css) { + qdev_reset_all(css); + } + sclp = DEVICE(object_resolve_path_type("", + "s390-sclp-event-facility", NULL)); + if (sclp) { + qdev_reset_all(sclp); + } +} + static int virtio_ccw_hcall_notify(const uint64_t *args) { uint64_t subch_id = args[0]; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 0878ab667..af9de5ed0 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -400,6 +400,7 @@ void cpu_unlock(void); typedef struct SubchDev SubchDev; #ifndef CONFIG_USER_ONLY +extern void io_subsystem_reset(void); SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid); bool css_subch_visible(SubchDev *sch); From 29c6157ca7bfa036a8c59805c1a1d76ba9a2a851 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 25 Jul 2013 16:45:51 +0200 Subject: [PATCH 4/7] s390: provide a cpu load normal function Some code needs to perform an IPL-like bootup that mimics the ESA (31bit) restart. Provide a cpu class method that does so. Signed-off-by: Christian Borntraeger Acked-by: Alexander Graf --- target-s390x/cpu-qom.h | 2 ++ target-s390x/cpu.c | 14 ++++++++++++++ target-s390x/cpu.h | 3 +++ 3 files changed, 19 insertions(+) diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index cbe2341b3..2dc175018 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -36,6 +36,7 @@ * S390CPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. + * @load_normal: Performs a load normal. * * An S/390 CPU model. */ @@ -46,6 +47,7 @@ typedef struct S390CPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + void (*load_normal)(CPUState *cpu); } S390CPUClass; /** diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 5cc99387b..69f5e105d 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -65,6 +65,17 @@ static void s390_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.psw.addr = value; } +#if !defined(CONFIG_USER_ONLY) +/* S390CPUClass::load_normal() */ +static void s390_cpu_load_normal(CPUState *s) +{ + S390CPU *cpu = S390_CPU(s); + cpu->env.psw.addr = ldl_phys(4) & PSW_MASK_ESA_ADDR; + cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64; + s390_add_running_cpu(cpu); +} +#endif + /* CPUClass::reset() */ static void s390_cpu_reset(CPUState *s) { @@ -169,6 +180,9 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) dc->realize = s390_cpu_realizefn; scc->parent_reset = cc->reset; +#if !defined(CONFIG_USER_ONLY) + scc->load_normal = s390_cpu_load_normal; +#endif cc->reset = s390_cpu_reset; cc->do_interrupt = s390_cpu_do_interrupt; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index af9de5ed0..b866ea189 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -228,6 +228,8 @@ typedef struct CPUS390XState { #undef PSW_MASK_CC #undef PSW_MASK_PM #undef PSW_MASK_64 +#undef PSW_MASK_32 +#undef PSW_MASK_ESA_ADDR #define PSW_MASK_PER 0x4000000000000000ULL #define PSW_MASK_DAT 0x0400000000000000ULL @@ -243,6 +245,7 @@ typedef struct CPUS390XState { #define PSW_MASK_PM 0x00000F0000000000ULL #define PSW_MASK_64 0x0000000100000000ULL #define PSW_MASK_32 0x0000000080000000ULL +#define PSW_MASK_ESA_ADDR 0x000000007fffffffULL #undef PSW_ASC_PRIMARY #undef PSW_ASC_ACCREG From f5ae2a4fd8d573cfebaf24220e2920bb5074d9a6 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 28 Jun 2013 10:51:09 +0200 Subject: [PATCH 5/7] s390/cpu: split CPU reset into architectured functions s390 provides several CPU resets: - CPU reset, clears interrupts, stop processing, clears TLB, but does not touch registers - initial CPU reset, like CPU reset, but also clears PSW, prefix, FPC, timer and control registers. It does not touch gprs, fprs and acrs (!) - Power on reset: the full monty wire up CPUClass reset to the full monty, but provide the lesser resets as part of S390CPUClass. Signed-off-by: Christian Borntraeger --- target-s390x/cpu-qom.h | 4 ++++ target-s390x/cpu.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index 2dc175018..ac0460eb3 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -37,6 +37,8 @@ * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * @load_normal: Performs a load normal. + * @cpu_reset: Performs a CPU reset. + * @initial_cpu_reset: Performs an initial CPU reset. * * An S/390 CPU model. */ @@ -48,6 +50,8 @@ typedef struct S390CPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); void (*load_normal)(CPUState *cpu); + void (*cpu_reset)(CPUState *cpu); + void (*initial_cpu_reset)(CPUState *cpu); } S390CPUClass; /** diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 69f5e105d..3c89f8a76 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -76,13 +76,44 @@ static void s390_cpu_load_normal(CPUState *s) } #endif -/* CPUClass::reset() */ +/* S390CPUClass::cpu_reset() */ static void s390_cpu_reset(CPUState *s) { S390CPU *cpu = S390_CPU(s); S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUS390XState *env = &cpu->env; + s390_del_running_cpu(cpu); + scc->parent_reset(s); +#if !defined(CONFIG_USER_ONLY) + s->halted = 1; +#endif + tlb_flush(env, 1); +} + +/* S390CPUClass::initial_reset() */ +static void s390_cpu_initial_reset(CPUState *s) +{ + S390CPU *cpu = S390_CPU(s); + CPUS390XState *env = &cpu->env; + + s390_cpu_reset(s); + /* initial reset does not touch regs,fregs and aregs */ + memset(&env->fpc, 0, offsetof(CPUS390XState, breakpoints) - + offsetof(CPUS390XState, fpc)); + + /* architectured initial values for CR 0 and 14 */ + env->cregs[0] = CR0_RESET; + env->cregs[14] = CR14_RESET; +} + +/* CPUClass:reset() */ +static void s390_cpu_full_reset(CPUState *s) +{ + S390CPU *cpu = S390_CPU(s); + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + CPUS390XState *env = &cpu->env; + s390_del_running_cpu(cpu); scc->parent_reset(s); @@ -183,8 +214,9 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) #if !defined(CONFIG_USER_ONLY) scc->load_normal = s390_cpu_load_normal; #endif - cc->reset = s390_cpu_reset; - + scc->cpu_reset = s390_cpu_reset; + scc->initial_cpu_reset = s390_cpu_initial_reset; + cc->reset = s390_cpu_full_reset; cc->do_interrupt = s390_cpu_do_interrupt; cc->dump_state = s390_cpu_dump_state; cc->set_pc = s390_cpu_set_pc; From f077847572708bbb3dd22bbc91ac6a277046e827 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 25 Jul 2013 16:57:45 +0200 Subject: [PATCH 6/7] s390: Implement load normal reset kdump on s390 uses a load normal reset to bring the system in a defined state by doing a subsystem reset. The issuing CPUs will have an initial CPU reset, all other CPUs will have a CPU reset as defined in POP (no register content will change). Implement this as architectured. Signed-off-by: Christian Borntraeger --- target-s390x/misc_helper.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 9b4423a03..4afd7dab1 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -31,6 +31,7 @@ #if !defined(CONFIG_USER_ONLY) #include "exec/softmmu_exec.h" +#include "sysemu/cpus.h" #include "sysemu/sysemu.h" #endif @@ -180,6 +181,32 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) } #ifndef CONFIG_USER_ONLY +static void cpu_reset_all(void) +{ + CPUState *cpu; + S390CPUClass *scc; + + for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) { + scc = S390_CPU_GET_CLASS(CPU(cpu)); + scc->cpu_reset(CPU(cpu)); + } +} + +static int load_normal_reset(S390CPU *cpu) +{ + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + + pause_all_vcpus(); + cpu_synchronize_all_states(); + cpu_reset_all(); + io_subsystem_reset(); + scc->initial_cpu_reset(CPU(cpu)); + scc->load_normal(CPU(cpu)); + cpu_synchronize_all_post_reset(); + resume_all_vcpus(); + return 0; +} + #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) @@ -198,6 +225,9 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) } switch (subcode) { + case 1: + load_normal_reset(s390_env_get_cpu(env)); + break; case 5: if ((r1 & 1) || (addr & 0x0fffULL)) { program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); From 7f7f975295bc19829b3bd26cadc7f1c9eadb7c6b Mon Sep 17 00:00:00 2001 From: "Eugene (jno) Dvurechenski" Date: Wed, 5 Dec 2012 15:50:07 +0100 Subject: [PATCH 7/7] s390: wire up nmi command to raise a RESTART interrupt on S390 There is the 'nmi' command that is used to trigger a guest dump via kdump feature on x86. s390 uses RESTART interrupt to trigger kdump. So, this patch provides a mean to use 'nmi' command on s390 to raise RESTART interrupt. The CPU to receive the RESTART interrupt is the "default" one. There is an infrastructure to select the "default" CPU using 'cpu' command. The 'info cpus' command can be used to see which one is the "default". In order to wire up the RESTART to 'nmi' command we had to: 1. implement the kvm_s390_cpu_restart function by exporting the existing code 2. implement s390_cpu_restart function as kvm-aware wrapper 3. modify the qmp_inject_nmi function to enable (for s390) the scan for "default" CPU and call s390_cpu_restart for it; 3. fix some messages. Signed-off-by: Eugene (jno) Dvurechenski Signed-off-by: Christian Borntraeger Acked-by: Alexander Graf --- cpus.c | 14 ++++++++++++++ hmp-commands.hx | 4 ++-- qmp-commands.hx | 2 +- target-s390x/cpu.h | 13 +++++++++++++ target-s390x/kvm.c | 6 +++--- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cpus.c b/cpus.c index b9e5685e1..d74cc117b 100644 --- a/cpus.c +++ b/cpus.c @@ -1401,6 +1401,20 @@ void qmp_inject_nmi(Error **errp) apic_deliver_nmi(env->apic_state); } } +#elif defined(TARGET_S390X) + CPUState *cs; + S390CPU *cpu; + + for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) { + cpu = S390_CPU(cs); + if (cpu->env.cpu_num == monitor_get_cpu_index()) { + if (s390_cpu_restart(S390_CPU(cs)) == -1) { + error_set(errp, QERR_UNSUPPORTED); + return; + } + break; + } + } #else error_set(errp, QERR_UNSUPPORTED); #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index 8c6b91a9c..628807f68 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -822,7 +822,7 @@ The values that can be specified here depend on the machine type, but are the same that can be specified in the @code{-boot} command line option. ETEXI -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_S390X) { .name = "nmi", .args_type = "", @@ -834,7 +834,7 @@ ETEXI STEXI @item nmi @var{cpu} @findex nmi -Inject an NMI on the given CPU (x86 only). +Inject an NMI (x86) or RESTART (s390x) on the given CPU. ETEXI diff --git a/qmp-commands.hx b/qmp-commands.hx index cf47e3fe7..bb09e7271 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -487,7 +487,7 @@ Example: <- { "return": {} } Note: inject-nmi fails when the guest doesn't support injecting. - Currently, only x86 guests do. + Currently, only x86 (NMI) and s390x (RESTART) guests do. EQMP diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b866ea189..8be564880 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1069,6 +1069,7 @@ void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_get_registers_partial(CPUState *cpu); int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); +int kvm_s390_cpu_restart(S390CPU *cpu); #else static inline void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, @@ -1093,8 +1094,20 @@ static inline int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, { return -ENOSYS; } +static inline int kvm_s390_cpu_restart(S390CPU *cpu) +{ + return -ENOSYS; +} #endif +static inline int s390_cpu_restart(S390CPU *cpu) +{ + if (kvm_enabled()) { + return kvm_s390_cpu_restart(cpu); + } + return -ENOSYS; +} + static inline void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, uint16_t subchannel_nr, diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index c7fcdfa88..185c8f5a4 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -612,12 +612,12 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) return r; } -static int s390_cpu_restart(S390CPU *cpu) +int kvm_s390_cpu_restart(S390CPU *cpu) { kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); s390_add_running_cpu(cpu); qemu_cpu_kick(CPU(cpu)); - DPRINTF("DONE: SIGP cpu restart: %p\n", &cpu->env); + DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env); return 0; } @@ -686,7 +686,7 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) switch (order_code) { case SIGP_RESTART: - r = s390_cpu_restart(target_cpu); + r = kvm_s390_cpu_restart(target_cpu); break; case SIGP_STORE_STATUS_ADDR: r = s390_store_status(target_env, parameter);