VirtualBox

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

Last change on this file since 45578 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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