SSM-new.cpp revision b7214b64b02fe9144ad778dd196e8b88cf985e8f
/* $Id$ */
/** @file
* SSM - Saved State Manager.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/** @page pg_ssm SSM - The Saved State Manager
*
* The Saved State Manager (SSM) implements facilities for saving and loading a
* VM state in a structural manner using callbacks for named data units.
*
* At init time each of the VMM components, Devices, Drivers and one or two
* other things will register data units which they need to save and restore.
* Each unit have a unique name (ascii), instance number, and a set of callbacks
* associated with it. The name will be used to identify the unit during
* restore. The callbacks are for the two operations, save and restore. There
* are three callbacks for each of the two - a prepare, a execute and a complete
* - giving each component ample opportunity to perform actions both before and
* afterwards.
*
* The SSM provides a number of APIs for encoding and decoding the data: @see
* grp_ssm
*
*
*
* @section sec_ssm_live_snapshots Live Snapshots
*
* The live snapshots feature (LS) is similar to live migration (LM) and was a
* natural first step when implementing LM. The main differences between LS and
* LM are that after a live snapshot we will have a saved state file, disk image
* snapshots, and the VM will still be running.
*
* Compared to normal saved stated and snapshots, the difference is in that the
* VM is running while we do most of the saving. Prior to LS, there was only
* round of callback during saving, after LS there are 1 or more while the VM is
* still running and a final one after it has been paused. The runtime stages
* is executed on a dedicated thread running at at the same priority as the EMTs
* so that the saving doesn't starve or lose in scheduling questions. The final
* phase is done on EMT(0).
*
* There are a couple of common reasons why LS and LM will fail:
* - Memory configuration changed (PCI memory mappings).
* - Takes too long (LM) / Too much output (LS).
*
* FIGURE THIS: It is currently unclear who will resume the VM after it has been
* paused. The most efficient way to do this is by doing it before returning
* from the VMR3Save call and use a callback for reconfiguring the disk images.
* (It is more efficient because of fewer thread switches.) The more convenient
* way is to have main do it after calling VMR3Save.
*
*
* @section sec_ssm_live_migration Live Migration
*
* As mentioned in the previous section, the main differences between this and
* live snapshots are in where the saved state is written and what state the
* local VM is in afterwards - at least from the VMM point of view. The
* necessary administrative work - establishing the connection to the remote
* machine, cloning the VM config on it and doing lowlevel saved state data
* transfer - is taken care of by layer above the VMM (i.e. Main).
*
* The SSM data format was made streamable for the purpose of live migration
* (v1.2 was the last non-streamable version).
*
*
* @section sec_ssm_format Saved State Format
*
* The stream format starts with a header (SSMFILEHDR) that indicates the
* version and such things, it is followed by zero or more saved state units
* (name + instance + phase), and the stream concludes with a footer
* (SSMFILEFTR) that contains unit counts and optionally a checksum for the
* entire file. (In version 1.2 and earlier, the checksum was in the header and
* there was no footer. This meant that the header was updated after the entire
* file was written.)
*
* The saved state units each starts with a variable sized header
* (SSMFILEUNITHDR) that contains the name, instance and phase. The data
* follows the header and is encoded as records with a 2-8 byte record header
* indicating the type, flags and size. The first byte in the record header
* indicates the type and flags:
*
* - bits 0..3: Record type:
* - type 0: Invalid.
* - type 1: Terminator with CRC-32 and unit size.
* - type 2: Raw data record.
* - type 3: Raw data compressed by LZF. The data is prefixed by a 8-bit
* field countining the length of the uncompressed data given as
* a page count.
* - type 4: Named data - length prefixed name followed by the data. This
* type is not implemented yet as we're missing the API part, so
* the type assignment is tentative.
* - types 5 thru 15 are current undefined.
* - bit 4: Important (set), can be skipped (clear).
* - bit 5: Undefined flag, must be zero.
* - bit 6: Undefined flag, must be zero.
* - bit 7: "magic" bit, always set.
*
* Record header byte 2 (optionally thru 7) is the size of the following data
* encoded in UTF-8 style.
*
* (In version 1.2 and earlier the unit data was compressed and not record
* based. The unit header contained the compressed size of the data, i.e. it
* needed updating after the data was written.)
*
*
* @section sec_ssm_future Future Changes
*
* There are plans to extend SSM to make it easier to be both backwards and
* (somewhat) forwards compatible. One of the new features will be being able
* to classify units and data items as unimportant (added to the format in
* v2.0). Another suggested feature is naming data items (also added to the
* format in v2.0), perhaps by extending the SSMR3PutStruct API. Both features
* will require API changes, the naming may possibly require both buffering of
* the stream as well as some helper managing them.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SSM
#include "SSMInternal.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The special value for the final phase. */
#define SSM_PHASE_FINAL UINT32_MAX
/** The max length of a unit name. */
#define SSM_MAX_NAME_SIZE 48
/** Saved state file magic base string. */
#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
/** Saved state file magic indicating version 1.x. */
#define SSMFILEHDR_MAGIC_V1_X "\177VirtualBox SavedState V1."
/** Saved state file v1.1 magic. */
#define SSMFILEHDR_MAGIC_V1_1 "\177VirtualBox SavedState V1.1\n"
/** Saved state file v1.2 magic. */
#define SSMFILEHDR_MAGIC_V1_2 "\177VirtualBox SavedState V1.2\n\0\0\0"
/** Saved state file v2.0 magic. */
#define SSMFILEHDR_MAGIC_V2_0 "\177VirtualBox SavedState V2.0\n\0\0\0"
/** @name SSMFILEHDR::fFlags
* @{ */
/** The stream is checkesummed up to the footer using CRC-32. */
#define SSMFILEHDR_FLAGS_STREAM_CRC32 RT_BIT_32(0)
/** @} */
/** The directory magic. */
#define SSMFILEDIR_MAGIC "\nDir\n\0\0"
/** Saved state file v2.0 magic. */
#define SSMFILEFTR_MAGIC "\nFooter"
/** Data unit magic. */
#define SSMFILEUNITHDR_MAGIC "\nUnit\n\0"
/** Data end marker magic. */
#define SSMFILEUNITHDR_END "\nTheEnd"
/** @name Record Types (data unit)
* @{ */
/** The record type mask. */
/** Invalid record. */
#define SSM_REC_TYPE_INVALID 0
/** Normal termination record, see SSMRECTERM. */
#define SSM_REC_TYPE_TERM 1
/** Raw data. The data follows the size field without further ado. */
#define SSM_REC_TYPE_RAW 2
/** Raw data compressed by LZF.
* The record header is followed by a 8-bit field containing the size of the
* uncompressed data. The compressed data is after it. */
#define SSM_REC_TYPE_RAW_LZF 3
/** Named data items.
* A length prefix zero terminated string (i.e. max 255) followed by the data. */
#define SSM_REC_TYPE_NAMED 4
/** Macro for validating the record type.
* This can be used with the flags+type byte, no need to mask out the type first. */
/** @} */
/** The flag mask. */
/** The record is important if this flag is set, if clear it can be omitted. */
/** This flag is always set. */
/** Macro for validating the flags.
* No need to mask the flags out of the flags+type byte before invoking this macro. */
/** Macro for validating the type and flags byte in a data record. */
#define SSM_REC_ARE_TYPE_AND_FLAGS_VALID(u8) ( SSM_REC_FLAGS_ARE_VALID(u8) && SSM_REC_TYPE_IS_VALID(u8) )
/** @name SSMRECTERM::fFlags
* @{ */
/** There is CRC-32 for the data. */
/** @} */
/** Start structure magic. (Isacc Asimov) */
#define SSMR3STRUCT_BEGIN 0x19200102
/** End structure magic. (Isacc Asimov) */
#define SSMR3STRUCT_END 0x19920406
/** Number of bytes to log in Log2 and Log4 statements. */
#define SSM_LOG_BYTES 16
/** Macro for checking the u32CRC field of a structure.
* The Msg can assume there are u32ActualCRC and u32CRC in the context. */
do \
{ \
(p)->u32CRC = 0; \
} while (0)
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** SSM state. */
typedef enum SSMSTATE
{
SSMSTATE_INVALID = 0,
} SSMSTATE;
/**
* Handle structure.
*/
typedef struct SSMHANDLE
{
/** The file handle. */
/** The VM handle. */
/** The current operation. */
/** What to do after save completes. (move the enum) */
/** The current rc of the save operation. */
int rc;
/** Number of compressed bytes left in the current data unit (V1). */
/** The current uncompressed offset into the data unit. */
/** Whether we're checksumming the unit or not. */
bool fUnitChecksummed;
/** The unit CRC. */
/** Pointer to the progress callback function. */
/** User specified arguemnt to the callback function. */
void *pvUser;
/** Next completion percentage. (corresponds to offEstProgress) */
unsigned uPercent;
/** The position of the next progress callback in the estimated file. */
/** The estimated total byte count.
* (Only valid after the prep.) */
/** Current position in the estimated file. */
/** End of current unit in the estimated file. */
/** the amount of % we reserve for the 'prepare' phase */
unsigned uPercentPrepare;
/** the amount of % we reserve for the 'done' stage */
unsigned uPercentDone;
bool fChecksummed;
/** The stream CRC if fChecksummed is set. */
union
{
/** Write data. */
struct
{
/** Offset into the databuffer. */
/** Space for the record header. */
/** Data buffer. */
} Write;
/** Read data. */
struct
{
/** V1: The decompressor of the current data unit. */
/** The major format version number. */
/** The minor format version number. */
/** V2: Unread bytes in the current record. */
/** V2: Bytes in the data buffer. */
/** V2: Current buffer position. */
/** V2: End of data indicator. */
bool fEndOfData;
/** V2: The type and flags byte fo the current record. */
unsigned cbGCPhys;
unsigned cbGCPtr;
/** Whether cbGCPtr is fixed or settable. */
bool fFixedGCPtrSize;
/** @name Header info (set by ssmR3ValidateFile)
* @{ */
/** The size of the file header. */
/** The major version number. */
/** The minor version number. */
/** The build number. */
/** The SVN revision. */
/** 32 or 64 depending on the host. */
/** The CRC of the loaded file. */
/** The size of the load file. */
/** @} */
/** V2: Data buffer.
* @remarks Be extremely careful when changing the size of this buffer! */
/** V2: Decompression buffer.
* @todo removed this when we start buffering the stream. */
} Read;
} u;
} SSMHANDLE;
/**
* Header of the saved state file.
*
* Added in r5xxxx on 2009-07-2?, VirtualBox v3.0.51.
*/
typedef struct SSMFILEHDR
{
/** Magic string which identifies this file as a version of VBox saved state
* file format (SSMFILEHDR_MAGIC_V2_0). */
char szMagic[32];
/** The major version number. */
/** The minor version number. */
/** The build number. */
/** The SVN revision. */
/** 32 or 64 depending on the host. */
/** The size of RTGCPHYS. */
/** The size of RTGCPTR. */
/** Reserved header space - must be zero. */
/** The number of units that (may) have stored data in the file. */
/** Flags, see SSMFILEHDR_FLAGS_XXX. */
/** The maximum size of decompressed data. */
/** The checksum of this header.
* This field is set to zero when calculating the checksum. */
} SSMFILEHDR;
/** Pointer to a saved state file header. */
typedef SSMFILEHDR *PSSMFILEHDR;
/** Pointer to a const saved state file header. */
typedef SSMFILEHDR const *PCSSMFILEHDR;
/**
* Header of the saved state file.
*
* Added in r40980 on 2008-12-15, VirtualBox v2.0.51.
*
* @remarks This is a superset of SSMFILEHDRV11.
*/
typedef struct SSMFILEHDRV12
{
/** Magic string which identifies this file as a version of VBox saved state
* file format (SSMFILEHDR_MAGIC_V1_2). */
char achMagic[32];
/** The size of this file. Used to check
* whether the save completed and that things are fine otherwise. */
/** File checksum. The actual calculation skips past the u32CRC field. */
/** Padding. */
/** The machine UUID. (Ignored if NIL.) */
/** The major version number. */
/** The minor version number. */
/** The build number. */
/** The SVN revision. */
/** 32 or 64 depending on the host. */
/** The size of RTGCPHYS. */
/** The size of RTGCPTR. */
/** Padding. */
/** Pointer to a saved state file header. */
typedef SSMFILEHDRV12 *PSSMFILEHDRV12;
/**
* Header of the saved state file, version 1.1.
*
* Added in r23677 on 2007-08-17, VirtualBox v1.4.1.
*/
typedef struct SSMFILEHDRV11
{
/** Magic string which identifies this file as a version of VBox saved state
* file format (SSMFILEHDR_MAGIC_V1_1). */
char achMagic[32];
/** The size of this file. Used to check
* whether the save completed and that things are fine otherwise. */
/** File checksum. The actual calculation skips past the u32CRC field. */
/** Padding. */
/** The machine UUID. (Ignored if NIL.) */
/** Pointer to a saved state file header. */
typedef SSMFILEHDRV11 *PSSMFILEHDRV11;
/**
* Data unit header.
*/
typedef struct SSMFILEUNITHDR
{
/** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
char szMagic[8];
/** The offset in the saved state stream of the start of this unit.
* This is mainly intended for sanity checking. */
/** The checksum of this structure, including the whole name.
* Calculated with this field set to zero. */
/** Data version. */
/** Instance number. */
/** Data phase number. */
/** Flags reserved for future extensions. Must be zero. */
/** Size of the data unit name including the terminator. (bytes) */
/** Data unit name, variable size. */
char szName[SSM_MAX_NAME_SIZE];
/** Pointer to SSMFILEUNITHDR. */
typedef SSMFILEUNITHDR *PSSMFILEUNITHDR;
/**
* Data unit header.
*
* This is used by v1.0, v1.1 and v1.2 of the format.
*/
typedef struct SSMFILEUNITHDRV1
{
/** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
char achMagic[8];
/** Number of bytes in this data unit including the header. */
/** Data version. */
/** Instance number. */
/** Size of the data unit name including the terminator. (bytes) */
/** Data unit name. */
char szName[1];
/** Pointer to SSMFILEUNITHDR. */
typedef SSMFILEUNITHDRV1 *PSSMFILEUNITHDRV1;
/**
* Termination data record.
*/
typedef struct SSMRECTERM
{
/** The record size (sizeof(SSMRECTERM) - 2). */
/** Flags, see SSMRECTERM_FLAGS_CRC32. */
/** The checksum of the data up to the start of this record. */
/** The length of this data unit in bytes (including this record). */
} SSMRECTERM;
/** Pointer to a termination record. */
typedef SSMRECTERM *PSSMRECTERM;
/** Pointer to a const termination record. */
typedef SSMRECTERM const *PCSSMRECTERM;
/**
* Directory entry.
*/
typedef struct SSMFILEDIRENTRY
{
/** The offset of the data unit. */
/** The instance number. */
/** The CRC-32 of the name excluding the terminator. (lazy bird) */
/** Pointer to a directory entry. */
typedef SSMFILEDIRENTRY *PSSMFILEDIRENTRY;
/** Pointer to a const directory entry. */
typedef SSMFILEDIRENTRY const *PCSSMFILEDIRENTRY;
/**
* Directory for the data units from the final phase.
*
* This is used to speed up SSMR3Seek (it would have to decompress and parse the
* whole stream otherwise).
*/
typedef struct SSMFILEDIR
{
/** Magic string (SSMFILEDIR_MAGIC). */
char szMagic[8];
/** The CRC-32 for the whole directory.
* Calculated with this field set to zero. */
/** The number of directory entries. */
/** The directory entries (variable size). */
} SSMFILEDIR;
/** Pointer to a directory. */
typedef SSMFILEDIR *PSSMFILEDIR;
/** Pointer to a const directory. */
typedef SSMFILEDIR *PSSMFILEDIR;
/**
* Footer structure
*/
typedef struct SSMFILEFTR
{
/** Magic string (SSMFILEFTR_MAGIC). */
char szMagic[8];
/** The offset of this record in the stream. */
/** The CRC for the stream.
* This is set to zero if SSMFILEHDR_FLAGS_STREAM_CRC32 is clear. */
/** Number directory entries. */
/** Reserved footer space - must be zero. */
/** The CRC-32 for this structure.
* Calculated with this field set to zero. */
} SSMFILEFTR;
/** Pointer to a footer. */
typedef SSMFILEFTR *PSSMFILEFTR;
/** Pointer to a const footer. */
typedef SSMFILEFTR const *PCSSMFILEFTR;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int ssmR3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
/**
* Performs lazy initialization of the SSM.
*
* @returns VBox status code.
* @param pVM The VM.
*/
{
/*
* Register a saved state unit which we use to put the VirtualBox version,
* revision and similar stuff in.
*/
return rc;
}
/**
* For saving usful things without having to go thru the tedious process of
* adding it to the header.
*
* @returns VBox status code.
* @param pVM Pointer to the shared VM structure.
* @param pSSM The SSM handle.
*/
{
/*
* String table containg pairs of variable and value string.
* Terminated by two empty strings.
*/
#ifdef VBOX_OSE
#endif
/* terminator */
}
/**
* For load the version + revision and stuff.
*
* @returns VBox status code.
* @param pVM Pointer to the shared VM structure.
* @param pSSM The SSM handle.
* @param u32Version The version (1).
*/
{
/*
* String table containg pairs of variable and value string.
* Terminated by two empty strings.
*/
for (unsigned i = 0; ; i++)
{
char szVar[128];
char szValue[1024];
break;
if (i == 0)
LogRel(("SSM: Saved state info:\n"));
}
return VINF_SUCCESS;
}
/**
* Internal registration worker.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance id.
* @param u32Version The data unit version.
* @param cbGuess The guessed data unit size.
* @param pszBefore Name of data unit to be placed in front of.
* Optional.
* @param ppUnit Where to store the insterted unit node.
* Caller must fill in the missing details.
*/
{
/*
* Validate input.
*/
AssertMsgReturn(cchName < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchName, SSM_MAX_NAME_SIZE, pszName), VERR_OUT_OF_RANGE);
AssertMsgReturn(cchBefore < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchBefore, SSM_MAX_NAME_SIZE, pszBefore), VERR_OUT_OF_RANGE);
/*
* Lazy init.
*/
{
}
/*
* Walk to the end of the list checking for duplicates as we go.
*/
while (pUnit)
{
{
return VERR_SSM_UNIT_EXISTS;
}
&& !pUnitBefore
{
pUnitBefore = pUnit;
}
/* next */
}
/*
* Allocate new node.
*/
if (!pUnit)
return VERR_NO_MEMORY;
/*
* Fill in (some) data. (Stuff is zero'ed.)
*/
/*
* Insert
*/
if (pUnitBefore)
{
if (pUnitBeforePrev)
else
}
else if (pUnitPrev)
else
return VINF_SUCCESS;
}
/**
* Register a PDM Devices data unit.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pDevIns Device instance.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pszBefore Name of data unit which we should be put in front
* of. Optional (NULL).
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore,
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Register a PDM driver data unit.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pDrvIns Driver instance.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Register a internal data unit.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Register an external data unit.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
* @param pvUser User argument.
*/
VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Deregister one or more PDM Device data units.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pDevIns Device instance.
* @param pszName Data unit name.
* Use NULL to deregister all data units for that device instance.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @remark Only for dynmaic data units and dynamic unloaded modules.
*/
VMMR3DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance)
{
/*
* Validate input.
*/
if (!pDevIns)
{
AssertMsgFailed(("pDevIns is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
while (pUnit)
{
&& ( !pszName
)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
if (pszName)
return VINF_SUCCESS;
rc = VINF_SUCCESS;
continue;
}
else if (pszName)
{
AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
return VERR_SSM_UNIT_NOT_OWNER;
}
}
/* next */
}
return rc;
}
/**
* Deregister one ore more PDM Driver data units.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDrvIns Driver instance.
* @param pszName Data unit name.
* Use NULL to deregister all data units for that driver instance.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique. Ignored if pszName is NULL.
* @remark Only for dynmaic data units and dynamic unloaded modules.
*/
VMMR3DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
{
/*
* Validate input.
*/
if (!pDrvIns)
{
AssertMsgFailed(("pDrvIns is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
while (pUnit)
{
&& ( !pszName
)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
if (pszName)
return VINF_SUCCESS;
rc = VINF_SUCCESS;
continue;
}
else if (pszName)
{
AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
return VERR_SSM_UNIT_NOT_OWNER;
}
}
/* next */
}
return rc;
}
/**
* Deregister a data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param enmType Unit type
* @param pszName Data unit name.
* @remark Only for dynmaic data units.
*/
{
/*
* Validate input.
*/
if (!pszName)
{
AssertMsgFailed(("pszName is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
int rc = VERR_SSM_UNIT_NOT_FOUND;
while (pUnit)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
return VINF_SUCCESS;
}
/* next */
}
return rc;
}
/**
* Deregister an internal data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @remark Only for dynmaic data units.
*/
{
}
/**
* Deregister an external data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @remark Only for dynmaic data units.
*/
{
}
/**
* Stream output routine.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param pvBuf What to write.
* @param cbToWrite How much to write.
*/
{
if (RT_SUCCESS(rc))
{
if (pSSM->fChecksummed)
return VINF_SUCCESS;
}
return rc;
}
/**
* Stream input routine.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param pvBuf Where to put what we read.
* @param cbToRead How much to read.
*/
{
if (RT_SUCCESS(rc))
{
if (pSSM->fChecksummed)
return VINF_SUCCESS;
}
return rc;
}
/**
* Flush any buffered data.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
*/
{
/* no buffering yet. */
return VINF_SUCCESS;
}
/**
* Tell current stream position.
*
* @returns stream position.
* @param pSSM The SSM handle.
*/
{
}
/**
* Calculate the checksum of a file portion.
*
* @returns VBox status.
* @param File Handle to the file. Positioned where to start
* checksumming.
* @param cbFile The portion of the file to checksum.
* @param pu32CRC Where to store the calculated checksum.
*/
{
/*
* Allocate a buffer.
*/
if (!pvBuf)
return VERR_NO_TMP_MEMORY;
/*
* Loop reading and calculating CRC32.
*/
int rc = VINF_SUCCESS;
while (cbFile)
{
/* read chunk */
if (RT_FAILURE(rc))
{
return rc;
}
/* update total */
/* calc crc32. */
}
/* store the calculated crc */
return VINF_SUCCESS;
}
/**
* Works the progress calculation.
*
* @param pSSM The SSM handle.
* @param cbAdvance Number of bytes to advance
*/
{
/* Can't advance it beyond the estimated end of the unit. */
/* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
{
if (pSSM->pfnProgress)
}
}
/**
* Writes the directory.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pSSM The SSM handle.
* @param pcEntries Where to return the number of directory entries.
*/
{
/*
* Grab some temporary memory for the dictionary.
*/
if (!pDir)
{
return VERR_NO_TMP_MEMORY;
}
/*
* Initialize it.
*/
{
}
/*
* Calculate the actual size and CRC-32, then write the directory
* out to the stream.
*/
return rc;
}
/**
* Start VM save operation.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pszFilename Name of the file to save the state in.
* @param enmAfter What is planned after a successful save operation.
* @param pfnProgress Progress callback. Optional.
* @param pvUser User argument for the progress callback.
*
* @thread EMT
*/
VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
{
LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
/*
* Validate input.
*/
if ( enmAfter != SSMAFTER_DESTROY
&& enmAfter != SSMAFTER_CONTINUE)
{
return VERR_INVALID_PARAMETER;
}
/*
* Create the handle and try open the file.
*
* Note that there might be quite some work to do after executing the saving,
* so we reserve 20% for the 'Done' period. The checksumming and closing of
* the saved state file might take a long time.
*/
Handle.cbUnitLeftV1 = 0;
Handle.fUnitChecksummed = false;
Handle.u32UnitCRC = 0;
Handle.offEstProgress = 0;
Handle.cbEstTotal = 0;
Handle.offEstUnitEnd = 0;
Handle.fChecksummed = true;
int rc = RTFileOpen(&Handle.hFile, pszFilename, RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Write header.
*/
union
{
} u;
u.FileHdr.u8Reserved = 0;
if (RT_SUCCESS(rc))
{
/*
* Clear the per unit flags and offsets.
*/
{
}
/*
* Do the prepare run.
*/
{
{
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_FAILURE(rc))
{
break;
}
}
}
/* Progress. */
if (pfnProgress)
/*
* Do the execute run.
*/
if (RT_SUCCESS(rc))
{
{
/*
* Estimate.
*/
/*
* Does this unit have a callback? If, not skip it.
*/
{
continue;
}
/*
* Write data unit header
*/
Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
u.UnitHdr.offStream, u.UnitHdr.szName, u.UnitHdr.u32Instance, u.UnitHdr.u32Phase, u.UnitHdr.u32Version));
if (RT_SUCCESS(rc))
{
/*
* Call the execute handler.
*/
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
/*
* Write the termination record and flush the compression stream.
*/
if (Handle.fUnitChecksummed)
{
}
else
{
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
Handle.u32UnitCRC = 0;
}
else
{
break;
}
}
else
{
break;
}
}
if (RT_FAILURE(rc))
{
break;
}
} /* for each unit */
/* finish the progress. */
if (RT_SUCCESS(rc))
}
/* (progress should be pending 99% now) */
AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
/*
* Do the done run.
*/
{
{
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_FAILURE(rc))
{
}
}
}
/*
* Finalize the file if successfully saved.
*/
if (RT_SUCCESS(rc))
{
/* Write the end unit. */
u.UnitHdr.u32Version = 0;
u.UnitHdr.u32Instance = 0;
if (RT_SUCCESS(rc))
{
/* Write the directory for the final units and then the footer. */
/* Flush the stream buffers so that the CRC is up to date. */
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
u.Footer.u32Reserved = 0;
if (RT_SUCCESS(rc))
{
if (pfnProgress)
return VINF_SUCCESS;
}
}
}
}
}
/*
* Delete the file on failure and destroy any compressors.
*/
return rc;
}
/**
* Validates the header information stored in the handle.
*
* @returns VBox status code.
*
* @param pSSM The handle.
* @param fHaveHostBits Set if the host bits field is valid.
* @param fHaveVersion Set if we have a version.
*/
{
if (fHaveVersion)
{
{
LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
return VERR_SSM_INTEGRITY_VBOX_VERSION;
}
}
else
if (fHaveHostBits)
{
{
return VERR_SSM_INTEGRITY_SIZES;
}
}
else
{
return VERR_SSM_INTEGRITY_SIZES;
}
{
return VERR_SSM_INTEGRITY_SIZES;
}
return VINF_SUCCESS;
}
/**
* Validates the integrity of a saved state file.
*
* @returns VBox status.
* @param File File to validate.
* The file position is undefined on return.
* @param fChecksumIt Whether to checksum the file or not.
* @param fChecksumOnRead Whether to validate the checksum while reading
* the stream instead of up front. If not possible,
* verify the checksum up front.
* @param pHdr Where to store the file header.
*/
{
/*
* Read the header.
*/
union
{
} uHdr;
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Verify the magic and make adjustments for versions differences.
*/
{
Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
return VERR_SSM_INTEGRITY_MAGIC;
}
{
/*
* Version 2.0 and later.
*/
bool fChecksummed;
{
/* validate the header. */
SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
{
return VERR_SSM_INTEGRITY;
}
{
return VERR_SSM_INTEGRITY;
}
{
return VERR_SSM_INTEGRITY;
}
/* set the header info. */
}
else
{
Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
return VERR_SSM_INTEGRITY_VERSION;
}
/*
* Read and validate the footer.
*/
{
return VERR_SSM_INTEGRITY;
}
SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
{
LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
return VERR_SSM_INTEGRITY;
}
if (Footer.u32Reserved)
{
return VERR_SSM_INTEGRITY;
}
if ( !fChecksummed
&& Footer.u32StreamCRC)
{
LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
return VERR_SSM_INTEGRITY;
}
/*
* Validate the header info we've set in the handle.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Check the checksum if that's called for and possible.
*/
if ( fChecksummed
&& fChecksumIt)
{
if (RT_FAILURE(rc))
return rc;
{
LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
return VERR_SSM_INTEGRITY_CRC;
}
}
}
else
{
/*
* Version 1.x of the format.
*/
bool fHaveHostBits = true;
bool fHaveVersion = false;
pSSM->fChecksummed = false;
{
fHaveHostBits = false;
}
{
fHaveVersion = true;
}
else
{
LogRel(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
return VERR_SSM_INTEGRITY_VERSION;
}
/*
* The MachineUuid must be NULL (was never used).
*/
if (!RTUuidIsNull(&MachineUuidFromHdr))
{
LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
return VERR_SMM_INTEGRITY_MACHINE;
}
/*
* Verify the file size.
*/
{
LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
return VERR_SSM_INTEGRITY_SIZE;
}
/*
* Validate the header info we've set in the handle.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Verify the checksum if requested.
*
* Note! The checksum is not actually generated for the whole file,
* this is of course a bug in the v1.x code that we cannot do
* anything about.
*/
if ( fChecksumIt
|| fChecksumOnRead)
{
rc = RTFileSeek(pSSM->hFile, RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC), RTFILE_SEEK_BEGIN, NULL);
if (RT_FAILURE(rc))
return rc;
{
LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
return VERR_SSM_INTEGRITY_CRC;
}
}
}
return VINF_SUCCESS;
}
/**
* Open a saved state for reading.
*
* The file will be positioned at the first data unit upon successful return.
*
* @returns VBox status code.
*
* @param pVM The VM handle.
* @param pszFilename The filename.
* @param fChecksumIt Check the checksum for the entire file.
* @param fChecksumOnRead Whether to validate the checksum while reading
* the stream instead of up front. If not possible,
* verify the checksum up front.
* @param pSSM Pointer to the handle structure. This will be
* completely initialized on success.
*/
static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead, PSSMHANDLE pSSM)
{
/*
* Initialize the handle.
*/
pSSM->cbUnitLeftV1 = 0;
pSSM->fUnitChecksummed = 0;
pSSM->u32UnitCRC = 0;
pSSM->offEstProgress = 0;
pSSM->cbEstTotal = 0;
pSSM->offEstUnitEnd = 0;
pSSM->u32StreamCRC = 0;
/*
* Try open and validate the file.
*/
int rc = RTFileOpen(&pSSM->hFile, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
return rc;
}
}
else
return rc;
}
/**
* Find a data unit by name.
*
* @returns Pointer to the unit.
* @returns NULL if not found.
*
* @param pVM VM handle.
* @param pszName Data unit name.
* @param u32Instance The data unit instance id.
*/
{
while ( pUnit
return pUnit;
}
/**
* Executes the loading of a V1.X file.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pSSM The saved state handle.
*/
{
int rc;
for (;;)
{
/*
* Save the current file position and read the data unit header.
*/
if (RT_SUCCESS(rc))
{
/*
* Check the magic and see if it's valid and whether it is a end header or not.
*/
{
{
/* Complete the progress bar (pending 99% afterwards). */
break;
}
LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
break;
}
/*
* Read the name.
* Adjust the name buffer first.
*/
{
if (pszName)
}
if (pszName)
{
if (RT_SUCCESS(rc))
{
{
break;
}
/*
* Find the data unit in our internal table.
*/
if (pUnit)
{
/*
* Call the execute handler.
*/
{
break;
}
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
/*
* Close the reader stream.
*/
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
/*
* Now, we'll check the current position to see if all, or
* more than all, the data was read.
*
* Note! Because of buffering / compression we'll only see the
* really bad ones here.
*/
if (i64Diff < 0)
{
}
else if (i64Diff > 0)
{
break;
}
}
else
{
LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
break;
}
}
else
{
/*
* SSM unit wasn't found - ignore this when loading for the debugger.
*/
break;
}
}
}
else
}
/*
* I/O errors ends up here (yea, I know, very nice programming).
*/
if (RT_FAILURE(rc))
{
break;
}
}
return rc;
}
/**
* Executes the loading of a V2.X file.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pSSM The saved state handle.
*/
{
for (;;)
{
/*
* Read the unit header and check its integrity.
*/
if (RT_FAILURE(rc))
return rc;
{
LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
return VERR_SSM_INTEGRITY_UNIT_MAGIC;
}
{
{
return VERR_SSM_INTEGRITY;
}
if (RT_FAILURE(rc))
return rc;
{
LogRel(("SSM: Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
return VERR_SSM_INTEGRITY;
}
}
("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
{
LogRel(("SSM: Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit));
return VERR_SSM_INTEGRITY;
}
AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags), VERR_SSM_INTEGRITY);
{
&& UnitHdr.u32Instance == 0
&& UnitHdr.u32Version == 0
/*
* Complete the progress bar (pending 99% afterwards) and RETURN.
*/
return VINF_SUCCESS;
}
AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
/*
* Find the data unit in our internal table.
*/
if (pUnit)
{
/*
* Call the execute handler.
*/
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
else
{
LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u): %Rrc\n",
return rc;
}
}
else
{
/*
* SSM unit wasn't found - ignore this when loading for the debugger.
*/
LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
//if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
}
}
/* won't get here */
}
/**
* Load VM save operation.
*
* @returns VBox status.
*
* @param pVM The VM handle.
* @param pszFilename Name of the file to save the state in.
* @param enmAfter What is planned after a successful load operation.
* Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
* @param pfnProgress Progress callback. Optional.
* @param pvUser User argument for the progress callback.
*
* @thread EMT
*/
VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
{
LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
/*
* Validate input.
*/
if ( enmAfter != SSMAFTER_RESUME
&& enmAfter != SSMAFTER_DEBUG_IT)
{
return VERR_INVALID_PARAMETER;
}
/*
* Create the handle and open the file.
*/
int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, &Handle);
if (RT_SUCCESS(rc))
{
LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
else
LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
if (pfnProgress)
/*
* Clear the per unit flags.
*/
/*
* Do the prepare run.
*/
{
{
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_FAILURE(rc))
{
break;
}
}
}
/* pending 2% */
if (pfnProgress)
/*
* Do the execute run.
*/
if (RT_SUCCESS(rc))
{
else
/* (progress should be pending 99% now) */
AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
}
/*
* Do the done run.
*/
{
{
rc = VINF_SUCCESS;
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (RT_FAILURE(rc))
{
LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
}
}
}
/* progress */
if (pfnProgress)
}
/*
* Done
*/
if (RT_SUCCESS(rc))
{
/* progress */
if (pfnProgress)
}
return rc;
}
/**
* Validates a file as a validate SSM saved state.
*
* This will only verify the file format, the format and content of individual
* data units are not inspected.
*
* @returns VINF_SUCCESS if valid.
* @returns VBox status code on other failures.
*
* @param pszFilename The path to the file to validate.
* @param fChecksumIt Whether to checksum the file or not.
*
* @thread Any.
*/
{
LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
/*
* Try open the file and validate it.
*/
if (RT_SUCCESS(rc))
else
return rc;
}
/**
* Opens a saved state file for reading.
*
* @returns VBox status code.
*
* @param pszFilename The path to the saved state file.
* @param fFlags Open flags. Reserved, must be 0.
* @param ppSSM Where to store the SSM handle.
*
* @thread Any.
*/
{
LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
/*
* Validate input.
*/
/*
* Allocate a handle.
*/
/*
* Try open the file and validate it.
*/
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
return rc;
}
/**
* Closes a saved state file opened by SSMR3Open().
*
* @returns VBox status code.
*
* @param pSSM The SSM handle returned by SSMR3Open().
*
* @thread Any, but the caller is responsible for serializing calls per handle.
*/
{
/*
* Validate input.
*/
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
/*
* Close the file and free the handle.
*/
{
}
return rc;
}
/**
* Worker for SSMR3Seek that seeks version 1 saved state files.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param pszUnit The unit to seek to.
* @param iInstance The particulart insance we seek.
* @param piVersion Where to store the unit version number.
*/
static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
{
/*
* Walk the data units until we find EOF or a match.
*/
char szName[SSM_MAX_NAME_SIZE];
{
/*
* Read the unit header and verify it.
*/
{
/*
* Does what we've got match, if so read the name.
*/
{
/*
* Does the name match?
*/
{
if (piVersion)
return VINF_SUCCESS;
}
}
}
return VERR_SSM_UNIT_NOT_FOUND;
else
AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
}
/* won't get here. */
}
/**
* Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param pszUnit The unit to seek to.
* @param iInstance The particulart insance we seek.
* @param piVersion Where to store the unit version number.
*/
static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries,
{
/*
* Read it.
*/
AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY);
for (uint32_t i = 0; i < cDirEntries; i++)
/*
* Search the directory.
*/
for (uint32_t i = 0; i < cDirEntries; i++)
{
{
/*
* Read and validate the unit header.
*/
{
}
("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
/*
* Ok, it is valid, get on with the comparing now.
*/
{
if (piVersion)
return VINF_SUCCESS;
}
}
}
return VERR_SSM_UNIT_NOT_FOUND;
}
/**
* Worker for SSMR3Seek that seeks version 2 saved state files.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param pszUnit The unit to seek to.
* @param iInstance The particulart insance we seek.
* @param piVersion Where to store the unit version number.
*/
static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
{
/*
* Read the footer, allocate a temporary buffer for the dictionary and
* pass it down to a worker to simplify cleanup.
*/
int rc = RTFileReadAt(pSSM->hFile, pSSM->u.Read.cbLoadFile - sizeof(Footer), &Footer, sizeof(Footer), NULL);
AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
if (RT_UNLIKELY(!pDir))
return VERR_NO_TMP_MEMORY;
return rc;
}
/**
* Seeks to a specific data unit.
*
* After seeking it's possible to use the getters to on
* that data unit.
*
* @returns VBox status code.
* @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
*
* @param pSSM The SSM handle returned by SSMR3Open().
* @param pszUnit The name of the data unit.
* @param iInstance The instance number.
* @param piVersion Where to store the version number. (Optional)
*
* @thread Any, but the caller is responsible for serializing calls per handle.
*/
VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
{
LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
/*
* Validate input.
*/
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
/*
* Reset the state.
*/
{
}
pSSM->cbUnitLeftV1 = 0;
/*
* Call the version specific workers.
*/
else
}
/**
* Finishes a data unit.
* All buffers and compressor instances are flushed and destroyed.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
*/
{
//Log2(("ssmR3DataWriteFinish: %#010llx start\n", RTFileTell(pSSM->File)));
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
return rc;
}
/**
* Begins writing the data of a data unit.
*
* Errors are signalled via pSSM->rc.
*
* @param pSSM The saved state handle.
*/
{
if (pSSM->fUnitChecksummed)
}
/**
* Writes a record to the current data item in the saved state file.
*
* @returns VBox status code. Sets pSSM->rc on failure.
* @param pSSM The saved state handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
{
Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
ssmR3StrmTell(pSSM), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
/*
* Check that everything is fine.
*/
/*
* Do the stream checksumming before we write the data.
*/
if (pSSM->fUnitChecksummed)
/*
* Write the data item in 1MB chunks for progress indicator reasons.
*/
while (cbBuf > 0)
{
if (RT_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}
/**
* Writes a record header for the specified amount of data.
*
* @returns VBox status code. Sets pSSM->rc on failure.
* @param pSSM The saved state handle
* @param cb The amount of data.
* @param u8TypeAndFlags The record type and flags.
*/
{
abHdr[0] = u8TypeAndFlags;
if (cb < 0x80)
{
cbHdr = 2;
}
else if (cb < 0x00000800)
{
cbHdr = 3;
}
else if (cb < 0x00010000)
{
cbHdr = 4;
}
else if (cb < 0x00200000)
{
cbHdr = 5;
}
else if (cb < 0x04000000)
{
cbHdr = 6;
}
else if (cb <= 0x7fffffff)
{
cbHdr = 7;
}
else
Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
ssmR3StrmTell(pSSM) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
}
/**
* Worker that flushes the buffered data.
*
* @returns VBox status code. Will set pSSM->rc on error.
* @param pSSM The saved state handle.
*/
{
if (!cb)
/*
* Create a record header.
*/
if (cb < 0x80)
{
cbTotal += 1;
pbHdr -= 1;
}
else if (cb < 0x00000800)
{
cbTotal += 2;
pbHdr -= 2;
}
else if (cb < 0x00010000)
{
cbTotal += 3;
pbHdr -= 3;
}
else if (cb < 0x00200000)
{
cbTotal += 4;
pbHdr -= 4;
}
else if (cb < 0x04000000)
{
cbTotal += 5;
pbHdr -= 5;
}
else if (cb <= 0x7fffffff)
{
cbTotal += 6;
pbHdr -= 6;
}
else
Log3(("ssmR3DataFlushBuffer: %08llx|%08llx/%08x: Type=RAW fImportant=true cbHdr=%u\n",
/*
* Write it and reset the buffer.
*/
return rc;
}
/**
* ssmR3DataWrite worker that writes big stuff.
*
* @returns VBox status code
* @param pSSM The saved state handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
{
if (RT_SUCCESS(rc))
{
/*
* Compress it if it's a page or more in size.
*/
for (;;)
{
{
struct
{
} s;
if (RT_SUCCESS(rc))
{
s.cPages = 1;
rc = ssmR3DataWriteRecHdr(pSSM, cbCompr, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF);
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
}
else
{
/* Didn't compress very well, store it. */
rc = ssmR3DataWriteRecHdr(pSSM, PAGE_SIZE, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}
else
{
/* Less than one page, just store it. */
rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
if (RT_SUCCESS(rc))
return rc;
}
}
}
return rc;
}
/**
* ssmR3DataWrite worker that is called when there isn't enough room in the
* buffer for the current chunk of data.
*
* This will first flush the buffer and then add the new bits to it.
*
* @returns VBox status code
* @param pSSM The saved state handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* Writes data to the current data unit.
*
* This is an inlined wrapper that optimizes the small writes that so many of
* the APIs make.
*
* @returns VBox status code
* @param pSSM The saved state handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
{
if (!cbBuf)
return VINF_SUCCESS;
return VINF_SUCCESS;
}
/**
* Puts a structure.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
* @param pvStruct The structure address.
* @param paFields The array of structure fields descriptions.
* The array must be terminated by a SSMFIELD_ENTRY_TERM().
*/
{
/* begin marker. */
if (RT_FAILURE(rc))
return rc;
/* put the fields */
pCur++)
{
if (RT_FAILURE(rc))
return rc;
}
/* end marker */
}
/**
* Saves a boolean item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param fBool Item to save.
*/
{
{
}
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 8-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u8 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 8-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i8 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 16-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u16 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 16-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i16 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 32-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u32 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 32-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i32 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 64-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u64 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 64-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i64 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 128-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u128 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 128-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i128 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a VBox unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
{
return ssmR3DataWrite(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a VBox signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
{
return ssmR3DataWrite(pSSM, &i, sizeof(i));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC natural unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*
* @deprecated Silly type, don't use it.
*/
{
return ssmR3DataWrite(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC unsigned integer register item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
{
return ssmR3DataWrite(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 32 bits GC physical address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPhys The item to save
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 64 bits GC physical address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPhys The item to save
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC physical address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPhys The item to save
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC virtual address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPtr The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves an RC virtual address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param RCPtr The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPtr The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a I/O port address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param IOPort The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a selector item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param Sel The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a memory item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pv Item to save.
* @param cb Size of the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a zero terminated string item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Item to save.
*/
{
{
{
AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
return VERR_TOO_MUCH_DATA;
}
if (rc)
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Closes the decompressor of a data unit.
*
* @param pSSM SSM operation handle.
*/
{
{
}
}
/**
* Callback for reading compressed data into the input buffer of the
* decompressor, for saved file format version 1.
*
* @returns VBox status code.
* @param pvSSM The SSM handle.
* @param pvBuf Where to store the compressed data.
* @param cbBuf Size of the buffer.
* @param pcbRead Number of bytes actually stored in the buffer.
*/
{
if (cbRead)
{
//Log2(("ssmR3ReadInV1: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->File), cbBuf, cbRead));
if (RT_SUCCESS(rc))
{
if (pcbRead)
return VINF_SUCCESS;
}
return rc;
}
/** @todo weed out lazy saving */
AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
return VERR_SSM_LOADED_TOO_MUCH;
}
/**
* Internal read worker for reading data from a version 1 unit.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
{
/*
* Open the decompressor on the first read.
*/
{
}
/*
* Do the requested read.
*/
if (RT_SUCCESS(rc))
{
Log2(("ssmR3DataRead: pvBuf=%p cbBuf=%#x offUnit=%#llx %.*Rhxs%s\n", pvBuf, cbBuf, pSSM->offUnit, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
return VINF_SUCCESS;
}
return rc;
}
/**
* Creates the decompressor for the data unit.
*
* pSSM->rc will be set on error.
*
* @param pSSM SSM operation handle.
*/
{
}
/**
* Checks for the termination record and closes the decompressor.
*
* pSSM->rc will be set on error.
*
* @param pSSM SSM operation handle.
*/
{
/*
* If we haven't encountered the end of the record, it must be the next one.
*/
{
if ( RT_SUCCESS(rc)
}
}
/**
* Read reader that does the decompression and keeps the offset and CRC members
* up to date.
*
* Does not set SSM::rc.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
* @param pvBuf Where to put the bits
* @param cbBuf How many bytes to read.
*/
{
/** @todo buffered reads! (at some level or another) */
if (RT_SUCCESS(rc))
{
if (pSSM->fUnitChecksummed)
return VINF_SUCCESS;
}
/** @todo weed out lazy saving */
AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
return VERR_SSM_LOADED_TOO_MUCH;
}
/**
* Reads and checks the LZF "header".
*
* @returns VBox status code.
* @param pSSM The saved state handle..
* @param pcbDecompr Where to store the size of the decompressed data.
*/
{
*pcbDecompr = 0; /* shuts up gcc. */
/** @todo this isn't very efficient, we know we have to read it all, so both
* reading the first byte separately. */
if (RT_FAILURE(rc))
return rc;
("%#x\n", cbDecompr),
*pcbDecompr = cbDecompr;
return VINF_SUCCESS;
}
/**
* Reads an LZF block from the stream and decompresses into the specified
* buffer.
*
* @returns VBox status code.
* @param SSM The saved state handle.
* @param pvDst Pointer to the output buffer.
* @param cbDecompr The size of the decompressed data.
*/
{
/** @todo optimize this wrt to stream buffering when that is added. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
AssertLogRelMsgReturn(cbDstActual == cbDecompr, ("%#x %#x\n", cbDstActual, cbDecompr), VERR_SSM_INTEGRITY);
return VINF_SUCCESS;
}
}
return rc;
}
/**
* Worker for reading the record header.
*
* It sets pSSM->u.Read.cbRecLeft, pSSM->u.Read.u8TypeAndFlags and
* pSSM->u.Read.fEndOfData. When a termination record is encounter, it will be
* read in full and validated, the fEndOfData indicator is set, and VINF_SUCCESS
* is returned.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
*/
{
/*
* Read the two mandatory bytes.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Validate the first byte and check for the termination records.
*/
AssertLogRelMsgReturn(SSM_REC_ARE_TYPE_AND_FLAGS_VALID(abHdr[0]), ("%#x %#x\n", abHdr[0], abHdr[1]), VERR_SSM_INTEGRITY);
{
/* get the rest */
if (RT_FAILURE(rc))
return rc;
/* validate integrity */
AssertLogRelMsgReturn(!(TermRec.fFlags & ~SSMRECTERM_FLAGS_CRC32), ("%#x\n", TermRec.fFlags), VERR_SSM_INTEGRITY);
else if (pSSM->fUnitChecksummed)
{
AssertLogRelMsgReturn(TermRec.u32CRC == u32UnitCRC, ("%#x, %#x\n", TermRec.u32CRC, u32UnitCRC), VERR_SSM_INTEGRITY_CRC);
}
Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx: TERM\n", ssmR3StrmTell(pSSM) - sizeof(SSMRECTERM), pSSM->offUnit));
return VINF_SUCCESS;
}
/*
* Figure the size. The 2nd byte is encoded in UTF-8 fashion, so this
* is can be highly enjoyable.
*/
if (!(cb & 0x80))
else
{
/*
* Need more data. Figure how much and read it.
*/
cb = 2;
cb = 3;
cb = 4;
cb = 5;
cb = 6;
else
if (RT_FAILURE(rc))
return rc;
/*
* Validate what we've read.
*/
switch (cb)
{
case 6:
AssertLogRelMsgReturn((abHdr[6] & 0xc0) == 0x80, ("6/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
case 5:
AssertLogRelMsgReturn((abHdr[5] & 0xc0) == 0x80, ("5/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
case 4:
AssertLogRelMsgReturn((abHdr[4] & 0xc0) == 0x80, ("4/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
case 3:
AssertLogRelMsgReturn((abHdr[3] & 0xc0) == 0x80, ("3/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
case 2:
AssertLogRelMsgReturn((abHdr[2] & 0xc0) == 0x80, ("2/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
break;
default:
return VERR_INTERNAL_ERROR;
}
/*
* Decode it and validate the range.
*/
switch (cb)
{
case 6:
break;
case 5:
break;
case 4:
break;
case 3:
break;
case 2:
break;
default:
return VERR_INTERNAL_ERROR;
}
}
Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
return VINF_SUCCESS;
}
/**
* Buffer miss, do an unbuffered read.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
{
/*
* Copy out what we've got in the buffer.
*/
Log4(("ssmR3DataReadUnbufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(pSSM), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
if (cbInBuffer > 0)
{
}
/*
* Read data.
*/
do
{
/*
* Read the next record header if no more data.
*/
{
if (RT_FAILURE(rc))
}
AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
/*
* Read data from the current record.
*/
{
case SSM_REC_TYPE_RAW:
{
if (RT_FAILURE(rc))
break;
}
case SSM_REC_TYPE_RAW_LZF:
{
if (RT_FAILURE(rc))
return rc;
{
if (RT_FAILURE(rc))
return rc;
}
else
{
/* output buffer is too small, use the data buffer. */
if (RT_FAILURE(rc))
return rc;
}
break;
}
default:
}
} while (cbBuf > 0);
Log4(("ssmR3DataReadUnBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
ssmR3StrmTell(pSSM), pSSM->offUnit, pSSM->u.Read.cbRecLeft, 0, cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
return VINF_SUCCESS;
}
/**
* Buffer miss, do a buffered read.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
{
/*
* Copy out what we've got in the buffer.
*/
Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(pSSM), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
if (cbInBuffer > 0)
{
}
/*
* Buffer more data.
*/
do
{
/*
* Read the next record header if no more data.
*/
{
if (RT_FAILURE(rc))
}
AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
/*
* Read data from the current record.
* LATER: optimize by reading directly into the output buffer for some cases.
*/
{
case SSM_REC_TYPE_RAW:
{
if (RT_FAILURE(rc))
break;
}
case SSM_REC_TYPE_RAW_LZF:
{
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
break;
}
default:
}
/*pSSM->u.Read.offDataBuffer = 0;*/
/*
* Copy data from the buffer.
*/
} while (cbBuf > 0);
Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
ssmR3StrmTell(pSSM), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
return VINF_SUCCESS;
}
/**
* Inlined worker that handles format checks and buffered reads.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
{
/*
* Fend off previous errors and V1 data units.
*/
/*
* Check if the requested data is buffered.
*/
{
}
? "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n"
: "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n",
ssmR3StrmTell(pSSM), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
return VINF_SUCCESS;
}
/**
* Gets a structure.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
* @param pvStruct The structure address.
* @param paFields The array of structure fields descriptions.
* The array must be terminated by a SSMFIELD_ENTRY_TERM().
*/
{
/* begin marker. */
if (RT_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_BEGIN)
/* put the fields */
pCur++)
{
if (RT_FAILURE(rc))
return rc;
}
/* end marker */
if (RT_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_END)
return rc;
}
/**
* Loads a boolean item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pfBool Where to store the item.
*/
{
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 8-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu8 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 8-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi8 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 16-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu16 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 16-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi16 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 32-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu32 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 32-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi32 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 64-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu64 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 64-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi64 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 128-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu128 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 128-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi128 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a VBox unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a VBox signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC natural unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu Where to store the integer.
*
* @deprecated Silly type with an incorrect size, don't use it.
*/
{
}
/**
* Loads a GC unsigned integer register item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu Where to store the integer.
*/
{
}
/**
* Loads a 32 bits GC physical address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPhys Where to store the GC physical address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 64 bits GC physical address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPhys Where to store the GC physical address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC physical address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPhys Where to store the GC physical address.
*/
{
{
/*
* Fiddly.
*/
{
/* 64-bit saved, 32-bit load: try truncate it. */
if (RT_FAILURE(rc))
return rc;
return VERR_SSM_GCPHYS_OVERFLOW;
return rc;
}
/* 32-bit saved, 64-bit load: clear the high part. */
*pGCPhys = 0;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC virtual address item from the current data unit.
*
* Only applies to in the 1.1 format:
* - SSMR3GetGCPtr
* - SSMR3GetGCUIntPtr
* - SSMR3GetGCUInt
* - SSMR3GetGCUIntReg
*
* Put functions are not affected.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param cbGCPtr Size of RTGCPTR
*
* @remarks This interface only works with saved state version 1.1, if the
* format isn't 1.1 the call will be ignored.
*/
{
{
}
AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %u bytes; requested %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
return VINF_SUCCESS;
}
/**
* Loads a GC virtual address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPtr Where to store the GC virtual address.
*/
{
{
/*
* Fiddly.
*/
{
/* 64-bit saved, 32-bit load: try truncate it. */
if (RT_FAILURE(rc))
return rc;
return VERR_SSM_GCPTR_OVERFLOW;
return rc;
}
/* 32-bit saved, 64-bit load: clear the high part. */
*pGCPtr = 0;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPtr Where to store the GC virtual address.
*/
{
}
/**
* Loads an RC virtual address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pRCPtr Where to store the RC virtual address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a I/O port address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pIOPort Where to store the I/O port address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a selector item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pSel Where to store the selector.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a memory item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pv Where to store the item.
* @param cb Size of the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a string item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Where to store the item.
* @param cbMax Max size of the item (including '\\0').
*/
{
}
/**
* Loads a string item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Where to store the item.
* @param cbMax Max size of the item (including '\\0').
* @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
*/
{
{
/* read size prefix. */
if (RT_SUCCESS(rc))
{
if (pcbStr)
{
/* terminate and read string content. */
}
return VERR_TOO_MUCH_DATA;
}
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Skips a number of bytes in the current data unit.
*
* @returns VBox status code.
* @param pSSM The SSM handle.
* @param cb The number of bytes to skip.
*/
{
while (cb > 0)
{
if (RT_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}
/**
* Query what the VBox status code of the operation is.
*
* This can be used for putting and getting a batch of values
* without bother checking the result till all the calls have
* been made.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
*/
{
}
/**
* Fail the load operation.
*
* This is mainly intended for sub item loaders (like timers) which
* return code isn't necessarily heeded by the caller but is important
* to SSM.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
* @param iStatus Failure status code. This MUST be a VERR_*.
*/
{
if (RT_FAILURE(iStatus))
{
}
return VERR_INVALID_PARAMETER;
}
/**
* Get what to do after this operation.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
*/
{
}
/**
* Get the current unit byte offset (uncompressed).
*
* @returns The offset. UINT64_MAX if called at a wrong time.
* @param pSSM SSM operation handle.
*/
{
}