diff options
Diffstat (limited to 'hw/s390x')
-rw-r--r-- | hw/s390x/ipl.c | 43 | ||||
-rw-r--r-- | hw/s390x/ipl.h | 16 | ||||
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 51 |
3 files changed, 96 insertions, 14 deletions
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 150f6c0582..04245b5258 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -26,6 +26,7 @@ #include "qemu/config-file.h" #include "qemu/cutils.h" #include "qemu/option.h" +#include "exec/exec-all.h" #define KERN_IMAGE_START 0x010000UL #define KERN_PARM_AREA 0x010480UL @@ -488,12 +489,20 @@ IplParameterBlock *s390_ipl_get_iplb(void) return &ipl->iplb; } -void s390_reipl_request(void) +void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type) { S390IPLState *ipl = get_ipl_device(); - ipl->reipl_requested = true; - if (ipl->iplb_valid && + if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) { + /* use CPU 0 for full resets */ + ipl->reset_cpu_index = 0; + } else { + ipl->reset_cpu_index = cs->cpu_index; + } + ipl->reset_type = reset_type; + + if (reset_type == S390_RESET_REIPL && + ipl->iplb_valid && !ipl->netboot && ipl->iplb.pbt == S390_IPL_TYPE_CCW && is_virtio_scsi_device(&ipl->iplb)) { @@ -510,6 +519,31 @@ void s390_reipl_request(void) } } qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + /* as this is triggered by a CPU, make sure to exit the loop */ + if (tcg_enabled()) { + cpu_loop_exit(cs); + } +} + +void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type) +{ + S390IPLState *ipl = get_ipl_device(); + + *cs = qemu_get_cpu(ipl->reset_cpu_index); + if (!*cs) { + /* use any CPU */ + *cs = first_cpu; + } + *reset_type = ipl->reset_type; +} + +void s390_ipl_clear_reset_request(void) +{ + S390IPLState *ipl = get_ipl_device(); + + ipl->reset_type = S390_RESET_EXTERNAL; + /* use CPU 0 for full resets */ + ipl->reset_cpu_index = 0; } static void s390_ipl_prepare_qipl(S390CPU *cpu) @@ -556,11 +590,10 @@ static void s390_ipl_reset(DeviceState *dev) { S390IPLState *ipl = S390_IPL(dev); - if (!ipl->reipl_requested) { + if (ipl->reset_type != S390_RESET_REIPL) { ipl->iplb_valid = false; memset(&ipl->iplb, 0, sizeof(IplParameterBlock)); } - ipl->reipl_requested = false; } static void s390_ipl_class_init(ObjectClass *klass, void *data) diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 0570d0ad75..4e87b89418 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -87,7 +87,17 @@ int s390_ipl_set_loadparm(uint8_t *loadparm); void s390_ipl_update_diag308(IplParameterBlock *iplb); void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); -void s390_reipl_request(void); + +enum s390_reset { + /* default is a reset not triggered by a CPU e.g. issued by QMP */ + S390_RESET_EXTERNAL = 0, + S390_RESET_REIPL, + S390_RESET_MODIFIED_CLEAR, + S390_RESET_LOAD_NORMAL, +}; +void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type); +void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type); +void s390_ipl_clear_reset_request(void); #define QIPL_ADDRESS 0xcc @@ -129,9 +139,11 @@ struct S390IPLState { bool enforce_bios; IplParameterBlock iplb; bool iplb_valid; - bool reipl_requested; bool netboot; QemuIplParameters qipl; + /* reset related properties don't have to be migrated or reset */ + enum s390_reset reset_type; + int reset_cpu_index; /*< public >*/ char *kernel; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 5796e24bd8..e548d341a0 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -93,7 +93,7 @@ static const char *const reset_dev_types[] = { "diag288", }; -void subsystem_reset(void) +static void subsystem_reset(void) { DeviceState *dev; int i; @@ -381,17 +381,54 @@ static void s390_cpu_plug(HotplugHandler *hotplug_dev, } } +static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg) +{ + S390CPU *cpu = S390_CPU(cs); + + s390_ipl_prepare_cpu(cpu); + s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); +} + static void s390_machine_reset(void) { - S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); + enum s390_reset reset_type; + CPUState *cs, *t; + /* get the reset parameters, reset them once done */ + s390_ipl_get_reset_request(&cs, &reset_type); + + /* all CPUs are paused and synchronized at this point */ s390_cmma_reset(); - qemu_devices_reset(); - s390_crypto_reset(); - /* all cpus are stopped - configure and start the ipl cpu only */ - s390_ipl_prepare_cpu(ipl_cpu); - s390_cpu_set_state(S390_CPU_STATE_OPERATING, ipl_cpu); + switch (reset_type) { + case S390_RESET_EXTERNAL: + case S390_RESET_REIPL: + qemu_devices_reset(); + s390_crypto_reset(); + + /* configure and start the ipl CPU only */ + run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL); + break; + case S390_RESET_MODIFIED_CLEAR: + CPU_FOREACH(t) { + run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); + } + subsystem_reset(); + s390_crypto_reset(); + run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); + break; + case S390_RESET_LOAD_NORMAL: + CPU_FOREACH(t) { + run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); + } + subsystem_reset(); + run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL); + run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); + break; + default: + g_assert_not_reached(); + } + s390_ipl_clear_reset_request(); } static void s390_machine_device_plug(HotplugHandler *hotplug_dev, |