VirtualBox

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

Last change on this file since 42640 was 42335, checked in by vboxsync, 12 years ago

SSM.cpp: offUnitUser - debug aid.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette