mirror of https://github.com/xemu-project/xemu.git
This is a set of patches dealing with kdump support for s390x/kvm.
kdump on s390x uses subcode 1 of diagnose 0x308 to put the hardware in a defined state. This is different from a full reset, since it does not touch all CPU registers. These patches define the cpu resets, the subsystem reset a load function and also wires up the "nmi" command to issue a RESTART interrupt as defined in the z/Architecture principles of operation. This allows recent guest kernels with properly setup userspace to trigger kdump: - via guest crash - via nmi from the host -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJSII3GAAoJEBF7vIC1phx8JV0P/RXnTR1NP+TZVfmO29k4rPqr GWg0OxjTYxUa+xcB28f28n4DfeoKrPROKSJ/VIPrixUiTxaJcWLt8ExdvFcQZT3I NF+omBfmNwHFFX+OvbxoLIIIORiixCEhuJd8XPGBNwcM4Plon82P5TueKPr9pjd2 KOORNYq4zJNm6+exvcbm2xSYgkrLEO/0AcXg1AmDqEpnpvM27/fL/5dYSJ/nqwmY EloC2kP7HWjfKSYdv/u2Xd0Btt0tQOjPRo2n6Sxm5Y890WpR7NKHUjoEAUyXcO9k Rh6zTzUJEong9DKEcDT6p/d+oz1vx0jH/iDp038IS0TEJ/bA+t50CtDRMChH87ds Eo+ClJINztxRAY2arKPx7bN3IT4WCohnwOUuToI1Znb+zoah0pWDeq5DC9d24V45 1i8ttf1RDR8oEw6hyYFxeV+zTDAZspKJRtpEBBkqkGe+OPf0AaZvAgJHFbZP/kZ9 M5Z4wfYLOywUA+dr87+IvcWj4oqq/LEv8tyYoMFaITifWkgK0w3EvFNyy/hwcN6Y AyQnrCjr0qqd3qm2BtlJd+Xf2k7AMjloSH6qug6Mhqrqqr9O7KkpAbmdr16oe9RF hKAVl8zAh/1AhYAFUBvyXBkqTBmyN1DpoT+MvoY7UbjPgFi7ysQN9w406yI1pKFp 3F92RfnPW0Hbr+gFxfng =vgFh -----END PGP SIGNATURE----- Merge remote-tracking branch 'borntraeger/tags/kdump' into staging This is a set of patches dealing with kdump support for s390x/kvm. kdump on s390x uses subcode 1 of diagnose 0x308 to put the hardware in a defined state. This is different from a full reset, since it does not touch all CPU registers. These patches define the cpu resets, the subsystem reset a load function and also wires up the "nmi" command to issue a RESTART interrupt as defined in the z/Architecture principles of operation. This allows recent guest kernels with properly setup userspace to trigger kdump: - via guest crash - via nmi from the host # gpg: Signature made Fri 30 Aug 2013 07:19:18 AM CDT using RSA key ID B5A61C7C # gpg: Can't check signature: public key not found # By Christian Borntraeger (5) and Eugene (jno) Dvurechenski (2) # Via Christian Borntraeger * borntraeger/tags/kdump: s390: wire up nmi command to raise a RESTART interrupt on S390 s390: Implement load normal reset s390/cpu: split CPU reset into architectured functions s390: provide a cpu load normal function s390: provide I/O subsystem reset s390/kvm: basic implementation of diagnose 308 subcode 6 s390x/kvm: Fix switch/case indentation for handle_diag Message-id: 1377810649-47484-1-git-send-email-borntraeger@de.ibm.com
This commit is contained in:
commit
b95fdc0e99
14
cpus.c
14
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
* S390CPUClass:
|
||||
* @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.
|
||||
*/
|
||||
|
@ -46,6 +49,9 @@ 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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,13 +65,55 @@ static void s390_cpu_set_pc(CPUState *cs, vaddr value)
|
|||
cpu->env.psw.addr = value;
|
||||
}
|
||||
|
||||
/* CPUClass::reset() */
|
||||
#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
|
||||
|
||||
/* 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);
|
||||
|
@ -169,8 +211,12 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
|
|||
dc->realize = s390_cpu_realizefn;
|
||||
|
||||
scc->parent_reset = cc->reset;
|
||||
cc->reset = s390_cpu_reset;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
scc->load_normal = s390_cpu_load_normal;
|
||||
#endif
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
@ -400,6 +403,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);
|
||||
|
@ -1047,6 +1051,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);
|
||||
|
@ -1062,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,
|
||||
|
@ -1086,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,
|
||||
|
|
|
@ -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,32 +579,45 @@ 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_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_IPL:
|
||||
kvm_handle_diag_308(cpu, run);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -672,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);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "exec/softmmu_exec.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#endif
|
||||
|
||||
|
@ -179,6 +180,75 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
|
|||
return r;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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 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);
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue