summaryrefslogtreecommitdiff
path: root/hw/s390x
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/ipl.c43
-rw-r--r--hw/s390x/ipl.h16
-rw-r--r--hw/s390x/s390-virtio-ccw.c51
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,