184a899deSJuan Quintela /*
284a899deSJuan Quintela * Global State configuration
384a899deSJuan Quintela *
484a899deSJuan Quintela * Copyright (c) 2014-2017 Red Hat Inc
584a899deSJuan Quintela *
684a899deSJuan Quintela * Authors:
784a899deSJuan Quintela * Juan Quintela <quintela@redhat.com>
884a899deSJuan Quintela *
984a899deSJuan Quintela * This work is licensed under the terms of the GNU GPL, version 2 or later.
1084a899deSJuan Quintela * See the COPYING file in the top-level directory.
1184a899deSJuan Quintela */
1284a899deSJuan Quintela
1384a899deSJuan Quintela #include "qemu/osdep.h"
1484a899deSJuan Quintela #include "qemu/cutils.h"
1584a899deSJuan Quintela #include "qemu/error-report.h"
1654d31236SMarkus Armbruster #include "sysemu/runstate.h"
1784a899deSJuan Quintela #include "qapi/error.h"
185272298cSPeter Xu #include "migration.h"
1984a899deSJuan Quintela #include "migration/global_state.h"
2084a899deSJuan Quintela #include "migration/vmstate.h"
2184a899deSJuan Quintela #include "trace.h"
2284a899deSJuan Quintela
2384a899deSJuan Quintela typedef struct {
2484a899deSJuan Quintela uint32_t size;
25*d3c86c99SSteve Sistare
26*d3c86c99SSteve Sistare /*
27*d3c86c99SSteve Sistare * runstate was 100 bytes, zero padded, but we trimmed it to add a
28*d3c86c99SSteve Sistare * few fields and maintain backwards compatibility.
29*d3c86c99SSteve Sistare */
30*d3c86c99SSteve Sistare uint8_t runstate[32];
31*d3c86c99SSteve Sistare uint8_t has_vm_was_suspended;
32*d3c86c99SSteve Sistare uint8_t vm_was_suspended;
33*d3c86c99SSteve Sistare uint8_t unused[66];
34*d3c86c99SSteve Sistare
3584a899deSJuan Quintela RunState state;
3684a899deSJuan Quintela bool received;
3784a899deSJuan Quintela } GlobalState;
3884a899deSJuan Quintela
3984a899deSJuan Quintela static GlobalState global_state;
4084a899deSJuan Quintela
global_state_do_store(RunState state)41c33f1829SVladimir Sementsov-Ogievskiy static void global_state_do_store(RunState state)
4284a899deSJuan Quintela {
43c33f1829SVladimir Sementsov-Ogievskiy const char *state_str = RunState_str(state);
44c33f1829SVladimir Sementsov-Ogievskiy assert(strlen(state_str) < sizeof(global_state.runstate));
45c33f1829SVladimir Sementsov-Ogievskiy strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate),
46c33f1829SVladimir Sementsov-Ogievskiy state_str, '\0');
47*d3c86c99SSteve Sistare global_state.has_vm_was_suspended = true;
48*d3c86c99SSteve Sistare global_state.vm_was_suspended = vm_get_suspended();
49*d3c86c99SSteve Sistare
50*d3c86c99SSteve Sistare memset(global_state.unused, 0, sizeof(global_state.unused));
5184a899deSJuan Quintela }
52c33f1829SVladimir Sementsov-Ogievskiy
global_state_store(void)53c33f1829SVladimir Sementsov-Ogievskiy void global_state_store(void)
54c33f1829SVladimir Sementsov-Ogievskiy {
55c33f1829SVladimir Sementsov-Ogievskiy global_state_do_store(runstate_get());
5684a899deSJuan Quintela }
5784a899deSJuan Quintela
global_state_store_running(void)5884a899deSJuan Quintela void global_state_store_running(void)
5984a899deSJuan Quintela {
60c33f1829SVladimir Sementsov-Ogievskiy global_state_do_store(RUN_STATE_RUNNING);
6184a899deSJuan Quintela }
6284a899deSJuan Quintela
global_state_received(void)6384a899deSJuan Quintela bool global_state_received(void)
6484a899deSJuan Quintela {
6584a899deSJuan Quintela return global_state.received;
6684a899deSJuan Quintela }
6784a899deSJuan Quintela
global_state_get_runstate(void)6884a899deSJuan Quintela RunState global_state_get_runstate(void)
6984a899deSJuan Quintela {
7084a899deSJuan Quintela return global_state.state;
7184a899deSJuan Quintela }
7284a899deSJuan Quintela
global_state_needed(void * opaque)7384a899deSJuan Quintela static bool global_state_needed(void *opaque)
7484a899deSJuan Quintela {
75*d3c86c99SSteve Sistare return migrate_get_current()->store_global_state;
7684a899deSJuan Quintela }
7784a899deSJuan Quintela
global_state_post_load(void * opaque,int version_id)7884a899deSJuan Quintela static int global_state_post_load(void *opaque, int version_id)
7984a899deSJuan Quintela {
8084a899deSJuan Quintela GlobalState *s = opaque;
8184a899deSJuan Quintela Error *local_err = NULL;
8284a899deSJuan Quintela int r;
8384a899deSJuan Quintela char *runstate = (char *)s->runstate;
8484a899deSJuan Quintela
8584a899deSJuan Quintela s->received = true;
8684a899deSJuan Quintela trace_migrate_global_state_post_load(runstate);
8784a899deSJuan Quintela
88a346af9cSPhilippe Mathieu-Daudé if (strnlen((char *)s->runstate,
89a346af9cSPhilippe Mathieu-Daudé sizeof(s->runstate)) == sizeof(s->runstate)) {
90a346af9cSPhilippe Mathieu-Daudé /*
91a346af9cSPhilippe Mathieu-Daudé * This condition should never happen during migration, because
92*d3c86c99SSteve Sistare * all runstate names are shorter than 32 bytes (the size of
93a346af9cSPhilippe Mathieu-Daudé * s->runstate). However, a malicious stream could overflow
94a346af9cSPhilippe Mathieu-Daudé * the qapi_enum_parse() call, so we force the last character
95a346af9cSPhilippe Mathieu-Daudé * to a NUL byte.
96a346af9cSPhilippe Mathieu-Daudé */
97a346af9cSPhilippe Mathieu-Daudé s->runstate[sizeof(s->runstate) - 1] = '\0';
98a346af9cSPhilippe Mathieu-Daudé }
99f7abe0ecSMarc-André Lureau r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
10084a899deSJuan Quintela
10184a899deSJuan Quintela if (r == -1) {
10284a899deSJuan Quintela if (local_err) {
10384a899deSJuan Quintela error_report_err(local_err);
10484a899deSJuan Quintela }
10584a899deSJuan Quintela return -EINVAL;
10684a899deSJuan Quintela }
10784a899deSJuan Quintela s->state = r;
10884a899deSJuan Quintela
109*d3c86c99SSteve Sistare /*
110*d3c86c99SSteve Sistare * global_state is saved on the outgoing side before forcing a stopped
111*d3c86c99SSteve Sistare * state, so it may have saved state=suspended and vm_was_suspended=0.
112*d3c86c99SSteve Sistare * Now we are in a paused state, and when we later call vm_start, it must
113*d3c86c99SSteve Sistare * restore the suspended state, so we must set vm_was_suspended=1 here.
114*d3c86c99SSteve Sistare */
115*d3c86c99SSteve Sistare vm_set_suspended(s->vm_was_suspended || r == RUN_STATE_SUSPENDED);
116*d3c86c99SSteve Sistare
11784a899deSJuan Quintela return 0;
11884a899deSJuan Quintela }
11984a899deSJuan Quintela
global_state_pre_save(void * opaque)12044b1ff31SDr. David Alan Gilbert static int global_state_pre_save(void *opaque)
12184a899deSJuan Quintela {
12284a899deSJuan Quintela GlobalState *s = opaque;
12384a899deSJuan Quintela
12484a899deSJuan Quintela trace_migrate_global_state_pre_save((char *)s->runstate);
125a346af9cSPhilippe Mathieu-Daudé s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
126a346af9cSPhilippe Mathieu-Daudé assert(s->size <= sizeof(s->runstate));
12744b1ff31SDr. David Alan Gilbert
12844b1ff31SDr. David Alan Gilbert return 0;
12984a899deSJuan Quintela }
13084a899deSJuan Quintela
13184a899deSJuan Quintela static const VMStateDescription vmstate_globalstate = {
13284a899deSJuan Quintela .name = "globalstate",
13384a899deSJuan Quintela .version_id = 1,
13484a899deSJuan Quintela .minimum_version_id = 1,
13584a899deSJuan Quintela .post_load = global_state_post_load,
13684a899deSJuan Quintela .pre_save = global_state_pre_save,
13784a899deSJuan Quintela .needed = global_state_needed,
138a77ffe95SRichard Henderson .fields = (const VMStateField[]) {
13984a899deSJuan Quintela VMSTATE_UINT32(size, GlobalState),
14084a899deSJuan Quintela VMSTATE_BUFFER(runstate, GlobalState),
141*d3c86c99SSteve Sistare VMSTATE_UINT8(has_vm_was_suspended, GlobalState),
142*d3c86c99SSteve Sistare VMSTATE_UINT8(vm_was_suspended, GlobalState),
143*d3c86c99SSteve Sistare VMSTATE_BUFFER(unused, GlobalState),
14484a899deSJuan Quintela VMSTATE_END_OF_LIST()
14584a899deSJuan Quintela },
14684a899deSJuan Quintela };
14784a899deSJuan Quintela
register_global_state(void)14884a899deSJuan Quintela void register_global_state(void)
14984a899deSJuan Quintela {
15084a899deSJuan Quintela /* We would use it independently that we receive it */
15184a899deSJuan Quintela strcpy((char *)&global_state.runstate, "");
15284a899deSJuan Quintela global_state.received = false;
15384a899deSJuan Quintela vmstate_register(NULL, 0, &vmstate_globalstate, &global_state);
15484a899deSJuan Quintela }
155