VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/SSM.cpp@ 84044

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 339.5 KB
RevLine 
[23]1/* $Id: SSM.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
[1]2/** @file
3 * SSM - Saved State Manager.
4 */
5
6/*
[82968]7 * Copyright (C) 2006-2020 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
18
19/** @page pg_ssm SSM - The Saved State Manager
20 *
[13594]21 * The Saved State Manager (SSM) implements facilities for saving and loading a
[21773]22 * VM state in a structural manner using callbacks for named data units.
[1]23 *
[13594]24 * At init time each of the VMM components, Devices, Drivers and one or two
[21773]25 * other things will register data units which they need to save and restore.
26 * Each unit have a unique name (ascii), instance number, and a set of callbacks
27 * associated with it. The name will be used to identify the unit during
28 * restore. The callbacks are for the two operations, save and restore. There
29 * are three callbacks for each of the two - a prepare, a execute and a complete
30 * - giving each component ample opportunity to perform actions both before and
31 * afterwards.
[1]32 *
[21773]33 * The SSM provides a number of APIs for encoding and decoding the data: @see
34 * grp_ssm
[13005]35 *
[13594]36 *
37 *
[21773]38 * @section sec_ssm_live_snapshots Live Snapshots
[13594]39 *
[23801]40 * The live snapshots feature (LS) is similar to teleportation (TP) and was a
41 * natural first step when implementing TP. The main differences between LS and
42 * TP are that after a live snapshot we will have a saved state file, disk image
[21773]43 * snapshots, and the VM will still be running.
44 *
45 * Compared to normal saved stated and snapshots, the difference is in that the
46 * VM is running while we do most of the saving. Prior to LS, there was only
[22807]47 * one round of callbacks during saving and the VM was paused during it. With
48 * LS there are 1 or more passes while the VM is still running and a final one
49 * after it has been paused. The runtime passes are executed on a dedicated
50 * thread running at at the same priority as the EMTs so that the saving doesn't
51 * starve or lose in scheduling questions (note: not implemented yet). The final
[22793]52 * pass is done on EMT(0).
[21773]53 *
[23801]54 * There are a couple of common reasons why LS and TP will fail:
[21773]55 * - Memory configuration changed (PCI memory mappings).
[23801]56 * - Takes too long (TP) / Too much output (LS).
[21773]57 *
58 *
[22807]59 * The live saving sequence is something like this:
[21773]60 *
[23595]61 * -# SSMR3LiveSave is called on EMT0. It returns a saved state
[22807]62 * handle.
63 * -# SSMR3LiveDoStep1 is called on a non-EMT. This will save the major
64 * parts of the state while the VM may still be running.
65 * -# The VM is suspended.
66 * -# SSMR3LiveDoStep2 is called on EMT0 to save the remainder of the state
67 * in the normal way.
68 * -# The client does any necessary reconfiguration of harddisks and
69 * similar.
70 * -# SSMR3LiveDone is called on EMT0 to close the handle.
71 * -# The VM is resumed or powered off and destroyed.
72 *
73 *
[23801]74 * @section sec_ssm_teleportation Teleportation
[21773]75 *
76 * As mentioned in the previous section, the main differences between this and
77 * live snapshots are in where the saved state is written and what state the
78 * local VM is in afterwards - at least from the VMM point of view. The
79 * necessary administrative work - establishing the connection to the remote
80 * machine, cloning the VM config on it and doing lowlevel saved state data
81 * transfer - is taken care of by layer above the VMM (i.e. Main).
82 *
[23801]83 * The SSM data format was made streamable for the purpose of teleportation
[21773]84 * (v1.2 was the last non-streamable version).
85 *
86 *
87 * @section sec_ssm_format Saved State Format
88 *
89 * The stream format starts with a header (SSMFILEHDR) that indicates the
90 * version and such things, it is followed by zero or more saved state units
[22793]91 * (name + instance + pass), and the stream concludes with a footer
[21773]92 * (SSMFILEFTR) that contains unit counts and optionally a checksum for the
93 * entire file. (In version 1.2 and earlier, the checksum was in the header and
94 * there was no footer. This meant that the header was updated after the entire
95 * file was written.)
96 *
97 * The saved state units each starts with a variable sized header
[22793]98 * (SSMFILEUNITHDRV2) that contains the name, instance and pass. The data
[21773]99 * follows the header and is encoded as records with a 2-8 byte record header
100 * indicating the type, flags and size. The first byte in the record header
101 * indicates the type and flags:
102 *
103 * - bits 0..3: Record type:
104 * - type 0: Invalid.
[21797]105 * - type 1: Terminator with CRC-32 and unit size.
106 * - type 2: Raw data record.
[21856]107 * - type 3: Raw data compressed by LZF. The data is prefixed by a 8-bit
[33540]108 * field containing the length of the uncompressed data given in
[21862]109 * 1KB units.
[22025]110 * - type 4: Zero data. The record header is followed by a 8-bit field
111 * counting the length of the zero data given in 1KB units.
112 * - type 5: Named data - length prefixed name followed by the data. This
[21856]113 * type is not implemented yet as we're missing the API part, so
114 * the type assignment is tentative.
[22025]115 * - types 6 thru 15 are current undefined.
[21773]116 * - bit 4: Important (set), can be skipped (clear).
117 * - bit 5: Undefined flag, must be zero.
118 * - bit 6: Undefined flag, must be zero.
119 * - bit 7: "magic" bit, always set.
120 *
121 * Record header byte 2 (optionally thru 7) is the size of the following data
[21862]122 * encoded in UTF-8 style. To make buffering simpler and more efficient during
123 * the save operation, the strict checks enforcing optimal encoding has been
124 * relaxed for the 2 and 3 byte encodings.
[21773]125 *
[21856]126 * (In version 1.2 and earlier the unit data was compressed and not record
127 * based. The unit header contained the compressed size of the data, i.e. it
128 * needed updating after the data was written.)
[21773]129 *
130 *
131 * @section sec_ssm_future Future Changes
132 *
[13594]133 * There are plans to extend SSM to make it easier to be both backwards and
134 * (somewhat) forwards compatible. One of the new features will be being able
[21797]135 * to classify units and data items as unimportant (added to the format in
136 * v2.0). Another suggested feature is naming data items (also added to the
137 * format in v2.0), perhaps by extending the SSMR3PutStruct API. Both features
138 * will require API changes, the naming may possibly require both buffering of
139 * the stream as well as some helper managing them.
[1]140 */
141
142
[57358]143/*********************************************************************************************************************************
144* Header Files *
145*********************************************************************************************************************************/
[1]146#define LOG_GROUP LOG_GROUP_SSM
[35346]147#include <VBox/vmm/ssm.h>
148#include <VBox/vmm/dbgf.h>
[44505]149#include <VBox/vmm/pdmapi.h>
150#include <VBox/vmm/pdmcritsect.h>
[35346]151#include <VBox/vmm/mm.h>
[1]152#include "SSMInternal.h"
[35346]153#include <VBox/vmm/vm.h>
[44347]154#include <VBox/vmm/uvm.h>
[1]155#include <VBox/err.h>
156#include <VBox/log.h>
[12440]157#include <VBox/version.h>
[1]158
[29250]159#include <iprt/asm.h>
[1]160#include <iprt/assert.h>
[31847]161#include <iprt/crc.h>
[1]162#include <iprt/file.h>
[29250]163#include <iprt/mem.h>
[21856]164#include <iprt/param.h>
165#include <iprt/thread.h>
[21866]166#include <iprt/semaphore.h>
[21856]167#include <iprt/string.h>
[1]168#include <iprt/uuid.h>
169#include <iprt/zip.h>
170
171
[57358]172/*********************************************************************************************************************************
173* Defined Constants And Macros *
174*********************************************************************************************************************************/
[21797]175/** The max length of a unit name. */
176#define SSM_MAX_NAME_SIZE 48
177
[13594]178/** Saved state file magic base string. */
[21797]179#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
180/** Saved state file magic indicating version 1.x. */
181#define SSMFILEHDR_MAGIC_V1_X "\177VirtualBox SavedState V1."
[13594]182/** Saved state file v1.1 magic. */
[21797]183#define SSMFILEHDR_MAGIC_V1_1 "\177VirtualBox SavedState V1.1\n"
[15503]184/** Saved state file v1.2 magic. */
[21797]185#define SSMFILEHDR_MAGIC_V1_2 "\177VirtualBox SavedState V1.2\n\0\0\0"
186/** Saved state file v2.0 magic. */
187#define SSMFILEHDR_MAGIC_V2_0 "\177VirtualBox SavedState V2.0\n\0\0\0"
[13594]188
[21797]189/** @name SSMFILEHDR::fFlags
190 * @{ */
[33540]191/** The stream is checksummed up to the footer using CRC-32. */
[21797]192#define SSMFILEHDR_FLAGS_STREAM_CRC32 RT_BIT_32(0)
[23540]193/** Indicates that the file was produced by a live save. */
194#define SSMFILEHDR_FLAGS_STREAM_LIVE_SAVE RT_BIT_32(1)
[21797]195/** @} */
196
197/** The directory magic. */
198#define SSMFILEDIR_MAGIC "\nDir\n\0\0"
199
200/** Saved state file v2.0 magic. */
201#define SSMFILEFTR_MAGIC "\nFooter"
202
[13594]203/** Data unit magic. */
[21797]204#define SSMFILEUNITHDR_MAGIC "\nUnit\n\0"
[13594]205/** Data end marker magic. */
[21797]206#define SSMFILEUNITHDR_END "\nTheEnd"
[13594]207
[21797]208
209/** @name Record Types (data unit)
210 * @{ */
211/** The record type mask. */
212#define SSM_REC_TYPE_MASK UINT8_C(0x0f)
213/** Invalid record. */
214#define SSM_REC_TYPE_INVALID 0
215/** Normal termination record, see SSMRECTERM. */
216#define SSM_REC_TYPE_TERM 1
217/** Raw data. The data follows the size field without further ado. */
218#define SSM_REC_TYPE_RAW 2
[21856]219/** Raw data compressed by LZF.
220 * The record header is followed by a 8-bit field containing the size of the
[22025]221 * uncompressed data in 1KB units. The compressed data is after it. */
[21856]222#define SSM_REC_TYPE_RAW_LZF 3
[22025]223/** Raw zero data.
224 * The record header is followed by a 8-bit field containing the size of the
225 * zero data in 1KB units. */
226#define SSM_REC_TYPE_RAW_ZERO 4
[21797]227/** Named data items.
228 * A length prefix zero terminated string (i.e. max 255) followed by the data. */
[22025]229#define SSM_REC_TYPE_NAMED 5
[21797]230/** Macro for validating the record type.
231 * This can be used with the flags+type byte, no need to mask out the type first. */
232#define SSM_REC_TYPE_IS_VALID(u8Type) ( ((u8Type) & SSM_REC_TYPE_MASK) > SSM_REC_TYPE_INVALID \
233 && ((u8Type) & SSM_REC_TYPE_MASK) <= SSM_REC_TYPE_NAMED )
234/** @} */
235
236/** The flag mask. */
237#define SSM_REC_FLAGS_MASK UINT8_C(0xf0)
238/** The record is important if this flag is set, if clear it can be omitted. */
239#define SSM_REC_FLAGS_IMPORTANT UINT8_C(0x10)
240/** This flag is always set. */
241#define SSM_REC_FLAGS_FIXED UINT8_C(0x80)
242/** Macro for validating the flags.
243 * No need to mask the flags out of the flags+type byte before invoking this macro. */
244#define SSM_REC_FLAGS_ARE_VALID(fFlags) ( ((fFlags) & UINT8_C(0xe0)) == UINT8_C(0x80) )
245
246/** Macro for validating the type and flags byte in a data record. */
247#define SSM_REC_ARE_TYPE_AND_FLAGS_VALID(u8) ( SSM_REC_FLAGS_ARE_VALID(u8) && SSM_REC_TYPE_IS_VALID(u8) )
248
249/** @name SSMRECTERM::fFlags
250 * @{ */
[21858]251/** There is a CRC-32 value for the stream. */
[21797]252#define SSMRECTERM_FLAGS_CRC32 UINT16_C(0x0001)
253/** @} */
254
[33248]255/** Start structure magic. (Isaac Asimov) */
[22554]256#define SSMR3STRUCT_BEGIN UINT32_C(0x19200102)
[33248]257/** End structure magic. (Isaac Asimov) */
[22554]258#define SSMR3STRUCT_END UINT32_C(0x19920406)
[1]259
260
[21797]261/** Number of bytes to log in Log2 and Log4 statements. */
262#define SSM_LOG_BYTES 16
263
[22884]264/** SSMHANDLE::fCancelled value indicating that the operation has been
265 * cancelled. */
266#define SSMHANDLE_CANCELLED UINT32_C(0xdeadbeef)
267/** SSMHANDLE::fCancelled value indicating no cancellation. */
268#define SSMHANDLE_OK UINT32_C(0x77777777)
[21797]269
[22884]270
[21797]271/** Macro for checking the u32CRC field of a structure.
272 * The Msg can assume there are u32ActualCRC and u32CRC in the context. */
273#define SSM_CHECK_CRC32_RET(p, cb, Msg) \
274 do \
275 { \
276 uint32_t u32CRC = (p)->u32CRC; \
277 (p)->u32CRC = 0; \
278 uint32_t u32ActualCRC = RTCrc32((p), (cb)); \
279 (p)->u32CRC = u32CRC; \
280 AssertLogRelMsgReturn(u32ActualCRC == u32CRC, Msg, VERR_SSM_INTEGRITY_CRC); \
281 } while (0)
282
[21862]283/** The number of bytes to compress is one block.
284 * Must be a multiple of 1KB. */
285#define SSM_ZIP_BLOCK_SIZE _4K
286AssertCompile(SSM_ZIP_BLOCK_SIZE / _1K * _1K == SSM_ZIP_BLOCK_SIZE);
[21797]287
[21862]288
[22554]289/**
290 * Asserts that the handle is writable and returns with VERR_SSM_INVALID_STATE
291 * if it isn't.
292 */
293#define SSM_ASSERT_WRITEABLE_RET(pSSM) \
294 AssertMsgReturn( pSSM->enmOp == SSMSTATE_SAVE_EXEC \
295 || pSSM->enmOp == SSMSTATE_LIVE_EXEC,\
296 ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
297
298/**
299 * Asserts that the handle is readable and returns with VERR_SSM_INVALID_STATE
300 * if it isn't.
301 */
302#define SSM_ASSERT_READABLE_RET(pSSM) \
303 AssertMsgReturn( pSSM->enmOp == SSMSTATE_LOAD_EXEC \
304 || pSSM->enmOp == SSMSTATE_OPEN_READ,\
305 ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
306
[22884]307/** Checks for cancellation and returns if pending.
308 * Sets SSMHANDLE::rc to VERR_SSM_CANCELLED (if it still indicates success) and
309 * then returns SSMHANDLE::rc. (Debug logging only.) */
310#define SSM_CHECK_CANCELLED_RET(pSSM) \
311 do \
312 { \
313 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED)) \
314 { \
315 LogFlow(("%Rfn: Cancelled -> VERR_SSM_CANCELLED\n", __PRETTY_FUNCTION__)); \
316 if (RT_SUCCESS((pSSM)->rc)) \
317 (pSSM)->rc = VERR_SSM_CANCELLED; \
318 return (pSSM)->rc; \
319 } \
320 } while (0)
[22554]321
[23542]322/**
323 * Asserts that the handle is somewhat valid. No returns as this is just a
324 * simple safeguard for catching bad API calls. */
[23540]325#define SSM_ASSERT_VALID_HANDLE(pSSM) \
326 do \
327 { \
328 AssertPtr(pSSM); \
[23541]329 Assert(pSSM->enmOp > SSMSTATE_INVALID && pSSM->enmOp < SSMSTATE_END); \
[23540]330 } while (0)
[22884]331
[23540]332
[23771]333/** @def SSM_HOST_IS_MSC_32
334 * Set to 1 if the host is 32-bit MSC, otherwise set to 0.
335 * */
336#if defined(_MSC_VER) && HC_ARCH_BITS == 32
337# define SSM_HOST_IS_MSC_32 1
338#else
339# define SSM_HOST_IS_MSC_32 0
340#endif
341
342
343
[57358]344/*********************************************************************************************************************************
345* Structures and Typedefs *
346*********************************************************************************************************************************/
[13594]347/** SSM state. */
[1]348typedef enum SSMSTATE
349{
[15503]350 SSMSTATE_INVALID = 0,
[22554]351 SSMSTATE_LIVE_PREP,
[22793]352 SSMSTATE_LIVE_STEP1,
[22554]353 SSMSTATE_LIVE_EXEC,
354 SSMSTATE_LIVE_VOTE,
[22793]355 SSMSTATE_LIVE_STEP2,
[15503]356 SSMSTATE_SAVE_PREP,
[1]357 SSMSTATE_SAVE_EXEC,
358 SSMSTATE_SAVE_DONE,
359 SSMSTATE_LOAD_PREP,
360 SSMSTATE_LOAD_EXEC,
361 SSMSTATE_LOAD_DONE,
[23540]362 SSMSTATE_OPEN_READ,
[23541]363 SSMSTATE_END
[1]364} SSMSTATE;
365
[23589]366
[21866]367/** Pointer to a SSM stream buffer. */
368typedef struct SSMSTRMBUF *PSSMSTRMBUF;
369/**
370 * A SSM stream buffer.
371 */
372typedef struct SSMSTRMBUF
373{
374 /** The buffer data. */
375 uint8_t abData[_64K];
[1]376
[21866]377 /** The stream position of this buffer. */
378 uint64_t offStream;
379 /** The amount of buffered data. */
[21871]380 uint32_t cb;
[21866]381 /** End of stream indicator (for read streams only). */
382 bool fEndOfStream;
[24895]383 /** The nano timestamp set by ssmR3StrmGetFreeBuf. */
384 uint64_t NanoTS;
[21866]385 /** Pointer to the next buffer in the chain. */
386 PSSMSTRMBUF volatile pNext;
387} SSMSTRMBUF;
388
[1]389/**
[21866]390 * SSM stream.
391 *
392 * This is a typical producer / consumer setup with a dedicated I/O thread and
393 * fixed number of buffers for read ahead and write back.
394 */
395typedef struct SSMSTRM
396{
[23589]397 /** The stream method table. */
398 PCSSMSTRMOPS pOps;
399 /** The user argument for the stream methods.
400 * For file based streams, this is the file handle and not a pointer. */
401 void *pvUser;
[21866]402
403 /** Write (set) or read (clear) stream. */
404 bool fWrite;
405 /** Termination indicator. */
406 bool volatile fTerminating;
[21871]407 /** Indicates whether it is necessary to seek before the next buffer is
408 * read from the stream. This is used to avoid a seek in ssmR3StrmPeekAt. */
409 bool fNeedSeek;
[21866]410 /** Stream error status. */
411 int32_t volatile rc;
[21871]412 /** The handle of the I/O thread. This is set to nil when not active. */
413 RTTHREAD hIoThread;
[21900]414 /** Where to seek to. */
415 uint64_t offNeedSeekTo;
[21866]416
417 /** The head of the consumer queue.
418 * For save the consumer is the I/O thread. For load the I/O thread is the
419 * producer. */
420 PSSMSTRMBUF volatile pHead;
421 /** Chain of free buffers.
422 * The consumer/producer roles are the inverse of pHead. */
423 PSSMSTRMBUF volatile pFree;
424 /** Event that's signalled when pHead is updated. */
425 RTSEMEVENT hEvtHead;
426 /** Event that's signalled when pFree is updated. */
427 RTSEMEVENT hEvtFree;
428
429 /** List of pending buffers that has been dequeued from pHead and reversed. */
430 PSSMSTRMBUF pPending;
431 /** Pointer to the current buffer. */
432 PSSMSTRMBUF pCur;
433 /** The stream offset of the current buffer. */
434 uint64_t offCurStream;
435 /** The current buffer offset. */
436 uint32_t off;
437 /** Whether we're checksumming reads/writes. */
438 bool fChecksummed;
439 /** The stream CRC if fChecksummed is set. */
440 uint32_t u32StreamCRC;
441 /** How far into the buffer u32StreamCRC is up-to-date.
442 * This may lag behind off as it's desirable to checksum as large blocks as
443 * possible. */
444 uint32_t offStreamCRC;
445} SSMSTRM;
446/** Pointer to a SSM stream. */
447typedef SSMSTRM *PSSMSTRM;
448
449
450/**
[1]451 * Handle structure.
452 */
453typedef struct SSMHANDLE
454{
[21866]455 /** Stream/buffer manager. */
[22884]456 SSMSTRM Strm;
[21866]457
[41783]458 /** Pointer to the VM. */
[22884]459 PVM pVM;
[1]460 /** The current operation. */
[22884]461 SSMSTATE enmOp;
[1]462 /** What to do after save completes. (move the enum) */
[22884]463 SSMAFTER enmAfter;
464 /** Flag indicating that the operation has been cancelled. */
465 uint32_t volatile fCancelled;
[1]466 /** The current rc of the save operation. */
[22884]467 int32_t rc;
[21797]468 /** Number of compressed bytes left in the current data unit (V1). */
[22884]469 uint64_t cbUnitLeftV1;
[42335]470 /** The current compressed? offset into the data unit. */
[22884]471 uint64_t offUnit;
[42335]472 /** The current user data offset into the unit (debug purposes). */
473 uint64_t offUnitUser;
[23540]474 /** Indicates that this is a live save or restore operation. */
475 bool fLiveSave;
[1]476
477 /** Pointer to the progress callback function. */
[22884]478 PFNVMPROGRESS pfnProgress;
[33540]479 /** User specified argument to the callback function. */
[22884]480 void *pvUser;
[1]481 /** Next completion percentage. (corresponds to offEstProgress) */
[22884]482 unsigned uPercent;
[1]483 /** The position of the next progress callback in the estimated file. */
[22884]484 uint64_t offEstProgress;
[1]485 /** The estimated total byte count.
486 * (Only valid after the prep.) */
[22884]487 uint64_t cbEstTotal;
[1]488 /** Current position in the estimated file. */
[22884]489 uint64_t offEst;
[1]490 /** End of current unit in the estimated file. */
[22884]491 uint64_t offEstUnitEnd;
[30396]492 /** The amount of % we reserve for the 'live' stage */
493 unsigned uPercentLive;
494 /** The amount of % we reserve for the 'prepare' phase */
[22884]495 unsigned uPercentPrepare;
[30396]496 /** The amount of % we reserve for the 'done' stage */
[22884]497 unsigned uPercentDone;
[30396]498 /** The lowest value reported via SSMR3HandleReportLivePercent during one
499 * vote run. */
500 unsigned uReportedLivePercent;
[22792]501 /** The filename, NULL if remote stream. */
[22884]502 const char *pszFilename;
[1]503
[21797]504 union
505 {
506 /** Write data. */
507 struct
508 {
509 /** Offset into the databuffer. */
510 uint32_t offDataBuffer;
511 /** Space for the record header. */
512 uint8_t abRecHdr[1+7];
513 /** Data buffer. */
514 uint8_t abDataBuffer[4096];
[24874]515 /** The maximum downtime given as milliseconds. */
516 uint32_t cMsMaxDowntime;
[21797]517 } Write;
518
519 /** Read data. */
520 struct
521 {
[21856]522 /** V1: The decompressor of the current data unit. */
523 PRTZIPDECOMP pZipDecompV1;
[21797]524 /** The major format version number. */
525 uint32_t uFmtVerMajor;
526 /** The minor format version number. */
527 uint32_t uFmtVerMinor;
528
529 /** V2: Unread bytes in the current record. */
530 uint32_t cbRecLeft;
531 /** V2: Bytes in the data buffer. */
532 uint32_t cbDataBuffer;
533 /** V2: Current buffer position. */
534 uint32_t offDataBuffer;
535 /** V2: End of data indicator. */
536 bool fEndOfData;
537 /** V2: The type and flags byte fo the current record. */
538 uint8_t u8TypeAndFlags;
539
[24264]540 /** @name Context info for SSMR3SetLoadError.
541 * @{ */
542 /** Pointer to the header for the current unit. */
543 PSSMUNIT pCurUnit;
544 /** The version of the current unit if in the load exec stage. */
545 uint32_t uCurUnitVer;
546 /** The pass number of the current unit if in the load exec stage. */
547 uint32_t uCurUnitPass;
[24268]548 /** Whether SSMR3SetLoadError[V] has been called.
549 * @note Using ASMAtomicXchgBool because I'm very lazy. */
550 bool volatile fHaveSetError;
[24264]551 /** @} */
552
[21797]553 /** RTGCPHYS size in bytes. (Only applicable when loading/reading.) */
554 unsigned cbGCPhys;
555 /** RTGCPTR size in bytes. (Only applicable when loading/reading.) */
556 unsigned cbGCPtr;
557 /** Whether cbGCPtr is fixed or settable. */
558 bool fFixedGCPtrSize;
559
[23771]560 /** 32-bit MSC saved this? */
561 bool fIsHostMsc32;
[24843]562 /** "Host OS" dot "architecture", picked up from recent SSM data units. */
563 char szHostOSAndArch[32];
[21797]564
565 /** @name Header info (set by ssmR3ValidateFile)
566 * @{ */
567 /** The size of the file header. */
[26526]568 uint32_t cbFileHdr;
[21797]569 /** The major version number. */
570 uint16_t u16VerMajor;
571 /** The minor version number. */
572 uint16_t u16VerMinor;
573 /** The build number. */
574 uint32_t u32VerBuild;
575 /** The SVN revision. */
576 uint32_t u32SvnRev;
577 /** 32 or 64 depending on the host. */
578 uint8_t cHostBits;
[23593]579 /** Whether the stream is checksummed (SSMFILEHDR_FLAGS_STREAM_CRC32). */
580 bool fStreamCrc32;
[21797]581 /** The CRC of the loaded file. */
582 uint32_t u32LoadCRC;
583 /** The size of the load file. */
584 uint64_t cbLoadFile;
585 /** @} */
586
[21856]587 /** V2: Data buffer.
588 * @remarks Be extremely careful when changing the size of this buffer! */
[21797]589 uint8_t abDataBuffer[4096];
[21856]590
[21897]591 /** V2: Decompression buffer for when we cannot use the stream buffer. */
[21856]592 uint8_t abComprBuffer[4096];
[21797]593 } Read;
594 } u;
[1]595} SSMHANDLE;
596
597
598/**
599 * Header of the saved state file.
[15503]600 *
[21797]601 * Added in r5xxxx on 2009-07-2?, VirtualBox v3.0.51.
[1]602 */
603typedef struct SSMFILEHDR
604{
[13594]605 /** Magic string which identifies this file as a version of VBox saved state
[21797]606 * file format (SSMFILEHDR_MAGIC_V2_0). */
607 char szMagic[32];
608 /** The major version number. */
609 uint16_t u16VerMajor;
610 /** The minor version number. */
611 uint16_t u16VerMinor;
612 /** The build number. */
613 uint32_t u32VerBuild;
614 /** The SVN revision. */
615 uint32_t u32SvnRev;
616 /** 32 or 64 depending on the host. */
617 uint8_t cHostBits;
618 /** The size of RTGCPHYS. */
619 uint8_t cbGCPhys;
620 /** The size of RTGCPTR. */
621 uint8_t cbGCPtr;
622 /** Reserved header space - must be zero. */
623 uint8_t u8Reserved;
624 /** The number of units that (may) have stored data in the file. */
625 uint32_t cUnits;
626 /** Flags, see SSMFILEHDR_FLAGS_XXX. */
627 uint32_t fFlags;
[21856]628 /** The maximum size of decompressed data. */
629 uint32_t cbMaxDecompr;
[21797]630 /** The checksum of this header.
631 * This field is set to zero when calculating the checksum. */
632 uint32_t u32CRC;
633} SSMFILEHDR;
634AssertCompileSize(SSMFILEHDR, 64);
635AssertCompileMemberOffset(SSMFILEHDR, u32CRC, 60);
636AssertCompileMemberSize(SSMFILEHDR, szMagic, sizeof(SSMFILEHDR_MAGIC_V2_0));
637/** Pointer to a saved state file header. */
638typedef SSMFILEHDR *PSSMFILEHDR;
639/** Pointer to a const saved state file header. */
640typedef SSMFILEHDR const *PCSSMFILEHDR;
641
642
643/**
644 * Header of the saved state file.
645 *
646 * Added in r40980 on 2008-12-15, VirtualBox v2.0.51.
647 *
648 * @remarks This is a superset of SSMFILEHDRV11.
649 */
650typedef struct SSMFILEHDRV12
651{
652 /** Magic string which identifies this file as a version of VBox saved state
[15503]653 * file format (SSMFILEHDR_MAGIC_V1_2). */
[13594]654 char achMagic[32];
[1]655 /** The size of this file. Used to check
656 * whether the save completed and that things are fine otherwise. */
[13594]657 uint64_t cbFile;
[1]658 /** File checksum. The actual calculation skips past the u32CRC field. */
[13594]659 uint32_t u32CRC;
[4185]660 /** Padding. */
[13594]661 uint32_t u32Reserved;
[1]662 /** The machine UUID. (Ignored if NIL.) */
[13594]663 RTUUID MachineUuid;
[15503]664
665 /** The major version number. */
666 uint16_t u16VerMajor;
667 /** The minor version number. */
668 uint16_t u16VerMinor;
669 /** The build number. */
670 uint32_t u32VerBuild;
671 /** The SVN revision. */
672 uint32_t u32SvnRev;
673
674 /** 32 or 64 depending on the host. */
675 uint8_t cHostBits;
676 /** The size of RTGCPHYS. */
677 uint8_t cbGCPhys;
678 /** The size of RTGCPTR. */
679 uint8_t cbGCPtr;
680 /** Padding. */
681 uint8_t au8Reserved;
[21797]682} SSMFILEHDRV12;
683AssertCompileSize(SSMFILEHDRV12, 64+16);
684AssertCompileMemberOffset(SSMFILEHDRV12, u32CRC, 40);
685AssertCompileMemberSize(SSMFILEHDRV12, achMagic, sizeof(SSMFILEHDR_MAGIC_V1_2));
[13594]686/** Pointer to a saved state file header. */
[21797]687typedef SSMFILEHDRV12 *PSSMFILEHDRV12;
[1]688
[4185]689
690/**
[15503]691 * Header of the saved state file, version 1.1.
[21797]692 *
693 * Added in r23677 on 2007-08-17, VirtualBox v1.4.1.
[15503]694 */
695typedef struct SSMFILEHDRV11
696{
697 /** Magic string which identifies this file as a version of VBox saved state
698 * file format (SSMFILEHDR_MAGIC_V1_1). */
699 char achMagic[32];
700 /** The size of this file. Used to check
701 * whether the save completed and that things are fine otherwise. */
702 uint64_t cbFile;
703 /** File checksum. The actual calculation skips past the u32CRC field. */
704 uint32_t u32CRC;
705 /** Padding. */
706 uint32_t u32Reserved;
707 /** The machine UUID. (Ignored if NIL.) */
708 RTUUID MachineUuid;
709} SSMFILEHDRV11;
710AssertCompileSize(SSMFILEHDRV11, 64);
[21797]711AssertCompileMemberOffset(SSMFILEHDRV11, u32CRC, 40);
[15503]712/** Pointer to a saved state file header. */
713typedef SSMFILEHDRV11 *PSSMFILEHDRV11;
714
715
716/**
[21797]717 * Data unit header.
[4185]718 */
[21932]719typedef struct SSMFILEUNITHDRV2
[4185]720{
[21797]721 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
722 char szMagic[8];
723 /** The offset in the saved state stream of the start of this unit.
724 * This is mainly intended for sanity checking. */
725 uint64_t offStream;
[21858]726 /** The CRC-in-progress value this unit starts at. */
727 uint32_t u32CurStreamCRC;
[21797]728 /** The checksum of this structure, including the whole name.
729 * Calculated with this field set to zero. */
[13594]730 uint32_t u32CRC;
[21797]731 /** Data version. */
732 uint32_t u32Version;
733 /** Instance number. */
734 uint32_t u32Instance;
[22793]735 /** Data pass number. */
736 uint32_t u32Pass;
[21797]737 /** Flags reserved for future extensions. Must be zero. */
738 uint32_t fFlags;
739 /** Size of the data unit name including the terminator. (bytes) */
740 uint32_t cbName;
741 /** Data unit name, variable size. */
742 char szName[SSM_MAX_NAME_SIZE];
[21932]743} SSMFILEUNITHDRV2;
744AssertCompileMemberOffset(SSMFILEUNITHDRV2, szName, 44);
745AssertCompileMemberSize(SSMFILEUNITHDRV2, szMagic, sizeof(SSMFILEUNITHDR_MAGIC));
746AssertCompileMemberSize(SSMFILEUNITHDRV2, szMagic, sizeof(SSMFILEUNITHDR_END));
747/** Pointer to SSMFILEUNITHDRV2. */
748typedef SSMFILEUNITHDRV2 *PSSMFILEUNITHDRV2;
[4185]749
750
[1]751/**
752 * Data unit header.
[21797]753 *
754 * This is used by v1.0, v1.1 and v1.2 of the format.
[1]755 */
[21797]756typedef struct SSMFILEUNITHDRV1
[1]757{
[13594]758 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
759 char achMagic[8];
[1]760 /** Number of bytes in this data unit including the header. */
[13594]761 uint64_t cbUnit;
[1]762 /** Data version. */
[13594]763 uint32_t u32Version;
[1]764 /** Instance number. */
[13594]765 uint32_t u32Instance;
[1]766 /** Size of the data unit name including the terminator. (bytes) */
[13594]767 uint32_t cchName;
[1]768 /** Data unit name. */
[13594]769 char szName[1];
[21797]770} SSMFILEUNITHDRV1;
[13594]771/** Pointer to SSMFILEUNITHDR. */
[21797]772typedef SSMFILEUNITHDRV1 *PSSMFILEUNITHDRV1;
[1]773
774
[21797]775/**
776 * Termination data record.
777 */
778typedef struct SSMRECTERM
779{
780 uint8_t u8TypeAndFlags;
781 /** The record size (sizeof(SSMRECTERM) - 2). */
782 uint8_t cbRec;
783 /** Flags, see SSMRECTERM_FLAGS_CRC32. */
784 uint16_t fFlags;
[21895]785 /** The checksum of the stream up to fFlags (exclusive). */
[21858]786 uint32_t u32StreamCRC;
[21797]787 /** The length of this data unit in bytes (including this record). */
788 uint64_t cbUnit;
789} SSMRECTERM;
790AssertCompileSize(SSMRECTERM, 16);
791AssertCompileMemberAlignment(SSMRECTERM, cbUnit, 8);
792/** Pointer to a termination record. */
793typedef SSMRECTERM *PSSMRECTERM;
794/** Pointer to a const termination record. */
795typedef SSMRECTERM const *PCSSMRECTERM;
796
797
798/**
799 * Directory entry.
800 */
801typedef struct SSMFILEDIRENTRY
802{
803 /** The offset of the data unit. */
804 uint64_t off;
805 /** The instance number. */
806 uint32_t u32Instance;
807 /** The CRC-32 of the name excluding the terminator. (lazy bird) */
808 uint32_t u32NameCRC;
809} SSMFILEDIRENTRY;
810AssertCompileSize(SSMFILEDIRENTRY, 16);
811/** Pointer to a directory entry. */
812typedef SSMFILEDIRENTRY *PSSMFILEDIRENTRY;
813/** Pointer to a const directory entry. */
814typedef SSMFILEDIRENTRY const *PCSSMFILEDIRENTRY;
815
816/**
[22793]817 * Directory for the data units from the final pass.
[21797]818 *
819 * This is used to speed up SSMR3Seek (it would have to decompress and parse the
820 * whole stream otherwise).
821 */
822typedef struct SSMFILEDIR
823{
824 /** Magic string (SSMFILEDIR_MAGIC). */
825 char szMagic[8];
826 /** The CRC-32 for the whole directory.
827 * Calculated with this field set to zero. */
828 uint32_t u32CRC;
829 /** The number of directory entries. */
830 uint32_t cEntries;
831 /** The directory entries (variable size). */
832 SSMFILEDIRENTRY aEntries[1];
833} SSMFILEDIR;
834AssertCompileSize(SSMFILEDIR, 32);
835/** Pointer to a directory. */
836typedef SSMFILEDIR *PSSMFILEDIR;
837/** Pointer to a const directory. */
838typedef SSMFILEDIR *PSSMFILEDIR;
839
840
841/**
842 * Footer structure
843 */
844typedef struct SSMFILEFTR
845{
846 /** Magic string (SSMFILEFTR_MAGIC). */
847 char szMagic[8];
848 /** The offset of this record in the stream. */
849 uint64_t offStream;
850 /** The CRC for the stream.
851 * This is set to zero if SSMFILEHDR_FLAGS_STREAM_CRC32 is clear. */
852 uint32_t u32StreamCRC;
853 /** Number directory entries. */
854 uint32_t cDirEntries;
855 /** Reserved footer space - must be zero. */
856 uint32_t u32Reserved;
857 /** The CRC-32 for this structure.
858 * Calculated with this field set to zero. */
859 uint32_t u32CRC;
860} SSMFILEFTR;
861AssertCompileSize(SSMFILEFTR, 32);
862/** Pointer to a footer. */
863typedef SSMFILEFTR *PSSMFILEFTR;
864/** Pointer to a const footer. */
865typedef SSMFILEFTR const *PCSSMFILEFTR;
866
867
[57358]868/*********************************************************************************************************************************
869* Global Variables *
870*********************************************************************************************************************************/
[63465]871#ifndef SSM_STANDALONE
[23872]872/** Zeros used by the struct putter.
873 * This must be at least 8 bytes or the code breaks. */
874static uint8_t const g_abZero[_1K] = {0};
[63465]875#endif
[23872]876
877
[57358]878/*********************************************************************************************************************************
879* Internal Functions *
880*********************************************************************************************************************************/
[24574]881#ifndef SSM_STANDALONE
[12440]882static int ssmR3LazyInit(PVM pVM);
[22793]883static DECLCALLBACK(int) ssmR3SelfLiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
[12440]884static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM);
[22793]885static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
[30396]886static DECLCALLBACK(int) ssmR3LiveControlLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
[22480]887static int ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
[30396]888static int ssmR3LiveControlEmit(PSSMHANDLE pSSM, long double lrdPct, uint32_t uPass);
[24574]889#endif
[22554]890
[21897]891static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm);
[21900]892static int ssmR3StrmReadMore(PSSMSTRM pStrm);
[22554]893
[39078]894#ifndef SSM_STANDALONE
[21797]895static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM);
[39078]896#endif
[21797]897static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM);
[1]898
899
[24574]900#ifndef SSM_STANDALONE
[22554]901
[1]902/**
[22884]903 * Cleans up resources allocated by SSM on VM termination.
904 *
[58122]905 * @param pVM The cross context VM structure.
[22884]906 */
907VMMR3_INT_DECL(void) SSMR3Term(PVM pVM)
908{
909 if (pVM->ssm.s.fInitialized)
910 {
911 pVM->ssm.s.fInitialized = false;
912 RTCritSectDelete(&pVM->ssm.s.CancelCritSect);
913 }
914}
915
916
917/**
[12440]918 * Performs lazy initialization of the SSM.
919 *
920 * @returns VBox status code.
[58122]921 * @param pVM The cross context VM structure.
[12440]922 */
923static int ssmR3LazyInit(PVM pVM)
924{
925 /*
926 * Register a saved state unit which we use to put the VirtualBox version,
927 * revision and similar stuff in.
928 */
929 pVM->ssm.s.fInitialized = true;
[22480]930 int rc = SSMR3RegisterInternal(pVM, "SSM", 0 /*uInstance*/, 1 /*uVersion*/, 64 /*cbGuess*/,
931 NULL /*pfnLivePrep*/, ssmR3SelfLiveExec, NULL /*pfnLiveVote*/,
[12440]932 NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
933 NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
[30396]934 if (RT_SUCCESS(rc))
935 rc = SSMR3RegisterInternal(pVM, "SSMLiveControl", 0 /*uInstance*/, 1 /*uVersion*/, 1 /*cbGuess*/,
936 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
937 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
938 NULL /*pfnSavePrep*/, ssmR3LiveControlLoadExec, NULL /*pfnSaveDone*/);
[22884]939
940 /*
941 * Initialize the cancellation critsect now.
942 */
943 if (RT_SUCCESS(rc))
944 rc = RTCritSectInit(&pVM->ssm.s.CancelCritSect);
[24804]945 if (RT_SUCCESS(rc))
946 {
947 STAM_REL_REG_USED(pVM, &pVM->ssm.s.uPass, STAMTYPE_U32, "/SSM/uPass", STAMUNIT_COUNT, "Current pass");
948 }
[22884]949
[12440]950 pVM->ssm.s.fInitialized = RT_SUCCESS(rc);
951 return rc;
952}
953
954
955/**
[22793]956 * Do ssmR3SelfSaveExec in pass 0.
[22480]957 *
958 * @returns VBox status code.
[58122]959 * @param pVM The cross context VM structure.
[22480]960 * @param pSSM The SSM handle.
[22793]961 * @param uPass The data pass number.
[22480]962 */
[22793]963static DECLCALLBACK(int) ssmR3SelfLiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
[22480]964{
[22793]965 if (uPass == 0)
[23714]966 {
967 int rc = ssmR3SelfSaveExec(pVM, pSSM);
968 if (RT_SUCCESS(rc))
969 rc = VINF_SSM_DONT_CALL_AGAIN;
970 return rc;
971 }
972 AssertFailed();
[39402]973 return VERR_SSM_UNEXPECTED_PASS;
[22480]974}
975
976
977/**
[15503]978 * For saving usful things without having to go thru the tedious process of
979 * adding it to the header.
[12440]980 *
981 * @returns VBox status code.
[58122]982 * @param pVM The cross context VM structure.
[12440]983 * @param pSSM The SSM handle.
984 */
985static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM)
986{
[39078]987 NOREF(pVM);
988
[12440]989 /*
[33540]990 * String table containing pairs of variable and value string.
[12440]991 * Terminated by two empty strings.
992 */
[22780]993 SSMR3PutStrZ(pSSM, "Build Type");
[22781]994 SSMR3PutStrZ(pSSM, KBUILD_TYPE);
995 SSMR3PutStrZ(pSSM, "Host OS");
996 SSMR3PutStrZ(pSSM, KBUILD_TARGET "." KBUILD_TARGET_ARCH);
[12440]997#ifdef VBOX_OSE
998 SSMR3PutStrZ(pSSM, "OSE");
999 SSMR3PutStrZ(pSSM, "true");
1000#endif
1001
1002 /* terminator */
1003 SSMR3PutStrZ(pSSM, "");
1004 return SSMR3PutStrZ(pSSM, "");
1005}
1006
1007
1008/**
1009 * For load the version + revision and stuff.
1010 *
1011 * @returns VBox status code.
[58122]1012 * @param pVM The cross context VM structure.
[12440]1013 * @param pSSM The SSM handle.
[22480]1014 * @param uVersion The version (1).
[22793]1015 * @param uPass The pass.
[12440]1016 */
[22793]1017static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
[12440]1018{
[56956]1019 AssertLogRelMsgReturn(uVersion == 1, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
[39078]1020 NOREF(pVM); NOREF(uPass);
[12440]1021
1022 /*
[23448]1023 * The first and last passes contains a {name, value} string table that is
1024 * terminated by two emptry strings. It contains useful informal build
1025 * info and can be very handy when something goes wrong after restore.
[12440]1026 */
[23448]1027 if ( uPass == 0
1028 || uPass == SSM_PASS_FINAL)
[12440]1029 {
[23448]1030 for (unsigned i = 0; ; i++)
1031 {
1032 char szVar[128];
1033 char szValue[1024];
1034 int rc = SSMR3GetStrZ(pSSM, szVar, sizeof(szVar));
1035 AssertRCReturn(rc, rc);
1036 rc = SSMR3GetStrZ(pSSM, szValue, sizeof(szValue));
1037 AssertRCReturn(rc, rc);
1038 if (!szVar[0] && !szValue[0])
1039 break;
1040 if (i == 0)
1041 LogRel(("SSM: Saved state info:\n"));
1042 LogRel(("SSM: %s: %s\n", szVar, szValue));
[23771]1043
1044 /*
1045 * Detect 32-bit MSC for handling SSMFIELD_ENTRY_PAD_MSC32_AUTO.
[24843]1046 * Save the Host OS for SSMR3HandleHostOSAndArch
[23771]1047 */
1048 if (!strcmp(szVar, "Host OS"))
1049 {
1050 bool fIsHostMsc32 = !strcmp(szValue, "win.x86");
1051 if (fIsHostMsc32 != pSSM->u.Read.fIsHostMsc32)
1052 {
1053 LogRel(("SSM: (fIsHostMsc32 %RTbool => %RTbool)\n", pSSM->u.Read.fIsHostMsc32, fIsHostMsc32));
1054 pSSM->u.Read.fIsHostMsc32 = fIsHostMsc32;
1055 }
[24843]1056
1057 size_t cchValue = strlen(szValue);
1058 size_t cchCopy = RT_MIN(cchValue, sizeof(pSSM->u.Read.szHostOSAndArch) - 1);
1059 Assert(cchValue == cchCopy);
1060 memcpy(pSSM->u.Read.szHostOSAndArch, szValue, cchCopy);
1061 pSSM->u.Read.szHostOSAndArch[cchCopy] = '\0';
[23771]1062 }
[23448]1063 }
[12440]1064 }
1065 return VINF_SUCCESS;
1066}
1067
1068
1069/**
[30396]1070 * Load exec callback for the special live save state unit that tracks the
1071 * progress of a live save.
1072 *
1073 * This is saved by ssmR3LiveControlEmit().
1074 *
1075 * @returns VBox status code.
[58122]1076 * @param pVM The cross context VM structure.
[30396]1077 * @param pSSM The SSM handle.
1078 * @param uVersion The version (1).
1079 * @param uPass The pass.
1080 */
1081static DECLCALLBACK(int) ssmR3LiveControlLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1082{
[56956]1083 AssertLogRelMsgReturn(uVersion == 1, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
[39078]1084 NOREF(uPass);
[30396]1085
1086 uint16_t uPartsPerTenThousand;
1087 int rc = SSMR3GetU16(pSSM, &uPartsPerTenThousand);
1088 if (RT_SUCCESS(rc))
1089 {
1090 /* Scale it down to fit in our exec range. */
1091 unsigned uPct = (unsigned)( (long double)uPartsPerTenThousand / 100
1092 * (100 - pSSM->uPercentPrepare - pSSM->uPercentDone) / 100)
1093 + pSSM->uPercentPrepare;
1094 if (uPct != pSSM->uPercent)
1095 {
1096 AssertMsg(uPct < 100, ("uPct=%d uPartsPerTenThousand=%d uPercentPrepare=%d uPercentDone=%d\n", uPct, uPartsPerTenThousand, pSSM->uPercentPrepare, pSSM->uPercentDone));
1097 pSSM->uPercent = uPct;
1098 if (pSSM->pfnProgress)
[44393]1099 pSSM->pfnProgress(pVM->pUVM, RT_MIN(uPct, 100 - pSSM->uPercentDone), pSSM->pvUser);
[30396]1100 }
1101 }
1102 return rc;
1103}
1104
1105
1106/**
[1]1107 * Internal registration worker.
1108 *
1109 * @returns VBox status code.
[58122]1110 * @param pVM The cross context VM structure.
[1]1111 * @param pszName Data unit name.
[22480]1112 * @param uInstance The instance id.
1113 * @param uVersion The data unit version.
[1]1114 * @param cbGuess The guessed data unit size.
[20153]1115 * @param pszBefore Name of data unit to be placed in front of.
1116 * Optional.
[33540]1117 * @param ppUnit Where to store the inserted unit node.
[1]1118 * Caller must fill in the missing details.
1119 */
[22480]1120static int ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance,
1121 uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit)
[1]1122{
[21797]1123 /*
1124 * Validate input.
1125 */
1126 AssertPtr(pszName);
[20153]1127 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
[21797]1128 size_t cchName = strlen(pszName);
1129 AssertMsgReturn(cchName < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchName, SSM_MAX_NAME_SIZE, pszName), VERR_OUT_OF_RANGE);
1130
[20153]1131 AssertReturn(!pszBefore || *pszBefore, VERR_INVALID_PARAMETER);
[21797]1132 size_t cchBefore = pszBefore ? strlen(pszBefore) : 0;
1133 AssertMsgReturn(cchBefore < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchBefore, SSM_MAX_NAME_SIZE, pszBefore), VERR_OUT_OF_RANGE);
[20153]1134
[1]1135 /*
[12440]1136 * Lazy init.
1137 */
1138 if (!pVM->ssm.s.fInitialized)
1139 {
1140 int rc = ssmR3LazyInit(pVM);
1141 AssertRCReturn(rc, rc);
1142 }
1143
1144 /*
[1]1145 * Walk to the end of the list checking for duplicates as we go.
1146 */
[20153]1147 PSSMUNIT pUnitBeforePrev = NULL;
1148 PSSMUNIT pUnitBefore = NULL;
1149 PSSMUNIT pUnitPrev = NULL;
1150 PSSMUNIT pUnit = pVM->ssm.s.pHead;
[1]1151 while (pUnit)
1152 {
[22480]1153 if ( pUnit->u32Instance == uInstance
[1]1154 && pUnit->cchName == cchName
1155 && !memcmp(pUnit->szName, pszName, cchName))
1156 {
1157 AssertMsgFailed(("Duplicate registration %s\n", pszName));
1158 return VERR_SSM_UNIT_EXISTS;
1159 }
[20153]1160 if ( pUnit->cchName == cchBefore
1161 && !pUnitBefore
1162 && !memcmp(pUnit->szName, pszBefore, cchBefore))
1163 {
1164 pUnitBeforePrev = pUnitPrev;
1165 pUnitBefore = pUnit;
1166 }
1167
[1]1168 /* next */
1169 pUnitPrev = pUnit;
1170 pUnit = pUnit->pNext;
1171 }
1172
1173 /*
1174 * Allocate new node.
1175 */
[73097]1176 pUnit = (PSSMUNIT)MMR3HeapAllocZ(pVM, MM_TAG_SSM, RT_UOFFSETOF_DYN(SSMUNIT, szName[cchName + 1]));
[1]1177 if (!pUnit)
1178 return VERR_NO_MEMORY;
1179
1180 /*
[33540]1181 * Fill in (some) data. (Stuff is zero'd.)
[1]1182 */
[22480]1183 pUnit->u32Version = uVersion;
1184 pUnit->u32Instance = uInstance;
[20153]1185 pUnit->cbGuess = cbGuess;
1186 pUnit->cchName = cchName;
[1]1187 memcpy(pUnit->szName, pszName, cchName);
1188
1189 /*
1190 * Insert
1191 */
[20153]1192 if (pUnitBefore)
1193 {
1194 pUnit->pNext = pUnitBefore;
1195 if (pUnitBeforePrev)
1196 pUnitBeforePrev->pNext = pUnit;
1197 else
1198 pVM->ssm.s.pHead = pUnit;
1199 }
1200 else if (pUnitPrev)
[1]1201 pUnitPrev->pNext = pUnit;
1202 else
1203 pVM->ssm.s.pHead = pUnit;
[21797]1204 pVM->ssm.s.cUnits++;
[1]1205
1206 *ppUnit = pUnit;
1207 return VINF_SUCCESS;
1208}
1209
1210
1211/**
1212 * Register a PDM Devices data unit.
1213 *
[58170]1214 * @returns VBox status code.
[13594]1215 *
[58122]1216 * @param pVM The cross context VM structure.
[1]1217 * @param pDevIns Device instance.
1218 * @param pszName Data unit name.
[22480]1219 * @param uInstance The instance identifier of the data unit.
[1]1220 * This must together with the name be unique.
[22480]1221 * @param uVersion Data layout version number.
[1]1222 * @param cbGuess The approximate amount of data in the unit.
1223 * Only for progress indicators.
[20153]1224 * @param pszBefore Name of data unit which we should be put in front
1225 * of. Optional (NULL).
[22480]1226 *
1227 * @param pfnLivePrep Prepare live save callback, optional.
1228 * @param pfnLiveExec Execute live save callback, optional.
1229 * @param pfnLiveVote Vote live save callback, optional.
1230 *
[1]1231 * @param pfnSavePrep Prepare save callback, optional.
1232 * @param pfnSaveExec Execute save callback, optional.
1233 * @param pfnSaveDone Done save callback, optional.
[22480]1234 *
[1]1235 * @param pfnLoadPrep Prepare load callback, optional.
1236 * @param pfnLoadExec Execute load callback, optional.
1237 * @param pfnLoadDone Done load callback, optional.
1238 */
[44522]1239VMMR3_INT_DECL(int)
1240SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName,
1241 uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore,
1242 PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote,
1243 PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
1244 PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
[1]1245{
1246 PSSMUNIT pUnit;
[22480]1247 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, pszBefore, &pUnit);
[13816]1248 if (RT_SUCCESS(rc))
[1]1249 {
1250 pUnit->enmType = SSMUNITTYPE_DEV;
[22480]1251 pUnit->u.Dev.pfnLivePrep = pfnLivePrep;
1252 pUnit->u.Dev.pfnLiveExec = pfnLiveExec;
1253 pUnit->u.Dev.pfnLiveVote = pfnLiveVote;
[1]1254 pUnit->u.Dev.pfnSavePrep = pfnSavePrep;
1255 pUnit->u.Dev.pfnSaveExec = pfnSaveExec;
1256 pUnit->u.Dev.pfnSaveDone = pfnSaveDone;
1257 pUnit->u.Dev.pfnLoadPrep = pfnLoadPrep;
1258 pUnit->u.Dev.pfnLoadExec = pfnLoadExec;
1259 pUnit->u.Dev.pfnLoadDone = pfnLoadDone;
1260 pUnit->u.Dev.pDevIns = pDevIns;
[44505]1261 pUnit->pCritSect = PDMR3DevGetCritSect(pVM, pDevIns);
[1]1262 }
1263 return rc;
1264}
1265
1266
1267/**
1268 * Register a PDM driver data unit.
1269 *
[58170]1270 * @returns VBox status code.
[13594]1271 *
[58122]1272 * @param pVM The cross context VM structure.
[1]1273 * @param pDrvIns Driver instance.
1274 * @param pszName Data unit name.
[22480]1275 * @param uInstance The instance identifier of the data unit.
[1]1276 * This must together with the name be unique.
[22480]1277 * @param uVersion Data layout version number.
[1]1278 * @param cbGuess The approximate amount of data in the unit.
1279 * Only for progress indicators.
[22480]1280 *
1281 * @param pfnLivePrep Prepare live save callback, optional.
1282 * @param pfnLiveExec Execute live save callback, optional.
1283 * @param pfnLiveVote Vote live save callback, optional.
1284 *
[1]1285 * @param pfnSavePrep Prepare save callback, optional.
1286 * @param pfnSaveExec Execute save callback, optional.
1287 * @param pfnSaveDone Done save callback, optional.
[22480]1288 *
[1]1289 * @param pfnLoadPrep Prepare load callback, optional.
1290 * @param pfnLoadExec Execute load callback, optional.
1291 * @param pfnLoadDone Done load callback, optional.
1292 */
[44522]1293VMMR3_INT_DECL(int)
1294SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1295 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
1296 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1297 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
[1]1298{
1299 PSSMUNIT pUnit;
[22480]1300 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL, &pUnit);
[13816]1301 if (RT_SUCCESS(rc))
[1]1302 {
1303 pUnit->enmType = SSMUNITTYPE_DRV;
[39078]1304 pUnit->u.Drv.pfnLivePrep = pfnLivePrep;
1305 pUnit->u.Drv.pfnLiveExec = pfnLiveExec;
1306 pUnit->u.Drv.pfnLiveVote = pfnLiveVote;
[1]1307 pUnit->u.Drv.pfnSavePrep = pfnSavePrep;
1308 pUnit->u.Drv.pfnSaveExec = pfnSaveExec;
1309 pUnit->u.Drv.pfnSaveDone = pfnSaveDone;
1310 pUnit->u.Drv.pfnLoadPrep = pfnLoadPrep;
1311 pUnit->u.Drv.pfnLoadExec = pfnLoadExec;
1312 pUnit->u.Drv.pfnLoadDone = pfnLoadDone;
1313 pUnit->u.Drv.pDrvIns = pDrvIns;
1314 }
1315 return rc;
1316}
1317
1318
1319/**
[48986]1320 * Register a PDM USB device data unit.
1321 *
[58170]1322 * @returns VBox status code.
[48986]1323 *
[58122]1324 * @param pVM The cross context VM structure.
[48986]1325 * @param pUsbIns USB instance.
1326 * @param pszName Data unit name.
1327 * @param uInstance The instance identifier of the data unit.
1328 * This must together with the name be unique.
1329 * @param uVersion Data layout version number.
1330 * @param cbGuess The approximate amount of data in the unit.
1331 * Only for progress indicators.
1332 *
1333 * @param pfnLivePrep Prepare live save callback, optional.
1334 * @param pfnLiveExec Execute live save callback, optional.
1335 * @param pfnLiveVote Vote live save callback, optional.
1336 *
1337 * @param pfnSavePrep Prepare save callback, optional.
1338 * @param pfnSaveExec Execute save callback, optional.
1339 * @param pfnSaveDone Done save callback, optional.
1340 *
1341 * @param pfnLoadPrep Prepare load callback, optional.
1342 * @param pfnLoadExec Execute load callback, optional.
1343 * @param pfnLoadDone Done load callback, optional.
1344 */
1345VMMR3_INT_DECL(int)
1346SSMR3RegisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1347 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1348 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1349 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1350{
1351 PSSMUNIT pUnit;
1352 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL, &pUnit);
1353 if (RT_SUCCESS(rc))
1354 {
1355 pUnit->enmType = SSMUNITTYPE_USB;
1356 pUnit->u.Usb.pfnLivePrep = pfnLivePrep;
1357 pUnit->u.Usb.pfnLiveExec = pfnLiveExec;
1358 pUnit->u.Usb.pfnLiveVote = pfnLiveVote;
1359 pUnit->u.Usb.pfnSavePrep = pfnSavePrep;
1360 pUnit->u.Usb.pfnSaveExec = pfnSaveExec;
1361 pUnit->u.Usb.pfnSaveDone = pfnSaveDone;
1362 pUnit->u.Usb.pfnLoadPrep = pfnLoadPrep;
1363 pUnit->u.Usb.pfnLoadExec = pfnLoadExec;
1364 pUnit->u.Usb.pfnLoadDone = pfnLoadDone;
1365 pUnit->u.Usb.pUsbIns = pUsbIns;
1366 }
1367 return rc;
1368}
1369
1370
1371/**
[1]1372 * Register a internal data unit.
1373 *
[58170]1374 * @returns VBox status code.
[13594]1375 *
[58122]1376 * @param pVM The cross context VM structure.
[1]1377 * @param pszName Data unit name.
[22480]1378 * @param uInstance The instance identifier of the data unit.
[1]1379 * This must together with the name be unique.
[22480]1380 * @param uVersion Data layout version number.
[1]1381 * @param cbGuess The approximate amount of data in the unit.
1382 * Only for progress indicators.
[22480]1383 *
1384 * @param pfnLivePrep Prepare live save callback, optional.
1385 * @param pfnLiveExec Execute live save callback, optional.
1386 * @param pfnLiveVote Vote live save callback, optional.
1387 *
[1]1388 * @param pfnSavePrep Prepare save callback, optional.
1389 * @param pfnSaveExec Execute save callback, optional.
1390 * @param pfnSaveDone Done save callback, optional.
[22480]1391 *
[1]1392 * @param pfnLoadPrep Prepare load callback, optional.
1393 * @param pfnLoadExec Execute load callback, optional.
1394 * @param pfnLoadDone Done load callback, optional.
1395 */
[22480]1396VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1397 PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote,
[1]1398 PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
1399 PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone)
1400{
1401 PSSMUNIT pUnit;
[51598]1402 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL /* pszBefore */, &pUnit);
[13816]1403 if (RT_SUCCESS(rc))
[1]1404 {
1405 pUnit->enmType = SSMUNITTYPE_INTERNAL;
[22480]1406 pUnit->u.Internal.pfnLivePrep = pfnLivePrep;
1407 pUnit->u.Internal.pfnLiveExec = pfnLiveExec;
1408 pUnit->u.Internal.pfnLiveVote = pfnLiveVote;
[1]1409 pUnit->u.Internal.pfnSavePrep = pfnSavePrep;
1410 pUnit->u.Internal.pfnSaveExec = pfnSaveExec;
1411 pUnit->u.Internal.pfnSaveDone = pfnSaveDone;
1412 pUnit->u.Internal.pfnLoadPrep = pfnLoadPrep;
1413 pUnit->u.Internal.pfnLoadExec = pfnLoadExec;
1414 pUnit->u.Internal.pfnLoadDone = pfnLoadDone;
1415 }
1416 return rc;
1417}
1418
1419
1420/**
1421 * Register an external data unit.
1422 *
[58170]1423 * @returns VBox status code.
[13594]1424 *
[44347]1425 * @param pUVM The user mode VM handle.
[1]1426 * @param pszName Data unit name.
[22480]1427 * @param uInstance The instance identifier of the data unit.
[1]1428 * This must together with the name be unique.
[22480]1429 * @param uVersion Data layout version number.
[1]1430 * @param cbGuess The approximate amount of data in the unit.
1431 * Only for progress indicators.
[22480]1432 *
1433 * @param pfnLivePrep Prepare live save callback, optional.
1434 * @param pfnLiveExec Execute live save callback, optional.
1435 * @param pfnLiveVote Vote live save callback, optional.
1436 *
[1]1437 * @param pfnSavePrep Prepare save callback, optional.
1438 * @param pfnSaveExec Execute save callback, optional.
1439 * @param pfnSaveDone Done save callback, optional.
[22480]1440 *
[1]1441 * @param pfnLoadPrep Prepare load callback, optional.
1442 * @param pfnLoadExec Execute load callback, optional.
1443 * @param pfnLoadDone Done load callback, optional.
1444 * @param pvUser User argument.
1445 */
[44347]1446VMMR3DECL(int) SSMR3RegisterExternal(PUVM pUVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
[22480]1447 PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote,
[1]1448 PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
1449 PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
1450{
[44347]1451 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1452 PVM pVM = pUVM->pVM;
1453 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1454
[1]1455 PSSMUNIT pUnit;
[51598]1456 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL /* pszBefore */, &pUnit);
[13816]1457 if (RT_SUCCESS(rc))
[1]1458 {
1459 pUnit->enmType = SSMUNITTYPE_EXTERNAL;
[22480]1460 pUnit->u.External.pfnLivePrep = pfnLivePrep;
1461 pUnit->u.External.pfnLiveExec = pfnLiveExec;
1462 pUnit->u.External.pfnLiveVote = pfnLiveVote;
[1]1463 pUnit->u.External.pfnSavePrep = pfnSavePrep;
1464 pUnit->u.External.pfnSaveExec = pfnSaveExec;
1465 pUnit->u.External.pfnSaveDone = pfnSaveDone;
1466 pUnit->u.External.pfnLoadPrep = pfnLoadPrep;
1467 pUnit->u.External.pfnLoadExec = pfnLoadExec;
1468 pUnit->u.External.pfnLoadDone = pfnLoadDone;
1469 pUnit->u.External.pvUser = pvUser;
1470 }
1471 return rc;
1472}
1473
1474
1475/**
[50575]1476 * @callback_method_impl{FNSSMINTLOADEXEC,
1477 * Stub that skips the whole unit (see SSMR3RegisterStub).}
1478 */
1479static DECLCALLBACK(int) ssmR3LoadExecStub(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1480{
1481 NOREF(pVM); NOREF(uVersion); NOREF(uPass);
1482 return SSMR3SkipToEndOfUnit(pSSM);
1483}
1484
1485
1486/**
1487 * Registers a stub state loader for working around legacy.
1488 *
1489 * This is used to deal with irelevant PATM and CSAM saved state units in HM
1490 * mode and when built without raw-mode.
1491 *
1492 * @returns VBox status code.
[58122]1493 * @param pVM The cross context VM structure.
[50575]1494 * @param pszName Data unit name.
1495 * @param uInstance Instance number.
1496 */
1497VMMR3DECL(int) SSMR3RegisterStub(PVM pVM, const char *pszName, uint32_t uInstance)
1498{
1499 return SSMR3RegisterInternal(pVM, pszName, uInstance, UINT32_MAX, 0,
1500 NULL, NULL, NULL,
1501 NULL, NULL, NULL,
1502 NULL, ssmR3LoadExecStub, NULL);
1503}
1504
1505
1506/**
[1]1507 * Deregister one or more PDM Device data units.
1508 *
[58170]1509 * @returns VBox status code.
[13594]1510 *
[58122]1511 * @param pVM The cross context VM structure.
[1]1512 * @param pDevIns Device instance.
1513 * @param pszName Data unit name.
1514 * Use NULL to deregister all data units for that device instance.
[22480]1515 * @param uInstance The instance identifier of the data unit.
[1]1516 * This must together with the name be unique.
[33540]1517 * @remark Only for dynamic data units and dynamic unloaded modules.
[1]1518 */
[22803]1519VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance)
[1]1520{
1521 /*
1522 * Validate input.
1523 */
1524 if (!pDevIns)
1525 {
1526 AssertMsgFailed(("pDevIns is NULL!\n"));
1527 return VERR_INVALID_PARAMETER;
1528 }
1529
1530 /*
1531 * Search the list.
1532 */
1533 size_t cchName = pszName ? strlen(pszName) : 0;
1534 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1535 PSSMUNIT pUnitPrev = NULL;
1536 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1537 while (pUnit)
1538 {
1539 if ( pUnit->enmType == SSMUNITTYPE_DEV
1540 && ( !pszName
1541 || ( pUnit->cchName == cchName
1542 && !memcmp(pUnit->szName, pszName, cchName)))
[22480]1543 && pUnit->u32Instance == uInstance
[1]1544 )
1545 {
1546 if (pUnit->u.Dev.pDevIns == pDevIns)
1547 {
1548 /*
1549 * Unlink it, advance pointer, and free the node.
1550 */
1551 PSSMUNIT pFree = pUnit;
1552 pUnit = pUnit->pNext;
1553 if (pUnitPrev)
1554 pUnitPrev->pNext = pUnit;
1555 else
1556 pVM->ssm.s.pHead = pUnit;
[21797]1557 pVM->ssm.s.cUnits--;
[1]1558 Log(("SSM: Removed data unit '%s' (pdm dev).\n", pFree->szName));
1559 MMR3HeapFree(pFree);
[21797]1560
[1]1561 if (pszName)
1562 return VINF_SUCCESS;
1563 rc = VINF_SUCCESS;
1564 continue;
1565 }
1566 else if (pszName)
1567 {
1568 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1569 pUnit->u.Dev.pDevIns, pDevIns, pszName));
1570 return VERR_SSM_UNIT_NOT_OWNER;
1571 }
1572 }
1573
1574 /* next */
1575 pUnitPrev = pUnit;
1576 pUnit = pUnit->pNext;
1577 }
1578
1579 return rc;
1580}
1581
1582
1583/**
1584 * Deregister one ore more PDM Driver data units.
1585 *
[58170]1586 * @returns VBox status code.
[58122]1587 * @param pVM The cross context VM structure.
[1]1588 * @param pDrvIns Driver instance.
1589 * @param pszName Data unit name.
1590 * Use NULL to deregister all data units for that driver instance.
[22480]1591 * @param uInstance The instance identifier of the data unit.
[1]1592 * This must together with the name be unique. Ignored if pszName is NULL.
[33540]1593 * @remark Only for dynamic data units and dynamic unloaded modules.
[1]1594 */
[22803]1595VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)
[1]1596{
1597 /*
1598 * Validate input.
1599 */
1600 if (!pDrvIns)
1601 {
1602 AssertMsgFailed(("pDrvIns is NULL!\n"));
1603 return VERR_INVALID_PARAMETER;
1604 }
1605
1606 /*
1607 * Search the list.
1608 */
1609 size_t cchName = pszName ? strlen(pszName) : 0;
1610 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1611 PSSMUNIT pUnitPrev = NULL;
1612 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1613 while (pUnit)
1614 {
1615 if ( pUnit->enmType == SSMUNITTYPE_DRV
1616 && ( !pszName
1617 || ( pUnit->cchName == cchName
1618 && !memcmp(pUnit->szName, pszName, cchName)
[22480]1619 && pUnit->u32Instance == uInstance))
[1]1620 )
1621 {
1622 if (pUnit->u.Drv.pDrvIns == pDrvIns)
1623 {
1624 /*
1625 * Unlink it, advance pointer, and free the node.
1626 */
1627 PSSMUNIT pFree = pUnit;
1628 pUnit = pUnit->pNext;
1629 if (pUnitPrev)
1630 pUnitPrev->pNext = pUnit;
1631 else
1632 pVM->ssm.s.pHead = pUnit;
[21797]1633 pVM->ssm.s.cUnits--;
[1]1634 Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
1635 MMR3HeapFree(pFree);
[21797]1636
[1]1637 if (pszName)
1638 return VINF_SUCCESS;
1639 rc = VINF_SUCCESS;
1640 continue;
1641 }
[24613]1642
1643 AssertMsgReturn(!pszName,
1644 ("Caller is not owner! Owner=%p Caller=%p %s\n", pUnit->u.Drv.pDrvIns, pDrvIns, pszName),
1645 VERR_SSM_UNIT_NOT_OWNER);
[1]1646 }
1647
1648 /* next */
1649 pUnitPrev = pUnit;
1650 pUnit = pUnit->pNext;
1651 }
1652
1653 return rc;
1654}
1655
[13594]1656
[1]1657/**
[48986]1658 * Deregister one or more PDM USB device data units.
1659 *
[58170]1660 * @returns VBox status code.
[58122]1661 * @param pVM The cross context VM structure.
[48986]1662 * @param pUsbIns USB device instance.
1663 * @param pszName Data unit name.
1664 * Use NULL to deregister all data units for that driver instance.
1665 * @param uInstance The instance identifier of the data unit.
1666 * This must together with the name be unique. Ignored if pszName is NULL.
1667 * @remark Only for dynamic data units and dynamic unloaded modules.
1668 */
1669VMMR3_INT_DECL(int) SSMR3DeregisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance)
1670{
1671 /*
1672 * Validate input.
1673 */
1674 AssertMsgReturn(VALID_PTR(pUsbIns), ("pUsbIns is NULL!\n"), VERR_INVALID_PARAMETER);
1675
1676 /*
1677 * Search the list.
1678 */
1679 size_t cchName = pszName ? strlen(pszName) : 0;
1680 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1681 PSSMUNIT pUnitPrev = NULL;
1682 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1683 while (pUnit)
1684 {
1685 if ( pUnit->enmType == SSMUNITTYPE_USB
1686 && ( !pszName
1687 || ( pUnit->cchName == cchName
1688 && !memcmp(pUnit->szName, pszName, cchName)
1689 && pUnit->u32Instance == uInstance))
1690 )
1691 {
1692 if (pUnit->u.Usb.pUsbIns == pUsbIns)
1693 {
1694 /*
1695 * Unlink it, advance pointer, and free the node.
1696 */
1697 PSSMUNIT pFree = pUnit;
1698 pUnit = pUnit->pNext;
1699 if (pUnitPrev)
1700 pUnitPrev->pNext = pUnit;
1701 else
1702 pVM->ssm.s.pHead = pUnit;
1703 pVM->ssm.s.cUnits--;
1704 Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
1705 MMR3HeapFree(pFree);
1706
1707 if (pszName)
1708 return VINF_SUCCESS;
1709 rc = VINF_SUCCESS;
1710 continue;
1711 }
1712
1713 AssertMsgReturn(!pszName,
1714 ("Caller is not owner! Owner=%p Caller=%p %s\n", pUnit->u.Usb.pUsbIns, pUsbIns, pszName),
1715 VERR_SSM_UNIT_NOT_OWNER);
1716 }
1717
1718 /* next */
1719 pUnitPrev = pUnit;
1720 pUnit = pUnit->pNext;
1721 }
1722
1723 return rc;
1724}
1725
1726
1727/**
[901]1728 * Deregister a data unit.
[1]1729 *
[58170]1730 * @returns VBox status code.
[58122]1731 * @param pVM The cross context VM structure.
[901]1732 * @param enmType Unit type
[1]1733 * @param pszName Data unit name.
[33540]1734 * @remark Only for dynamic data units.
[1]1735 */
[901]1736static int ssmR3DeregisterByNameAndType(PVM pVM, const char *pszName, SSMUNITTYPE enmType)
[1]1737{
1738 /*
1739 * Validate input.
1740 */
1741 if (!pszName)
1742 {
1743 AssertMsgFailed(("pszName is NULL!\n"));
1744 return VERR_INVALID_PARAMETER;
1745 }
1746
1747 /*
1748 * Search the list.
1749 */
1750 size_t cchName = strlen(pszName);
1751 int rc = VERR_SSM_UNIT_NOT_FOUND;
1752 PSSMUNIT pUnitPrev = NULL;
1753 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1754 while (pUnit)
1755 {
[901]1756 if ( pUnit->enmType == enmType
[1]1757 && pUnit->cchName == cchName
1758 && !memcmp(pUnit->szName, pszName, cchName))
1759 {
1760 /*
1761 * Unlink it, advance pointer, and free the node.
1762 */
1763 PSSMUNIT pFree = pUnit;
1764 pUnit = pUnit->pNext;
1765 if (pUnitPrev)
1766 pUnitPrev->pNext = pUnit;
1767 else
1768 pVM->ssm.s.pHead = pUnit;
[21797]1769 pVM->ssm.s.cUnits--;
[901]1770 Log(("SSM: Removed data unit '%s' (type=%d).\n", pFree->szName, enmType));
[1]1771 MMR3HeapFree(pFree);
1772 return VINF_SUCCESS;
1773 }
1774
1775 /* next */
1776 pUnitPrev = pUnit;
1777 pUnit = pUnit->pNext;
1778 }
1779
1780 return rc;
1781}
1782
[990]1783
[901]1784/**
1785 * Deregister an internal data unit.
1786 *
[58170]1787 * @returns VBox status code.
[58122]1788 * @param pVM The cross context VM structure.
[901]1789 * @param pszName Data unit name.
[33540]1790 * @remark Only for dynamic data units.
[901]1791 */
[12989]1792VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName)
[901]1793{
1794 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_INTERNAL);
1795}
[1]1796
[901]1797
[1]1798/**
[901]1799 * Deregister an external data unit.
1800 *
[58170]1801 * @returns VBox status code.
[58126]1802 * @param pUVM The user mode VM structure.
[901]1803 * @param pszName Data unit name.
[33540]1804 * @remark Only for dynamic data units.
[901]1805 */
[44347]1806VMMR3DECL(int) SSMR3DeregisterExternal(PUVM pUVM, const char *pszName)
[901]1807{
[44347]1808 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1809 PVM pVM = pUVM->pVM;
1810 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1811
[901]1812 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_EXTERNAL);
1813}
1814
[24574]1815#endif /* !SSM_STANDALONE */
[990]1816
[24574]1817
[901]1818/**
[21866]1819 * Initializes the stream after/before opening the file/whatever.
1820 *
1821 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
1822 * @param pStrm The stream handle.
1823 * @param fChecksummed Whether the stream is to be checksummed while
1824 * written/read.
[21901]1825 * @param cBuffers The number of buffers.
[21866]1826 */
[23593]1827static int ssmR3StrmInitInternal(PSSMSTRM pStrm, bool fChecksummed, uint32_t cBuffers)
[21866]1828{
[21901]1829 Assert(cBuffers > 0);
1830
[21866]1831 /*
1832 * Init the common data members.
1833 */
1834 pStrm->fTerminating = false;
[21871]1835 pStrm->fNeedSeek = false;
[21866]1836 pStrm->rc = VINF_SUCCESS;
[21871]1837 pStrm->hIoThread = NIL_RTTHREAD;
[21900]1838 pStrm->offNeedSeekTo= UINT64_MAX;
[21866]1839
1840 pStrm->pHead = NULL;
1841 pStrm->pFree = NULL;
1842 pStrm->hEvtHead = NIL_RTSEMEVENT;
1843 pStrm->hEvtFree = NIL_RTSEMEVENT;
1844
1845 pStrm->pPending = NULL;
1846 pStrm->pCur = NULL;
1847 pStrm->offCurStream = 0;
1848 pStrm->off = 0;
1849 pStrm->fChecksummed = fChecksummed;
1850 pStrm->u32StreamCRC = fChecksummed ? RTCrc32Start() : 0;
1851 pStrm->offStreamCRC = 0;
1852
1853 /*
1854 * Allocate the buffers. Page align them in case that makes the kernel
1855 * and/or cpu happier in some way.
1856 */
1857 int rc = VINF_SUCCESS;
[21901]1858 for (uint32_t i = 0; i < cBuffers; i++)
[21866]1859 {
1860 PSSMSTRMBUF pBuf = (PSSMSTRMBUF)RTMemPageAllocZ(sizeof(*pBuf));
1861 if (!pBuf)
1862 {
1863 if (i > 2)
1864 {
1865 LogRel(("ssmR3StrmAllocBuffer: WARNING: Could only get %d stream buffers.\n", i));
1866 break;
1867 }
1868 LogRel(("ssmR3StrmAllocBuffer: Failed to allocate stream buffers. (i=%d)\n", i));
1869 return VERR_NO_MEMORY;
1870 }
1871
1872 /* link it */
1873 pBuf->pNext = pStrm->pFree;
1874 pStrm->pFree = pBuf;
1875 }
1876
1877 /*
1878 * Create the event semaphores.
1879 */
1880 rc = RTSemEventCreate(&pStrm->hEvtHead);
1881 if (RT_FAILURE(rc))
1882 return rc;
1883 rc = RTSemEventCreate(&pStrm->hEvtFree);
1884 if (RT_FAILURE(rc))
1885 return rc;
1886
1887 return VINF_SUCCESS;
1888}
1889
1890
1891/**
1892 * Destroys a list of buffers.
1893 *
1894 * @param pHead Pointer to the head.
1895 */
1896static void ssmR3StrmDestroyBufList(PSSMSTRMBUF pHead)
1897{
1898 while (pHead)
1899 {
1900 PSSMSTRMBUF pCur = pHead;
1901 pHead = pCur->pNext;
1902 pCur->pNext = NULL;
[28317]1903 RTMemPageFree(pCur, sizeof(*pCur));
[21866]1904 }
1905}
1906
1907
1908/**
[23593]1909 * Cleans up a stream after ssmR3StrmInitInternal has been called (regardless of
1910 * it succeeded or not).
[21866]1911 *
1912 * @param pStrm The stream handle.
1913 */
1914static void ssmR3StrmDelete(PSSMSTRM pStrm)
1915{
[28317]1916 RTMemPageFree(pStrm->pCur, sizeof(*pStrm->pCur));
[21866]1917 pStrm->pCur = NULL;
1918 ssmR3StrmDestroyBufList(pStrm->pHead);
1919 pStrm->pHead = NULL;
1920 ssmR3StrmDestroyBufList(pStrm->pPending);
1921 pStrm->pPending = NULL;
1922 ssmR3StrmDestroyBufList(pStrm->pFree);
1923 pStrm->pFree = NULL;
1924
1925 RTSemEventDestroy(pStrm->hEvtHead);
1926 pStrm->hEvtHead = NIL_RTSEMEVENT;
1927
1928 RTSemEventDestroy(pStrm->hEvtFree);
1929 pStrm->hEvtFree = NIL_RTSEMEVENT;
1930}
1931
1932
1933/**
[23593]1934 * Initializes a stream that uses a method table.
1935 *
1936 * @returns VBox status code.
1937 * @param pStrm The stream manager structure.
1938 * @param pStreamOps The stream method table.
1939 * @param pvUser The user argument for the stream methods.
1940 * @param fWrite Whether to open for writing or reading.
1941 * @param fChecksummed Whether the stream is to be checksummed while
1942 * written/read.
1943 * @param cBuffers The number of buffers.
1944 */
1945static int ssmR3StrmInit(PSSMSTRM pStrm, PCSSMSTRMOPS pStreamOps, void *pvUser, bool fWrite, bool fChecksummed, uint32_t cBuffers)
1946{
1947 int rc = ssmR3StrmInitInternal(pStrm, fChecksummed, cBuffers);
1948 if (RT_SUCCESS(rc))
1949 {
1950 pStrm->pOps = pStreamOps;
1951 pStrm->pvUser = pvUser;
1952 pStrm->fWrite = fWrite;
1953 return VINF_SUCCESS;
1954 }
1955
1956 ssmR3StrmDelete(pStrm);
1957 pStrm->rc = rc;
1958 return rc;
1959}
1960
1961
1962/**
[23589]1963 * @copydoc SSMSTRMOPS::pfnWrite
1964 */
1965static DECLCALLBACK(int) ssmR3FileWrite(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)
1966{
[77360]1967 NOREF(offStream);
[23589]1968 return RTFileWriteAt((RTFILE)(uintptr_t)pvUser, offStream, pvBuf, cbToWrite, NULL); /** @todo use RTFileWrite */
1969}
1970
1971
1972/**
1973 * @copydoc SSMSTRMOPS::pfnRead
1974 */
1975static DECLCALLBACK(int) ssmR3FileRead(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)
1976{
1977 Assert(RTFileTell((RTFILE)(uintptr_t)pvUser) == offStream); NOREF(offStream);
1978 return RTFileRead((RTFILE)(uintptr_t)pvUser, pvBuf, cbToRead, pcbRead);
1979}
1980
1981
1982/**
1983 * @copydoc SSMSTRMOPS::pfnSeek
1984 */
1985static DECLCALLBACK(int) ssmR3FileSeek(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
1986{
1987 return RTFileSeek((RTFILE)(uintptr_t)pvUser, offSeek, uMethod, poffActual);
1988}
1989
1990
1991/**
1992 * @copydoc SSMSTRMOPS::pfnTell
1993 */
1994static DECLCALLBACK(uint64_t) ssmR3FileTell(void *pvUser)
1995{
1996 return RTFileTell((RTFILE)(uintptr_t)pvUser);
1997}
1998
1999
2000/**
2001 * @copydoc SSMSTRMOPS::pfnSize
2002 */
2003static DECLCALLBACK(int) ssmR3FileSize(void *pvUser, uint64_t *pcb)
2004{
[80585]2005 return RTFileQuerySize((RTFILE)(uintptr_t)pvUser, pcb);
[23589]2006}
2007
2008
2009/**
[24895]2010 * @copydoc SSMSTRMOPS::pfnIsOk
2011 */
2012static DECLCALLBACK(int) ssmR3FileIsOk(void *pvUser)
2013{
2014 /*
2015 * Check that there is still some space left on the disk.
2016 */
2017 RTFOFF cbFree;
2018 int rc = RTFileQueryFsSizes((RTFILE)(uintptr_t)pvUser, NULL, &cbFree, NULL, NULL);
2019#define SSM_MIN_DISK_FREE ((RTFOFF)( 10 * _1M ))
2020 if (RT_SUCCESS(rc))
2021 {
2022 if (cbFree < SSM_MIN_DISK_FREE)
2023 {
2024 LogRel(("SSM: Giving up: Low on disk space. (cbFree=%RTfoff, SSM_MIN_DISK_FREE=%RTfoff).\n",
2025 cbFree, SSM_MIN_DISK_FREE));
2026 rc = VERR_SSM_LOW_ON_DISK_SPACE;
2027 }
2028 }
2029 else if (rc == VERR_NOT_SUPPORTED)
2030 rc = VINF_SUCCESS;
2031 else
2032 AssertLogRelRC(rc);
2033 return rc;
2034}
2035
2036
2037/**
[23589]2038 * @copydoc SSMSTRMOPS::pfnClose
2039 */
[24917]2040static DECLCALLBACK(int) ssmR3FileClose(void *pvUser, bool fCancelled)
[23589]2041{
[24917]2042 NOREF(fCancelled);
[23589]2043 return RTFileClose((RTFILE)(uintptr_t)pvUser);
2044}
2045
2046
2047/**
2048 * Method table for a file based stream.
2049 */
2050static SSMSTRMOPS const g_ssmR3FileOps =
2051{
2052 SSMSTRMOPS_VERSION,
2053 ssmR3FileWrite,
2054 ssmR3FileRead,
2055 ssmR3FileSeek,
2056 ssmR3FileTell,
2057 ssmR3FileSize,
[24895]2058 ssmR3FileIsOk,
[23589]2059 ssmR3FileClose,
2060 SSMSTRMOPS_VERSION
2061};
2062
2063
2064/**
[21866]2065 * Opens a file stream.
2066 *
2067 * @returns VBox status code.
2068 * @param pStrm The stream manager structure.
2069 * @param pszFilename The file to open or create.
2070 * @param fWrite Whether to open for writing or reading.
2071 * @param fChecksummed Whether the stream is to be checksummed while
2072 * written/read.
[21901]2073 * @param cBuffers The number of buffers.
[21866]2074 */
[21901]2075static int ssmR3StrmOpenFile(PSSMSTRM pStrm, const char *pszFilename, bool fWrite, bool fChecksummed, uint32_t cBuffers)
[21866]2076{
[23593]2077 int rc = ssmR3StrmInitInternal(pStrm, fChecksummed, cBuffers);
[21866]2078 if (RT_SUCCESS(rc))
2079 {
2080 uint32_t fFlags = fWrite
2081 ? RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE
2082 : RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
[23589]2083 RTFILE hFile;
2084 rc = RTFileOpen(&hFile, pszFilename, fFlags);
[21866]2085 if (RT_SUCCESS(rc))
2086 {
[23589]2087 pStrm->pOps = &g_ssmR3FileOps;
2088 pStrm->pvUser = (void *)(uintptr_t)hFile;
[21866]2089 pStrm->fWrite = fWrite;
2090 return VINF_SUCCESS;
2091 }
2092 }
2093
2094 ssmR3StrmDelete(pStrm);
2095 pStrm->rc = rc;
2096 return rc;
2097}
2098
2099
2100/**
2101 * Raise an error condition on the stream.
2102 *
2103 * @returns true if we raised the error condition, false if the stream already
2104 * had an error condition set.
2105 *
2106 * @param pStrm The stream handle.
2107 * @param rc The VBox error status code.
2108 *
2109 * @thread Any.
2110 */
2111DECLINLINE(bool) ssmR3StrmSetError(PSSMSTRM pStrm, int rc)
2112{
2113 Assert(RT_FAILURE_NP(rc));
2114 return ASMAtomicCmpXchgS32(&pStrm->rc, rc, VINF_SUCCESS);
2115}
2116
2117
2118/**
2119 * Puts a buffer into the free list.
2120 *
2121 * @param pStrm The stream handle.
2122 * @param pBuf The buffer.
2123 *
2124 * @thread The consumer.
2125 */
2126static void ssmR3StrmPutFreeBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
2127{
2128 for (;;)
2129 {
[30111]2130 PSSMSTRMBUF pCurFreeHead = ASMAtomicUoReadPtrT(&pStrm->pFree, PSSMSTRMBUF);
2131 ASMAtomicUoWritePtr(&pBuf->pNext, pCurFreeHead);
2132 if (ASMAtomicCmpXchgPtr(&pStrm->pFree, pBuf, pCurFreeHead))
[21866]2133 {
2134 int rc = RTSemEventSignal(pStrm->hEvtFree);
2135 AssertRC(rc);
2136 return;
2137 }
2138 }
2139}
2140
2141
2142/**
2143 * Gets a free buffer, waits for one if necessary.
2144 *
2145 * @returns Pointer to the buffer on success. NULL if we're terminating.
2146 * @param pStrm The stream handle.
2147 *
2148 * @thread The producer.
2149 */
2150static PSSMSTRMBUF ssmR3StrmGetFreeBuf(PSSMSTRM pStrm)
2151{
2152 for (;;)
2153 {
[30111]2154 PSSMSTRMBUF pMine = ASMAtomicUoReadPtrT(&pStrm->pFree, PSSMSTRMBUF);
[21866]2155 if (!pMine)
2156 {
2157 if (pStrm->fTerminating)
2158 return NULL;
2159 if (RT_FAILURE(pStrm->rc))
2160 return NULL;
[21897]2161 if ( pStrm->fWrite
2162 && pStrm->hIoThread == NIL_RTTHREAD)
2163 {
2164 int rc = ssmR3StrmWriteBuffers(pStrm);
2165 if (RT_FAILURE(rc))
2166 return NULL;
2167 }
[21866]2168 int rc = RTSemEventWaitNoResume(pStrm->hEvtFree, 30000);
2169 if ( rc == VERR_SEM_DESTROYED
2170 || pStrm->fTerminating)
2171 return NULL;
2172 continue;
2173 }
2174
[30111]2175 if (ASMAtomicCmpXchgPtr(&pStrm->pFree, pMine->pNext, pMine))
[21866]2176 {
2177 pMine->offStream = UINT64_MAX;
2178 pMine->cb = 0;
2179 pMine->pNext = NULL;
2180 pMine->fEndOfStream = false;
[24895]2181 pMine->NanoTS = RTTimeNanoTS();
[21866]2182 return pMine;
2183 }
2184 }
2185}
2186
2187
2188/**
2189 * Puts a buffer onto the queue.
2190 *
[58126]2191 * @param pStrm The stream handle.
2192 * @param pBuf The stream buffer to put.
[21866]2193 *
2194 * @thread The producer.
2195 */
2196static void ssmR3StrmPutBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
2197{
2198 for (;;)
2199 {
[30111]2200 PSSMSTRMBUF pCurHead = ASMAtomicUoReadPtrT(&pStrm->pHead, PSSMSTRMBUF);
2201 ASMAtomicUoWritePtr(&pBuf->pNext, pCurHead);
2202 if (ASMAtomicCmpXchgPtr(&pStrm->pHead, pBuf, pCurHead))
[21866]2203 {
2204 int rc = RTSemEventSignal(pStrm->hEvtHead);
2205 AssertRC(rc);
2206 return;
2207 }
2208 }
2209}
2210
2211
2212/**
2213 * Reverses the list.
2214 *
2215 * @returns The head of the reversed list.
2216 * @param pHead The head of the list to reverse.
2217 */
2218static PSSMSTRMBUF ssmR3StrmReverseList(PSSMSTRMBUF pHead)
2219{
2220 PSSMSTRMBUF pRevHead = NULL;
2221 while (pHead)
2222 {
2223 PSSMSTRMBUF pCur = pHead;
2224 pHead = pCur->pNext;
2225 pCur->pNext = pRevHead;
2226 pRevHead = pCur;
2227 }
2228 return pRevHead;
2229}
2230
2231
2232/**
2233 * Gets one buffer from the queue, will wait for one to become ready if
2234 * necessary.
2235 *
2236 * @returns Pointer to the buffer on success. NULL if we're terminating.
[58126]2237 * @param pStrm The stream handle.
[21866]2238 *
2239 * @thread The consumer.
2240 */
2241static PSSMSTRMBUF ssmR3StrmGetBuf(PSSMSTRM pStrm)
2242{
2243 for (;;)
2244 {
2245 PSSMSTRMBUF pMine = pStrm->pPending;
2246 if (pMine)
2247 {
2248 pStrm->pPending = pMine->pNext;
2249 pMine->pNext = NULL;
2250 return pMine;
2251 }
2252
[30111]2253 pMine = ASMAtomicXchgPtrT(&pStrm->pHead, NULL, PSSMSTRMBUF);
[21866]2254 if (pMine)
2255 pStrm->pPending = ssmR3StrmReverseList(pMine);
2256 else
2257 {
2258 if (pStrm->fTerminating)
2259 return NULL;
2260 if (RT_FAILURE(pStrm->rc))
2261 return NULL;
[21900]2262 if ( !pStrm->fWrite
2263 && pStrm->hIoThread == NIL_RTTHREAD)
2264 {
2265 int rc = ssmR3StrmReadMore(pStrm);
2266 if (RT_FAILURE(rc))
2267 return NULL;
2268 continue;
2269 }
2270
[21866]2271 int rc = RTSemEventWaitNoResume(pStrm->hEvtHead, 30000);
2272 if ( rc == VERR_SEM_DESTROYED
2273 || pStrm->fTerminating)
2274 return NULL;
2275 }
2276 }
2277}
2278
2279
2280/**
2281 * Flushes the current buffer (both write and read streams).
2282 *
2283 * @param pStrm The stream handle.
2284 */
2285static void ssmR3StrmFlushCurBuf(PSSMSTRM pStrm)
2286{
2287 if (pStrm->pCur)
2288 {
[21871]2289 PSSMSTRMBUF pBuf = pStrm->pCur;
[21866]2290 pStrm->pCur = NULL;
2291
2292 if (pStrm->fWrite)
2293 {
2294 uint32_t cb = pStrm->off;
[21871]2295 pBuf->cb = cb;
2296 pBuf->offStream = pStrm->offCurStream;
[21866]2297 if ( pStrm->fChecksummed
2298 && pStrm->offStreamCRC < cb)
2299 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
[21871]2300 &pBuf->abData[pStrm->offStreamCRC],
[21866]2301 cb - pStrm->offStreamCRC);
2302 pStrm->offCurStream += cb;
[21900]2303 pStrm->off = 0;
2304 pStrm->offStreamCRC = 0;
[21866]2305
[21871]2306 ssmR3StrmPutBuf(pStrm, pBuf);
[21866]2307 }
2308 else
2309 {
[21871]2310 uint32_t cb = pBuf->cb;
[21866]2311 if ( pStrm->fChecksummed
2312 && pStrm->offStreamCRC < cb)
2313 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
[21871]2314 &pBuf->abData[pStrm->offStreamCRC],
[21866]2315 cb - pStrm->offStreamCRC);
2316 pStrm->offCurStream += cb;
[21900]2317 pStrm->off = 0;
2318 pStrm->offStreamCRC = 0;
[21866]2319
[21871]2320 ssmR3StrmPutFreeBuf(pStrm, pBuf);
[21866]2321 }
2322 }
2323}
2324
2325
2326/**
[21894]2327 * Flush buffered data.
[21866]2328 *
[21901]2329 * @returns VBox status code. Returns VINF_EOF if we encounter a buffer with the
2330 * fEndOfStream indicator set.
[21866]2331 * @param pStrm The stream handle.
2332 *
2333 * @thread The producer thread.
2334 */
[21894]2335static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm)
[21866]2336{
[21894]2337 Assert(pStrm->fWrite);
2338
[21866]2339 /*
[21894]2340 * Just return if the stream has a pending error condition.
[21866]2341 */
2342 int rc = pStrm->rc;
2343 if (RT_FAILURE(rc))
2344 return rc;
2345
2346 /*
2347 * Grab the pending list and write it out.
2348 */
[30111]2349 PSSMSTRMBUF pHead = ASMAtomicXchgPtrT(&pStrm->pHead, NULL, PSSMSTRMBUF);
[21866]2350 if (!pHead)
2351 return VINF_SUCCESS;
2352 pHead = ssmR3StrmReverseList(pHead);
2353
2354 while (pHead)
2355 {
2356 /* pop */
2357 PSSMSTRMBUF pCur = pHead;
2358 pHead = pCur->pNext;
2359
2360 /* flush */
[25235]2361 rc = pStrm->pOps->pfnIsOk(pStrm->pvUser);
[24895]2362 if (RT_SUCCESS(rc))
2363 rc = pStrm->pOps->pfnWrite(pStrm->pvUser, pCur->offStream, &pCur->abData[0], pCur->cb);
[21866]2364 if ( RT_FAILURE(rc)
2365 && ssmR3StrmSetError(pStrm, rc))
[24895]2366 LogRel(("ssmR3StrmWriteBuffers: Write failed with rc=%Rrc at offStream=%#llx\n", rc, pCur->offStream));
[21866]2367
[21952]2368 /* free */
[21901]2369 bool fEndOfStream = pCur->fEndOfStream;
[21866]2370 ssmR3StrmPutFreeBuf(pStrm, pCur);
[21901]2371 if (fEndOfStream)
2372 {
2373 Assert(!pHead);
2374 return VINF_EOF;
2375 }
[21866]2376 }
2377
2378 return pStrm->rc;
2379}
2380
2381
2382/**
2383 * Closes the stream after first flushing any pending write.
2384 *
2385 * @returns VBox status code.
2386 * @param pStrm The stream handle.
[24917]2387 * @param fCancelled Indicates whether the operation was cancelled or
2388 * not.
[21866]2389 */
[24917]2390static int ssmR3StrmClose(PSSMSTRM pStrm, bool fCancelled)
[21866]2391{
2392 /*
[21900]2393 * Flush, terminate the I/O thread, and close the stream.
[21866]2394 */
[21894]2395 if (pStrm->fWrite)
2396 {
2397 ssmR3StrmFlushCurBuf(pStrm);
[21900]2398 if (pStrm->hIoThread == NIL_RTTHREAD)
2399 ssmR3StrmWriteBuffers(pStrm);
[21894]2400 }
[21900]2401
2402 if (pStrm->hIoThread != NIL_RTTHREAD)
[23668]2403 ASMAtomicWriteBool(&pStrm->fTerminating, true);
2404
2405 int rc;
2406 if (pStrm->fWrite)
[21900]2407 {
[23729]2408 if (pStrm->hIoThread != NIL_RTTHREAD)
2409 {
[24897]2410 int rc2 = RTSemEventSignal(pStrm->hEvtHead);
[23729]2411 AssertLogRelRC(rc2);
2412 int rc3 = RTThreadWait(pStrm->hIoThread, RT_INDEFINITE_WAIT, NULL);
2413 AssertLogRelRC(rc3);
2414 pStrm->hIoThread = NIL_RTTHREAD;
2415 }
[23668]2416
[24917]2417 rc = pStrm->pOps->pfnClose(pStrm->pvUser, fCancelled);
[23668]2418 if (RT_FAILURE(rc))
2419 ssmR3StrmSetError(pStrm, rc);
[21900]2420 }
[23668]2421 else
2422 {
[24917]2423 rc = pStrm->pOps->pfnClose(pStrm->pvUser, fCancelled);
[23668]2424 if (RT_FAILURE(rc))
2425 ssmR3StrmSetError(pStrm, rc);
[21900]2426
[23729]2427 if (pStrm->hIoThread != NIL_RTTHREAD)
2428 {
[23761]2429 int rc2 = RTSemEventSignal(pStrm->hEvtFree);
[23729]2430 AssertLogRelRC(rc2);
2431 int rc3 = RTThreadWait(pStrm->hIoThread, RT_INDEFINITE_WAIT, NULL);
2432 AssertLogRelRC(rc3);
2433 pStrm->hIoThread = NIL_RTTHREAD;
2434 }
[23668]2435 }
2436
[23589]2437 pStrm->pOps = NULL;
2438 pStrm->pvUser = NULL;
[21866]2439
2440 rc = pStrm->rc;
2441 ssmR3StrmDelete(pStrm);
2442
2443 return rc;
2444}
2445
[39078]2446#ifndef SSM_STANDALONE
[21866]2447
2448/**
[21797]2449 * Stream output routine.
2450 *
2451 * @returns VBox status code.
[21866]2452 * @param pStrm The stream handle.
[21797]2453 * @param pvBuf What to write.
2454 * @param cbToWrite How much to write.
[21866]2455 *
2456 * @thread The producer in a write stream (never the I/O thread).
[21797]2457 */
[21866]2458static int ssmR3StrmWrite(PSSMSTRM pStrm, const void *pvBuf, size_t cbToWrite)
[21797]2459{
[21866]2460 AssertReturn(cbToWrite > 0, VINF_SUCCESS);
2461 Assert(pStrm->fWrite);
2462
2463 /*
2464 * Squeeze as much as possible into the current buffer.
2465 */
2466 PSSMSTRMBUF pBuf = pStrm->pCur;
2467 if (RT_LIKELY(pBuf))
2468 {
[21871]2469 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
[21866]2470 if (RT_LIKELY(cbLeft >= cbToWrite))
2471 {
2472 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbToWrite);
[21871]2473 pStrm->off += (uint32_t)cbToWrite;
[21866]2474 return VINF_SUCCESS;
2475 }
2476
2477 if (cbLeft > 0)
2478 {
2479 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbLeft);
2480 pStrm->off += cbLeft;
2481 cbToWrite -= cbLeft;
2482 pvBuf = (uint8_t const *)pvBuf + cbLeft;
2483 }
[21871]2484 Assert(pStrm->off == RT_SIZEOFMEMB(SSMSTRMBUF, abData));
[21866]2485 }
2486
2487 /*
2488 * Need one or more new buffers.
2489 */
2490 do
2491 {
2492 /*
2493 * Flush the current buffer and replace it with a new one.
2494 */
[21894]2495 ssmR3StrmFlushCurBuf(pStrm);
[21866]2496 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2497 if (!pBuf)
2498 break;
2499 pStrm->pCur = pBuf;
2500 Assert(pStrm->off == 0);
2501
2502 /*
2503 * Copy data to the buffer.
2504 */
[21871]2505 uint32_t cbCopy = RT_SIZEOFMEMB(SSMSTRMBUF, abData);
[21866]2506 if (cbCopy > cbToWrite)
[21871]2507 cbCopy = (uint32_t)cbToWrite;
2508 memcpy(&pBuf->abData[0], pvBuf, cbCopy);
2509 pStrm->off = cbCopy;
[21866]2510 cbToWrite -= cbCopy;
2511 pvBuf = (uint8_t const *)pvBuf + cbCopy;
2512 } while (cbToWrite > 0);
2513
2514 return pStrm->rc;
2515}
2516
2517
[21897]2518/**
2519 * Reserves space in the current buffer so the caller can write directly to the
2520 * buffer instead of doing double buffering.
2521 *
2522 * @returns VBox status code
2523 * @param pStrm The stream handle.
2524 * @param cb The amount of buffer space to reserve.
2525 * @param ppb Where to return the pointer.
2526 */
2527static int ssmR3StrmReserveWriteBufferSpace(PSSMSTRM pStrm, size_t cb, uint8_t **ppb)
2528{
2529 Assert(pStrm->fWrite);
2530 Assert(RT_SIZEOFMEMB(SSMSTRMBUF, abData) / 4 >= cb);
[21866]2531
[21897]2532 /*
2533 * Check if there is room in the current buffer, it not flush it.
2534 */
2535 PSSMSTRMBUF pBuf = pStrm->pCur;
2536 if (pBuf)
2537 {
2538 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
2539 if (cbLeft >= cb)
2540 {
2541 *ppb = &pBuf->abData[pStrm->off];
2542 return VINF_SUCCESS;
2543 }
2544
2545 ssmR3StrmFlushCurBuf(pStrm);
2546 }
2547
2548 /*
2549 * Get a fresh buffer and return a pointer into it.
2550 */
2551 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2552 if (pBuf)
2553 {
2554 pStrm->pCur = pBuf;
2555 Assert(pStrm->off == 0);
2556 *ppb = &pBuf->abData[0];
2557 }
2558 else
2559 *ppb = NULL; /* make gcc happy. */
2560 return pStrm->rc;
2561}
2562
2563
[21866]2564/**
[21897]2565 * Commits buffer space reserved by ssmR3StrmReserveWriteBufferSpace.
2566 *
2567 * @returns VBox status code.
2568 * @param pStrm The stream handle.
2569 * @param cb The amount of buffer space to commit. This can be less
2570 * that what was reserved initially.
2571 */
2572static int ssmR3StrmCommitWriteBufferSpace(PSSMSTRM pStrm, size_t cb)
2573{
2574 Assert(pStrm->pCur);
2575 Assert(pStrm->off + cb <= RT_SIZEOFMEMB(SSMSTRMBUF, abData));
[26526]2576 pStrm->off += (uint32_t)cb;
[21897]2577 return VINF_SUCCESS;
2578}
2579
2580
2581/**
[21901]2582 * Marks the end of the stream.
2583 *
2584 * This will cause the I/O thread to quit waiting for more buffers.
2585 *
2586 * @returns VBox status code.
2587 * @param pStrm The stream handle.
2588 */
2589static int ssmR3StrmSetEnd(PSSMSTRM pStrm)
2590{
2591 Assert(pStrm->fWrite);
2592 PSSMSTRMBUF pBuf = pStrm->pCur;
2593 if (RT_UNLIKELY(!pStrm->pCur))
2594 {
2595 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2596 if (!pBuf)
2597 return pStrm->rc;
2598 pStrm->pCur = pBuf;
2599 Assert(pStrm->off == 0);
2600 }
2601 pBuf->fEndOfStream = true;
2602 ssmR3StrmFlushCurBuf(pStrm);
2603 return VINF_SUCCESS;
2604}
2605
[39078]2606#endif /* !SSM_STANDALONE */
[21901]2607
2608/**
[21866]2609 * Read more from the stream.
2610 *
[21900]2611 * @returns VBox status code. VERR_EOF gets translated into VINF_EOF.
[21866]2612 * @param pStrm The stream handle.
2613 *
[21900]2614 * @thread The I/O thread when we got one, otherwise the stream user.
[21866]2615 */
2616static int ssmR3StrmReadMore(PSSMSTRM pStrm)
2617{
[21871]2618 int rc;
[21900]2619 Log6(("ssmR3StrmReadMore:\n"));
[21871]2620
2621 /*
2622 * Undo seek done by ssmR3StrmPeekAt.
2623 */
2624 if (pStrm->fNeedSeek)
2625 {
[23589]2626 rc = pStrm->pOps->pfnSeek(pStrm->pvUser, pStrm->offNeedSeekTo, RTFILE_SEEK_BEGIN, NULL);
[21871]2627 if (RT_FAILURE(rc))
2628 {
2629 if (ssmR3StrmSetError(pStrm, rc))
[21900]2630 LogRel(("ssmR3StrmReadMore: RTFileSeek(,%#llx,) failed with rc=%Rrc\n", pStrm->offNeedSeekTo, rc));
[21871]2631 return rc;
2632 }
[21900]2633 pStrm->fNeedSeek = false;
2634 pStrm->offNeedSeekTo = UINT64_MAX;
[21871]2635 }
2636
2637 /*
2638 * Get a free buffer and try fill it up.
2639 */
[21866]2640 PSSMSTRMBUF pBuf = ssmR3StrmGetFreeBuf(pStrm);
2641 if (!pBuf)
2642 return pStrm->rc;
2643
[23589]2644 pBuf->offStream = pStrm->pOps->pfnTell(pStrm->pvUser);
[21866]2645 size_t cbRead = sizeof(pBuf->abData);
[23589]2646 rc = pStrm->pOps->pfnRead(pStrm->pvUser, pBuf->offStream, &pBuf->abData[0], cbRead, &cbRead);
[21900]2647 if ( RT_SUCCESS(rc)
2648 && cbRead > 0)
[21797]2649 {
[21871]2650 pBuf->cb = (uint32_t)cbRead;
[21900]2651 pBuf->fEndOfStream = false;
2652 Log6(("ssmR3StrmReadMore: %#010llx %#x\n", pBuf->offStream, pBuf->cb));
[21866]2653 ssmR3StrmPutBuf(pStrm, pBuf);
[21797]2654 }
[21900]2655 else if ( ( RT_SUCCESS_NP(rc)
2656 && cbRead == 0)
2657 || rc == VERR_EOF)
[21866]2658 {
2659 pBuf->cb = 0;
2660 pBuf->fEndOfStream = true;
[21900]2661 Log6(("ssmR3StrmReadMore: %#010llx 0 EOF!\n", pBuf->offStream));
[21866]2662 ssmR3StrmPutBuf(pStrm, pBuf);
[21900]2663 rc = VINF_EOF;
[21866]2664 }
2665 else
2666 {
[21900]2667 Log6(("ssmR3StrmReadMore: %#010llx rc=%Rrc!\n", pBuf->offStream, rc));
[21866]2668 if (ssmR3StrmSetError(pStrm, rc))
2669 LogRel(("ssmR3StrmReadMore: RTFileRead(,,%#x,) -> %Rrc at offset %#llx\n",
2670 sizeof(pBuf->abData), rc, pBuf->offStream));
2671 ssmR3StrmPutFreeBuf(pStrm, pBuf);
2672 }
[21797]2673 return rc;
2674}
2675
2676
2677/**
2678 * Stream input routine.
2679 *
2680 * @returns VBox status code.
[21866]2681 * @param pStrm The stream handle.
[21797]2682 * @param pvBuf Where to put what we read.
2683 * @param cbToRead How much to read.
2684 */
[21866]2685static int ssmR3StrmRead(PSSMSTRM pStrm, void *pvBuf, size_t cbToRead)
[21797]2686{
[21866]2687 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2688 Assert(!pStrm->fWrite);
2689
2690 /*
2691 * Read from the current buffer if we got one.
2692 */
2693 PSSMSTRMBUF pBuf = pStrm->pCur;
2694 if (RT_LIKELY(pBuf))
[21797]2695 {
[21866]2696 Assert(pStrm->off <= pBuf->cb);
[21871]2697 uint32_t cbLeft = pBuf->cb - pStrm->off;
[21866]2698 if (cbLeft >= cbToRead)
2699 {
2700 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbToRead);
[21871]2701 pStrm->off += (uint32_t)cbToRead;
2702 Assert(pStrm->off <= pBuf->cb);
[21866]2703 return VINF_SUCCESS;
2704 }
2705 if (cbLeft)
2706 {
2707 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbLeft);
2708 pStrm->off += cbLeft;
2709 cbToRead -= cbLeft;
2710 pvBuf = (uint8_t *)pvBuf + cbLeft;
2711 }
2712 else if (pBuf->fEndOfStream)
2713 return VERR_EOF;
[21871]2714 Assert(pStrm->off == pBuf->cb);
[21797]2715 }
2716
[21866]2717 /*
2718 * Get more buffers from the stream.
2719 */
[21897]2720 int rc = VINF_SUCCESS;
[21866]2721 do
2722 {
2723 /*
2724 * Check for EOF first - never flush the EOF buffer.
2725 */
2726 if ( pBuf
2727 && pBuf->fEndOfStream)
2728 return VERR_EOF;
2729
2730 /*
2731 * Flush the current buffer and get the next one.
2732 */
2733 ssmR3StrmFlushCurBuf(pStrm);
[25235]2734 pBuf = ssmR3StrmGetBuf(pStrm);
[21866]2735 if (!pBuf)
2736 {
2737 rc = pStrm->rc;
2738 break;
2739 }
2740 pStrm->pCur = pBuf;
2741 Assert(pStrm->off == 0);
2742 Assert(pStrm->offCurStream == pBuf->offStream);
2743 if (!pBuf->cb)
2744 {
2745 Assert(pBuf->fEndOfStream);
2746 return VERR_EOF;
2747 }
2748
2749 /*
2750 * Read data from the buffer.
2751 */
[21871]2752 uint32_t cbCopy = pBuf->cb;
[21866]2753 if (cbCopy > cbToRead)
[21871]2754 cbCopy = (uint32_t)cbToRead;
2755 memcpy(pvBuf, &pBuf->abData[0], cbCopy);
2756 pStrm->off = cbCopy;
[21866]2757 cbToRead -= cbCopy;
2758 pvBuf = (uint8_t *)pvBuf + cbCopy;
[21871]2759 Assert(!pStrm->pCur || pStrm->off <= pStrm->pCur->cb);
[21866]2760 } while (cbToRead > 0);
2761
[21797]2762 return rc;
2763}
2764
2765
2766/**
[21897]2767 * Reads data from the stream but instead of copying it to some output buffer
2768 * the caller gets a pointer to into the current stream buffer.
2769 *
2770 * The returned pointer becomes invalid after the next stream operation!
2771 *
2772 * @returns Pointer to the read data residing in the stream buffer. NULL is
2773 * returned if the request amount of data isn't available in the
2774 * buffer. The caller must fall back on ssmR3StrmRead when this
2775 * happens.
2776 *
2777 * @param pStrm The stream handle.
2778 * @param cbToRead The number of bytes to tread.
2779 */
2780static uint8_t const *ssmR3StrmReadDirect(PSSMSTRM pStrm, size_t cbToRead)
2781{
2782 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2783 Assert(!pStrm->fWrite);
2784
2785 /*
2786 * Too lazy to fetch more data for the odd case that we're
[33540]2787 * exactly at the boundary between two buffers.
[21897]2788 */
2789 PSSMSTRMBUF pBuf = pStrm->pCur;
2790 if (RT_LIKELY(pBuf))
2791 {
2792 Assert(pStrm->off <= pBuf->cb);
2793 uint32_t cbLeft = pBuf->cb - pStrm->off;
2794 if (cbLeft >= cbToRead)
2795 {
2796 uint8_t const *pb = &pBuf->abData[pStrm->off];
2797 pStrm->off += (uint32_t)cbToRead;
2798 Assert(pStrm->off <= pBuf->cb);
2799 return pb;
2800 }
2801 }
2802 return NULL;
2803}
2804
2805
[39078]2806#ifndef SSM_STANDALONE
[21897]2807/**
[24895]2808 * Check that the stream is OK and flush data that is getting old
2809 *
2810 * The checking is mainly for testing for cancellation and out of space
2811 * conditions.
2812 *
2813 * @returns VBox status code.
2814 * @param pStrm The stream handle.
2815 */
2816static int ssmR3StrmCheckAndFlush(PSSMSTRM pStrm)
2817{
2818 int rc = pStrm->pOps->pfnIsOk(pStrm->pvUser);
2819 if (RT_FAILURE(rc))
2820 return rc;
2821
2822 if ( pStrm->fWrite
2823 && pStrm->hIoThread != NIL_RTTHREAD
2824 && !pStrm->pHead /* the worker is probably idle */
2825 && pStrm->pCur
2826 && RTTimeNanoTS() - pStrm->pCur->NanoTS > 500*1000*1000 /* 0.5s */
2827 )
2828 ssmR3StrmFlushCurBuf(pStrm);
2829 return VINF_SUCCESS;
2830}
[39078]2831#endif /* !SSM_STANDALONE */
[24895]2832
[62869]2833
2834#if !defined(SSM_STANDALONE) || defined(LOG_ENABLED)
[24895]2835/**
[21866]2836 * Tell current stream position.
[21797]2837 *
[21866]2838 * @returns stream position.
2839 * @param pStrm The stream handle.
2840 */
2841static uint64_t ssmR3StrmTell(PSSMSTRM pStrm)
2842{
2843 return pStrm->offCurStream + pStrm->off;
2844}
[62869]2845#endif
[21866]2846
2847
2848/**
2849 * Gets the intermediate stream CRC up to the current position.
2850 *
2851 * @returns CRC.
2852 * @param pStrm The stream handle.
2853 */
2854static uint32_t ssmR3StrmCurCRC(PSSMSTRM pStrm)
2855{
2856 if (!pStrm->fChecksummed)
2857 return 0;
2858 if (pStrm->offStreamCRC < pStrm->off)
2859 {
2860 PSSMSTRMBUF pBuf = pStrm->pCur; Assert(pBuf);
[21871]2861 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC, &pBuf->abData[pStrm->offStreamCRC], pStrm->off - pStrm->offStreamCRC);
2862 pStrm->offStreamCRC = pStrm->off;
[21866]2863 }
2864 else
2865 Assert(pStrm->offStreamCRC == pStrm->off);
2866 return pStrm->u32StreamCRC;
2867}
2868
2869
2870/**
2871 * Gets the final stream CRC up to the current position.
2872 *
2873 * @returns CRC.
2874 * @param pStrm The stream handle.
2875 */
2876static uint32_t ssmR3StrmFinalCRC(PSSMSTRM pStrm)
2877{
2878 if (!pStrm->fChecksummed)
2879 return 0;
2880 return RTCrc32Finish(ssmR3StrmCurCRC(pStrm));
2881}
2882
2883
2884/**
2885 * Disables checksumming of the stream.
2886 *
2887 * @param pStrm The stream handle.
2888 */
2889static void ssmR3StrmDisableChecksumming(PSSMSTRM pStrm)
2890{
2891 pStrm->fChecksummed = false;
2892}
2893
2894
2895/**
[21892]2896 * Used by SSMR3Seek to position the stream at the new unit.
[21871]2897 *
[33540]2898 * @returns VBox status code.
[21871]2899 * @param pStrm The strem handle.
2900 * @param off The seek offset.
2901 * @param uMethod The seek method.
[21892]2902 * @param u32CurCRC The current CRC at the seek position.
[21871]2903 */
[21892]2904static int ssmR3StrmSeek(PSSMSTRM pStrm, int64_t off, uint32_t uMethod, uint32_t u32CurCRC)
[21871]2905{
2906 AssertReturn(!pStrm->fWrite, VERR_NOT_SUPPORTED);
2907 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
2908
2909 uint64_t offStream;
[23589]2910 int rc = pStrm->pOps->pfnSeek(pStrm->pvUser, off, uMethod, &offStream);
[21871]2911 if (RT_SUCCESS(rc))
2912 {
[21892]2913 pStrm->fNeedSeek = false;
[21900]2914 pStrm->offNeedSeekTo= UINT64_MAX;
[21871]2915 pStrm->offCurStream = offStream;
[21892]2916 pStrm->off = 0;
[21871]2917 pStrm->offStreamCRC = 0;
[21892]2918 if (pStrm->fChecksummed)
2919 pStrm->u32StreamCRC = u32CurCRC;
[21871]2920 if (pStrm->pCur)
2921 {
2922 ssmR3StrmPutFreeBuf(pStrm, pStrm->pCur);
2923 pStrm->pCur = NULL;
2924 }
[56965]2925 if (pStrm->pPending)
2926 {
2927 ssmR3StrmDestroyBufList(pStrm->pPending);
2928 pStrm->pPending = NULL;
2929 }
2930 if (pStrm->pHead)
2931 {
2932 ssmR3StrmDestroyBufList(pStrm->pHead);
2933 pStrm->pHead = NULL;
2934 }
[21871]2935 }
2936 return rc;
2937}
2938
2939
[39078]2940#ifndef SSM_STANDALONE
[21871]2941/**
[21866]2942 * Skip some bytes in the stream.
2943 *
2944 * This is only used if someone didn't read all of their data in the V1 format,
2945 * so don't bother making this very efficient yet.
2946 *
[21797]2947 * @returns VBox status code.
[21866]2948 * @param pStrm The stream handle.
2949 * @param offDst The destination offset.
[21797]2950 */
[21866]2951static int ssmR3StrmSkipTo(PSSMSTRM pStrm, uint64_t offDst)
[21797]2952{
[21866]2953 /* dead simple - lazy bird! */
2954 for (;;)
2955 {
2956 uint64_t offCur = ssmR3StrmTell(pStrm);
[39402]2957 AssertReturn(offCur <= offDst, VERR_SSM_SKIP_BACKWARDS);
[21866]2958 if (offCur == offDst)
2959 return VINF_SUCCESS;
2960
2961 uint8_t abBuf[4096];
2962 size_t cbToRead = RT_MIN(sizeof(abBuf), offDst - offCur);
2963 int rc = ssmR3StrmRead(pStrm, abBuf, cbToRead);
2964 if (RT_FAILURE(rc))
2965 return rc;
2966 }
[21797]2967}
[39078]2968#endif /* !SSM_STANDALONE */
[21797]2969
2970
2971/**
[21866]2972 * Get the size of the file.
[21797]2973 *
[21866]2974 * This does not work for non-file streams!
2975 *
2976 * @returns The file size, or UINT64_MAX if not a file stream.
2977 * @param pStrm The stream handle.
[21797]2978 */
[21866]2979static uint64_t ssmR3StrmGetSize(PSSMSTRM pStrm)
[21797]2980{
[21866]2981 uint64_t cbFile;
[23589]2982 int rc = pStrm->pOps->pfnSize(pStrm->pvUser, &cbFile);
[21866]2983 AssertLogRelRCReturn(rc, UINT64_MAX);
2984 return cbFile;
[21797]2985}
2986
2987
[21871]2988/***
2989 * Tests if the stream is a file stream or not.
2990 *
2991 * @returns true / false.
2992 * @param pStrm The stream handle.
2993 */
2994static bool ssmR3StrmIsFile(PSSMSTRM pStrm)
2995{
[23589]2996 return pStrm->pOps == &g_ssmR3FileOps;
[21871]2997}
[21797]2998
[21871]2999
[21797]3000/**
[21871]3001 * Peeks at data in a file stream without buffering anything (or upsetting
3002 * the buffering for that matter).
3003 *
3004 * @returns VBox status code.
3005 * @param pStrm The stream handle
3006 * @param off The offset to start peeking at. Use a negative offset to
3007 * peek at something relative to the end of the file.
3008 * @param pvBuf Output buffer.
3009 * @param cbToRead How much to read.
3010 * @param poff Where to optionally store the position. Useful when
3011 * using a negative off.
3012 *
[33540]3013 * @remarks Failures occurring while peeking will not be raised on the stream.
[21871]3014 */
3015static int ssmR3StrmPeekAt(PSSMSTRM pStrm, RTFOFF off, void *pvBuf, size_t cbToRead, uint64_t *poff)
3016{
[23589]3017 AssertReturn(!pStrm->fWrite, VERR_NOT_SUPPORTED);
[21871]3018 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
3019
[21900]3020 if (!pStrm->fNeedSeek)
3021 {
3022 pStrm->fNeedSeek = true;
3023 pStrm->offNeedSeekTo = pStrm->offCurStream + (pStrm->pCur ? pStrm->pCur->cb : 0);
3024 }
[23589]3025 uint64_t offActual;
3026 int rc = pStrm->pOps->pfnSeek(pStrm->pvUser, off, off >= 0 ? RTFILE_SEEK_BEGIN : RTFILE_SEEK_END, &offActual);
[21871]3027 if (RT_SUCCESS(rc))
[23589]3028 {
3029 if (poff)
3030 *poff = offActual;
3031 rc = pStrm->pOps->pfnRead(pStrm->pvUser, offActual, pvBuf, cbToRead, NULL);
3032 }
[21871]3033
3034 return rc;
3035}
3036
[39078]3037#ifndef SSM_STANDALONE
[21871]3038
3039/**
[21900]3040 * The I/O thread.
3041 *
3042 * @returns VINF_SUCCESS (ignored).
3043 * @param hSelf The thread handle.
3044 * @param pvStrm The stream handle.
3045 */
3046static DECLCALLBACK(int) ssmR3StrmIoThread(RTTHREAD hSelf, void *pvStrm)
3047{
3048 PSSMSTRM pStrm = (PSSMSTRM)pvStrm;
3049 ASMAtomicWriteHandle(&pStrm->hIoThread, hSelf); /* paranoia */
3050
3051 Log(("ssmR3StrmIoThread: starts working\n"));
3052 if (pStrm->fWrite)
3053 {
3054 /*
3055 * Write until error or terminated.
3056 */
3057 for (;;)
3058 {
[21901]3059 int rc = ssmR3StrmWriteBuffers(pStrm);
3060 if ( RT_FAILURE(rc)
3061 || rc == VINF_EOF)
3062 {
3063 Log(("ssmR3StrmIoThread: quitting writing with rc=%Rrc.\n", rc));
3064 break;
3065 }
3066 if (RT_FAILURE(pStrm->rc))
3067 {
3068 Log(("ssmR3StrmIoThread: quitting writing with stream rc=%Rrc\n", pStrm->rc));
3069 break;
3070 }
[21900]3071
[21901]3072 if (ASMAtomicReadBool(&pStrm->fTerminating))
3073 {
[30111]3074 if (!ASMAtomicReadPtrT(&pStrm->pHead, PSSMSTRMBUF))
[21901]3075 {
3076 Log(("ssmR3StrmIoThread: quitting writing because of pending termination.\n"));
3077 break;
3078 }
3079 Log(("ssmR3StrmIoThread: postponing termination because of pending buffers.\n"));
3080 }
[30111]3081 else if (!ASMAtomicReadPtrT(&pStrm->pHead, PSSMSTRMBUF))
[21901]3082 {
3083 rc = RTSemEventWait(pStrm->hEvtHead, RT_INDEFINITE_WAIT);
3084 AssertLogRelRC(rc);
3085 }
[21900]3086 }
[29954]3087
3088 if (!ASMAtomicReadBool(&pStrm->fTerminating))
3089 RTSemEventSignal(pStrm->hEvtFree);
[21900]3090 }
3091 else
3092 {
3093 /*
3094 * Read until end of file, error or termination.
3095 */
3096 for (;;)
3097 {
3098 if (ASMAtomicReadBool(&pStrm->fTerminating))
3099 {
3100 Log(("ssmR3StrmIoThread: quitting reading because of pending termination.\n"));
3101 break;
3102 }
3103
3104 int rc = ssmR3StrmReadMore(pStrm);
3105 if ( RT_FAILURE(rc)
3106 || rc == VINF_EOF)
3107 {
3108 Log(("ssmR3StrmIoThread: quitting reading with rc=%Rrc\n", rc));
3109 break;
3110 }
3111 if (RT_FAILURE(pStrm->rc))
3112 {
3113 Log(("ssmR3StrmIoThread: quitting reading with stream rc=%Rrc\n", pStrm->rc));
3114 break;
3115 }
3116 }
[29954]3117
3118 if (!ASMAtomicReadBool(&pStrm->fTerminating))
3119 RTSemEventSignal(pStrm->hEvtHead);
[21900]3120 }
3121
3122 return VINF_SUCCESS;
3123}
3124
3125
3126/**
3127 * Starts the I/O thread for the specified stream.
3128 *
3129 * @param pStrm The stream handle.
3130 */
3131static void ssmR3StrmStartIoThread(PSSMSTRM pStrm)
3132{
3133 Assert(pStrm->hIoThread == NIL_RTTHREAD);
3134
3135 RTTHREAD hThread;
3136 int rc = RTThreadCreate(&hThread, ssmR3StrmIoThread, pStrm, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SSM-IO");
3137 AssertRCReturnVoid(rc);
3138 ASMAtomicWriteHandle(&pStrm->hIoThread, hThread); /* paranoia */
3139}
3140
[56965]3141
3142/**
3143 * Stops the I/O thread.
3144 *
3145 * @param pStrm The stream handle.
3146 */
3147static void ssmR3StrmStopIoThread(PSSMSTRM pStrm)
3148{
3149 LogFlow(("ssmR3StrmStopIoThread: %p\n", pStrm->hIoThread));
3150 if (pStrm->hIoThread != NIL_RTTHREAD)
3151 {
3152 /*
3153 * Signal the I/O thread and wait for it to complete.
3154 */
3155 ASMAtomicWriteBool(&pStrm->fTerminating, true);
3156 if (pStrm->fWrite)
3157 {
3158 int rc1 = RTSemEventSignal(pStrm->hEvtHead);
3159 AssertLogRelRC(rc1);
3160 }
3161 else
3162 {
3163 int rc2 = RTSemEventSignal(pStrm->hEvtFree);
3164 AssertLogRelRC(rc2);
3165 }
3166 int rc3 = RTThreadWait(pStrm->hIoThread, RT_INDEFINITE_WAIT, NULL);
3167 AssertLogRelRC(rc3);
3168 pStrm->hIoThread = NIL_RTTHREAD;
3169 pStrm->fTerminating = false; /* Can't read stuff otherwise. */
3170 }
3171}
3172
[39078]3173#endif /* !SSM_STANDALONE */
[21900]3174
3175/**
[30396]3176 * Works the progress calculation for non-live saves and restores.
[1]3177 *
3178 * @param pSSM The SSM handle.
[30396]3179 * @param cbAdvance Number of bytes to advance (with in the current unit).
[1]3180 */
[30396]3181static void ssmR3ProgressByByte(PSSMHANDLE pSSM, uint64_t cbAdvance)
[1]3182{
[30396]3183 if (!pSSM->fLiveSave)
3184 {
3185 /* Can't advance it beyond the estimated end of the unit. */
3186 uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
3187 if (cbAdvance > cbLeft)
3188 cbAdvance = cbLeft;
3189 pSSM->offEst += cbAdvance;
[1]3190
[30396]3191 /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc. This is not
3192 quite right for live save, but the non-live stage there is very short. */
3193 while ( pSSM->offEst >= pSSM->offEstProgress
3194 && pSSM->uPercent <= 100 - pSSM->uPercentDone)
3195 {
3196 if (pSSM->pfnProgress)
[44393]3197 pSSM->pfnProgress(pSSM->pVM->pUVM, pSSM->uPercent, pSSM->pvUser);
[30396]3198 pSSM->uPercent++;
3199 pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare - pSSM->uPercentLive) * pSSM->cbEstTotal
3200 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare - pSSM->uPercentLive);
3201 }
[1]3202 }
3203}
3204
3205
[39078]3206#ifndef SSM_STANDALONE
[1]3207/**
[22884]3208 * Makes the SSM operation cancellable or not (via SSMR3Cancel).
3209 *
[58122]3210 * @param pVM The cross context VM structure.
[22884]3211 * @param pSSM The saved state handle. (SSMHANDLE::rc may be set.)
3212 * @param fCancellable The new state.
3213 */
3214static void ssmR3SetCancellable(PVM pVM, PSSMHANDLE pSSM, bool fCancellable)
3215{
3216 RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
3217 if (fCancellable)
3218 {
3219 Assert(!pVM->ssm.s.pSSM);
3220 pVM->ssm.s.pSSM = pSSM;
3221 }
3222 else
3223 {
3224 if (pVM->ssm.s.pSSM == pSSM)
3225 pVM->ssm.s.pSSM = NULL;
3226
3227 uint32_t fCancelled = ASMAtomicUoReadU32(&pSSM->fCancelled);
3228 if ( fCancelled == SSMHANDLE_CANCELLED
3229 && RT_SUCCESS(pSSM->rc))
3230 pSSM->rc = VERR_SSM_CANCELLED;
3231 }
3232
3233 RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
3234}
[39078]3235#endif /* !SSM_STANDALONE */
[22884]3236
3237
3238/**
[23771]3239 * Gets the host bit count of the saved state.
[23764]3240 *
3241 * Works for on both save and load handles.
3242 *
3243 * @returns 32 or 64.
3244 * @param pSSM The saved state handle.
3245 */
3246DECLINLINE(uint32_t) ssmR3GetHostBits(PSSMHANDLE pSSM)
3247{
3248 if (pSSM->enmOp >= SSMSTATE_LOAD_PREP)
3249 {
3250 uint32_t cBits = pSSM->u.Read.cHostBits;
3251 if (cBits)
3252 return cBits;
3253 }
3254 return HC_ARCH_BITS;
3255}
3256
3257
3258/**
[23771]3259 * Saved state origins on a host using 32-bit MSC?
3260 *
3261 * Works for on both save and load handles.
3262 *
3263 * @returns true/false.
3264 * @param pSSM The saved state handle.
3265 */
3266DECLINLINE(bool) ssmR3IsHostMsc32(PSSMHANDLE pSSM)
3267{
3268 if (pSSM->enmOp >= SSMSTATE_LOAD_PREP)
[23773]3269 return pSSM->u.Read.fIsHostMsc32;
[23771]3270 return SSM_HOST_IS_MSC_32;
3271}
3272
[24574]3273#ifndef SSM_STANDALONE
[23771]3274
3275/**
[1]3276 * Finishes a data unit.
3277 * All buffers and compressor instances are flushed and destroyed.
3278 *
[58170]3279 * @returns VBox status code.
[23764]3280 * @param pSSM The saved state handle.
[1]3281 */
[21797]3282static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
[1]3283{
[21894]3284 //Log2(("ssmR3DataWriteFinish: %#010llx start\n", ssmR3StrmTell(&pSSM->Strm)));
[21797]3285 int rc = ssmR3DataFlushBuffer(pSSM);
[13816]3286 if (RT_SUCCESS(rc))
[22792]3287 {
[42335]3288 pSSM->offUnit = UINT64_MAX;
3289 pSSM->offUnitUser = UINT64_MAX;
[21856]3290 return VINF_SUCCESS;
[22792]3291 }
[21797]3292
[13816]3293 if (RT_SUCCESS(pSSM->rc))
[1]3294 pSSM->rc = rc;
[21797]3295 Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
[1]3296 return rc;
3297}
3298
[13594]3299
[1]3300/**
[21797]3301 * Begins writing the data of a data unit.
3302 *
3303 * Errors are signalled via pSSM->rc.
3304 *
3305 * @param pSSM The saved state handle.
3306 */
3307static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
3308{
[42335]3309 pSSM->offUnit = 0;
3310 pSSM->offUnitUser = 0;
[21797]3311}
3312
3313
3314/**
3315 * Writes a record to the current data item in the saved state file.
3316 *
3317 * @returns VBox status code. Sets pSSM->rc on failure.
3318 * @param pSSM The saved state handle.
[1]3319 * @param pvBuf The bits to write.
3320 * @param cbBuf The number of bytes to write.
3321 */
[21797]3322static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
[1]3323{
[21856]3324 Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
[21866]3325 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
[1]3326
3327 /*
3328 * Check that everything is fine.
3329 */
[21797]3330 if (RT_FAILURE(pSSM->rc))
3331 return pSSM->rc;
3332
3333 /*
3334 * Write the data item in 1MB chunks for progress indicator reasons.
3335 */
3336 while (cbBuf > 0)
[1]3337 {
[21797]3338 size_t cbChunk = RT_MIN(cbBuf, _1M);
[21866]3339 int rc = ssmR3StrmWrite(&pSSM->Strm, pvBuf, cbChunk);
[21797]3340 if (RT_FAILURE(rc))
3341 return rc;
3342 pSSM->offUnit += cbChunk;
3343 cbBuf -= cbChunk;
3344 pvBuf = (char *)pvBuf + cbChunk;
3345 }
[1]3346
[21797]3347 return VINF_SUCCESS;
3348}
3349
[21856]3350
[21797]3351/**
3352 * Writes a record header for the specified amount of data.
3353 *
3354 * @returns VBox status code. Sets pSSM->rc on failure.
3355 * @param pSSM The saved state handle
3356 * @param cb The amount of data.
3357 * @param u8TypeAndFlags The record type and flags.
3358 */
3359static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
3360{
3361 size_t cbHdr;
3362 uint8_t abHdr[8];
3363 abHdr[0] = u8TypeAndFlags;
3364 if (cb < 0x80)
3365 {
3366 cbHdr = 2;
[21871]3367 abHdr[1] = (uint8_t)cb;
[1]3368 }
[21797]3369 else if (cb < 0x00000800)
3370 {
3371 cbHdr = 3;
[21871]3372 abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
3373 abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
[21797]3374 }
3375 else if (cb < 0x00010000)
3376 {
3377 cbHdr = 4;
[21871]3378 abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
3379 abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
3380 abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
[21797]3381 }
3382 else if (cb < 0x00200000)
3383 {
3384 cbHdr = 5;
[21871]3385 abHdr[1] = (uint8_t)(0xf0 | (cb >> 18));
3386 abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
3387 abHdr[3] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
3388 abHdr[4] = (uint8_t)(0x80 | (cb & 0x3f));
[21797]3389 }
3390 else if (cb < 0x04000000)
3391 {
3392 cbHdr = 6;
[21871]3393 abHdr[1] = (uint8_t)(0xf8 | (cb >> 24));
3394 abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
3395 abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
3396 abHdr[4] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
3397 abHdr[5] = (uint8_t)(0x80 | (cb & 0x3f));
[21797]3398 }
3399 else if (cb <= 0x7fffffff)
3400 {
3401 cbHdr = 7;
[21871]3402 abHdr[1] = (uint8_t)(0xfc | (cb >> 30));
3403 abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
3404 abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
3405 abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
3406 abHdr[5] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
3407 abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
[21797]3408 }
3409 else
[39402]3410 AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_SSM_MEM_TOO_BIG);
[1]3411
[21856]3412 Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
[21866]3413 ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
[21797]3414
3415 return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
[1]3416}
3417
3418
3419/**
[21797]3420 * Worker that flushes the buffered data.
[1]3421 *
[21797]3422 * @returns VBox status code. Will set pSSM->rc on error.
3423 * @param pSSM The saved state handle.
[1]3424 */
[21797]3425static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
[1]3426{
[21897]3427 /*
3428 * Check how much there current is in the buffer.
3429 */
[21797]3430 uint32_t cb = pSSM->u.Write.offDataBuffer;
3431 if (!cb)
3432 return pSSM->rc;
[21897]3433 pSSM->u.Write.offDataBuffer = 0;
[21797]3434
3435 /*
[21897]3436 * Write a record header and then the data.
3437 * (No need for fancy optimizations here any longer since the stream is
3438 * fully buffered.)
[21797]3439 */
[21897]3440 int rc = ssmR3DataWriteRecHdr(pSSM, cb, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
3441 if (RT_SUCCESS(rc))
3442 rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
[30396]3443 ssmR3ProgressByByte(pSSM, cb);
[21797]3444 return rc;
3445}
3446
3447
3448/**
3449 * ssmR3DataWrite worker that writes big stuff.
3450 *
3451 * @returns VBox status code
3452 * @param pSSM The saved state handle.
3453 * @param pvBuf The bits to write.
3454 * @param cbBuf The number of bytes to write.
3455 */
3456static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3457{
3458 int rc = ssmR3DataFlushBuffer(pSSM);
[13816]3459 if (RT_SUCCESS(rc))
[21797]3460 {
[42335]3461 pSSM->offUnitUser += cbBuf;
3462
[21856]3463 /*
[22025]3464 * Split it up into compression blocks.
[21856]3465 */
3466 for (;;)
3467 {
[22025]3468 AssertCompile(SSM_ZIP_BLOCK_SIZE == PAGE_SIZE);
3469 if ( cbBuf >= SSM_ZIP_BLOCK_SIZE
3470 && ( ((uintptr_t)pvBuf & 0xf)
3471 || !ASMMemIsZeroPage(pvBuf))
3472 )
[21856]3473 {
[22025]3474 /*
3475 * Compress it.
3476 */
[21897]3477 AssertCompile(1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE < 0x00010000);
3478 uint8_t *pb;
3479 rc = ssmR3StrmReserveWriteBufferSpace(&pSSM->Strm, 1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE, &pb);
3480 if (RT_FAILURE(rc))
3481 break;
3482 size_t cbRec = SSM_ZIP_BLOCK_SIZE - (SSM_ZIP_BLOCK_SIZE / 16);
[21856]3483 rc = RTZipBlockCompress(RTZIPTYPE_LZF, RTZIPLEVEL_FAST, 0 /*fFlags*/,
[21862]3484 pvBuf, SSM_ZIP_BLOCK_SIZE,
[21897]3485 pb + 1 + 3 + 1, cbRec, &cbRec);
[21856]3486 if (RT_SUCCESS(rc))
3487 {
[21897]3488 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF;
3489 pb[4] = SSM_ZIP_BLOCK_SIZE / _1K;
3490 cbRec += 1;
[21856]3491 }
3492 else
3493 {
[21897]3494 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
3495 memcpy(&pb[4], pvBuf, SSM_ZIP_BLOCK_SIZE);
3496 cbRec = SSM_ZIP_BLOCK_SIZE;
[21856]3497 }
[21897]3498 pb[1] = (uint8_t)(0xe0 | ( cbRec >> 12));
3499 pb[2] = (uint8_t)(0x80 | ((cbRec >> 6) & 0x3f));
3500 pb[3] = (uint8_t)(0x80 | ( cbRec & 0x3f));
3501 cbRec += 1 + 3;
3502 rc = ssmR3StrmCommitWriteBufferSpace(&pSSM->Strm, cbRec);
3503 if (RT_FAILURE(rc))
3504 break;
3505
3506 pSSM->offUnit += cbRec;
[30396]3507 ssmR3ProgressByByte(pSSM, SSM_ZIP_BLOCK_SIZE);
[21897]3508
3509 /* advance */
[21862]3510 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
[21856]3511 return VINF_SUCCESS;
[21862]3512 cbBuf -= SSM_ZIP_BLOCK_SIZE;
3513 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
[21856]3514 }
[22025]3515 else if (cbBuf >= SSM_ZIP_BLOCK_SIZE)
3516 {
3517 /*
3518 * Zero block.
3519 */
3520 uint8_t abRec[3];
3521 abRec[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_ZERO;
3522 abRec[1] = 1;
3523 abRec[2] = SSM_ZIP_BLOCK_SIZE / _1K;
3524 Log3(("ssmR3DataWriteBig: %08llx|%08llx/%08x: ZERO\n", ssmR3StrmTell(&pSSM->Strm) + 2, pSSM->offUnit + 2, 1));
3525 rc = ssmR3DataWriteRaw(pSSM, &abRec[0], sizeof(abRec));
3526 if (RT_FAILURE(rc))
3527 break;
3528
3529 /* advance */
[30396]3530 ssmR3ProgressByByte(pSSM, SSM_ZIP_BLOCK_SIZE);
[22025]3531 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
3532 return VINF_SUCCESS;
3533 cbBuf -= SSM_ZIP_BLOCK_SIZE;
3534 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
3535 }
[21856]3536 else
3537 {
[21897]3538 /*
3539 * Less than one block left, store it the simple way.
3540 */
[21856]3541 rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
3542 if (RT_SUCCESS(rc))
3543 rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
[30396]3544 ssmR3ProgressByByte(pSSM, cbBuf);
[21897]3545 break;
[21856]3546 }
3547 }
[21797]3548 }
[1]3549 return rc;
3550}
3551
[21856]3552
[21797]3553/**
3554 * ssmR3DataWrite worker that is called when there isn't enough room in the
3555 * buffer for the current chunk of data.
3556 *
3557 * This will first flush the buffer and then add the new bits to it.
3558 *
3559 * @returns VBox status code
3560 * @param pSSM The saved state handle.
3561 * @param pvBuf The bits to write.
3562 * @param cbBuf The number of bytes to write.
3563 */
3564static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3565{
3566 int rc = ssmR3DataFlushBuffer(pSSM);
3567 if (RT_SUCCESS(rc))
3568 {
3569 memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
[21871]3570 pSSM->u.Write.offDataBuffer = (uint32_t)cbBuf;
[42335]3571 pSSM->offUnitUser += cbBuf;
[21797]3572 }
3573 return rc;
3574}
[1]3575
[21797]3576
[1]3577/**
[21797]3578 * Writes data to the current data unit.
3579 *
3580 * This is an inlined wrapper that optimizes the small writes that so many of
3581 * the APIs make.
3582 *
3583 * @returns VBox status code
3584 * @param pSSM The saved state handle.
3585 * @param pvBuf The bits to write.
3586 * @param cbBuf The number of bytes to write.
3587 */
3588DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3589{
3590 if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
3591 return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
3592 if (!cbBuf)
3593 return VINF_SUCCESS;
3594
3595 uint32_t off = pSSM->u.Write.offDataBuffer;
3596 if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
3597 return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
3598
3599 memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
[21871]3600 pSSM->u.Write.offDataBuffer = off + (uint32_t)cbBuf;
[42335]3601 pSSM->offUnitUser += cbBuf;
[21797]3602 return VINF_SUCCESS;
3603}
3604
3605
3606/**
[1]3607 * Puts a structure.
3608 *
3609 * @returns VBox status code.
3610 * @param pSSM The saved state handle.
3611 * @param pvStruct The structure address.
3612 * @param paFields The array of structure fields descriptions.
3613 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
3614 */
[12989]3615VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
[1]3616{
[23753]3617 SSM_ASSERT_WRITEABLE_RET(pSSM);
3618 SSM_CHECK_CANCELLED_RET(pSSM);
3619 AssertPtr(pvStruct);
3620 AssertPtr(paFields);
3621
[1]3622 /* begin marker. */
3623 int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
[13816]3624 if (RT_FAILURE(rc))
[1]3625 return rc;
3626
3627 /* put the fields */
3628 for (PCSSMFIELD pCur = paFields;
3629 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
3630 pCur++)
3631 {
[23749]3632 uint8_t const *pbField = (uint8_t const *)pvStruct + pCur->off;
3633 switch ((uintptr_t)pCur->pfnGetPutOrTransformer)
3634 {
3635 case SSMFIELDTRANS_NO_TRANSFORMATION:
3636 rc = ssmR3DataWrite(pSSM, pbField, pCur->cb);
3637 break;
3638
3639 case SSMFIELDTRANS_GCPTR:
[49800]3640 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPTR), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23749]3641 rc = SSMR3PutGCPtr(pSSM, *(PRTGCPTR)pbField);
3642 break;
3643
3644 case SSMFIELDTRANS_GCPHYS:
[49800]3645 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPHYS), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23749]3646 rc = SSMR3PutGCPhys(pSSM, *(PRTGCPHYS)pbField);
3647 break;
3648
[23764]3649 case SSMFIELDTRANS_RCPTR:
[49800]3650 AssertMsgBreakStmt(pCur->cb == sizeof(RTRCPTR), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23764]3651 rc = SSMR3PutRCPtr(pSSM, *(PRTRCPTR)pbField);
3652 break;
3653
3654 case SSMFIELDTRANS_RCPTR_ARRAY:
3655 {
3656 uint32_t const cEntries = pCur->cb / sizeof(RTRCPTR);
[49800]3657 AssertMsgBreakStmt(pCur->cb == cEntries * sizeof(RTRCPTR) && cEntries, ("%#x (%s)\n", pCur->cb, pCur->pszName),
3658 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23775]3659 rc = VINF_SUCCESS;
[23764]3660 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
3661 rc = SSMR3PutRCPtr(pSSM, ((PRTRCPTR)pbField)[i]);
3662 break;
3663 }
3664
[23749]3665 default:
[49800]3666 AssertMsgFailedBreakStmt(("%#x\n", pCur->pfnGetPutOrTransformer), rc = VERR_SSM_FIELD_COMPLEX);
[23749]3667 }
[23752]3668 if (RT_FAILURE(rc))
[49800]3669 {
3670 if (RT_SUCCESS(pSSM->rc))
3671 pSSM->rc = rc;
[23752]3672 return rc;
[49800]3673 }
[1]3674 }
3675
3676 /* end marker */
3677 return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
3678}
3679
3680
3681/**
[23764]3682 * SSMR3PutStructEx helper that puts a HCPTR that is used as a NULL indicator.
3683 *
3684 * @returns VBox status code.
3685 *
3686 * @param pSSM The saved state handle.
3687 * @param pv The value to put.
3688 * @param fFlags SSMSTRUCT_FLAGS_XXX.
3689 */
3690DECLINLINE(int) ssmR3PutHCPtrNI(PSSMHANDLE pSSM, void *pv, uint32_t fFlags)
3691{
3692 int rc;
3693 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
3694 rc = ssmR3DataWrite(pSSM, &pv, sizeof(void *));
3695 else
3696 rc = SSMR3PutBool(pSSM, pv != NULL);
3697 return rc;
3698}
3699
3700
3701/**
[23872]3702 * SSMR3PutStructEx helper that puts an arbitrary number of zeros.
3703 *
3704 * @returns VBox status code.
3705 * @param pSSM The saved state handle.
3706 * @param cbToFill The number of zeros to stuff into the state.
3707 */
3708static int ssmR3PutZeros(PSSMHANDLE pSSM, uint32_t cbToFill)
3709{
3710 while (cbToFill > 0)
3711 {
[26526]3712 uint32_t cb = RT_MIN(sizeof(g_abZero), cbToFill);
[23872]3713 int rc = ssmR3DataWrite(pSSM, g_abZero, cb);
3714 if (RT_FAILURE(rc))
3715 return rc;
3716 cbToFill -= cb;
3717 }
3718 return VINF_SUCCESS;
3719}
3720
3721
3722/**
[23752]3723 * Puts a structure, extended API.
3724 *
3725 * @returns VBox status code.
3726 * @param pSSM The saved state handle.
3727 * @param pvStruct The structure address.
3728 * @param cbStruct The size of the struct (use for validation only).
3729 * @param fFlags Combination of SSMSTRUCT_FLAGS_XXX defines.
3730 * @param paFields The array of structure fields descriptions. The
3731 * array must be terminated by a SSMFIELD_ENTRY_TERM().
3732 * @param pvUser User argument for any callbacks that paFields might
3733 * contain.
3734 */
3735VMMR3DECL(int) SSMR3PutStructEx(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct,
3736 uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)
3737{
3738 int rc;
3739
3740 /*
3741 * Validation.
3742 */
[23753]3743 SSM_ASSERT_WRITEABLE_RET(pSSM);
3744 SSM_CHECK_CANCELLED_RET(pSSM);
[49800]3745 AssertMsgReturn(!(fFlags & ~SSMSTRUCT_FLAGS_VALID_MASK), ("%#x\n", fFlags), pSSM->rc = VERR_INVALID_PARAMETER);
[23752]3746 AssertPtr(pvStruct);
3747 AssertPtr(paFields);
3748
3749
3750 /*
3751 * Begin marker.
3752 */
[55063]3753 if (!(fFlags & (SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_NO_LEAD_MARKER)))
[23752]3754 {
3755 rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
3756 if (RT_FAILURE(rc))
3757 return rc;
3758 }
3759
3760 /*
3761 * Put the fields
3762 */
[49800]3763 rc = VINF_SUCCESS;
[55465]3764 uint32_t off = 0;
[23752]3765 for (PCSSMFIELD pCur = paFields;
3766 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
3767 pCur++)
3768 {
[23785]3769 uint32_t const offField = (!SSMFIELDTRANS_IS_PADDING(pCur->pfnGetPutOrTransformer) || pCur->off != UINT32_MAX / 2)
3770 && !SSMFIELDTRANS_IS_OLD(pCur->pfnGetPutOrTransformer)
[23764]3771 ? pCur->off
3772 : off;
[23785]3773 uint32_t const cbField = SSMFIELDTRANS_IS_OLD(pCur->pfnGetPutOrTransformer)
3774 ? 0
3775 : SSMFIELDTRANS_IS_PADDING(pCur->pfnGetPutOrTransformer)
3776 ? RT_HIWORD(pCur->cb)
3777 : pCur->cb;
[49800]3778 AssertMsgBreakStmt( cbField <= cbStruct
3779 && offField + cbField <= cbStruct
3780 && offField + cbField >= offField,
[72159]3781 ("offField=%#x cbField=%#x cbStruct=%#x (%s)\n", offField, cbField, cbStruct, pCur->pszName),
[49800]3782 rc = VERR_SSM_FIELD_OUT_OF_BOUNDS);
3783 AssertMsgBreakStmt( !(fFlags & SSMSTRUCT_FLAGS_FULL_STRUCT)
3784 || off == offField,
3785 ("off=%#x offField=%#x (%s)\n", off, offField, pCur->pszName),
3786 rc = VERR_SSM_FIELD_NOT_CONSECUTIVE);
[23752]3787
[23872]3788 rc = VINF_SUCCESS;
[23764]3789 uint8_t const *pbField = (uint8_t const *)pvStruct + offField;
[23752]3790 switch ((uintptr_t)pCur->pfnGetPutOrTransformer)
3791 {
3792 case SSMFIELDTRANS_NO_TRANSFORMATION:
[23764]3793 rc = ssmR3DataWrite(pSSM, pbField, cbField);
[23752]3794 break;
3795
[23785]3796 case SSMFIELDTRANS_GCPHYS:
[49800]3797 AssertMsgBreakStmt(cbField == sizeof(RTGCPHYS), ("%#x (%s)\n", cbField, pCur->pszName),
3798 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23785]3799 rc = SSMR3PutGCPhys(pSSM, *(PRTGCPHYS)pbField);
3800 break;
3801
[23752]3802 case SSMFIELDTRANS_GCPTR:
[49800]3803 AssertMsgBreakStmt(cbField == sizeof(RTGCPTR), ("%#x (%s)\n", cbField, pCur->pszName),
3804 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23752]3805 rc = SSMR3PutGCPtr(pSSM, *(PRTGCPTR)pbField);
3806 break;
3807
[23764]3808 case SSMFIELDTRANS_RCPTR:
[49800]3809 AssertMsgBreakStmt(cbField == sizeof(RTRCPTR), ("%#x (%s)\n", cbField, pCur->pszName),
3810 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23764]3811 rc = SSMR3PutRCPtr(pSSM, *(PRTRCPTR)pbField);
3812 break;
3813
3814 case SSMFIELDTRANS_RCPTR_ARRAY:
3815 {
3816 uint32_t const cEntries = cbField / sizeof(RTRCPTR);
[49800]3817 AssertMsgBreakStmt(cbField == cEntries * sizeof(RTRCPTR) && cEntries, ("%#x (%s)\n", cbField, pCur->pszName),
3818 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23764]3819 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
3820 rc = SSMR3PutRCPtr(pSSM, ((PRTRCPTR)pbField)[i]);
3821 break;
3822 }
3823
3824 case SSMFIELDTRANS_HCPTR_NI:
[49800]3825 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName),
3826 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23764]3827 rc = ssmR3PutHCPtrNI(pSSM, *(void * const *)pbField, fFlags);
3828 break;
3829
3830 case SSMFIELDTRANS_HCPTR_NI_ARRAY:
3831 {
3832 uint32_t const cEntries = cbField / sizeof(void *);
[49800]3833 AssertMsgBreakStmt(cbField == cEntries * sizeof(void *) && cEntries, ("%#x (%s)\n", cbField, pCur->pszName),
3834 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23764]3835 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
3836 rc = ssmR3PutHCPtrNI(pSSM, ((void * const *)pbField)[i], fFlags);
3837 break;
3838 }
3839
[23783]3840 case SSMFIELDTRANS_HCPTR_HACK_U32:
[49800]3841 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
3842 AssertMsgBreakStmt(*(uintptr_t *)pbField <= UINT32_MAX, ("%p (%s)\n", *(uintptr_t *)pbField, pCur->pszName),
3843 rc = VERR_SSM_FIELD_INVALID_VALUE);
[23783]3844 rc = ssmR3DataWrite(pSSM, pbField, sizeof(uint32_t));
[49800]3845 if ((fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE) && sizeof(void *) != sizeof(uint32_t) && RT_SUCCESS(rc))
[23872]3846 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(uint32_t));
[23783]3847 break;
3848
[41900]3849 case SSMFIELDTRANS_U32_ZX_U64:
[49800]3850 AssertFailedBreakStmt(rc = VERR_SSM_FIELD_LOAD_ONLY_TRANSFORMATION);
[41900]3851 break;
[23783]3852
[23752]3853 case SSMFIELDTRANS_IGNORE:
3854 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3855 rc = ssmR3PutZeros(pSSM, cbField);
[23752]3856 break;
3857
[23785]3858 case SSMFIELDTRANS_IGN_GCPHYS:
[49800]3859 AssertMsgBreakStmt(cbField == sizeof(RTGCPHYS), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23785]3860 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3861 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTGCPHYS));
[23785]3862 break;
3863
[23780]3864 case SSMFIELDTRANS_IGN_GCPTR:
[49800]3865 AssertMsgBreakStmt(cbField == sizeof(RTGCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23780]3866 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3867 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTGCPTR));
[23780]3868 break;
3869
[23779]3870 case SSMFIELDTRANS_IGN_RCPTR:
[49800]3871 AssertMsgBreakStmt(cbField == sizeof(RTRCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23779]3872 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3873 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTRCPTR));
[23779]3874 break;
3875
[23777]3876 case SSMFIELDTRANS_IGN_HCPTR:
[49800]3877 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23777]3878 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3879 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(void *));
[23777]3880 break;
3881
[23783]3882
[23785]3883 case SSMFIELDTRANS_OLD:
[49800]3884 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3885 rc = ssmR3PutZeros(pSSM, pCur->cb);
[23785]3886 break;
3887
3888 case SSMFIELDTRANS_OLD_GCPHYS:
[49800]3889 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPHYS) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3890 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3891 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTGCPHYS));
[23785]3892 break;
3893
3894 case SSMFIELDTRANS_OLD_GCPTR:
[49800]3895 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPTR) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3896 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3897 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTGCPTR));
[23785]3898 break;
3899
3900 case SSMFIELDTRANS_OLD_RCPTR:
[49800]3901 AssertMsgBreakStmt(pCur->cb == sizeof(RTRCPTR) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3902 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3903 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(RTRCPTR));
[23785]3904 break;
3905
3906 case SSMFIELDTRANS_OLD_HCPTR:
[49800]3907 AssertMsgBreakStmt(pCur->cb == sizeof(void *) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3908 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3909 rc = ssmR3DataWrite(pSSM, g_abZero, sizeof(void *));
[23785]3910 break;
3911
[23872]3912 case SSMFIELDTRANS_OLD_PAD_HC:
[49800]3913 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3914 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3915 rc = ssmR3PutZeros(pSSM, HC_ARCH_BITS == 64 ? RT_HIWORD(pCur->cb) : RT_LOWORD(pCur->cb));
3916 break;
[23785]3917
[23872]3918 case SSMFIELDTRANS_OLD_PAD_MSC32:
[49800]3919 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName),
3920 rc = VERR_SSM_FIELD_INVALID_SIZE);
[23872]3921 if (SSM_HOST_IS_MSC_32)
3922 rc = ssmR3PutZeros(pSSM, pCur->cb);
3923 break;
3924
3925
[23764]3926 case SSMFIELDTRANS_PAD_HC:
3927 case SSMFIELDTRANS_PAD_HC32:
3928 case SSMFIELDTRANS_PAD_HC64:
3929 case SSMFIELDTRANS_PAD_HC_AUTO:
[23771]3930 case SSMFIELDTRANS_PAD_MSC32_AUTO:
[23764]3931 {
3932 uint32_t cb32 = RT_BYTE1(pCur->cb);
3933 uint32_t cb64 = RT_BYTE2(pCur->cb);
[23771]3934 uint32_t cbCtx = HC_ARCH_BITS == 64
3935 || ( (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
[23776]3936 && !SSM_HOST_IS_MSC_32)
[23771]3937 ? cb64 : cb32;
3938 uint32_t cbSaved = ssmR3GetHostBits(pSSM) == 64
3939 || ( (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
[23776]3940 && !ssmR3IsHostMsc32(pSSM))
[23771]3941 ? cb64 : cb32;
[49800]3942 AssertMsgBreakStmt( cbField == cbCtx
3943 && ( ( pCur->off == UINT32_MAX / 2
3944 && ( cbField == 0
3945 || (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_HC_AUTO
3946 || (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
3947 )
3948 )
3949 || (pCur->off != UINT32_MAX / 2 && cbField != 0)
[23771]3950 )
[49800]3951 , ("cbField=%#x cb32=%#x cb64=%#x HC_ARCH_BITS=%u cbCtx=%#x cbSaved=%#x off=%#x\n",
3952 cbField, cb32, cb64, HC_ARCH_BITS, cbCtx, cbSaved, pCur->off),
3953 rc = VERR_SSM_FIELD_INVALID_PADDING_SIZE);
[23764]3954 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
[23872]3955 rc = ssmR3PutZeros(pSSM, cbSaved);
[23764]3956 break;
3957 }
3958
[23752]3959 default:
[49800]3960 AssertPtrBreakStmt(pCur->pfnGetPutOrTransformer, rc = VERR_SSM_FIELD_INVALID_CALLBACK);
[23752]3961 rc = pCur->pfnGetPutOrTransformer(pSSM, pCur, (void *)pvStruct, fFlags, false /*fGetOrPut*/, pvUser);
3962 break;
3963 }
3964 if (RT_FAILURE(rc))
[49800]3965 break; /* Deal with failures in one place (see below). */
[23752]3966
[23764]3967 off = offField + cbField;
[23752]3968 }
3969
[49800]3970 if (RT_SUCCESS(rc))
3971 AssertMsgStmt( !(fFlags & SSMSTRUCT_FLAGS_FULL_STRUCT)
3972 || off == cbStruct,
3973 ("off=%#x cbStruct=%#x\n", off, cbStruct),
3974 rc = VERR_SSM_FIELD_NOT_CONSECUTIVE);
3975
3976 if (RT_FAILURE(rc))
3977 {
3978 if (RT_SUCCESS(pSSM->rc))
3979 pSSM->rc = rc;
3980 return rc;
3981 }
3982
[23752]3983 /*
3984 * End marker
3985 */
[55063]3986 if (!(fFlags & (SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_NO_TAIL_MARKER)))
[23752]3987 {
3988 rc = SSMR3PutU32(pSSM, SSMR3STRUCT_END);
3989 if (RT_FAILURE(rc))
3990 return rc;
3991 }
3992
3993 return VINF_SUCCESS;
3994}
3995
3996
3997/**
[1]3998 * Saves a boolean item to the current data unit.
3999 *
[58170]4000 * @returns VBox status code.
[23764]4001 * @param pSSM The saved state handle.
[1]4002 * @param fBool Item to save.
4003 */
[12989]4004VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
[1]4005{
[22554]4006 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4007 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4008 uint8_t u8 = fBool; /* enforce 1 byte size */
4009 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
[1]4010}
4011
[13594]4012
[1]4013/**
4014 * Saves a 8-bit unsigned integer item to the current data unit.
4015 *
[58170]4016 * @returns VBox status code.
[23764]4017 * @param pSSM The saved state handle.
[1]4018 * @param u8 Item to save.
4019 */
[12989]4020VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
[1]4021{
[22554]4022 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4023 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4024 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
[1]4025}
4026
[13594]4027
[1]4028/**
4029 * Saves a 8-bit signed integer item to the current data unit.
4030 *
[58170]4031 * @returns VBox status code.
[23764]4032 * @param pSSM The saved state handle.
[1]4033 * @param i8 Item to save.
4034 */
[12989]4035VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
[1]4036{
[22554]4037 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4038 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4039 return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
[1]4040}
4041
[13594]4042
[1]4043/**
4044 * Saves a 16-bit unsigned integer item to the current data unit.
4045 *
[58170]4046 * @returns VBox status code.
[23764]4047 * @param pSSM The saved state handle.
[1]4048 * @param u16 Item to save.
4049 */
[12989]4050VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
[1]4051{
[22554]4052 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4053 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4054 return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
[1]4055}
4056
[13594]4057
[1]4058/**
4059 * Saves a 16-bit signed integer item to the current data unit.
4060 *
[58170]4061 * @returns VBox status code.
[23764]4062 * @param pSSM The saved state handle.
[1]4063 * @param i16 Item to save.
4064 */
[12989]4065VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
[1]4066{
[22554]4067 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4068 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4069 return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
[1]4070}
4071
[13594]4072
[1]4073/**
4074 * Saves a 32-bit unsigned integer item to the current data unit.
4075 *
[58170]4076 * @returns VBox status code.
[23764]4077 * @param pSSM The saved state handle.
[1]4078 * @param u32 Item to save.
4079 */
[12989]4080VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
[1]4081{
[22554]4082 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4083 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4084 return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
[1]4085}
4086
[13594]4087
[1]4088/**
4089 * Saves a 32-bit signed integer item to the current data unit.
4090 *
[58170]4091 * @returns VBox status code.
[23764]4092 * @param pSSM The saved state handle.
[1]4093 * @param i32 Item to save.
4094 */
[12989]4095VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
[1]4096{
[22554]4097 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4098 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4099 return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
[1]4100}
4101
[13594]4102
[1]4103/**
4104 * Saves a 64-bit unsigned integer item to the current data unit.
4105 *
[58170]4106 * @returns VBox status code.
[23764]4107 * @param pSSM The saved state handle.
[1]4108 * @param u64 Item to save.
4109 */
[12989]4110VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
[1]4111{
[22554]4112 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4113 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4114 return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
[1]4115}
4116
[13594]4117
[1]4118/**
4119 * Saves a 64-bit signed integer item to the current data unit.
4120 *
[58170]4121 * @returns VBox status code.
[23764]4122 * @param pSSM The saved state handle.
[1]4123 * @param i64 Item to save.
4124 */
[12989]4125VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
[1]4126{
[22554]4127 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4128 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4129 return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
[1]4130}
4131
[13594]4132
[1]4133/**
4134 * Saves a 128-bit unsigned integer item to the current data unit.
4135 *
[58170]4136 * @returns VBox status code.
[23764]4137 * @param pSSM The saved state handle.
[1]4138 * @param u128 Item to save.
4139 */
[12989]4140VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
[1]4141{
[22554]4142 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4143 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4144 return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
[1]4145}
4146
[13594]4147
[1]4148/**
4149 * Saves a 128-bit signed integer item to the current data unit.
4150 *
[58170]4151 * @returns VBox status code.
[23764]4152 * @param pSSM The saved state handle.
[1]4153 * @param i128 Item to save.
4154 */
[12989]4155VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
[1]4156{
[22554]4157 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4158 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4159 return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
[1]4160}
4161
[13594]4162
[1]4163/**
4164 * Saves a VBox unsigned integer item to the current data unit.
4165 *
[58170]4166 * @returns VBox status code.
[23764]4167 * @param pSSM The saved state handle.
[1]4168 * @param u Item to save.
4169 */
[12989]4170VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
[1]4171{
[22554]4172 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4173 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4174 return ssmR3DataWrite(pSSM, &u, sizeof(u));
[1]4175}
4176
4177
4178/**
4179 * Saves a VBox signed integer item to the current data unit.
4180 *
[58170]4181 * @returns VBox status code.
[23764]4182 * @param pSSM The saved state handle.
[1]4183 * @param i Item to save.
4184 */
[12989]4185VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
[1]4186{
[22554]4187 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4188 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4189 return ssmR3DataWrite(pSSM, &i, sizeof(i));
[1]4190}
4191
4192
4193/**
4194 * Saves a GC natural unsigned integer item to the current data unit.
4195 *
[58170]4196 * @returns VBox status code.
[23764]4197 * @param pSSM The saved state handle.
[1]4198 * @param u Item to save.
[13596]4199 *
4200 * @deprecated Silly type, don't use it.
[1]4201 */
[12989]4202VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
[1]4203{
[22554]4204 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4205 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4206 return ssmR3DataWrite(pSSM, &u, sizeof(u));
[1]4207}
4208
4209
4210/**
[13596]4211 * Saves a GC unsigned integer register item to the current data unit.
[1]4212 *
[58170]4213 * @returns VBox status code.
[23764]4214 * @param pSSM The saved state handle.
[13596]4215 * @param u Item to save.
[1]4216 */
[13596]4217VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
[1]4218{
[22554]4219 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4220 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4221 return ssmR3DataWrite(pSSM, &u, sizeof(u));
[1]4222}
4223
4224
4225/**
[7072]4226 * Saves a 32 bits GC physical address item to the current data unit.
4227 *
[58170]4228 * @returns VBox status code.
[23764]4229 * @param pSSM The saved state handle.
[7072]4230 * @param GCPhys The item to save
4231 */
[12989]4232VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
[7072]4233{
[22554]4234 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4235 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4236 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
[7072]4237}
4238
[7591]4239
[7581]4240/**
4241 * Saves a 64 bits GC physical address item to the current data unit.
4242 *
[58170]4243 * @returns VBox status code.
[23764]4244 * @param pSSM The saved state handle.
[7581]4245 * @param GCPhys The item to save
4246 */
[12989]4247VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
[7581]4248{
[22554]4249 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4250 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4251 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
[7581]4252}
[7111]4253
[7581]4254
[7072]4255/**
[1]4256 * Saves a GC physical address item to the current data unit.
4257 *
[58170]4258 * @returns VBox status code.
[23764]4259 * @param pSSM The saved state handle.
[1]4260 * @param GCPhys The item to save
4261 */
[12989]4262VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
[1]4263{
[22554]4264 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4265 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4266 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
[1]4267}
4268
4269
4270/**
4271 * Saves a GC virtual address item to the current data unit.
4272 *
[58170]4273 * @returns VBox status code.
[23764]4274 * @param pSSM The saved state handle.
[1]4275 * @param GCPtr The item to save.
4276 */
[12989]4277VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
[1]4278{
[22554]4279 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4280 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4281 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
[1]4282}
4283
4284
4285/**
[11944]4286 * Saves an RC virtual address item to the current data unit.
4287 *
[58170]4288 * @returns VBox status code.
[23764]4289 * @param pSSM The saved state handle.
[11944]4290 * @param RCPtr The item to save.
4291 */
[12989]4292VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
[11944]4293{
[22554]4294 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4295 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4296 return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
[11944]4297}
4298
4299
4300/**
[1]4301 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
4302 *
[58170]4303 * @returns VBox status code.
[23764]4304 * @param pSSM The saved state handle.
[1]4305 * @param GCPtr The item to save.
4306 */
[12989]4307VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
[1]4308{
[22554]4309 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4310 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4311 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
[1]4312}
4313
4314
4315/**
4316 * Saves a I/O port address item to the current data unit.
4317 *
[58170]4318 * @returns VBox status code.
[23764]4319 * @param pSSM The saved state handle.
[1]4320 * @param IOPort The item to save.
4321 */
[12989]4322VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
[1]4323{
[22554]4324 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4325 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4326 return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
[1]4327}
4328
4329
4330/**
4331 * Saves a selector item to the current data unit.
4332 *
[58170]4333 * @returns VBox status code.
[23764]4334 * @param pSSM The saved state handle.
[1]4335 * @param Sel The item to save.
4336 */
[12989]4337VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
[1]4338{
[22554]4339 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4340 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4341 return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
[1]4342}
4343
4344
4345/**
4346 * Saves a memory item to the current data unit.
4347 *
[58170]4348 * @returns VBox status code.
[23764]4349 * @param pSSM The saved state handle.
[1]4350 * @param pv Item to save.
4351 * @param cb Size of the item.
4352 */
[12989]4353VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
[1]4354{
[22554]4355 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4356 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4357 return ssmR3DataWrite(pSSM, pv, cb);
[1]4358}
4359
[13594]4360
[1]4361/**
4362 * Saves a zero terminated string item to the current data unit.
4363 *
[58170]4364 * @returns VBox status code.
[23764]4365 * @param pSSM The saved state handle.
[1]4366 * @param psz Item to save.
4367 */
[12989]4368VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
[1]4369{
[22554]4370 SSM_ASSERT_WRITEABLE_RET(pSSM);
[22884]4371 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]4372
4373 size_t cch = strlen(psz);
4374 if (cch > _1M)
[1]4375 {
[23895]4376 AssertMsgFailed(("a %zu byte long string, what's this!?!\n", cch));
[22034]4377 return VERR_TOO_MUCH_DATA;
[1]4378 }
[22034]4379 uint32_t u32 = (uint32_t)cch;
4380 int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
4381 if (rc)
4382 return rc;
4383 return ssmR3DataWrite(pSSM, psz, cch);
[1]4384}
4385
4386
[22554]4387/**
[30396]4388 * Emits a SSMLiveControl unit with a new progress report.
4389 *
4390 * @returns VBox status code.
4391 * @param pSSM The saved state handle.
[41783]4392 * @param lrdPct The progress of the live save.
[30396]4393 * @param uPass The current pass.
4394 */
4395static int ssmR3LiveControlEmit(PSSMHANDLE pSSM, long double lrdPct, uint32_t uPass)
4396{
4397 AssertMsg(lrdPct <= 100.0, ("%u\n", lrdPct * 100));
4398
4399 /*
4400 * Make sure we're in one of the two EXEC states or we may fail.
4401 */
4402 SSMSTATE enmSavedState = pSSM->enmOp;
4403 if (enmSavedState == SSMSTATE_LIVE_VOTE)
4404 pSSM->enmOp = SSMSTATE_LIVE_EXEC;
4405 else if (enmSavedState == SSMSTATE_SAVE_DONE)
4406 pSSM->enmOp = SSMSTATE_SAVE_EXEC;
4407
4408 /*
4409 * Write the unit header.
4410 */
4411 SSMFILEUNITHDRV2 UnitHdr;
4412 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
4413 UnitHdr.offStream = ssmR3StrmTell(&pSSM->Strm);
4414 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
4415 UnitHdr.u32CRC = 0;
4416 UnitHdr.u32Version = 1;
4417 UnitHdr.u32Instance = 0;
4418 UnitHdr.u32Pass = uPass;
4419 UnitHdr.fFlags = 0;
4420 UnitHdr.cbName = sizeof("SSMLiveControl");
4421 memcpy(&UnitHdr.szName[0], "SSMLiveControl", UnitHdr.cbName);
[73097]4422 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[30396]4423 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
4424 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
[73097]4425 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[30396]4426 if (RT_SUCCESS(rc))
4427 {
4428 /*
4429 * Write the payload.
4430 */
4431 ssmR3DataWriteBegin(pSSM);
4432
4433 uint16_t u16PartsPerTenThousand = (uint16_t)(lrdPct * (100 - pSSM->uPercentDone));
4434 AssertMsg(u16PartsPerTenThousand <= 10000, ("%u\n", u16PartsPerTenThousand));
4435 ssmR3DataWrite(pSSM, &u16PartsPerTenThousand, sizeof(u16PartsPerTenThousand));
4436
4437 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
4438 if (RT_SUCCESS(rc))
4439 {
4440 /*
4441 * Write the termination record and flush the compression stream.
4442 */
4443 SSMRECTERM TermRec;
4444 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
4445 TermRec.cbRec = sizeof(TermRec) - 2;
4446 if (pSSM->Strm.fChecksummed)
4447 {
4448 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
4449 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
4450 }
4451 else
4452 {
4453 TermRec.fFlags = 0;
4454 TermRec.u32StreamCRC = 0;
4455 }
4456 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec);
4457 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
4458 if (RT_SUCCESS(rc))
4459 rc = ssmR3DataWriteFinish(pSSM);
4460 if (RT_SUCCESS(rc))
4461 {
4462 pSSM->enmOp = enmSavedState;
4463 return rc;
4464 }
4465 }
4466 }
4467
4468 LogRel(("SSM: Failed to write live control unit. rc=%Rrc\n", rc));
4469 if (RT_SUCCESS_NP(pSSM->rc))
4470 pSSM->rc = rc;
4471 pSSM->enmOp = enmSavedState;
4472 return rc;
4473}
4474
4475
[44505]4476
[30396]4477/**
[44505]4478 * Enters the critical session (optionally) associated with the unit.
4479 *
4480 * @param pUnit The unit.
4481 */
4482DECLINLINE(void) ssmR3UnitCritSectEnter(PSSMUNIT pUnit)
4483{
4484 PPDMCRITSECT pCritSect = pUnit->pCritSect;
4485 if (pCritSect)
4486 {
4487 int rc = PDMCritSectEnter(pCritSect, VERR_IGNORED);
4488 AssertRC(rc);
4489 }
4490}
4491
4492
4493/**
4494 * Leaves the critical session (optionally) associated with the unit.
4495 *
4496 * @param pUnit The unit.
4497 */
4498DECLINLINE(void) ssmR3UnitCritSectLeave(PSSMUNIT pUnit)
4499{
4500 PPDMCRITSECT pCritSect = pUnit->pCritSect;
4501 if (pCritSect)
4502 {
4503 int rc = PDMCritSectLeave(pCritSect);
4504 AssertRC(rc);
4505 }
4506}
4507
4508
4509/**
[24198]4510 * Do the pfnSaveDone run.
4511 *
4512 * @returns VBox status code (pSSM->rc).
[58122]4513 * @param pVM The cross context VM structure.
[24198]4514 * @param pSSM The saved state handle.
4515 */
4516static int ssmR3SaveDoDoneRun(PVM pVM, PSSMHANDLE pSSM)
4517{
4518 VM_ASSERT_EMT0(pVM);
4519
4520 /*
4521 * Do the done run.
4522 */
4523 pSSM->enmOp = SSMSTATE_SAVE_DONE;
4524 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4525 {
4526 if ( pUnit->u.Common.pfnSaveDone
4527 && ( pUnit->fCalled
4528 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
4529 {
4530 int rcOld = pSSM->rc;
4531 int rc;
[44505]4532 ssmR3UnitCritSectEnter(pUnit);
[24198]4533 switch (pUnit->enmType)
4534 {
4535 case SSMUNITTYPE_DEV:
4536 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, pSSM);
4537 break;
4538 case SSMUNITTYPE_DRV:
4539 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, pSSM);
4540 break;
[48986]4541 case SSMUNITTYPE_USB:
4542 rc = pUnit->u.Usb.pfnSaveDone(pUnit->u.Usb.pUsbIns, pSSM);
4543 break;
[24198]4544 case SSMUNITTYPE_INTERNAL:
4545 rc = pUnit->u.Internal.pfnSaveDone(pVM, pSSM);
4546 break;
4547 case SSMUNITTYPE_EXTERNAL:
4548 rc = pUnit->u.External.pfnSaveDone(pSSM, pUnit->u.External.pvUser);
4549 break;
4550 default:
[39402]4551 rc = VERR_SSM_IPE_1;
[24198]4552 break;
4553 }
[44505]4554 ssmR3UnitCritSectLeave(pUnit);
[24198]4555 if (RT_SUCCESS(rc) && pSSM->rc != rcOld)
4556 rc = pSSM->rc;
4557 if (RT_FAILURE(rc))
4558 {
4559 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
4560 if (RT_SUCCESS_NP(pSSM->rc))
4561 pSSM->rc = rc;
4562 }
4563 }
4564 }
4565 return pSSM->rc;
4566}
4567
4568
4569/**
[22792]4570 * Worker for SSMR3LiveDone and SSMR3Save that closes the handle and deletes the
4571 * saved state file on failure.
4572 *
4573 * @returns VBox status code (pSSM->rc).
[58122]4574 * @param pVM The cross context VM structure.
[22792]4575 * @param pSSM The saved state handle.
4576 */
4577static int ssmR3SaveDoClose(PVM pVM, PSSMHANDLE pSSM)
4578{
4579 VM_ASSERT_EMT0(pVM);
[24804]4580 pVM->ssm.s.uPass = 0;
[22792]4581
4582 /*
[22884]4583 * Make it non-cancellable, close the stream and delete the file on failure.
[22792]4584 */
[22884]4585 ssmR3SetCancellable(pVM, pSSM, false);
[24917]4586 int rc = ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED);
[22792]4587 if (RT_SUCCESS(rc))
4588 rc = pSSM->rc;
4589 if (RT_SUCCESS(rc))
4590 {
[24198]4591 Assert(pSSM->enmOp == SSMSTATE_SAVE_DONE);
[22792]4592 if (pSSM->pfnProgress)
[44393]4593 pSSM->pfnProgress(pVM->pUVM, 100, pSSM->pvUser);
[22792]4594 LogRel(("SSM: Successfully saved the VM state to '%s'\n",
4595 pSSM->pszFilename ? pSSM->pszFilename : "<remote-machine>"));
4596 }
4597 else
4598 {
4599 if (pSSM->pszFilename)
4600 {
4601 int rc2 = RTFileDelete(pSSM->pszFilename);
4602 AssertRC(rc2);
4603 if (RT_SUCCESS(rc2))
4604 LogRel(("SSM: Failed to save the VM state to '%s' (file deleted): %Rrc\n",
4605 pSSM->pszFilename, rc));
4606 else
4607 LogRel(("SSM: Failed to save the VM state to '%s' (file deletion failed, rc2=%Rrc): %Rrc\n",
4608 pSSM->pszFilename, rc2, rc));
4609 }
4610 else
4611 LogRel(("SSM: Failed to save the VM state.\n"));
[24198]4612
4613 Assert(pSSM->enmOp <= SSMSTATE_SAVE_DONE);
4614 if (pSSM->enmOp != SSMSTATE_SAVE_DONE)
4615 ssmR3SaveDoDoneRun(pVM, pSSM);
[22792]4616 }
4617
4618 /*
4619 * Trash the handle before freeing it.
4620 */
[22884]4621 ASMAtomicWriteU32(&pSSM->fCancelled, 0);
[22792]4622 pSSM->pVM = NULL;
4623 pSSM->enmAfter = SSMAFTER_INVALID;
4624 pSSM->enmOp = SSMSTATE_INVALID;
4625 RTMemFree(pSSM);
4626
4627 return rc;
4628}
4629
4630
4631/**
4632 * Closes the SSM handle.
4633 *
[23595]4634 * This must always be called on a handled returned by SSMR3LiveSave.
[22792]4635 *
[58170]4636 * @returns VBox status code.
[22792]4637 *
[23595]4638 * @param pSSM The SSM handle returned by SSMR3LiveSave.
[22792]4639 *
4640 * @thread EMT(0).
4641 */
[22803]4642VMMR3_INT_DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM)
[22792]4643{
4644 LogFlow(("SSMR3LiveDone: pSSM=%p\n", pSSM));
4645
4646 /*
4647 * Validate input.
4648 */
4649 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
4650 PVM pVM = pSSM->pVM;
4651 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
4652 VM_ASSERT_EMT0(pVM);
4653 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
[23668]4654 || pSSM->enmAfter == SSMAFTER_CONTINUE
[23801]4655 || pSSM->enmAfter == SSMAFTER_TELEPORT,
[22792]4656 ("%d\n", pSSM->enmAfter),
4657 VERR_INVALID_PARAMETER);
4658 AssertMsgReturn( pSSM->enmOp >= SSMSTATE_LIVE_PREP
4659 && pSSM->enmOp <= SSMSTATE_SAVE_DONE,
4660 ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
4661
4662 /*
4663 * Join paths with SSMR3Save again.
4664 */
4665 return ssmR3SaveDoClose(pVM, pSSM);
4666}
4667
4668
4669/**
[22554]4670 * Writes the directory.
4671 *
4672 * @returns VBox status code.
[58122]4673 * @param pVM The cross context VM structure.
[22554]4674 * @param pSSM The SSM handle.
4675 * @param pcEntries Where to return the number of directory entries.
4676 */
4677static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries)
4678{
[22792]4679 VM_ASSERT_EMT0(pVM);
4680
[22554]4681 /*
4682 * Grab some temporary memory for the dictionary.
4683 */
[73097]4684 size_t cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[pVM->ssm.s.cUnits]);
[22554]4685 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
4686 if (!pDir)
4687 {
4688 LogRel(("ssmR3WriteDirectory: failed to allocate %zu bytes!\n", cbDir));
4689 return VERR_NO_TMP_MEMORY;
4690 }
[1]4691
[22554]4692 /*
4693 * Initialize it.
4694 */
4695 memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic));
4696 pDir->u32CRC = 0;
4697 pDir->cEntries = 0;
[1]4698
[22554]4699 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4700 if (pUnit->offStream != RTFOFF_MIN)
4701 {
4702 PSSMFILEDIRENTRY pEntry = &pDir->aEntries[pDir->cEntries++];
4703 Assert(pDir->cEntries <= pVM->ssm.s.cUnits);
[23593]4704 Assert(pUnit->offStream >= (RTFOFF)sizeof(SSMFILEHDR));
[22554]4705 pEntry->off = pUnit->offStream;
4706 pEntry->u32Instance = pUnit->u32Instance;
4707 pEntry->u32NameCRC = RTCrc32(pUnit->szName, pUnit->cchName);
4708 }
[1]4709
[22554]4710 /*
4711 * Calculate the actual size and CRC-32, then write the directory
4712 * out to the stream.
4713 */
4714 *pcEntries = pDir->cEntries;
[73097]4715 cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[pDir->cEntries]);
[22554]4716 pDir->u32CRC = RTCrc32(pDir, cbDir);
4717 int rc = ssmR3StrmWrite(&pSSM->Strm, pDir, cbDir);
4718 RTMemTmpFree(pDir);
4719 return rc;
4720}
4721
4722
[1]4723/**
[22792]4724 * Finalize the saved state stream, i.e. add the end unit, directory
4725 * and footer.
4726 *
4727 * @returns VBox status code (pSSM->rc).
[58122]4728 * @param pVM The cross context VM structure.
[22792]4729 * @param pSSM The saved state handle.
4730 */
4731static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM)
4732{
4733 VM_ASSERT_EMT0(pVM);
4734 Assert(RT_SUCCESS(pSSM->rc));
4735
4736 /*
4737 * Write the end unit.
4738 */
4739 SSMFILEUNITHDRV2 UnitHdr;
4740 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic));
4741 UnitHdr.offStream = ssmR3StrmTell(&pSSM->Strm);
4742 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
4743 UnitHdr.u32CRC = 0;
4744 UnitHdr.u32Version = 0;
4745 UnitHdr.u32Instance = 0;
[22793]4746 UnitHdr.u32Pass = SSM_PASS_FINAL;
[22792]4747 UnitHdr.fFlags = 0;
4748 UnitHdr.cbName = 0;
[73097]4749 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF(SSMFILEUNITHDRV2, szName[0]));
[22792]4750 Log(("SSM: Unit at %#9llx: END UNIT\n", UnitHdr.offStream));
[73097]4751 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF(SSMFILEUNITHDRV2, szName[0]));
[22792]4752 if (RT_FAILURE(rc))
4753 {
4754 LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc));
4755 return pSSM->rc = rc;
4756 }
4757
4758 /*
4759 * Write the directory for the final units and then the footer.
4760 */
4761 SSMFILEFTR Footer;
4762 rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries);
4763 if (RT_FAILURE(rc))
4764 {
4765 LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));
4766 return pSSM->rc = rc;
4767 }
4768
4769 memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic));
4770 Footer.offStream = ssmR3StrmTell(&pSSM->Strm);
4771 Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
4772 Footer.u32Reserved = 0;
4773 Footer.u32CRC = 0;
4774 Footer.u32CRC = RTCrc32(&Footer, sizeof(Footer));
4775 Log(("SSM: Footer at %#9llx: \n", Footer.offStream));
4776 rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));
4777 if (RT_SUCCESS(rc))
4778 rc = ssmR3StrmSetEnd(&pSSM->Strm);
4779 if (RT_FAILURE(rc))
4780 {
4781 LogRel(("SSM: Failed writing the footer: %Rrc\n", rc));
4782 return pSSM->rc = rc;
4783 }
4784
4785 LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n",
4786 Footer.offStream, Footer.offStream, Footer.cDirEntries));
4787 return VINF_SUCCESS;
4788}
4789
4790
4791/**
[30396]4792 * Works the progress calculation during the exec part of a live save.
4793 *
4794 * @param pSSM The SSM handle.
4795 * @param iUnit The current unit number.
4796 */
4797static void ssmR3ProgressByUnit(PSSMHANDLE pSSM, uint32_t iUnit)
4798{
4799 if (pSSM->fLiveSave)
4800 {
4801 unsigned uPctExec = iUnit * 100 / pSSM->pVM->ssm.s.cUnits;
4802 unsigned cPctExec = 100 - pSSM->uPercentDone - pSSM->uPercentPrepare - pSSM->uPercentLive;
4803 long double lrdPct = (long double)uPctExec * cPctExec / 100 + pSSM->uPercentPrepare + pSSM->uPercentLive;
4804 unsigned uPct = (unsigned)lrdPct;
4805 if (uPct != pSSM->uPercent)
4806 {
4807 ssmR3LiveControlEmit(pSSM, lrdPct, SSM_PASS_FINAL);
4808 pSSM->uPercent = uPct;
[44393]4809 pSSM->pfnProgress(pSSM->pVM->pUVM, uPct, pSSM->pvUser);
[30396]4810 }
4811 }
4812}
4813
4814
4815/**
[22792]4816 * Do the pfnSaveExec run.
4817 *
4818 * @returns VBox status code (pSSM->rc).
[58122]4819 * @param pVM The cross context VM structure.
[22792]4820 * @param pSSM The saved state handle.
4821 */
4822static int ssmR3SaveDoExecRun(PVM pVM, PSSMHANDLE pSSM)
4823{
4824 VM_ASSERT_EMT0(pVM);
[22793]4825 AssertRC(pSSM->rc);
4826 pSSM->rc = VINF_SUCCESS;
[22792]4827 pSSM->enmOp = SSMSTATE_SAVE_EXEC;
[30396]4828 unsigned iUnit = 0;
4829 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext, iUnit++)
[22792]4830 {
4831 /*
4832 * Not all unit have a callback. Skip those which don't and
4833 * make sure to keep the progress indicator up to date.
4834 */
[30396]4835 ssmR3ProgressByUnit(pSSM, iUnit);
[22792]4836 pSSM->offEstUnitEnd += pUnit->cbGuess;
4837 if (!pUnit->u.Common.pfnSaveExec)
4838 {
4839 pUnit->fCalled = true;
4840 if (pUnit->cbGuess)
[30396]4841 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
[22792]4842 continue;
4843 }
4844 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
4845
4846 /*
[22884]4847 * Check for cancellation.
4848 */
4849 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
4850 {
4851 LogRel(("SSM: Cancelled!\n"));
4852 AssertRC(pSSM->rc);
4853 return pSSM->rc = VERR_SSM_CANCELLED;
4854 }
4855
4856 /*
[22792]4857 * Write data unit header
4858 */
4859 SSMFILEUNITHDRV2 UnitHdr;
4860 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
4861 UnitHdr.offStream = pUnit->offStream;
4862 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
4863 UnitHdr.u32CRC = 0;
4864 UnitHdr.u32Version = pUnit->u32Version;
4865 UnitHdr.u32Instance = pUnit->u32Instance;
[22793]4866 UnitHdr.u32Pass = SSM_PASS_FINAL;
[22792]4867 UnitHdr.fFlags = 0;
4868 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
4869 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
[73097]4870 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[22793]4871 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
4872 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
[73097]4873 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[22792]4874 if (RT_FAILURE(rc))
4875 {
4876 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
4877 return pSSM->rc = rc;
4878 }
4879
4880 /*
4881 * Call the execute handler.
4882 */
4883 ssmR3DataWriteBegin(pSSM);
[44505]4884 ssmR3UnitCritSectEnter(pUnit);
[22792]4885 switch (pUnit->enmType)
4886 {
4887 case SSMUNITTYPE_DEV:
4888 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, pSSM);
4889 break;
4890 case SSMUNITTYPE_DRV:
4891 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, pSSM);
4892 break;
[48986]4893 case SSMUNITTYPE_USB:
4894 rc = pUnit->u.Usb.pfnSaveExec(pUnit->u.Usb.pUsbIns, pSSM);
4895 break;
[22792]4896 case SSMUNITTYPE_INTERNAL:
4897 rc = pUnit->u.Internal.pfnSaveExec(pVM, pSSM);
4898 break;
4899 case SSMUNITTYPE_EXTERNAL:
4900 pUnit->u.External.pfnSaveExec(pSSM, pUnit->u.External.pvUser);
4901 rc = pSSM->rc;
4902 break;
4903 default:
[39402]4904 rc = VERR_SSM_IPE_1;
[22792]4905 break;
4906 }
[44505]4907 ssmR3UnitCritSectLeave(pUnit);
[22792]4908 pUnit->fCalled = true;
[23436]4909 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
4910 pSSM->rc = rc;
4911 else
[22792]4912 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
4913 if (RT_FAILURE(rc))
4914 {
4915 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance));
4916 return rc;
4917 }
4918
4919 /*
4920 * Write the termination record and flush the compression stream.
4921 */
4922 SSMRECTERM TermRec;
4923 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
4924 TermRec.cbRec = sizeof(TermRec) - 2;
4925 if (pSSM->Strm.fChecksummed)
4926 {
4927 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
4928 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
4929 }
4930 else
4931 {
4932 TermRec.fFlags = 0;
4933 TermRec.u32StreamCRC = 0;
4934 }
4935 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec);
4936 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
4937 if (RT_SUCCESS(rc))
4938 rc = ssmR3DataWriteFinish(pSSM);
4939 if (RT_FAILURE(rc))
4940 {
[22793]4941 LogRel(("SSM: Failed terminating unit: %Rrc\n", rc));
[22792]4942 return pSSM->rc = rc;
4943 }
4944
4945 /*
4946 * Advance the progress indicator to the end of the current unit.
4947 */
[30396]4948 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
[22792]4949 } /* for each unit */
[30396]4950 ssmR3ProgressByUnit(pSSM, pVM->ssm.s.cUnits);
[22792]4951
4952 /* (progress should be pending 99% now) */
[30396]4953 AssertMsg( pSSM->uPercent == 101 - pSSM->uPercentDone
4954 || pSSM->uPercent == 100 - pSSM->uPercentDone,
4955 ("%d\n", pSSM->uPercent));
[22792]4956 return VINF_SUCCESS;
4957}
4958
4959
4960/**
4961 * Do the pfnSavePrep run.
4962 *
4963 * @returns VBox status code (pSSM->rc).
[58122]4964 * @param pVM The cross context VM structure.
[22792]4965 * @param pSSM The saved state handle.
4966 */
4967static int ssmR3SaveDoPrepRun(PVM pVM, PSSMHANDLE pSSM)
4968{
4969 VM_ASSERT_EMT0(pVM);
4970 Assert(RT_SUCCESS(pSSM->rc));
4971 pSSM->enmOp = SSMSTATE_SAVE_PREP;
4972 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4973 {
4974 if (pUnit->u.Common.pfnSavePrep)
4975 {
4976 int rc;
[44505]4977 ssmR3UnitCritSectEnter(pUnit);
[22792]4978 switch (pUnit->enmType)
4979 {
4980 case SSMUNITTYPE_DEV:
4981 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, pSSM);
4982 break;
4983 case SSMUNITTYPE_DRV:
4984 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, pSSM);
4985 break;
[48986]4986 case SSMUNITTYPE_USB:
4987 rc = pUnit->u.Usb.pfnSavePrep(pUnit->u.Usb.pUsbIns, pSSM);
4988 break;
[22792]4989 case SSMUNITTYPE_INTERNAL:
4990 rc = pUnit->u.Internal.pfnSavePrep(pVM, pSSM);
4991 break;
4992 case SSMUNITTYPE_EXTERNAL:
4993 rc = pUnit->u.External.pfnSavePrep(pSSM, pUnit->u.External.pvUser);
4994 break;
4995 default:
[39402]4996 rc = VERR_SSM_IPE_1;
[22792]4997 break;
4998 }
[44505]4999 ssmR3UnitCritSectLeave(pUnit);
[22792]5000 pUnit->fCalled = true;
[23436]5001 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
5002 pSSM->rc = rc;
5003 else
[22792]5004 rc = pSSM->rc;
5005 if (RT_FAILURE(rc))
5006 {
5007 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
5008 return rc;
5009 }
5010 }
5011
5012 pSSM->cbEstTotal += pUnit->cbGuess;
5013 }
5014
5015 /*
5016 * Work the progress indicator if we got one.
5017 */
5018 if (pSSM->pfnProgress)
[44393]5019 pSSM->pfnProgress(pVM->pUVM, pSSM->uPercentPrepare + pSSM->uPercentLive - 1, pSSM->pvUser);
[30396]5020 pSSM->uPercent = pSSM->uPercentPrepare + pSSM->uPercentLive;
[22792]5021
5022 return VINF_SUCCESS;
5023}
5024
5025
5026/**
[23595]5027 * Common worker for SSMR3Save and SSMR3LiveSave.
[22792]5028 *
5029 * @returns VBox status code (no need to check pSSM->rc).
[58122]5030 * @param pVM The cross context VM structure.
[22792]5031 * @param pSSM The state handle.
5032 *
5033 * @thread EMT(0)
5034 */
5035static int ssmR3SaveDoCommon(PVM pVM, PSSMHANDLE pSSM)
5036{
5037 VM_ASSERT_EMT0(pVM);
5038
5039 /*
5040 * Do the work.
5041 */
5042 int rc = ssmR3SaveDoPrepRun(pVM, pSSM);
5043 if (RT_SUCCESS(rc))
5044 {
5045 rc = ssmR3SaveDoExecRun(pVM, pSSM);
5046 if (RT_SUCCESS(rc))
5047 rc = ssmR3SaveDoFinalization(pVM, pSSM);
5048 }
5049 Assert(pSSM->rc == rc);
5050 int rc2 = ssmR3SaveDoDoneRun(pVM, pSSM);
5051 if (RT_SUCCESS(rc))
5052 rc = rc2;
5053
5054 return rc;
5055}
5056
5057
5058/**
5059 * Saves the rest of the state on EMT0.
5060 *
[58170]5061 * @returns VBox status code.
[22792]5062 *
[23595]5063 * @param pSSM The SSM handle returned by SSMR3LiveSave.
[22792]5064 *
5065 * @thread Non-EMT thread. Will involve the EMT at the end of the operation.
5066 */
[22803]5067VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM)
[22792]5068{
5069 LogFlow(("SSMR3LiveDoStep2: pSSM=%p\n", pSSM));
5070
5071 /*
5072 * Validate input.
5073 */
5074 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
5075 PVM pVM = pSSM->pVM;
5076 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
5077 VM_ASSERT_EMT0(pVM);
5078 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
[23668]5079 || pSSM->enmAfter == SSMAFTER_CONTINUE
[23801]5080 || pSSM->enmAfter == SSMAFTER_TELEPORT,
[22792]5081 ("%d\n", pSSM->enmAfter),
5082 VERR_INVALID_PARAMETER);
[22793]5083 AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_STEP2, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
5084 AssertRCReturn(pSSM->rc, pSSM->rc);
[22792]5085
5086 /*
5087 * Join paths with VMMR3Save.
5088 */
5089 return ssmR3SaveDoCommon(pVM, pSSM);
5090}
5091
5092
5093/**
5094 * Writes the file header and clear the per-unit data.
5095 *
5096 * @returns VBox status code.
[58122]5097 * @param pVM The cross context VM structure.
[22792]5098 * @param pSSM The SSM handle.
5099 */
5100static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM)
5101{
5102 /*
5103 * Write the header.
5104 */
5105 SSMFILEHDR FileHdr;
5106 memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic));
5107 FileHdr.u16VerMajor = VBOX_VERSION_MAJOR;
5108 FileHdr.u16VerMinor = VBOX_VERSION_MINOR;
5109 FileHdr.u32VerBuild = VBOX_VERSION_BUILD;
[32343]5110 FileHdr.u32SvnRev = VMMGetSvnRev();
[22792]5111 FileHdr.cHostBits = HC_ARCH_BITS;
5112 FileHdr.cbGCPhys = sizeof(RTGCPHYS);
5113 FileHdr.cbGCPtr = sizeof(RTGCPTR);
5114 FileHdr.u8Reserved = 0;
5115 FileHdr.cUnits = pVM->ssm.s.cUnits;
5116 FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32;
[23540]5117 if (pSSM->fLiveSave)
5118 FileHdr.fFlags |= SSMFILEHDR_FLAGS_STREAM_LIVE_SAVE;
[22792]5119 FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer);
5120 FileHdr.u32CRC = 0;
5121 FileHdr.u32CRC = RTCrc32(&FileHdr, sizeof(FileHdr));
5122 int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr));
[23593]5123 if (RT_FAILURE(rc))
[22792]5124 return rc;
5125
5126 /*
5127 * Clear the per unit flags and offsets.
5128 */
5129 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
5130 {
5131 pUnit->fCalled = false;
5132 pUnit->offStream = RTFOFF_MIN;
5133 }
5134
5135 return VINF_SUCCESS;
5136}
5137
5138
5139/**
5140 * Creates a new saved state file.
5141 *
5142 * @returns VBox status code.
[58122]5143 * @param pVM The cross context VM structure.
[23595]5144 * @param pszFilename The name of the file. NULL if pStreamOps is
5145 * used.
5146 * @param pStreamOps The stream methods. NULL if pszFilename is
5147 * used.
5148 * @param pvStreamOpsUser The user argument to the stream methods.
[22792]5149 * @param enmAfter What to do afterwards.
5150 * @param pfnProgress The progress callback.
[23596]5151 * @param pvProgressUser The progress callback user argument.
[22792]5152 * @param ppSSM Where to return the pointer to the saved state
5153 * handle upon successful return. Free it using
5154 * RTMemFree after closing the stream.
5155 */
[23595]5156static int ssmR3SaveDoCreateFile(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
[23596]5157 SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser, PSSMHANDLE *ppSSM)
[22792]5158{
5159 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
5160 if (!pSSM)
5161 return VERR_NO_MEMORY;
5162
[24874]5163 pSSM->pVM = pVM;
5164 pSSM->enmOp = SSMSTATE_INVALID;
5165 pSSM->enmAfter = enmAfter;
5166 pSSM->fCancelled = SSMHANDLE_OK;
5167 pSSM->rc = VINF_SUCCESS;
5168 pSSM->cbUnitLeftV1 = 0;
5169 pSSM->offUnit = UINT64_MAX;
[42335]5170 pSSM->offUnitUser = UINT64_MAX;
[24874]5171 pSSM->fLiveSave = false;
5172 pSSM->pfnProgress = pfnProgress;
5173 pSSM->pvUser = pvProgressUser;
5174 pSSM->uPercent = 0;
5175 pSSM->offEstProgress = 0;
5176 pSSM->cbEstTotal = 0;
5177 pSSM->offEst = 0;
5178 pSSM->offEstUnitEnd = 0;
[30396]5179 pSSM->uPercentLive = 0;
[24874]5180 pSSM->uPercentPrepare = 0;
5181 pSSM->uPercentDone = 0;
[30396]5182 pSSM->uReportedLivePercent = 0;
[24874]5183 pSSM->pszFilename = pszFilename;
5184 pSSM->u.Write.offDataBuffer = 0;
5185 pSSM->u.Write.cMsMaxDowntime = UINT32_MAX;
[22792]5186
[23595]5187 int rc;
5188 if (pStreamOps)
5189 rc = ssmR3StrmInit(&pSSM->Strm, pStreamOps, pvStreamOpsUser, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/);
5190 else
5191 rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/);
[22792]5192 if (RT_FAILURE(rc))
5193 {
5194 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));
5195 RTMemFree(pSSM);
5196 return rc;
5197 }
5198
5199 *ppSSM = pSSM;
5200 return VINF_SUCCESS;
5201}
5202
5203
5204/**
[22554]5205 * Start VM save operation.
5206 *
[58170]5207 * @returns VBox status code.
[22554]5208 *
[58122]5209 * @param pVM The cross context VM structure.
[31895]5210 * @param pszFilename Name of the file to save the state in. NULL if pStreamOps is used.
5211 * @param pStreamOps The stream method table. NULL if pszFilename is
5212 * used.
5213 * @param pvStreamOpsUser The user argument to the stream methods.
[22554]5214 * @param enmAfter What is planned after a successful save operation.
5215 * @param pfnProgress Progress callback. Optional.
5216 * @param pvUser User argument for the progress callback.
5217 *
5218 * @thread EMT
5219 */
[32343]5220VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
[31895]5221 SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
[22554]5222{
5223 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
[22792]5224 VM_ASSERT_EMT0(pVM);
[22554]5225
5226 /*
5227 * Validate input.
5228 */
[22559]5229 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY
[22792]5230 || enmAfter == SSMAFTER_CONTINUE,
[22559]5231 ("%d\n", enmAfter),
5232 VERR_INVALID_PARAMETER);
[22554]5233
[31895]5234 AssertReturn(!pszFilename != !pStreamOps, VERR_INVALID_PARAMETER);
5235 if (pStreamOps)
5236 {
5237 AssertReturn(pStreamOps->u32Version == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
5238 AssertReturn(pStreamOps->u32EndVersion == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
5239 AssertReturn(pStreamOps->pfnWrite, VERR_INVALID_PARAMETER);
5240 AssertReturn(pStreamOps->pfnRead, VERR_INVALID_PARAMETER);
5241 AssertReturn(pStreamOps->pfnSeek, VERR_INVALID_PARAMETER);
5242 AssertReturn(pStreamOps->pfnTell, VERR_INVALID_PARAMETER);
5243 AssertReturn(pStreamOps->pfnSize, VERR_INVALID_PARAMETER);
5244 AssertReturn(pStreamOps->pfnClose, VERR_INVALID_PARAMETER);
5245 }
5246
[22554]5247 /*
[22792]5248 * Create the saved state file and handle.
[22554]5249 *
5250 * Note that there might be quite some work to do after executing the saving,
[22792]5251 * so we reserve 20% for the 'Done' period.
[22554]5252 */
[22792]5253 PSSMHANDLE pSSM;
[31895]5254 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, pStreamOps, pvStreamOpsUser,
[23595]5255 enmAfter, pfnProgress, pvUser, &pSSM);
[22554]5256 if (RT_FAILURE(rc))
5257 return rc;
[30396]5258 pSSM->uPercentLive = 0;
[22792]5259 pSSM->uPercentPrepare = 20;
5260 pSSM->uPercentDone = 2;
[31895]5261 pSSM->fLiveSave = false;
[22554]5262
[22792]5263 /*
5264 * Write the saved state stream header and join paths with
5265 * the other save methods for the rest of the job.
5266 */
[22554]5267 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
[22792]5268 ssmR3StrmStartIoThread(&pSSM->Strm);
5269 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
5270 if (RT_SUCCESS(rc))
[22884]5271 {
5272 ssmR3SetCancellable(pVM, pSSM, true);
[22792]5273 ssmR3SaveDoCommon(pVM, pSSM);
[22884]5274 }
5275
[22792]5276 return ssmR3SaveDoClose(pVM, pSSM);
5277}
[22554]5278
[22792]5279
5280/**
[30396]5281 * Used by PGM to report the completion percentage of the live stage during the
5282 * vote run.
5283 *
5284 * @param pSSM The saved state handle.
5285 * @param uPercent The completion percentage.
5286 */
5287VMMR3DECL(void) SSMR3HandleReportLivePercent(PSSMHANDLE pSSM, unsigned uPercent)
5288{
5289 AssertMsgReturnVoid(pSSM->enmOp == SSMSTATE_LIVE_VOTE, ("%d\n", pSSM->enmOp));
5290 AssertReturnVoid(uPercent <= 100);
5291 if (uPercent < pSSM->uReportedLivePercent)
5292 pSSM->uReportedLivePercent = uPercent;
5293}
5294
5295
5296/**
[22792]5297 * Calls pfnLiveVote for all units.
5298 *
5299 * @returns VBox status code (no need to check pSSM->rc).
[22793]5300 * @retval VINF_SUCCESS if we can pass on to step 2.
5301 * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if we need another pass.
5302 *
[58122]5303 * @param pVM The cross context VM structure.
[22792]5304 * @param pSSM The saved state handle.
[22793]5305 * @param uPass The current pass.
[22792]5306 */
[22793]5307static int ssmR3LiveDoVoteRun(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
[22792]5308{
[23709]5309 int rcRet = VINF_SUCCESS;
[22793]5310 AssertRC(pSSM->rc);
[22792]5311 pSSM->rc = VINF_SUCCESS;
5312 pSSM->enmOp = SSMSTATE_LIVE_VOTE;
[30396]5313
5314 unsigned uPrevPrecent = pSSM->uReportedLivePercent;
5315 pSSM->uReportedLivePercent = 101;
5316
[22792]5317 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
[22554]5318 {
[23709]5319 if ( pUnit->u.Common.pfnLiveVote
5320 && !pUnit->fDoneLive)
[22554]5321 {
[22792]5322 int rc;
[44505]5323 ssmR3UnitCritSectEnter(pUnit);
[22792]5324 switch (pUnit->enmType)
5325 {
5326 case SSMUNITTYPE_DEV:
[24793]5327 rc = pUnit->u.Dev.pfnLiveVote(pUnit->u.Dev.pDevIns, pSSM, uPass);
[22792]5328 break;
5329 case SSMUNITTYPE_DRV:
[24793]5330 rc = pUnit->u.Drv.pfnLiveVote(pUnit->u.Drv.pDrvIns, pSSM, uPass);
[22792]5331 break;
[48986]5332 case SSMUNITTYPE_USB:
5333 rc = pUnit->u.Usb.pfnLiveVote(pUnit->u.Usb.pUsbIns, pSSM, uPass);
5334 break;
[22792]5335 case SSMUNITTYPE_INTERNAL:
[24793]5336 rc = pUnit->u.Internal.pfnLiveVote(pVM, pSSM, uPass);
[22792]5337 break;
5338 case SSMUNITTYPE_EXTERNAL:
[24793]5339 rc = pUnit->u.External.pfnLiveVote(pSSM, pUnit->u.External.pvUser, uPass);
[22792]5340 break;
5341 default:
[39402]5342 rc = VERR_SSM_IPE_1;
[22792]5343 break;
5344 }
[44505]5345 ssmR3UnitCritSectLeave(pUnit);
[23436]5346 pUnit->fCalled = true;
[22792]5347 Assert(pSSM->rc == VINF_SUCCESS);
5348 if (rc != VINF_SUCCESS)
[22554]5349 {
[22792]5350 if (rc == VINF_SSM_VOTE_FOR_ANOTHER_PASS)
[22554]5351 {
[22793]5352 Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> VINF_SSM_VOTE_FOR_ANOTHER_PASS (pass=%u)\n", pUnit->szName, pUnit->u32Instance, uPass));
[23709]5353 rcRet = VINF_SSM_VOTE_FOR_ANOTHER_PASS;
[22554]5354 }
[23709]5355 else if (rc == VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN)
5356 {
5357 pUnit->fDoneLive = true;
5358 Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN (pass=%u)\n", pUnit->szName, pUnit->u32Instance, uPass));
5359 }
5360 else
5361 {
5362 /*
5363 * rc is usually VERR_SSM_VOTE_FOR_GIVING_UP here, but we allow
5364 * other status codes for better user feed back. However, no
5365 * other non-error status is allowed.
5366 */
5367 LogRel(("SSM: Error - '%s'/#%u voted %Rrc! (pass=%u)\n", pUnit->szName, pUnit->u32Instance, rc, uPass));
5368 AssertMsgReturn(RT_FAILURE(rc), ("%Rrc; '%s'\n", rc, pUnit->szName), pSSM->rc = VERR_IPE_UNEXPECTED_INFO_STATUS);
5369 return pSSM->rc = rc;
5370 }
[22554]5371 }
5372 }
[22792]5373 }
[23709]5374 if (rcRet == VINF_SUCCESS)
[30396]5375 {
[23709]5376 LogRel(("SSM: Step 1 completed after pass %u.\n", uPass));
[30396]5377 pSSM->uReportedLivePercent = 100;
5378 }
5379 else
5380 {
5381 /*
5382 * Work the progress callback.
5383 */
5384 if (pSSM->uReportedLivePercent > 100)
5385 pSSM->uReportedLivePercent = 0;
5386 if ( pSSM->uReportedLivePercent != uPrevPrecent
5387 && pSSM->pfnProgress
5388 && pSSM->uPercentLive)
5389 {
5390 long double lrdPct = (long double)pSSM->uReportedLivePercent * pSSM->uPercentLive / 100;
5391 unsigned uPct = (unsigned)lrdPct;
5392 if (uPct != pSSM->uPercent)
5393 {
5394 ssmR3LiveControlEmit(pSSM, lrdPct, uPass);
5395 pSSM->uPercent = uPct;
[44393]5396 pSSM->pfnProgress(pVM->pUVM, uPct, pSSM->pvUser);
[30396]5397 }
5398 }
5399 }
[23709]5400 return rcRet;
[22792]5401}
[22554]5402
5403
[22792]5404/**
[22793]5405 * Calls pfnLiveExec for all units.
5406 *
5407 * @returns VBox status code (no need to check pSSM->rc).
5408 *
[58122]5409 * @param pVM The cross context VM structure.
[22793]5410 * @param pSSM The saved state handle.
5411 * @param uPass The current pass.
5412 */
5413static int ssmR3LiveDoExecRun(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
5414{
5415 AssertRC(pSSM->rc);
5416 pSSM->rc = VINF_SUCCESS;
5417 pSSM->enmOp = SSMSTATE_LIVE_EXEC;
[23905]5418 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
[22793]5419 {
5420 /*
5421 * Skip units without a callback (this is most).
5422 */
[23709]5423 if ( !pUnit->u.Common.pfnLiveExec
5424 || pUnit->fDoneLive)
[22793]5425 continue;
5426 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
5427
5428 /*
[22884]5429 * Check for cancellation.
5430 */
5431 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
5432 {
5433 LogRel(("SSM: Cancelled!\n"));
5434 AssertRC(pSSM->rc);
5435 return pSSM->rc = VERR_SSM_CANCELLED;
5436 }
5437
5438 /*
[22793]5439 * Write data unit header.
5440 */
5441 SSMFILEUNITHDRV2 UnitHdr;
5442 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
5443 UnitHdr.offStream = pUnit->offStream;
5444 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
5445 UnitHdr.u32CRC = 0;
5446 UnitHdr.u32Version = pUnit->u32Version;
5447 UnitHdr.u32Instance = pUnit->u32Instance;
5448 UnitHdr.u32Pass = uPass;
5449 UnitHdr.fFlags = 0;
5450 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
5451 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
[73097]5452 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[22793]5453 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
5454 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
[73097]5455 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
[22793]5456 if (RT_FAILURE(rc))
5457 {
5458 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
5459 return pSSM->rc = rc;
5460 }
5461
5462 /*
5463 * Call the execute handler.
5464 */
5465 ssmR3DataWriteBegin(pSSM);
[44505]5466 ssmR3UnitCritSectEnter(pUnit);
[22793]5467 switch (pUnit->enmType)
5468 {
5469 case SSMUNITTYPE_DEV:
5470 rc = pUnit->u.Dev.pfnLiveExec(pUnit->u.Dev.pDevIns, pSSM, uPass);
5471 break;
5472 case SSMUNITTYPE_DRV:
5473 rc = pUnit->u.Drv.pfnLiveExec(pUnit->u.Drv.pDrvIns, pSSM, uPass);
5474 break;
[48986]5475 case SSMUNITTYPE_USB:
5476 rc = pUnit->u.Usb.pfnLiveExec(pUnit->u.Usb.pUsbIns, pSSM, uPass);
5477 break;
[22793]5478 case SSMUNITTYPE_INTERNAL:
5479 rc = pUnit->u.Internal.pfnLiveExec(pVM, pSSM, uPass);
5480 break;
5481 case SSMUNITTYPE_EXTERNAL:
5482 rc = pUnit->u.External.pfnLiveExec(pSSM, pUnit->u.External.pvUser, uPass);
5483 break;
5484 default:
[39402]5485 rc = VERR_SSM_IPE_1;
[22793]5486 break;
5487 }
[44505]5488 ssmR3UnitCritSectLeave(pUnit);
[22793]5489 pUnit->fCalled = true;
[23436]5490 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
5491 pSSM->rc = rc;
5492 else
[23714]5493 {
5494 if (rc == VINF_SSM_DONT_CALL_AGAIN)
5495 pUnit->fDoneLive = true;
[22793]5496 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
[23714]5497 }
[22793]5498 if (RT_FAILURE(rc))
5499 {
5500 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance));
5501 if (RT_SUCCESS(pSSM->rc))
5502 pSSM->rc = rc;
5503 return rc;
5504 }
5505
5506 /*
5507 * Write the termination record and flush the compression stream.
5508 */
5509 SSMRECTERM TermRec;
5510 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
5511 TermRec.cbRec = sizeof(TermRec) - 2;
5512 if (pSSM->Strm.fChecksummed)
5513 {
5514 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
5515 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
5516 }
5517 else
5518 {
5519 TermRec.fFlags = 0;
5520 TermRec.u32StreamCRC = 0;
5521 }
5522 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec);
5523 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
5524 if (RT_SUCCESS(rc))
5525 rc = ssmR3DataWriteFinish(pSSM);
5526 if (RT_FAILURE(rc))
5527 {
5528 LogRel(("SSM: Failed terminating unit: %Rrc (pass=%u)\n", rc, uPass));
5529 return pSSM->rc = rc;
5530 }
5531 } /* for each unit */
5532
5533 return VINF_SUCCESS;
5534}
5535
5536
5537/**
[23905]5538 * Implements the live exec+vote loop.
[22792]5539 *
[23905]5540 * @returns VBox status code (no need to check pSSM->rc).
[58122]5541 * @param pVM The cross context VM structure.
[23905]5542 * @param pSSM The saved state handle.
[22792]5543 */
[23905]5544static int ssmR3DoLiveExecVoteLoop(PVM pVM, PSSMHANDLE pSSM)
[22792]5545{
5546 /*
[22793]5547 * Calc the max saved state size before we should give up because of insane
5548 * amounts of data.
[22792]5549 */
[22793]5550#define SSM_MAX_GROWTH_FILE 10000
5551#define SSM_MAX_GROWTH_REMOTE 100000
5552 uint64_t cbSum = 0;
5553 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
5554 cbSum += pUnit->cbGuess;
5555 uint64_t cbMax = cbSum * (pSSM->pszFilename ? SSM_MAX_GROWTH_FILE : SSM_MAX_GROWTH_REMOTE);
5556 AssertLogRelMsgReturn(cbMax > cbSum, ("cbMax=%#RX64, cbSum=%#RX64\n", cbMax, cbSum), pSSM->rc = VERR_OUT_OF_RANGE);
5557 if (cbMax < _1G)
5558 cbMax = _1G;
[22554]5559
[22793]5560 /*
5561 * The pass loop.
5562 *
[33540]5563 * The number of iterations is restricted for two reasons, first
[22793]5564 * to make sure
5565 */
5566#define SSM_MAX_PASSES _1M
5567 for (uint32_t uPass = 0; uPass < SSM_MAX_PASSES; uPass++)
5568 {
[24804]5569 pVM->ssm.s.uPass = uPass;
5570
[22793]5571 /*
5572 * Save state and vote on whether we need more passes or not.
5573 */
5574 int rc = ssmR3LiveDoExecRun(pVM, pSSM, uPass);
5575 if (RT_FAILURE(rc))
5576 return rc;
5577 rc = ssmR3LiveDoVoteRun(pVM, pSSM, uPass);
5578 if (rc == VINF_SUCCESS)
5579 {
5580 pSSM->enmOp = SSMSTATE_LIVE_STEP2;
5581 return VINF_SUCCESS;
5582 }
5583 if (RT_FAILURE(rc))
5584 return rc;
5585
5586 /*
5587 * Check that we're still within sane data amounts.
5588 */
5589 uint64_t cbSaved = ssmR3StrmTell(&pSSM->Strm);
5590 if (cbSaved > cbMax)
5591 {
5592 LogRel(("SSM: Giving up: Exceeded max state size. (cbSaved=%#RX64, cbMax=%#RX64)\n", cbSaved, cbMax));
5593 return pSSM->rc = VERR_SSM_STATE_GREW_TOO_BIG;
5594 }
5595
5596 /*
[24895]5597 * Check that the stream is still OK.
[22793]5598 */
[24895]5599 rc = ssmR3StrmCheckAndFlush(&pSSM->Strm);
5600 if (RT_FAILURE(rc))
5601 return pSSM->rc = rc;
[22793]5602 }
5603
5604 LogRel(("SSM: Giving up: Too many passes! (%u)\n", SSM_MAX_PASSES));
5605 return pSSM->rc = VERR_SSM_TOO_MANY_PASSES;
[22792]5606}
[22554]5607
[22792]5608
5609/**
5610 * Calls pfnLivePrep for all units.
5611 *
5612 * @returns VBox status code (no need to check pSSM->rc).
[58122]5613 * @param pVM The cross context VM structure.
[22792]5614 * @param pSSM The saved state handle.
5615 */
5616static int ssmR3DoLivePrepRun(PVM pVM, PSSMHANDLE pSSM)
5617{
5618 /*
5619 * Do the prepare run.
5620 */
5621 pSSM->rc = VINF_SUCCESS;
5622 pSSM->enmOp = SSMSTATE_SAVE_PREP;
5623 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
5624 {
5625 if (pUnit->u.Common.pfnLivePrep)
[22554]5626 {
[22792]5627 int rc;
[44505]5628 ssmR3UnitCritSectEnter(pUnit);
[22792]5629 switch (pUnit->enmType)
[22554]5630 {
[22792]5631 case SSMUNITTYPE_DEV:
5632 rc = pUnit->u.Dev.pfnLivePrep(pUnit->u.Dev.pDevIns, pSSM);
5633 break;
5634 case SSMUNITTYPE_DRV:
5635 rc = pUnit->u.Drv.pfnLivePrep(pUnit->u.Drv.pDrvIns, pSSM);
5636 break;
[48986]5637 case SSMUNITTYPE_USB:
5638 rc = pUnit->u.Usb.pfnLivePrep(pUnit->u.Usb.pUsbIns, pSSM);
5639 break;
[22792]5640 case SSMUNITTYPE_INTERNAL:
5641 rc = pUnit->u.Internal.pfnLivePrep(pVM, pSSM);
5642 break;
5643 case SSMUNITTYPE_EXTERNAL:
5644 rc = pUnit->u.External.pfnLivePrep(pSSM, pUnit->u.External.pvUser);
5645 break;
5646 default:
[39402]5647 rc = VERR_SSM_IPE_1;
[22792]5648 break;
[22554]5649 }
[44505]5650 ssmR3UnitCritSectLeave(pUnit);
[22792]5651 pUnit->fCalled = true;
[23436]5652 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
5653 pSSM->rc = rc;
5654 else
[22792]5655 rc = pSSM->rc;
[22554]5656 if (RT_FAILURE(rc))
5657 {
[22792]5658 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
5659 return rc;
[22554]5660 }
5661 }
5662
[22792]5663 pSSM->cbEstTotal += pUnit->cbGuess;
5664 }
5665
5666 /*
5667 * Work the progress indicator if we got one.
5668 */
5669 if (pSSM->pfnProgress)
[44393]5670 pSSM->pfnProgress(pVM->pUVM, 2, pSSM->pvUser);
[22792]5671 pSSM->uPercent = 2;
5672
5673 return VINF_SUCCESS;
5674}
5675
5676
5677/**
[23905]5678 * Continue a live state saving operation on the worker thread.
5679 *
[58170]5680 * @returns VBox status code.
[23905]5681 *
5682 * @param pSSM The SSM handle returned by SSMR3LiveSave.
5683 *
5684 * @thread Non-EMT thread. Will involve the EMT at the end of the operation.
5685 */
5686VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM)
5687{
5688 LogFlow(("SSMR3LiveDoStep1: pSSM=%p\n", pSSM));
5689
5690 /*
5691 * Validate input.
5692 */
5693 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
5694 PVM pVM = pSSM->pVM;
5695 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
5696 VM_ASSERT_OTHER_THREAD(pVM);
5697 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
5698 || pSSM->enmAfter == SSMAFTER_CONTINUE
5699 || pSSM->enmAfter == SSMAFTER_TELEPORT,
5700 ("%d\n", pSSM->enmAfter),
5701 VERR_INVALID_PARAMETER);
5702 AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_STEP1, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
5703 AssertRCReturn(pSSM->rc, pSSM->rc);
5704
5705 /*
5706 * Do the prep run, then the exec+vote cycle.
5707 */
5708 int rc = ssmR3DoLivePrepRun(pVM, pSSM);
5709 if (RT_SUCCESS(rc))
5710 rc = ssmR3DoLiveExecVoteLoop(pVM, pSSM);
5711 return rc;
5712}
5713
5714
5715/**
[23595]5716 * Start saving the live state.
[22792]5717 *
[22807]5718 * Call SSMR3LiveDoStep1, SSMR3LiveDoStep2 and finally SSMR3LiveDone on success.
[22792]5719 * SSMR3LiveDone should be called even if SSMR3LiveDoStep1 or SSMR3LiveDoStep2
5720 * fails.
5721 *
[58170]5722 * @returns VBox status code.
[22792]5723 *
[58122]5724 * @param pVM The cross context VM structure.
[24874]5725 * @param cMsMaxDowntime The maximum downtime given as milliseconds.
[23596]5726 * @param pszFilename Name of the file to save the state in. This string
[22792]5727 * must remain valid until SSMR3LiveDone is called.
[23596]5728 * Must be NULL if pStreamOps is used.
5729 * @param pStreamOps The stream method table. NULL if pszFilename is
5730 * used.
5731 * @param pvStreamOpsUser The user argument to the stream methods.
[22792]5732 * @param enmAfter What is planned after a successful save operation.
5733 * @param pfnProgress Progress callback. Optional.
[23596]5734 * @param pvProgressUser User argument for the progress callback.
[58126]5735 * @param ppSSM Where to return the saved state handle on success.
[22792]5736 *
5737 * @thread EMT0
5738 */
[24874]5739VMMR3_INT_DECL(int) SSMR3LiveSave(PVM pVM, uint32_t cMsMaxDowntime,
5740 const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
5741 SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser,
5742 PSSMHANDLE *ppSSM)
[22792]5743{
[24874]5744 LogFlow(("SSMR3LiveSave: cMsMaxDowntime=%u pszFilename=%p:{%s} pStreamOps=%p pvStreamOpsUser=%p enmAfter=%d pfnProgress=%p pvProgressUser=%p\n",
5745 cMsMaxDowntime, pszFilename, pszFilename, pStreamOps, pvStreamOpsUser, enmAfter, pfnProgress, pvProgressUser));
[22792]5746 VM_ASSERT_EMT0(pVM);
5747
5748 /*
5749 * Validate input.
5750 */
5751 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY
[23668]5752 || enmAfter == SSMAFTER_CONTINUE
[23801]5753 || enmAfter == SSMAFTER_TELEPORT,
[22792]5754 ("%d\n", enmAfter),
5755 VERR_INVALID_PARAMETER);
[23595]5756 AssertReturn(!pszFilename != !pStreamOps, VERR_INVALID_PARAMETER);
5757 if (pStreamOps)
5758 {
5759 AssertReturn(pStreamOps->u32Version == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
5760 AssertReturn(pStreamOps->u32EndVersion == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
5761 AssertReturn(pStreamOps->pfnWrite, VERR_INVALID_PARAMETER);
5762 AssertReturn(pStreamOps->pfnRead, VERR_INVALID_PARAMETER);
5763 AssertReturn(pStreamOps->pfnSeek, VERR_INVALID_PARAMETER);
5764 AssertReturn(pStreamOps->pfnTell, VERR_INVALID_PARAMETER);
5765 AssertReturn(pStreamOps->pfnSize, VERR_INVALID_PARAMETER);
5766 AssertReturn(pStreamOps->pfnClose, VERR_INVALID_PARAMETER);
5767 }
[22792]5768
5769 /*
5770 * Create the saved state file and handle.
5771 *
5772 * Note that there might be quite some work to do after executing the saving,
5773 * so we reserve 20% for the 'Done' period.
5774 */
5775 PSSMHANDLE pSSM;
[23595]5776 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, pStreamOps, pvStreamOpsUser,
5777 enmAfter, pfnProgress, pvProgressUser, &pSSM);
[22792]5778 if (RT_FAILURE(rc))
5779 return rc;
[30396]5780 pSSM->uPercentLive = 93;
5781 pSSM->uPercentPrepare = 2;
[24874]5782 pSSM->uPercentDone = 2;
5783 pSSM->fLiveSave = true;
5784 pSSM->u.Write.cMsMaxDowntime = cMsMaxDowntime;
[22792]5785
5786 /*
5787 * Write the saved state stream header and do the prep run for live saving.
5788 */
5789 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
5790 ssmR3StrmStartIoThread(&pSSM->Strm);
5791 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
5792 if (RT_SUCCESS(rc))
5793 {
[23905]5794 /*
[33540]5795 * Return and let the requestor thread do the pfnLiveExec/Vote part
[23905]5796 * via SSMR3SaveFinishLive
5797 */
5798 pSSM->enmOp = SSMSTATE_LIVE_STEP1;
5799 ssmR3SetCancellable(pVM, pSSM, true);
5800 *ppSSM = pSSM;
5801 return VINF_SUCCESS;
[22554]5802 }
[22792]5803 /* bail out. */
[24917]5804 int rc2 = ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED);
[22792]5805 RTMemFree(pSSM);
5806 rc2 = RTFileDelete(pszFilename);
[22554]5807 AssertRC(rc2);
5808 return rc;
5809}
5810
[24574]5811#endif /* !SSM_STANDALONE */
[22554]5812
[22792]5813
[22554]5814/* ... Loading and reading starts here ... */
5815/* ... Loading and reading starts here ... */
5816/* ... Loading and reading starts here ... */
5817/* ... Loading and reading starts here ... */
5818/* ... Loading and reading starts here ... */
5819/* ... Loading and reading starts here ... */
5820/* ... Loading and reading starts here ... */
5821/* ... Loading and reading starts here ... */
5822/* ... Loading and reading starts here ... */
5823/* ... Loading and reading starts here ... */
5824/* ... Loading and reading starts here ... */
5825/* ... Loading and reading starts here ... */
5826/* ... Loading and reading starts here ... */
5827/* ... Loading and reading starts here ... */
5828/* ... Loading and reading starts here ... */
5829/* ... Loading and reading starts here ... */
5830/* ... Loading and reading starts here ... */
5831
5832
[39078]5833#ifndef SSM_STANDALONE
[22554]5834/**
[1]5835 * Closes the decompressor of a data unit.
5836 *
[23436]5837 * @returns pSSM->rc.
[23764]5838 * @param pSSM The saved state handle.
[1]5839 */
[23436]5840static int ssmR3DataReadFinishV1(PSSMHANDLE pSSM)
[1]5841{
[21856]5842 if (pSSM->u.Read.pZipDecompV1)
[21797]5843 {
[21856]5844 int rc = RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
[21797]5845 AssertRC(rc);
[21856]5846 pSSM->u.Read.pZipDecompV1 = NULL;
[21797]5847 }
[23436]5848 return pSSM->rc;
[1]5849}
[39078]5850#endif /* !SSM_STANDALONE */
[1]5851
[13594]5852
[1]5853/**
[21797]5854 * Callback for reading compressed data into the input buffer of the
5855 * decompressor, for saved file format version 1.
[1]5856 *
[24917]5857 * @returns VBox status code. Set pSSM->rc on error.
[21797]5858 * @param pvSSM The SSM handle.
5859 * @param pvBuf Where to store the compressed data.
5860 * @param cbBuf Size of the buffer.
5861 * @param pcbRead Number of bytes actually stored in the buffer.
5862 */
5863static DECLCALLBACK(int) ssmR3ReadInV1(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
5864{
5865 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
5866 size_t cbRead = cbBuf;
5867 if (pSSM->cbUnitLeftV1 < cbBuf)
5868 cbRead = (size_t)pSSM->cbUnitLeftV1;
5869 if (cbRead)
5870 {
[21894]5871 //Log2(("ssmR3ReadInV1: %#010llx cbBug=%#x cbRead=%#x\n", ssmR3StrmTell(&pSSM->Strm), cbBuf, cbRead));
[21866]5872 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbRead);
[21797]5873 if (RT_SUCCESS(rc))
5874 {
5875 pSSM->cbUnitLeftV1 -= cbRead;
5876 if (pcbRead)
5877 *pcbRead = cbRead;
[30396]5878 ssmR3ProgressByByte(pSSM, cbRead);
[21797]5879 return VINF_SUCCESS;
5880 }
[24917]5881 return pSSM->rc = rc;
[21797]5882 }
5883
5884 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
5885 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
[24917]5886 return pSSM->rc = VERR_SSM_LOADED_TOO_MUCH;
[21797]5887}
5888
5889
5890/**
5891 * Internal read worker for reading data from a version 1 unit.
5892 *
[24917]5893 * @returns VBox status code, pSSM->rc is set on error.
5894 *
[23764]5895 * @param pSSM The saved state handle.
[1]5896 * @param pvBuf Where to store the read data.
5897 * @param cbBuf Number of bytes to read.
5898 */
[21797]5899static int ssmR3DataReadV1(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
[1]5900{
5901 /*
[21797]5902 * Open the decompressor on the first read.
[1]5903 */
[21856]5904 if (!pSSM->u.Read.pZipDecompV1)
[1]5905 {
[21856]5906 pSSM->rc = RTZipDecompCreate(&pSSM->u.Read.pZipDecompV1, pSSM, ssmR3ReadInV1);
[21797]5907 if (RT_FAILURE(pSSM->rc))
5908 return pSSM->rc;
5909 }
5910
5911 /*
5912 * Do the requested read.
5913 */
[21856]5914 int rc = pSSM->rc = RTZipDecompress(pSSM->u.Read.pZipDecompV1, pvBuf, cbBuf, NULL);
[21797]5915 if (RT_SUCCESS(rc))
5916 {
5917 Log2(("ssmR3DataRead: pvBuf=%p cbBuf=%#x offUnit=%#llx %.*Rhxs%s\n", pvBuf, cbBuf, pSSM->offUnit, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
[42335]5918 pSSM->offUnit += cbBuf;
5919 pSSM->offUnitUser += cbBuf;
[21797]5920 return VINF_SUCCESS;
5921 }
5922 AssertMsgFailed(("rc=%Rrc cbBuf=%#x\n", rc, cbBuf));
5923 return rc;
5924}
5925
5926
5927/**
5928 * Creates the decompressor for the data unit.
5929 *
5930 * pSSM->rc will be set on error.
5931 *
[23764]5932 * @param pSSM The saved state handle.
[21797]5933 */
5934static void ssmR3DataReadBeginV2(PSSMHANDLE pSSM)
5935{
5936 Assert(!pSSM->u.Read.cbDataBuffer || pSSM->u.Read.cbDataBuffer == pSSM->u.Read.offDataBuffer);
5937 Assert(!pSSM->u.Read.cbRecLeft);
5938
[42335]5939 pSSM->offUnit = 0;
5940 pSSM->offUnitUser = 0;
[21797]5941 pSSM->u.Read.cbRecLeft = 0;
5942 pSSM->u.Read.cbDataBuffer = 0;
5943 pSSM->u.Read.offDataBuffer = 0;
5944 pSSM->u.Read.fEndOfData = false;
5945 pSSM->u.Read.u8TypeAndFlags = 0;
5946}
5947
5948
[39078]5949#ifndef SSM_STANDALONE
[21797]5950/**
5951 * Checks for the termination record and closes the decompressor.
5952 *
5953 * pSSM->rc will be set on error.
5954 *
[23436]5955 * @returns pSSM->rc.
[23764]5956 * @param pSSM The saved state handle.
[21797]5957 */
[23436]5958static int ssmR3DataReadFinishV2(PSSMHANDLE pSSM)
[21797]5959{
5960 /*
5961 * If we haven't encountered the end of the record, it must be the next one.
5962 */
[23436]5963 int rc = pSSM->rc;
[21797]5964 if ( !pSSM->u.Read.fEndOfData
[23436]5965 && RT_SUCCESS(rc))
[21797]5966 {
[39368]5967 if ( pSSM->u.Read.cbDataBuffer != pSSM->u.Read.offDataBuffer
5968 && pSSM->u.Read.cbDataBuffer > 0)
[42335]5969 {
5970 LogRel(("SSM: At least %#x bytes left to read\n", pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer));
[39368]5971 rc = VERR_SSM_LOADED_TOO_LITTLE;
[42335]5972 }
[39368]5973 else
[21927]5974 {
[39368]5975 rc = ssmR3DataReadRecHdrV2(pSSM);
5976 if ( RT_SUCCESS(rc)
5977 && !pSSM->u.Read.fEndOfData)
5978 {
[42335]5979 LogRel(("SSM: At least %#x bytes left to read\n", pSSM->u.Read.cbDataBuffer));
[39368]5980 rc = VERR_SSM_LOADED_TOO_LITTLE;
5981 AssertFailed();
5982 }
[21927]5983 }
[21797]5984 pSSM->rc = rc;
5985 }
[23436]5986 return rc;
[21797]5987}
[39078]5988#endif /* !SSM_STANDALONE */
[21797]5989
5990
5991/**
[42335]5992 * Read raw record bytes, work the progress indicator and unit offset.
[21797]5993 *
[24917]5994 * @returns VBox status code. Does NOT set pSSM->rc.
[21797]5995 * @param pSSM The saved state handle.
5996 * @param pvBuf Where to put the bits
[58126]5997 * @param cbToRead How many bytes to read.
[21797]5998 */
5999DECLINLINE(int) ssmR3DataReadV2Raw(PSSMHANDLE pSSM, void *pvBuf, size_t cbToRead)
6000{
[21866]6001 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbToRead);
[21856]6002 if (RT_SUCCESS(rc))
6003 {
6004 pSSM->offUnit += cbToRead;
[30396]6005 ssmR3ProgressByByte(pSSM, cbToRead);
[21856]6006 return VINF_SUCCESS;
6007 }
6008
[24917]6009 if (rc == VERR_SSM_CANCELLED)
6010 return rc;
6011
[29954]6012 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT && rc == VERR_EOF)
6013 AssertMsgFailedReturn(("SSM: attempted reading more than the unit! rc=%Rrc\n", rc), VERR_SSM_LOADED_TOO_MUCH);
6014 return VERR_SSM_STREAM_ERROR;
[21856]6015}
6016
6017
6018/**
6019 * Reads and checks the LZF "header".
6020 *
[24917]6021 * @returns VBox status code. Sets pSSM->rc on error.
[21856]6022 * @param pSSM The saved state handle..
6023 * @param pcbDecompr Where to store the size of the decompressed data.
6024 */
[21871]6025DECLINLINE(int) ssmR3DataReadV2RawLzfHdr(PSSMHANDLE pSSM, uint32_t *pcbDecompr)
[21856]6026{
6027 *pcbDecompr = 0; /* shuts up gcc. */
6028 AssertLogRelMsgReturn( pSSM->u.Read.cbRecLeft > 1
6029 && pSSM->u.Read.cbRecLeft <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abComprBuffer) + 2,
6030 ("%#x\n", pSSM->u.Read.cbRecLeft),
[49800]6031 pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION);
[21856]6032
[21862]6033 uint8_t cKB;
6034 int rc = ssmR3DataReadV2Raw(pSSM, &cKB, 1);
[21797]6035 if (RT_FAILURE(rc))
[24917]6036 return pSSM->rc = rc;
[21862]6037 pSSM->u.Read.cbRecLeft -= sizeof(cKB);
[21856]6038
[21871]6039 uint32_t cbDecompr = (uint32_t)cKB * _1K;
[21856]6040 AssertLogRelMsgReturn( cbDecompr >= pSSM->u.Read.cbRecLeft
6041 && cbDecompr <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer),
6042 ("%#x\n", cbDecompr),
[49800]6043 pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION);
[21856]6044
6045 *pcbDecompr = cbDecompr;
[21797]6046 return VINF_SUCCESS;
6047}
6048
6049
6050/**
[21856]6051 * Reads an LZF block from the stream and decompresses into the specified
6052 * buffer.
6053 *
[24917]6054 * @returns VBox status code. Sets pSSM->rc on error.
[58126]6055 * @param pSSM The saved state handle.
[21856]6056 * @param pvDst Pointer to the output buffer.
6057 * @param cbDecompr The size of the decompressed data.
6058 */
6059static int ssmR3DataReadV2RawLzf(PSSMHANDLE pSSM, void *pvDst, size_t cbDecompr)
6060{
[21897]6061 int rc;
6062 uint32_t cbCompr = pSSM->u.Read.cbRecLeft;
[21856]6063 pSSM->u.Read.cbRecLeft = 0;
6064
[21897]6065 /*
6066 * Try use the stream buffer directly to avoid copying things around.
6067 */
6068 uint8_t const *pb = ssmR3StrmReadDirect(&pSSM->Strm, cbCompr);
6069 if (pb)
6070 {
6071 pSSM->offUnit += cbCompr;
[30396]6072 ssmR3ProgressByByte(pSSM, cbCompr);
[21897]6073 }
6074 else
6075 {
6076 rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abComprBuffer[0], cbCompr);
6077 if (RT_FAILURE(rc))
[24917]6078 return pSSM->rc = rc;
[21897]6079 pb = &pSSM->u.Read.abComprBuffer[0];
6080 }
6081
6082 /*
6083 * Decompress it.
6084 */
6085 size_t cbDstActual;
6086 rc = RTZipBlockDecompress(RTZIPTYPE_LZF, 0 /*fFlags*/,
6087 pb, cbCompr, NULL /*pcbSrcActual*/,
6088 pvDst, cbDecompr, &cbDstActual);
[21856]6089 if (RT_SUCCESS(rc))
6090 {
[49800]6091 AssertLogRelMsgReturn(cbDstActual == cbDecompr, ("%#x %#x\n", cbDstActual, cbDecompr), pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION);
[21897]6092 return VINF_SUCCESS;
[21856]6093 }
[21927]6094
6095 AssertLogRelMsgFailed(("cbCompr=%#x cbDecompr=%#x rc=%Rrc\n", cbCompr, cbDecompr, rc));
[24917]6096 return pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION;
[21856]6097}
6098
6099
6100/**
[22025]6101 * Reads and checks the raw zero "header".
6102 *
[24917]6103 * @returns VBox status code. Sets pSSM->rc on error.
[22025]6104 * @param pSSM The saved state handle..
[58126]6105 * @param pcbZero Where to store the size of the zero data.
[22025]6106 */
6107DECLINLINE(int) ssmR3DataReadV2RawZeroHdr(PSSMHANDLE pSSM, uint32_t *pcbZero)
6108{
6109 *pcbZero = 0; /* shuts up gcc. */
[49800]6110 AssertLogRelMsgReturn(pSSM->u.Read.cbRecLeft == 1, ("%#x\n", pSSM->u.Read.cbRecLeft), pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION);
[22025]6111
6112 uint8_t cKB;
6113 int rc = ssmR3DataReadV2Raw(pSSM, &cKB, 1);
6114 if (RT_FAILURE(rc))
[24917]6115 return pSSM->rc = rc;
[22025]6116 pSSM->u.Read.cbRecLeft = 0;
6117
6118 uint32_t cbZero = (uint32_t)cKB * _1K;
6119 AssertLogRelMsgReturn(cbZero <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer),
[49800]6120 ("%#x\n", cbZero), pSSM->rc = VERR_SSM_INTEGRITY_DECOMPRESSION);
[22025]6121
6122 *pcbZero = cbZero;
6123 return VINF_SUCCESS;
6124}
6125
6126
6127/**
[21797]6128 * Worker for reading the record header.
6129 *
6130 * It sets pSSM->u.Read.cbRecLeft, pSSM->u.Read.u8TypeAndFlags and
6131 * pSSM->u.Read.fEndOfData. When a termination record is encounter, it will be
6132 * read in full and validated, the fEndOfData indicator is set, and VINF_SUCCESS
6133 * is returned.
6134 *
[24917]6135 * @returns VBox status code. Does not set pSSM->rc.
[21797]6136 * @param pSSM The saved state handle.
6137 */
6138static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM)
6139{
6140 AssertLogRelReturn(!pSSM->u.Read.fEndOfData, VERR_SSM_LOADED_TOO_MUCH);
6141
6142 /*
6143 * Read the two mandatory bytes.
6144 */
6145 uint8_t abHdr[8];
6146 int rc = ssmR3DataReadV2Raw(pSSM, abHdr, 2);
6147 if (RT_FAILURE(rc))
6148 return rc;
6149
6150 /*
6151 * Validate the first byte and check for the termination records.
6152 */
6153 pSSM->u.Read.u8TypeAndFlags = abHdr[0];
[21927]6154 AssertLogRelMsgReturn(SSM_REC_ARE_TYPE_AND_FLAGS_VALID(abHdr[0]), ("%#x %#x\n", abHdr[0], abHdr[1]), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6155 if ((abHdr[0] & SSM_REC_TYPE_MASK) == SSM_REC_TYPE_TERM)
6156 {
6157 pSSM->u.Read.cbRecLeft = 0;
6158 pSSM->u.Read.fEndOfData = true;
[21927]6159 AssertLogRelMsgReturn(abHdr[1] == sizeof(SSMRECTERM) - 2, ("%#x\n", abHdr[1]), VERR_SSM_INTEGRITY_REC_TERM);
6160 AssertLogRelMsgReturn(abHdr[0] & SSM_REC_FLAGS_IMPORTANT, ("%#x\n", abHdr[0]), VERR_SSM_INTEGRITY_REC_TERM);
[21797]6161
6162 /* get the rest */
[21895]6163 uint32_t u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
6164 SSMRECTERM TermRec;
[25235]6165 rc = ssmR3DataReadV2Raw(pSSM, (uint8_t *)&TermRec + 2, sizeof(SSMRECTERM) - 2);
[21797]6166 if (RT_FAILURE(rc))
6167 return rc;
6168
6169 /* validate integrity */
6170 AssertLogRelMsgReturn(TermRec.cbUnit == pSSM->offUnit,
6171 ("cbUnit=%#llx offUnit=%#llx\n", TermRec.cbUnit, pSSM->offUnit),
[21927]6172 VERR_SSM_INTEGRITY_REC_TERM);
6173 AssertLogRelMsgReturn(!(TermRec.fFlags & ~SSMRECTERM_FLAGS_CRC32), ("%#x\n", TermRec.fFlags), VERR_SSM_INTEGRITY_REC_TERM);
[21797]6174 if (!(TermRec.fFlags & SSMRECTERM_FLAGS_CRC32))
[21927]6175 AssertLogRelMsgReturn(TermRec.u32StreamCRC == 0, ("%#x\n", TermRec.u32StreamCRC), VERR_SSM_INTEGRITY_REC_TERM);
[21866]6176 else if (pSSM->Strm.fChecksummed)
[21927]6177 AssertLogRelMsgReturn(TermRec.u32StreamCRC == u32StreamCRC, ("%#x, %#x\n", TermRec.u32StreamCRC, u32StreamCRC),
6178 VERR_SSM_INTEGRITY_REC_TERM_CRC);
[21797]6179
[21866]6180 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx: TERM\n", ssmR3StrmTell(&pSSM->Strm) - sizeof(SSMRECTERM), pSSM->offUnit));
[21797]6181 return VINF_SUCCESS;
6182 }
6183
6184 /*
6185 * Figure the size. The 2nd byte is encoded in UTF-8 fashion, so this
6186 * is can be highly enjoyable.
6187 */
6188 uint32_t cbHdr = 2;
6189 uint32_t cb = abHdr[1];
6190 if (!(cb & 0x80))
6191 pSSM->u.Read.cbRecLeft = cb;
6192 else
6193 {
[1]6194 /*
[21797]6195 * Need more data. Figure how much and read it.
[1]6196 */
[21797]6197 if (!(cb & RT_BIT(5)))
6198 cb = 2;
6199 else if (!(cb & RT_BIT(4)))
6200 cb = 3;
6201 else if (!(cb & RT_BIT(3)))
6202 cb = 4;
6203 else if (!(cb & RT_BIT(2)))
6204 cb = 5;
6205 else if (!(cb & RT_BIT(1)))
6206 cb = 6;
6207 else
[21927]6208 AssertLogRelMsgFailedReturn(("Invalid record size byte: %#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6209 cbHdr = cb + 1;
6210
6211 rc = ssmR3DataReadV2Raw(pSSM, &abHdr[2], cb - 1);
6212 if (RT_FAILURE(rc))
6213 return rc;
6214
6215 /*
6216 * Validate what we've read.
6217 */
6218 switch (cb)
[1]6219 {
[21797]6220 case 6:
[21927]6221 AssertLogRelMsgReturn((abHdr[6] & 0xc0) == 0x80, ("6/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
[69046]6222 RT_FALL_THRU();
[21797]6223 case 5:
[21927]6224 AssertLogRelMsgReturn((abHdr[5] & 0xc0) == 0x80, ("5/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
[69046]6225 RT_FALL_THRU();
[21797]6226 case 4:
[21927]6227 AssertLogRelMsgReturn((abHdr[4] & 0xc0) == 0x80, ("4/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
[69046]6228 RT_FALL_THRU();
[21797]6229 case 3:
[21927]6230 AssertLogRelMsgReturn((abHdr[3] & 0xc0) == 0x80, ("3/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
[69046]6231 RT_FALL_THRU();
[21797]6232 case 2:
[21927]6233 AssertLogRelMsgReturn((abHdr[2] & 0xc0) == 0x80, ("2/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6234 break;
6235 default:
[39402]6236 return VERR_IPE_NOT_REACHED_DEFAULT_CASE;
[1]6237 }
6238
6239 /*
[21797]6240 * Decode it and validate the range.
[1]6241 */
[21797]6242 switch (cb)
[18045]6243 {
[21797]6244 case 6:
6245 cb = (abHdr[6] & 0x3f)
6246 | ((uint32_t)(abHdr[5] & 0x3f) << 6)
6247 | ((uint32_t)(abHdr[4] & 0x3f) << 12)
6248 | ((uint32_t)(abHdr[3] & 0x3f) << 18)
6249 | ((uint32_t)(abHdr[2] & 0x3f) << 24)
6250 | ((uint32_t)(abHdr[1] & 0x01) << 30);
[21927]6251 AssertLogRelMsgReturn(cb >= 0x04000000 && cb <= 0x7fffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6252 break;
6253 case 5:
6254 cb = (abHdr[5] & 0x3f)
6255 | ((uint32_t)(abHdr[4] & 0x3f) << 6)
6256 | ((uint32_t)(abHdr[3] & 0x3f) << 12)
6257 | ((uint32_t)(abHdr[2] & 0x3f) << 18)
6258 | ((uint32_t)(abHdr[1] & 0x03) << 24);
[21927]6259 AssertLogRelMsgReturn(cb >= 0x00200000 && cb <= 0x03ffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6260 break;
6261 case 4:
6262 cb = (abHdr[4] & 0x3f)
6263 | ((uint32_t)(abHdr[3] & 0x3f) << 6)
6264 | ((uint32_t)(abHdr[2] & 0x3f) << 12)
6265 | ((uint32_t)(abHdr[1] & 0x07) << 18);
[21927]6266 AssertLogRelMsgReturn(cb >= 0x00010000 && cb <= 0x001fffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21797]6267 break;
6268 case 3:
6269 cb = (abHdr[3] & 0x3f)
6270 | ((uint32_t)(abHdr[2] & 0x3f) << 6)
6271 | ((uint32_t)(abHdr[1] & 0x0f) << 12);
[21862]6272#if 0 /* disabled to optimize buffering */
[21927]6273 AssertLogRelMsgReturn(cb >= 0x00000800 && cb <= 0x0000ffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21862]6274#endif
[21797]6275 break;
6276 case 2:
6277 cb = (abHdr[2] & 0x3f)
6278 | ((uint32_t)(abHdr[1] & 0x1f) << 6);
[21862]6279#if 0 /* disabled to optimize buffering */
[21927]6280 AssertLogRelMsgReturn(cb >= 0x00000080 && cb <= 0x000007ff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
[21862]6281#endif
[21797]6282 break;
6283 default:
[39402]6284 return VERR_IPE_NOT_REACHED_DEFAULT_CASE;
[18045]6285 }
[21797]6286
6287 pSSM->u.Read.cbRecLeft = cb;
[1]6288 }
6289
[21856]6290 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
[21866]6291 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft,
[21797]6292 pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK,
6293 !!(pSSM->u.Read.u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT),
6294 cbHdr
6295 )); NOREF(cbHdr);
6296 return VINF_SUCCESS;
[1]6297}
6298
[13594]6299
[1]6300/**
[21797]6301 * Buffer miss, do an unbuffered read.
[1]6302 *
[49800]6303 * @returns VBox status code. Sets pSSM->rc on error.
[23764]6304 * @param pSSM The saved state handle.
[21797]6305 * @param pvBuf Where to store the read data.
6306 * @param cbBuf Number of bytes to read.
[1]6307 */
[21797]6308static int ssmR3DataReadUnbufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
[1]6309{
[21797]6310 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
6311 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
6312
6313 /*
6314 * Copy out what we've got in the buffer.
6315 */
6316 uint32_t off = pSSM->u.Read.offDataBuffer;
6317 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
[21866]6318 Log4(("ssmR3DataReadUnbufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
[21797]6319 if (cbInBuffer > 0)
[1]6320 {
[21797]6321 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
6322 Assert(cbBuf > cbToCopy);
6323 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
[21871]6324 pvBuf = (uint8_t *)pvBuf + cbToCopy;
[21797]6325 cbBuf -= cbToCopy;
[21871]6326 pSSM->u.Read.cbDataBuffer = 0;
[21797]6327 pSSM->u.Read.offDataBuffer = 0;
6328 }
6329
6330 /*
6331 * Read data.
6332 */
6333 do
6334 {
6335 /*
6336 * Read the next record header if no more data.
6337 */
6338 if (!pSSM->u.Read.cbRecLeft)
[1]6339 {
[21797]6340 int rc = ssmR3DataReadRecHdrV2(pSSM);
6341 if (RT_FAILURE(rc))
6342 return pSSM->rc = rc;
[1]6343 }
[56956]6344 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu\n", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
[21797]6345
6346 /*
6347 * Read data from the current record.
6348 */
[21871]6349 uint32_t cbToRead;
[21856]6350 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
6351 {
6352 case SSM_REC_TYPE_RAW:
6353 {
[21871]6354 cbToRead = (uint32_t)RT_MIN(cbBuf, pSSM->u.Read.cbRecLeft);
[21856]6355 int rc = ssmR3DataReadV2Raw(pSSM, pvBuf, cbToRead);
6356 if (RT_FAILURE(rc))
6357 return pSSM->rc = rc;
6358 pSSM->u.Read.cbRecLeft -= cbToRead;
6359 break;
6360 }
6361
6362 case SSM_REC_TYPE_RAW_LZF:
6363 {
[22025]6364 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbToRead);
[21856]6365 if (RT_FAILURE(rc))
6366 return rc;
[22025]6367 if (cbToRead <= cbBuf)
[21856]6368 {
[22025]6369 rc = ssmR3DataReadV2RawLzf(pSSM, pvBuf, cbToRead);
[21856]6370 if (RT_FAILURE(rc))
6371 return rc;
6372 }
6373 else
6374 {
[22025]6375 /* The output buffer is too small, use the data buffer. */
6376 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
[21856]6377 if (RT_FAILURE(rc))
6378 return rc;
[22025]6379 pSSM->u.Read.cbDataBuffer = cbToRead;
[21871]6380 cbToRead = (uint32_t)cbBuf;
[22025]6381 pSSM->u.Read.offDataBuffer = cbToRead;
[21871]6382 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToRead);
[21856]6383 }
6384 break;
6385 }
6386
[22025]6387 case SSM_REC_TYPE_RAW_ZERO:
6388 {
6389 int rc = ssmR3DataReadV2RawZeroHdr(pSSM, &cbToRead);
6390 if (RT_FAILURE(rc))
6391 return rc;
6392 if (cbToRead > cbBuf)
6393 {
[33540]6394 /* Spill the remainder into the data buffer. */
[22025]6395 memset(&pSSM->u.Read.abDataBuffer[0], 0, cbToRead - cbBuf);
[26526]6396 pSSM->u.Read.cbDataBuffer = cbToRead - (uint32_t)cbBuf;
[22025]6397 pSSM->u.Read.offDataBuffer = 0;
6398 cbToRead = (uint32_t)cbBuf;
6399 }
6400 memset(pvBuf, 0, cbToRead);
6401 break;
6402 }
6403
[21856]6404 default:
[49800]6405 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), pSSM->rc = VERR_SSM_BAD_REC_TYPE);
[21856]6406 }
6407
[42335]6408 pSSM->offUnitUser += cbToRead;
[21797]6409 cbBuf -= cbToRead;
6410 pvBuf = (uint8_t *)pvBuf + cbToRead;
6411 } while (cbBuf > 0);
6412
[21856]6413 Log4(("ssmR3DataReadUnBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
[21866]6414 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, 0, cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
[21797]6415 return VINF_SUCCESS;
6416}
6417
6418
6419/**
6420 * Buffer miss, do a buffered read.
6421 *
[24917]6422 * @returns VBox status code. Sets pSSM->rc on error.
6423 *
[23764]6424 * @param pSSM The saved state handle.
[21797]6425 * @param pvBuf Where to store the read data.
6426 * @param cbBuf Number of bytes to read.
6427 */
6428static int ssmR3DataReadBufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
6429{
6430 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
6431 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
6432
6433 /*
6434 * Copy out what we've got in the buffer.
6435 */
6436 uint32_t off = pSSM->u.Read.offDataBuffer;
6437 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
[21866]6438 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
[21797]6439 if (cbInBuffer > 0)
6440 {
6441 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
6442 Assert(cbBuf > cbToCopy);
6443 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
[21871]6444 pvBuf = (uint8_t *)pvBuf + cbToCopy;
[21797]6445 cbBuf -= cbToCopy;
[42335]6446 pSSM->offUnitUser += cbToCopy;
[21871]6447 pSSM->u.Read.cbDataBuffer = 0;
[21797]6448 pSSM->u.Read.offDataBuffer = 0;
[1]6449 }
6450
[21797]6451 /*
6452 * Buffer more data.
6453 */
6454 do
6455 {
6456 /*
6457 * Read the next record header if no more data.
6458 */
6459 if (!pSSM->u.Read.cbRecLeft)
6460 {
6461 int rc = ssmR3DataReadRecHdrV2(pSSM);
6462 if (RT_FAILURE(rc))
6463 return pSSM->rc = rc;
6464 }
[56956]6465 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu\n", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
[21797]6466
6467 /*
6468 * Read data from the current record.
6469 * LATER: optimize by reading directly into the output buffer for some cases.
6470 */
[21871]6471 uint32_t cbToRead;
[21856]6472 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
6473 {
6474 case SSM_REC_TYPE_RAW:
6475 {
6476 cbToRead = RT_MIN(sizeof(pSSM->u.Read.abDataBuffer), pSSM->u.Read.cbRecLeft);
6477 int rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
6478 if (RT_FAILURE(rc))
6479 return pSSM->rc = rc;
[21871]6480 pSSM->u.Read.cbRecLeft -= cbToRead;
[21856]6481 pSSM->u.Read.cbDataBuffer = cbToRead;
6482 break;
6483 }
6484
6485 case SSM_REC_TYPE_RAW_LZF:
6486 {
[22025]6487 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbToRead);
[21856]6488 if (RT_FAILURE(rc))
6489 return rc;
6490 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
6491 if (RT_FAILURE(rc))
6492 return rc;
6493 pSSM->u.Read.cbDataBuffer = cbToRead;
6494 break;
6495 }
6496
[22025]6497 case SSM_REC_TYPE_RAW_ZERO:
6498 {
6499 int rc = ssmR3DataReadV2RawZeroHdr(pSSM, &cbToRead);
6500 if (RT_FAILURE(rc))
6501 return rc;
6502 memset(&pSSM->u.Read.abDataBuffer[0], 0, cbToRead);
6503 pSSM->u.Read.cbDataBuffer = cbToRead;
6504 break;
6505 }
6506
[21856]6507 default:
[49800]6508 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), pSSM->rc = VERR_SSM_BAD_REC_TYPE);
[21856]6509 }
[21797]6510 /*pSSM->u.Read.offDataBuffer = 0;*/
6511
6512 /*
6513 * Copy data from the buffer.
6514 */
[21871]6515 uint32_t cbToCopy = (uint32_t)RT_MIN(cbBuf, cbToRead);
[21797]6516 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToCopy);
6517 cbBuf -= cbToCopy;
6518 pvBuf = (uint8_t *)pvBuf + cbToCopy;
[42335]6519 pSSM->offUnitUser += cbToCopy;
[21797]6520 pSSM->u.Read.offDataBuffer = cbToCopy;
6521 } while (cbBuf > 0);
6522
[21856]6523 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
[21866]6524 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
[21797]6525 cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
6526 return VINF_SUCCESS;
[1]6527}
6528
6529
6530/**
[21797]6531 * Inlined worker that handles format checks and buffered reads.
6532 *
[23764]6533 * @param pSSM The saved state handle.
[21797]6534 * @param pvBuf Where to store the read data.
6535 * @param cbBuf Number of bytes to read.
6536 */
6537DECLINLINE(int) ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
6538{
6539 /*
6540 * Fend off previous errors and V1 data units.
6541 */
[56965]6542 if (RT_SUCCESS(pSSM->rc))
[21797]6543 {
[56965]6544 if (RT_LIKELY(pSSM->u.Read.uFmtVerMajor != 1))
6545 {
6546 /*
6547 * Check if the requested data is buffered.
6548 */
6549 uint32_t off = pSSM->u.Read.offDataBuffer;
6550 if ( off + cbBuf > pSSM->u.Read.cbDataBuffer
6551 || cbBuf > sizeof(pSSM->u.Read.abDataBuffer))
6552 {
6553 if (cbBuf <= sizeof(pSSM->u.Read.abDataBuffer) / 8)
6554 return ssmR3DataReadBufferedV2(pSSM, pvBuf, cbBuf);
6555 return ssmR3DataReadUnbufferedV2(pSSM, pvBuf, cbBuf);
6556 }
[21797]6557
[56965]6558 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbBuf);
6559 pSSM->u.Read.offDataBuffer = off + (uint32_t)cbBuf;
6560 pSSM->offUnitUser += cbBuf;
6561 Log4((cbBuf
6562 ? "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n"
6563 : "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n",
6564 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
6565 cbBuf, RT_MIN(SSM_LOG_BYTES, cbBuf), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
[21797]6566
[56965]6567 return VINF_SUCCESS;
6568 }
6569 return ssmR3DataReadV1(pSSM, pvBuf, cbBuf);
6570 }
6571 return pSSM->rc;
[21797]6572}
6573
6574
6575/**
[1]6576 * Gets a structure.
6577 *
6578 * @returns VBox status code.
6579 * @param pSSM The saved state handle.
6580 * @param pvStruct The structure address.
6581 * @param paFields The array of structure fields descriptions.
6582 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
6583 */
[12989]6584VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
[1]6585{
[23753]6586 SSM_ASSERT_READABLE_RET(pSSM);
6587 SSM_CHECK_CANCELLED_RET(pSSM);
6588 AssertPtr(pvStruct);
6589 AssertPtr(paFields);
6590
[1]6591 /* begin marker. */
6592 uint32_t u32Magic;
6593 int rc = SSMR3GetU32(pSSM, &u32Magic);
[13816]6594 if (RT_FAILURE(rc))
[1]6595 return rc;
[49800]6596 AssertMsgReturn(u32Magic == SSMR3STRUCT_BEGIN, ("u32Magic=%#RX32\n", u32Magic), pSSM->rc = VERR_SSM_STRUCTURE_MAGIC);
[1]6597
[23749]6598 /* get the fields */
[1]6599 for (PCSSMFIELD pCur = paFields;
6600 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
6601 pCur++)
6602 {
[55465]6603 if (pCur->uFirstVer <= pSSM->u.Read.uCurUnitVer)
[23749]6604 {
[55465]6605 uint8_t *pbField = (uint8_t *)pvStruct + pCur->off;
6606 switch ((uintptr_t)pCur->pfnGetPutOrTransformer)
6607 {
6608 case SSMFIELDTRANS_NO_TRANSFORMATION:
6609 rc = ssmR3DataRead(pSSM, pbField, pCur->cb);
6610 break;
[23749]6611
[55465]6612 case SSMFIELDTRANS_GCPTR:
6613 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPTR), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6614 rc = SSMR3GetGCPtr(pSSM, (PRTGCPTR)pbField);
6615 break;
[23749]6616
[55465]6617 case SSMFIELDTRANS_GCPHYS:
6618 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPHYS), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6619 rc = SSMR3GetGCPhys(pSSM, (PRTGCPHYS)pbField);
6620 break;
[23749]6621
[55465]6622 case SSMFIELDTRANS_RCPTR:
6623 AssertMsgBreakStmt(pCur->cb == sizeof(RTRCPTR), ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6624 rc = SSMR3GetRCPtr(pSSM, (PRTRCPTR)pbField);
6625 break;
[23764]6626
[55465]6627 case SSMFIELDTRANS_RCPTR_ARRAY:
6628 {
6629 uint32_t const cEntries = pCur->cb / sizeof(RTRCPTR);
6630 AssertMsgBreakStmt(pCur->cb == cEntries * sizeof(RTRCPTR) && cEntries, ("%#x (%s)\n", pCur->cb, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6631 rc = VINF_SUCCESS;
6632 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
6633 rc = SSMR3GetRCPtr(pSSM, &((PRTRCPTR)pbField)[i]);
6634 break;
6635 }
6636
6637 default:
6638 AssertMsgFailedBreakStmt(("%#x\n", pCur->pfnGetPutOrTransformer), rc = VERR_SSM_FIELD_COMPLEX);
6639 }
6640 if (RT_FAILURE(rc))
[23764]6641 {
[55465]6642 if (RT_SUCCESS(pSSM->rc))
6643 pSSM->rc = rc;
6644 return rc;
[23764]6645 }
[23749]6646 }
[1]6647 }
6648
6649 /* end marker */
6650 rc = SSMR3GetU32(pSSM, &u32Magic);
[13816]6651 if (RT_FAILURE(rc))
[1]6652 return rc;
[49800]6653 AssertMsgReturn(u32Magic == SSMR3STRUCT_END, ("u32Magic=%#RX32\n", u32Magic), pSSM->rc = VERR_SSM_STRUCTURE_MAGIC);
[1]6654 return rc;
6655}
6656
6657
6658/**
[23764]6659 * SSMR3GetStructEx helper that gets a HCPTR that is used as a NULL indicator.
6660 *
6661 * @returns VBox status code.
6662 *
6663 * @param pSSM The saved state handle.
6664 * @param ppv Where to return the value (0/1).
6665 * @param fFlags SSMSTRUCT_FLAGS_XXX.
6666 */
6667DECLINLINE(int) ssmR3GetHCPtrNI(PSSMHANDLE pSSM, void **ppv, uint32_t fFlags)
6668{
[37026]6669 uintptr_t uPtrNI;
[23764]6670 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6671 {
6672 if (ssmR3GetHostBits(pSSM) == 64)
6673 {
6674 uint64_t u;
[37026]6675 int rc = ssmR3DataRead(pSSM, &u, sizeof(u));
6676 if (RT_FAILURE(rc))
6677 return rc;
6678 uPtrNI = u ? 1 : 0;
[23764]6679 }
6680 else
6681 {
6682 uint32_t u;
[37026]6683 int rc = ssmR3DataRead(pSSM, &u, sizeof(u));
6684 if (RT_FAILURE(rc))
6685 return rc;
6686 uPtrNI = u ? 1 : 0;
[23764]6687 }
6688 }
6689 else
6690 {
6691 bool f;
[37026]6692 int rc = SSMR3GetBool(pSSM, &f);
6693 if (RT_FAILURE(rc))
6694 return rc;
6695 uPtrNI = f ? 1 : 0;
[23764]6696 }
[37026]6697 *ppv = (void *)uPtrNI;
6698 return VINF_SUCCESS;
[23764]6699}
6700
6701
6702/**
[58411]6703 * Gets a structure, extended API.
[23752]6704 *
6705 * @returns VBox status code.
6706 * @param pSSM The saved state handle.
6707 * @param pvStruct The structure address.
6708 * @param cbStruct The size of the struct (use for validation only).
6709 * @param fFlags Combination of SSMSTRUCT_FLAGS_XXX defines.
6710 * @param paFields The array of structure fields descriptions. The
6711 * array must be terminated by a SSMFIELD_ENTRY_TERM().
6712 * @param pvUser User argument for any callbacks that paFields might
6713 * contain.
6714 */
6715VMMR3DECL(int) SSMR3GetStructEx(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct,
6716 uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)
6717{
6718 int rc;
6719 uint32_t u32Magic;
6720
6721 /*
6722 * Validation.
6723 */
[23753]6724 SSM_ASSERT_READABLE_RET(pSSM);
6725 SSM_CHECK_CANCELLED_RET(pSSM);
[49800]6726 AssertMsgReturn(!(fFlags & ~SSMSTRUCT_FLAGS_VALID_MASK), ("%#x\n", fFlags), pSSM->rc = VERR_INVALID_PARAMETER);
[23752]6727 AssertPtr(pvStruct);
6728 AssertPtr(paFields);
6729
6730 /*
6731 * Begin marker.
6732 */
[55048]6733 if (!(fFlags & (SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_NO_LEAD_MARKER)))
[23752]6734 {
6735 rc = SSMR3GetU32(pSSM, &u32Magic);
6736 if (RT_FAILURE(rc))
6737 return rc;
[49800]6738 AssertMsgReturn(u32Magic == SSMR3STRUCT_BEGIN, ("u32Magic=%#RX32\n", u32Magic), pSSM->rc = VERR_SSM_STRUCTURE_MAGIC);
[23752]6739 }
6740
6741 /*
6742 * Put the fields
6743 */
[49801]6744 rc = VINF_SUCCESS;
[23752]6745 uint32_t off = 0;
6746 for (PCSSMFIELD pCur = paFields;
6747 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
6748 pCur++)
6749 {
[23785]6750 uint32_t const offField = (!SSMFIELDTRANS_IS_PADDING(pCur->pfnGetPutOrTransformer) || pCur->off != UINT32_MAX / 2)
6751 && !SSMFIELDTRANS_IS_OLD(pCur->pfnGetPutOrTransformer)
[23764]6752 ? pCur->off
6753 : off;
[23785]6754 uint32_t const cbField = SSMFIELDTRANS_IS_OLD(pCur->pfnGetPutOrTransformer)
6755 ? 0
6756 : SSMFIELDTRANS_IS_PADDING(pCur->pfnGetPutOrTransformer)
6757 ? RT_HIWORD(pCur->cb)
6758 : pCur->cb;
[23764]6759 AssertMsgReturn( cbField <= cbStruct
6760 && offField + cbField <= cbStruct
6761 && offField + cbField >= offField,
6762 ("off=%#x cb=%#x cbStruct=%#x (%s)\n", cbField, offField, cbStruct, pCur->pszName),
[49800]6763 pSSM->rc = VERR_SSM_FIELD_OUT_OF_BOUNDS);
[23752]6764 AssertMsgReturn( !(fFlags & SSMSTRUCT_FLAGS_FULL_STRUCT)
[23764]6765 || off == offField,
6766 ("off=%#x offField=%#x (%s)\n", off, offField, pCur->pszName),
[49800]6767 pSSM->rc = VERR_SSM_FIELD_NOT_CONSECUTIVE);
[23752]6768
[55465]6769 if (pCur->uFirstVer <= pSSM->u.Read.uCurUnitVer)
[23752]6770 {
[55465]6771 rc = VINF_SUCCESS;
6772 uint8_t *pbField = (uint8_t *)pvStruct + offField;
6773 switch ((uintptr_t)pCur->pfnGetPutOrTransformer)
6774 {
6775 case SSMFIELDTRANS_NO_TRANSFORMATION:
6776 rc = ssmR3DataRead(pSSM, pbField, cbField);
6777 break;
[23752]6778
[55465]6779 case SSMFIELDTRANS_GCPHYS:
6780 AssertMsgBreakStmt(cbField == sizeof(RTGCPHYS), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6781 rc = SSMR3GetGCPhys(pSSM, (PRTGCPHYS)pbField);
6782 break;
[23785]6783
[55465]6784 case SSMFIELDTRANS_GCPTR:
6785 AssertMsgBreakStmt(cbField == sizeof(RTGCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6786 rc = SSMR3GetGCPtr(pSSM, (PRTGCPTR)pbField);
6787 break;
[23752]6788
[55465]6789 case SSMFIELDTRANS_RCPTR:
6790 AssertMsgBreakStmt(cbField == sizeof(RTRCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6791 rc = SSMR3GetRCPtr(pSSM, (PRTRCPTR)pbField);
6792 break;
[23764]6793
[55465]6794 case SSMFIELDTRANS_RCPTR_ARRAY:
6795 {
6796 uint32_t const cEntries = cbField / sizeof(RTRCPTR);
6797 AssertMsgBreakStmt(cbField == cEntries * sizeof(RTRCPTR) && cEntries, ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6798 rc = VINF_SUCCESS;
6799 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
6800 rc = SSMR3GetRCPtr(pSSM, &((PRTRCPTR)pbField)[i]);
6801 break;
6802 }
[23764]6803
[55465]6804 case SSMFIELDTRANS_HCPTR_NI:
6805 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6806 rc = ssmR3GetHCPtrNI(pSSM, (void **)pbField, fFlags);
6807 break;
[23764]6808
[55465]6809 case SSMFIELDTRANS_HCPTR_NI_ARRAY:
[23783]6810 {
[55465]6811 uint32_t const cEntries = cbField / sizeof(void *);
6812 AssertMsgBreakStmt(cbField == cEntries * sizeof(void *) && cEntries, ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6813 rc = VINF_SUCCESS;
6814 for (uint32_t i = 0; i < cEntries && RT_SUCCESS(rc); i++)
6815 rc = ssmR3GetHCPtrNI(pSSM, &((void **)pbField)[i], fFlags);
6816 break;
[23783]6817 }
6818
[55465]6819 case SSMFIELDTRANS_HCPTR_HACK_U32:
6820 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6821 *(uintptr_t *)pbField = 0;
6822 rc = ssmR3DataRead(pSSM, pbField, sizeof(uint32_t));
6823 if ((fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE) && ssmR3GetHostBits(pSSM) == 64)
6824 {
6825 uint32_t u32;
6826 rc = ssmR3DataRead(pSSM, &u32, sizeof(uint32_t));
6827 AssertMsgBreakStmt(RT_FAILURE(rc) || u32 == 0 || (fFlags & SSMSTRUCT_FLAGS_SAVED_AS_MEM),
6828 ("high=%#x low=%#x (%s)\n", u32, *(uint32_t *)pbField, pCur->pszName),
6829 rc = VERR_SSM_FIELD_INVALID_VALUE);
6830 }
6831 break;
[23783]6832
[55465]6833 case SSMFIELDTRANS_U32_ZX_U64:
6834 AssertMsgBreakStmt(cbField == sizeof(uint64_t), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6835 ((uint32_t *)pbField)[1] = 0;
6836 rc = SSMR3GetU32(pSSM, (uint32_t *)pbField);
6837 break;
[41900]6838
[23752]6839
[55465]6840 case SSMFIELDTRANS_IGNORE:
6841 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6842 rc = SSMR3Skip(pSSM, cbField);
6843 break;
[23785]6844
[55465]6845 case SSMFIELDTRANS_IGN_GCPHYS:
6846 AssertMsgBreakStmt(cbField == sizeof(RTGCPHYS), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6847 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6848 rc = SSMR3Skip(pSSM, pSSM->u.Read.cbGCPhys);
6849 break;
[23780]6850
[55465]6851 case SSMFIELDTRANS_IGN_GCPTR:
6852 AssertMsgBreakStmt(cbField == sizeof(RTGCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6853 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6854 rc = SSMR3Skip(pSSM, pSSM->u.Read.cbGCPtr);
6855 break;
[23779]6856
[55465]6857 case SSMFIELDTRANS_IGN_RCPTR:
6858 AssertMsgBreakStmt(cbField == sizeof(RTRCPTR), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6859 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6860 rc = SSMR3Skip(pSSM, sizeof(RTRCPTR));
6861 break;
[23752]6862
[55465]6863 case SSMFIELDTRANS_IGN_HCPTR:
6864 AssertMsgBreakStmt(cbField == sizeof(void *), ("%#x (%s)\n", cbField, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6865 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6866 rc = SSMR3Skip(pSSM, ssmR3GetHostBits(pSSM) / 8);
6867 break;
[23783]6868
[23785]6869
[55465]6870 case SSMFIELDTRANS_OLD:
6871 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6872 rc = SSMR3Skip(pSSM, pCur->cb);
6873 break;
[23785]6874
[55465]6875 case SSMFIELDTRANS_OLD_GCPHYS:
6876 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPHYS) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6877 rc = SSMR3Skip(pSSM, pSSM->u.Read.cbGCPhys);
6878 break;
[23785]6879
[55465]6880 case SSMFIELDTRANS_OLD_GCPTR:
6881 AssertMsgBreakStmt(pCur->cb == sizeof(RTGCPTR) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6882 rc = SSMR3Skip(pSSM, pSSM->u.Read.cbGCPtr);
6883 break;
[23785]6884
[55465]6885 case SSMFIELDTRANS_OLD_RCPTR:
6886 AssertMsgBreakStmt(pCur->cb == sizeof(RTRCPTR) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6887 rc = SSMR3Skip(pSSM, sizeof(RTRCPTR));
6888 break;
[23785]6889
[55465]6890 case SSMFIELDTRANS_OLD_HCPTR:
6891 AssertMsgBreakStmt(pCur->cb == sizeof(void *) && pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6892 rc = SSMR3Skip(pSSM, ssmR3GetHostBits(pSSM) / 8);
6893 break;
[23785]6894
[55465]6895 case SSMFIELDTRANS_OLD_PAD_HC:
6896 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6897 rc = SSMR3Skip(pSSM, ssmR3GetHostBits(pSSM) == 64 ? RT_HIWORD(pCur->cb) : RT_LOWORD(pCur->cb));
6898 break;
[23872]6899
[55465]6900 case SSMFIELDTRANS_OLD_PAD_MSC32:
6901 AssertMsgBreakStmt(pCur->off == UINT32_MAX / 2, ("%#x %#x (%s)\n", pCur->cb, pCur->off, pCur->pszName), rc = VERR_SSM_FIELD_INVALID_SIZE);
6902 if (ssmR3IsHostMsc32(pSSM))
6903 rc = SSMR3Skip(pSSM, pCur->cb);
6904 break;
[23872]6905
[55465]6906
6907 case SSMFIELDTRANS_PAD_HC:
6908 case SSMFIELDTRANS_PAD_HC32:
6909 case SSMFIELDTRANS_PAD_HC64:
6910 case SSMFIELDTRANS_PAD_HC_AUTO:
6911 case SSMFIELDTRANS_PAD_MSC32_AUTO:
6912 {
6913 uint32_t cb32 = RT_BYTE1(pCur->cb);
6914 uint32_t cb64 = RT_BYTE2(pCur->cb);
6915 uint32_t cbCtx = HC_ARCH_BITS == 64
6916 || ( (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
6917 && !SSM_HOST_IS_MSC_32)
6918 ? cb64 : cb32;
6919 uint32_t cbSaved = ssmR3GetHostBits(pSSM) == 64
6920 || ( (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
6921 && !ssmR3IsHostMsc32(pSSM))
6922 ? cb64 : cb32;
6923 AssertMsgBreakStmt( cbField == cbCtx
6924 && ( ( pCur->off == UINT32_MAX / 2
6925 && ( cbField == 0
6926 || (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_HC_AUTO
6927 || (uintptr_t)pCur->pfnGetPutOrTransformer == SSMFIELDTRANS_PAD_MSC32_AUTO
6928 )
[49800]6929 )
[55465]6930 || (pCur->off != UINT32_MAX / 2 && cbField != 0)
6931 )
6932 , ("cbField=%#x cb32=%#x cb64=%#x HC_ARCH_BITS=%u cbCtx=%#x cbSaved=%#x off=%#x\n",
6933 cbField, cb32, cb64, HC_ARCH_BITS, cbCtx, cbSaved, pCur->off),
6934 rc = VERR_SSM_FIELD_INVALID_PADDING_SIZE);
6935 if (fFlags & SSMSTRUCT_FLAGS_DONT_IGNORE)
6936 rc = SSMR3Skip(pSSM, cbSaved);
6937 break;
6938 }
6939
6940 default:
6941 AssertBreakStmt(pCur->pfnGetPutOrTransformer, rc = VERR_SSM_FIELD_INVALID_CALLBACK);
6942 rc = pCur->pfnGetPutOrTransformer(pSSM, pCur, pvStruct, fFlags, true /*fGetOrPut*/, pvUser);
6943 break;
[23764]6944 }
[55465]6945 if (RT_FAILURE(rc))
[23752]6946 break;
6947 }
6948
[23764]6949 off = offField + cbField;
[23752]6950 }
6951
[49800]6952 if (RT_SUCCESS(rc))
6953 AssertMsgStmt( !(fFlags & SSMSTRUCT_FLAGS_FULL_STRUCT)
6954 || off == cbStruct,
6955 ("off=%#x cbStruct=%#x\n", off, cbStruct),
6956 rc = VERR_SSM_FIELD_NOT_CONSECUTIVE);
6957
6958 if (RT_FAILURE(rc))
6959 {
6960 if (RT_SUCCESS(pSSM->rc))
6961 pSSM->rc = rc;
6962 return rc;
6963 }
6964
[23752]6965 /*
6966 * End marker
6967 */
[55048]6968 if (!(fFlags & (SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_NO_TAIL_MARKER)))
[23752]6969 {
6970 rc = SSMR3GetU32(pSSM, &u32Magic);
6971 if (RT_FAILURE(rc))
6972 return rc;
[49800]6973 AssertMsgReturn(u32Magic == SSMR3STRUCT_END, ("u32Magic=%#RX32\n", u32Magic), pSSM->rc = VERR_SSM_STRUCTURE_MAGIC);
[23752]6974 }
6975
6976 return VINF_SUCCESS;
6977}
6978
6979
6980/**
[1]6981 * Loads a boolean item from the current data unit.
6982 *
[58170]6983 * @returns VBox status code.
[23764]6984 * @param pSSM The saved state handle.
[1]6985 * @param pfBool Where to store the item.
6986 */
[12989]6987VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
[1]6988{
[22554]6989 SSM_ASSERT_READABLE_RET(pSSM);
[22884]6990 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]6991 uint8_t u8; /* see SSMR3PutBool */
6992 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
6993 if (RT_SUCCESS(rc))
[1]6994 {
[22034]6995 Assert(u8 <= 1);
[81753]6996 *pfBool = RT_BOOL(u8);
[1]6997 }
[22034]6998 return rc;
[1]6999}
7000
[13594]7001
[1]7002/**
[81753]7003 * Loads a volatile boolean item from the current data unit.
7004 *
7005 * @returns VBox status code.
7006 * @param pSSM The saved state handle.
7007 * @param pfBool Where to store the item.
7008 */
7009VMMR3DECL(int) SSMR3GetBoolV(PSSMHANDLE pSSM, bool volatile *pfBool)
7010{
7011 SSM_ASSERT_READABLE_RET(pSSM);
7012 SSM_CHECK_CANCELLED_RET(pSSM);
7013 uint8_t u8; /* see SSMR3PutBool */
7014 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
7015 if (RT_SUCCESS(rc))
7016 {
7017 Assert(u8 <= 1);
7018 *pfBool = RT_BOOL(u8);
7019 }
7020 return rc;
7021}
7022
7023
7024/**
[1]7025 * Loads a 8-bit unsigned integer item from the current data unit.
7026 *
[58170]7027 * @returns VBox status code.
[23764]7028 * @param pSSM The saved state handle.
[1]7029 * @param pu8 Where to store the item.
7030 */
[12989]7031VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
[1]7032{
[22554]7033 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7034 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7035 return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
[1]7036}
7037
[13594]7038
[1]7039/**
[81753]7040 * Loads a volatile 8-bit unsigned integer item from the current data unit.
7041 *
7042 * @returns VBox status code.
7043 * @param pSSM The saved state handle.
7044 * @param pu8 Where to store the item.
7045 */
7046VMMR3DECL(int) SSMR3GetU8V(PSSMHANDLE pSSM, uint8_t volatile *pu8)
7047{
7048 SSM_ASSERT_READABLE_RET(pSSM);
7049 SSM_CHECK_CANCELLED_RET(pSSM);
7050 return ssmR3DataRead(pSSM, (void *)pu8, sizeof(*pu8));
7051}
7052
7053
7054/**
[1]7055 * Loads a 8-bit signed integer item from the current data unit.
7056 *
[58170]7057 * @returns VBox status code.
[23764]7058 * @param pSSM The saved state handle.
[1]7059 * @param pi8 Where to store the item.
7060 */
[12989]7061VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
[1]7062{
[22554]7063 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7064 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7065 return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
[1]7066}
7067
[13594]7068
[1]7069/**
[81753]7070 * Loads a volatile 8-bit signed integer item from the current data unit.
7071 *
7072 * @returns VBox status code.
7073 * @param pSSM The saved state handle.
7074 * @param pi8 Where to store the item.
7075 */
7076VMMR3DECL(int) SSMR3GetS8V(PSSMHANDLE pSSM, int8_t volatile *pi8)
7077{
7078 SSM_ASSERT_READABLE_RET(pSSM);
7079 SSM_CHECK_CANCELLED_RET(pSSM);
7080 return ssmR3DataRead(pSSM, (void *)pi8, sizeof(*pi8));
7081}
7082
7083
7084/**
[1]7085 * Loads a 16-bit unsigned integer item from the current data unit.
7086 *
[58170]7087 * @returns VBox status code.
[23764]7088 * @param pSSM The saved state handle.
[1]7089 * @param pu16 Where to store the item.
7090 */
[12989]7091VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
[1]7092{
[22554]7093 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7094 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7095 return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
[1]7096}
7097
[13594]7098
[1]7099/**
[81753]7100 * Loads a volatile 16-bit unsigned integer item from the current data unit.
7101 *
7102 * @returns VBox status code.
7103 * @param pSSM The saved state handle.
7104 * @param pu16 Where to store the item.
7105 */
7106VMMR3DECL(int) SSMR3GetU16V(PSSMHANDLE pSSM, uint16_t volatile *pu16)
7107{
7108 SSM_ASSERT_READABLE_RET(pSSM);
7109 SSM_CHECK_CANCELLED_RET(pSSM);
7110 return ssmR3DataRead(pSSM, (void *)pu16, sizeof(*pu16));
7111}
7112
7113
7114/**
[1]7115 * Loads a 16-bit signed integer item from the current data unit.
7116 *
[58170]7117 * @returns VBox status code.
[23764]7118 * @param pSSM The saved state handle.
[1]7119 * @param pi16 Where to store the item.
7120 */
[12989]7121VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
[1]7122{
[22554]7123 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7124 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7125 return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
[1]7126}
7127
[13594]7128
[1]7129/**
[81753]7130 * Loads a volatile 16-bit signed integer item from the current data unit.
7131 *
7132 * @returns VBox status code.
7133 * @param pSSM The saved state handle.
7134 * @param pi16 Where to store the item.
7135 */
7136VMMR3DECL(int) SSMR3GetS16V(PSSMHANDLE pSSM, int16_t volatile *pi16)
7137{
7138 SSM_ASSERT_READABLE_RET(pSSM);
7139 SSM_CHECK_CANCELLED_RET(pSSM);
7140 return ssmR3DataRead(pSSM, (void *)pi16, sizeof(*pi16));
7141}
7142
7143
7144/**
[1]7145 * Loads a 32-bit unsigned integer item from the current data unit.
7146 *
[58170]7147 * @returns VBox status code.
[23764]7148 * @param pSSM The saved state handle.
[1]7149 * @param pu32 Where to store the item.
7150 */
[12989]7151VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
[1]7152{
[22554]7153 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7154 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7155 return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
[1]7156}
7157
[13594]7158
[1]7159/**
[81753]7160 * Loads a volatile 32-bit unsigned integer item from the current data unit.
7161 *
7162 * @returns VBox status code.
7163 * @param pSSM The saved state handle.
7164 * @param pu32 Where to store the item.
7165 */
7166VMMR3DECL(int) SSMR3GetU32V(PSSMHANDLE pSSM, uint32_t volatile *pu32)
7167{
7168 SSM_ASSERT_READABLE_RET(pSSM);
7169 SSM_CHECK_CANCELLED_RET(pSSM);
7170 return ssmR3DataRead(pSSM, (void *)pu32, sizeof(*pu32));
7171}
7172
7173
7174/**
[1]7175 * Loads a 32-bit signed integer item from the current data unit.
7176 *
[58170]7177 * @returns VBox status code.
[23764]7178 * @param pSSM The saved state handle.
[1]7179 * @param pi32 Where to store the item.
7180 */
[12989]7181VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
[1]7182{
[22554]7183 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7184 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7185 return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
[1]7186}
7187
[13594]7188
[1]7189/**
[81753]7190 * Loads a volatile 32-bit signed integer item from the current data unit.
7191 *
7192 * @returns VBox status code.
7193 * @param pSSM The saved state handle.
7194 * @param pi32 Where to store the item.
7195 */
7196VMMR3DECL(int) SSMR3GetS32V(PSSMHANDLE pSSM, int32_t volatile *pi32)
7197{
7198 SSM_ASSERT_READABLE_RET(pSSM);
7199 SSM_CHECK_CANCELLED_RET(pSSM);
7200 return ssmR3DataRead(pSSM, (void *)pi32, sizeof(*pi32));
7201}
7202
7203
7204/**
[1]7205 * Loads a 64-bit unsigned integer item from the current data unit.
7206 *
[58170]7207 * @returns VBox status code.
[23764]7208 * @param pSSM The saved state handle.
[1]7209 * @param pu64 Where to store the item.
7210 */
[12989]7211VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
[1]7212{
[22554]7213 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7214 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7215 return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
[1]7216}
7217
[13594]7218
[1]7219/**
[81753]7220 * Loads a volatile 64-bit unsigned integer item from the current data unit.
7221 *
7222 * @returns VBox status code.
7223 * @param pSSM The saved state handle.
7224 * @param pu64 Where to store the item.
7225 */
7226VMMR3DECL(int) SSMR3GetU64V(PSSMHANDLE pSSM, uint64_t volatile *pu64)
7227{
7228 SSM_ASSERT_READABLE_RET(pSSM);
7229 SSM_CHECK_CANCELLED_RET(pSSM);
7230 return ssmR3DataRead(pSSM, (void *)pu64, sizeof(*pu64));
7231}
7232
7233
7234/**
[1]7235 * Loads a 64-bit signed integer item from the current data unit.
7236 *
[58170]7237 * @returns VBox status code.
[23764]7238 * @param pSSM The saved state handle.
[1]7239 * @param pi64 Where to store the item.
7240 */
[12989]7241VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
[1]7242{
[22554]7243 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7244 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7245 return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
[1]7246}
7247
[13594]7248
[1]7249/**
[81753]7250 * Loads a volatile 64-bit signed integer item from the current data unit.
7251 *
7252 * @returns VBox status code.
7253 * @param pSSM The saved state handle.
7254 * @param pi64 Where to store the item.
7255 */
7256VMMR3DECL(int) SSMR3GetS64V(PSSMHANDLE pSSM, int64_t volatile *pi64)
7257{
7258 SSM_ASSERT_READABLE_RET(pSSM);
7259 SSM_CHECK_CANCELLED_RET(pSSM);
7260 return ssmR3DataRead(pSSM, (void *)pi64, sizeof(*pi64));
7261}
7262
7263
7264/**
[1]7265 * Loads a 128-bit unsigned integer item from the current data unit.
7266 *
[58170]7267 * @returns VBox status code.
[23764]7268 * @param pSSM The saved state handle.
[1]7269 * @param pu128 Where to store the item.
7270 */
[12989]7271VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
[1]7272{
[22554]7273 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7274 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7275 return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
[1]7276}
7277
7278
7279/**
[81753]7280 * Loads a volatile 128-bit unsigned integer item from the current data unit.
7281 *
7282 * @returns VBox status code.
7283 * @param pSSM The saved state handle.
7284 * @param pu128 Where to store the item.
7285 */
7286VMMR3DECL(int) SSMR3GetU128V(PSSMHANDLE pSSM, uint128_t volatile *pu128)
7287{
7288 SSM_ASSERT_READABLE_RET(pSSM);
7289 SSM_CHECK_CANCELLED_RET(pSSM);
7290 return ssmR3DataRead(pSSM, (void *)pu128, sizeof(*pu128));
7291}
7292
7293
7294/**
[1]7295 * Loads a 128-bit signed integer item from the current data unit.
7296 *
[58170]7297 * @returns VBox status code.
[23764]7298 * @param pSSM The saved state handle.
[1]7299 * @param pi128 Where to store the item.
7300 */
[12989]7301VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
[1]7302{
[22554]7303 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7304 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7305 return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
[1]7306}
7307
7308
7309/**
[81753]7310 * Loads a volatile 128-bit signed integer item from the current data unit.
7311 *
7312 * @returns VBox status code.
7313 * @param pSSM The saved state handle.
7314 * @param pi128 Where to store the item.
7315 */
7316VMMR3DECL(int) SSMR3GetS128V(PSSMHANDLE pSSM, int128_t volatile *pi128)
7317{
7318 SSM_ASSERT_READABLE_RET(pSSM);
7319 SSM_CHECK_CANCELLED_RET(pSSM);
7320 return ssmR3DataRead(pSSM, (void *)pi128, sizeof(*pi128));
7321}
7322
7323
7324/**
[1]7325 * Loads a VBox unsigned integer item from the current data unit.
7326 *
[58170]7327 * @returns VBox status code.
[23764]7328 * @param pSSM The saved state handle.
[1]7329 * @param pu Where to store the integer.
7330 */
[12989]7331VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
[1]7332{
[22554]7333 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7334 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7335 return ssmR3DataRead(pSSM, pu, sizeof(*pu));
[1]7336}
7337
7338
7339/**
7340 * Loads a VBox signed integer item from the current data unit.
7341 *
[58170]7342 * @returns VBox status code.
[23764]7343 * @param pSSM The saved state handle.
[1]7344 * @param pi Where to store the integer.
7345 */
[12989]7346VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
[1]7347{
[22554]7348 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7349 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7350 return ssmR3DataRead(pSSM, pi, sizeof(*pi));
[1]7351}
7352
7353
7354/**
7355 * Loads a GC natural unsigned integer item from the current data unit.
7356 *
[58170]7357 * @returns VBox status code.
[23764]7358 * @param pSSM The saved state handle.
[1]7359 * @param pu Where to store the integer.
[13596]7360 *
[15503]7361 * @deprecated Silly type with an incorrect size, don't use it.
[1]7362 */
[12989]7363VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
[1]7364{
[15503]7365 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
7366 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
[1]7367}
7368
7369
7370/**
[13596]7371 * Loads a GC unsigned integer register item from the current data unit.
[1]7372 *
[58170]7373 * @returns VBox status code.
[23764]7374 * @param pSSM The saved state handle.
[13596]7375 * @param pu Where to store the integer.
[1]7376 */
[13596]7377VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu)
[1]7378{
[15503]7379 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
7380 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
[1]7381}
7382
[7111]7383
[7072]7384/**
7385 * Loads a 32 bits GC physical address item from the current data unit.
7386 *
[58170]7387 * @returns VBox status code.
[23764]7388 * @param pSSM The saved state handle.
[7072]7389 * @param pGCPhys Where to store the GC physical address.
7390 */
[12989]7391VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
[7072]7392{
[22554]7393 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7394 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7395 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
[7072]7396}
[1]7397
[7591]7398
[7581]7399/**
[81753]7400 * Loads a 32 bits GC physical address item from the current data unit.
7401 *
7402 * @returns VBox status code.
7403 * @param pSSM The saved state handle.
7404 * @param pGCPhys Where to store the GC physical address.
7405 */
7406VMMR3DECL(int) SSMR3GetGCPhys32V(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)
7407{
7408 SSM_ASSERT_READABLE_RET(pSSM);
7409 SSM_CHECK_CANCELLED_RET(pSSM);
7410 return ssmR3DataRead(pSSM, (void *)pGCPhys, sizeof(*pGCPhys));
7411}
7412
7413
7414/**
[7581]7415 * Loads a 64 bits GC physical address item from the current data unit.
7416 *
[58170]7417 * @returns VBox status code.
[23764]7418 * @param pSSM The saved state handle.
[7581]7419 * @param pGCPhys Where to store the GC physical address.
7420 */
[12989]7421VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
[7581]7422{
[22554]7423 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7424 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7425 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
[7581]7426}
[7072]7427
[7581]7428
[1]7429/**
[81753]7430 * Loads a volatile 64 bits GC physical address item from the current data unit.
7431 *
7432 * @returns VBox status code.
7433 * @param pSSM The saved state handle.
7434 * @param pGCPhys Where to store the GC physical address.
7435 */
7436VMMR3DECL(int) SSMR3GetGCPhys64V(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)
7437{
7438 SSM_ASSERT_READABLE_RET(pSSM);
7439 SSM_CHECK_CANCELLED_RET(pSSM);
7440 return ssmR3DataRead(pSSM, (void *)pGCPhys, sizeof(*pGCPhys));
7441}
7442
7443
7444/**
[1]7445 * Loads a GC physical address item from the current data unit.
7446 *
[58170]7447 * @returns VBox status code.
[23764]7448 * @param pSSM The saved state handle.
[1]7449 * @param pGCPhys Where to store the GC physical address.
7450 */
[12989]7451VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
[1]7452{
[22554]7453 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7454 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7455
7456 /*
7457 * Default size?
7458 */
7459 if (RT_LIKELY(sizeof(*pGCPhys) == pSSM->u.Read.cbGCPhys))
7460 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
7461
7462 /*
7463 * Fiddly.
7464 */
7465 Assert(sizeof(*pGCPhys) == sizeof(uint64_t) || sizeof(*pGCPhys) == sizeof(uint32_t));
7466 Assert(pSSM->u.Read.cbGCPhys == sizeof(uint64_t) || pSSM->u.Read.cbGCPhys == sizeof(uint32_t));
7467 if (pSSM->u.Read.cbGCPhys == sizeof(uint64_t))
[15503]7468 {
[22034]7469 /* 64-bit saved, 32-bit load: try truncate it. */
7470 uint64_t u64;
7471 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
7472 if (RT_FAILURE(rc))
[21797]7473 return rc;
[22034]7474 if (u64 >= _4G)
7475 return VERR_SSM_GCPHYS_OVERFLOW;
7476 *pGCPhys = (RTGCPHYS)u64;
7477 return rc;
7478 }
[21797]7479
[22034]7480 /* 32-bit saved, 64-bit load: clear the high part. */
7481 *pGCPhys = 0;
7482 return ssmR3DataRead(pSSM, pGCPhys, sizeof(uint32_t));
[1]7483}
7484
[81753]7485/**
7486 * Loads a volatile GC physical address item from the current data unit.
7487 *
7488 * @returns VBox status code.
7489 * @param pSSM The saved state handle.
7490 * @param pGCPhys Where to store the GC physical address.
7491 */
7492VMMR3DECL(int) SSMR3GetGCPhysV(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)
7493{
7494 return SSMR3GetGCPhys(pSSM, (PRTGCPHYS)pGCPhys);
7495}
[1]7496
[81753]7497
[1]7498/**
7499 * Loads a GC virtual address item from the current data unit.
7500 *
[15503]7501 * Only applies to in the 1.1 format:
[13594]7502 * - SSMR3GetGCPtr
7503 * - SSMR3GetGCUIntPtr
7504 * - SSMR3GetGCUInt
[13596]7505 * - SSMR3GetGCUIntReg
[11808]7506 *
7507 * Put functions are not affected.
7508 *
[58170]7509 * @returns VBox status code.
[23764]7510 * @param pSSM The saved state handle.
[11808]7511 * @param cbGCPtr Size of RTGCPTR
[15503]7512 *
7513 * @remarks This interface only works with saved state version 1.1, if the
7514 * format isn't 1.1 the call will be ignored.
[11808]7515 */
[30396]7516VMMR3_INT_DECL(int) SSMR3HandleSetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
[11808]7517{
7518 Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
[21797]7519 if (!pSSM->u.Read.fFixedGCPtrSize)
[15503]7520 {
[21797]7521 Log(("SSMR3SetGCPtrSize: %u -> %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
7522 pSSM->u.Read.cbGCPtr = cbGCPtr;
7523 pSSM->u.Read.fFixedGCPtrSize = true;
[15503]7524 }
[21797]7525 else if ( pSSM->u.Read.cbGCPtr != cbGCPtr
[22100]7526 && pSSM->u.Read.uFmtVerMajor == 1
7527 && pSSM->u.Read.uFmtVerMinor == 1)
[21797]7528 AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %u bytes; requested %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
[15503]7529
[11808]7530 return VINF_SUCCESS;
7531}
7532
[13594]7533
[11808]7534/**
7535 * Loads a GC virtual address item from the current data unit.
7536 *
[58170]7537 * @returns VBox status code.
[23764]7538 * @param pSSM The saved state handle.
[1]7539 * @param pGCPtr Where to store the GC virtual address.
7540 */
[12989]7541VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
[1]7542{
[22554]7543 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7544 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7545
7546 /*
7547 * Default size?
7548 */
7549 if (RT_LIKELY(sizeof(*pGCPtr) == pSSM->u.Read.cbGCPtr))
7550 return ssmR3DataRead(pSSM, pGCPtr, sizeof(*pGCPtr));
7551
7552 /*
7553 * Fiddly.
7554 */
7555 Assert(sizeof(*pGCPtr) == sizeof(uint64_t) || sizeof(*pGCPtr) == sizeof(uint32_t));
7556 Assert(pSSM->u.Read.cbGCPtr == sizeof(uint64_t) || pSSM->u.Read.cbGCPtr == sizeof(uint32_t));
7557 if (pSSM->u.Read.cbGCPtr == sizeof(uint64_t))
[11808]7558 {
[22034]7559 /* 64-bit saved, 32-bit load: try truncate it. */
7560 uint64_t u64;
7561 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
7562 if (RT_FAILURE(rc))
[21797]7563 return rc;
[22034]7564 if (u64 >= _4G)
7565 return VERR_SSM_GCPTR_OVERFLOW;
7566 *pGCPtr = (RTGCPTR)u64;
7567 return rc;
7568 }
[21797]7569
[22034]7570 /* 32-bit saved, 64-bit load: clear the high part. */
7571 *pGCPtr = 0;
7572 return ssmR3DataRead(pSSM, pGCPtr, sizeof(uint32_t));
[1]7573}
7574
[13594]7575
[11944]7576/**
[15503]7577 * Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
[11944]7578 *
[58170]7579 * @returns VBox status code.
[23764]7580 * @param pSSM The saved state handle.
[15503]7581 * @param pGCPtr Where to store the GC virtual address.
[11944]7582 */
[15503]7583VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
[11944]7584{
[15503]7585 AssertCompile(sizeof(RTGCPTR) == sizeof(*pGCPtr));
7586 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pGCPtr);
[11944]7587}
7588
[13594]7589
[1]7590/**
[15503]7591 * Loads an RC virtual address item from the current data unit.
[1]7592 *
[58170]7593 * @returns VBox status code.
[23764]7594 * @param pSSM The saved state handle.
[15503]7595 * @param pRCPtr Where to store the RC virtual address.
[1]7596 */
[15503]7597VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
[1]7598{
[22554]7599 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7600 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7601 return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
[1]7602}
7603
7604
7605/**
7606 * Loads a I/O port address item from the current data unit.
7607 *
[58170]7608 * @returns VBox status code.
[23764]7609 * @param pSSM The saved state handle.
[1]7610 * @param pIOPort Where to store the I/O port address.
7611 */
[12989]7612VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
[1]7613{
[22554]7614 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7615 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7616 return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
[1]7617}
7618
7619
7620/**
7621 * Loads a selector item from the current data unit.
7622 *
[58170]7623 * @returns VBox status code.
[23764]7624 * @param pSSM The saved state handle.
[1]7625 * @param pSel Where to store the selector.
7626 */
[12989]7627VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
[1]7628{
[22554]7629 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7630 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7631 return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
[1]7632}
7633
7634
7635/**
7636 * Loads a memory item from the current data unit.
7637 *
[58170]7638 * @returns VBox status code.
[23764]7639 * @param pSSM The saved state handle.
[1]7640 * @param pv Where to store the item.
7641 * @param cb Size of the item.
7642 */
[12989]7643VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
[1]7644{
[22554]7645 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7646 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7647 return ssmR3DataRead(pSSM, pv, cb);
[1]7648}
7649
7650
7651/**
7652 * Loads a string item from the current data unit.
7653 *
[58170]7654 * @returns VBox status code.
[23764]7655 * @param pSSM The saved state handle.
[1]7656 * @param psz Where to store the item.
7657 * @param cbMax Max size of the item (including '\\0').
7658 */
[12989]7659VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
[1]7660{
7661 return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
7662}
7663
7664
7665/**
7666 * Loads a string item from the current data unit.
7667 *
[58170]7668 * @returns VBox status code.
[23764]7669 * @param pSSM The saved state handle.
[1]7670 * @param psz Where to store the item.
7671 * @param cbMax Max size of the item (including '\\0').
7672 * @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
7673 */
[12989]7674VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
[1]7675{
[22554]7676 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7677 SSM_CHECK_CANCELLED_RET(pSSM);
[22034]7678
7679 /* read size prefix. */
7680 uint32_t u32;
7681 int rc = SSMR3GetU32(pSSM, &u32);
7682 if (RT_SUCCESS(rc))
[1]7683 {
[22034]7684 if (pcbStr)
7685 *pcbStr = u32;
7686 if (u32 < cbMax)
[1]7687 {
[22034]7688 /* terminate and read string content. */
7689 psz[u32] = '\0';
7690 return ssmR3DataRead(pSSM, psz, u32);
[1]7691 }
[22034]7692 return VERR_TOO_MUCH_DATA;
[1]7693 }
[22034]7694 return rc;
[1]7695}
7696
7697
[20114]7698/**
7699 * Skips a number of bytes in the current data unit.
7700 *
7701 * @returns VBox status code.
7702 * @param pSSM The SSM handle.
7703 * @param cb The number of bytes to skip.
7704 */
7705VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
7706{
[22554]7707 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7708 SSM_CHECK_CANCELLED_RET(pSSM);
[20114]7709 while (cb > 0)
7710 {
7711 uint8_t abBuf[8192];
7712 size_t cbCur = RT_MIN(sizeof(abBuf), cb);
7713 cb -= cbCur;
[21797]7714 int rc = ssmR3DataRead(pSSM, abBuf, cbCur);
[20114]7715 if (RT_FAILURE(rc))
7716 return rc;
7717 }
[1]7718
[20114]7719 return VINF_SUCCESS;
7720}
7721
7722
[1]7723/**
[21927]7724 * Skips to the end of the current data unit.
7725 *
7726 * Since version 2 of the format, the load exec callback have to explicitly call
7727 * this API if it wish to be lazy for some reason. This is because there seldom
7728 * is a good reason to not read your entire data unit and it was hiding bugs.
7729 *
7730 * @returns VBox status code.
7731 * @param pSSM The saved state handle.
7732 */
7733VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM)
7734{
[22554]7735 SSM_ASSERT_READABLE_RET(pSSM);
[22884]7736 SSM_CHECK_CANCELLED_RET(pSSM);
[21927]7737 if (pSSM->u.Read.uFmtVerMajor >= 2)
7738 {
7739 /*
7740 * Read until we the end of data condition is raised.
7741 */
7742 pSSM->u.Read.cbDataBuffer = 0;
7743 pSSM->u.Read.offDataBuffer = 0;
7744 if (!pSSM->u.Read.fEndOfData)
7745 {
7746 do
7747 {
7748 /* read the rest of the current record */
7749 while (pSSM->u.Read.cbRecLeft)
7750 {
[26526]7751 uint8_t abBuf[8192];
7752 uint32_t cbToRead = RT_MIN(pSSM->u.Read.cbRecLeft, sizeof(abBuf));
[21927]7753 int rc = ssmR3DataReadV2Raw(pSSM, abBuf, cbToRead);
7754 if (RT_FAILURE(rc))
7755 return pSSM->rc = rc;
7756 pSSM->u.Read.cbRecLeft -= cbToRead;
7757 }
7758
7759 /* read the next header. */
7760 int rc = ssmR3DataReadRecHdrV2(pSSM);
7761 if (RT_FAILURE(rc))
7762 return pSSM->rc = rc;
7763 } while (!pSSM->u.Read.fEndOfData);
7764 }
7765 }
7766 /* else: Doesn't matter for the version 1 loading. */
7767
7768 return VINF_SUCCESS;
7769}
7770
7771
7772/**
[22554]7773 * Calculate the checksum of a file portion.
7774 *
[58170]7775 * @returns VBox status code.
[22554]7776 * @param pStrm The stream handle
7777 * @param off Where to start checksumming.
7778 * @param cb How much to checksum.
7779 * @param pu32CRC Where to store the calculated checksum.
7780 */
7781static int ssmR3CalcChecksum(PSSMSTRM pStrm, uint64_t off, uint64_t cb, uint32_t *pu32CRC)
7782{
7783 /*
7784 * Allocate a buffer.
7785 */
7786 const size_t cbBuf = _32K;
7787 void *pvBuf = RTMemTmpAlloc(cbBuf);
7788 if (!pvBuf)
7789 return VERR_NO_TMP_MEMORY;
7790
7791 /*
7792 * Loop reading and calculating CRC32.
7793 */
7794 int rc = VINF_SUCCESS;
7795 uint32_t u32CRC = RTCrc32Start();
7796 while (cb > 0)
7797 {
7798 /* read chunk */
7799 size_t cbToRead = cbBuf;
7800 if (cb < cbBuf)
7801 cbToRead = cb;
7802 rc = ssmR3StrmPeekAt(pStrm, off, pvBuf, cbToRead, NULL);
7803 if (RT_FAILURE(rc))
7804 {
7805 AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
7806 RTMemTmpFree(pvBuf);
7807 return rc;
7808 }
7809
7810 /* advance */
7811 cb -= cbToRead;
7812 off += cbToRead;
7813
7814 /* calc crc32. */
7815 u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
7816 }
7817 RTMemTmpFree(pvBuf);
7818
7819 /* store the calculated crc */
7820 u32CRC = RTCrc32Finish(u32CRC);
7821 Log(("SSM: u32CRC=0x%08x\n", u32CRC));
7822 *pu32CRC = u32CRC;
7823
7824 return VINF_SUCCESS;
7825}
7826
7827
7828/**
[23593]7829 * Validates a version 2 footer.
7830 *
7831 * @returns VBox status code.
7832 *
7833 * @param pFooter The footer.
7834 * @param offFooter The stream offset of the footer.
7835 * @param cDirEntries The number of directory entries. UINT32_MAX if
7836 * unknown.
7837 * @param fStreamCrc32 Whether the stream is checksummed using CRC-32.
7838 * @param u32StreamCRC The stream checksum.
7839 */
7840static int ssmR3ValidateFooter(PSSMFILEFTR pFooter, uint64_t offFooter, uint32_t cDirEntries, bool fStreamCrc32, uint32_t u32StreamCRC)
7841{
7842 if (memcmp(pFooter->szMagic, SSMFILEFTR_MAGIC, sizeof(pFooter->szMagic)))
7843 {
7844 LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(pFooter->szMagic), &pFooter->szMagic[0]));
7845 return VERR_SSM_INTEGRITY_FOOTER;
7846 }
7847 SSM_CHECK_CRC32_RET(pFooter, sizeof(*pFooter), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
7848 if (pFooter->offStream != offFooter)
7849 {
7850 LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", pFooter->offStream, offFooter));
7851 return VERR_SSM_INTEGRITY_FOOTER;
7852 }
7853 if (pFooter->u32Reserved)
7854 {
7855 LogRel(("SSM: Reserved footer field isn't zero: %08x\n", pFooter->u32Reserved));
7856 return VERR_SSM_INTEGRITY_FOOTER;
7857 }
7858 if (cDirEntries != UINT32_MAX)
7859 AssertLogRelMsgReturn(pFooter->cDirEntries == cDirEntries,
7860 ("Footer: cDirEntries=%#x, expected %#x\n", pFooter->cDirEntries, cDirEntries),
7861 VERR_SSM_INTEGRITY_FOOTER);
7862 else
7863 AssertLogRelMsgReturn(pFooter->cDirEntries < _64K,
7864 ("Footer: cDirEntries=%#x\n", pFooter->cDirEntries),
7865 VERR_SSM_INTEGRITY_FOOTER);
7866 if ( !fStreamCrc32
7867 && pFooter->u32StreamCRC)
7868 {
7869 LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
7870 return VERR_SSM_INTEGRITY_FOOTER;
7871 }
7872 if ( fStreamCrc32
7873 && pFooter->u32StreamCRC != u32StreamCRC)
7874 {
7875 LogRel(("SSM: Bad stream CRC: %#x, expected %#x.\n", pFooter->u32StreamCRC, u32StreamCRC));
7876 return VERR_SSM_INTEGRITY_CRC;
7877 }
7878 return VINF_SUCCESS;
7879}
7880
7881
7882/**
[22554]7883 * Validates the header information stored in the handle.
7884 *
7885 * @returns VBox status code.
7886 *
7887 * @param pSSM The handle.
7888 * @param fHaveHostBits Set if the host bits field is valid.
7889 * @param fHaveVersion Set if we have a version.
7890 */
7891static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
7892{
7893 Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
7894 Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
7895 Assert(pSSM->u.Read.uFmtVerMinor <= 2);
7896
7897 if (fHaveVersion)
7898 {
7899 if ( pSSM->u.Read.u16VerMajor == 0
7900 || pSSM->u.Read.u16VerMajor > 1000
7901 || pSSM->u.Read.u16VerMinor > 1000
7902 || pSSM->u.Read.u32VerBuild > _1M
7903 || pSSM->u.Read.u32SvnRev == 0
7904 || pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
7905 {
7906 LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
7907 pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
7908 return VERR_SSM_INTEGRITY_VBOX_VERSION;
7909 }
7910 }
7911 else
7912 AssertLogRelReturn( pSSM->u.Read.u16VerMajor == 0
7913 && pSSM->u.Read.u16VerMinor == 0
7914 && pSSM->u.Read.u32VerBuild == 0
7915 && pSSM->u.Read.u32SvnRev == 0,
7916 VERR_SSM_INTEGRITY_VBOX_VERSION);
7917
7918 if (fHaveHostBits)
7919 {
7920 if ( pSSM->u.Read.cHostBits != 32
7921 && pSSM->u.Read.cHostBits != 64)
7922 {
7923 LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
7924 return VERR_SSM_INTEGRITY_HEADER;
7925 }
7926 }
7927 else
7928 AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_HEADER);
7929
7930 if ( pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
7931 && pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
7932 {
7933 LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
7934 return VERR_SSM_INTEGRITY_HEADER;
7935 }
7936 if ( pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
7937 && pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
7938 {
7939 LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
7940 return VERR_SSM_INTEGRITY_HEADER;
7941 }
7942
7943 return VINF_SUCCESS;
7944}
7945
7946
7947/**
7948 * Reads the header, detects the format version and performs integrity
7949 * validations.
7950 *
[58170]7951 * @returns VBox status code.
[23540]7952 * @param pSSM The saved state handle. A number of field will
7953 * be updated, mostly header related information.
7954 * fLiveSave is also set if appropriate.
[22554]7955 * @param fChecksumIt Whether to checksum the file or not. This will
7956 * be ignored if it the stream isn't a file.
7957 * @param fChecksumOnRead Whether to validate the checksum while reading
7958 * the stream instead of up front. If not possible,
7959 * verify the checksum up front.
7960 */
7961static int ssmR3HeaderAndValidate(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
7962{
7963 /*
7964 * Read and check the header magic.
7965 */
7966 union
7967 {
7968 SSMFILEHDR v2_0;
7969 SSMFILEHDRV12 v1_2;
7970 SSMFILEHDRV11 v1_1;
7971 } uHdr;
7972 int rc = ssmR3StrmRead(&pSSM->Strm, &uHdr, sizeof(uHdr.v2_0.szMagic));
7973 if (RT_FAILURE(rc))
7974 {
7975 LogRel(("SSM: Failed to read file magic header. rc=%Rrc\n", rc));
7976 return rc;
7977 }
7978 if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
7979 {
7980 Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
7981 return VERR_SSM_INTEGRITY_MAGIC;
7982 }
7983
7984 /*
7985 * Find the header size and read the rest.
7986 */
7987 static const struct
7988 {
7989 char szMagic[sizeof(SSMFILEHDR_MAGIC_V2_0)];
[26526]7990 uint32_t cbHdr;
[22554]7991 unsigned uFmtVerMajor;
7992 unsigned uFmtVerMinor;
7993 } s_aVers[] =
7994 {
7995 { SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR), 2, 0 },
7996 { SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDRV12), 1, 2 },
7997 { SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDRV11), 1, 1 },
7998 };
7999 int iVer = RT_ELEMENTS(s_aVers);
8000 while (iVer-- > 0)
8001 if (!memcmp(uHdr.v2_0.szMagic, s_aVers[iVer].szMagic, sizeof(uHdr.v2_0.szMagic)))
8002 break;
8003 if (iVer < 0)
8004 {
8005 Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
8006 return VERR_SSM_INTEGRITY_VERSION;
8007 }
8008 pSSM->u.Read.uFmtVerMajor = s_aVers[iVer].uFmtVerMajor;
8009 pSSM->u.Read.uFmtVerMinor = s_aVers[iVer].uFmtVerMinor;
8010 pSSM->u.Read.cbFileHdr = s_aVers[iVer].cbHdr;
8011
8012 rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)&uHdr + sizeof(uHdr.v2_0.szMagic), pSSM->u.Read.cbFileHdr - sizeof(uHdr.v2_0.szMagic));
8013 if (RT_FAILURE(rc))
8014 {
8015 LogRel(("SSM: Failed to read the file header. rc=%Rrc\n", rc));
8016 return rc;
8017 }
8018
8019 /*
8020 * Make version specific adjustments.
8021 */
8022 if (pSSM->u.Read.uFmtVerMajor >= 2)
8023 {
8024 /*
8025 * Version 2.0 and later.
8026 */
8027 if (pSSM->u.Read.uFmtVerMinor == 0)
8028 {
8029 /* validate the header. */
8030 SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
8031 if (uHdr.v2_0.u8Reserved)
8032 {
8033 LogRel(("SSM: Reserved header field isn't zero: %02x\n", uHdr.v2_0.u8Reserved));
8034 return VERR_SSM_INTEGRITY;
8035 }
[23540]8036 if (uHdr.v2_0.fFlags & ~(SSMFILEHDR_FLAGS_STREAM_CRC32 | SSMFILEHDR_FLAGS_STREAM_LIVE_SAVE))
[22554]8037 {
8038 LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
8039 return VERR_SSM_INTEGRITY;
8040 }
8041 if ( uHdr.v2_0.cbMaxDecompr > sizeof(pSSM->u.Read.abDataBuffer)
8042 || uHdr.v2_0.cbMaxDecompr < _1K
8043 || (uHdr.v2_0.cbMaxDecompr & 0xff) != 0)
8044 {
8045 LogRel(("SSM: The cbMaxDecompr header field is out of range: %#x\n", uHdr.v2_0.cbMaxDecompr));
8046 return VERR_SSM_INTEGRITY;
8047 }
8048
8049 /* set the header info. */
8050 pSSM->u.Read.cHostBits = uHdr.v2_0.cHostBits;
8051 pSSM->u.Read.u16VerMajor = uHdr.v2_0.u16VerMajor;
8052 pSSM->u.Read.u16VerMinor = uHdr.v2_0.u16VerMinor;
8053 pSSM->u.Read.u32VerBuild = uHdr.v2_0.u32VerBuild;
8054 pSSM->u.Read.u32SvnRev = uHdr.v2_0.u32SvnRev;
8055 pSSM->u.Read.cbGCPhys = uHdr.v2_0.cbGCPhys;
8056 pSSM->u.Read.cbGCPtr = uHdr.v2_0.cbGCPtr;
[23540]8057 pSSM->u.Read.fFixedGCPtrSize= true;
[23593]8058 pSSM->u.Read.fStreamCrc32 = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
[23540]8059 pSSM->fLiveSave = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_LIVE_SAVE);
[22554]8060 }
8061 else
[39402]8062 AssertFailedReturn(VERR_SSM_IPE_2);
[23593]8063 if (!pSSM->u.Read.fStreamCrc32)
[22554]8064 ssmR3StrmDisableChecksumming(&pSSM->Strm);
8065
8066 /*
8067 * Read and validate the footer if it's a file.
8068 */
8069 if (ssmR3StrmIsFile(&pSSM->Strm))
8070 {
8071 SSMFILEFTR Footer;
8072 uint64_t offFooter;
8073 rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(SSMFILEFTR), &Footer, sizeof(Footer), &offFooter);
8074 AssertLogRelRCReturn(rc, rc);
8075
[23593]8076 rc = ssmR3ValidateFooter(&Footer, offFooter, UINT32_MAX, pSSM->u.Read.fStreamCrc32, Footer.u32StreamCRC);
8077 if (RT_FAILURE(rc))
8078 return rc;
8079
[22554]8080 pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
8081 pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
8082 }
8083 else
8084 {
8085 pSSM->u.Read.cbLoadFile = UINT64_MAX;
8086 pSSM->u.Read.u32LoadCRC = 0;
8087 }
8088
8089 /*
8090 * Validate the header info we've set in the handle.
8091 */
8092 rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
8093 if (RT_FAILURE(rc))
8094 return rc;
8095
8096 /*
8097 * Check the checksum if that's called for and possible.
8098 */
[23593]8099 if ( pSSM->u.Read.fStreamCrc32
[22554]8100 && fChecksumIt
8101 && !fChecksumOnRead
8102 && ssmR3StrmIsFile(&pSSM->Strm))
8103 {
8104 uint32_t u32CRC;
8105 rc = ssmR3CalcChecksum(&pSSM->Strm, 0, pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR), &u32CRC);
8106 if (RT_FAILURE(rc))
8107 return rc;
8108 if (u32CRC != pSSM->u.Read.u32LoadCRC)
8109 {
8110 LogRel(("SSM: Invalid CRC! Calculated %#010x, in footer %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
8111 return VERR_SSM_INTEGRITY_CRC;
8112 }
8113 }
8114 }
8115 else
8116 {
8117 /*
8118 * Version 1.x of the format.
8119 */
8120 bool fHaveHostBits = true;
8121 bool fHaveVersion = false;
8122 RTUUID MachineUuidFromHdr;
8123
8124 ssmR3StrmDisableChecksumming(&pSSM->Strm);
8125 if (pSSM->u.Read.uFmtVerMinor == 1)
8126 {
8127 pSSM->u.Read.cHostBits = 0; /* unknown */
8128 pSSM->u.Read.u16VerMajor = 0;
8129 pSSM->u.Read.u16VerMinor = 0;
8130 pSSM->u.Read.u32VerBuild = 0;
8131 pSSM->u.Read.u32SvnRev = 0;
8132 pSSM->u.Read.cbLoadFile = uHdr.v1_1.cbFile;
8133 pSSM->u.Read.u32LoadCRC = uHdr.v1_1.u32CRC;
8134 pSSM->u.Read.cbGCPhys = sizeof(RTGCPHYS);
8135 pSSM->u.Read.cbGCPtr = sizeof(RTGCPTR);
8136 pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
[23593]8137 pSSM->u.Read.fStreamCrc32 = false;
[22554]8138
8139 MachineUuidFromHdr = uHdr.v1_1.MachineUuid;
8140 fHaveHostBits = false;
8141 }
8142 else if (pSSM->u.Read.uFmtVerMinor == 2)
8143 {
8144 pSSM->u.Read.cHostBits = uHdr.v1_2.cHostBits;
8145 pSSM->u.Read.u16VerMajor = uHdr.v1_2.u16VerMajor;
8146 pSSM->u.Read.u16VerMinor = uHdr.v1_2.u16VerMinor;
8147 pSSM->u.Read.u32VerBuild = uHdr.v1_2.u32VerBuild;
8148 pSSM->u.Read.u32SvnRev = uHdr.v1_2.u32SvnRev;
8149 pSSM->u.Read.cbLoadFile = uHdr.v1_2.cbFile;
8150 pSSM->u.Read.u32LoadCRC = uHdr.v1_2.u32CRC;
8151 pSSM->u.Read.cbGCPhys = uHdr.v1_2.cbGCPhys;
8152 pSSM->u.Read.cbGCPtr = uHdr.v1_2.cbGCPtr;
8153 pSSM->u.Read.fFixedGCPtrSize = true;
[23593]8154 pSSM->u.Read.fStreamCrc32 = false;
[22554]8155
8156 MachineUuidFromHdr = uHdr.v1_2.MachineUuid;
8157 fHaveVersion = true;
8158 }
8159 else
[39402]8160 AssertFailedReturn(VERR_SSM_IPE_1);
[22554]8161
8162 /*
8163 * The MachineUuid must be NULL (was never used).
8164 */
8165 if (!RTUuidIsNull(&MachineUuidFromHdr))
8166 {
8167 LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
8168 return VERR_SMM_INTEGRITY_MACHINE;
8169 }
8170
8171 /*
8172 * Verify the file size.
8173 */
8174 uint64_t cbFile = ssmR3StrmGetSize(&pSSM->Strm);
8175 if (cbFile != pSSM->u.Read.cbLoadFile)
8176 {
8177 LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
8178 return VERR_SSM_INTEGRITY_SIZE;
8179 }
8180
8181 /*
8182 * Validate the header info we've set in the handle.
8183 */
8184 rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
8185 if (RT_FAILURE(rc))
8186 return rc;
8187
8188 /*
8189 * Verify the checksum if requested.
8190 *
8191 * Note! The checksum is not actually generated for the whole file,
8192 * this is of course a bug in the v1.x code that we cannot do
8193 * anything about.
8194 */
8195 if ( fChecksumIt
8196 || fChecksumOnRead)
8197 {
8198 uint32_t u32CRC;
8199 rc = ssmR3CalcChecksum(&pSSM->Strm,
[73097]8200 RT_UOFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC),
[22554]8201 cbFile - pSSM->u.Read.cbFileHdr,
8202 &u32CRC);
8203 if (RT_FAILURE(rc))
8204 return rc;
8205 if (u32CRC != pSSM->u.Read.u32LoadCRC)
8206 {
8207 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
8208 return VERR_SSM_INTEGRITY_CRC;
8209 }
8210 }
8211 }
8212
8213 return VINF_SUCCESS;
8214}
8215
8216
8217/**
8218 * Open a saved state for reading.
8219 *
8220 * The file will be positioned at the first data unit upon successful return.
8221 *
8222 * @returns VBox status code.
8223 *
[58122]8224 * @param pVM The cross context VM structure.
[23593]8225 * @param pszFilename The filename. NULL if pStreamOps is used.
8226 * @param pStreamOps The stream method table. NULL if pszFilename is
8227 * used.
8228 * @param pvUser The user argument to the stream methods.
[22554]8229 * @param fChecksumIt Check the checksum for the entire file.
8230 * @param fChecksumOnRead Whether to validate the checksum while reading
8231 * the stream instead of up front. If not possible,
8232 * verify the checksum up front.
8233 * @param pSSM Pointer to the handle structure. This will be
8234 * completely initialized on success.
8235 * @param cBuffers The number of stream buffers.
8236 */
[23593]8237static int ssmR3OpenFile(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvUser,
8238 bool fChecksumIt, bool fChecksumOnRead, uint32_t cBuffers, PSSMHANDLE pSSM)
[22554]8239{
8240 /*
8241 * Initialize the handle.
8242 */
[30396]8243 pSSM->pVM = pVM;
8244 pSSM->enmOp = SSMSTATE_INVALID;
8245 pSSM->enmAfter = SSMAFTER_INVALID;
8246 pSSM->fCancelled = SSMHANDLE_OK;
8247 pSSM->rc = VINF_SUCCESS;
8248 pSSM->cbUnitLeftV1 = 0;
8249 pSSM->offUnit = UINT64_MAX;
[42335]8250 pSSM->offUnitUser = UINT64_MAX;
[30396]8251 pSSM->fLiveSave = false;
8252 pSSM->pfnProgress = NULL;
8253 pSSM->pvUser = NULL;
8254 pSSM->uPercent = 0;
8255 pSSM->offEstProgress = 0;
8256 pSSM->cbEstTotal = 0;
8257 pSSM->offEst = 0;
8258 pSSM->offEstUnitEnd = 0;
8259 pSSM->uPercentLive = 0;
8260 pSSM->uPercentPrepare = 5;
8261 pSSM->uPercentDone = 2;
8262 pSSM->uReportedLivePercent = 0;
8263 pSSM->pszFilename = pszFilename;
[22554]8264
8265 pSSM->u.Read.pZipDecompV1 = NULL;
8266 pSSM->u.Read.uFmtVerMajor = UINT32_MAX;
8267 pSSM->u.Read.uFmtVerMinor = UINT32_MAX;
8268 pSSM->u.Read.cbFileHdr = UINT32_MAX;
8269 pSSM->u.Read.cbGCPhys = UINT8_MAX;
8270 pSSM->u.Read.cbGCPtr = UINT8_MAX;
8271 pSSM->u.Read.fFixedGCPtrSize= false;
[23771]8272 pSSM->u.Read.fIsHostMsc32 = SSM_HOST_IS_MSC_32;
[24843]8273 RT_ZERO(pSSM->u.Read.szHostOSAndArch);
[22554]8274 pSSM->u.Read.u16VerMajor = UINT16_MAX;
8275 pSSM->u.Read.u16VerMinor = UINT16_MAX;
8276 pSSM->u.Read.u32VerBuild = UINT32_MAX;
8277 pSSM->u.Read.u32SvnRev = UINT32_MAX;
8278 pSSM->u.Read.cHostBits = UINT8_MAX;
8279 pSSM->u.Read.cbLoadFile = UINT64_MAX;
8280
8281 pSSM->u.Read.cbRecLeft = 0;
8282 pSSM->u.Read.cbDataBuffer = 0;
8283 pSSM->u.Read.offDataBuffer = 0;
8284 pSSM->u.Read.fEndOfData = 0;
8285 pSSM->u.Read.u8TypeAndFlags = 0;
8286
[24264]8287 pSSM->u.Read.pCurUnit = NULL;
8288 pSSM->u.Read.uCurUnitVer = UINT32_MAX;
8289 pSSM->u.Read.uCurUnitPass = 0;
8290 pSSM->u.Read.fHaveSetError = false;
8291
[22554]8292 /*
8293 * Try open and validate the file.
8294 */
[23593]8295 int rc;
8296 if (pStreamOps)
8297 rc = ssmR3StrmInit(&pSSM->Strm, pStreamOps, pvUser, false /*fWrite*/, fChecksumOnRead, cBuffers);
8298 else
8299 rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, false /*fWrite*/, fChecksumOnRead, cBuffers);
[22554]8300 if (RT_SUCCESS(rc))
8301 {
8302 rc = ssmR3HeaderAndValidate(pSSM, fChecksumIt, fChecksumOnRead);
8303 if (RT_SUCCESS(rc))
8304 return rc;
8305
8306 /* failure path */
[24917]8307 ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED);
[22554]8308 }
8309 else
8310 Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n", pszFilename, rc));
8311 return rc;
8312}
8313
[24575]8314
8315/**
8316 * Verifies the directory.
8317 *
8318 * @returns VBox status code.
8319 *
8320 * @param pDir The full directory.
8321 * @param cbDir The size of the directory.
8322 * @param offDir The directory stream offset.
8323 * @param cDirEntries The directory entry count from the footer.
8324 * @param cbHdr The header size.
8325 * @param uSvnRev The SVN revision that saved the state. Bug detection.
8326 */
8327static int ssmR3ValidateDirectory(PSSMFILEDIR pDir, size_t cbDir, uint64_t offDir, uint32_t cDirEntries,
8328 uint32_t cbHdr, uint32_t uSvnRev)
8329{
8330 AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY_DIR_MAGIC);
8331 SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
8332 AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
8333 ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
8334 VERR_SSM_INTEGRITY_DIR);
[73097]8335 AssertLogRelReturn(RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[pDir->cEntries]) == cbDir, VERR_SSM_INTEGRITY_DIR);
[24575]8336
8337 for (uint32_t i = 0; i < pDir->cEntries; i++)
8338 {
8339 AssertLogRelMsgReturn( ( pDir->aEntries[i].off >= cbHdr
8340 && pDir->aEntries[i].off < offDir)
8341 || ( pDir->aEntries[i].off == 0 /* bug in unreleased code */
8342 && uSvnRev < 53365),
8343 ("off=%#llx cbHdr=%#x offDir=%#llx\n", pDir->aEntries[i].off, cbHdr, offDir),
8344 VERR_SSM_INTEGRITY_DIR);
8345 }
8346 return VINF_SUCCESS;
8347}
8348
[24574]8349#ifndef SSM_STANDALONE
[22554]8350
8351/**
[56965]8352 * LogRel the unit content.
8353 *
8354 * @param pSSM The save state handle.
8355 * @param pUnitHdr The unit head (for cbName).
8356 * @param offUnit The offset of the unit header.
8357 * @param offStart Where to start.
8358 * @param offEnd Where to end.
8359 */
8360static void ssmR3StrmLogUnitContent(PSSMHANDLE pSSM, SSMFILEUNITHDRV2 const *pUnitHdr, uint64_t offUnit,
8361 uint64_t offStart, uint64_t offEnd)
8362{
8363 /*
8364 * Stop the I/O thread (if present).
8365 */
8366 ssmR3StrmStopIoThread(&pSSM->Strm);
8367
8368 /*
8369 * Save the current status, resetting it so we can read + log the unit bytes.
8370 */
8371 int rcSaved = pSSM->rc;
8372 pSSM->rc = VINF_SUCCESS;
8373
8374 /*
8375 * Reverse back to the start of the unit if we can.
8376 */
[73097]8377 uint32_t cbUnitHdr = RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[pUnitHdr->cbName]);
[56965]8378 int rc = ssmR3StrmSeek(&pSSM->Strm, offUnit/* + cbUnitHdr*/, RTFILE_SEEK_BEGIN, pUnitHdr->u32CurStreamCRC);
8379 if (RT_SUCCESS(rc))
8380 {
8381 SSMFILEUNITHDRV2 UnitHdr2;
8382 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr2, cbUnitHdr);
8383 if ( RT_SUCCESS(rc)
8384 && memcmp(&UnitHdr2, pUnitHdr, cbUnitHdr) == 0)
8385 {
8386 pSSM->u.Read.cbDataBuffer = 0; /* avoid assertions */
8387 pSSM->u.Read.cbRecLeft = 0;
8388 ssmR3DataReadBeginV2(pSSM);
8389
8390 /*
8391 * Read the unit, dumping the requested bits.
8392 */
8393 uint8_t cbLine = 0;
8394 uint8_t abLine[16];
8395 uint64_t offCur = 0;
8396 offStart &= ~(uint64_t)(sizeof(abLine) - 1);
8397 Assert(offStart < offEnd);
8398 LogRel(("SSM: Unit '%s' contents:\n", pUnitHdr->szName));
8399
8400 do
8401 {
8402 /*
8403 * Read the next 16 bytes into abLine. We have to take some care to
8404 * get all the bytes in the unit, since we don't really know its size.
8405 */
8406 while ( cbLine < sizeof(abLine)
8407 && !pSSM->u.Read.fEndOfData
8408 && RT_SUCCESS(pSSM->rc))
8409 {
8410 uint32_t cbToRead = sizeof(abLine) - cbLine;
8411 if (cbToRead > 1)
8412 {
8413 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer;
8414 if ((int32_t)cbToRead > cbInBuffer)
8415 {
8416 if (cbInBuffer > 0)
8417 cbToRead = cbInBuffer;
8418 else if (pSSM->u.Read.cbRecLeft)
8419 cbToRead = 1;
8420 else
8421 {
8422 rc = ssmR3DataReadRecHdrV2(pSSM);
8423 if (RT_FAILURE(rc))
8424 {
8425 pSSM->rc = rc;
8426 break;
8427 }
8428 if (pSSM->u.Read.fEndOfData)
8429 break;
8430 }
8431 }
8432 }
8433 rc = ssmR3DataRead(pSSM, &abLine[cbLine], cbToRead);
8434 if (RT_SUCCESS(rc))
8435 cbLine += cbToRead;
8436 else
8437 break;
8438 }
8439
8440 /*
8441 * Display the bytes if in the requested range.
8442 */
8443 if ( offCur >= offStart
8444 && offCur <= offEnd)
8445 {
8446 char szLine[132];
8447 char *pchDst = szLine;
8448 uint8_t offSrc = 0;
8449 while (offSrc < cbLine)
8450 {
8451 static char const s_szHex[17] = "0123456789abcdef";
8452 uint8_t const b = abLine[offSrc++];
8453 *pchDst++ = s_szHex[b >> 4];
[56968]8454 *pchDst++ = s_szHex[b & 0xf];
[56965]8455 *pchDst++ = offSrc != 8 ? ' ' : '-';
8456 }
8457 while (offSrc < sizeof(abLine))
8458 {
8459 *pchDst++ = ' ';
8460 *pchDst++ = ' ';
8461 *pchDst++ = offSrc != 7 ? ' ' : '-';
8462 offSrc++;
8463 }
8464 *pchDst++ = ' ';
8465
8466 offSrc = 0;
8467 while (offSrc < cbLine)
8468 {
8469 char const ch = (int8_t)abLine[offSrc++];
8470 if (ch < 0x20 || ch >= 0x7f)
8471 *pchDst++ = '.';
8472 else
8473 *pchDst++ = ch;
8474 }
8475 *pchDst = '\0';
8476 Assert((uintptr_t)(pchDst - &szLine[0]) < sizeof(szLine));
8477 Assert(strchr(szLine, '\0') == pchDst);
8478
8479 LogRel(("%#010llx: %s\n", offCur, szLine));
8480 }
8481 offCur += cbLine;
8482 cbLine = 0;
8483 } while ( !pSSM->u.Read.fEndOfData
8484 && RT_SUCCESS(pSSM->rc));
8485 LogRel(("SSM: offCur=%#llx fEndOfData=%d (rc=%Rrc)\n", offCur, pSSM->u.Read.fEndOfData, rc));
8486 }
8487 else if (RT_SUCCESS(rc))
8488 LogRel(("SSM: Cannot dump unit - mismatching unit head\n"));
8489 else
8490 LogRel(("SSM: Cannot dump unit - unit header read error: %Rrc\n", rc));
8491 }
8492 else
8493 LogRel(("SSM: Cannot dump unit - ssmR3StrmSeek error: %Rrc\n", rc));
8494
[62657]8495 pSSM->rc = rcSaved;
[56965]8496}
8497
8498
8499/**
[22554]8500 * Find a data unit by name.
8501 *
8502 * @returns Pointer to the unit.
8503 * @returns NULL if not found.
8504 *
[58122]8505 * @param pVM The cross context VM structure.
[22554]8506 * @param pszName Data unit name.
8507 * @param uInstance The data unit instance id.
8508 */
8509static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t uInstance)
8510{
8511 size_t cchName = strlen(pszName);
8512 PSSMUNIT pUnit = pVM->ssm.s.pHead;
8513 while ( pUnit
8514 && ( pUnit->u32Instance != uInstance
8515 || pUnit->cchName != cchName
8516 || memcmp(pUnit->szName, pszName, cchName)))
8517 pUnit = pUnit->pNext;
8518 return pUnit;
8519}
8520
8521
8522/**
8523 * Executes the loading of a V1.X file.
8524 *
8525 * @returns VBox status code.
[58122]8526 * @param pVM The cross context VM structure.
[22554]8527 * @param pSSM The saved state handle.
8528 */
8529static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
8530{
8531 int rc;
8532 char *pszName = NULL;
8533 size_t cchName = 0;
8534 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
8535 for (;;)
8536 {
8537 /*
8538 * Save the current file position and read the data unit header.
8539 */
8540 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
8541 SSMFILEUNITHDRV1 UnitHdr;
[73097]8542 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF(SSMFILEUNITHDRV1, szName));
[22554]8543 if (RT_SUCCESS(rc))
8544 {
8545 /*
8546 * Check the magic and see if it's valid and whether it is a end header or not.
8547 */
8548 if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
8549 {
8550 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
8551 {
8552 Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
8553 /* Complete the progress bar (pending 99% afterwards). */
[30396]8554 ssmR3ProgressByByte(pSSM, pSSM->cbEstTotal - pSSM->offEst);
[22554]8555 break;
8556 }
8557 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
8558 offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
8559 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
8560 break;
8561 }
8562
8563 /*
8564 * Read the name.
8565 * Adjust the name buffer first.
8566 */
8567 if (cchName < UnitHdr.cchName)
8568 {
8569 if (pszName)
8570 RTMemTmpFree(pszName);
8571 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
8572 pszName = (char *)RTMemTmpAlloc(cchName);
8573 }
8574 if (pszName)
8575 {
8576 rc = ssmR3StrmRead(&pSSM->Strm, pszName, UnitHdr.cchName);
8577 if (RT_SUCCESS(rc))
8578 {
8579 if (pszName[UnitHdr.cchName - 1])
8580 {
8581 LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
8582 rc = VERR_SSM_INTEGRITY_UNIT;
8583 break;
8584 }
8585 Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
8586
8587 /*
8588 * Find the data unit in our internal table.
8589 */
8590 PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
8591 if (pUnit)
8592 {
8593 /*
8594 * Call the execute handler.
8595 */
[73097]8596 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_UOFFSETOF_DYN(SSMFILEUNITHDRV1, szName[UnitHdr.cchName]);
[42335]8597 pSSM->offUnit = 0;
8598 pSSM->offUnitUser = 0;
[24264]8599 pSSM->u.Read.uCurUnitVer = UnitHdr.u32Version;
8600 pSSM->u.Read.uCurUnitPass = SSM_PASS_FINAL;
8601 pSSM->u.Read.pCurUnit = pUnit;
[22554]8602 if (!pUnit->u.Common.pfnLoadExec)
8603 {
8604 LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
[23436]8605 pSSM->rc = rc = VERR_SSM_NO_LOAD_EXEC;
[22554]8606 break;
8607 }
[44505]8608 ssmR3UnitCritSectEnter(pUnit);
[22554]8609 switch (pUnit->enmType)
8610 {
8611 case SSMUNITTYPE_DEV:
[22793]8612 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
[22554]8613 break;
8614 case SSMUNITTYPE_DRV:
[22793]8615 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
[22554]8616 break;
[48986]8617 case SSMUNITTYPE_USB:
8618 rc = pUnit->u.Usb.pfnLoadExec(pUnit->u.Usb.pUsbIns, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
8619 break;
[22554]8620 case SSMUNITTYPE_INTERNAL:
[22793]8621 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
[22554]8622 break;
8623 case SSMUNITTYPE_EXTERNAL:
[22793]8624 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PASS_FINAL);
[22554]8625 break;
[22792]8626 default:
[39402]8627 rc = VERR_SSM_IPE_1;
[22792]8628 break;
[22554]8629 }
[44505]8630 ssmR3UnitCritSectLeave(pUnit);
[23436]8631 pUnit->fCalled = true;
8632 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
8633 pSSM->rc = rc;
[22554]8634
8635 /*
8636 * Close the reader stream.
8637 */
[23436]8638 rc = ssmR3DataReadFinishV1(pSSM);
[22554]8639 if (RT_SUCCESS(rc))
8640 {
8641 /*
8642 * Now, we'll check the current position to see if all, or
8643 * more than all, the data was read.
8644 *
8645 * Note! Because of buffering / compression we'll only see the
8646 * really bad ones here.
8647 */
8648 uint64_t off = ssmR3StrmTell(&pSSM->Strm);
8649 int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
8650 if (i64Diff < 0)
8651 {
8652 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
8653 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
[30396]8654 ssmR3ProgressByByte(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
[22554]8655 }
8656 else if (i64Diff > 0)
8657 {
8658 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
[24268]8659 if (!ASMAtomicXchgBool(&pSSM->u.Read.fHaveSetError, true))
[24264]8660 rc = VMSetError(pVM, VERR_SSM_LOADED_TOO_MUCH, RT_SRC_POS,
8661 N_("Unit '%s' read %lld bytes too much"), pszName, i64Diff);
[22554]8662 break;
8663 }
8664
[42335]8665 pSSM->offUnit = UINT64_MAX;
8666 pSSM->offUnitUser = UINT64_MAX;
[22554]8667 }
8668 else
8669 {
8670 LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
8671 pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
[24268]8672 if (!ASMAtomicXchgBool(&pSSM->u.Read.fHaveSetError, true))
[24566]8673 {
[24508]8674 if (rc == VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION)
8675 VMSetError(pVM, rc, RT_SRC_POS, N_("Unsupported version %u of data unit '%s' (instance #%u)"),
8676 UnitHdr.u32Version, UnitHdr.szName, UnitHdr.u32Instance);
8677 else
8678 VMSetError(pVM, rc, RT_SRC_POS, N_("Load exec failed for '%s' instance #%u (version %u)"),
8679 pszName, UnitHdr.u32Instance, UnitHdr.u32Version);
[24566]8680 }
[22554]8681 break;
8682 }
[24264]8683
8684 pSSM->u.Read.pCurUnit = NULL;
8685 pSSM->u.Read.uCurUnitVer = UINT32_MAX;
8686 pSSM->u.Read.uCurUnitPass = 0;
[22554]8687 }
8688 else
8689 {
8690 /*
8691 * SSM unit wasn't found - ignore this when loading for the debugger.
8692 */
8693 LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
8694 rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
8695 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
8696 break;
8697 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
8698 }
8699 }
8700 }
8701 else
8702 rc = VERR_NO_TMP_MEMORY;
8703 }
8704
8705 /*
8706 * I/O errors ends up here (yea, I know, very nice programming).
8707 */
8708 if (RT_FAILURE(rc))
8709 {
8710 LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
8711 break;
8712 }
[22884]8713
8714 /*
8715 * Check for cancellation.
8716 */
8717 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
8718 {
8719 LogRel(("SSM: Cancelled!n"));
8720 rc = pSSM->rc;
8721 if (RT_SUCCESS(pSSM->rc))
8722 pSSM->rc = rc = VERR_SSM_CANCELLED;
8723 break;
8724 }
[22554]8725 }
8726
8727 RTMemTmpFree(pszName);
8728 return rc;
8729}
8730
8731
8732/**
[23593]8733 * Reads and verifies the directory and footer.
8734 *
8735 * @returns VBox status code.
8736 * @param pSSM The saved state handle.
8737 */
8738static int ssmR3LoadDirectoryAndFooter(PSSMHANDLE pSSM)
8739{
8740 /*
8741 * The directory.
8742 *
8743 * Get the header containing the number of entries first. Then read the
8744 * entries and pass the combined block to the validation function.
8745 */
8746 uint64_t off = ssmR3StrmTell(&pSSM->Strm);
[73097]8747 size_t const cbDirHdr = RT_UOFFSETOF(SSMFILEDIR, aEntries);
[23593]8748 SSMFILEDIR DirHdr;
8749 int rc = ssmR3StrmRead(&pSSM->Strm, &DirHdr, cbDirHdr);
8750 if (RT_FAILURE(rc))
8751 return rc;
8752 AssertLogRelMsgReturn(!memcmp(DirHdr.szMagic, SSMFILEDIR_MAGIC, sizeof(DirHdr.szMagic)),
8753 ("Invalid directory magic at %#llx (%lld): %.*Rhxs\n", off, off, sizeof(DirHdr.szMagic), DirHdr.szMagic),
8754 VERR_SSM_INTEGRITY_DIR_MAGIC);
8755 AssertLogRelMsgReturn(DirHdr.cEntries < _64K,
8756 ("Too many directory entries at %#llx (%lld): %#x\n", off, off, DirHdr.cEntries),
8757 VERR_SSM_INTEGRITY_DIR);
8758
[73097]8759 size_t cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[DirHdr.cEntries]);
[23593]8760 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
8761 if (!pDir)
8762 return VERR_NO_TMP_MEMORY;
8763 memcpy(pDir, &DirHdr, cbDirHdr);
8764 rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)pDir + cbDirHdr, cbDir - cbDirHdr);
8765 if (RT_SUCCESS(rc))
8766 rc = ssmR3ValidateDirectory(pDir, cbDir, off, DirHdr.cEntries, pSSM->u.Read.cbFileHdr, pSSM->u.Read.u32SvnRev);
8767 RTMemTmpFree(pDir);
8768 if (RT_FAILURE(rc))
8769 return rc;
8770
8771 /*
8772 * Read and validate the footer.
8773 */
8774 off = ssmR3StrmTell(&pSSM->Strm);
8775 uint32_t u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
8776 SSMFILEFTR Footer;
8777 rc = ssmR3StrmRead(&pSSM->Strm, &Footer, sizeof(Footer));
8778 if (RT_FAILURE(rc))
8779 return rc;
8780 return ssmR3ValidateFooter(&Footer, off, DirHdr.cEntries, pSSM->u.Read.fStreamCrc32, u32StreamCRC);
8781}
8782
8783
8784/**
[22554]8785 * Executes the loading of a V2.X file.
8786 *
[24917]8787 * @returns VBox status code. May or may not set pSSM->rc, the returned
8788 * status code is ALWAYS the more accurate of the two.
[58122]8789 * @param pVM The cross context VM structure.
[22554]8790 * @param pSSM The saved state handle.
8791 */
8792static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
8793{
8794 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
8795 for (;;)
8796 {
8797 /*
8798 * Read the unit header and check its integrity.
8799 */
8800 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
8801 uint32_t u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
8802 SSMFILEUNITHDRV2 UnitHdr;
[73097]8803 int rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF(SSMFILEUNITHDRV2, szName));
[22554]8804 if (RT_FAILURE(rc))
8805 return rc;
8806 if (RT_UNLIKELY( memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
8807 && memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic))))
8808 {
8809 LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
8810 offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
[24268]8811 pSSM->u.Read.fHaveSetError = true;
[22554]8812 return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_MAGIC, RT_SRC_POS,
8813 N_("Unit at %#llx (%lld): Invalid unit magic"), offUnit, offUnit);
8814 }
8815 if (UnitHdr.cbName)
8816 {
8817 AssertLogRelMsgReturn(UnitHdr.cbName <= sizeof(UnitHdr.szName),
8818 ("Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
8819 offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)),
8820 VERR_SSM_INTEGRITY_UNIT);
8821 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr.szName[0], UnitHdr.cbName);
8822 if (RT_FAILURE(rc))
8823 return rc;
8824 AssertLogRelMsgReturn(!UnitHdr.szName[UnitHdr.cbName - 1],
8825 ("Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
8826 offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName),
8827 VERR_SSM_INTEGRITY_UNIT);
8828 }
[73097]8829 SSM_CHECK_CRC32_RET(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
[22554]8830 ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
8831 AssertLogRelMsgReturn(UnitHdr.offStream == offUnit,
8832 ("Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit),
8833 VERR_SSM_INTEGRITY_UNIT);
8834 AssertLogRelMsgReturn(UnitHdr.u32CurStreamCRC == u32CurStreamCRC || !pSSM->Strm.fChecksummed,
8835 ("Unit at %#llx (%lld): Stream CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, UnitHdr.u32CurStreamCRC, u32CurStreamCRC),
8836 VERR_SSM_INTEGRITY_UNIT);
8837 AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags),
8838 VERR_SSM_INTEGRITY_UNIT);
8839 if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)))
8840 {
8841 AssertLogRelMsgReturn( UnitHdr.cbName == 0
8842 && UnitHdr.u32Instance == 0
8843 && UnitHdr.u32Version == 0
[22793]8844 && UnitHdr.u32Pass == SSM_PASS_FINAL,
[22554]8845 ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
8846 VERR_SSM_INTEGRITY_UNIT);
8847
8848 /*
8849 * Complete the progress bar (pending 99% afterwards) and RETURN.
8850 */
8851 Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
[30396]8852 ssmR3ProgressByByte(pSSM, pSSM->cbEstTotal - pSSM->offEst);
[23593]8853 return ssmR3LoadDirectoryAndFooter(pSSM);
[22554]8854 }
8855 AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
8856
[22793]8857 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
8858 offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
[22554]8859
8860 /*
8861 * Find the data unit in our internal table.
8862 */
8863 PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
8864 if (pUnit)
8865 {
8866 /*
8867 * Call the execute handler.
8868 */
8869 AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
8870 ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
8871 VERR_SSM_NO_LOAD_EXEC);
[24264]8872 pSSM->u.Read.uCurUnitVer = UnitHdr.u32Version;
8873 pSSM->u.Read.uCurUnitPass = UnitHdr.u32Pass;
8874 pSSM->u.Read.pCurUnit = pUnit;
[22554]8875 ssmR3DataReadBeginV2(pSSM);
[44505]8876 ssmR3UnitCritSectEnter(pUnit);
[22554]8877 switch (pUnit->enmType)
8878 {
8879 case SSMUNITTYPE_DEV:
[22793]8880 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
[22554]8881 break;
8882 case SSMUNITTYPE_DRV:
[22793]8883 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
[22554]8884 break;
[48986]8885 case SSMUNITTYPE_USB:
8886 rc = pUnit->u.Usb.pfnLoadExec(pUnit->u.Usb.pUsbIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
8887 break;
[22554]8888 case SSMUNITTYPE_INTERNAL:
[22793]8889 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
[22554]8890 break;
8891 case SSMUNITTYPE_EXTERNAL:
[22793]8892 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Pass);
[22554]8893 break;
[22792]8894 default:
[39402]8895 rc = VERR_SSM_IPE_1;
[22792]8896 break;
[22554]8897 }
[44505]8898 ssmR3UnitCritSectLeave(pUnit);
[22554]8899 pUnit->fCalled = true;
[23436]8900 if (RT_FAILURE(rc) && RT_SUCCESS_NP(pSSM->rc))
8901 pSSM->rc = rc;
8902 rc = ssmR3DataReadFinishV2(pSSM);
[22554]8903 if (RT_SUCCESS(rc))
[42335]8904 {
8905 pSSM->offUnit = UINT64_MAX;
8906 pSSM->offUnitUser = UINT64_MAX;
8907 }
[22554]8908 else
8909 {
[22793]8910 LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u, pass %#x): %Rrc\n",
8911 UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Pass, rc));
[56965]8912 LogRel(("SSM: Unit at %#llx, current position: offUnit=%#llx offUnitUser=%#llx\n",
8913 offUnit, pSSM->offUnit, pSSM->offUnitUser));
8914
[24268]8915 if (!ASMAtomicXchgBool(&pSSM->u.Read.fHaveSetError, true))
[24566]8916 {
[24508]8917 if (rc == VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION)
8918 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Unsupported version %u of data unit '%s' (instance #%u, pass %#x)"),
8919 UnitHdr.u32Version, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass);
8920 else
8921 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to load unit '%s'"), UnitHdr.szName);
[24566]8922 }
[56965]8923
8924 /* Try log the unit content, unless it's too big. */
[56966]8925 if (pSSM->offUnitUser < _512K)
[56965]8926 ssmR3StrmLogUnitContent(pSSM, &UnitHdr, offUnit, 0, pSSM->offUnitUser + _16K);
8927 else
8928 ssmR3StrmLogUnitContent(pSSM, &UnitHdr, offUnit, pSSM->offUnitUser - _256K, pSSM->offUnitUser + _16K);
[24264]8929 return rc;
[22554]8930 }
8931 }
8932 else
8933 {
8934 /*
8935 * SSM unit wasn't found - ignore this when loading for the debugger.
8936 */
8937 LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
8938 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
[24268]8939 {
8940 pSSM->u.Read.fHaveSetError = true;
[22554]8941 return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_NOT_FOUND, RT_SRC_POS,
8942 N_("Found no handler for unit '%s' instance #%u"), UnitHdr.szName, UnitHdr.u32Instance);
[24268]8943 }
[22554]8944 SSMR3SkipToEndOfUnit(pSSM);
8945 ssmR3DataReadFinishV2(pSSM);
8946 }
[22884]8947
8948 /*
8949 * Check for cancellation.
8950 */
8951 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
8952 {
8953 LogRel(("SSM: Cancelled!\n"));
8954 if (RT_SUCCESS(pSSM->rc))
8955 pSSM->rc = VERR_SSM_CANCELLED;
8956 return pSSM->rc;
8957 }
[22554]8958 }
8959 /* won't get here */
8960}
8961
8962
8963
8964
8965/**
8966 * Load VM save operation.
8967 *
[58170]8968 * @returns VBox status code.
[22554]8969 *
[58122]8970 * @param pVM The cross context VM structure.
[23593]8971 * @param pszFilename The name of the saved state file. NULL if pStreamOps
8972 * is used.
8973 * @param pStreamOps The stream method table. NULL if pszFilename is
8974 * used.
[23596]8975 * @param pvStreamOpsUser The user argument for the stream methods.
[22554]8976 * @param enmAfter What is planned after a successful load operation.
8977 * Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
8978 * @param pfnProgress Progress callback. Optional.
[23596]8979 * @param pvProgressUser User argument for the progress callback.
[22554]8980 *
8981 * @thread EMT
8982 */
[23593]8983VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
8984 SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser)
[22554]8985{
[23593]8986 LogFlow(("SSMR3Load: pszFilename=%p:{%s} pStreamOps=%p pvStreamOpsUser=%p enmAfter=%d pfnProgress=%p pvProgressUser=%p\n",
8987 pszFilename, pszFilename, pStreamOps, pvStreamOpsUser, enmAfter, pfnProgress, pvProgressUser));
[22792]8988 VM_ASSERT_EMT0(pVM);
[22554]8989
8990 /*
8991 * Validate input.
8992 */
[22559]8993 AssertMsgReturn( enmAfter == SSMAFTER_RESUME
[23801]8994 || enmAfter == SSMAFTER_TELEPORT
[22559]8995 || enmAfter == SSMAFTER_DEBUG_IT,
8996 ("%d\n", enmAfter),
8997 VERR_INVALID_PARAMETER);
[23593]8998 AssertReturn(!pszFilename != !pStreamOps, VERR_INVALID_PARAMETER);
8999 if (pStreamOps)
9000 {
9001 AssertReturn(pStreamOps->u32Version == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
9002 AssertReturn(pStreamOps->u32EndVersion == SSMSTRMOPS_VERSION, VERR_INVALID_MAGIC);
9003 AssertReturn(pStreamOps->pfnWrite, VERR_INVALID_PARAMETER);
9004 AssertReturn(pStreamOps->pfnRead, VERR_INVALID_PARAMETER);
9005 AssertReturn(pStreamOps->pfnSeek, VERR_INVALID_PARAMETER);
9006 AssertReturn(pStreamOps->pfnTell, VERR_INVALID_PARAMETER);
9007 AssertReturn(pStreamOps->pfnSize, VERR_INVALID_PARAMETER);
9008 AssertReturn(pStreamOps->pfnClose, VERR_INVALID_PARAMETER);
9009 }
[22554]9010
9011 /*
9012 * Create the handle and open the file.
9013 */
9014 SSMHANDLE Handle;
[23593]9015 int rc = ssmR3OpenFile(pVM, pszFilename, pStreamOps, pvStreamOpsUser, false /* fChecksumIt */,
9016 true /* fChecksumOnRead */, 8 /*cBuffers*/, &Handle);
[22554]9017 if (RT_SUCCESS(rc))
9018 {
9019 ssmR3StrmStartIoThread(&Handle.Strm);
[22884]9020 ssmR3SetCancellable(pVM, &Handle, true);
[22554]9021
[30396]9022 Handle.enmAfter = enmAfter;
9023 Handle.pfnProgress = pfnProgress;
9024 Handle.pvUser = pvProgressUser;
9025 Handle.uPercentLive = 0;
9026 Handle.uPercentPrepare = 2;
9027 Handle.uPercentDone = 2;
[22554]9028
9029 if (Handle.u.Read.u16VerMajor)
9030 LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
9031 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
9032 Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
9033 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
9034 else
9035 LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
9036 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
9037 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
9038
9039 if (pfnProgress)
[44393]9040 pfnProgress(pVM->pUVM, Handle.uPercent, pvProgressUser);
[22554]9041
9042 /*
9043 * Clear the per unit flags.
9044 */
9045 PSSMUNIT pUnit;
9046 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
9047 pUnit->fCalled = false;
9048
9049 /*
9050 * Do the prepare run.
9051 */
9052 Handle.rc = VINF_SUCCESS;
9053 Handle.enmOp = SSMSTATE_LOAD_PREP;
9054 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
9055 {
9056 if (pUnit->u.Common.pfnLoadPrep)
9057 {
[24264]9058 Handle.u.Read.pCurUnit = pUnit;
[22554]9059 pUnit->fCalled = true;
[44505]9060 ssmR3UnitCritSectEnter(pUnit);
[22554]9061 switch (pUnit->enmType)
9062 {
9063 case SSMUNITTYPE_DEV:
9064 rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
9065 break;
9066 case SSMUNITTYPE_DRV:
9067 rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
9068 break;
[48986]9069 case SSMUNITTYPE_USB:
9070 rc = pUnit->u.Usb.pfnLoadPrep(pUnit->u.Usb.pUsbIns, &Handle);
9071 break;
[22554]9072 case SSMUNITTYPE_INTERNAL:
9073 rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
9074 break;
9075 case SSMUNITTYPE_EXTERNAL:
9076 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
9077 break;
[22792]9078 default:
[39402]9079 rc = VERR_SSM_IPE_1;
[22792]9080 break;
[22554]9081 }
[44505]9082 ssmR3UnitCritSectLeave(pUnit);
[24264]9083 Handle.u.Read.pCurUnit = NULL;
[23436]9084 if (RT_FAILURE(rc) && RT_SUCCESS_NP(Handle.rc))
9085 Handle.rc = rc;
9086 else
9087 rc = Handle.rc;
[22554]9088 if (RT_FAILURE(rc))
9089 {
9090 LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
9091 break;
9092 }
9093 }
9094 }
9095
[30396]9096 /* end of prepare % */
[22554]9097 if (pfnProgress)
[44393]9098 pfnProgress(pVM->pUVM, Handle.uPercentPrepare - 1, pvProgressUser);
[22554]9099 Handle.uPercent = Handle.uPercentPrepare;
9100 Handle.cbEstTotal = Handle.u.Read.cbLoadFile;
9101 Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
9102
9103 /*
9104 * Do the execute run.
9105 */
9106 if (RT_SUCCESS(rc))
9107 {
9108 if (Handle.u.Read.uFmtVerMajor >= 2)
9109 rc = ssmR3LoadExecV2(pVM, &Handle);
9110 else
9111 rc = ssmR3LoadExecV1(pVM, &Handle);
[24264]9112 Handle.u.Read.pCurUnit = NULL;
9113 Handle.u.Read.uCurUnitVer = UINT32_MAX;
9114 Handle.u.Read.uCurUnitPass = 0;
[23593]9115
[22554]9116 /* (progress should be pending 99% now) */
[23593]9117 AssertMsg( Handle.fLiveSave
9118 || RT_FAILURE(rc)
[30396]9119 || Handle.uPercent == 101 - Handle.uPercentDone, ("%d\n", Handle.uPercent));
[22554]9120 }
9121
9122 /*
9123 * Do the done run.
9124 */
9125 Handle.rc = rc;
9126 Handle.enmOp = SSMSTATE_LOAD_DONE;
9127 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
9128 {
9129 if ( pUnit->u.Common.pfnLoadDone
9130 && ( pUnit->fCalled
9131 || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
9132 {
[24264]9133 Handle.u.Read.pCurUnit = pUnit;
[23436]9134 int const rcOld = Handle.rc;
[22554]9135 rc = VINF_SUCCESS;
[44505]9136 ssmR3UnitCritSectEnter(pUnit);
[22554]9137 switch (pUnit->enmType)
9138 {
9139 case SSMUNITTYPE_DEV:
9140 rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
9141 break;
9142 case SSMUNITTYPE_DRV:
9143 rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
9144 break;
[48986]9145 case SSMUNITTYPE_USB:
9146 rc = pUnit->u.Usb.pfnLoadDone(pUnit->u.Usb.pUsbIns, &Handle);
9147 break;
[22554]9148 case SSMUNITTYPE_INTERNAL:
9149 rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
9150 break;
9151 case SSMUNITTYPE_EXTERNAL:
9152 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
9153 break;
[22792]9154 default:
[39402]9155 rc = VERR_SSM_IPE_1;
[22792]9156 break;
[22554]9157 }
[44505]9158 ssmR3UnitCritSectLeave(pUnit);
[24264]9159 Handle.u.Read.pCurUnit = NULL;
[23436]9160 if (RT_SUCCESS(rc) && Handle.rc != rcOld)
9161 rc = Handle.rc;
[22554]9162 if (RT_FAILURE(rc))
9163 {
9164 LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
9165 rc, pUnit->szName, pUnit->u32Instance));
[24268]9166 if (!ASMAtomicXchgBool(&Handle.u.Read.fHaveSetError, true))
9167 VMSetError(pVM, rc, RT_SRC_POS, N_("LoadDone failed with rc=%Rrc for data unit '%s' instance #%u."),
9168 rc, pUnit->szName, pUnit->u32Instance);
[23436]9169 if (RT_SUCCESS_NP(Handle.rc))
[22554]9170 Handle.rc = rc;
9171 }
9172 }
9173 }
9174
9175 /* progress */
9176 if (pfnProgress)
[44393]9177 pfnProgress(pVM->pUVM, 99, pvProgressUser);
[22554]9178
[22884]9179 ssmR3SetCancellable(pVM, &Handle, false);
[24917]9180 ssmR3StrmClose(&Handle.Strm, Handle.rc == VERR_SSM_CANCELLED);
9181 rc = Handle.rc;
[22554]9182 }
9183
9184 /*
9185 * Done
9186 */
9187 if (RT_SUCCESS(rc))
9188 {
9189 /* progress */
9190 if (pfnProgress)
[44393]9191 pfnProgress(pVM->pUVM, 100, pvProgressUser);
[22554]9192 Log(("SSM: Load of '%s' completed!\n", pszFilename));
9193 }
9194 return rc;
9195}
9196
9197
[24575]9198/**
9199 * VMSetError wrapper for load errors that inserts the saved state details.
9200 *
9201 * @returns rc.
9202 * @param pSSM The saved state handle.
9203 * @param rc The status code of the error. Use RT_SRC_POS.
[58116]9204 * @param SRC_POS The source location.
[24575]9205 * @param pszFormat The message format string.
9206 * @param ... Variable argument list.
9207 */
9208VMMR3DECL(int) SSMR3SetLoadError(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
9209{
9210 va_list va;
9211 va_start(va, pszFormat);
9212 rc = SSMR3SetLoadErrorV(pSSM, rc, RT_SRC_POS_ARGS, pszFormat, va);
9213 va_end(va);
9214 return rc;
9215}
[24574]9216
[24575]9217
[22554]9218/**
[24575]9219 * VMSetError wrapper for load errors that inserts the saved state details.
9220 *
9221 * @returns rc.
9222 * @param pSSM The saved state handle.
9223 * @param rc The status code of the error.
[58116]9224 * @param SRC_POS The error location, use RT_SRC_POS.
[24575]9225 * @param pszFormat The message format string.
9226 * @param va Variable argument list.
9227 */
9228VMMR3DECL(int) SSMR3SetLoadErrorV(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
9229{
9230 /*
9231 * Input validations.
9232 */
9233 SSM_ASSERT_READABLE_RET(pSSM);
9234 AssertPtr(pszFormat);
9235 Assert(RT_FAILURE_NP(rc));
9236
9237 /*
9238 * Format the incoming error.
9239 */
9240 char *pszMsg;
9241 RTStrAPrintfV(&pszMsg, pszFormat, va);
9242 if (!pszMsg)
9243 {
9244 VMSetError(pSSM->pVM, VERR_NO_MEMORY, RT_SRC_POS,
9245 N_("SSMR3SetLoadErrorV ran out of memory formatting: %s\n"), pszFormat);
9246 return rc;
9247 }
9248
9249 /*
9250 * Forward to VMSetError with the additional info.
9251 */
9252 PSSMUNIT pUnit = pSSM->u.Read.pCurUnit;
9253 const char *pszName = pUnit ? pUnit->szName : "unknown";
9254 uint32_t uInstance = pUnit ? pUnit->u32Instance : 0;
9255 if ( pSSM->enmOp == SSMSTATE_LOAD_EXEC
9256 && pSSM->u.Read.uCurUnitPass == SSM_PASS_FINAL)
9257 rc = VMSetError(pSSM->pVM, rc, RT_SRC_POS_ARGS, N_("%s#%u: %s [ver=%u pass=final]"),
9258 pszName, uInstance, pszMsg, pSSM->u.Read.uCurUnitVer);
9259 else if (pSSM->enmOp == SSMSTATE_LOAD_EXEC)
9260 rc = VMSetError(pSSM->pVM, rc, RT_SRC_POS_ARGS, N_("%s#%u: %s [ver=%u pass=#%u]"),
9261 pszName, uInstance, pszMsg, pSSM->u.Read.uCurUnitVer, pSSM->u.Read.uCurUnitPass);
9262 else if (pSSM->enmOp == SSMSTATE_LOAD_PREP)
9263 rc = VMSetError(pSSM->pVM, rc, RT_SRC_POS_ARGS, N_("%s#%u: %s [prep]"),
9264 pszName, uInstance, pszMsg);
9265 else if (pSSM->enmOp == SSMSTATE_LOAD_DONE)
9266 rc = VMSetError(pSSM->pVM, rc, RT_SRC_POS_ARGS, N_("%s#%u: %s [done]"),
9267 pszName, uInstance, pszMsg);
9268 else if (pSSM->enmOp == SSMSTATE_OPEN_READ)
9269 rc = VMSetError(pSSM->pVM, rc, RT_SRC_POS_ARGS, N_("%s#%u: %s [read]"),
9270 pszName, uInstance, pszMsg);
9271 else
9272 AssertFailed();
9273 pSSM->u.Read.fHaveSetError = true;
9274 RTStrFree(pszMsg);
9275 return rc;
9276}
9277
9278
9279/**
9280 * SSMR3SetLoadError wrapper that returns VERR_SSM_LOAD_CONFIG_MISMATCH.
9281 *
9282 * @returns VERR_SSM_LOAD_CONFIG_MISMATCH.
9283 * @param pSSM The saved state handle.
[58116]9284 * @param SRC_POS The error location, use RT_SRC_POS.
[24575]9285 * @param pszFormat The message format string.
[58126]9286 * @param ... Variable argument list.
[24575]9287 */
9288VMMR3DECL(int) SSMR3SetCfgError(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...)
9289{
9290 va_list va;
9291 va_start(va, pszFormat);
9292 int rc = SSMR3SetLoadErrorV(pSSM, VERR_SSM_LOAD_CONFIG_MISMATCH, RT_SRC_POS_ARGS, pszFormat, va);
9293 va_end(va);
9294 return rc;
9295}
9296
[80531]9297
9298/**
9299 * SSMR3SetLoadError wrapper that returns VERR_SSM_LOAD_CONFIG_MISMATCH.
9300 *
9301 * @returns VERR_SSM_LOAD_CONFIG_MISMATCH.
9302 * @param pSSM The saved state handle.
9303 * @param SRC_POS The error location, use RT_SRC_POS.
9304 * @param pszFormat The message format string.
9305 * @param va Variable argument list.
9306 */
9307VMMR3DECL(int) SSMR3SetCfgErrorV(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
9308{
9309 return SSMR3SetLoadErrorV(pSSM, VERR_SSM_LOAD_CONFIG_MISMATCH, RT_SRC_POS_ARGS, pszFormat, va);
9310}
9311
[24575]9312#endif /* !SSM_STANDALONE */
9313
9314/**
[22554]9315 * Validates a file as a validate SSM saved state.
9316 *
9317 * This will only verify the file format, the format and content of individual
9318 * data units are not inspected.
9319 *
9320 * @returns VINF_SUCCESS if valid.
9321 * @returns VBox status code on other failures.
9322 *
9323 * @param pszFilename The path to the file to validate.
9324 * @param fChecksumIt Whether to checksum the file or not.
9325 *
9326 * @thread Any.
9327 */
9328VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
9329{
9330 LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
9331
9332 /*
9333 * Try open the file and validate it.
9334 */
9335 SSMHANDLE Handle;
[23593]9336 int rc = ssmR3OpenFile(NULL, pszFilename, NULL /*pStreamOps*/, NULL /*pvUser*/, fChecksumIt,
9337 false /*fChecksumOnRead*/, 1 /*cBuffers*/, &Handle);
[22554]9338 if (RT_SUCCESS(rc))
[24917]9339 ssmR3StrmClose(&Handle.Strm, false /*fCancelled*/);
[22554]9340 else
9341 Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
9342 return rc;
9343}
9344
9345
9346/**
9347 * Opens a saved state file for reading.
9348 *
9349 * @returns VBox status code.
9350 *
9351 * @param pszFilename The path to the saved state file.
9352 * @param fFlags Open flags. Reserved, must be 0.
9353 * @param ppSSM Where to store the SSM handle.
9354 *
9355 * @thread Any.
9356 */
9357VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
9358{
9359 LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
9360
9361 /*
9362 * Validate input.
9363 */
9364 AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
9365 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
9366 AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
9367
9368 /*
9369 * Allocate a handle.
9370 */
9371 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
9372 AssertReturn(pSSM, VERR_NO_MEMORY);
9373
9374 /*
9375 * Try open the file and validate it.
9376 */
[23593]9377 int rc = ssmR3OpenFile(NULL, pszFilename, NULL /*pStreamOps*/, NULL /*pvUser*/, false /*fChecksumIt*/,
9378 true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
[22554]9379 if (RT_SUCCESS(rc))
9380 {
9381 pSSM->enmAfter = SSMAFTER_OPENED;
9382 pSSM->enmOp = SSMSTATE_OPEN_READ;
9383 *ppSSM = pSSM;
9384 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
9385 return VINF_SUCCESS;
9386 }
9387
9388 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
9389 RTMemFree(pSSM);
9390 return rc;
9391
9392}
9393
9394
9395/**
9396 * Closes a saved state file opened by SSMR3Open().
9397 *
9398 * @returns VBox status code.
9399 *
9400 * @param pSSM The SSM handle returned by SSMR3Open().
9401 *
9402 * @thread Any, but the caller is responsible for serializing calls per handle.
9403 */
9404VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
9405{
9406 LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
9407
9408 /*
9409 * Validate input.
9410 */
9411 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
9412 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
9413 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
[22884]9414 Assert(pSSM->fCancelled == SSMHANDLE_OK);
[22554]9415
9416 /*
9417 * Close the stream and free the handle.
9418 */
[24917]9419 int rc = ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED);
[22554]9420 if (pSSM->u.Read.pZipDecompV1)
9421 {
9422 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
9423 pSSM->u.Read.pZipDecompV1 = NULL;
9424 }
9425 RTMemFree(pSSM);
9426 return rc;
9427}
9428
9429
9430/**
9431 * Worker for SSMR3Seek that seeks version 1 saved state files.
9432 *
9433 * @returns VBox status code.
9434 * @param pSSM The SSM handle.
9435 * @param pszUnit The unit to seek to.
[33540]9436 * @param iInstance The particular instance we seek.
[22554]9437 * @param piVersion Where to store the unit version number.
9438 */
9439static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
9440{
9441 /*
9442 * Walk the data units until we find EOF or a match.
9443 */
9444 size_t cbUnitNm = strlen(pszUnit) + 1;
9445 AssertLogRelReturn(cbUnitNm <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
9446 char szName[SSM_MAX_NAME_SIZE];
9447 SSMFILEUNITHDRV1 UnitHdr;
9448 for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
9449 {
9450 /*
9451 * Read the unit header and verify it.
9452 */
[73097]9453 int rc = ssmR3StrmPeekAt(&pSSM->Strm, off, &UnitHdr, RT_UOFFSETOF(SSMFILEUNITHDRV1, szName), NULL);
[22554]9454 AssertRCReturn(rc, rc);
9455 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
9456 {
9457 /*
9458 * Does what we've got match, if so read the name.
9459 */
9460 if ( UnitHdr.u32Instance == iInstance
9461 && UnitHdr.cchName == cbUnitNm)
9462 {
[73097]9463 rc = ssmR3StrmPeekAt(&pSSM->Strm, off + RT_UOFFSETOF(SSMFILEUNITHDRV1, szName), szName, cbUnitNm, NULL);
[22554]9464 AssertRCReturn(rc, rc);
9465 AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
9466 (" Unit name '%.*s' was not properly terminated.\n", cbUnitNm, szName),
9467 VERR_SSM_INTEGRITY_UNIT);
9468
9469 /*
9470 * Does the name match?
9471 */
9472 if (!memcmp(szName, pszUnit, cbUnitNm))
9473 {
[73097]9474 rc = ssmR3StrmSeek(&pSSM->Strm, off + RT_UOFFSETOF(SSMFILEUNITHDRV1, szName) + cbUnitNm, RTFILE_SEEK_BEGIN, 0);
9475 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_UOFFSETOF_DYN(SSMFILEUNITHDRV1, szName[cbUnitNm]);
[42335]9476 pSSM->offUnit = 0;
9477 pSSM->offUnitUser = 0;
[22554]9478 if (piVersion)
9479 *piVersion = UnitHdr.u32Version;
9480 return VINF_SUCCESS;
9481 }
9482 }
9483 }
9484 else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
9485 return VERR_SSM_UNIT_NOT_FOUND;
9486 else
9487 AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
9488 off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
9489 VERR_SSM_INTEGRITY_UNIT_MAGIC);
9490 }
9491 /* won't get here. */
9492}
9493
9494
9495/**
9496 * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
9497 *
9498 * @returns VBox status code.
9499 * @param pSSM The SSM handle.
9500 * @param pDir The directory buffer.
9501 * @param cbDir The size of the directory.
9502 * @param cDirEntries The number of directory entries.
9503 * @param offDir The directory offset in the file.
9504 * @param pszUnit The unit to seek to.
[33540]9505 * @param iInstance The particular instance we seek.
[22554]9506 * @param piVersion Where to store the unit version number.
9507 */
9508static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries, uint64_t offDir,
9509 const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
9510{
9511 /*
9512 * Read it.
9513 */
9514 int rc = ssmR3StrmPeekAt(&pSSM->Strm, offDir, pDir, cbDir, NULL);
9515 AssertLogRelRCReturn(rc, rc);
[26526]9516 rc = ssmR3ValidateDirectory(pDir, (uint32_t)cbDir, offDir, cDirEntries, pSSM->u.Read.cbFileHdr, pSSM->u.Read.u32SvnRev);
[23593]9517 if (RT_FAILURE(rc))
9518 return rc;
[22554]9519
9520 /*
9521 * Search the directory.
9522 */
9523 size_t cbUnitNm = strlen(pszUnit) + 1;
9524 uint32_t const u32NameCRC = RTCrc32(pszUnit, cbUnitNm - 1);
9525 for (uint32_t i = 0; i < cDirEntries; i++)
9526 {
9527 if ( pDir->aEntries[i].u32NameCRC == u32NameCRC
[23593]9528 && pDir->aEntries[i].u32Instance == iInstance
[23649]9529 && pDir->aEntries[i].off != 0 /* bug in unreleased code */
[23593]9530 )
[22554]9531 {
9532 /*
9533 * Read and validate the unit header.
9534 */
9535 SSMFILEUNITHDRV2 UnitHdr;
9536 size_t cbToRead = sizeof(UnitHdr);
9537 if (pDir->aEntries[i].off + cbToRead > offDir)
9538 {
9539 cbToRead = offDir - pDir->aEntries[i].off;
9540 RT_ZERO(UnitHdr);
9541 }
9542 rc = ssmR3StrmPeekAt(&pSSM->Strm, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
9543 AssertLogRelRCReturn(rc, rc);
9544
9545 AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
9546 ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
9547 VERR_SSM_INTEGRITY_UNIT);
9548 AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
9549 ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
9550 VERR_SSM_INTEGRITY_UNIT);
9551 AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
9552 ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
9553 i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
9554 VERR_SSM_INTEGRITY_UNIT);
[73097]9555 uint32_t cbUnitHdr = RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]);
[22554]9556 AssertLogRelMsgReturn( UnitHdr.cbName > 0
9557 && UnitHdr.cbName < sizeof(UnitHdr)
9558 && cbUnitHdr <= cbToRead,
9559 ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
9560 VERR_SSM_INTEGRITY_UNIT);
[73097]9561 SSM_CHECK_CRC32_RET(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
[22554]9562 ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
9563 i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
9564
9565 /*
9566 * Ok, it is valid, get on with the comparing now.
9567 */
9568 if ( UnitHdr.cbName == cbUnitNm
9569 && !memcmp(UnitHdr.szName, pszUnit, cbUnitNm))
9570 {
9571 if (piVersion)
9572 *piVersion = UnitHdr.u32Version;
9573 rc = ssmR3StrmSeek(&pSSM->Strm, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN,
9574 RTCrc32Process(UnitHdr.u32CurStreamCRC, &UnitHdr, cbUnitHdr));
9575 AssertLogRelRCReturn(rc, rc);
9576 ssmR3DataReadBeginV2(pSSM);
9577 return VINF_SUCCESS;
9578 }
9579 }
9580 }
9581
9582 return VERR_SSM_UNIT_NOT_FOUND;
9583}
9584
9585
9586/**
9587 * Worker for SSMR3Seek that seeks version 2 saved state files.
9588 *
9589 * @returns VBox status code.
9590 * @param pSSM The SSM handle.
9591 * @param pszUnit The unit to seek to.
[33540]9592 * @param iInstance The particular instance we seek.
[22554]9593 * @param piVersion Where to store the unit version number.
9594 */
9595static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
9596{
9597 /*
9598 * Read the footer, allocate a temporary buffer for the dictionary and
9599 * pass it down to a worker to simplify cleanup.
9600 */
9601 uint64_t offFooter;
9602 SSMFILEFTR Footer;
9603 int rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(Footer), &Footer, sizeof(Footer), &offFooter);
9604 AssertLogRelRCReturn(rc, rc);
9605 AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
9606 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
9607
[73097]9608 size_t const cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[Footer.cDirEntries]);
[22554]9609 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
9610 if (RT_UNLIKELY(!pDir))
9611 return VERR_NO_TMP_MEMORY;
9612 rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, offFooter - cbDir,
9613 pszUnit, iInstance, piVersion);
9614 RTMemTmpFree(pDir);
9615
9616 return rc;
9617}
9618
9619
9620/**
9621 * Seeks to a specific data unit.
9622 *
9623 * After seeking it's possible to use the getters to on
9624 * that data unit.
9625 *
9626 * @returns VBox status code.
9627 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
9628 *
9629 * @param pSSM The SSM handle returned by SSMR3Open().
9630 * @param pszUnit The name of the data unit.
9631 * @param iInstance The instance number.
9632 * @param piVersion Where to store the version number. (Optional)
9633 *
9634 * @thread Any, but the caller is responsible for serializing calls per handle.
9635 */
9636VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
9637{
9638 LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
9639 pSSM, pszUnit, pszUnit, iInstance, piVersion));
9640
9641 /*
9642 * Validate input.
9643 */
9644 AssertPtrReturn(pSSM, VERR_INVALID_PARAMETER);
9645 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
9646 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
9647 AssertPtrReturn(pszUnit, VERR_INVALID_POINTER);
9648 AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
9649
9650 /*
9651 * Reset the state.
9652 */
9653 if (pSSM->u.Read.pZipDecompV1)
9654 {
9655 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
9656 pSSM->u.Read.pZipDecompV1 = NULL;
9657 }
9658 pSSM->cbUnitLeftV1 = 0;
9659 pSSM->offUnit = UINT64_MAX;
[42335]9660 pSSM->offUnitUser = UINT64_MAX;
[22554]9661
9662 /*
9663 * Call the version specific workers.
9664 */
9665 if (pSSM->u.Read.uFmtVerMajor >= 2)
9666 pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
9667 else
9668 pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
9669 return pSSM->rc;
9670}
9671
9672
9673
9674/* ... Misc APIs ... */
9675/* ... Misc APIs ... */
9676/* ... Misc APIs ... */
9677/* ... Misc APIs ... */
9678/* ... Misc APIs ... */
9679/* ... Misc APIs ... */
9680/* ... Misc APIs ... */
9681/* ... Misc APIs ... */
9682/* ... Misc APIs ... */
9683/* ... Misc APIs ... */
9684/* ... Misc APIs ... */
9685
9686
9687
9688/**
[1]9689 * Query what the VBox status code of the operation is.
9690 *
9691 * This can be used for putting and getting a batch of values
9692 * without bother checking the result till all the calls have
9693 * been made.
9694 *
9695 * @returns SSMAFTER enum value.
[23764]9696 * @param pSSM The saved state handle.
[1]9697 */
[12989]9698VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
[1]9699{
[23540]9700 SSM_ASSERT_VALID_HANDLE(pSSM);
[1]9701 return pSSM->rc;
9702}
9703
[13594]9704
[1]9705/**
9706 * Fail the load operation.
9707 *
9708 * This is mainly intended for sub item loaders (like timers) which
9709 * return code isn't necessarily heeded by the caller but is important
9710 * to SSM.
9711 *
[22884]9712 * @returns VBox status code of the handle, or VERR_INVALID_PARAMETER.
[23764]9713 * @param pSSM The saved state handle.
[1]9714 * @param iStatus Failure status code. This MUST be a VERR_*.
9715 */
[12989]9716VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
[1]9717{
[23540]9718 SSM_ASSERT_VALID_HANDLE(pSSM);
[22792]9719 Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE);
[13816]9720 if (RT_FAILURE(iStatus))
[1]9721 {
[22884]9722 int rc = pSSM->rc;
9723 if (RT_SUCCESS(rc))
9724 pSSM->rc = rc = iStatus;
9725 return rc;
[1]9726 }
[13818]9727 AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
[1]9728 return VERR_INVALID_PARAMETER;
9729}
9730
9731
9732/**
[18045]9733 * Get what to do after this operation.
[1]9734 *
9735 * @returns SSMAFTER enum value.
[23764]9736 * @param pSSM The saved state handle.
[1]9737 */
[12989]9738VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
[1]9739{
[23540]9740 SSM_ASSERT_VALID_HANDLE(pSSM);
[1]9741 return pSSM->enmAfter;
9742}
9743
[18045]9744
9745/**
[23540]9746 * Checks if it is a live save operation or not.
[20114]9747 *
[23540]9748 * @returns True if it is, false if it isn't.
[23764]9749 * @param pSSM The saved state handle.
[18045]9750 */
[23540]9751VMMR3DECL(bool) SSMR3HandleIsLiveSave(PSSMHANDLE pSSM)
[18045]9752{
[23540]9753 SSM_ASSERT_VALID_HANDLE(pSSM);
9754 return pSSM->fLiveSave;
[18045]9755}
9756
[22884]9757
9758/**
[24874]9759 * Gets the maximum downtime for a live operation.
9760 *
9761 * @returns The max downtime in milliseconds. Can be anything from 0 thru
9762 * UINT32_MAX.
9763 *
9764 * @param pSSM The saved state handle.
9765 */
9766VMMR3DECL(uint32_t) SSMR3HandleMaxDowntime(PSSMHANDLE pSSM)
9767{
9768 SSM_ASSERT_VALID_HANDLE(pSSM);
9769 if (pSSM->enmOp <= SSMSTATE_SAVE_DONE)
9770 return pSSM->u.Write.cMsMaxDowntime;
9771 return UINT32_MAX;
9772}
9773
9774
9775/**
[23764]9776 * Gets the host bit count of a saved state.
9777 *
9778 * @returns 32 or 64. If pSSM is invalid, 0 is returned.
9779 * @param pSSM The saved state handle.
[24843]9780 *
9781 * @remarks This method should ONLY be used for hacks when loading OLDER saved
[33540]9782 * state that have data layout or semantic changes without the
[24843]9783 * compulsory version number change.
[23764]9784 */
9785VMMR3DECL(uint32_t) SSMR3HandleHostBits(PSSMHANDLE pSSM)
9786{
9787 SSM_ASSERT_VALID_HANDLE(pSSM);
9788 return ssmR3GetHostBits(pSSM);
9789}
9790
9791
[24843]9792/**
9793 * Get the VirtualBox SVN revision that created the saved state.
9794 *
9795 * @returns The revision number on success.
[24845]9796 * form. If we don't know, it's 0.
[24843]9797 * @param pSSM The saved state handle.
9798 *
9799 * @remarks This method should ONLY be used for hacks when loading OLDER saved
[33540]9800 * state that have data layout or semantic changes without the
[24843]9801 * compulsory version number change. Be VERY careful with this
9802 * function since it will return different values for OSE builds!
9803 */
9804VMMR3DECL(uint32_t) SSMR3HandleRevision(PSSMHANDLE pSSM)
9805{
9806 if (pSSM->enmOp >= SSMSTATE_LOAD_PREP)
9807 return pSSM->u.Read.u32SvnRev;
[24845]9808#ifdef SSM_STANDALONE
[24846]9809 return 0;
9810#else
[24843]9811 return VMMGetSvnRev();
[24845]9812#endif
[24843]9813}
9814
9815
9816/**
9817 * Gets the VirtualBox version that created the saved state.
9818 *
9819 * @returns VBOX_FULL_VERSION style version number.
9820 * Returns UINT32_MAX if unknown or somehow out of range.
9821 *
9822 * @param pSSM The saved state handle.
9823 *
9824 * @remarks This method should ONLY be used for hacks when loading OLDER saved
[33540]9825 * state that have data layout or semantic changes without the
[24843]9826 * compulsory version number change.
9827 */
9828VMMR3DECL(uint32_t) SSMR3HandleVersion(PSSMHANDLE pSSM)
9829{
9830 if (pSSM->enmOp >= SSMSTATE_LOAD_PREP)
9831 {
9832 if ( !pSSM->u.Read.u16VerMajor
9833 && !pSSM->u.Read.u16VerMinor
9834 && !pSSM->u.Read.u32VerBuild)
9835 return UINT32_MAX;
9836 AssertReturn(pSSM->u.Read.u16VerMajor <= 0xff, UINT32_MAX);
9837 AssertReturn(pSSM->u.Read.u16VerMinor <= 0xff, UINT32_MAX);
9838 AssertReturn(pSSM->u.Read.u32VerBuild <= 0xffff, UINT32_MAX);
9839 return VBOX_FULL_VERSION_MAKE(pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild);
9840 }
9841 return VBOX_FULL_VERSION;
9842}
9843
9844
9845/**
9846 * Get the host OS and architecture where the saved state was created.
9847 *
9848 * @returns Pointer to a read only string. When known, this is on the os.arch
9849 * form. If we don't know, it's an empty string.
9850 * @param pSSM The saved state handle.
9851 *
9852 * @remarks This method should ONLY be used for hacks when loading OLDER saved
[33540]9853 * state that have data layout or semantic changes without the
[24843]9854 * compulsory version number change.
9855 */
9856VMMR3DECL(const char *) SSMR3HandleHostOSAndArch(PSSMHANDLE pSSM)
9857{
9858 if (pSSM->enmOp >= SSMSTATE_LOAD_PREP)
9859 return pSSM->u.Read.szHostOSAndArch;
9860 return KBUILD_TARGET "." KBUILD_TARGET_ARCH;
9861}
9862
9863
[81049]9864#ifdef DEBUG
9865/**
9866 * Gets current data offset, relative to the start of the unit - only for debugging
9867 */
9868VMMR3DECL(uint64_t) SSMR3HandleTellInUnit(PSSMHANDLE pSSM)
9869{
9870 return ssmR3StrmTell(&pSSM->Strm) - pSSM->offUnitUser;
9871}
9872#endif
9873
9874
[24574]9875#ifndef SSM_STANDALONE
[23764]9876/**
[22884]9877 * Asynchronously cancels the current SSM operation ASAP.
9878 *
9879 * @returns VBox status code.
9880 * @retval VINF_SUCCESS on success.
9881 * @retval VERR_SSM_NO_PENDING_OPERATION if nothing around that can be
9882 * cancelled.
9883 * @retval VERR_SSM_ALREADY_CANCELLED if the operation as already been
9884 * cancelled.
9885 *
[44347]9886 * @param pUVM The VM handle.
[22884]9887 *
9888 * @thread Any.
9889 */
[44347]9890VMMR3DECL(int) SSMR3Cancel(PUVM pUVM)
[22884]9891{
[44347]9892 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
9893 PVM pVM = pUVM->pVM;
[22884]9894 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
9895
9896 int rc = RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
9897 AssertRCReturn(rc, rc);
9898
9899 PSSMHANDLE pSSM = pVM->ssm.s.pSSM;
9900 if (pSSM)
9901 {
9902 uint32_t u32Old;
9903 if (ASMAtomicCmpXchgExU32(&pSSM->fCancelled, SSMHANDLE_CANCELLED, SSMHANDLE_OK, &u32Old))
9904 {
9905 LogRel(("SSM: Cancelled pending operation\n"));
9906 rc = VINF_SUCCESS;
9907 }
9908 else if (u32Old == SSMHANDLE_CANCELLED)
9909 rc = VERR_SSM_ALREADY_CANCELLED;
9910 else
9911 {
9912 AssertLogRelMsgFailed(("fCancelled=%RX32 enmOp=%d\n", u32Old, pSSM->enmOp));
[39402]9913 rc = VERR_SSM_IPE_3;
[22884]9914 }
9915 }
9916 else
9917 rc = VERR_SSM_NO_PENDING_OPERATION;
9918
9919 RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
9920 return rc;
9921}
[24574]9922#endif /* !SSM_STANDALONE */
[22884]9923
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use