Devices need to be serialized before sending them over ethernet and deserialized after receiving them. Some devices need further configuration on the target machine (the VGA model device for example). In the underlying implementation the MotherBoard
class has an additional bus, namely the RestoreBus
, which transports Messages of type MessageRestore
.
A MessageRestore
contains the following fields: devtype
, bytes
, id1
, id2
, a write
flag and a byte pointer space
. The devtype
field contains an enumeration value to identify what action shall follow on which type of device on the bus, when received. The other fields are explained in the following subsections.
Using a seperate bus for this it is easy to append new devices to the migration process without messing around on other message protocols. This turned out to be quite comfortable.
Making a Device Migrateable
The devices in question need to be attached to the motherboard’s restore bus. This is done in their constructors. Furthermore they need to implement a receive(MessageRestore &msg)
method.
The receive
method does the following:
-
if (msg.devtype == MessageRestore::RESTORE_RESTART)
Set internal processed
bit to false, increment msg.bytes
by the size in bytes this device will consume later, and return. (The bus is reset on all devices)
-
if (msg.devtype != MessageRestore::RESTORE_<MY_TYPE> || processed == true)
return false (This message is for a different device type)
-
if (msg.write == true)
{ save internal state to msg.space
and set msg.bytes
to the number of bytes consumed for this. Optionally use the id1
and id2
fields for further internal identification needs. }
else
{ Do the opposite: load device state from msg.space
}
Most devices just do a memcpy(...)
over their member variables. If any custom reinitialization etc. needs to be done before/after serialization/deserialization, this can also be done here.
Devices will only react via their receive
function. The only sender of MessageRestore
messages will always be the migration process.
Serializing Devices for Take-Off
The execution flow in control of the migration process sends a MessageRestore::RESTORE_RESTART
over the bus first. Since this message went through all serializable devices which are currently running in the underlying VMM and every device added its size to msg.bytes
during the restart event, the process knows how many bytes have to be allocated for buffering them.
Then the serialization itself follows:
The process sends restore messages over the bus (with the earlyout
parameter set to true). The first device which receives it saves its state into the buffer and returns true. The same device will never return true again (Unless another MessageRestore::RESTORE_RESTART
is sent to reset its processed
bit).
This way the migration process does neither have to know what devices nor how many of them it serializes: The send
function of the bus will eventually return false for the first time when all devices are serialized into the buffer.
The buffer, containing a dense queue of restore messages and following serialized data strings, can be sent over network now.
Deserializing Devices after Arrival
After parsing the queue of restore messages and serialized device strings, the migration process pushes all the restore messages onto the restore bus. The devices will identify their restore message and deserialize themselves.
Special Restore Messages
While most enumeration values for msg.devtype
identify a serialize/deserialize action for a specific device type (Which is actually split into multiple specific types to enable for implementing a serialization/deserialization order, if this ever becomes relevant in the future), there are special enumeration values identifying custom actions. MessageRestore::RESTORE_RESTART
is a first example for this. Currently there are two other values which identify actions like “return me the video mode currently displayed” or “display string on the user’s framebuffer”, which are relevant on different stages of the migration process.