SSM.cpp revision c98fb3e16fcd571a790eab772c0c66173d225205
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/* $Id$ */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** @file
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * SSM - Saved State Manager.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 innotek GmbH
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * available from http://www.virtualbox.org. This file is free software;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * you can redistribute it and/or modify it under the terms of the GNU
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * General Public License as published by the Free Software Foundation,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** @page pg_ssm SSM - The Saved State Manager
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * The Saved State Manager (SSM) implements facilities for saving and loading
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * a VM state in a structural manner using callbacks for each collection of
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * data which needs saving.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * At init time each of the VM components will register data entities which
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * they need to save and restore. Each entity have a unique name (ascii) and
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * a set of callbacks associated with it. The name will be used to identify
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * the entity during restore. The callbacks are for the two operations, save
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * and restore. There are three callbacks for each of the two - a prepare,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * a execute and a what-now.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * The SSM provides a number of APIs for encoding and decoding the data.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/*******************************************************************************
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync* Header Files *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync*******************************************************************************/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define LOG_GROUP LOG_GROUP_SSM
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/ssm.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/dbgf.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/mm.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include "SSMInternal.h"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/vm.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync#include <VBox/err.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <VBox/log.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/assert.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/file.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync#include <iprt/alloc.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync#include <iprt/uuid.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync#include <iprt/zip.h>
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync#include <iprt/crc32.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/thread.h>
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#include <iprt/string.h>
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
710a6316a22868b04400caf79719f96c18163cd3vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/*******************************************************************************
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync* Defined Constants And Macros *
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync*******************************************************************************/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** Start structure magic. (Isacc Asimov) */
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync#define SSMR3STRUCT_BEGIN 0x19200102
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** End structure magic. (Isacc Asimov) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define SSMR3STRUCT_END 0x19920406
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/*******************************************************************************
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync* Structures and Typedefs *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync*******************************************************************************/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsynctypedef enum SSMSTATE
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMSTATE_SAVE_PREP = 1,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync SSMSTATE_SAVE_EXEC,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync SSMSTATE_SAVE_DONE,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync SSMSTATE_LOAD_PREP,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync SSMSTATE_LOAD_EXEC,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMSTATE_LOAD_DONE,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync SSMSTATE_OPEN_READ
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync} SSMSTATE;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Handle structure.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsynctypedef struct SSMHANDLE
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** The file handle. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTFILE File;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** The VM handle. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PVM pVM;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** The current operation. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMSTATE enmOp;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** What to do after save completes. (move the enum) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMAFTER enmAfter;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** The current rc of the save operation. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** The compressor of the current data unit. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync PRTZIPCOMP pZipComp;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** The decompressor of the current data unit. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync PRTZIPDECOMP pZipDecomp;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** Number of bytes left in the current data unit. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync uint64_t cbUnitLeft;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Pointer to the progress callback function. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PFNVMPROGRESS pfnProgress;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** User specified arguemnt to the callback function. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync void *pvUser;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Next completion percentage. (corresponds to offEstProgress) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync unsigned uPercent;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** The position of the next progress callback in the estimated file. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint64_t offEstProgress;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** The estimated total byte count.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * (Only valid after the prep.) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint64_t cbEstTotal;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Current position in the estimated file. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync uint64_t offEst;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** End of current unit in the estimated file. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync uint64_t offEstUnitEnd;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** the amount of % we reserve for the 'prepare' phase */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync unsigned uPercentPrepare;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /** the amount of % we reserve for the 'done' stage */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync unsigned uPercentDone;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync} SSMHANDLE;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Header of the saved state file.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsynctypedef struct SSMFILEHDR
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Magic string which identifies this file as a version of VBox saved state file format. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync char achMagic[32];
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync /** The size of this file. Used to check
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync * whether the save completed and that things are fine otherwise. */
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync uint64_t cbFile;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync /** File checksum. The actual calculation skips past the u32CRC field. */
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync uint32_t u32CRC;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync /** The machine UUID. (Ignored if NIL.) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTUUID MachineUuid;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync} SSMFILEHDR, *PSSMFILEHDR;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** Saved state file magic base string. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** Saved state file v1.0 magic. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define SSMFILEHDR_MAGIC_V1 "\177VirtualBox SavedState V1.0\n"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Data unit header.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsynctypedef struct SSMFILEUNITHDR
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Magic. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync char achMagic[8];
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync /** Number of bytes in this data unit including the header. */
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync uint64_t cbUnit;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync /** Data version. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t u32Version;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Instance number. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t u32Instance;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /** Size of the data unit name including the terminator. (bytes) */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t cchName;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /** Data unit name. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync char szName[1];
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync} SSMFILEUNITHDR, *PSSMFILEUNITHDR;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** Data unit magic. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define SSMFILEUNITHDR_MAGIC "\nUnit\n"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/** Data end marker magic. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define SSMFILEUNITHDR_END "\nTheEnd"
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync/*******************************************************************************
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync* Internal Functions *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync*******************************************************************************/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic int smmr3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, PSSMUNIT *ppUnit);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic int ssmr3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncstatic void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic int ssmr3Validate(RTFILE File, PSSMFILEHDR pHdr);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic PSSMUNIT ssmr3Find(PVM pVM, const char *pszName, uint32_t u32Instance);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic int ssmr3WriteFinish(PSSMHANDLE pSSM);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic int ssmr3Write(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic DECLCALLBACK(int) ssmr3WriteOut(void *pvSSM, const void *pvBuf, size_t cbBuf);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic void ssmr3ReadFinish(PSSMHANDLE pSSM);
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsyncstatic int ssmr3Read(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf);
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsyncstatic DECLCALLBACK(int) ssmr3ReadIn(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead);
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync/**
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync * Internal registration worker.
5f2909f8dd32d40a7e87f636c1a7c9de674be94bvboxsync *
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @returns VBox status code.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pVM The VM handle.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pszName Data unit name.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param u32Instance The instance id.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param u32Version The data unit version.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param cbGuess The guessed data unit size.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param ppUnit Where to store the insterted unit node.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Caller must fill in the missing details.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncstatic int smmr3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, PSSMUNIT *ppUnit)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Walk to the end of the list checking for duplicates as we go.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
a771f44b96a464259788456c0c68e049e7588066vboxsync size_t cchName = strlen(pszName);
a771f44b96a464259788456c0c68e049e7588066vboxsync PSSMUNIT pUnitPrev = NULL;
a771f44b96a464259788456c0c68e049e7588066vboxsync PSSMUNIT pUnit = pVM->ssm.s.pHead;
a771f44b96a464259788456c0c68e049e7588066vboxsync while (pUnit)
a771f44b96a464259788456c0c68e049e7588066vboxsync {
a771f44b96a464259788456c0c68e049e7588066vboxsync if ( pUnit->u32Instance == u32Instance
a771f44b96a464259788456c0c68e049e7588066vboxsync && pUnit->cchName == cchName
a771f44b96a464259788456c0c68e049e7588066vboxsync && !memcmp(pUnit->szName, pszName, cchName))
a771f44b96a464259788456c0c68e049e7588066vboxsync {
a771f44b96a464259788456c0c68e049e7588066vboxsync AssertMsgFailed(("Duplicate registration %s\n", pszName));
a771f44b96a464259788456c0c68e049e7588066vboxsync return VERR_SSM_UNIT_EXISTS;
a771f44b96a464259788456c0c68e049e7588066vboxsync }
a771f44b96a464259788456c0c68e049e7588066vboxsync /* next */
a771f44b96a464259788456c0c68e049e7588066vboxsync pUnitPrev = pUnit;
a771f44b96a464259788456c0c68e049e7588066vboxsync pUnit = pUnit->pNext;
a771f44b96a464259788456c0c68e049e7588066vboxsync }
a771f44b96a464259788456c0c68e049e7588066vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Allocate new node.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit = (PSSMUNIT)MMR3HeapAllocZ(pVM, MM_TAG_SSM, RT_OFFSETOF(SSMUNIT, szName[cchName + 1]));
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (!pUnit)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return VERR_NO_MEMORY;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Fill in (some) data. (Stuff is zero'ed.)
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u32Version = u32Version;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u32Instance = u32Instance;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->cbGuess = cbGuess;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit->cchName = cchName;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync memcpy(pUnit->szName, pszName, cchName);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Insert
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync if (pUnitPrev)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnitPrev->pNext = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync pVM->ssm.s.pHead = pUnit;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync *ppUnit = pUnit;
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync return VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Register a PDM Devices data unit.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pVM The VM handle.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pDevIns Device instance.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pszName Data unit name.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param u32Instance The instance identifier of the data unit.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * This must together with the name be unique.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param u32Version Data layout version number.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param cbGuess The approximate amount of data in the unit.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * Only for progress indicators.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param pfnSavePrep Prepare save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnSaveExec Execute save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnSaveDone Done save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadPrep Prepare load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadExec Execute load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadDone Done load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync */
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsyncSSMR3DECL(int) SSMR3Register(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync{
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PSSMUNIT pUnit;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync int rc = smmr3Register(pVM, pszName, u32Instance, u32Version, cbGuess, &pUnit);
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync if (VBOX_SUCCESS(rc))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->enmType = SSMUNITTYPE_DEV;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnSavePrep = pfnSavePrep;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnSaveExec = pfnSaveExec;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnSaveDone = pfnSaveDone;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnLoadPrep = pfnLoadPrep;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnLoadExec = pfnLoadExec;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit->u.Dev.pfnLoadDone = pfnLoadDone;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit->u.Dev.pDevIns = pDevIns;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync}
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync/**
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * Register a PDM driver data unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync *
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @returns VBox status.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pVM The VM handle.
eb381fae3bd3bff1dc6b4a194a9dab770961691evboxsync * @param pDrvIns Driver instance.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pszName Data unit name.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param u32Instance The instance identifier of the data unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * This must together with the name be unique.
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync * @param u32Version Data layout version number.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param cbGuess The approximate amount of data in the unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * Only for progress indicators.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSavePrep Prepare save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSaveExec Execute save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSaveDone Done save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadPrep Prepare load callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadExec Execute load callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadDone Done load callback, optional.
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync */
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsyncSSMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
eb381fae3bd3bff1dc6b4a194a9dab770961691evboxsync PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync{
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync PSSMUNIT pUnit;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync int rc = smmr3Register(pVM, pszName, u32Instance, u32Version, cbGuess, &pUnit);
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync if (VBOX_SUCCESS(rc))
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync {
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->enmType = SSMUNITTYPE_DRV;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnSavePrep = pfnSavePrep;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnSaveExec = pfnSaveExec;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnSaveDone = pfnSaveDone;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnLoadPrep = pfnLoadPrep;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnLoadExec = pfnLoadExec;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pfnLoadDone = pfnLoadDone;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Drv.pDrvIns = pDrvIns;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync }
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync return rc;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync}
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync/**
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * Register a internal data unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync *
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @returns VBox status.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pVM The VM handle.
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync * @param pszName Data unit name.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param u32Instance The instance identifier of the data unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * This must together with the name be unique.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param u32Version Data layout version number.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param cbGuess The approximate amount of data in the unit.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * Only for progress indicators.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSavePrep Prepare save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSaveExec Execute save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnSaveDone Done save callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadPrep Prepare load callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadExec Execute load callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync * @param pfnLoadDone Done load callback, optional.
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync */
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsyncSSMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone)
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync{
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync PSSMUNIT pUnit;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync int rc = smmr3Register(pVM, pszName, u32Instance, u32Version, cbGuess, &pUnit);
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync if (VBOX_SUCCESS(rc))
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync {
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->enmType = SSMUNITTYPE_INTERNAL;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnSavePrep = pfnSavePrep;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnSaveExec = pfnSaveExec;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnSaveDone = pfnSaveDone;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnLoadPrep = pfnLoadPrep;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnLoadExec = pfnLoadExec;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync pUnit->u.Internal.pfnLoadDone = pfnLoadDone;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync }
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync return rc;
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync}
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Register an external data unit.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @returns VBox status.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pVM The VM handle.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pszName Data unit name.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param u32Instance The instance identifier of the data unit.
9f2784134174d879b339a957156bb14151f39fd8vboxsync * This must together with the name be unique.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param u32Version Data layout version number.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param cbGuess The approximate amount of data in the unit.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * Only for progress indicators.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnSavePrep Prepare save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnSaveExec Execute save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnSaveDone Done save callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadPrep Prepare load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadExec Execute load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pfnLoadDone Done load callback, optional.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync * @param pvUser User argument.
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync */
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsyncSSMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync{
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync PSSMUNIT pUnit;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync int rc = smmr3Register(pVM, pszName, u32Instance, u32Version, cbGuess, &pUnit);
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync if (VBOX_SUCCESS(rc))
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync {
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->enmType = SSMUNITTYPE_EXTERNAL;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnSavePrep = pfnSavePrep;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnSaveExec = pfnSaveExec;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnSaveDone = pfnSaveDone;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnLoadPrep = pfnLoadPrep;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnLoadExec = pfnLoadExec;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pfnLoadDone = pfnLoadDone;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync pUnit->u.External.pvUser = pvUser;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync }
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync return rc;
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync}
ba05e6aeed3cd14961a36e0162c29a267b66d7f7vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Deregister one or more PDM Device data units.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pVM The VM handle.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pDevIns Device instance.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pszName Data unit name.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Use NULL to deregister all data units for that device instance.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param u32Instance The instance identifier of the data unit.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * This must together with the name be unique.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @remark Only for dynmaic data units and dynamic unloaded modules.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncSSMR3DECL(int) SSMR3Deregister(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Validate input.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!pDevIns)
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AssertMsgFailed(("pDevIns is NULL!\n"));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_INVALID_PARAMETER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Search the list.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync size_t cchName = pszName ? strlen(pszName) : 0;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pUnitPrev = NULL;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pUnit = pVM->ssm.s.pHead;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync while (pUnit)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if ( pUnit->enmType == SSMUNITTYPE_DEV
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && ( !pszName
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync || ( pUnit->cchName == cchName
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync && !memcmp(pUnit->szName, pszName, cchName)))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && pUnit->u32Instance == u32Instance
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync )
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnit->u.Dev.pDevIns == pDevIns)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Unlink it, advance pointer, and free the node.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pFree = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit = pUnit->pNext;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnitPrev)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnitPrev->pNext = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pVM->ssm.s.pHead = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Log(("SSM: Removed data unit '%s' (pdm dev).\n", pFree->szName));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync MMR3HeapFree(pFree);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pszName)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync continue;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else if (pszName)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->u.Dev.pDevIns, pDevIns, pszName));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_SSM_UNIT_NOT_OWNER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* next */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnitPrev = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit = pUnit->pNext;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Deregister one ore more PDM Driver data units.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pVM The VM handle.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pDrvIns Driver instance.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pszName Data unit name.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Use NULL to deregister all data units for that driver instance.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param u32Instance The instance identifier of the data unit.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * This must together with the name be unique. Ignored if pszName is NULL.
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync * @remark Only for dynmaic data units and dynamic unloaded modules.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncSSMR3DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Validate input.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!pDrvIns)
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync {
6320f517ddc16e8d8dd450a47edfaab81f67942avboxsync AssertMsgFailed(("pDrvIns is NULL!\n"));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_INVALID_PARAMETER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Search the list.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync size_t cchName = pszName ? strlen(pszName) : 0;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pUnitPrev = NULL;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync PSSMUNIT pUnit = pVM->ssm.s.pHead;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync while (pUnit)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if ( pUnit->enmType == SSMUNITTYPE_DRV
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync && ( !pszName
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync || ( pUnit->cchName == cchName
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && !memcmp(pUnit->szName, pszName, cchName)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && pUnit->u32Instance == u32Instance))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync )
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnit->u.Drv.pDrvIns == pDrvIns)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Unlink it, advance pointer, and free the node.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pFree = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit = pUnit->pNext;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnitPrev)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnitPrev->pNext = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pVM->ssm.s.pHead = pUnit;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync MMR3HeapFree(pFree);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pszName)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = VINF_SUCCESS;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync continue;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync else if (pszName)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit->u.Drv.pDrvIns, pDrvIns, pszName));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_SSM_UNIT_NOT_OWNER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* next */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnitPrev = pUnit;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit = pUnit->pNext;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Deregister a data unit.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pVM The VM handle.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param enmType Unit type
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pszName Data unit name.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @remark Only for dynmaic data units.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic int ssmR3DeregisterByNameAndType(PVM pVM, const char *pszName, SSMUNITTYPE enmType)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Validate input.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!pszName)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync {
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync AssertMsgFailed(("pszName is NULL!\n"));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_INVALID_PARAMETER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Search the list.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync size_t cchName = strlen(pszName);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync int rc = VERR_SSM_UNIT_NOT_FOUND;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pUnitPrev = NULL;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync PSSMUNIT pUnit = pVM->ssm.s.pHead;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync while (pUnit)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if ( pUnit->enmType == enmType
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync && pUnit->cchName == cchName
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && !memcmp(pUnit->szName, pszName, cchName))
41b3442e21c3a79f3bc61ce67e3445757a83f281vboxsync {
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Unlink it, advance pointer, and free the node.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync PSSMUNIT pFree = pUnit;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit = pUnit->pNext;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (pUnitPrev)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnitPrev->pNext = pUnit;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync else
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pVM->ssm.s.pHead = pUnit;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync Log(("SSM: Removed data unit '%s' (type=%d).\n", pFree->szName, enmType));
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync MMR3HeapFree(pFree);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return VINF_SUCCESS;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /* next */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnitPrev = pUnit;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pUnit = pUnit->pNext;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return rc;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync}
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync/**
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Deregister an internal data unit.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @returns VBox status.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pVM The VM handle.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param pszName Data unit name.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @remark Only for dynmaic data units.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncSSMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync{
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_INTERNAL);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync}
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Deregister an external data unit.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param pVM The VM handle.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pszName Data unit name.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @remark Only for dynmaic data units.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncSSMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_EXTERNAL);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Calculate the checksum of a file portion.
2294b1479e3fb6f4e9c9550b3e15f3d3a3f1fc24vboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * The current implementation is a cut&past of the libkern/crc32.c file from FreeBSD.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @returns VBox status.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * @param File Handle to the file.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param cbFile Size of the file.
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync * @param pu32CRC Where to store the calculated checksum.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic int ssmr3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Allocate a buffer.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync void *pvBuf = RTMemTmpAlloc(32*1024);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (!pvBuf)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_NO_TMP_MEMORY;
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Loop reading and calculating CRC32.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int rc = VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint32_t u32CRC = RTCrc32Start();
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync while (cbFile)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* read chunk */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync register unsigned cbToRead = 32*1024;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (cbFile < 32*1024)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cbToRead = (unsigned)cbFile;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = RTFileRead(File, pvBuf, cbToRead, NULL);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_FAILURE(rc))
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AssertMsgFailed(("Failed with rc=%Vrc while calculating crc.\n", rc));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTMemTmpFree(pvBuf);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* update total */
2294b1479e3fb6f4e9c9550b3e15f3d3a3f1fc24vboxsync cbFile -= cbToRead;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* calc crc32. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync RTMemTmpFree(pvBuf);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* store the calculated crc */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync u32CRC = RTCrc32Finish(u32CRC);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Log(("SSM: u32CRC=0x%08x\n", u32CRC));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *pu32CRC = u32CRC;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Works the progress calculation.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync *
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param pSSM The SSM handle.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * @param cbAdvance Number of bytes to advance
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Can't advance it beyond the estimated end of the unit. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (cbAdvance > cbLeft)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cbAdvance = cbLeft;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pSSM->offEst += cbAdvance;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync while (pSSM->offEst >= pSSM->offEstProgress && pSSM->uPercent <= 100-pSSM->uPercentDone)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pSSM->pfnProgress)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pSSM->uPercent++;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal /
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync (100-pSSM->uPercentDone-pSSM->uPercentPrepare);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync}
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/**
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Start VM save operation.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * The caller must be the emulation thread!
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync *
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync * @returns VBox status.
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync * @param pVM The VM handle.
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync * @param pszFilename Name of the file to save the state in.
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync * @param enmAfter What is planned after a successful save operation.
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync * @param pfnProgress Progress callback. Optional.
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync * @param pvUser User argument for the progress callback.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncSSMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync{
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Validate input.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (enmAfter != SSMAFTER_DESTROY && enmAfter != SSMAFTER_CONTINUE)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return VERR_INVALID_PARAMETER;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Try open the file.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMHANDLE Handle = {0};
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.enmAfter = enmAfter;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Handle.pVM = pVM;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.pfnProgress = pfnProgress;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.pvUser = pvUser;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * The 'done' part might take much time:
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * (1) Call the SaveDone function of each module
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * (2) Calculate the Checksum
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * (3) RTFileClose() will probably flush the write cache
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.uPercentPrepare = 2;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.uPercentDone = 20; /* reserve substantial time for crc-checking the image */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (VBOX_FAILURE(rc))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync LogRel(("SSM: Failed to create save state file '%s', rc=%Vrc.\n", pszFilename, rc));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync return rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Write header.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMFILEHDR Hdr = { SSMFILEHDR_MAGIC_V1, 0, 0 };
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = RTFileWrite(Handle.File, &Hdr, sizeof(Hdr), NULL);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * Clear the per unit flags.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync PSSMUNIT pUnit;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit->fCalled = false;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Do the prepare run.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Handle.rc = VINF_SUCCESS;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.enmOp = SSMSTATE_SAVE_PREP;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync switch (pUnit->enmType)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_DEV:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnit->u.Dev.pfnSavePrep)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->fCalled = true;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync case SSMUNITTYPE_DRV:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pUnit->u.Drv.pfnSavePrep)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pUnit->fCalled = true;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_INTERNAL:
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync if (pUnit->u.Internal.pfnSavePrep)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->fCalled = true;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync case SSMUNITTYPE_EXTERNAL:
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync if (pUnit->u.External.pfnSavePrep)
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync {
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->fCalled = true;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_FAILURE(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync LogRel(("SSM: Prepare save failed with rc=%Vrc for data unit '%s.\n", rc, pUnit->szName));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.cbEstTotal += pUnit->cbGuess;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Progress. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (pfnProgress)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.uPercent = Handle.uPercentPrepare;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Do the execute run.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Handle.enmOp = SSMSTATE_SAVE_EXEC;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Estimate.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Handle.offEstUnitEnd += pUnit->cbGuess;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Does this unit have a callback? If, not skip it.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync bool fSkip;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync switch (pUnit->enmType)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync case SSMUNITTYPE_DEV: fSkip = pUnit->u.Dev.pfnSaveExec == NULL; break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_DRV: fSkip = pUnit->u.Drv.pfnSaveExec == NULL; break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_INTERNAL: fSkip = pUnit->u.Internal.pfnSaveExec == NULL; break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_EXTERNAL: fSkip = pUnit->u.External.pfnSaveExec == NULL; break;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync default: fSkip = true; break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
40f74699d21578c96f79fa80bd8563a72c7b315cvboxsync if (fSkip)
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync {
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync pUnit->fCalled = true;
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync continue;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Write data unit header
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint64_t offHdr = RTFileTell(Handle.File);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SSMFILEUNITHDR UnitHdr = { SSMFILEUNITHDR_MAGIC, 0, pUnit->u32Version, pUnit->u32Instance, pUnit->cchName + 1, { '\0' } };
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = RTFileWrite(Handle.File, &pUnit->szName[0], pUnit->cchName + 1, NULL);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Call the execute handler.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync switch (pUnit->enmType)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync case SSMUNITTYPE_DEV:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_DRV:
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_INTERNAL:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync case SSMUNITTYPE_EXTERNAL:
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = Handle.rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pUnit->fCalled = true;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_FAILURE(Handle.rc) && VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = Handle.rc;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Flush buffer / end compression stream.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (Handle.pZipComp)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync rc = ssmr3WriteFinish(&Handle);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Update header with correct length.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uint64_t offEnd = RTFileTell(Handle.File);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rc = RTFileSeek(Handle.File, offHdr, RTFILE_SEEK_BEGIN, NULL);
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync if (VBOX_SUCCESS(rc))
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync {
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync UnitHdr.cbUnit = offEnd - offHdr;
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync if (VBOX_SUCCESS(rc))
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync {
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync rc = RTFileSeek(Handle.File, offEnd, RTFILE_SEEK_BEGIN, NULL);
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync if (VBOX_SUCCESS(rc))
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offHdr, UnitHdr.cbUnit, pUnit->szName));
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync else
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync {
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync LogRel(("SSM: Failed ending compression stream. rc=%Vrc\n", rc));
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync break;
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync }
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync else
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync {
aceec09dd145a4d6fb14f2ea75a459cc88b334abvboxsync LogRel(("SSM: Execute save failed with rc=%Vrc for data unit '%s.\n", rc, pUnit->szName));
89de31eab6e960abcacfb70916598ae1c2e7f737vboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_FAILURE(rc))
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync LogRel(("SSM: Failed to write unit header. rc=%Vrc\n", rc));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync break;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync } /* for each unit */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* finish the progress. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (VBOX_SUCCESS(rc))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
41c24e185aa1d6b5dc290edbd061c5a3c23a9e2fvboxsync }
/* (progress should be pending 99% now) */
AssertMsg(VBOX_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
/*
* Do the done run.
*/
Handle.rc = rc;
Handle.enmOp = SSMSTATE_SAVE_DONE;
for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
{
switch (pUnit->enmType)
{
case SSMUNITTYPE_DEV:
if ( pUnit->u.Dev.pfnSaveDone
&& ( pUnit->fCalled
|| (!pUnit->u.Dev.pfnSavePrep && !pUnit->u.Dev.pfnSaveExec)))
rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle);
break;
case SSMUNITTYPE_DRV:
if ( pUnit->u.Drv.pfnSaveDone
&& ( pUnit->fCalled
|| (!pUnit->u.Drv.pfnSavePrep && !pUnit->u.Drv.pfnSaveExec)))
rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle);
break;
case SSMUNITTYPE_INTERNAL:
if ( pUnit->u.Internal.pfnSaveDone
&& ( pUnit->fCalled
|| (!pUnit->u.Internal.pfnSavePrep && !pUnit->u.Internal.pfnSaveExec)))
rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle);
break;
case SSMUNITTYPE_EXTERNAL:
if ( pUnit->u.External.pfnSaveDone
&& ( pUnit->fCalled
|| (!pUnit->u.External.pfnSavePrep && !pUnit->u.External.pfnSaveExec)))
rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser);
break;
}
if (VBOX_FAILURE(rc))
{
LogRel(("SSM: Done save failed with rc=%Vrc for data unit '%s.\n", rc, pUnit->szName));
if (VBOX_SUCCESS(Handle.rc))
Handle.rc = rc;
}
}
rc = Handle.rc;
/*
* Finalize the file if successfully saved.
*/
if (VBOX_SUCCESS(rc))
{
/* end record */
SSMFILEUNITHDR UnitHdr = { SSMFILEUNITHDR_END, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), 0, '\0'};
rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
if (VBOX_SUCCESS(rc))
{
/* get size */
Hdr.cbFile = RTFileTell(Handle.File);
/* calc checksum */
rc = RTFileSeek(Handle.File, RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(Hdr.u32CRC), RTFILE_SEEK_BEGIN, NULL);
if (VBOX_SUCCESS(rc))
rc = ssmr3CalcChecksum(Handle.File, Hdr.cbFile - sizeof(Hdr), &Hdr.u32CRC);
if (VBOX_SUCCESS(rc))
{
if (pfnProgress)
pfnProgress(pVM, 90, pvUser);
/*
* Write the update the header to the file.
*/
rc = RTFileSeek(Handle.File, 0, RTFILE_SEEK_BEGIN, NULL);
if (VBOX_SUCCESS(rc))
rc = RTFileWrite(Handle.File, &Hdr, sizeof(Hdr), NULL);
if (VBOX_SUCCESS(rc))
{
rc = RTFileClose(Handle.File);
AssertRC(rc);
if (pfnProgress)
pfnProgress(pVM, 100, pvUser);
Log(("SSM: Successfully saved the vm state to '%s'.\n", pszFilename));
Log(("\n\n\n"));
DBGFR3InfoLog(pVM, "cpum", "verbose");
DBGFR3InfoLog(pVM, "timers", NULL);
DBGFR3InfoLog(pVM, "activetimers", NULL);
DBGFR3InfoLog(pVM, "ioport", NULL);
DBGFR3InfoLog(pVM, "mmio", NULL);
DBGFR3InfoLog(pVM, "phys", NULL);
Log(("\n\n\n"));
return VINF_SUCCESS;
}
}
}
LogRel(("SSM: Failed to finalize state file! rc=%Vrc\n", pszFilename));
}
}
/*
* Delete the file on failure and destroy any compressors.
*/
int rc2 = RTFileClose(Handle.File);
AssertRC(rc2);
rc2 = RTFileDelete(pszFilename);
AssertRC(rc2);
if (Handle.pZipComp)
RTZipCompDestroy(Handle.pZipComp);
return rc;
}
/**
* Validates the integrity of a saved state file.
*
* @returns VBox status.
* @param File File to validate.
* The file position is undefined on return.
* @param pHdr Where to store the file header.
*/
static int ssmr3Validate(RTFILE File, PSSMFILEHDR pHdr)
{
/*
* Read the header.
*/
int rc = RTFileRead(File, pHdr, sizeof(*pHdr), NULL);
if (VBOX_FAILURE(rc))
{
Log(("SSM: Failed to read file header. rc=%Vrc\n", rc));
return rc;
}
/*
* Verify the magic.
*/
if (memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
{
Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(pHdr->achMagic) - 1, pHdr->achMagic));
return VERR_SSM_INTEGRITY_MAGIC;
}
if (memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_V1, sizeof(SSMFILEHDR_MAGIC_V1)))
{
Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(pHdr->achMagic) - 1, pHdr->achMagic));
return VERR_SSM_INTEGRITY_VERSION;
}
/*
* Verify the file size.
*/
uint64_t cbFile;
rc = RTFileGetSize(File, &cbFile);
if (VBOX_FAILURE(rc))
{
Log(("SSM: Failed to get file size. rc=%Vrc\n", rc));
return rc;
}
if (cbFile != pHdr->cbFile)
{
Log(("SSM: File size mistmatch. hdr.cbFile=%lld actual %lld\n", pHdr->cbFile, cbFile));
return VERR_SSM_INTEGRITY_SIZE;
}
/*
* Verify the checksum.
*/
rc = RTFileSeek(File, RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(pHdr->u32CRC), RTFILE_SEEK_BEGIN, NULL);
if (VBOX_FAILURE(rc))
{
Log(("SSM: Failed to seek to crc start. rc=%Vrc\n", rc));
return rc;
}
uint32_t u32CRC;
rc = ssmr3CalcChecksum(File, pHdr->cbFile - sizeof(*pHdr), &u32CRC);
if (VBOX_FAILURE(rc))
return rc;
if (u32CRC != pHdr->u32CRC)
{
Log(("SSM: Invalid CRC! Calculated %#08x, in header %#08x\n", u32CRC, pHdr->u32CRC));
return VERR_SSM_INTEGRITY_CRC;
}
/*
* Verify Virtual Machine UUID.
*/
RTUUID Uuid;
memset(&Uuid, 0, sizeof(Uuid));
/** @todo get machine uuids CFGGetUuid(, &Uuid); */
if ( RTUuidCompare(&pHdr->MachineUuid, &Uuid)
&& !RTUuidIsNull(&pHdr->MachineUuid)) /* temporary hack, allowing NULL uuids. */
{
Log(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
return VERR_SMM_INTEGRITY_MACHINE;
}
return VINF_SUCCESS;
}
/**
* 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.
*/
static PSSMUNIT ssmr3Find(PVM pVM, const char *pszName, uint32_t u32Instance)
{
size_t cchName = strlen(pszName);
PSSMUNIT pUnit = pVM->ssm.s.pHead;
while ( pUnit
&& ( pUnit->u32Instance != u32Instance
|| pUnit->cchName != cchName
|| memcmp(pUnit->szName, pszName, cchName)))
pUnit = pUnit->pNext;
return pUnit;
}
/**
* Load VM save operation.
* The caller must be the emulation thread!
*
* @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.
*/
SSMR3DECL(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)
{
AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
return VERR_INVALID_PARAMETER;
}
/*
* Open the file.
*/
SSMHANDLE Handle = {0};
Handle.enmAfter = enmAfter;
Handle.pVM = pVM;
Handle.pfnProgress = pfnProgress;
Handle.pvUser = pvUser;
Handle.uPercentPrepare = 20; /* reserve substantial time for validating the image */
Handle.uPercentDone = 2;
int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (VBOX_FAILURE(rc))
{
Log(("SSM: Failed to open save state file '%s', rc=%Vrc.\n", pszFilename, rc));
return rc;
}
/*
* Read file header and validate it.
*/
SSMFILEHDR Hdr;
rc = ssmr3Validate(Handle.File, &Hdr);
if (VBOX_SUCCESS(rc))
{
/*
* Clear the per unit flags.
*/
PSSMUNIT pUnit;
for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
pUnit->fCalled = false;
/*
* Do the prepare run.
*/
Handle.rc = VINF_SUCCESS;
Handle.enmOp = SSMSTATE_LOAD_PREP;
for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
{
switch (pUnit->enmType)
{
case SSMUNITTYPE_DEV:
if (pUnit->u.Dev.pfnLoadPrep)
{
rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
pUnit->fCalled = true;
}
break;
case SSMUNITTYPE_DRV:
if (pUnit->u.Drv.pfnLoadPrep)
{
rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
pUnit->fCalled = true;
}
break;
case SSMUNITTYPE_INTERNAL:
if (pUnit->u.Internal.pfnLoadPrep)
{
rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
pUnit->fCalled = true;
}
break;
case SSMUNITTYPE_EXTERNAL:
if (pUnit->u.External.pfnLoadPrep)
{
rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
pUnit->fCalled = true;
}
break;
}
if (VBOX_FAILURE(rc))
{
LogRel(("SSM: Prepare load failed with rc=%Vrc for data unit '%s.\n", rc, pUnit->szName));
break;
}
}
/* pending 2% */
if (pfnProgress)
pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
Handle.uPercent = Handle.uPercentPrepare;
Handle.cbEstTotal = Hdr.cbFile;
/*
* Do the execute run.
*/
if (VBOX_SUCCESS(rc))
rc = RTFileSeek(Handle.File, sizeof(Hdr), RTFILE_SEEK_BEGIN, NULL);
if (VBOX_SUCCESS(rc))
{
char *pszName = NULL;
size_t cchName = 0;
Handle.enmOp = SSMSTATE_LOAD_EXEC;
for (;;)
{
/*
* Save the current file position and read the data unit header.
*/
uint64_t offUnit = RTFileTell(Handle.File);
SSMFILEUNITHDR UnitHdr;
rc = RTFileRead(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
if (VBOX_SUCCESS(rc))
{
/*
* Check the magic and see if it's valid and whether it is a end header or not.
*/
if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
{
if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
{
Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
/* Complete the progress bar (pending 99% afterwards). */
Handle.offEstUnitEnd = Handle.cbEstTotal;
ssmR3Progress(&Handle, Handle.cbEstTotal - Handle.offEst);
break;
}
LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
break;
}
/*
* Read the name.
* Adjust the name buffer first.
*/
if (cchName < UnitHdr.cchName)
{
if (pszName)
RTMemTmpFree(pszName);
cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
pszName = (char *)RTMemTmpAlloc(cchName);
}
if (pszName)
{
rc = RTFileRead(Handle.File, pszName, UnitHdr.cchName, NULL);
if (VBOX_SUCCESS(rc))
{
if (!pszName[UnitHdr.cchName - 1])
{
Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
/*
* Progress
*/
Handle.offEstUnitEnd += UnitHdr.cbUnit;
/*
* Find the data unit in our internal table.
*/
pUnit = ssmr3Find(pVM, pszName, UnitHdr.u32Instance);
if (pUnit)
{
/*
* Call the execute handler.
*/
Handle.cbUnitLeft = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
switch (pUnit->enmType)
{
case SSMUNITTYPE_DEV:
if (pUnit->u.Dev.pfnLoadExec)
rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, &Handle, UnitHdr.u32Version);
else
rc = VERR_SSM_NO_LOAD_EXEC;
break;
case SSMUNITTYPE_DRV:
if (pUnit->u.Drv.pfnLoadExec)
rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, &Handle, UnitHdr.u32Version);
else
rc = VERR_SSM_NO_LOAD_EXEC;
break;
case SSMUNITTYPE_INTERNAL:
if (pUnit->u.Internal.pfnLoadExec)
rc = pUnit->u.Internal.pfnLoadExec(pVM, &Handle, UnitHdr.u32Version);
else
rc = VERR_SSM_NO_LOAD_EXEC;
break;
case SSMUNITTYPE_EXTERNAL:
if (pUnit->u.External.pfnLoadExec)
{
rc = pUnit->u.External.pfnLoadExec(&Handle, pUnit->u.External.pvUser, UnitHdr.u32Version);
if (!rc)
rc = Handle.rc;
}
else
rc = VERR_SSM_NO_LOAD_EXEC;
break;
}
if (rc != VERR_SSM_NO_LOAD_EXEC)
{
/*
* Close the reader stream.
*/
if (Handle.pZipDecomp)
ssmr3ReadFinish(&Handle);
pUnit->fCalled = true;
if (VBOX_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.
*/
uint64_t off = RTFileTell(Handle.File);
int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
if (i64Diff < 0)
{
Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
rc = RTFileSeek(Handle.File, offUnit + UnitHdr.cbUnit, RTFILE_SEEK_BEGIN, NULL);
}
else if (i64Diff > 0)
{
LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
rc = VERR_SSM_INTEGRITY;
break;
}
/* Advance the progress bar to the end of the block. */
ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
}
else
{
LogRel(("SSM: LoadExec failed with rc=%Vrc for unit '%s'!\n", rc, pszName));
break;
}
}
else
{
LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
rc = VERR_SSM_INTEGRITY;
break;
}
}
else
{
LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
break;
}
}
else
{
LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
rc = VERR_SSM_INTEGRITY;
break;
}
}
}
else
rc = VERR_NO_TMP_MEMORY;
}
/*
* I/O errors ends up here (yea, I know, very nice programming).
*/
if (VBOX_FAILURE(rc))
{
LogRel(("SSM: I/O error. rc=%Vrc\n", rc));
break;
}
}
}
/* (progress should be pending 99% now) */
AssertMsg(VBOX_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
/*
* Do the done run.
*/
Handle.rc = rc;
Handle.enmOp = SSMSTATE_LOAD_DONE;
for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
{
rc = VINF_SUCCESS;
switch (pUnit->enmType)
{
case SSMUNITTYPE_DEV:
if ( pUnit->u.Dev.pfnLoadDone
&& ( pUnit->fCalled
|| (!pUnit->u.Dev.pfnLoadPrep && !pUnit->u.Dev.pfnLoadExec)))
rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
break;
case SSMUNITTYPE_DRV:
if ( pUnit->u.Drv.pfnLoadDone
&& ( pUnit->fCalled
|| (!pUnit->u.Drv.pfnLoadPrep && !pUnit->u.Drv.pfnLoadExec)))
rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
break;
case SSMUNITTYPE_INTERNAL:
if (pUnit->u.Internal.pfnLoadDone
&& ( pUnit->fCalled
|| (!pUnit->u.Internal.pfnLoadPrep && !pUnit->u.Internal.pfnLoadExec)))
rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
break;
case SSMUNITTYPE_EXTERNAL:
if (pUnit->u.External.pfnLoadDone
&& ( pUnit->fCalled
|| (!pUnit->u.Internal.pfnLoadPrep && !pUnit->u.Internal.pfnLoadExec)))
rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
break;
}
if (VBOX_FAILURE(rc))
{
LogRel(("SSM: Done load failed with rc=%Vrc for data unit '%s'.\n", rc, pUnit->szName));
if (VBOX_SUCCESS(Handle.rc))
Handle.rc = rc;
}
}
rc = Handle.rc;
/* progress */
if (pfnProgress)
pfnProgress(pVM, 99, pvUser);
}
/*
* Done
*/
int rc2 = RTFileClose(Handle.File);
AssertRC(rc2);
if (VBOX_SUCCESS(rc))
{
/* progress */
if (pfnProgress)
pfnProgress(pVM, 100, pvUser);
Log(("SSM: Load of '%s' completed!\n", pszFilename));
Log(("\n\n\n"));
DBGFR3InfoLog(pVM, "cpum", "verbose");
DBGFR3InfoLog(pVM, "timers", NULL);
DBGFR3InfoLog(pVM, "activetimers", NULL);
DBGFR3InfoLog(pVM, "ioport", NULL);
DBGFR3InfoLog(pVM, "mmio", NULL);
DBGFR3InfoLog(pVM, "phys", NULL);
Log(("\n\n\n"));
}
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.
*/
SSMR3DECL(int) SSMR3ValidateFile(const char *pszFilename)
{
LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s}\n", pszFilename, pszFilename));
/*
* Try open the file and validate it.
*/
RTFILE File;
int rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (VBOX_SUCCESS(rc))
{
SSMFILEHDR Hdr;
rc = ssmr3Validate(File, &Hdr);
RTFileClose(File);
}
else
Log(("SSM: Failed to open saved state file '%s', rc=%Vrc.\n", pszFilename, rc));
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.
*/
SSMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
{
LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
/*
* Validate input.
*/
AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
/*
* Allocate a handle.
*/
PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
AssertReturn(pSSM, VERR_NO_MEMORY);
/*
* Try open the file and validate it.
*/
int rc = RTFileOpen(&pSSM->File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (VBOX_SUCCESS(rc))
{
SSMFILEHDR Hdr;
rc = ssmr3Validate(pSSM->File, &Hdr);
if (VBOX_SUCCESS(rc))
{
//pSSM->pVM = NULL;
pSSM->enmOp = SSMSTATE_OPEN_READ;
pSSM->enmAfter = SSMAFTER_OPENED;
pSSM->uPercentPrepare = 20; /* reserve substantial time for validating the image */
pSSM->uPercentDone = 2;
//pSSM->rc = VINF_SUCCESS;
//pSSM->pZipComp = NULL;
//pSSM->pZipDecomp = NULL;
//pSSM->cbUnitLeft = 0;
//pSSM->pfnProgress = NULL;
//pSSM->pvUser = NULL;
//pSSM->uPercent = 0;
//pSSM->offEstProgress= 0;
//pSSM->cbEstTotal = 0;
//pSSM->offEst = 0;
//pSSM->offEstUnitEnd = 0;
*ppSSM = pSSM;
LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
return VINF_SUCCESS;
}
Log(("SSMR3Open: Validation of '%s' failed, rc=%Vrc.\n", pszFilename, rc));
RTFileClose(pSSM->File);
}
else
Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Vrc.\n", pszFilename, rc));
RTMemFree(pSSM);
return rc;
}
/**
* Closes a saved state file opened by SSMR3Open().
*
* @returns VBox status code.
* @param pSSM The SSM handle returned by SSMR3Open().
*/
SSMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
{
LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
/*
* Validate input.
*/
AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
/*
* Close the file and free the handle.
*/
int rc = RTFileClose(pSSM->File);
AssertRC(rc);
RTMemFree(pSSM);
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)
*/
SSMR3DECL(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",
pSSM, pszUnit, iInstance, piVersion));
/*
* Validate input.
*/
AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
AssertMsgReturn(VALID_PTR(pszUnit), ("%p\n", pszUnit), VERR_INVALID_POINTER);
AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
/*
* Reset the state.
*/
if (pSSM->pZipDecomp)
{
RTZipDecompDestroy(pSSM->pZipDecomp);
pSSM->pZipDecomp = NULL;
}
pSSM->rc = VERR_SSM_UNIT_NOT_FOUND;
pSSM->cbUnitLeft = 0;
/*
* Walk the data units until we find EOF or a match.
*/
size_t cchUnit = strlen(pszUnit) + 1;
int rc = VINF_SUCCESS;
char *pszName = NULL;
size_t cchName = 0;
SSMFILEUNITHDR UnitHdr;
for (RTFOFF off = sizeof(SSMFILEHDR); ; off += UnitHdr.cbUnit)
{
/*
* Read the unit header and verify it.
*/
rc = RTFileReadAt(pSSM->File, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
AssertRC(rc);
if (VBOX_SUCCESS(rc))
{
if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
{
/*
* Does it match thus far or should we just skip along?
*/
if ( UnitHdr.u32Instance != iInstance
&& UnitHdr.cchName != cchUnit)
continue;
/*
* Read the name.
* Adjust the name buffer first.
*/
if (cchName < UnitHdr.cchName)
{
if (pszName)
RTMemTmpFree(pszName);
cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
pszName = (char *)RTMemTmpAlloc(cchName);
}
rc = VERR_NO_MEMORY;
if (pszName)
{
rc = RTFileRead(pSSM->File, pszName, UnitHdr.cchName, NULL);
AssertRC(rc);
if (VBOX_SUCCESS(rc))
{
if (!pszName[UnitHdr.cchName - 1])
{
/*
* Does the name match? If not continue with the next item.
*/
if (memcmp(pszName, pszUnit, cchUnit))
continue;
pSSM->rc = rc = VINF_SUCCESS;
pSSM->cbUnitLeft = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
if (piVersion)
*piVersion = UnitHdr.u32Version;
}
else
{
AssertMsgFailed((" Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
rc = VERR_SSM_INTEGRITY;
}
}
}
}
else
{
if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
rc = VERR_SSM_UNIT_NOT_FOUND;
else
{
AssertMsgFailed(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
}
}
}
/* error or success, two continue statements cover the iterating */
break;
}
RTMemFree(pszName);
return rc;
}
/**
* Finishes a data unit.
* All buffers and compressor instances are flushed and destroyed.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
*/
static int ssmr3WriteFinish(PSSMHANDLE pSSM)
{
//Log2(("ssmr3WriteFinish: %#010llx start\n", RTFileTell(pSSM->File)));
if (!pSSM->pZipComp)
return VINF_SUCCESS;
int rc = RTZipCompFinish(pSSM->pZipComp);
if (VBOX_SUCCESS(rc))
{
rc = RTZipCompDestroy(pSSM->pZipComp);
if (VBOX_SUCCESS(rc))
{
pSSM->pZipComp = NULL;
//Log2(("ssmr3WriteFinish: %#010llx done\n", RTFileTell(pSSM->File)));
return VINF_SUCCESS;
}
}
if (VBOX_SUCCESS(pSSM->rc))
pSSM->rc = rc;
Log2(("ssmr3WriteFinish: failure rc=%Vrc\n", rc));
return rc;
}
/**
* Writes something to the current data item in the saved state file.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
static int ssmr3Write(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
{
Log2(("ssmr3Write: pvBuf=%p cbBuf=%#x %.*Vhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
/*
* Check that everything is fine.
*/
if (VBOX_SUCCESS(pSSM->rc))
{
/*
* First call starts the compression.
*/
if (!pSSM->pZipComp)
{
//int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmr3WriteOut, RTZIPTYPE_ZLIB, RTZIPLEVEL_FAST);
int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmr3WriteOut, RTZIPTYPE_LZF, RTZIPLEVEL_FAST);
if (VBOX_FAILURE(rc))
return rc;
}
/*
* Write the data item in 128kb chunks for progress indicator reasons.
*/
while (cbBuf > 0)
{
size_t cbChunk = RT_MIN(cbBuf, 128*1024);
pSSM->rc = RTZipCompress(pSSM->pZipComp, pvBuf, cbChunk);
if (VBOX_FAILURE(pSSM->rc))
break;
ssmR3Progress(pSSM, cbChunk);
cbBuf -= cbChunk;
pvBuf = (char *)pvBuf + cbChunk;
}
}
return pSSM->rc;
}
/**
* Callback for flusing the output buffer of a compression stream.
*
* @returns VBox status.
* @param pvSSM SSM operation handle.
* @param pvBuf Compressed data.
* @param cbBuf Size of the compressed data.
*/
static DECLCALLBACK(int) ssmr3WriteOut(void *pvSSM, const void *pvBuf, size_t cbBuf)
{
//Log2(("ssmr3WriteOut: %#010llx cbBuf=%#x\n", RTFileTell(((PSSMHANDLE)pvSSM)->File), cbBuf));
int rc = RTFileWrite(((PSSMHANDLE)pvSSM)->File, pvBuf, cbBuf, NULL);
if (VBOX_SUCCESS(rc))
return rc;
Log(("ssmr3WriteOut: RTFileWrite(,,%d) -> %d\n", cbBuf, rc));
return rc;
}
/**
* 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().
*/
SSMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
{
/* begin marker. */
int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
if (VBOX_FAILURE(rc))
return rc;
/* put the fields */
for (PCSSMFIELD pCur = paFields;
pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
pCur++)
{
rc = ssmr3Write(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
if (VBOX_FAILURE(rc))
return rc;
}
/* end marker */
return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
}
/**
* Saves a boolean item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param fBool Item to save.
*/
SSMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
{
uint8_t u8 = fBool; /* enforce 1 byte size */
return ssmr3Write(pSSM, &u8, sizeof(u8));
}
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u8, sizeof(u8));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i8, sizeof(i8));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u16, sizeof(u16));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i16, sizeof(i16));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u32, sizeof(u32));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i32, sizeof(i32));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u64, sizeof(u64));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i64, sizeof(i64));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u128, sizeof(u128));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i128, sizeof(i128));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u, sizeof(u));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i, sizeof(i));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u, sizeof(u));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC natural signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
SSMR3DECL(int) SSMR3PutGCSInt(PSSMHANDLE pSSM, RTGCINT i)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i, sizeof(i));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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
*/
SSMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &GCPhys, sizeof(GCPhys));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &GCPtr, sizeof(GCPtr));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &GCPtr, sizeof(GCPtr));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a HC natural unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
SSMR3DECL(int) SSMR3PutHCUInt(PSSMHANDLE pSSM, RTHCUINT u)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &u, sizeof(u));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a HC natural signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
SSMR3DECL(int) SSMR3PutHCSInt(PSSMHANDLE pSSM, RTHCINT i)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &i, sizeof(i));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &IOPort, sizeof(IOPort));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, &Sel, sizeof(Sel));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
return ssmr3Write(pSSM, pv, cb);
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
{
if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
{
size_t cch = strlen(psz);
if (cch > 1024*1024)
{
AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
return VERR_TOO_MUCH_DATA;
}
uint32_t u32 = (uint32_t)cch;
int rc = ssmr3Write(pSSM, &u32, sizeof(u32));
if (rc)
return rc;
return ssmr3Write(pSSM, psz, cch);
}
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* Closes the decompressor of a data unit.
*
* @param pSSM SSM operation handle.
*/
static void ssmr3ReadFinish(PSSMHANDLE pSSM)
{
int rc = RTZipDecompDestroy(pSSM->pZipDecomp);
AssertRC(rc);
pSSM->pZipDecomp = NULL;
}
/**
* Internal read worker.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
static int ssmr3Read(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
{
/*
* Check that everything is fine.
*/
if (VBOX_SUCCESS(pSSM->rc))
{
/*
* Open the decompressor on the first read.
*/
if (!pSSM->pZipDecomp)
{
pSSM->rc = RTZipDecompCreate(&pSSM->pZipDecomp, pSSM, ssmr3ReadIn);
if (VBOX_FAILURE(pSSM->rc))
return pSSM->rc;
}
/*
* Do the requested read.
* Use 32kb chunks to work the progress indicator.
*/
pSSM->rc = RTZipDecompress(pSSM->pZipDecomp, pvBuf, cbBuf, NULL);
if (VBOX_SUCCESS(pSSM->rc))
Log2(("ssmr3Read: pvBuf=%p cbBuf=%#x %.*Vhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
else
AssertMsgFailed(("rc=%Vrc cbBuf=%#x\n", pSSM->rc, cbBuf));
}
return pSSM->rc;
}
/**
* Callback for reading compressed data into the input buffer of the
* decompressor.
*
* @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.
*/
static DECLCALLBACK(int) ssmr3ReadIn(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
{
PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
size_t cbRead = cbBuf;
if (pSSM->cbUnitLeft < cbBuf)
cbRead = (size_t)pSSM->cbUnitLeft;
if (cbRead)
{
//Log2(("ssmr3ReadIn: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->File), cbBuf, cbRead));
int rc = RTFileRead(pSSM->File, pvBuf, cbRead, NULL);
if (VBOX_SUCCESS(rc))
{
pSSM->cbUnitLeft -= cbRead;
if (pcbRead)
*pcbRead = cbRead;
ssmR3Progress(pSSM, cbRead);
return VINF_SUCCESS;
}
Log(("ssmr3ReadIn: RTFileRead(,,%d) -> %d\n", cbRead, rc));
return rc;
}
AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
return VERR_SSM_LOADED_TOO_MUCH;
}
/**
* 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().
*/
SSMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
{
/* begin marker. */
uint32_t u32Magic;
int rc = SSMR3GetU32(pSSM, &u32Magic);
if (VBOX_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_BEGIN)
AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
/* put the fields */
for (PCSSMFIELD pCur = paFields;
pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
pCur++)
{
rc = ssmr3Read(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
if (VBOX_FAILURE(rc))
return rc;
}
/* end marker */
rc = SSMR3GetU32(pSSM, &u32Magic);
if (VBOX_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_END)
AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
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.
*/
SSMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
{
uint8_t u8; /* see SSMR3PutBool */
int rc = ssmr3Read(pSSM, &u8, sizeof(u8));
if (VBOX_SUCCESS(rc))
{
Assert(u8 <= 1);
*pfBool = !!u8;
}
return rc;
}
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu8, sizeof(*pu8));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi8, sizeof(*pi8));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu16, sizeof(*pu16));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi16, sizeof(*pi16));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu32, sizeof(*pu32));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi32, sizeof(*pi32));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu64, sizeof(*pu64));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi64, sizeof(*pi64));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu128, sizeof(*pu128));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi128, sizeof(*pi128));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu, sizeof(*pu));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi, sizeof(*pi));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pu, sizeof(*pu));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC natural signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi Where to store the integer.
*/
SSMR3DECL(int) SSMR3GetGCSInt(PSSMHANDLE pSSM, PRTGCINT pi)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pi, sizeof(*pi));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pGCPhys, sizeof(*pGCPhys));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* 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.
*/
SSMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pGCPtr, sizeof(*pGCPtr));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pGCPtr, sizeof(*pGCPtr));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pIOPort, sizeof(*pIOPort));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pSel, sizeof(*pSel));
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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.
*/
SSMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
return ssmr3Read(pSSM, pv, cb);
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
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').
*/
SSMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
{
return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
}
/**
* 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)
*/
SSMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
{
if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
{
/* read size prefix. */
uint32_t u32;
int rc = SSMR3GetU32(pSSM, &u32);
if (VBOX_SUCCESS(rc))
{
if (pcbStr)
*pcbStr = u32;
if (u32 < cbMax)
{
/* terminate and read string content. */
psz[u32] = '\0';
return ssmr3Read(pSSM, psz, u32);
}
return VERR_TOO_MUCH_DATA;
}
return rc;
}
AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
return VERR_SSM_INVALID_STATE;
}
/**
* 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.
*/
SSMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
{
return pSSM->rc;
}
/**
* 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_*.
*/
SSMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
{
if (VBOX_FAILURE(iStatus))
{
if (VBOX_SUCCESS(pSSM->rc))
pSSM->rc = iStatus;
return pSSM->rc = iStatus;
}
AssertMsgFailed(("iStatus=%d %Vrc\n", iStatus, iStatus));
return VERR_INVALID_PARAMETER;
}
/**
* Query what to do after this operation.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
*/
SSMR3DECL(int) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
{
return pSSM->enmAfter;
}