phase_until() is implemented in vl.c and is meant to be used to make startup progress up to a specified phase being reached(). At this point, no behavior change is introduced: phase_until() only supports a single double transition corresponding to the functionality of qmp_exit_preconfig(): + accel-created -> machine-initialized -> machine-ready
As a result qmp_exit_preconfig() now uses phase_until(). This commit is a preparation to support cold plugging a device using qapi command (which will be introduced in a following commit). For this we need fine grain control of the phase. Signed-off-by: Damien Hedde <damien.he...@greensocs.com> --- include/hw/qdev-core.h | 14 ++++++++ softmmu/vl.c | 78 ++++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index e29c705b74..5f73d06408 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -909,4 +909,18 @@ extern bool phase_check(MachineInitPhase phase); */ extern void phase_advance(MachineInitPhase phase); +/** + * @phase_until: + * @phase: the target phase + * @errp: error report + * + * Make the machine init progress until the target phase is reached. + * + * Its is a no-op is the target phase is the current or an earlier + * phase. + * + * Returns true in case of success. + */ +extern bool phase_until(MachineInitPhase phase, Error **errp); + #endif diff --git a/softmmu/vl.c b/softmmu/vl.c index 5e1b35ba48..5689d0be88 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2741,30 +2741,72 @@ void qmp_x_exit_preconfig(Error **errp) error_setg(errp, "The command is permitted only before machine initialization"); return; } + phase_until(PHASE_MACHINE_READY, errp); +} - qemu_init_board(); - qemu_create_cli_devices(); - qemu_machine_creation_done(); - - if (loadvm) { - load_snapshot(loadvm, NULL, false, NULL, &error_fatal); - } - if (replay_mode != REPLAY_MODE_NONE) { - replay_vmstate_init(); +bool phase_until(MachineInitPhase phase, Error **errp) +{ + if (!phase_check(PHASE_ACCEL_CREATED)) { + error_setg(errp, "Phase transition is not supported until accelerator" + " is created"); + return false; } - if (incoming) { - Error *local_err = NULL; - if (strcmp(incoming, "defer") != 0) { - qmp_migrate_incoming(incoming, &local_err); - if (local_err) { - error_reportf_err(local_err, "-incoming %s: ", incoming); - exit(1); + while (!phase_check(phase)) { + MachineInitPhase cur_phase = phase_get(); + + switch (cur_phase) { + case PHASE_ACCEL_CREATED: + qemu_init_board(); + /* We are now in PHASE_MACHINE_INITIALIZED. */ + qemu_create_cli_devices(); + /* + * At this point all CLI options are handled apart: + * + -S (autostart) + * + -incoming + */ + qemu_machine_creation_done(); + /* We are now in PHASE_MACHINE_READY. */ + + if (loadvm) { + load_snapshot(loadvm, NULL, false, NULL, &error_fatal); } + if (replay_mode != REPLAY_MODE_NONE) { + replay_vmstate_init(); + } + + if (incoming) { + Error *local_err = NULL; + if (strcmp(incoming, "defer") != 0) { + qmp_migrate_incoming(incoming, &local_err); + if (local_err) { + error_reportf_err(local_err, "-incoming %s: ", + incoming); + exit(1); + } + } + } else if (autostart) { + qmp_cont(NULL); + } + break; + + default: + /* + * If we end up here, it is because we miss a case above. + */ + error_setg(&error_abort, "Requested phase transition is not" + " implemented"); + return false; } - } else if (autostart) { - qmp_cont(NULL); + + /* + * Ensure we made some progress. + * With the default case above, it should be enough to prevent + * any infinite loop. + */ + assert(cur_phase < phase_get()); } + return true; } void qemu_init(int argc, char **argv, char **envp) -- 2.35.1