VirtualBox

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

Last change on this file since 22898 was 22884, checked in by vboxsync, 15 years ago

SSM: Added cancellation support (SSMR3Cancel). Needed by the state machinery as well as main.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 241.1 KB
Line 
1/* $Id: SSM.cpp 22884 2009-09-09 21:55:47Z vboxsync $ */
2/** @file
3 * SSM - Saved State Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/** @page pg_ssm SSM - The Saved State Manager
24 *
25 * The Saved State Manager (SSM) implements facilities for saving and loading a
26 * VM state in a structural manner using callbacks for named data units.
27 *
28 * At init time each of the VMM components, Devices, Drivers and one or two
29 * other things will register data units which they need to save and restore.
30 * Each unit have a unique name (ascii), instance number, and a set of callbacks
31 * associated with it. The name will be used to identify the unit during
32 * restore. The callbacks are for the two operations, save and restore. There
33 * are three callbacks for each of the two - a prepare, a execute and a complete
34 * - giving each component ample opportunity to perform actions both before and
35 * afterwards.
36 *
37 * The SSM provides a number of APIs for encoding and decoding the data: @see
38 * grp_ssm
39 *
40 *
41 *
42 * @section sec_ssm_live_snapshots Live Snapshots
43 *
44 * The live snapshots feature (LS) is similar to live migration (LM) and was a
45 * natural first step when implementing LM. The main differences between LS and
46 * LM are that after a live snapshot we will have a saved state file, disk image
47 * snapshots, and the VM will still be running.
48 *
49 * Compared to normal saved stated and snapshots, the difference is in that the
50 * VM is running while we do most of the saving. Prior to LS, there was only
51 * one round of callbacks during saving and the VM was paused during it. With
52 * LS there are 1 or more passes while the VM is still running and a final one
53 * after it has been paused. The runtime passes are executed on a dedicated
54 * thread running at at the same priority as the EMTs so that the saving doesn't
55 * starve or lose in scheduling questions (note: not implemented yet). The final
56 * pass is done on EMT(0).
57 *
58 * There are a couple of common reasons why LS and LM will fail:
59 * - Memory configuration changed (PCI memory mappings).
60 * - Takes too long (LM) / Too much output (LS).
61 *
62 *
63 * The live saving sequence is something like this:
64 *
65 * -# SSMR3LiveToFile is called on EMT0. It returns a saved state
66 * handle.
67 * -# SSMR3LiveDoStep1 is called on a non-EMT. This will save the major
68 * parts of the state while the VM may still be running.
69 * -# The VM is suspended.
70 * -# SSMR3LiveDoStep2 is called on EMT0 to save the remainder of the state
71 * in the normal way.
72 * -# The client does any necessary reconfiguration of harddisks and
73 * similar.
74 * -# SSMR3LiveDone is called on EMT0 to close the handle.
75 * -# The VM is resumed or powered off and destroyed.
76 *
77 *
78 * @section sec_ssm_live_migration Live Migration
79 *
80 * As mentioned in the previous section, the main differences between this and
81 * live snapshots are in where the saved state is written and what state the
82 * local VM is in afterwards - at least from the VMM point of view. The
83 * necessary administrative work - establishing the connection to the remote
84 * machine, cloning the VM config on it and doing lowlevel saved state data
85 * transfer - is taken care of by layer above the VMM (i.e. Main).
86 *
87 * The SSM data format was made streamable for the purpose of live migration
88 * (v1.2 was the last non-streamable version).
89 *
90 *
91 * @section sec_ssm_format Saved State Format
92 *
93 * The stream format starts with a header (SSMFILEHDR) that indicates the
94 * version and such things, it is followed by zero or more saved state units
95 * (name + instance + pass), and the stream concludes with a footer
96 * (SSMFILEFTR) that contains unit counts and optionally a checksum for the
97 * entire file. (In version 1.2 and earlier, the checksum was in the header and
98 * there was no footer. This meant that the header was updated after the entire
99 * file was written.)
100 *
101 * The saved state units each starts with a variable sized header
102 * (SSMFILEUNITHDRV2) that contains the name, instance and pass. The data
103 * follows the header and is encoded as records with a 2-8 byte record header
104 * indicating the type, flags and size. The first byte in the record header
105 * indicates the type and flags:
106 *
107 * - bits 0..3: Record type:
108 * - type 0: Invalid.
109 * - type 1: Terminator with CRC-32 and unit size.
110 * - type 2: Raw data record.
111 * - type 3: Raw data compressed by LZF. The data is prefixed by a 8-bit
112 * field countining the length of the uncompressed data given in
113 * 1KB units.
114 * - type 4: Zero data. The record header is followed by a 8-bit field
115 * counting the length of the zero data given in 1KB units.
116 * - type 5: Named data - length prefixed name followed by the data. This
117 * type is not implemented yet as we're missing the API part, so
118 * the type assignment is tentative.
119 * - types 6 thru 15 are current undefined.
120 * - bit 4: Important (set), can be skipped (clear).
121 * - bit 5: Undefined flag, must be zero.
122 * - bit 6: Undefined flag, must be zero.
123 * - bit 7: "magic" bit, always set.
124 *
125 * Record header byte 2 (optionally thru 7) is the size of the following data
126 * encoded in UTF-8 style. To make buffering simpler and more efficient during
127 * the save operation, the strict checks enforcing optimal encoding has been
128 * relaxed for the 2 and 3 byte encodings.
129 *
130 * (In version 1.2 and earlier the unit data was compressed and not record
131 * based. The unit header contained the compressed size of the data, i.e. it
132 * needed updating after the data was written.)
133 *
134 *
135 * @section sec_ssm_future Future Changes
136 *
137 * There are plans to extend SSM to make it easier to be both backwards and
138 * (somewhat) forwards compatible. One of the new features will be being able
139 * to classify units and data items as unimportant (added to the format in
140 * v2.0). Another suggested feature is naming data items (also added to the
141 * format in v2.0), perhaps by extending the SSMR3PutStruct API. Both features
142 * will require API changes, the naming may possibly require both buffering of
143 * the stream as well as some helper managing them.
144 */
145
146
147/*******************************************************************************
148* Header Files *
149*******************************************************************************/
150#define LOG_GROUP LOG_GROUP_SSM
151#include <VBox/ssm.h>
152#include <VBox/dbgf.h>
153#include <VBox/mm.h>
154#include "SSMInternal.h"
155#include <VBox/vm.h>
156#include <VBox/err.h>
157#include <VBox/log.h>
158#include <VBox/version.h>
159
160#include <iprt/alloc.h>
161#include <iprt/assert.h>
162#include <iprt/crc32.h>
163#include <iprt/file.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 checkesummed up to the footer using CRC-32. */
192#define SSMFILEHDR_FLAGS_STREAM_CRC32 RT_BIT_32(0)
193/** @} */
194
195/** The directory magic. */
196#define SSMFILEDIR_MAGIC "\nDir\n\0\0"
197
198/** Saved state file v2.0 magic. */
199#define SSMFILEFTR_MAGIC "\nFooter"
200
201/** Data unit magic. */
202#define SSMFILEUNITHDR_MAGIC "\nUnit\n\0"
203/** Data end marker magic. */
204#define SSMFILEUNITHDR_END "\nTheEnd"
205
206
207/** @name Record Types (data unit)
208 * @{ */
209/** The record type mask. */
210#define SSM_REC_TYPE_MASK UINT8_C(0x0f)
211/** Invalid record. */
212#define SSM_REC_TYPE_INVALID 0
213/** Normal termination record, see SSMRECTERM. */
214#define SSM_REC_TYPE_TERM 1
215/** Raw data. The data follows the size field without further ado. */
216#define SSM_REC_TYPE_RAW 2
217/** Raw data compressed by LZF.
218 * The record header is followed by a 8-bit field containing the size of the
219 * uncompressed data in 1KB units. The compressed data is after it. */
220#define SSM_REC_TYPE_RAW_LZF 3
221/** Raw zero data.
222 * The record header is followed by a 8-bit field containing the size of the
223 * zero data in 1KB units. */
224#define SSM_REC_TYPE_RAW_ZERO 4
225/** Named data items.
226 * A length prefix zero terminated string (i.e. max 255) followed by the data. */
227#define SSM_REC_TYPE_NAMED 5
228/** Macro for validating the record type.
229 * This can be used with the flags+type byte, no need to mask out the type first. */
230#define SSM_REC_TYPE_IS_VALID(u8Type) ( ((u8Type) & SSM_REC_TYPE_MASK) > SSM_REC_TYPE_INVALID \
231 && ((u8Type) & SSM_REC_TYPE_MASK) <= SSM_REC_TYPE_NAMED )
232/** @} */
233
234/** The flag mask. */
235#define SSM_REC_FLAGS_MASK UINT8_C(0xf0)
236/** The record is important if this flag is set, if clear it can be omitted. */
237#define SSM_REC_FLAGS_IMPORTANT UINT8_C(0x10)
238/** This flag is always set. */
239#define SSM_REC_FLAGS_FIXED UINT8_C(0x80)
240/** Macro for validating the flags.
241 * No need to mask the flags out of the flags+type byte before invoking this macro. */
242#define SSM_REC_FLAGS_ARE_VALID(fFlags) ( ((fFlags) & UINT8_C(0xe0)) == UINT8_C(0x80) )
243
244/** Macro for validating the type and flags byte in a data record. */
245#define SSM_REC_ARE_TYPE_AND_FLAGS_VALID(u8) ( SSM_REC_FLAGS_ARE_VALID(u8) && SSM_REC_TYPE_IS_VALID(u8) )
246
247/** @name SSMRECTERM::fFlags
248 * @{ */
249/** There is a CRC-32 value for the stream. */
250#define SSMRECTERM_FLAGS_CRC32 UINT16_C(0x0001)
251/** @} */
252
253/** Start structure magic. (Isacc Asimov) */
254#define SSMR3STRUCT_BEGIN UINT32_C(0x19200102)
255/** End structure magic. (Isacc Asimov) */
256#define SSMR3STRUCT_END UINT32_C(0x19920406)
257
258
259/** Number of bytes to log in Log2 and Log4 statements. */
260#define SSM_LOG_BYTES 16
261
262/** SSMHANDLE::fCancelled value indicating that the operation has been
263 * cancelled. */
264#define SSMHANDLE_CANCELLED UINT32_C(0xdeadbeef)
265/** SSMHANDLE::fCancelled value indicating no cancellation. */
266#define SSMHANDLE_OK UINT32_C(0x77777777)
267
268
269/** Macro for checking the u32CRC field of a structure.
270 * The Msg can assume there are u32ActualCRC and u32CRC in the context. */
271#define SSM_CHECK_CRC32_RET(p, cb, Msg) \
272 do \
273 { \
274 uint32_t u32CRC = (p)->u32CRC; \
275 (p)->u32CRC = 0; \
276 uint32_t u32ActualCRC = RTCrc32((p), (cb)); \
277 (p)->u32CRC = u32CRC; \
278 AssertLogRelMsgReturn(u32ActualCRC == u32CRC, Msg, VERR_SSM_INTEGRITY_CRC); \
279 } while (0)
280
281/** The number of bytes to compress is one block.
282 * Must be a multiple of 1KB. */
283#define SSM_ZIP_BLOCK_SIZE _4K
284AssertCompile(SSM_ZIP_BLOCK_SIZE / _1K * _1K == SSM_ZIP_BLOCK_SIZE);
285
286
287/**
288 * Asserts that the handle is writable and returns with VERR_SSM_INVALID_STATE
289 * if it isn't.
290 */
291#define SSM_ASSERT_WRITEABLE_RET(pSSM) \
292 AssertMsgReturn( pSSM->enmOp == SSMSTATE_SAVE_EXEC \
293 || pSSM->enmOp == SSMSTATE_LIVE_EXEC,\
294 ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
295
296/**
297 * Asserts that the handle is readable and returns with VERR_SSM_INVALID_STATE
298 * if it isn't.
299 */
300#define SSM_ASSERT_READABLE_RET(pSSM) \
301 AssertMsgReturn( pSSM->enmOp == SSMSTATE_LOAD_EXEC \
302 || pSSM->enmOp == SSMSTATE_OPEN_READ,\
303 ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
304
305/** Checks for cancellation and returns if pending.
306 * Sets SSMHANDLE::rc to VERR_SSM_CANCELLED (if it still indicates success) and
307 * then returns SSMHANDLE::rc. (Debug logging only.) */
308#define SSM_CHECK_CANCELLED_RET(pSSM) \
309 do \
310 { \
311 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED)) \
312 { \
313 LogFlow(("%Rfn: Cancelled -> VERR_SSM_CANCELLED\n", __PRETTY_FUNCTION__)); \
314 if (RT_SUCCESS((pSSM)->rc)) \
315 (pSSM)->rc = VERR_SSM_CANCELLED; \
316 return (pSSM)->rc; \
317 } \
318 } while (0)
319
320
321/*******************************************************************************
322* Structures and Typedefs *
323*******************************************************************************/
324/** SSM state. */
325typedef enum SSMSTATE
326{
327 SSMSTATE_INVALID = 0,
328 SSMSTATE_LIVE_PREP,
329 SSMSTATE_LIVE_STEP1,
330 SSMSTATE_LIVE_EXEC,
331 SSMSTATE_LIVE_VOTE,
332 SSMSTATE_LIVE_STEP2,
333 SSMSTATE_SAVE_PREP,
334 SSMSTATE_SAVE_EXEC,
335 SSMSTATE_SAVE_DONE,
336 SSMSTATE_LOAD_PREP,
337 SSMSTATE_LOAD_EXEC,
338 SSMSTATE_LOAD_DONE,
339 SSMSTATE_OPEN_READ
340} SSMSTATE;
341
342/** Pointer to a SSM stream buffer. */
343typedef struct SSMSTRMBUF *PSSMSTRMBUF;
344/**
345 * A SSM stream buffer.
346 */
347typedef struct SSMSTRMBUF
348{
349 /** The buffer data. */
350 uint8_t abData[_64K];
351
352 /** The stream position of this buffer. */
353 uint64_t offStream;
354 /** The amount of buffered data. */
355 uint32_t cb;
356 /** End of stream indicator (for read streams only). */
357 bool fEndOfStream;
358 /** Pointer to the next buffer in the chain. */
359 PSSMSTRMBUF volatile pNext;
360} SSMSTRMBUF;
361
362/**
363 * SSM stream.
364 *
365 * This is a typical producer / consumer setup with a dedicated I/O thread and
366 * fixed number of buffers for read ahead and write back.
367 */
368typedef struct SSMSTRM
369{
370 /** The file handle. */
371 RTFILE hFile;
372
373 /** Write (set) or read (clear) stream. */
374 bool fWrite;
375 /** Termination indicator. */
376 bool volatile fTerminating;
377 /** Indicates whether it is necessary to seek before the next buffer is
378 * read from the stream. This is used to avoid a seek in ssmR3StrmPeekAt. */
379 bool fNeedSeek;
380 /** Stream error status. */
381 int32_t volatile rc;
382 /** The handle of the I/O thread. This is set to nil when not active. */
383 RTTHREAD hIoThread;
384 /** Where to seek to. */
385 uint64_t offNeedSeekTo;
386
387 /** The head of the consumer queue.
388 * For save the consumer is the I/O thread. For load the I/O thread is the
389 * producer. */
390 PSSMSTRMBUF volatile pHead;
391 /** Chain of free buffers.
392 * The consumer/producer roles are the inverse of pHead. */
393 PSSMSTRMBUF volatile pFree;
394 /** Event that's signalled when pHead is updated. */
395 RTSEMEVENT hEvtHead;
396 /** Event that's signalled when pFree is updated. */
397 RTSEMEVENT hEvtFree;
398
399 /** List of pending buffers that has been dequeued from pHead and reversed. */
400 PSSMSTRMBUF pPending;
401 /** Pointer to the current buffer. */
402 PSSMSTRMBUF pCur;
403 /** The stream offset of the current buffer. */
404 uint64_t offCurStream;
405 /** The current buffer offset. */
406 uint32_t off;
407 /** Whether we're checksumming reads/writes. */
408 bool fChecksummed;
409 /** The stream CRC if fChecksummed is set. */
410 uint32_t u32StreamCRC;
411 /** How far into the buffer u32StreamCRC is up-to-date.
412 * This may lag behind off as it's desirable to checksum as large blocks as
413 * possible. */
414 uint32_t offStreamCRC;
415} SSMSTRM;
416/** Pointer to a SSM stream. */
417typedef SSMSTRM *PSSMSTRM;
418
419
420/**
421 * Handle structure.
422 */
423typedef struct SSMHANDLE
424{
425 /** Stream/buffer manager. */
426 SSMSTRM Strm;
427
428 /** The VM handle. */
429 PVM pVM;
430 /** The current operation. */
431 SSMSTATE enmOp;
432 /** What to do after save completes. (move the enum) */
433 SSMAFTER enmAfter;
434 /** Flag indicating that the operation has been cancelled. */
435 uint32_t volatile fCancelled;
436 /** The current rc of the save operation. */
437 int32_t rc;
438 /** Number of compressed bytes left in the current data unit (V1). */
439 uint64_t cbUnitLeftV1;
440 /** The current uncompressed offset into the data unit. */
441 uint64_t offUnit;
442
443 /** Pointer to the progress callback function. */
444 PFNVMPROGRESS pfnProgress;
445 /** User specified arguemnt to the callback function. */
446 void *pvUser;
447 /** Next completion percentage. (corresponds to offEstProgress) */
448 unsigned uPercent;
449 /** The position of the next progress callback in the estimated file. */
450 uint64_t offEstProgress;
451 /** The estimated total byte count.
452 * (Only valid after the prep.) */
453 uint64_t cbEstTotal;
454 /** Current position in the estimated file. */
455 uint64_t offEst;
456 /** End of current unit in the estimated file. */
457 uint64_t offEstUnitEnd;
458 /** the amount of % we reserve for the 'prepare' phase */
459 unsigned uPercentPrepare;
460 /** the amount of % we reserve for the 'done' stage */
461 unsigned uPercentDone;
462 /** The filename, NULL if remote stream. */
463 const char *pszFilename;
464
465 union
466 {
467 /** Write data. */
468 struct
469 {
470 /** Offset into the databuffer. */
471 uint32_t offDataBuffer;
472 /** Space for the record header. */
473 uint8_t abRecHdr[1+7];
474 /** Data buffer. */
475 uint8_t abDataBuffer[4096];
476 } Write;
477
478 /** Read data. */
479 struct
480 {
481 /** V1: The decompressor of the current data unit. */
482 PRTZIPDECOMP pZipDecompV1;
483 /** The major format version number. */
484 uint32_t uFmtVerMajor;
485 /** The minor format version number. */
486 uint32_t uFmtVerMinor;
487
488 /** V2: Unread bytes in the current record. */
489 uint32_t cbRecLeft;
490 /** V2: Bytes in the data buffer. */
491 uint32_t cbDataBuffer;
492 /** V2: Current buffer position. */
493 uint32_t offDataBuffer;
494 /** V2: End of data indicator. */
495 bool fEndOfData;
496 /** V2: The type and flags byte fo the current record. */
497 uint8_t u8TypeAndFlags;
498
499 /** RTGCPHYS size in bytes. (Only applicable when loading/reading.) */
500 unsigned cbGCPhys;
501 /** RTGCPTR size in bytes. (Only applicable when loading/reading.) */
502 unsigned cbGCPtr;
503 /** Whether cbGCPtr is fixed or settable. */
504 bool fFixedGCPtrSize;
505
506
507 /** @name Header info (set by ssmR3ValidateFile)
508 * @{ */
509 /** The size of the file header. */
510 size_t cbFileHdr;
511 /** The major version number. */
512 uint16_t u16VerMajor;
513 /** The minor version number. */
514 uint16_t u16VerMinor;
515 /** The build number. */
516 uint32_t u32VerBuild;
517 /** The SVN revision. */
518 uint32_t u32SvnRev;
519 /** 32 or 64 depending on the host. */
520 uint8_t cHostBits;
521 /** The CRC of the loaded file. */
522 uint32_t u32LoadCRC;
523 /** The size of the load file. */
524 uint64_t cbLoadFile;
525 /** @} */
526
527 /** V2: Data buffer.
528 * @remarks Be extremely careful when changing the size of this buffer! */
529 uint8_t abDataBuffer[4096];
530
531 /** V2: Decompression buffer for when we cannot use the stream buffer. */
532 uint8_t abComprBuffer[4096];
533 } Read;
534 } u;
535} SSMHANDLE;
536
537
538/**
539 * Header of the saved state file.
540 *
541 * Added in r5xxxx on 2009-07-2?, VirtualBox v3.0.51.
542 */
543typedef struct SSMFILEHDR
544{
545 /** Magic string which identifies this file as a version of VBox saved state
546 * file format (SSMFILEHDR_MAGIC_V2_0). */
547 char szMagic[32];
548 /** The major version number. */
549 uint16_t u16VerMajor;
550 /** The minor version number. */
551 uint16_t u16VerMinor;
552 /** The build number. */
553 uint32_t u32VerBuild;
554 /** The SVN revision. */
555 uint32_t u32SvnRev;
556 /** 32 or 64 depending on the host. */
557 uint8_t cHostBits;
558 /** The size of RTGCPHYS. */
559 uint8_t cbGCPhys;
560 /** The size of RTGCPTR. */
561 uint8_t cbGCPtr;
562 /** Reserved header space - must be zero. */
563 uint8_t u8Reserved;
564 /** The number of units that (may) have stored data in the file. */
565 uint32_t cUnits;
566 /** Flags, see SSMFILEHDR_FLAGS_XXX. */
567 uint32_t fFlags;
568 /** The maximum size of decompressed data. */
569 uint32_t cbMaxDecompr;
570 /** The checksum of this header.
571 * This field is set to zero when calculating the checksum. */
572 uint32_t u32CRC;
573} SSMFILEHDR;
574AssertCompileSize(SSMFILEHDR, 64);
575AssertCompileMemberOffset(SSMFILEHDR, u32CRC, 60);
576AssertCompileMemberSize(SSMFILEHDR, szMagic, sizeof(SSMFILEHDR_MAGIC_V2_0));
577/** Pointer to a saved state file header. */
578typedef SSMFILEHDR *PSSMFILEHDR;
579/** Pointer to a const saved state file header. */
580typedef SSMFILEHDR const *PCSSMFILEHDR;
581
582
583/**
584 * Header of the saved state file.
585 *
586 * Added in r40980 on 2008-12-15, VirtualBox v2.0.51.
587 *
588 * @remarks This is a superset of SSMFILEHDRV11.
589 */
590typedef struct SSMFILEHDRV12
591{
592 /** Magic string which identifies this file as a version of VBox saved state
593 * file format (SSMFILEHDR_MAGIC_V1_2). */
594 char achMagic[32];
595 /** The size of this file. Used to check
596 * whether the save completed and that things are fine otherwise. */
597 uint64_t cbFile;
598 /** File checksum. The actual calculation skips past the u32CRC field. */
599 uint32_t u32CRC;
600 /** Padding. */
601 uint32_t u32Reserved;
602 /** The machine UUID. (Ignored if NIL.) */
603 RTUUID MachineUuid;
604
605 /** The major version number. */
606 uint16_t u16VerMajor;
607 /** The minor version number. */
608 uint16_t u16VerMinor;
609 /** The build number. */
610 uint32_t u32VerBuild;
611 /** The SVN revision. */
612 uint32_t u32SvnRev;
613
614 /** 32 or 64 depending on the host. */
615 uint8_t cHostBits;
616 /** The size of RTGCPHYS. */
617 uint8_t cbGCPhys;
618 /** The size of RTGCPTR. */
619 uint8_t cbGCPtr;
620 /** Padding. */
621 uint8_t au8Reserved;
622} SSMFILEHDRV12;
623AssertCompileSize(SSMFILEHDRV12, 64+16);
624AssertCompileMemberOffset(SSMFILEHDRV12, u32CRC, 40);
625AssertCompileMemberSize(SSMFILEHDRV12, achMagic, sizeof(SSMFILEHDR_MAGIC_V1_2));
626/** Pointer to a saved state file header. */
627typedef SSMFILEHDRV12 *PSSMFILEHDRV12;
628
629
630/**
631 * Header of the saved state file, version 1.1.
632 *
633 * Added in r23677 on 2007-08-17, VirtualBox v1.4.1.
634 */
635typedef struct SSMFILEHDRV11
636{
637 /** Magic string which identifies this file as a version of VBox saved state
638 * file format (SSMFILEHDR_MAGIC_V1_1). */
639 char achMagic[32];
640 /** The size of this file. Used to check
641 * whether the save completed and that things are fine otherwise. */
642 uint64_t cbFile;
643 /** File checksum. The actual calculation skips past the u32CRC field. */
644 uint32_t u32CRC;
645 /** Padding. */
646 uint32_t u32Reserved;
647 /** The machine UUID. (Ignored if NIL.) */
648 RTUUID MachineUuid;
649} SSMFILEHDRV11;
650AssertCompileSize(SSMFILEHDRV11, 64);
651AssertCompileMemberOffset(SSMFILEHDRV11, u32CRC, 40);
652/** Pointer to a saved state file header. */
653typedef SSMFILEHDRV11 *PSSMFILEHDRV11;
654
655
656/**
657 * Data unit header.
658 */
659typedef struct SSMFILEUNITHDRV2
660{
661 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
662 char szMagic[8];
663 /** The offset in the saved state stream of the start of this unit.
664 * This is mainly intended for sanity checking. */
665 uint64_t offStream;
666 /** The CRC-in-progress value this unit starts at. */
667 uint32_t u32CurStreamCRC;
668 /** The checksum of this structure, including the whole name.
669 * Calculated with this field set to zero. */
670 uint32_t u32CRC;
671 /** Data version. */
672 uint32_t u32Version;
673 /** Instance number. */
674 uint32_t u32Instance;
675 /** Data pass number. */
676 uint32_t u32Pass;
677 /** Flags reserved for future extensions. Must be zero. */
678 uint32_t fFlags;
679 /** Size of the data unit name including the terminator. (bytes) */
680 uint32_t cbName;
681 /** Data unit name, variable size. */
682 char szName[SSM_MAX_NAME_SIZE];
683} SSMFILEUNITHDRV2;
684AssertCompileMemberOffset(SSMFILEUNITHDRV2, szName, 44);
685AssertCompileMemberSize(SSMFILEUNITHDRV2, szMagic, sizeof(SSMFILEUNITHDR_MAGIC));
686AssertCompileMemberSize(SSMFILEUNITHDRV2, szMagic, sizeof(SSMFILEUNITHDR_END));
687/** Pointer to SSMFILEUNITHDRV2. */
688typedef SSMFILEUNITHDRV2 *PSSMFILEUNITHDRV2;
689
690
691/**
692 * Data unit header.
693 *
694 * This is used by v1.0, v1.1 and v1.2 of the format.
695 */
696typedef struct SSMFILEUNITHDRV1
697{
698 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
699 char achMagic[8];
700 /** Number of bytes in this data unit including the header. */
701 uint64_t cbUnit;
702 /** Data version. */
703 uint32_t u32Version;
704 /** Instance number. */
705 uint32_t u32Instance;
706 /** Size of the data unit name including the terminator. (bytes) */
707 uint32_t cchName;
708 /** Data unit name. */
709 char szName[1];
710} SSMFILEUNITHDRV1;
711/** Pointer to SSMFILEUNITHDR. */
712typedef SSMFILEUNITHDRV1 *PSSMFILEUNITHDRV1;
713
714
715/**
716 * Termination data record.
717 */
718typedef struct SSMRECTERM
719{
720 uint8_t u8TypeAndFlags;
721 /** The record size (sizeof(SSMRECTERM) - 2). */
722 uint8_t cbRec;
723 /** Flags, see SSMRECTERM_FLAGS_CRC32. */
724 uint16_t fFlags;
725 /** The checksum of the stream up to fFlags (exclusive). */
726 uint32_t u32StreamCRC;
727 /** The length of this data unit in bytes (including this record). */
728 uint64_t cbUnit;
729} SSMRECTERM;
730AssertCompileSize(SSMRECTERM, 16);
731AssertCompileMemberAlignment(SSMRECTERM, cbUnit, 8);
732/** Pointer to a termination record. */
733typedef SSMRECTERM *PSSMRECTERM;
734/** Pointer to a const termination record. */
735typedef SSMRECTERM const *PCSSMRECTERM;
736
737
738/**
739 * Directory entry.
740 */
741typedef struct SSMFILEDIRENTRY
742{
743 /** The offset of the data unit. */
744 uint64_t off;
745 /** The instance number. */
746 uint32_t u32Instance;
747 /** The CRC-32 of the name excluding the terminator. (lazy bird) */
748 uint32_t u32NameCRC;
749} SSMFILEDIRENTRY;
750AssertCompileSize(SSMFILEDIRENTRY, 16);
751/** Pointer to a directory entry. */
752typedef SSMFILEDIRENTRY *PSSMFILEDIRENTRY;
753/** Pointer to a const directory entry. */
754typedef SSMFILEDIRENTRY const *PCSSMFILEDIRENTRY;
755
756/**
757 * Directory for the data units from the final pass.
758 *
759 * This is used to speed up SSMR3Seek (it would have to decompress and parse the
760 * whole stream otherwise).
761 */
762typedef struct SSMFILEDIR
763{
764 /** Magic string (SSMFILEDIR_MAGIC). */
765 char szMagic[8];
766 /** The CRC-32 for the whole directory.
767 * Calculated with this field set to zero. */
768 uint32_t u32CRC;
769 /** The number of directory entries. */
770 uint32_t cEntries;
771 /** The directory entries (variable size). */
772 SSMFILEDIRENTRY aEntries[1];
773} SSMFILEDIR;
774AssertCompileSize(SSMFILEDIR, 32);
775/** Pointer to a directory. */
776typedef SSMFILEDIR *PSSMFILEDIR;
777/** Pointer to a const directory. */
778typedef SSMFILEDIR *PSSMFILEDIR;
779
780
781/**
782 * Footer structure
783 */
784typedef struct SSMFILEFTR
785{
786 /** Magic string (SSMFILEFTR_MAGIC). */
787 char szMagic[8];
788 /** The offset of this record in the stream. */
789 uint64_t offStream;
790 /** The CRC for the stream.
791 * This is set to zero if SSMFILEHDR_FLAGS_STREAM_CRC32 is clear. */
792 uint32_t u32StreamCRC;
793 /** Number directory entries. */
794 uint32_t cDirEntries;
795 /** Reserved footer space - must be zero. */
796 uint32_t u32Reserved;
797 /** The CRC-32 for this structure.
798 * Calculated with this field set to zero. */
799 uint32_t u32CRC;
800} SSMFILEFTR;
801AssertCompileSize(SSMFILEFTR, 32);
802/** Pointer to a footer. */
803typedef SSMFILEFTR *PSSMFILEFTR;
804/** Pointer to a const footer. */
805typedef SSMFILEFTR const *PCSSMFILEFTR;
806
807
808/*******************************************************************************
809* Internal Functions *
810*******************************************************************************/
811static int ssmR3LazyInit(PVM pVM);
812static DECLCALLBACK(int) ssmR3SelfLiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
813static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM);
814static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
815static int ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
816
817static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm);
818static int ssmR3StrmReadMore(PSSMSTRM pStrm);
819
820static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM);
821static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM);
822
823
824
825/**
826 * Cleans up resources allocated by SSM on VM termination.
827 *
828 * @param pVM The VM handle.
829 */
830VMMR3_INT_DECL(void) SSMR3Term(PVM pVM)
831{
832 if (pVM->ssm.s.fInitialized)
833 {
834 pVM->ssm.s.fInitialized = false;
835 RTCritSectDelete(&pVM->ssm.s.CancelCritSect);
836 }
837}
838
839
840/**
841 * Performs lazy initialization of the SSM.
842 *
843 * @returns VBox status code.
844 * @param pVM The VM.
845 */
846static int ssmR3LazyInit(PVM pVM)
847{
848 /*
849 * Register a saved state unit which we use to put the VirtualBox version,
850 * revision and similar stuff in.
851 */
852 pVM->ssm.s.fInitialized = true;
853 int rc = SSMR3RegisterInternal(pVM, "SSM", 0 /*uInstance*/, 1 /*uVersion*/, 64 /*cbGuess*/,
854 NULL /*pfnLivePrep*/, ssmR3SelfLiveExec, NULL /*pfnLiveVote*/,
855 NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
856 NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
857
858 /*
859 * Initialize the cancellation critsect now.
860 */
861 if (RT_SUCCESS(rc))
862 rc = RTCritSectInit(&pVM->ssm.s.CancelCritSect);
863
864 pVM->ssm.s.fInitialized = RT_SUCCESS(rc);
865 return rc;
866}
867
868
869/**
870 * Do ssmR3SelfSaveExec in pass 0.
871 *
872 * @returns VBox status code.
873 * @param pVM Pointer to the shared VM structure.
874 * @param pSSM The SSM handle.
875 * @param uPass The data pass number.
876 */
877static DECLCALLBACK(int) ssmR3SelfLiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
878{
879 if (uPass == 0)
880 return ssmR3SelfSaveExec(pVM, pSSM);
881 return VINF_SUCCESS;
882}
883
884
885/**
886 * For saving usful things without having to go thru the tedious process of
887 * adding it to the header.
888 *
889 * @returns VBox status code.
890 * @param pVM Pointer to the shared VM structure.
891 * @param pSSM The SSM handle.
892 */
893static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM)
894{
895 /*
896 * String table containg pairs of variable and value string.
897 * Terminated by two empty strings.
898 */
899 SSMR3PutStrZ(pSSM, "Build Type");
900 SSMR3PutStrZ(pSSM, KBUILD_TYPE);
901 SSMR3PutStrZ(pSSM, "Host OS");
902 SSMR3PutStrZ(pSSM, KBUILD_TARGET "." KBUILD_TARGET_ARCH);
903#ifdef VBOX_OSE
904 SSMR3PutStrZ(pSSM, "OSE");
905 SSMR3PutStrZ(pSSM, "true");
906#endif
907
908 /* terminator */
909 SSMR3PutStrZ(pSSM, "");
910 return SSMR3PutStrZ(pSSM, "");
911}
912
913
914/**
915 * For load the version + revision and stuff.
916 *
917 * @returns VBox status code.
918 * @param pVM Pointer to the shared VM structure.
919 * @param pSSM The SSM handle.
920 * @param uVersion The version (1).
921 * @param uPass The pass.
922 */
923static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
924{
925 AssertLogRelMsgReturn(uVersion == 1, ("%d", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
926
927 /*
928 * String table containg pairs of variable and value string.
929 * Terminated by two empty strings.
930 */
931 for (unsigned i = 0; ; i++)
932 {
933 char szVar[128];
934 char szValue[1024];
935 int rc = SSMR3GetStrZ(pSSM, szVar, sizeof(szVar));
936 AssertRCReturn(rc, rc);
937 rc = SSMR3GetStrZ(pSSM, szValue, sizeof(szValue));
938 AssertRCReturn(rc, rc);
939 if (!szVar[0] && !szValue[0])
940 break;
941 if (i == 0)
942 LogRel(("SSM: Saved state info:\n"));
943 LogRel(("SSM: %s: %s\n", szVar, szValue));
944 }
945 return VINF_SUCCESS;
946}
947
948
949/**
950 * Internal registration worker.
951 *
952 * @returns VBox status code.
953 * @param pVM The VM handle.
954 * @param pszName Data unit name.
955 * @param uInstance The instance id.
956 * @param uVersion The data unit version.
957 * @param cbGuess The guessed data unit size.
958 * @param pszBefore Name of data unit to be placed in front of.
959 * Optional.
960 * @param ppUnit Where to store the insterted unit node.
961 * Caller must fill in the missing details.
962 */
963static int ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance,
964 uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit)
965{
966 /*
967 * Validate input.
968 */
969 AssertPtr(pszName);
970 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
971 size_t cchName = strlen(pszName);
972 AssertMsgReturn(cchName < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchName, SSM_MAX_NAME_SIZE, pszName), VERR_OUT_OF_RANGE);
973
974 AssertReturn(!pszBefore || *pszBefore, VERR_INVALID_PARAMETER);
975 size_t cchBefore = pszBefore ? strlen(pszBefore) : 0;
976 AssertMsgReturn(cchBefore < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchBefore, SSM_MAX_NAME_SIZE, pszBefore), VERR_OUT_OF_RANGE);
977
978 /*
979 * Lazy init.
980 */
981 if (!pVM->ssm.s.fInitialized)
982 {
983 int rc = ssmR3LazyInit(pVM);
984 AssertRCReturn(rc, rc);
985 }
986
987 /*
988 * Walk to the end of the list checking for duplicates as we go.
989 */
990 PSSMUNIT pUnitBeforePrev = NULL;
991 PSSMUNIT pUnitBefore = NULL;
992 PSSMUNIT pUnitPrev = NULL;
993 PSSMUNIT pUnit = pVM->ssm.s.pHead;
994 while (pUnit)
995 {
996 if ( pUnit->u32Instance == uInstance
997 && pUnit->cchName == cchName
998 && !memcmp(pUnit->szName, pszName, cchName))
999 {
1000 AssertMsgFailed(("Duplicate registration %s\n", pszName));
1001 return VERR_SSM_UNIT_EXISTS;
1002 }
1003 if ( pUnit->cchName == cchBefore
1004 && !pUnitBefore
1005 && !memcmp(pUnit->szName, pszBefore, cchBefore))
1006 {
1007 pUnitBeforePrev = pUnitPrev;
1008 pUnitBefore = pUnit;
1009 }
1010
1011 /* next */
1012 pUnitPrev = pUnit;
1013 pUnit = pUnit->pNext;
1014 }
1015
1016 /*
1017 * Allocate new node.
1018 */
1019 pUnit = (PSSMUNIT)MMR3HeapAllocZ(pVM, MM_TAG_SSM, RT_OFFSETOF(SSMUNIT, szName[cchName + 1]));
1020 if (!pUnit)
1021 return VERR_NO_MEMORY;
1022
1023 /*
1024 * Fill in (some) data. (Stuff is zero'ed.)
1025 */
1026 pUnit->u32Version = uVersion;
1027 pUnit->u32Instance = uInstance;
1028 pUnit->cbGuess = cbGuess;
1029 pUnit->cchName = cchName;
1030 memcpy(pUnit->szName, pszName, cchName);
1031
1032 /*
1033 * Insert
1034 */
1035 if (pUnitBefore)
1036 {
1037 pUnit->pNext = pUnitBefore;
1038 if (pUnitBeforePrev)
1039 pUnitBeforePrev->pNext = pUnit;
1040 else
1041 pVM->ssm.s.pHead = pUnit;
1042 }
1043 else if (pUnitPrev)
1044 pUnitPrev->pNext = pUnit;
1045 else
1046 pVM->ssm.s.pHead = pUnit;
1047 pVM->ssm.s.cUnits++;
1048
1049 *ppUnit = pUnit;
1050 return VINF_SUCCESS;
1051}
1052
1053
1054/**
1055 * Register a PDM Devices data unit.
1056 *
1057 * @returns VBox status.
1058 *
1059 * @param pVM The VM handle.
1060 * @param pDevIns Device instance.
1061 * @param pszName Data unit name.
1062 * @param uInstance The instance identifier of the data unit.
1063 * This must together with the name be unique.
1064 * @param uVersion Data layout version number.
1065 * @param cbGuess The approximate amount of data in the unit.
1066 * Only for progress indicators.
1067 * @param pszBefore Name of data unit which we should be put in front
1068 * of. Optional (NULL).
1069 *
1070 * @param pfnLivePrep Prepare live save callback, optional.
1071 * @param pfnLiveExec Execute live save callback, optional.
1072 * @param pfnLiveVote Vote live save callback, optional.
1073 *
1074 * @param pfnSavePrep Prepare save callback, optional.
1075 * @param pfnSaveExec Execute save callback, optional.
1076 * @param pfnSaveDone Done save callback, optional.
1077 *
1078 * @param pfnLoadPrep Prepare load callback, optional.
1079 * @param pfnLoadExec Execute load callback, optional.
1080 * @param pfnLoadDone Done load callback, optional.
1081 */
1082VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore,
1083 PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote,
1084 PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
1085 PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
1086{
1087 PSSMUNIT pUnit;
1088 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, pszBefore, &pUnit);
1089 if (RT_SUCCESS(rc))
1090 {
1091 pUnit->enmType = SSMUNITTYPE_DEV;
1092 pUnit->u.Dev.pfnLivePrep = pfnLivePrep;
1093 pUnit->u.Dev.pfnLiveExec = pfnLiveExec;
1094 pUnit->u.Dev.pfnLiveVote = pfnLiveVote;
1095 pUnit->u.Dev.pfnSavePrep = pfnSavePrep;
1096 pUnit->u.Dev.pfnSaveExec = pfnSaveExec;
1097 pUnit->u.Dev.pfnSaveDone = pfnSaveDone;
1098 pUnit->u.Dev.pfnLoadPrep = pfnLoadPrep;
1099 pUnit->u.Dev.pfnLoadExec = pfnLoadExec;
1100 pUnit->u.Dev.pfnLoadDone = pfnLoadDone;
1101 pUnit->u.Dev.pDevIns = pDevIns;
1102 }
1103 return rc;
1104}
1105
1106
1107/**
1108 * Register a PDM driver data unit.
1109 *
1110 * @returns VBox status.
1111 *
1112 * @param pVM The VM handle.
1113 * @param pDrvIns Driver instance.
1114 * @param pszName Data unit name.
1115 * @param uInstance The instance identifier of the data unit.
1116 * This must together with the name be unique.
1117 * @param uVersion Data layout version number.
1118 * @param cbGuess The approximate amount of data in the unit.
1119 * Only for progress indicators.
1120 *
1121 * @param pfnLivePrep Prepare live save callback, optional.
1122 * @param pfnLiveExec Execute live save callback, optional.
1123 * @param pfnLiveVote Vote live save callback, optional.
1124 *
1125 * @param pfnSavePrep Prepare save callback, optional.
1126 * @param pfnSaveExec Execute save callback, optional.
1127 * @param pfnSaveDone Done save callback, optional.
1128 *
1129 * @param pfnLoadPrep Prepare load callback, optional.
1130 * @param pfnLoadExec Execute load callback, optional.
1131 * @param pfnLoadDone Done load callback, optional.
1132 */
1133VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1134 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
1135 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1136 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
1137{
1138 PSSMUNIT pUnit;
1139 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL, &pUnit);
1140 if (RT_SUCCESS(rc))
1141 {
1142 pUnit->enmType = SSMUNITTYPE_DRV;
1143 pUnit->u.Drv.pfnSavePrep = pfnSavePrep;
1144 pUnit->u.Drv.pfnSaveExec = pfnSaveExec;
1145 pUnit->u.Drv.pfnSaveDone = pfnSaveDone;
1146 pUnit->u.Drv.pfnLoadPrep = pfnLoadPrep;
1147 pUnit->u.Drv.pfnLoadExec = pfnLoadExec;
1148 pUnit->u.Drv.pfnLoadDone = pfnLoadDone;
1149 pUnit->u.Drv.pDrvIns = pDrvIns;
1150 }
1151 return rc;
1152}
1153
1154
1155/**
1156 * Register a internal data unit.
1157 *
1158 * @returns VBox status.
1159 *
1160 * @param pVM The VM handle.
1161 * @param pszName Data unit name.
1162 * @param uInstance The instance identifier of the data unit.
1163 * This must together with the name be unique.
1164 * @param uVersion Data layout version number.
1165 * @param cbGuess The approximate amount of data in the unit.
1166 * Only for progress indicators.
1167 *
1168 * @param pfnLivePrep Prepare live save callback, optional.
1169 * @param pfnLiveExec Execute live save callback, optional.
1170 * @param pfnLiveVote Vote live save callback, optional.
1171 *
1172 * @param pfnSavePrep Prepare save callback, optional.
1173 * @param pfnSaveExec Execute save callback, optional.
1174 * @param pfnSaveDone Done save callback, optional.
1175 *
1176 * @param pfnLoadPrep Prepare load callback, optional.
1177 * @param pfnLoadExec Execute load callback, optional.
1178 * @param pfnLoadDone Done load callback, optional.
1179 */
1180VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1181 PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote,
1182 PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
1183 PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone)
1184{
1185 PSSMUNIT pUnit;
1186 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL, &pUnit);
1187 if (RT_SUCCESS(rc))
1188 {
1189 pUnit->enmType = SSMUNITTYPE_INTERNAL;
1190 pUnit->u.Internal.pfnLivePrep = pfnLivePrep;
1191 pUnit->u.Internal.pfnLiveExec = pfnLiveExec;
1192 pUnit->u.Internal.pfnLiveVote = pfnLiveVote;
1193 pUnit->u.Internal.pfnSavePrep = pfnSavePrep;
1194 pUnit->u.Internal.pfnSaveExec = pfnSaveExec;
1195 pUnit->u.Internal.pfnSaveDone = pfnSaveDone;
1196 pUnit->u.Internal.pfnLoadPrep = pfnLoadPrep;
1197 pUnit->u.Internal.pfnLoadExec = pfnLoadExec;
1198 pUnit->u.Internal.pfnLoadDone = pfnLoadDone;
1199 }
1200 return rc;
1201}
1202
1203
1204/**
1205 * Register an external data unit.
1206 *
1207 * @returns VBox status.
1208 *
1209 * @param pVM The VM handle.
1210 * @param pszName Data unit name.
1211 * @param uInstance The instance identifier of the data unit.
1212 * This must together with the name be unique.
1213 * @param uVersion Data layout version number.
1214 * @param cbGuess The approximate amount of data in the unit.
1215 * Only for progress indicators.
1216 *
1217 * @param pfnLivePrep Prepare live save callback, optional.
1218 * @param pfnLiveExec Execute live save callback, optional.
1219 * @param pfnLiveVote Vote live save callback, optional.
1220 *
1221 * @param pfnSavePrep Prepare save callback, optional.
1222 * @param pfnSaveExec Execute save callback, optional.
1223 * @param pfnSaveDone Done save callback, optional.
1224 *
1225 * @param pfnLoadPrep Prepare load callback, optional.
1226 * @param pfnLoadExec Execute load callback, optional.
1227 * @param pfnLoadDone Done load callback, optional.
1228 * @param pvUser User argument.
1229 */
1230VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess,
1231 PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote,
1232 PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
1233 PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
1234{
1235 PSSMUNIT pUnit;
1236 int rc = ssmR3Register(pVM, pszName, uInstance, uVersion, cbGuess, NULL, &pUnit);
1237 if (RT_SUCCESS(rc))
1238 {
1239 pUnit->enmType = SSMUNITTYPE_EXTERNAL;
1240 pUnit->u.External.pfnLivePrep = pfnLivePrep;
1241 pUnit->u.External.pfnLiveExec = pfnLiveExec;
1242 pUnit->u.External.pfnLiveVote = pfnLiveVote;
1243 pUnit->u.External.pfnSavePrep = pfnSavePrep;
1244 pUnit->u.External.pfnSaveExec = pfnSaveExec;
1245 pUnit->u.External.pfnSaveDone = pfnSaveDone;
1246 pUnit->u.External.pfnLoadPrep = pfnLoadPrep;
1247 pUnit->u.External.pfnLoadExec = pfnLoadExec;
1248 pUnit->u.External.pfnLoadDone = pfnLoadDone;
1249 pUnit->u.External.pvUser = pvUser;
1250 }
1251 return rc;
1252}
1253
1254
1255/**
1256 * Deregister one or more PDM Device data units.
1257 *
1258 * @returns VBox status.
1259 *
1260 * @param pVM The VM handle.
1261 * @param pDevIns Device instance.
1262 * @param pszName Data unit name.
1263 * Use NULL to deregister all data units for that device instance.
1264 * @param uInstance The instance identifier of the data unit.
1265 * This must together with the name be unique.
1266 * @remark Only for dynmaic data units and dynamic unloaded modules.
1267 */
1268VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance)
1269{
1270 /*
1271 * Validate input.
1272 */
1273 if (!pDevIns)
1274 {
1275 AssertMsgFailed(("pDevIns is NULL!\n"));
1276 return VERR_INVALID_PARAMETER;
1277 }
1278
1279 /*
1280 * Search the list.
1281 */
1282 size_t cchName = pszName ? strlen(pszName) : 0;
1283 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1284 PSSMUNIT pUnitPrev = NULL;
1285 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1286 while (pUnit)
1287 {
1288 if ( pUnit->enmType == SSMUNITTYPE_DEV
1289 && ( !pszName
1290 || ( pUnit->cchName == cchName
1291 && !memcmp(pUnit->szName, pszName, cchName)))
1292 && pUnit->u32Instance == uInstance
1293 )
1294 {
1295 if (pUnit->u.Dev.pDevIns == pDevIns)
1296 {
1297 /*
1298 * Unlink it, advance pointer, and free the node.
1299 */
1300 PSSMUNIT pFree = pUnit;
1301 pUnit = pUnit->pNext;
1302 if (pUnitPrev)
1303 pUnitPrev->pNext = pUnit;
1304 else
1305 pVM->ssm.s.pHead = pUnit;
1306 pVM->ssm.s.cUnits--;
1307 Log(("SSM: Removed data unit '%s' (pdm dev).\n", pFree->szName));
1308 MMR3HeapFree(pFree);
1309
1310 if (pszName)
1311 return VINF_SUCCESS;
1312 rc = VINF_SUCCESS;
1313 continue;
1314 }
1315 else if (pszName)
1316 {
1317 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1318 pUnit->u.Dev.pDevIns, pDevIns, pszName));
1319 return VERR_SSM_UNIT_NOT_OWNER;
1320 }
1321 }
1322
1323 /* next */
1324 pUnitPrev = pUnit;
1325 pUnit = pUnit->pNext;
1326 }
1327
1328 return rc;
1329}
1330
1331
1332/**
1333 * Deregister one ore more PDM Driver data units.
1334 *
1335 * @returns VBox status.
1336 * @param pVM The VM handle.
1337 * @param pDrvIns Driver instance.
1338 * @param pszName Data unit name.
1339 * Use NULL to deregister all data units for that driver instance.
1340 * @param uInstance The instance identifier of the data unit.
1341 * This must together with the name be unique. Ignored if pszName is NULL.
1342 * @remark Only for dynmaic data units and dynamic unloaded modules.
1343 */
1344VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)
1345{
1346 /*
1347 * Validate input.
1348 */
1349 if (!pDrvIns)
1350 {
1351 AssertMsgFailed(("pDrvIns is NULL!\n"));
1352 return VERR_INVALID_PARAMETER;
1353 }
1354
1355 /*
1356 * Search the list.
1357 */
1358 size_t cchName = pszName ? strlen(pszName) : 0;
1359 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1360 PSSMUNIT pUnitPrev = NULL;
1361 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1362 while (pUnit)
1363 {
1364 if ( pUnit->enmType == SSMUNITTYPE_DRV
1365 && ( !pszName
1366 || ( pUnit->cchName == cchName
1367 && !memcmp(pUnit->szName, pszName, cchName)
1368 && pUnit->u32Instance == uInstance))
1369 )
1370 {
1371 if (pUnit->u.Drv.pDrvIns == pDrvIns)
1372 {
1373 /*
1374 * Unlink it, advance pointer, and free the node.
1375 */
1376 PSSMUNIT pFree = pUnit;
1377 pUnit = pUnit->pNext;
1378 if (pUnitPrev)
1379 pUnitPrev->pNext = pUnit;
1380 else
1381 pVM->ssm.s.pHead = pUnit;
1382 pVM->ssm.s.cUnits--;
1383 Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
1384 MMR3HeapFree(pFree);
1385
1386 if (pszName)
1387 return VINF_SUCCESS;
1388 rc = VINF_SUCCESS;
1389 continue;
1390 }
1391 else if (pszName)
1392 {
1393 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1394 pUnit->u.Drv.pDrvIns, pDrvIns, pszName));
1395 return VERR_SSM_UNIT_NOT_OWNER;
1396 }
1397 }
1398
1399 /* next */
1400 pUnitPrev = pUnit;
1401 pUnit = pUnit->pNext;
1402 }
1403
1404 return rc;
1405}
1406
1407
1408/**
1409 * Deregister a data unit.
1410 *
1411 * @returns VBox status.
1412 * @param pVM The VM handle.
1413 * @param enmType Unit type
1414 * @param pszName Data unit name.
1415 * @remark Only for dynmaic data units.
1416 */
1417static int ssmR3DeregisterByNameAndType(PVM pVM, const char *pszName, SSMUNITTYPE enmType)
1418{
1419 /*
1420 * Validate input.
1421 */
1422 if (!pszName)
1423 {
1424 AssertMsgFailed(("pszName is NULL!\n"));
1425 return VERR_INVALID_PARAMETER;
1426 }
1427
1428 /*
1429 * Search the list.
1430 */
1431 size_t cchName = strlen(pszName);
1432 int rc = VERR_SSM_UNIT_NOT_FOUND;
1433 PSSMUNIT pUnitPrev = NULL;
1434 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1435 while (pUnit)
1436 {
1437 if ( pUnit->enmType == enmType
1438 && pUnit->cchName == cchName
1439 && !memcmp(pUnit->szName, pszName, cchName))
1440 {
1441 /*
1442 * Unlink it, advance pointer, and free the node.
1443 */
1444 PSSMUNIT pFree = pUnit;
1445 pUnit = pUnit->pNext;
1446 if (pUnitPrev)
1447 pUnitPrev->pNext = pUnit;
1448 else
1449 pVM->ssm.s.pHead = pUnit;
1450 pVM->ssm.s.cUnits--;
1451 Log(("SSM: Removed data unit '%s' (type=%d).\n", pFree->szName, enmType));
1452 MMR3HeapFree(pFree);
1453 return VINF_SUCCESS;
1454 }
1455
1456 /* next */
1457 pUnitPrev = pUnit;
1458 pUnit = pUnit->pNext;
1459 }
1460
1461 return rc;
1462}
1463
1464
1465/**
1466 * Deregister an internal data unit.
1467 *
1468 * @returns VBox status.
1469 * @param pVM The VM handle.
1470 * @param pszName Data unit name.
1471 * @remark Only for dynmaic data units.
1472 */
1473VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName)
1474{
1475 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_INTERNAL);
1476}
1477
1478
1479/**
1480 * Deregister an external data unit.
1481 *
1482 * @returns VBox status.
1483 * @param pVM The VM handle.
1484 * @param pszName Data unit name.
1485 * @remark Only for dynmaic data units.
1486 */
1487VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName)
1488{
1489 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_EXTERNAL);
1490}
1491
1492
1493/**
1494 * Initializes the stream after/before opening the file/whatever.
1495 *
1496 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
1497 * @param pStrm The stream handle.
1498 * @param fChecksummed Whether the stream is to be checksummed while
1499 * written/read.
1500 * @param cBuffers The number of buffers.
1501 */
1502static int ssmR3StrmInit(PSSMSTRM pStrm, bool fChecksummed, uint32_t cBuffers)
1503{
1504 Assert(cBuffers > 0);
1505
1506 /*
1507 * Init the common data members.
1508 */
1509 pStrm->fTerminating = false;
1510 pStrm->fNeedSeek = false;
1511 pStrm->rc = VINF_SUCCESS;
1512 pStrm->hIoThread = NIL_RTTHREAD;
1513 pStrm->offNeedSeekTo= UINT64_MAX;
1514
1515 pStrm->pHead = NULL;
1516 pStrm->pFree = NULL;
1517 pStrm->hEvtHead = NIL_RTSEMEVENT;
1518 pStrm->hEvtFree = NIL_RTSEMEVENT;
1519
1520 pStrm->pPending = NULL;
1521 pStrm->pCur = NULL;
1522 pStrm->offCurStream = 0;
1523 pStrm->off = 0;
1524 pStrm->fChecksummed = fChecksummed;
1525 pStrm->u32StreamCRC = fChecksummed ? RTCrc32Start() : 0;
1526 pStrm->offStreamCRC = 0;
1527
1528 /*
1529 * Allocate the buffers. Page align them in case that makes the kernel
1530 * and/or cpu happier in some way.
1531 */
1532 int rc = VINF_SUCCESS;
1533 for (uint32_t i = 0; i < cBuffers; i++)
1534 {
1535 PSSMSTRMBUF pBuf = (PSSMSTRMBUF)RTMemPageAllocZ(sizeof(*pBuf));
1536 if (!pBuf)
1537 {
1538 if (i > 2)
1539 {
1540 LogRel(("ssmR3StrmAllocBuffer: WARNING: Could only get %d stream buffers.\n", i));
1541 break;
1542 }
1543 LogRel(("ssmR3StrmAllocBuffer: Failed to allocate stream buffers. (i=%d)\n", i));
1544 return VERR_NO_MEMORY;
1545 }
1546
1547 /* link it */
1548 pBuf->pNext = pStrm->pFree;
1549 pStrm->pFree = pBuf;
1550 }
1551
1552 /*
1553 * Create the event semaphores.
1554 */
1555 rc = RTSemEventCreate(&pStrm->hEvtHead);
1556 if (RT_FAILURE(rc))
1557 return rc;
1558 rc = RTSemEventCreate(&pStrm->hEvtFree);
1559 if (RT_FAILURE(rc))
1560 return rc;
1561
1562 return VINF_SUCCESS;
1563}
1564
1565
1566/**
1567 * Destroys a list of buffers.
1568 *
1569 * @param pHead Pointer to the head.
1570 */
1571static void ssmR3StrmDestroyBufList(PSSMSTRMBUF pHead)
1572{
1573 while (pHead)
1574 {
1575 PSSMSTRMBUF pCur = pHead;
1576 pHead = pCur->pNext;
1577 pCur->pNext = NULL;
1578 RTMemPageFree(pCur);
1579 }
1580}
1581
1582
1583/**
1584 * Cleans up a stream after ssmR3StrmInit has been called (regardless of it
1585 * succeeded or not).
1586 *
1587 * @param pStrm The stream handle.
1588 */
1589static void ssmR3StrmDelete(PSSMSTRM pStrm)
1590{
1591 RTMemPageFree(pStrm->pCur);
1592 pStrm->pCur = NULL;
1593 ssmR3StrmDestroyBufList(pStrm->pHead);
1594 pStrm->pHead = NULL;
1595 ssmR3StrmDestroyBufList(pStrm->pPending);
1596 pStrm->pPending = NULL;
1597 ssmR3StrmDestroyBufList(pStrm->pFree);
1598 pStrm->pFree = NULL;
1599
1600 RTSemEventDestroy(pStrm->hEvtHead);
1601 pStrm->hEvtHead = NIL_RTSEMEVENT;
1602
1603 RTSemEventDestroy(pStrm->hEvtFree);
1604 pStrm->hEvtFree = NIL_RTSEMEVENT;
1605}
1606
1607
1608/**
1609 * Opens a file stream.
1610 *
1611 * @returns VBox status code.
1612 * @param pStrm The stream manager structure.
1613 * @param pszFilename The file to open or create.
1614 * @param fWrite Whether to open for writing or reading.
1615 * @param fChecksummed Whether the stream is to be checksummed while
1616 * written/read.
1617 * @param cBuffers The number of buffers.
1618 */
1619static int ssmR3StrmOpenFile(PSSMSTRM pStrm, const char *pszFilename, bool fWrite, bool fChecksummed, uint32_t cBuffers)
1620{
1621 int rc = ssmR3StrmInit(pStrm, fChecksummed, cBuffers);
1622 if (RT_SUCCESS(rc))
1623 {
1624 uint32_t fFlags = fWrite
1625 ? RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE
1626 : RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
1627 rc = RTFileOpen(&pStrm->hFile, pszFilename, fFlags);
1628 if (RT_SUCCESS(rc))
1629 {
1630 pStrm->fWrite = fWrite;
1631 return VINF_SUCCESS;
1632 }
1633 }
1634
1635 ssmR3StrmDelete(pStrm);
1636 pStrm->rc = rc;
1637 return rc;
1638}
1639
1640
1641/**
1642 * Raise an error condition on the stream.
1643 *
1644 * @returns true if we raised the error condition, false if the stream already
1645 * had an error condition set.
1646 *
1647 * @param pStrm The stream handle.
1648 * @param rc The VBox error status code.
1649 *
1650 * @thread Any.
1651 */
1652DECLINLINE(bool) ssmR3StrmSetError(PSSMSTRM pStrm, int rc)
1653{
1654 Assert(RT_FAILURE_NP(rc));
1655 return ASMAtomicCmpXchgS32(&pStrm->rc, rc, VINF_SUCCESS);
1656}
1657
1658
1659/**
1660 * Puts a buffer into the free list.
1661 *
1662 * @param pStrm The stream handle.
1663 * @param pBuf The buffer.
1664 *
1665 * @thread The consumer.
1666 */
1667static void ssmR3StrmPutFreeBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
1668{
1669 for (;;)
1670 {
1671 PSSMSTRMBUF pCurFreeHead = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pFree);
1672 ASMAtomicUoWritePtr((void * volatile *)&pBuf->pNext, pCurFreeHead);
1673 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pFree, pBuf, pCurFreeHead))
1674 {
1675 int rc = RTSemEventSignal(pStrm->hEvtFree);
1676 AssertRC(rc);
1677 return;
1678 }
1679 }
1680}
1681
1682
1683/**
1684 * Gets a free buffer, waits for one if necessary.
1685 *
1686 * @returns Pointer to the buffer on success. NULL if we're terminating.
1687 * @param pStrm The stream handle.
1688 *
1689 * @thread The producer.
1690 */
1691static PSSMSTRMBUF ssmR3StrmGetFreeBuf(PSSMSTRM pStrm)
1692{
1693 for (;;)
1694 {
1695 PSSMSTRMBUF pMine = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pFree);
1696 if (!pMine)
1697 {
1698 if (pStrm->fTerminating)
1699 return NULL;
1700 if (RT_FAILURE(pStrm->rc))
1701 return NULL;
1702 if ( pStrm->fWrite
1703 && pStrm->hIoThread == NIL_RTTHREAD)
1704 {
1705 int rc = ssmR3StrmWriteBuffers(pStrm);
1706 if (RT_FAILURE(rc))
1707 return NULL;
1708 }
1709 int rc = RTSemEventWaitNoResume(pStrm->hEvtFree, 30000);
1710 if ( rc == VERR_SEM_DESTROYED
1711 || pStrm->fTerminating)
1712 return NULL;
1713 continue;
1714 }
1715
1716 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pFree, pMine->pNext, pMine))
1717 {
1718 pMine->offStream = UINT64_MAX;
1719 pMine->cb = 0;
1720 pMine->pNext = NULL;
1721 pMine->fEndOfStream = false;
1722 return pMine;
1723 }
1724 }
1725}
1726
1727
1728/**
1729 * Puts a buffer onto the queue.
1730 *
1731 * @param pBuf The buffer.
1732 *
1733 * @thread The producer.
1734 */
1735static void ssmR3StrmPutBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
1736{
1737 for (;;)
1738 {
1739 PSSMSTRMBUF pCurHead = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pHead);
1740 ASMAtomicUoWritePtr((void * volatile *)&pBuf->pNext, pCurHead);
1741 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pHead, pBuf, pCurHead))
1742 {
1743 int rc = RTSemEventSignal(pStrm->hEvtHead);
1744 AssertRC(rc);
1745 return;
1746 }
1747 }
1748}
1749
1750
1751/**
1752 * Reverses the list.
1753 *
1754 * @returns The head of the reversed list.
1755 * @param pHead The head of the list to reverse.
1756 */
1757static PSSMSTRMBUF ssmR3StrmReverseList(PSSMSTRMBUF pHead)
1758{
1759 PSSMSTRMBUF pRevHead = NULL;
1760 while (pHead)
1761 {
1762 PSSMSTRMBUF pCur = pHead;
1763 pHead = pCur->pNext;
1764 pCur->pNext = pRevHead;
1765 pRevHead = pCur;
1766 }
1767 return pRevHead;
1768}
1769
1770
1771/**
1772 * Gets one buffer from the queue, will wait for one to become ready if
1773 * necessary.
1774 *
1775 * @returns Pointer to the buffer on success. NULL if we're terminating.
1776 * @param pBuf The buffer.
1777 *
1778 * @thread The consumer.
1779 */
1780static PSSMSTRMBUF ssmR3StrmGetBuf(PSSMSTRM pStrm)
1781{
1782 for (;;)
1783 {
1784 PSSMSTRMBUF pMine = pStrm->pPending;
1785 if (pMine)
1786 {
1787 pStrm->pPending = pMine->pNext;
1788 pMine->pNext = NULL;
1789 return pMine;
1790 }
1791
1792 pMine = (PSSMSTRMBUF)ASMAtomicXchgPtr((void * volatile *)&pStrm->pHead, NULL);
1793 if (pMine)
1794 pStrm->pPending = ssmR3StrmReverseList(pMine);
1795 else
1796 {
1797 if (pStrm->fTerminating)
1798 return NULL;
1799 if (RT_FAILURE(pStrm->rc))
1800 return NULL;
1801 if ( !pStrm->fWrite
1802 && pStrm->hIoThread == NIL_RTTHREAD)
1803 {
1804 int rc = ssmR3StrmReadMore(pStrm);
1805 if (RT_FAILURE(rc))
1806 return NULL;
1807 continue;
1808 }
1809
1810 int rc = RTSemEventWaitNoResume(pStrm->hEvtHead, 30000);
1811 if ( rc == VERR_SEM_DESTROYED
1812 || pStrm->fTerminating)
1813 return NULL;
1814 }
1815 }
1816}
1817
1818
1819/**
1820 * Flushes the current buffer (both write and read streams).
1821 *
1822 * @param pStrm The stream handle.
1823 */
1824static void ssmR3StrmFlushCurBuf(PSSMSTRM pStrm)
1825{
1826 if (pStrm->pCur)
1827 {
1828 PSSMSTRMBUF pBuf = pStrm->pCur;
1829 pStrm->pCur = NULL;
1830
1831 if (pStrm->fWrite)
1832 {
1833 uint32_t cb = pStrm->off;
1834 pBuf->cb = cb;
1835 pBuf->offStream = pStrm->offCurStream;
1836 if ( pStrm->fChecksummed
1837 && pStrm->offStreamCRC < cb)
1838 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
1839 &pBuf->abData[pStrm->offStreamCRC],
1840 cb - pStrm->offStreamCRC);
1841 pStrm->offCurStream += cb;
1842 pStrm->off = 0;
1843 pStrm->offStreamCRC = 0;
1844
1845 ssmR3StrmPutBuf(pStrm, pBuf);
1846 }
1847 else
1848 {
1849 uint32_t cb = pBuf->cb;
1850 if ( pStrm->fChecksummed
1851 && pStrm->offStreamCRC < cb)
1852 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
1853 &pBuf->abData[pStrm->offStreamCRC],
1854 cb - pStrm->offStreamCRC);
1855 pStrm->offCurStream += cb;
1856 pStrm->off = 0;
1857 pStrm->offStreamCRC = 0;
1858
1859 ssmR3StrmPutFreeBuf(pStrm, pBuf);
1860 }
1861 }
1862}
1863
1864
1865/**
1866 * Flush buffered data.
1867 *
1868 * @returns VBox status code. Returns VINF_EOF if we encounter a buffer with the
1869 * fEndOfStream indicator set.
1870 * @param pStrm The stream handle.
1871 *
1872 * @thread The producer thread.
1873 */
1874static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm)
1875{
1876 Assert(pStrm->fWrite);
1877
1878 /*
1879 * Just return if the stream has a pending error condition.
1880 */
1881 int rc = pStrm->rc;
1882 if (RT_FAILURE(rc))
1883 return rc;
1884
1885 /*
1886 * Grab the pending list and write it out.
1887 */
1888 PSSMSTRMBUF pHead = (PSSMSTRMBUF)ASMAtomicXchgPtr((void * volatile *)&pStrm->pHead, NULL);
1889 if (!pHead)
1890 return VINF_SUCCESS;
1891 pHead = ssmR3StrmReverseList(pHead);
1892
1893 while (pHead)
1894 {
1895 /* pop */
1896 PSSMSTRMBUF pCur = pHead;
1897 pHead = pCur->pNext;
1898
1899 /* flush */
1900 int rc = RTFileWriteAt(pStrm->hFile, pCur->offStream, &pCur->abData[0], pCur->cb, NULL);
1901 if ( RT_FAILURE(rc)
1902 && ssmR3StrmSetError(pStrm, rc))
1903 LogRel(("ssmR3StrmWriteBuffers: RTFileWriteAt failed with rc=%Rrc at offStream=%#llx\n", rc, pCur->offStream));
1904
1905 /* free */
1906 bool fEndOfStream = pCur->fEndOfStream;
1907 ssmR3StrmPutFreeBuf(pStrm, pCur);
1908 if (fEndOfStream)
1909 {
1910 Assert(!pHead);
1911 return VINF_EOF;
1912 }
1913 }
1914
1915 return pStrm->rc;
1916}
1917
1918
1919/**
1920 * Closes the stream after first flushing any pending write.
1921 *
1922 * @returns VBox status code.
1923 * @param pStrm The stream handle.
1924 */
1925static int ssmR3StrmClose(PSSMSTRM pStrm)
1926{
1927 /*
1928 * Flush, terminate the I/O thread, and close the stream.
1929 */
1930 if (pStrm->fWrite)
1931 {
1932 ssmR3StrmFlushCurBuf(pStrm);
1933 if (pStrm->hIoThread == NIL_RTTHREAD)
1934 ssmR3StrmWriteBuffers(pStrm);
1935 }
1936
1937 if (pStrm->hIoThread != NIL_RTTHREAD)
1938 {
1939 ASMAtomicWriteBool(&pStrm->fTerminating, true);
1940 int rc2 = RTSemEventSignal(pStrm->fWrite ? pStrm->hEvtHead : pStrm->hEvtFree); AssertLogRelRC(rc2);
1941 int rc3 = RTThreadWait(pStrm->hIoThread, RT_INDEFINITE_WAIT, NULL); AssertLogRelRC(rc3);
1942 pStrm->hIoThread = NIL_RTTHREAD;
1943 }
1944
1945 int rc = RTFileClose(pStrm->hFile);
1946 if (RT_FAILURE(rc))
1947 ssmR3StrmSetError(pStrm, rc);
1948 pStrm->hFile = NIL_RTFILE;
1949
1950 rc = pStrm->rc;
1951 ssmR3StrmDelete(pStrm);
1952
1953 return rc;
1954}
1955
1956
1957/**
1958 * Stream output routine.
1959 *
1960 * @returns VBox status code.
1961 * @param pStrm The stream handle.
1962 * @param pvBuf What to write.
1963 * @param cbToWrite How much to write.
1964 *
1965 * @thread The producer in a write stream (never the I/O thread).
1966 */
1967static int ssmR3StrmWrite(PSSMSTRM pStrm, const void *pvBuf, size_t cbToWrite)
1968{
1969 AssertReturn(cbToWrite > 0, VINF_SUCCESS);
1970 Assert(pStrm->fWrite);
1971
1972 /*
1973 * Squeeze as much as possible into the current buffer.
1974 */
1975 PSSMSTRMBUF pBuf = pStrm->pCur;
1976 if (RT_LIKELY(pBuf))
1977 {
1978 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
1979 if (RT_LIKELY(cbLeft >= cbToWrite))
1980 {
1981 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbToWrite);
1982 pStrm->off += (uint32_t)cbToWrite;
1983 return VINF_SUCCESS;
1984 }
1985
1986 if (cbLeft > 0)
1987 {
1988 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbLeft);
1989 pStrm->off += cbLeft;
1990 cbToWrite -= cbLeft;
1991 pvBuf = (uint8_t const *)pvBuf + cbLeft;
1992 }
1993 Assert(pStrm->off == RT_SIZEOFMEMB(SSMSTRMBUF, abData));
1994 }
1995
1996 /*
1997 * Need one or more new buffers.
1998 */
1999 do
2000 {
2001 /*
2002 * Flush the current buffer and replace it with a new one.
2003 */
2004 ssmR3StrmFlushCurBuf(pStrm);
2005 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2006 if (!pBuf)
2007 break;
2008 pStrm->pCur = pBuf;
2009 Assert(pStrm->off == 0);
2010
2011 /*
2012 * Copy data to the buffer.
2013 */
2014 uint32_t cbCopy = RT_SIZEOFMEMB(SSMSTRMBUF, abData);
2015 if (cbCopy > cbToWrite)
2016 cbCopy = (uint32_t)cbToWrite;
2017 memcpy(&pBuf->abData[0], pvBuf, cbCopy);
2018 pStrm->off = cbCopy;
2019 cbToWrite -= cbCopy;
2020 pvBuf = (uint8_t const *)pvBuf + cbCopy;
2021 } while (cbToWrite > 0);
2022
2023 return pStrm->rc;
2024}
2025
2026
2027/**
2028 * Reserves space in the current buffer so the caller can write directly to the
2029 * buffer instead of doing double buffering.
2030 *
2031 * @returns VBox status code
2032 * @param pStrm The stream handle.
2033 * @param cb The amount of buffer space to reserve.
2034 * @param ppb Where to return the pointer.
2035 */
2036static int ssmR3StrmReserveWriteBufferSpace(PSSMSTRM pStrm, size_t cb, uint8_t **ppb)
2037{
2038 Assert(pStrm->fWrite);
2039 Assert(RT_SIZEOFMEMB(SSMSTRMBUF, abData) / 4 >= cb);
2040
2041 /*
2042 * Check if there is room in the current buffer, it not flush it.
2043 */
2044 PSSMSTRMBUF pBuf = pStrm->pCur;
2045 if (pBuf)
2046 {
2047 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
2048 if (cbLeft >= cb)
2049 {
2050 *ppb = &pBuf->abData[pStrm->off];
2051 return VINF_SUCCESS;
2052 }
2053
2054 ssmR3StrmFlushCurBuf(pStrm);
2055 }
2056
2057 /*
2058 * Get a fresh buffer and return a pointer into it.
2059 */
2060 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2061 if (pBuf)
2062 {
2063 pStrm->pCur = pBuf;
2064 Assert(pStrm->off == 0);
2065 *ppb = &pBuf->abData[0];
2066 }
2067 else
2068 *ppb = NULL; /* make gcc happy. */
2069 return pStrm->rc;
2070}
2071
2072
2073/**
2074 * Commits buffer space reserved by ssmR3StrmReserveWriteBufferSpace.
2075 *
2076 * @returns VBox status code.
2077 * @param pStrm The stream handle.
2078 * @param cb The amount of buffer space to commit. This can be less
2079 * that what was reserved initially.
2080 */
2081static int ssmR3StrmCommitWriteBufferSpace(PSSMSTRM pStrm, size_t cb)
2082{
2083 Assert(pStrm->pCur);
2084 Assert(pStrm->off + cb <= RT_SIZEOFMEMB(SSMSTRMBUF, abData));
2085 pStrm->off += cb;
2086 return VINF_SUCCESS;
2087}
2088
2089
2090/**
2091 * Marks the end of the stream.
2092 *
2093 * This will cause the I/O thread to quit waiting for more buffers.
2094 *
2095 * @returns VBox status code.
2096 * @param pStrm The stream handle.
2097 */
2098static int ssmR3StrmSetEnd(PSSMSTRM pStrm)
2099{
2100 Assert(pStrm->fWrite);
2101 PSSMSTRMBUF pBuf = pStrm->pCur;
2102 if (RT_UNLIKELY(!pStrm->pCur))
2103 {
2104 pBuf = ssmR3StrmGetFreeBuf(pStrm);
2105 if (!pBuf)
2106 return pStrm->rc;
2107 pStrm->pCur = pBuf;
2108 Assert(pStrm->off == 0);
2109 }
2110 pBuf->fEndOfStream = true;
2111 ssmR3StrmFlushCurBuf(pStrm);
2112 return VINF_SUCCESS;
2113}
2114
2115
2116/**
2117 * Read more from the stream.
2118 *
2119 * @returns VBox status code. VERR_EOF gets translated into VINF_EOF.
2120 * @param pStrm The stream handle.
2121 *
2122 * @thread The I/O thread when we got one, otherwise the stream user.
2123 */
2124static int ssmR3StrmReadMore(PSSMSTRM pStrm)
2125{
2126 int rc;
2127 Log6(("ssmR3StrmReadMore:\n"));
2128
2129 /*
2130 * Undo seek done by ssmR3StrmPeekAt.
2131 */
2132 if (pStrm->fNeedSeek)
2133 {
2134 rc = RTFileSeek(pStrm->hFile, pStrm->offNeedSeekTo, RTFILE_SEEK_BEGIN, NULL);
2135 if (RT_FAILURE(rc))
2136 {
2137 if (ssmR3StrmSetError(pStrm, rc))
2138 LogRel(("ssmR3StrmReadMore: RTFileSeek(,%#llx,) failed with rc=%Rrc\n", pStrm->offNeedSeekTo, rc));
2139 return rc;
2140 }
2141 pStrm->fNeedSeek = false;
2142 pStrm->offNeedSeekTo = UINT64_MAX;
2143 }
2144
2145 /*
2146 * Get a free buffer and try fill it up.
2147 */
2148 PSSMSTRMBUF pBuf = ssmR3StrmGetFreeBuf(pStrm);
2149 if (!pBuf)
2150 return pStrm->rc;
2151
2152 pBuf->offStream = RTFileTell(pStrm->hFile);
2153 size_t cbRead = sizeof(pBuf->abData);
2154 rc = RTFileRead(pStrm->hFile, &pBuf->abData[0], cbRead, &cbRead);
2155 if ( RT_SUCCESS(rc)
2156 && cbRead > 0)
2157 {
2158 pBuf->cb = (uint32_t)cbRead;
2159 pBuf->fEndOfStream = false;
2160 Log6(("ssmR3StrmReadMore: %#010llx %#x\n", pBuf->offStream, pBuf->cb));
2161 ssmR3StrmPutBuf(pStrm, pBuf);
2162 }
2163 else if ( ( RT_SUCCESS_NP(rc)
2164 && cbRead == 0)
2165 || rc == VERR_EOF)
2166 {
2167 pBuf->cb = 0;
2168 pBuf->fEndOfStream = true;
2169 Log6(("ssmR3StrmReadMore: %#010llx 0 EOF!\n", pBuf->offStream));
2170 ssmR3StrmPutBuf(pStrm, pBuf);
2171 rc = VINF_EOF;
2172 }
2173 else
2174 {
2175 Log6(("ssmR3StrmReadMore: %#010llx rc=%Rrc!\n", pBuf->offStream, rc));
2176 if (ssmR3StrmSetError(pStrm, rc))
2177 LogRel(("ssmR3StrmReadMore: RTFileRead(,,%#x,) -> %Rrc at offset %#llx\n",
2178 sizeof(pBuf->abData), rc, pBuf->offStream));
2179 ssmR3StrmPutFreeBuf(pStrm, pBuf);
2180 }
2181 return rc;
2182}
2183
2184
2185/**
2186 * Stream input routine.
2187 *
2188 * @returns VBox status code.
2189 * @param pStrm The stream handle.
2190 * @param pvBuf Where to put what we read.
2191 * @param cbToRead How much to read.
2192 */
2193static int ssmR3StrmRead(PSSMSTRM pStrm, void *pvBuf, size_t cbToRead)
2194{
2195 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2196 Assert(!pStrm->fWrite);
2197
2198 /*
2199 * Read from the current buffer if we got one.
2200 */
2201 PSSMSTRMBUF pBuf = pStrm->pCur;
2202 if (RT_LIKELY(pBuf))
2203 {
2204 Assert(pStrm->off <= pBuf->cb);
2205 uint32_t cbLeft = pBuf->cb - pStrm->off;
2206 if (cbLeft >= cbToRead)
2207 {
2208 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbToRead);
2209 pStrm->off += (uint32_t)cbToRead;
2210 Assert(pStrm->off <= pBuf->cb);
2211 return VINF_SUCCESS;
2212 }
2213 if (cbLeft)
2214 {
2215 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbLeft);
2216 pStrm->off += cbLeft;
2217 cbToRead -= cbLeft;
2218 pvBuf = (uint8_t *)pvBuf + cbLeft;
2219 }
2220 else if (pBuf->fEndOfStream)
2221 return VERR_EOF;
2222 Assert(pStrm->off == pBuf->cb);
2223 }
2224
2225 /*
2226 * Get more buffers from the stream.
2227 */
2228 int rc = VINF_SUCCESS;
2229 do
2230 {
2231 /*
2232 * Check for EOF first - never flush the EOF buffer.
2233 */
2234 if ( pBuf
2235 && pBuf->fEndOfStream)
2236 return VERR_EOF;
2237
2238 /*
2239 * Flush the current buffer and get the next one.
2240 */
2241 ssmR3StrmFlushCurBuf(pStrm);
2242 PSSMSTRMBUF pBuf = ssmR3StrmGetBuf(pStrm);
2243 if (!pBuf)
2244 {
2245 rc = pStrm->rc;
2246 break;
2247 }
2248 pStrm->pCur = pBuf;
2249 Assert(pStrm->off == 0);
2250 Assert(pStrm->offCurStream == pBuf->offStream);
2251 if (!pBuf->cb)
2252 {
2253 Assert(pBuf->fEndOfStream);
2254 return VERR_EOF;
2255 }
2256
2257 /*
2258 * Read data from the buffer.
2259 */
2260 uint32_t cbCopy = pBuf->cb;
2261 if (cbCopy > cbToRead)
2262 cbCopy = (uint32_t)cbToRead;
2263 memcpy(pvBuf, &pBuf->abData[0], cbCopy);
2264 pStrm->off = cbCopy;
2265 cbToRead -= cbCopy;
2266 pvBuf = (uint8_t *)pvBuf + cbCopy;
2267 Assert(!pStrm->pCur || pStrm->off <= pStrm->pCur->cb);
2268 } while (cbToRead > 0);
2269
2270 return rc;
2271}
2272
2273
2274/**
2275 * Reads data from the stream but instead of copying it to some output buffer
2276 * the caller gets a pointer to into the current stream buffer.
2277 *
2278 * The returned pointer becomes invalid after the next stream operation!
2279 *
2280 * @returns Pointer to the read data residing in the stream buffer. NULL is
2281 * returned if the request amount of data isn't available in the
2282 * buffer. The caller must fall back on ssmR3StrmRead when this
2283 * happens.
2284 *
2285 * @param pStrm The stream handle.
2286 * @param cbToRead The number of bytes to tread.
2287 */
2288static uint8_t const *ssmR3StrmReadDirect(PSSMSTRM pStrm, size_t cbToRead)
2289{
2290 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2291 Assert(!pStrm->fWrite);
2292
2293 /*
2294 * Too lazy to fetch more data for the odd case that we're
2295 * exactly at the boundrary between two buffers.
2296 */
2297 PSSMSTRMBUF pBuf = pStrm->pCur;
2298 if (RT_LIKELY(pBuf))
2299 {
2300 Assert(pStrm->off <= pBuf->cb);
2301 uint32_t cbLeft = pBuf->cb - pStrm->off;
2302 if (cbLeft >= cbToRead)
2303 {
2304 uint8_t const *pb = &pBuf->abData[pStrm->off];
2305 pStrm->off += (uint32_t)cbToRead;
2306 Assert(pStrm->off <= pBuf->cb);
2307 return pb;
2308 }
2309 }
2310 return NULL;
2311}
2312
2313
2314/**
2315 * Tell current stream position.
2316 *
2317 * @returns stream position.
2318 * @param pStrm The stream handle.
2319 */
2320static uint64_t ssmR3StrmTell(PSSMSTRM pStrm)
2321{
2322 return pStrm->offCurStream + pStrm->off;
2323}
2324
2325
2326/**
2327 * Gets the intermediate stream CRC up to the current position.
2328 *
2329 * @returns CRC.
2330 * @param pStrm The stream handle.
2331 */
2332static uint32_t ssmR3StrmCurCRC(PSSMSTRM pStrm)
2333{
2334 if (!pStrm->fChecksummed)
2335 return 0;
2336 if (pStrm->offStreamCRC < pStrm->off)
2337 {
2338 PSSMSTRMBUF pBuf = pStrm->pCur; Assert(pBuf);
2339 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC, &pBuf->abData[pStrm->offStreamCRC], pStrm->off - pStrm->offStreamCRC);
2340 pStrm->offStreamCRC = pStrm->off;
2341 }
2342 else
2343 Assert(pStrm->offStreamCRC == pStrm->off);
2344 return pStrm->u32StreamCRC;
2345}
2346
2347
2348/**
2349 * Gets the final stream CRC up to the current position.
2350 *
2351 * @returns CRC.
2352 * @param pStrm The stream handle.
2353 */
2354static uint32_t ssmR3StrmFinalCRC(PSSMSTRM pStrm)
2355{
2356 if (!pStrm->fChecksummed)
2357 return 0;
2358 return RTCrc32Finish(ssmR3StrmCurCRC(pStrm));
2359}
2360
2361
2362/**
2363 * Disables checksumming of the stream.
2364 *
2365 * @param pStrm The stream handle.
2366 */
2367static void ssmR3StrmDisableChecksumming(PSSMSTRM pStrm)
2368{
2369 pStrm->fChecksummed = false;
2370}
2371
2372
2373/**
2374 * Used by SSMR3Seek to position the stream at the new unit.
2375 *
2376 * @returns VBox stutus code.
2377 * @param pStrm The strem handle.
2378 * @param off The seek offset.
2379 * @param uMethod The seek method.
2380 * @param u32CurCRC The current CRC at the seek position.
2381 */
2382static int ssmR3StrmSeek(PSSMSTRM pStrm, int64_t off, uint32_t uMethod, uint32_t u32CurCRC)
2383{
2384 AssertReturn(!pStrm->fWrite, VERR_NOT_SUPPORTED);
2385 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
2386
2387 uint64_t offStream;
2388 int rc = RTFileSeek(pStrm->hFile, off, uMethod, &offStream);
2389 if (RT_SUCCESS(rc))
2390 {
2391 pStrm->fNeedSeek = false;
2392 pStrm->offNeedSeekTo= UINT64_MAX;
2393 pStrm->offCurStream = offStream;
2394 pStrm->off = 0;
2395 pStrm->offStreamCRC = 0;
2396 if (pStrm->fChecksummed)
2397 pStrm->u32StreamCRC = u32CurCRC;
2398 if (pStrm->pCur)
2399 {
2400 ssmR3StrmPutFreeBuf(pStrm, pStrm->pCur);
2401 pStrm->pCur = NULL;
2402 }
2403 }
2404 return rc;
2405}
2406
2407
2408/**
2409 * Skip some bytes in the stream.
2410 *
2411 * This is only used if someone didn't read all of their data in the V1 format,
2412 * so don't bother making this very efficient yet.
2413 *
2414 * @returns VBox status code.
2415 * @param pStrm The stream handle.
2416 * @param offDst The destination offset.
2417 */
2418static int ssmR3StrmSkipTo(PSSMSTRM pStrm, uint64_t offDst)
2419{
2420 /* dead simple - lazy bird! */
2421 for (;;)
2422 {
2423 uint64_t offCur = ssmR3StrmTell(pStrm);
2424 AssertReturn(offCur <= offDst, VERR_INTERNAL_ERROR_4);
2425 if (offCur == offDst)
2426 return VINF_SUCCESS;
2427
2428 uint8_t abBuf[4096];
2429 size_t cbToRead = RT_MIN(sizeof(abBuf), offDst - offCur);
2430 int rc = ssmR3StrmRead(pStrm, abBuf, cbToRead);
2431 if (RT_FAILURE(rc))
2432 return rc;
2433 }
2434}
2435
2436
2437/**
2438 * Get the size of the file.
2439 *
2440 * This does not work for non-file streams!
2441 *
2442 * @returns The file size, or UINT64_MAX if not a file stream.
2443 * @param pStrm The stream handle.
2444 */
2445static uint64_t ssmR3StrmGetSize(PSSMSTRM pStrm)
2446{
2447 uint64_t cbFile;
2448 int rc = RTFileGetSize(pStrm->hFile, &cbFile);
2449 AssertLogRelRCReturn(rc, UINT64_MAX);
2450 return cbFile;
2451}
2452
2453
2454/***
2455 * Tests if the stream is a file stream or not.
2456 *
2457 * @returns true / false.
2458 * @param pStrm The stream handle.
2459 */
2460static bool ssmR3StrmIsFile(PSSMSTRM pStrm)
2461{
2462 return pStrm->hFile != NIL_RTFILE;
2463}
2464
2465
2466/**
2467 * Peeks at data in a file stream without buffering anything (or upsetting
2468 * the buffering for that matter).
2469 *
2470 * @returns VBox status code.
2471 * @param pStrm The stream handle
2472 * @param off The offset to start peeking at. Use a negative offset to
2473 * peek at something relative to the end of the file.
2474 * @param pvBuf Output buffer.
2475 * @param cbToRead How much to read.
2476 * @param poff Where to optionally store the position. Useful when
2477 * using a negative off.
2478 *
2479 * @remarks Failures occuring while peeking will not be raised on the stream.
2480 */
2481static int ssmR3StrmPeekAt(PSSMSTRM pStrm, RTFOFF off, void *pvBuf, size_t cbToRead, uint64_t *poff)
2482{
2483 AssertReturn(!pStrm->fWrite && pStrm->hFile != NIL_RTFILE, VERR_NOT_SUPPORTED);
2484 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
2485
2486 if (!pStrm->fNeedSeek)
2487 {
2488 pStrm->fNeedSeek = true;
2489 pStrm->offNeedSeekTo = pStrm->offCurStream + (pStrm->pCur ? pStrm->pCur->cb : 0);
2490 }
2491
2492 int rc = RTFileSeek(pStrm->hFile, off, off >= 0 ? RTFILE_SEEK_BEGIN : RTFILE_SEEK_END, poff);
2493 if (RT_SUCCESS(rc))
2494 rc = RTFileRead(pStrm->hFile, pvBuf, cbToRead, NULL);
2495
2496 return rc;
2497}
2498
2499
2500/**
2501 * The I/O thread.
2502 *
2503 * @returns VINF_SUCCESS (ignored).
2504 * @param hSelf The thread handle.
2505 * @param pvStrm The stream handle.
2506 */
2507static DECLCALLBACK(int) ssmR3StrmIoThread(RTTHREAD hSelf, void *pvStrm)
2508{
2509 PSSMSTRM pStrm = (PSSMSTRM)pvStrm;
2510 ASMAtomicWriteHandle(&pStrm->hIoThread, hSelf); /* paranoia */
2511
2512 Log(("ssmR3StrmIoThread: starts working\n"));
2513 if (pStrm->fWrite)
2514 {
2515 /*
2516 * Write until error or terminated.
2517 */
2518 for (;;)
2519 {
2520 int rc = ssmR3StrmWriteBuffers(pStrm);
2521 if ( RT_FAILURE(rc)
2522 || rc == VINF_EOF)
2523 {
2524 Log(("ssmR3StrmIoThread: quitting writing with rc=%Rrc.\n", rc));
2525 break;
2526 }
2527 if (RT_FAILURE(pStrm->rc))
2528 {
2529 Log(("ssmR3StrmIoThread: quitting writing with stream rc=%Rrc\n", pStrm->rc));
2530 break;
2531 }
2532
2533 if (ASMAtomicReadBool(&pStrm->fTerminating))
2534 {
2535 if (!ASMAtomicReadPtr((void * volatile *)&pStrm->pHead))
2536 {
2537 Log(("ssmR3StrmIoThread: quitting writing because of pending termination.\n"));
2538 break;
2539 }
2540 Log(("ssmR3StrmIoThread: postponing termination because of pending buffers.\n"));
2541 }
2542 else if (!ASMAtomicReadPtr((void * volatile *)&pStrm->pHead))
2543 {
2544 rc = RTSemEventWait(pStrm->hEvtHead, RT_INDEFINITE_WAIT);
2545 AssertLogRelRC(rc);
2546 }
2547 }
2548 }
2549 else
2550 {
2551 /*
2552 * Read until end of file, error or termination.
2553 */
2554 for (;;)
2555 {
2556 if (ASMAtomicReadBool(&pStrm->fTerminating))
2557 {
2558 Log(("ssmR3StrmIoThread: quitting reading because of pending termination.\n"));
2559 break;
2560 }
2561
2562 int rc = ssmR3StrmReadMore(pStrm);
2563 if ( RT_FAILURE(rc)
2564 || rc == VINF_EOF)
2565 {
2566 Log(("ssmR3StrmIoThread: quitting reading with rc=%Rrc\n", rc));
2567 break;
2568 }
2569 if (RT_FAILURE(pStrm->rc))
2570 {
2571 Log(("ssmR3StrmIoThread: quitting reading with stream rc=%Rrc\n", pStrm->rc));
2572 break;
2573 }
2574 }
2575 }
2576
2577 return VINF_SUCCESS;
2578}
2579
2580
2581/**
2582 * Starts the I/O thread for the specified stream.
2583 *
2584 * @param pStrm The stream handle.
2585 */
2586static void ssmR3StrmStartIoThread(PSSMSTRM pStrm)
2587{
2588 Assert(pStrm->hIoThread == NIL_RTTHREAD);
2589
2590 RTTHREAD hThread;
2591 int rc = RTThreadCreate(&hThread, ssmR3StrmIoThread, pStrm, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SSM-IO");
2592 AssertRCReturnVoid(rc);
2593 ASMAtomicWriteHandle(&pStrm->hIoThread, hThread); /* paranoia */
2594}
2595
2596
2597/**
2598 * Works the progress calculation.
2599 *
2600 * @param pSSM The SSM handle.
2601 * @param cbAdvance Number of bytes to advance
2602 */
2603static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
2604{
2605 /* Can't advance it beyond the estimated end of the unit. */
2606 uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
2607 if (cbAdvance > cbLeft)
2608 cbAdvance = cbLeft;
2609 pSSM->offEst += cbAdvance;
2610
2611 /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
2612 while ( pSSM->offEst >= pSSM->offEstProgress
2613 && pSSM->uPercent <= 100-pSSM->uPercentDone)
2614 {
2615 if (pSSM->pfnProgress)
2616 pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
2617 pSSM->uPercent++;
2618 pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal
2619 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
2620 }
2621}
2622
2623
2624/**
2625 * Makes the SSM operation cancellable or not (via SSMR3Cancel).
2626 *
2627 * @param pVM The VM handle.
2628 * @param pSSM The saved state handle. (SSMHANDLE::rc may be set.)
2629 * @param fCancellable The new state.
2630 */
2631static void ssmR3SetCancellable(PVM pVM, PSSMHANDLE pSSM, bool fCancellable)
2632{
2633 RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
2634 if (fCancellable)
2635 {
2636 Assert(!pVM->ssm.s.pSSM);
2637 pVM->ssm.s.pSSM = pSSM;
2638 }
2639 else
2640 {
2641 if (pVM->ssm.s.pSSM == pSSM)
2642 pVM->ssm.s.pSSM = NULL;
2643
2644 uint32_t fCancelled = ASMAtomicUoReadU32(&pSSM->fCancelled);
2645 if ( fCancelled == SSMHANDLE_CANCELLED
2646 && RT_SUCCESS(pSSM->rc))
2647 pSSM->rc = VERR_SSM_CANCELLED;
2648 }
2649
2650 RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
2651}
2652
2653
2654/**
2655 * Finishes a data unit.
2656 * All buffers and compressor instances are flushed and destroyed.
2657 *
2658 * @returns VBox status.
2659 * @param pSSM SSM operation handle.
2660 */
2661static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
2662{
2663 //Log2(("ssmR3DataWriteFinish: %#010llx start\n", ssmR3StrmTell(&pSSM->Strm)));
2664 int rc = ssmR3DataFlushBuffer(pSSM);
2665 if (RT_SUCCESS(rc))
2666 {
2667 pSSM->offUnit = UINT64_MAX;
2668 return VINF_SUCCESS;
2669 }
2670
2671 if (RT_SUCCESS(pSSM->rc))
2672 pSSM->rc = rc;
2673 Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
2674 return rc;
2675}
2676
2677
2678/**
2679 * Begins writing the data of a data unit.
2680 *
2681 * Errors are signalled via pSSM->rc.
2682 *
2683 * @param pSSM The saved state handle.
2684 */
2685static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
2686{
2687 pSSM->offUnit = 0;
2688}
2689
2690
2691/**
2692 * Writes a record to the current data item in the saved state file.
2693 *
2694 * @returns VBox status code. Sets pSSM->rc on failure.
2695 * @param pSSM The saved state handle.
2696 * @param pvBuf The bits to write.
2697 * @param cbBuf The number of bytes to write.
2698 */
2699static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
2700{
2701 Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
2702 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
2703
2704 /*
2705 * Check that everything is fine.
2706 */
2707 if (RT_FAILURE(pSSM->rc))
2708 return pSSM->rc;
2709
2710 /*
2711 * Write the data item in 1MB chunks for progress indicator reasons.
2712 */
2713 while (cbBuf > 0)
2714 {
2715 size_t cbChunk = RT_MIN(cbBuf, _1M);
2716 int rc = ssmR3StrmWrite(&pSSM->Strm, pvBuf, cbChunk);
2717 if (RT_FAILURE(rc))
2718 return rc;
2719 pSSM->offUnit += cbChunk;
2720 cbBuf -= cbChunk;
2721 pvBuf = (char *)pvBuf + cbChunk;
2722 }
2723
2724 return VINF_SUCCESS;
2725}
2726
2727
2728/**
2729 * Writes a record header for the specified amount of data.
2730 *
2731 * @returns VBox status code. Sets pSSM->rc on failure.
2732 * @param pSSM The saved state handle
2733 * @param cb The amount of data.
2734 * @param u8TypeAndFlags The record type and flags.
2735 */
2736static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
2737{
2738 size_t cbHdr;
2739 uint8_t abHdr[8];
2740 abHdr[0] = u8TypeAndFlags;
2741 if (cb < 0x80)
2742 {
2743 cbHdr = 2;
2744 abHdr[1] = (uint8_t)cb;
2745 }
2746 else if (cb < 0x00000800)
2747 {
2748 cbHdr = 3;
2749 abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
2750 abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
2751 }
2752 else if (cb < 0x00010000)
2753 {
2754 cbHdr = 4;
2755 abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
2756 abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
2757 abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
2758 }
2759 else if (cb < 0x00200000)
2760 {
2761 cbHdr = 5;
2762 abHdr[1] = (uint8_t)(0xf0 | (cb >> 18));
2763 abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
2764 abHdr[3] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
2765 abHdr[4] = (uint8_t)(0x80 | (cb & 0x3f));
2766 }
2767 else if (cb < 0x04000000)
2768 {
2769 cbHdr = 6;
2770 abHdr[1] = (uint8_t)(0xf8 | (cb >> 24));
2771 abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
2772 abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
2773 abHdr[4] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
2774 abHdr[5] = (uint8_t)(0x80 | (cb & 0x3f));
2775 }
2776 else if (cb <= 0x7fffffff)
2777 {
2778 cbHdr = 7;
2779 abHdr[1] = (uint8_t)(0xfc | (cb >> 30));
2780 abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
2781 abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
2782 abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
2783 abHdr[5] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
2784 abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
2785 }
2786 else
2787 AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_INTERNAL_ERROR);
2788
2789 Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
2790 ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
2791
2792 return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
2793}
2794
2795
2796/**
2797 * Worker that flushes the buffered data.
2798 *
2799 * @returns VBox status code. Will set pSSM->rc on error.
2800 * @param pSSM The saved state handle.
2801 */
2802static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
2803{
2804 /*
2805 * Check how much there current is in the buffer.
2806 */
2807 uint32_t cb = pSSM->u.Write.offDataBuffer;
2808 if (!cb)
2809 return pSSM->rc;
2810 pSSM->u.Write.offDataBuffer = 0;
2811
2812 /*
2813 * Write a record header and then the data.
2814 * (No need for fancy optimizations here any longer since the stream is
2815 * fully buffered.)
2816 */
2817 int rc = ssmR3DataWriteRecHdr(pSSM, cb, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
2818 if (RT_SUCCESS(rc))
2819 rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
2820 ssmR3Progress(pSSM, cb);
2821 return rc;
2822}
2823
2824
2825/**
2826 * ssmR3DataWrite worker that writes big stuff.
2827 *
2828 * @returns VBox status code
2829 * @param pSSM The saved state handle.
2830 * @param pvBuf The bits to write.
2831 * @param cbBuf The number of bytes to write.
2832 */
2833static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
2834{
2835 int rc = ssmR3DataFlushBuffer(pSSM);
2836 if (RT_SUCCESS(rc))
2837 {
2838 /*
2839 * Split it up into compression blocks.
2840 */
2841 for (;;)
2842 {
2843 AssertCompile(SSM_ZIP_BLOCK_SIZE == PAGE_SIZE);
2844 if ( cbBuf >= SSM_ZIP_BLOCK_SIZE
2845 && ( ((uintptr_t)pvBuf & 0xf)
2846 || !ASMMemIsZeroPage(pvBuf))
2847 )
2848 {
2849 /*
2850 * Compress it.
2851 */
2852 AssertCompile(1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE < 0x00010000);
2853 uint8_t *pb;
2854 rc = ssmR3StrmReserveWriteBufferSpace(&pSSM->Strm, 1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE, &pb);
2855 if (RT_FAILURE(rc))
2856 break;
2857 size_t cbRec = SSM_ZIP_BLOCK_SIZE - (SSM_ZIP_BLOCK_SIZE / 16);
2858 rc = RTZipBlockCompress(RTZIPTYPE_LZF, RTZIPLEVEL_FAST, 0 /*fFlags*/,
2859 pvBuf, SSM_ZIP_BLOCK_SIZE,
2860 pb + 1 + 3 + 1, cbRec, &cbRec);
2861 if (RT_SUCCESS(rc))
2862 {
2863 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF;
2864 pb[4] = SSM_ZIP_BLOCK_SIZE / _1K;
2865 cbRec += 1;
2866 }
2867 else
2868 {
2869 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
2870 memcpy(&pb[4], pvBuf, SSM_ZIP_BLOCK_SIZE);
2871 cbRec = SSM_ZIP_BLOCK_SIZE;
2872 }
2873 pb[1] = (uint8_t)(0xe0 | ( cbRec >> 12));
2874 pb[2] = (uint8_t)(0x80 | ((cbRec >> 6) & 0x3f));
2875 pb[3] = (uint8_t)(0x80 | ( cbRec & 0x3f));
2876 cbRec += 1 + 3;
2877 rc = ssmR3StrmCommitWriteBufferSpace(&pSSM->Strm, cbRec);
2878 if (RT_FAILURE(rc))
2879 break;
2880
2881 pSSM->offUnit += cbRec;
2882 ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
2883
2884 /* advance */
2885 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
2886 return VINF_SUCCESS;
2887 cbBuf -= SSM_ZIP_BLOCK_SIZE;
2888 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
2889 }
2890 else if (cbBuf >= SSM_ZIP_BLOCK_SIZE)
2891 {
2892 /*
2893 * Zero block.
2894 */
2895 uint8_t abRec[3];
2896 abRec[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_ZERO;
2897 abRec[1] = 1;
2898 abRec[2] = SSM_ZIP_BLOCK_SIZE / _1K;
2899 Log3(("ssmR3DataWriteBig: %08llx|%08llx/%08x: ZERO\n", ssmR3StrmTell(&pSSM->Strm) + 2, pSSM->offUnit + 2, 1));
2900 rc = ssmR3DataWriteRaw(pSSM, &abRec[0], sizeof(abRec));
2901 if (RT_FAILURE(rc))
2902 break;
2903
2904 /* advance */
2905 ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
2906 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
2907 return VINF_SUCCESS;
2908 cbBuf -= SSM_ZIP_BLOCK_SIZE;
2909 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
2910 }
2911 else
2912 {
2913 /*
2914 * Less than one block left, store it the simple way.
2915 */
2916 rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
2917 if (RT_SUCCESS(rc))
2918 rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
2919 ssmR3Progress(pSSM, cbBuf);
2920 break;
2921 }
2922 }
2923 }
2924 return rc;
2925}
2926
2927
2928/**
2929 * ssmR3DataWrite worker that is called when there isn't enough room in the
2930 * buffer for the current chunk of data.
2931 *
2932 * This will first flush the buffer and then add the new bits to it.
2933 *
2934 * @returns VBox status code
2935 * @param pSSM The saved state handle.
2936 * @param pvBuf The bits to write.
2937 * @param cbBuf The number of bytes to write.
2938 */
2939static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
2940{
2941 int rc = ssmR3DataFlushBuffer(pSSM);
2942 if (RT_SUCCESS(rc))
2943 {
2944 memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
2945 pSSM->u.Write.offDataBuffer = (uint32_t)cbBuf;
2946 }
2947 return rc;
2948}
2949
2950
2951/**
2952 * Writes data to the current data unit.
2953 *
2954 * This is an inlined wrapper that optimizes the small writes that so many of
2955 * the APIs make.
2956 *
2957 * @returns VBox status code
2958 * @param pSSM The saved state handle.
2959 * @param pvBuf The bits to write.
2960 * @param cbBuf The number of bytes to write.
2961 */
2962DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
2963{
2964 if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
2965 return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
2966 if (!cbBuf)
2967 return VINF_SUCCESS;
2968
2969 uint32_t off = pSSM->u.Write.offDataBuffer;
2970 if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
2971 return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
2972
2973 memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
2974 pSSM->u.Write.offDataBuffer = off + (uint32_t)cbBuf;
2975 return VINF_SUCCESS;
2976}
2977
2978
2979/**
2980 * Puts a structure.
2981 *
2982 * @returns VBox status code.
2983 * @param pSSM The saved state handle.
2984 * @param pvStruct The structure address.
2985 * @param paFields The array of structure fields descriptions.
2986 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
2987 */
2988VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
2989{
2990 /* begin marker. */
2991 int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
2992 if (RT_FAILURE(rc))
2993 return rc;
2994
2995 /* put the fields */
2996 for (PCSSMFIELD pCur = paFields;
2997 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
2998 pCur++)
2999 {
3000 rc = ssmR3DataWrite(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
3001 if (RT_FAILURE(rc))
3002 return rc;
3003 }
3004
3005 /* end marker */
3006 return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
3007}
3008
3009
3010/**
3011 * Saves a boolean item to the current data unit.
3012 *
3013 * @returns VBox status.
3014 * @param pSSM SSM operation handle.
3015 * @param fBool Item to save.
3016 */
3017VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
3018{
3019 SSM_ASSERT_WRITEABLE_RET(pSSM);
3020 SSM_CHECK_CANCELLED_RET(pSSM);
3021 uint8_t u8 = fBool; /* enforce 1 byte size */
3022 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
3023}
3024
3025
3026/**
3027 * Saves a 8-bit unsigned integer item to the current data unit.
3028 *
3029 * @returns VBox status.
3030 * @param pSSM SSM operation handle.
3031 * @param u8 Item to save.
3032 */
3033VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
3034{
3035 SSM_ASSERT_WRITEABLE_RET(pSSM);
3036 SSM_CHECK_CANCELLED_RET(pSSM);
3037 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
3038}
3039
3040
3041/**
3042 * Saves a 8-bit signed integer item to the current data unit.
3043 *
3044 * @returns VBox status.
3045 * @param pSSM SSM operation handle.
3046 * @param i8 Item to save.
3047 */
3048VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
3049{
3050 SSM_ASSERT_WRITEABLE_RET(pSSM);
3051 SSM_CHECK_CANCELLED_RET(pSSM);
3052 return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
3053}
3054
3055
3056/**
3057 * Saves a 16-bit unsigned integer item to the current data unit.
3058 *
3059 * @returns VBox status.
3060 * @param pSSM SSM operation handle.
3061 * @param u16 Item to save.
3062 */
3063VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
3064{
3065 SSM_ASSERT_WRITEABLE_RET(pSSM);
3066 SSM_CHECK_CANCELLED_RET(pSSM);
3067 return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
3068}
3069
3070
3071/**
3072 * Saves a 16-bit signed integer item to the current data unit.
3073 *
3074 * @returns VBox status.
3075 * @param pSSM SSM operation handle.
3076 * @param i16 Item to save.
3077 */
3078VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
3079{
3080 SSM_ASSERT_WRITEABLE_RET(pSSM);
3081 SSM_CHECK_CANCELLED_RET(pSSM);
3082 return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
3083}
3084
3085
3086/**
3087 * Saves a 32-bit unsigned integer item to the current data unit.
3088 *
3089 * @returns VBox status.
3090 * @param pSSM SSM operation handle.
3091 * @param u32 Item to save.
3092 */
3093VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
3094{
3095 SSM_ASSERT_WRITEABLE_RET(pSSM);
3096 SSM_CHECK_CANCELLED_RET(pSSM);
3097 return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
3098}
3099
3100
3101/**
3102 * Saves a 32-bit signed integer item to the current data unit.
3103 *
3104 * @returns VBox status.
3105 * @param pSSM SSM operation handle.
3106 * @param i32 Item to save.
3107 */
3108VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
3109{
3110 SSM_ASSERT_WRITEABLE_RET(pSSM);
3111 SSM_CHECK_CANCELLED_RET(pSSM);
3112 return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
3113}
3114
3115
3116/**
3117 * Saves a 64-bit unsigned integer item to the current data unit.
3118 *
3119 * @returns VBox status.
3120 * @param pSSM SSM operation handle.
3121 * @param u64 Item to save.
3122 */
3123VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
3124{
3125 SSM_ASSERT_WRITEABLE_RET(pSSM);
3126 SSM_CHECK_CANCELLED_RET(pSSM);
3127 return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
3128}
3129
3130
3131/**
3132 * Saves a 64-bit signed integer item to the current data unit.
3133 *
3134 * @returns VBox status.
3135 * @param pSSM SSM operation handle.
3136 * @param i64 Item to save.
3137 */
3138VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
3139{
3140 SSM_ASSERT_WRITEABLE_RET(pSSM);
3141 SSM_CHECK_CANCELLED_RET(pSSM);
3142 return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
3143}
3144
3145
3146/**
3147 * Saves a 128-bit unsigned integer item to the current data unit.
3148 *
3149 * @returns VBox status.
3150 * @param pSSM SSM operation handle.
3151 * @param u128 Item to save.
3152 */
3153VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
3154{
3155 SSM_ASSERT_WRITEABLE_RET(pSSM);
3156 SSM_CHECK_CANCELLED_RET(pSSM);
3157 return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
3158}
3159
3160
3161/**
3162 * Saves a 128-bit signed integer item to the current data unit.
3163 *
3164 * @returns VBox status.
3165 * @param pSSM SSM operation handle.
3166 * @param i128 Item to save.
3167 */
3168VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
3169{
3170 SSM_ASSERT_WRITEABLE_RET(pSSM);
3171 SSM_CHECK_CANCELLED_RET(pSSM);
3172 return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
3173}
3174
3175
3176/**
3177 * Saves a VBox unsigned integer item to the current data unit.
3178 *
3179 * @returns VBox status.
3180 * @param pSSM SSM operation handle.
3181 * @param u Item to save.
3182 */
3183VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
3184{
3185 SSM_ASSERT_WRITEABLE_RET(pSSM);
3186 SSM_CHECK_CANCELLED_RET(pSSM);
3187 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3188}
3189
3190
3191/**
3192 * Saves a VBox signed integer item to the current data unit.
3193 *
3194 * @returns VBox status.
3195 * @param pSSM SSM operation handle.
3196 * @param i Item to save.
3197 */
3198VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
3199{
3200 SSM_ASSERT_WRITEABLE_RET(pSSM);
3201 SSM_CHECK_CANCELLED_RET(pSSM);
3202 return ssmR3DataWrite(pSSM, &i, sizeof(i));
3203}
3204
3205
3206/**
3207 * Saves a GC natural unsigned integer item to the current data unit.
3208 *
3209 * @returns VBox status.
3210 * @param pSSM SSM operation handle.
3211 * @param u Item to save.
3212 *
3213 * @deprecated Silly type, don't use it.
3214 */
3215VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
3216{
3217 SSM_ASSERT_WRITEABLE_RET(pSSM);
3218 SSM_CHECK_CANCELLED_RET(pSSM);
3219 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3220}
3221
3222
3223/**
3224 * Saves a GC unsigned integer register item to the current data unit.
3225 *
3226 * @returns VBox status.
3227 * @param pSSM SSM operation handle.
3228 * @param u Item to save.
3229 */
3230VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
3231{
3232 SSM_ASSERT_WRITEABLE_RET(pSSM);
3233 SSM_CHECK_CANCELLED_RET(pSSM);
3234 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3235}
3236
3237
3238/**
3239 * Saves a 32 bits GC physical address item to the current data unit.
3240 *
3241 * @returns VBox status.
3242 * @param pSSM SSM operation handle.
3243 * @param GCPhys The item to save
3244 */
3245VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
3246{
3247 SSM_ASSERT_WRITEABLE_RET(pSSM);
3248 SSM_CHECK_CANCELLED_RET(pSSM);
3249 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3250}
3251
3252
3253/**
3254 * Saves a 64 bits GC physical address item to the current data unit.
3255 *
3256 * @returns VBox status.
3257 * @param pSSM SSM operation handle.
3258 * @param GCPhys The item to save
3259 */
3260VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
3261{
3262 SSM_ASSERT_WRITEABLE_RET(pSSM);
3263 SSM_CHECK_CANCELLED_RET(pSSM);
3264 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3265}
3266
3267
3268/**
3269 * Saves a GC physical address item to the current data unit.
3270 *
3271 * @returns VBox status.
3272 * @param pSSM SSM operation handle.
3273 * @param GCPhys The item to save
3274 */
3275VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
3276{
3277 SSM_ASSERT_WRITEABLE_RET(pSSM);
3278 SSM_CHECK_CANCELLED_RET(pSSM);
3279 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3280}
3281
3282
3283/**
3284 * Saves a GC virtual address item to the current data unit.
3285 *
3286 * @returns VBox status.
3287 * @param pSSM SSM operation handle.
3288 * @param GCPtr The item to save.
3289 */
3290VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
3291{
3292 SSM_ASSERT_WRITEABLE_RET(pSSM);
3293 SSM_CHECK_CANCELLED_RET(pSSM);
3294 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
3295}
3296
3297
3298/**
3299 * Saves an RC virtual address item to the current data unit.
3300 *
3301 * @returns VBox status.
3302 * @param pSSM SSM operation handle.
3303 * @param RCPtr The item to save.
3304 */
3305VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
3306{
3307 SSM_ASSERT_WRITEABLE_RET(pSSM);
3308 SSM_CHECK_CANCELLED_RET(pSSM);
3309 return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
3310}
3311
3312
3313/**
3314 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
3315 *
3316 * @returns VBox status.
3317 * @param pSSM SSM operation handle.
3318 * @param GCPtr The item to save.
3319 */
3320VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
3321{
3322 SSM_ASSERT_WRITEABLE_RET(pSSM);
3323 SSM_CHECK_CANCELLED_RET(pSSM);
3324 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
3325}
3326
3327
3328/**
3329 * Saves a I/O port address item to the current data unit.
3330 *
3331 * @returns VBox status.
3332 * @param pSSM SSM operation handle.
3333 * @param IOPort The item to save.
3334 */
3335VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
3336{
3337 SSM_ASSERT_WRITEABLE_RET(pSSM);
3338 SSM_CHECK_CANCELLED_RET(pSSM);
3339 return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
3340}
3341
3342
3343/**
3344 * Saves a selector item to the current data unit.
3345 *
3346 * @returns VBox status.
3347 * @param pSSM SSM operation handle.
3348 * @param Sel The item to save.
3349 */
3350VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
3351{
3352 SSM_ASSERT_WRITEABLE_RET(pSSM);
3353 SSM_CHECK_CANCELLED_RET(pSSM);
3354 return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
3355}
3356
3357
3358/**
3359 * Saves a memory item to the current data unit.
3360 *
3361 * @returns VBox status.
3362 * @param pSSM SSM operation handle.
3363 * @param pv Item to save.
3364 * @param cb Size of the item.
3365 */
3366VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
3367{
3368 SSM_ASSERT_WRITEABLE_RET(pSSM);
3369 SSM_CHECK_CANCELLED_RET(pSSM);
3370 return ssmR3DataWrite(pSSM, pv, cb);
3371}
3372
3373
3374/**
3375 * Saves a zero terminated string item to the current data unit.
3376 *
3377 * @returns VBox status.
3378 * @param pSSM SSM operation handle.
3379 * @param psz Item to save.
3380 */
3381VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
3382{
3383 SSM_ASSERT_WRITEABLE_RET(pSSM);
3384 SSM_CHECK_CANCELLED_RET(pSSM);
3385
3386 size_t cch = strlen(psz);
3387 if (cch > _1M)
3388 {
3389 AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
3390 return VERR_TOO_MUCH_DATA;
3391 }
3392 uint32_t u32 = (uint32_t)cch;
3393 int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
3394 if (rc)
3395 return rc;
3396 return ssmR3DataWrite(pSSM, psz, cch);
3397}
3398
3399
3400/**
3401 * Worker for SSMR3LiveDone and SSMR3Save that closes the handle and deletes the
3402 * saved state file on failure.
3403 *
3404 * @returns VBox status code (pSSM->rc).
3405 * @param pVM The VM handle.
3406 * @param pSSM The saved state handle.
3407 */
3408static int ssmR3SaveDoClose(PVM pVM, PSSMHANDLE pSSM)
3409{
3410 VM_ASSERT_EMT0(pVM);
3411
3412 /*
3413 * Make it non-cancellable, close the stream and delete the file on failure.
3414 */
3415 ssmR3SetCancellable(pVM, pSSM, false);
3416 int rc = ssmR3StrmClose(&pSSM->Strm);
3417 if (RT_SUCCESS(rc))
3418 rc = pSSM->rc;
3419 if (RT_SUCCESS(rc))
3420 {
3421 if (pSSM->pfnProgress)
3422 pSSM->pfnProgress(pVM, 100, pSSM->pvUser);
3423 LogRel(("SSM: Successfully saved the VM state to '%s'\n",
3424 pSSM->pszFilename ? pSSM->pszFilename : "<remote-machine>"));
3425 }
3426 else
3427 {
3428 if (pSSM->pszFilename)
3429 {
3430 int rc2 = RTFileDelete(pSSM->pszFilename);
3431 AssertRC(rc2);
3432 if (RT_SUCCESS(rc2))
3433 LogRel(("SSM: Failed to save the VM state to '%s' (file deleted): %Rrc\n",
3434 pSSM->pszFilename, rc));
3435 else
3436 LogRel(("SSM: Failed to save the VM state to '%s' (file deletion failed, rc2=%Rrc): %Rrc\n",
3437 pSSM->pszFilename, rc2, rc));
3438 }
3439 else
3440 LogRel(("SSM: Failed to save the VM state.\n"));
3441 }
3442
3443 /*
3444 * Trash the handle before freeing it.
3445 */
3446 ASMAtomicWriteU32(&pSSM->fCancelled, 0);
3447 pSSM->pVM = NULL;
3448 pSSM->enmAfter = SSMAFTER_INVALID;
3449 pSSM->enmOp = SSMSTATE_INVALID;
3450 RTMemFree(pSSM);
3451
3452 return rc;
3453}
3454
3455
3456/**
3457 * Closes the SSM handle.
3458 *
3459 * This must always be called on a handled returned by SSMR3LiveToFile or
3460 * SSMR3LiveToRemote.
3461 *
3462 * @returns VBox status.
3463 *
3464 * @param pSSM The SSM handle returned by SSMR3LiveToFile or
3465 * SSMR3LiveToRemote.
3466 *
3467 * @thread EMT(0).
3468 */
3469VMMR3_INT_DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM)
3470{
3471 LogFlow(("SSMR3LiveDone: pSSM=%p\n", pSSM));
3472
3473 /*
3474 * Validate input.
3475 */
3476 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
3477 PVM pVM = pSSM->pVM;
3478 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
3479 VM_ASSERT_EMT0(pVM);
3480 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
3481 || pSSM->enmAfter == SSMAFTER_CONTINUE,
3482 ("%d\n", pSSM->enmAfter),
3483 VERR_INVALID_PARAMETER);
3484 AssertMsgReturn( pSSM->enmOp >= SSMSTATE_LIVE_PREP
3485 && pSSM->enmOp <= SSMSTATE_SAVE_DONE,
3486 ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
3487
3488 /*
3489 * Join paths with SSMR3Save again.
3490 */
3491 return ssmR3SaveDoClose(pVM, pSSM);
3492}
3493
3494
3495/**
3496 * Do the pfnSaveDone run.
3497 *
3498 * @returns VBox status code (pSSM->rc).
3499 * @param pVM The VM handle.
3500 * @param pSSM The saved state handle.
3501 */
3502static int ssmR3SaveDoDoneRun(PVM pVM, PSSMHANDLE pSSM)
3503{
3504 VM_ASSERT_EMT0(pVM);
3505
3506 /*
3507 * Do the done run.
3508 */
3509 pSSM->enmOp = SSMSTATE_SAVE_DONE;
3510 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3511 {
3512 if ( pUnit->u.Common.pfnSaveDone
3513 && ( pUnit->fCalled
3514 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
3515 {
3516 int rcOld = pSSM->rc;
3517 int rc;
3518 switch (pUnit->enmType)
3519 {
3520 case SSMUNITTYPE_DEV:
3521 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, pSSM);
3522 break;
3523 case SSMUNITTYPE_DRV:
3524 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, pSSM);
3525 break;
3526 case SSMUNITTYPE_INTERNAL:
3527 rc = pUnit->u.Internal.pfnSaveDone(pVM, pSSM);
3528 break;
3529 case SSMUNITTYPE_EXTERNAL:
3530 rc = pUnit->u.External.pfnSaveDone(pSSM, pUnit->u.External.pvUser);
3531 break;
3532 default:
3533 rc = VERR_INTERNAL_ERROR;
3534 break;
3535 }
3536 if (RT_SUCCESS(rc) && pSSM->rc != rcOld)
3537 rc = pSSM->rc;
3538 if (RT_FAILURE(rc))
3539 {
3540 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
3541 if (RT_SUCCESS(pSSM->rc))
3542 pSSM->rc = rc;
3543 }
3544 }
3545 }
3546 return pSSM->rc;
3547}
3548
3549
3550/**
3551 * Writes the directory.
3552 *
3553 * @returns VBox status code.
3554 * @param pVM The VM handle.
3555 * @param pSSM The SSM handle.
3556 * @param pcEntries Where to return the number of directory entries.
3557 */
3558static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries)
3559{
3560 VM_ASSERT_EMT0(pVM);
3561
3562 /*
3563 * Grab some temporary memory for the dictionary.
3564 */
3565 size_t cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pVM->ssm.s.cUnits]);
3566 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
3567 if (!pDir)
3568 {
3569 LogRel(("ssmR3WriteDirectory: failed to allocate %zu bytes!\n", cbDir));
3570 return VERR_NO_TMP_MEMORY;
3571 }
3572
3573 /*
3574 * Initialize it.
3575 */
3576 memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic));
3577 pDir->u32CRC = 0;
3578 pDir->cEntries = 0;
3579
3580 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3581 if (pUnit->offStream != RTFOFF_MIN)
3582 {
3583 PSSMFILEDIRENTRY pEntry = &pDir->aEntries[pDir->cEntries++];
3584 Assert(pDir->cEntries <= pVM->ssm.s.cUnits);
3585 pEntry->off = pUnit->offStream;
3586 pEntry->u32Instance = pUnit->u32Instance;
3587 pEntry->u32NameCRC = RTCrc32(pUnit->szName, pUnit->cchName);
3588 }
3589
3590 /*
3591 * Calculate the actual size and CRC-32, then write the directory
3592 * out to the stream.
3593 */
3594 *pcEntries = pDir->cEntries;
3595 cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pDir->cEntries]);
3596 pDir->u32CRC = RTCrc32(pDir, cbDir);
3597 int rc = ssmR3StrmWrite(&pSSM->Strm, pDir, cbDir);
3598 RTMemTmpFree(pDir);
3599 return rc;
3600}
3601
3602
3603/**
3604 * Finalize the saved state stream, i.e. add the end unit, directory
3605 * and footer.
3606 *
3607 * @returns VBox status code (pSSM->rc).
3608 * @param pVM The VM handle.
3609 * @param pSSM The saved state handle.
3610 */
3611static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM)
3612{
3613 VM_ASSERT_EMT0(pVM);
3614 Assert(RT_SUCCESS(pSSM->rc));
3615
3616 /*
3617 * Write the end unit.
3618 */
3619 SSMFILEUNITHDRV2 UnitHdr;
3620 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic));
3621 UnitHdr.offStream = ssmR3StrmTell(&pSSM->Strm);
3622 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
3623 UnitHdr.u32CRC = 0;
3624 UnitHdr.u32Version = 0;
3625 UnitHdr.u32Instance = 0;
3626 UnitHdr.u32Pass = SSM_PASS_FINAL;
3627 UnitHdr.fFlags = 0;
3628 UnitHdr.cbName = 0;
3629 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
3630 Log(("SSM: Unit at %#9llx: END UNIT\n", UnitHdr.offStream));
3631 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[0]));
3632 if (RT_FAILURE(rc))
3633 {
3634 LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc));
3635 return pSSM->rc = rc;
3636 }
3637
3638 /*
3639 * Write the directory for the final units and then the footer.
3640 */
3641 SSMFILEFTR Footer;
3642 rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries);
3643 if (RT_FAILURE(rc))
3644 {
3645 LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));
3646 return pSSM->rc = rc;
3647 }
3648
3649 memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic));
3650 Footer.offStream = ssmR3StrmTell(&pSSM->Strm);
3651 Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
3652 Footer.u32Reserved = 0;
3653 Footer.u32CRC = 0;
3654 Footer.u32CRC = RTCrc32(&Footer, sizeof(Footer));
3655 Log(("SSM: Footer at %#9llx: \n", Footer.offStream));
3656 rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));
3657 if (RT_SUCCESS(rc))
3658 rc = ssmR3StrmSetEnd(&pSSM->Strm);
3659 if (RT_FAILURE(rc))
3660 {
3661 LogRel(("SSM: Failed writing the footer: %Rrc\n", rc));
3662 return pSSM->rc = rc;
3663 }
3664
3665 LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n",
3666 Footer.offStream, Footer.offStream, Footer.cDirEntries));
3667 return VINF_SUCCESS;
3668}
3669
3670
3671/**
3672 * Do the pfnSaveExec run.
3673 *
3674 * @returns VBox status code (pSSM->rc).
3675 * @param pVM The VM handle.
3676 * @param pSSM The saved state handle.
3677 */
3678static int ssmR3SaveDoExecRun(PVM pVM, PSSMHANDLE pSSM)
3679{
3680 VM_ASSERT_EMT0(pVM);
3681 AssertRC(pSSM->rc);
3682 pSSM->rc = VINF_SUCCESS;
3683 pSSM->enmOp = SSMSTATE_SAVE_EXEC;
3684 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3685 {
3686 /*
3687 * Not all unit have a callback. Skip those which don't and
3688 * make sure to keep the progress indicator up to date.
3689 */
3690 pSSM->offEstUnitEnd += pUnit->cbGuess;
3691 if (!pUnit->u.Common.pfnSaveExec)
3692 {
3693 pUnit->fCalled = true;
3694 if (pUnit->cbGuess)
3695 ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
3696 continue;
3697 }
3698 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
3699
3700 /*
3701 * Check for cancellation.
3702 */
3703 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
3704 {
3705 LogRel(("SSM: Cancelled!\n"));
3706 AssertRC(pSSM->rc);
3707 return pSSM->rc = VERR_SSM_CANCELLED;
3708 }
3709
3710 /*
3711 * Write data unit header
3712 */
3713 SSMFILEUNITHDRV2 UnitHdr;
3714 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
3715 UnitHdr.offStream = pUnit->offStream;
3716 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
3717 UnitHdr.u32CRC = 0;
3718 UnitHdr.u32Version = pUnit->u32Version;
3719 UnitHdr.u32Instance = pUnit->u32Instance;
3720 UnitHdr.u32Pass = SSM_PASS_FINAL;
3721 UnitHdr.fFlags = 0;
3722 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
3723 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
3724 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
3725 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
3726 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
3727 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
3728 if (RT_FAILURE(rc))
3729 {
3730 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
3731 return pSSM->rc = rc;
3732 }
3733
3734 /*
3735 * Call the execute handler.
3736 */
3737 ssmR3DataWriteBegin(pSSM);
3738 switch (pUnit->enmType)
3739 {
3740 case SSMUNITTYPE_DEV:
3741 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, pSSM);
3742 break;
3743 case SSMUNITTYPE_DRV:
3744 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, pSSM);
3745 break;
3746 case SSMUNITTYPE_INTERNAL:
3747 rc = pUnit->u.Internal.pfnSaveExec(pVM, pSSM);
3748 break;
3749 case SSMUNITTYPE_EXTERNAL:
3750 pUnit->u.External.pfnSaveExec(pSSM, pUnit->u.External.pvUser);
3751 rc = pSSM->rc;
3752 break;
3753 default:
3754 rc = VERR_INTERNAL_ERROR;
3755 break;
3756 }
3757 pUnit->fCalled = true;
3758 if (RT_SUCCESS(rc))
3759 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
3760 if (RT_FAILURE(rc))
3761 {
3762 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance));
3763 if (RT_SUCCESS(pSSM->rc))
3764 pSSM->rc = rc;
3765 return rc;
3766 }
3767
3768 /*
3769 * Write the termination record and flush the compression stream.
3770 */
3771 SSMRECTERM TermRec;
3772 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
3773 TermRec.cbRec = sizeof(TermRec) - 2;
3774 if (pSSM->Strm.fChecksummed)
3775 {
3776 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
3777 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
3778 }
3779 else
3780 {
3781 TermRec.fFlags = 0;
3782 TermRec.u32StreamCRC = 0;
3783 }
3784 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec);
3785 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
3786 if (RT_SUCCESS(rc))
3787 rc = ssmR3DataWriteFinish(pSSM);
3788 if (RT_FAILURE(rc))
3789 {
3790 LogRel(("SSM: Failed terminating unit: %Rrc\n", rc));
3791 return pSSM->rc = rc;
3792 }
3793
3794 /*
3795 * Advance the progress indicator to the end of the current unit.
3796 */
3797 ssmR3Progress(pSSM, pSSM->offEstUnitEnd - pSSM->offEst);
3798 } /* for each unit */
3799
3800
3801 /* (progress should be pending 99% now) */
3802 AssertMsg(pSSM->uPercent == (101 - pSSM->uPercentDone), ("%d\n", pSSM->uPercent));
3803 return VINF_SUCCESS;
3804}
3805
3806
3807/**
3808 * Do the pfnSavePrep run.
3809 *
3810 * @returns VBox status code (pSSM->rc).
3811 * @param pVM The VM handle.
3812 * @param pSSM The saved state handle.
3813 */
3814static int ssmR3SaveDoPrepRun(PVM pVM, PSSMHANDLE pSSM)
3815{
3816 VM_ASSERT_EMT0(pVM);
3817 Assert(RT_SUCCESS(pSSM->rc));
3818 pSSM->enmOp = SSMSTATE_SAVE_PREP;
3819 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3820 {
3821 if (pUnit->u.Common.pfnSavePrep)
3822 {
3823 int rc;
3824 switch (pUnit->enmType)
3825 {
3826 case SSMUNITTYPE_DEV:
3827 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, pSSM);
3828 break;
3829 case SSMUNITTYPE_DRV:
3830 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, pSSM);
3831 break;
3832 case SSMUNITTYPE_INTERNAL:
3833 rc = pUnit->u.Internal.pfnSavePrep(pVM, pSSM);
3834 break;
3835 case SSMUNITTYPE_EXTERNAL:
3836 rc = pUnit->u.External.pfnSavePrep(pSSM, pUnit->u.External.pvUser);
3837 break;
3838 default:
3839 rc = VERR_INTERNAL_ERROR;
3840 break;
3841 }
3842 pUnit->fCalled = true;
3843 if (RT_SUCCESS(rc))
3844 rc = pSSM->rc;
3845 if (RT_FAILURE(rc))
3846 {
3847 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
3848 if (RT_SUCCESS(pSSM->rc))
3849 pSSM->rc = rc;
3850 return rc;
3851 }
3852 }
3853
3854 pSSM->cbEstTotal += pUnit->cbGuess;
3855 }
3856
3857 /*
3858 * Work the progress indicator if we got one.
3859 */
3860 if (pSSM->pfnProgress)
3861 pSSM->pfnProgress(pVM, pSSM->uPercentPrepare-1, pSSM->pvUser);
3862 pSSM->uPercent = pSSM->uPercentPrepare;
3863
3864 return VINF_SUCCESS;
3865}
3866
3867
3868/**
3869 * Common worker for SSMR3Save and SSMR3Migrate.
3870 *
3871 * @returns VBox status code (no need to check pSSM->rc).
3872 * @param pVM The VM handle.
3873 * @param pSSM The state handle.
3874 *
3875 * @thread EMT(0)
3876 */
3877static int ssmR3SaveDoCommon(PVM pVM, PSSMHANDLE pSSM)
3878{
3879 VM_ASSERT_EMT0(pVM);
3880
3881 /*
3882 * Do the work.
3883 */
3884 int rc = ssmR3SaveDoPrepRun(pVM, pSSM);
3885 if (RT_SUCCESS(rc))
3886 {
3887 rc = ssmR3SaveDoExecRun(pVM, pSSM);
3888 if (RT_SUCCESS(rc))
3889 rc = ssmR3SaveDoFinalization(pVM, pSSM);
3890 }
3891 Assert(pSSM->rc == rc);
3892 int rc2 = ssmR3SaveDoDoneRun(pVM, pSSM);
3893 if (RT_SUCCESS(rc))
3894 rc = rc2;
3895
3896 return rc;
3897}
3898
3899
3900/**
3901 * Saves the rest of the state on EMT0.
3902 *
3903 * @returns VBox status.
3904 *
3905 * @param pSSM The SSM handle returned by SSMR3LiveToFile or
3906 * SSMR3LiveToRemote.
3907 *
3908 * @thread Non-EMT thread. Will involve the EMT at the end of the operation.
3909 */
3910VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM)
3911{
3912 LogFlow(("SSMR3LiveDoStep2: pSSM=%p\n", pSSM));
3913
3914 /*
3915 * Validate input.
3916 */
3917 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
3918 PVM pVM = pSSM->pVM;
3919 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
3920 VM_ASSERT_EMT0(pVM);
3921 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
3922 || pSSM->enmAfter == SSMAFTER_CONTINUE,
3923 ("%d\n", pSSM->enmAfter),
3924 VERR_INVALID_PARAMETER);
3925 AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_STEP2, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
3926 AssertRCReturn(pSSM->rc, pSSM->rc);
3927
3928 /*
3929 * Join paths with VMMR3Save.
3930 */
3931 return ssmR3SaveDoCommon(pVM, pSSM);
3932}
3933
3934
3935/**
3936 * Writes the file header and clear the per-unit data.
3937 *
3938 * @returns VBox status code.
3939 * @param pVM The VM handle.
3940 * @param pSSM The SSM handle.
3941 */
3942static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM)
3943{
3944 /*
3945 * Write the header.
3946 */
3947 SSMFILEHDR FileHdr;
3948 memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic));
3949 FileHdr.u16VerMajor = VBOX_VERSION_MAJOR;
3950 FileHdr.u16VerMinor = VBOX_VERSION_MINOR;
3951 FileHdr.u32VerBuild = VBOX_VERSION_BUILD;
3952 FileHdr.u32SvnRev = VMMGetSvnRev(),
3953 FileHdr.cHostBits = HC_ARCH_BITS;
3954 FileHdr.cbGCPhys = sizeof(RTGCPHYS);
3955 FileHdr.cbGCPtr = sizeof(RTGCPTR);
3956 FileHdr.u8Reserved = 0;
3957 FileHdr.cUnits = pVM->ssm.s.cUnits;
3958 FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32;
3959 FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer);
3960 FileHdr.u32CRC = 0;
3961 FileHdr.u32CRC = RTCrc32(&FileHdr, sizeof(FileHdr));
3962 int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr));
3963 if (RT_SUCCESS(rc))
3964 return rc;
3965
3966 /*
3967 * Clear the per unit flags and offsets.
3968 */
3969 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3970 {
3971 pUnit->fCalled = false;
3972 pUnit->offStream = RTFOFF_MIN;
3973 }
3974
3975 return VINF_SUCCESS;
3976}
3977
3978
3979/**
3980 * Creates a new saved state file.
3981 *
3982 * @returns VBox status code.
3983 * @param pVM The VM handle.
3984 * @param pszFilename The name of the file.
3985 * @param enmAfter What to do afterwards.
3986 * @param pfnProgress The progress callback.
3987 * @param pvUser The progress callback user argument.
3988 * @param ppSSM Where to return the pointer to the saved state
3989 * handle upon successful return. Free it using
3990 * RTMemFree after closing the stream.
3991 */
3992static int ssmR3SaveDoCreateFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
3993 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
3994{
3995 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
3996 if (!pSSM)
3997 return VERR_NO_MEMORY;
3998
3999 pSSM->pVM = pVM;
4000 pSSM->enmOp = SSMSTATE_INVALID;
4001 pSSM->enmAfter = enmAfter;
4002 pSSM->fCancelled = SSMHANDLE_OK;
4003 pSSM->rc = VINF_SUCCESS;
4004 pSSM->cbUnitLeftV1 = 0;
4005 pSSM->offUnit = UINT64_MAX;
4006 pSSM->pfnProgress = pfnProgress;
4007 pSSM->pvUser = pvUser;
4008 pSSM->uPercent = 0;
4009 pSSM->offEstProgress = 0;
4010 pSSM->cbEstTotal = 0;
4011 pSSM->offEst = 0;
4012 pSSM->offEstUnitEnd = 0;
4013 pSSM->uPercentPrepare = 0;
4014 pSSM->uPercentDone = 0;
4015 pSSM->pszFilename = pszFilename;
4016 pSSM->u.Write.offDataBuffer = 0;
4017
4018 int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/, 8 /*cBuffers*/);
4019 if (RT_FAILURE(rc))
4020 {
4021 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));
4022 RTMemFree(pSSM);
4023 return rc;
4024 }
4025
4026 *ppSSM = pSSM;
4027 return VINF_SUCCESS;
4028}
4029
4030
4031/**
4032 * Start VM save operation.
4033 *
4034 * @returns VBox status.
4035 *
4036 * @param pVM The VM handle.
4037 * @param pszFilename Name of the file to save the state in.
4038 * @param enmAfter What is planned after a successful save operation.
4039 * @param pfnProgress Progress callback. Optional.
4040 * @param pvUser User argument for the progress callback.
4041 *
4042 * @thread EMT
4043 */
4044VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
4045{
4046 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
4047 VM_ASSERT_EMT0(pVM);
4048
4049 /*
4050 * Validate input.
4051 */
4052 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY
4053 || enmAfter == SSMAFTER_CONTINUE,
4054 ("%d\n", enmAfter),
4055 VERR_INVALID_PARAMETER);
4056
4057 /*
4058 * Create the saved state file and handle.
4059 *
4060 * Note that there might be quite some work to do after executing the saving,
4061 * so we reserve 20% for the 'Done' period.
4062 */
4063 PSSMHANDLE pSSM;
4064 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM);
4065 if (RT_FAILURE(rc))
4066 return rc;
4067 pSSM->uPercentPrepare = 20;
4068 pSSM->uPercentDone = 2;
4069
4070 /*
4071 * Write the saved state stream header and join paths with
4072 * the other save methods for the rest of the job.
4073 */
4074 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
4075 ssmR3StrmStartIoThread(&pSSM->Strm);
4076 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
4077 if (RT_SUCCESS(rc))
4078 {
4079 ssmR3SetCancellable(pVM, pSSM, true);
4080 ssmR3SaveDoCommon(pVM, pSSM);
4081 }
4082
4083 return ssmR3SaveDoClose(pVM, pSSM);
4084}
4085
4086
4087/**
4088 * Calls pfnLiveVote for all units.
4089 *
4090 * @returns VBox status code (no need to check pSSM->rc).
4091 * @retval VINF_SUCCESS if we can pass on to step 2.
4092 * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if we need another pass.
4093 *
4094 * @param pVM The VM handle.
4095 * @param pSSM The saved state handle.
4096 * @param uPass The current pass.
4097 */
4098static int ssmR3LiveDoVoteRun(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
4099{
4100 AssertRC(pSSM->rc);
4101 pSSM->rc = VINF_SUCCESS;
4102 pSSM->enmOp = SSMSTATE_LIVE_VOTE;
4103 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4104 {
4105 if (pUnit->u.Common.pfnLiveVote)
4106 {
4107 int rc;
4108 switch (pUnit->enmType)
4109 {
4110 case SSMUNITTYPE_DEV:
4111 rc = pUnit->u.Dev.pfnLiveVote(pUnit->u.Dev.pDevIns, pSSM);
4112 break;
4113 case SSMUNITTYPE_DRV:
4114 rc = pUnit->u.Drv.pfnLiveVote(pUnit->u.Drv.pDrvIns, pSSM);
4115 break;
4116 case SSMUNITTYPE_INTERNAL:
4117 rc = pUnit->u.Internal.pfnLiveVote(pVM, pSSM);
4118 break;
4119 case SSMUNITTYPE_EXTERNAL:
4120 rc = pUnit->u.External.pfnLiveVote(pSSM, pUnit->u.External.pvUser);
4121 break;
4122 default:
4123 rc = VERR_INTERNAL_ERROR;
4124 break;
4125 }
4126 Assert(pSSM->rc == VINF_SUCCESS);
4127
4128 pUnit->fCalled = true;
4129 if (rc != VINF_SUCCESS)
4130 {
4131 if (rc == VINF_SSM_VOTE_FOR_ANOTHER_PASS)
4132 {
4133 Log(("ssmR3DoLiveVoteRun: '%s'/#%u -> VINF_SSM_VOTE_FOR_ANOTHER_PASS (pass=%u)\n", pUnit->szName, pUnit->u32Instance, uPass));
4134 return VINF_SSM_VOTE_FOR_ANOTHER_PASS;
4135 }
4136
4137 /*
4138 * rc is usually VERR_SSM_VOTE_FOR_GIVING_UP here, but we allow
4139 * other status codes for better user feed back. However, no
4140 * other non-error status is allowed.
4141 */
4142 LogRel(("SSM: Error - '%s'/#%u voted %Rrc! (pass=%u)\n", pUnit->szName, pUnit->u32Instance, rc, uPass));
4143 AssertMsgReturn(RT_FAILURE(rc), ("%Rrc; '%s'\n", rc, pUnit->szName), pSSM->rc = VERR_IPE_UNEXPECTED_INFO_STATUS);
4144 return pSSM->rc = rc;
4145 }
4146 }
4147 }
4148
4149 LogRel(("SSM: Step 1 completed after pass %u.\n", uPass));
4150 return VINF_SUCCESS;
4151}
4152
4153
4154/**
4155 * Calls pfnLiveExec for all units.
4156 *
4157 * @returns VBox status code (no need to check pSSM->rc).
4158 *
4159 * @param pVM The VM handle.
4160 * @param pSSM The saved state handle.
4161 * @param uPass The current pass.
4162 */
4163static int ssmR3LiveDoExecRun(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
4164{
4165 AssertRC(pSSM->rc);
4166 pSSM->rc = VINF_SUCCESS;
4167 pSSM->enmOp = SSMSTATE_LIVE_EXEC;
4168 for (PSSMUNIT pUnit = pVM->ssm.s.pHead;
4169 /** @todo VMR3GetState(pVM) == VMSTATE_LIVE_SAVING &&*/ pUnit;
4170 pUnit = pUnit->pNext)
4171 {
4172 /*
4173 * Skip units without a callback (this is most).
4174 */
4175 if (!pUnit->u.Common.pfnLiveExec)
4176 continue;
4177 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm);
4178
4179 /*
4180 * Check for cancellation.
4181 */
4182 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
4183 {
4184 LogRel(("SSM: Cancelled!\n"));
4185 AssertRC(pSSM->rc);
4186 return pSSM->rc = VERR_SSM_CANCELLED;
4187 }
4188
4189 /*
4190 * Write data unit header.
4191 */
4192 SSMFILEUNITHDRV2 UnitHdr;
4193 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic));
4194 UnitHdr.offStream = pUnit->offStream;
4195 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
4196 UnitHdr.u32CRC = 0;
4197 UnitHdr.u32Version = pUnit->u32Version;
4198 UnitHdr.u32Instance = pUnit->u32Instance;
4199 UnitHdr.u32Pass = uPass;
4200 UnitHdr.fFlags = 0;
4201 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
4202 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName);
4203 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
4204 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
4205 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
4206 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]));
4207 if (RT_FAILURE(rc))
4208 {
4209 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
4210 return pSSM->rc = rc;
4211 }
4212
4213 /*
4214 * Call the execute handler.
4215 */
4216 ssmR3DataWriteBegin(pSSM);
4217 switch (pUnit->enmType)
4218 {
4219 case SSMUNITTYPE_DEV:
4220 rc = pUnit->u.Dev.pfnLiveExec(pUnit->u.Dev.pDevIns, pSSM, uPass);
4221 break;
4222 case SSMUNITTYPE_DRV:
4223 rc = pUnit->u.Drv.pfnLiveExec(pUnit->u.Drv.pDrvIns, pSSM, uPass);
4224 break;
4225 case SSMUNITTYPE_INTERNAL:
4226 rc = pUnit->u.Internal.pfnLiveExec(pVM, pSSM, uPass);
4227 break;
4228 case SSMUNITTYPE_EXTERNAL:
4229 rc = pUnit->u.External.pfnLiveExec(pSSM, pUnit->u.External.pvUser, uPass);
4230 break;
4231 default:
4232 rc = VERR_INTERNAL_ERROR;
4233 break;
4234 }
4235 pUnit->fCalled = true;
4236 if (RT_SUCCESS(rc))
4237 rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */
4238 if (RT_FAILURE(rc))
4239 {
4240 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s'/#%u.\n", rc, pUnit->szName, pUnit->u32Instance));
4241 if (RT_SUCCESS(pSSM->rc))
4242 pSSM->rc = rc;
4243 return rc;
4244 }
4245
4246 /*
4247 * Write the termination record and flush the compression stream.
4248 */
4249 SSMRECTERM TermRec;
4250 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
4251 TermRec.cbRec = sizeof(TermRec) - 2;
4252 if (pSSM->Strm.fChecksummed)
4253 {
4254 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
4255 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2));
4256 }
4257 else
4258 {
4259 TermRec.fFlags = 0;
4260 TermRec.u32StreamCRC = 0;
4261 }
4262 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec);
4263 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec));
4264 if (RT_SUCCESS(rc))
4265 rc = ssmR3DataWriteFinish(pSSM);
4266 if (RT_FAILURE(rc))
4267 {
4268 LogRel(("SSM: Failed terminating unit: %Rrc (pass=%u)\n", rc, uPass));
4269 return pSSM->rc = rc;
4270 }
4271 } /* for each unit */
4272
4273 return VINF_SUCCESS;
4274}
4275
4276
4277
4278/**
4279 * Continue a live state saving operation on the worker thread.
4280 *
4281 * @returns VBox status.
4282 *
4283 * @param pSSM The SSM handle returned by SSMR3LiveToFile or
4284 * SSMR3LiveToRemote.
4285 *
4286 * @thread Non-EMT thread. Will involve the EMT at the end of the operation.
4287 */
4288VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM)
4289{
4290 LogFlow(("SSMR3LiveDoStep1: pSSM=%p\n", pSSM));
4291
4292 /*
4293 * Validate input.
4294 */
4295 AssertPtrReturn(pSSM, VERR_INVALID_POINTER);
4296 PVM pVM = pSSM->pVM;
4297 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
4298 VM_ASSERT_OTHER_THREAD(pVM);
4299 AssertMsgReturn( pSSM->enmAfter == SSMAFTER_DESTROY
4300 || pSSM->enmAfter == SSMAFTER_CONTINUE,
4301 ("%d\n", pSSM->enmAfter),
4302 VERR_INVALID_PARAMETER);
4303 AssertMsgReturn(pSSM->enmOp == SSMSTATE_LIVE_STEP1, ("%d\n", pSSM->enmOp), VERR_INVALID_STATE);
4304 AssertRCReturn(pSSM->rc, pSSM->rc);
4305
4306 /*
4307 * Calc the max saved state size before we should give up because of insane
4308 * amounts of data.
4309 */
4310#define SSM_MAX_GROWTH_FILE 10000
4311#define SSM_MAX_GROWTH_REMOTE 100000
4312 uint64_t cbSum = 0;
4313 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4314 cbSum += pUnit->cbGuess;
4315 uint64_t cbMax = cbSum * (pSSM->pszFilename ? SSM_MAX_GROWTH_FILE : SSM_MAX_GROWTH_REMOTE);
4316 AssertLogRelMsgReturn(cbMax > cbSum, ("cbMax=%#RX64, cbSum=%#RX64\n", cbMax, cbSum), pSSM->rc = VERR_OUT_OF_RANGE);
4317 if (cbMax < _1G)
4318 cbMax = _1G;
4319
4320 /*
4321 * The pass loop.
4322 *
4323 * The number of interations is restricted for two reasons, first
4324 * to make sure
4325 */
4326#define SSM_MAX_PASSES _1M
4327 for (uint32_t uPass = 0; uPass < SSM_MAX_PASSES; uPass++)
4328 {
4329 /*
4330 * Save state and vote on whether we need more passes or not.
4331 */
4332 int rc = ssmR3LiveDoExecRun(pVM, pSSM, uPass);
4333 if (RT_FAILURE(rc))
4334 return rc;
4335 rc = ssmR3LiveDoVoteRun(pVM, pSSM, uPass);
4336 if (rc == VINF_SUCCESS)
4337 {
4338 pSSM->enmOp = SSMSTATE_LIVE_STEP2;
4339 return VINF_SUCCESS;
4340 }
4341 if (RT_FAILURE(rc))
4342 return rc;
4343
4344 /*
4345 * Check that we're still within sane data amounts.
4346 */
4347 uint64_t cbSaved = ssmR3StrmTell(&pSSM->Strm);
4348 if (cbSaved > cbMax)
4349 {
4350 LogRel(("SSM: Giving up: Exceeded max state size. (cbSaved=%#RX64, cbMax=%#RX64)\n", cbSaved, cbMax));
4351 return pSSM->rc = VERR_SSM_STATE_GREW_TOO_BIG;
4352 }
4353
4354 /*
4355 * Check that there is still some space left on the disk.
4356 */
4357 /** @todo move this to the stream flushing code? It's not perfect when done
4358 * here, it could be way better if we did it there. */
4359 if (pSSM->pszFilename)
4360 {
4361 RTFOFF cbFree;
4362 rc = RTFsQuerySizes(pSSM->pszFilename, NULL, &cbFree, NULL, NULL);
4363 AssertRC(rc);
4364#define SSM_MIN_DISK_FREE ((RTFOFF)( 10 * _1M ))
4365 if ( RT_SUCCESS(rc)
4366 && cbFree < SSM_MIN_DISK_FREE)
4367 {
4368 LogRel(("SSM: Giving up: Low on disk space. (cbFree=%RTfoff, SSM_MIN_DISK_FREE=%RTfoff).\n",
4369 cbFree, SSM_MIN_DISK_FREE));
4370 return pSSM->rc = VERR_SSM_LOW_ON_DISK_SPACE;
4371 }
4372 }
4373#if 0
4374 /*
4375 * Check the VM state to see if it has changed.
4376 */
4377 VMSTATE enmState = VMR3GetState(pVM);
4378 if (enmState != VMSTATE_LIVE_SAVING)
4379 {
4380 switch (enmState)
4381 {
4382 case VMSTATE_LIVE_CANCELLED:
4383 LogRel(("SSM: Cancelled\n"));
4384 return pSSM->rc = VERR_SSM_LIVE_CANCELLED;
4385 case VMSTATE_LIVE_POWERED_OFF:
4386 LogRel(("SSM: Powered off, no state to save, aborting.\n"));
4387 return pSSM->rc = VERR_SSM_LIVE_POWERED_OFF;
4388 case VMSTATE_GURU_MEDITATION:
4389 LogRel(("SSM: Guru meditation, aborting.\n"));
4390 return pSSM->rc = VERR_SSM_LIVE_GURU_MEDITATION;
4391 default:
4392 LogRel(("SSM: Invalid VM state transition: %d->%d\n", VMSTATE_LIVE_SAVING, enmState));
4393 return pSSM->rc = VERR_INTERNAL_ERROR_3;
4394 }
4395 }
4396#endif
4397 }
4398
4399 LogRel(("SSM: Giving up: Too many passes! (%u)\n", SSM_MAX_PASSES));
4400 return pSSM->rc = VERR_SSM_TOO_MANY_PASSES;
4401}
4402
4403
4404/**
4405 * Calls pfnLivePrep for all units.
4406 *
4407 * @returns VBox status code (no need to check pSSM->rc).
4408 * @param pVM The VM handle.
4409 * @param pSSM The saved state handle.
4410 */
4411static int ssmR3DoLivePrepRun(PVM pVM, PSSMHANDLE pSSM)
4412{
4413 /*
4414 * Do the prepare run.
4415 */
4416 pSSM->rc = VINF_SUCCESS;
4417 pSSM->enmOp = SSMSTATE_SAVE_PREP;
4418 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
4419 {
4420 if (pUnit->u.Common.pfnLivePrep)
4421 {
4422 int rc;
4423 switch (pUnit->enmType)
4424 {
4425 case SSMUNITTYPE_DEV:
4426 rc = pUnit->u.Dev.pfnLivePrep(pUnit->u.Dev.pDevIns, pSSM);
4427 break;
4428 case SSMUNITTYPE_DRV:
4429 rc = pUnit->u.Drv.pfnLivePrep(pUnit->u.Drv.pDrvIns, pSSM);
4430 break;
4431 case SSMUNITTYPE_INTERNAL:
4432 rc = pUnit->u.Internal.pfnLivePrep(pVM, pSSM);
4433 break;
4434 case SSMUNITTYPE_EXTERNAL:
4435 rc = pUnit->u.External.pfnLivePrep(pSSM, pUnit->u.External.pvUser);
4436 break;
4437 default:
4438 rc = VERR_INTERNAL_ERROR;
4439 break;
4440 }
4441 pUnit->fCalled = true;
4442 if (RT_SUCCESS(rc))
4443 rc = pSSM->rc;
4444 if (RT_FAILURE(rc))
4445 {
4446 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
4447 if (RT_SUCCESS(pSSM->rc))
4448 pSSM->rc = rc;
4449 return rc;
4450 }
4451 }
4452
4453 pSSM->cbEstTotal += pUnit->cbGuess;
4454 }
4455
4456 /*
4457 * Work the progress indicator if we got one.
4458 */
4459 if (pSSM->pfnProgress)
4460 pSSM->pfnProgress(pVM, 2, pSSM->pvUser);
4461 pSSM->uPercent = 2;
4462
4463 return VINF_SUCCESS;
4464}
4465
4466
4467/**
4468 * Start saving the live state to a file.
4469 *
4470 * Call SSMR3LiveDoStep1, SSMR3LiveDoStep2 and finally SSMR3LiveDone on success.
4471 * SSMR3LiveDone should be called even if SSMR3LiveDoStep1 or SSMR3LiveDoStep2
4472 * fails.
4473 *
4474 * @returns VBox status.
4475 *
4476 * @param pVM The VM handle.
4477 * @param pszFilename Name of the file to save the state in. This string
4478 * must remain valid until SSMR3LiveDone is called.
4479 * @param enmAfter What is planned after a successful save operation.
4480 * @param pfnProgress Progress callback. Optional.
4481 * @param pvUser User argument for the progress callback.
4482 *
4483 * @thread EMT0
4484 */
4485VMMR3_INT_DECL(int) SSMR3LiveToFile(PVM pVM, const char *pszFilename, SSMAFTER enmAfter,
4486 PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
4487{
4488 LogFlow(("SSMR3LiveToFile: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
4489 VM_ASSERT_EMT0(pVM);
4490
4491 /*
4492 * Validate input.
4493 */
4494 AssertMsgReturn( enmAfter == SSMAFTER_DESTROY
4495 || enmAfter == SSMAFTER_CONTINUE,
4496 ("%d\n", enmAfter),
4497 VERR_INVALID_PARAMETER);
4498
4499 /*
4500 * Create the saved state file and handle.
4501 *
4502 * Note that there might be quite some work to do after executing the saving,
4503 * so we reserve 20% for the 'Done' period.
4504 */
4505 PSSMHANDLE pSSM;
4506 int rc = ssmR3SaveDoCreateFile(pVM, pszFilename, enmAfter, pfnProgress, pvUser, &pSSM);
4507 if (RT_FAILURE(rc))
4508 return rc;
4509 pSSM->uPercentPrepare = 20; /** @todo fix these. */
4510 pSSM->uPercentDone = 2;
4511
4512 /*
4513 * Write the saved state stream header and do the prep run for live saving.
4514 */
4515 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
4516 ssmR3StrmStartIoThread(&pSSM->Strm);
4517 rc = ssmR3WriteHeaderAndClearPerUnitData(pVM, pSSM);
4518 if (RT_SUCCESS(rc))
4519 {
4520/** @todo If it turns out we don't need to do ssmR3DoLivePrepRun on EMT0,
4521 * simply move the code to SSMR3LiveDoStep1. */
4522 rc = ssmR3DoLivePrepRun(pVM, pSSM);
4523 if (RT_SUCCESS(rc))
4524 {
4525 /*
4526 * Return and let the requstor thread do the pfnLiveExec/Vote part
4527 * via SSMR3SaveFinishLive
4528 */
4529 pSSM->enmOp = SSMSTATE_LIVE_STEP1;
4530 ssmR3SetCancellable(pVM, pSSM, true);
4531 *ppSSM = pSSM;
4532 return VINF_SUCCESS;
4533 }
4534 }
4535 /* bail out. */
4536 int rc2 = ssmR3StrmClose(&pSSM->Strm);
4537 RTMemFree(pSSM);
4538 rc2 = RTFileDelete(pszFilename);
4539 AssertRC(rc2);
4540 return rc;
4541}
4542
4543
4544VMMR3DECL(int) SSMR3LiveToRemote(PVM pVM, PFNVMPROGRESS pfnProgress, void *pvUser /*,
4545 invent stream interface and stuff */)
4546{
4547 return VERR_NOT_IMPLEMENTED;
4548}
4549
4550
4551/* ... Loading and reading starts here ... */
4552/* ... Loading and reading starts here ... */
4553/* ... Loading and reading starts here ... */
4554/* ... Loading and reading starts here ... */
4555/* ... Loading and reading starts here ... */
4556/* ... Loading and reading starts here ... */
4557/* ... Loading and reading starts here ... */
4558/* ... Loading and reading starts here ... */
4559/* ... Loading and reading starts here ... */
4560/* ... Loading and reading starts here ... */
4561/* ... Loading and reading starts here ... */
4562/* ... Loading and reading starts here ... */
4563/* ... Loading and reading starts here ... */
4564/* ... Loading and reading starts here ... */
4565/* ... Loading and reading starts here ... */
4566/* ... Loading and reading starts here ... */
4567/* ... Loading and reading starts here ... */
4568
4569
4570/**
4571 * Closes the decompressor of a data unit.
4572 *
4573 * @param pSSM SSM operation handle.
4574 */
4575static void ssmR3DataReadFinishV1(PSSMHANDLE pSSM)
4576{
4577 if (pSSM->u.Read.pZipDecompV1)
4578 {
4579 int rc = RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
4580 AssertRC(rc);
4581 pSSM->u.Read.pZipDecompV1 = NULL;
4582 }
4583}
4584
4585
4586/**
4587 * Callback for reading compressed data into the input buffer of the
4588 * decompressor, for saved file format version 1.
4589 *
4590 * @returns VBox status code.
4591 * @param pvSSM The SSM handle.
4592 * @param pvBuf Where to store the compressed data.
4593 * @param cbBuf Size of the buffer.
4594 * @param pcbRead Number of bytes actually stored in the buffer.
4595 */
4596static DECLCALLBACK(int) ssmR3ReadInV1(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
4597{
4598 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
4599 size_t cbRead = cbBuf;
4600 if (pSSM->cbUnitLeftV1 < cbBuf)
4601 cbRead = (size_t)pSSM->cbUnitLeftV1;
4602 if (cbRead)
4603 {
4604 //Log2(("ssmR3ReadInV1: %#010llx cbBug=%#x cbRead=%#x\n", ssmR3StrmTell(&pSSM->Strm), cbBuf, cbRead));
4605 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbRead);
4606 if (RT_SUCCESS(rc))
4607 {
4608 pSSM->cbUnitLeftV1 -= cbRead;
4609 if (pcbRead)
4610 *pcbRead = cbRead;
4611 ssmR3Progress(pSSM, cbRead);
4612 return VINF_SUCCESS;
4613 }
4614 return rc;
4615 }
4616
4617 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
4618 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
4619 return VERR_SSM_LOADED_TOO_MUCH;
4620}
4621
4622
4623/**
4624 * Internal read worker for reading data from a version 1 unit.
4625 *
4626 * @param pSSM SSM operation handle.
4627 * @param pvBuf Where to store the read data.
4628 * @param cbBuf Number of bytes to read.
4629 */
4630static int ssmR3DataReadV1(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
4631{
4632 /*
4633 * Open the decompressor on the first read.
4634 */
4635 if (!pSSM->u.Read.pZipDecompV1)
4636 {
4637 pSSM->rc = RTZipDecompCreate(&pSSM->u.Read.pZipDecompV1, pSSM, ssmR3ReadInV1);
4638 if (RT_FAILURE(pSSM->rc))
4639 return pSSM->rc;
4640 }
4641
4642 /*
4643 * Do the requested read.
4644 */
4645 int rc = pSSM->rc = RTZipDecompress(pSSM->u.Read.pZipDecompV1, pvBuf, cbBuf, NULL);
4646 if (RT_SUCCESS(rc))
4647 {
4648 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 ? "..." : ""));
4649 pSSM->offUnit += cbBuf;
4650 return VINF_SUCCESS;
4651 }
4652 AssertMsgFailed(("rc=%Rrc cbBuf=%#x\n", rc, cbBuf));
4653 return rc;
4654}
4655
4656
4657/**
4658 * Creates the decompressor for the data unit.
4659 *
4660 * pSSM->rc will be set on error.
4661 *
4662 * @param pSSM SSM operation handle.
4663 */
4664static void ssmR3DataReadBeginV2(PSSMHANDLE pSSM)
4665{
4666 Assert(!pSSM->u.Read.cbDataBuffer || pSSM->u.Read.cbDataBuffer == pSSM->u.Read.offDataBuffer);
4667 Assert(!pSSM->u.Read.cbRecLeft);
4668
4669 pSSM->offUnit = 0;
4670 pSSM->u.Read.cbRecLeft = 0;
4671 pSSM->u.Read.cbDataBuffer = 0;
4672 pSSM->u.Read.offDataBuffer = 0;
4673 pSSM->u.Read.fEndOfData = false;
4674 pSSM->u.Read.u8TypeAndFlags = 0;
4675}
4676
4677
4678/**
4679 * Checks for the termination record and closes the decompressor.
4680 *
4681 * pSSM->rc will be set on error.
4682 *
4683 * @param pSSM SSM operation handle.
4684 */
4685static void ssmR3DataReadFinishV2(PSSMHANDLE pSSM)
4686{
4687 /*
4688 * If we haven't encountered the end of the record, it must be the next one.
4689 */
4690 if ( !pSSM->u.Read.fEndOfData
4691 && RT_SUCCESS(pSSM->rc))
4692 {
4693 int rc = ssmR3DataReadRecHdrV2(pSSM);
4694 if ( RT_SUCCESS(rc)
4695 && !pSSM->u.Read.fEndOfData)
4696 {
4697 rc = VERR_SSM_LOADED_TOO_LITTLE;
4698 AssertFailed();
4699 }
4700 pSSM->rc = rc;
4701 }
4702}
4703
4704
4705/**
4706 * Read reader that keep works the progress indicator and unit offset.
4707 *
4708 * Does not set SSM::rc.
4709 *
4710 * @returns VBox status code.
4711 * @param pSSM The saved state handle.
4712 * @param pvBuf Where to put the bits
4713 * @param cbBuf How many bytes to read.
4714 */
4715DECLINLINE(int) ssmR3DataReadV2Raw(PSSMHANDLE pSSM, void *pvBuf, size_t cbToRead)
4716{
4717 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbToRead);
4718 if (RT_SUCCESS(rc))
4719 {
4720 pSSM->offUnit += cbToRead;
4721 ssmR3Progress(pSSM, cbToRead);
4722 return VINF_SUCCESS;
4723 }
4724
4725 /** @todo weed out lazy saving */
4726 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
4727 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
4728 return VERR_SSM_LOADED_TOO_MUCH;
4729}
4730
4731
4732/**
4733 * Reads and checks the LZF "header".
4734 *
4735 * @returns VBox status code.
4736 * @param pSSM The saved state handle..
4737 * @param pcbDecompr Where to store the size of the decompressed data.
4738 */
4739DECLINLINE(int) ssmR3DataReadV2RawLzfHdr(PSSMHANDLE pSSM, uint32_t *pcbDecompr)
4740{
4741 *pcbDecompr = 0; /* shuts up gcc. */
4742 AssertLogRelMsgReturn( pSSM->u.Read.cbRecLeft > 1
4743 && pSSM->u.Read.cbRecLeft <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abComprBuffer) + 2,
4744 ("%#x\n", pSSM->u.Read.cbRecLeft),
4745 VERR_SSM_INTEGRITY_DECOMPRESSION);
4746
4747 uint8_t cKB;
4748 int rc = ssmR3DataReadV2Raw(pSSM, &cKB, 1);
4749 if (RT_FAILURE(rc))
4750 return rc;
4751 pSSM->u.Read.cbRecLeft -= sizeof(cKB);
4752
4753 uint32_t cbDecompr = (uint32_t)cKB * _1K;
4754 AssertLogRelMsgReturn( cbDecompr >= pSSM->u.Read.cbRecLeft
4755 && cbDecompr <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer),
4756 ("%#x\n", cbDecompr),
4757 VERR_SSM_INTEGRITY_DECOMPRESSION);
4758
4759 *pcbDecompr = cbDecompr;
4760 return VINF_SUCCESS;
4761}
4762
4763
4764/**
4765 * Reads an LZF block from the stream and decompresses into the specified
4766 * buffer.
4767 *
4768 * @returns VBox status code.
4769 * @param SSM The saved state handle.
4770 * @param pvDst Pointer to the output buffer.
4771 * @param cbDecompr The size of the decompressed data.
4772 */
4773static int ssmR3DataReadV2RawLzf(PSSMHANDLE pSSM, void *pvDst, size_t cbDecompr)
4774{
4775 int rc;
4776 uint32_t cbCompr = pSSM->u.Read.cbRecLeft;
4777 pSSM->u.Read.cbRecLeft = 0;
4778
4779 /*
4780 * Try use the stream buffer directly to avoid copying things around.
4781 */
4782 uint8_t const *pb = ssmR3StrmReadDirect(&pSSM->Strm, cbCompr);
4783 if (pb)
4784 {
4785 pSSM->offUnit += cbCompr;
4786 ssmR3Progress(pSSM, cbCompr);
4787 }
4788 else
4789 {
4790 rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abComprBuffer[0], cbCompr);
4791 if (RT_FAILURE(rc))
4792 return rc;
4793 pb = &pSSM->u.Read.abComprBuffer[0];
4794 }
4795
4796 /*
4797 * Decompress it.
4798 */
4799 size_t cbDstActual;
4800 rc = RTZipBlockDecompress(RTZIPTYPE_LZF, 0 /*fFlags*/,
4801 pb, cbCompr, NULL /*pcbSrcActual*/,
4802 pvDst, cbDecompr, &cbDstActual);
4803 if (RT_SUCCESS(rc))
4804 {
4805 AssertLogRelMsgReturn(cbDstActual == cbDecompr, ("%#x %#x\n", cbDstActual, cbDecompr), VERR_SSM_INTEGRITY_DECOMPRESSION);
4806 return VINF_SUCCESS;
4807 }
4808
4809 AssertLogRelMsgFailed(("cbCompr=%#x cbDecompr=%#x rc=%Rrc\n", cbCompr, cbDecompr, rc));
4810 return VERR_SSM_INTEGRITY_DECOMPRESSION;
4811}
4812
4813
4814/**
4815 * Reads and checks the raw zero "header".
4816 *
4817 * @returns VBox status code.
4818 * @param pSSM The saved state handle..
4819 * @param pcbDecompr Where to store the size of the zero data.
4820 */
4821DECLINLINE(int) ssmR3DataReadV2RawZeroHdr(PSSMHANDLE pSSM, uint32_t *pcbZero)
4822{
4823 *pcbZero = 0; /* shuts up gcc. */
4824 AssertLogRelMsgReturn(pSSM->u.Read.cbRecLeft == 1, ("%#x\n", pSSM->u.Read.cbRecLeft), VERR_SSM_INTEGRITY_DECOMPRESSION);
4825
4826 uint8_t cKB;
4827 int rc = ssmR3DataReadV2Raw(pSSM, &cKB, 1);
4828 if (RT_FAILURE(rc))
4829 return rc;
4830 pSSM->u.Read.cbRecLeft = 0;
4831
4832 uint32_t cbZero = (uint32_t)cKB * _1K;
4833 AssertLogRelMsgReturn(cbZero <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer),
4834 ("%#x\n", cbZero), VERR_SSM_INTEGRITY_DECOMPRESSION);
4835
4836 *pcbZero = cbZero;
4837 return VINF_SUCCESS;
4838}
4839
4840
4841/**
4842 * Worker for reading the record header.
4843 *
4844 * It sets pSSM->u.Read.cbRecLeft, pSSM->u.Read.u8TypeAndFlags and
4845 * pSSM->u.Read.fEndOfData. When a termination record is encounter, it will be
4846 * read in full and validated, the fEndOfData indicator is set, and VINF_SUCCESS
4847 * is returned.
4848 *
4849 * @returns VBox status code.
4850 * @param pSSM The saved state handle.
4851 */
4852static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM)
4853{
4854 AssertLogRelReturn(!pSSM->u.Read.fEndOfData, VERR_SSM_LOADED_TOO_MUCH);
4855
4856 /*
4857 * Read the two mandatory bytes.
4858 */
4859 uint8_t abHdr[8];
4860 int rc = ssmR3DataReadV2Raw(pSSM, abHdr, 2);
4861 if (RT_FAILURE(rc))
4862 return rc;
4863
4864 /*
4865 * Validate the first byte and check for the termination records.
4866 */
4867 pSSM->u.Read.u8TypeAndFlags = abHdr[0];
4868 AssertLogRelMsgReturn(SSM_REC_ARE_TYPE_AND_FLAGS_VALID(abHdr[0]), ("%#x %#x\n", abHdr[0], abHdr[1]), VERR_SSM_INTEGRITY_REC_HDR);
4869 if ((abHdr[0] & SSM_REC_TYPE_MASK) == SSM_REC_TYPE_TERM)
4870 {
4871 pSSM->u.Read.cbRecLeft = 0;
4872 pSSM->u.Read.fEndOfData = true;
4873 AssertLogRelMsgReturn(abHdr[1] == sizeof(SSMRECTERM) - 2, ("%#x\n", abHdr[1]), VERR_SSM_INTEGRITY_REC_TERM);
4874 AssertLogRelMsgReturn(abHdr[0] & SSM_REC_FLAGS_IMPORTANT, ("%#x\n", abHdr[0]), VERR_SSM_INTEGRITY_REC_TERM);
4875
4876 /* get the rest */
4877 uint32_t u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
4878 SSMRECTERM TermRec;
4879 int rc = ssmR3DataReadV2Raw(pSSM, (uint8_t *)&TermRec + 2, sizeof(SSMRECTERM) - 2);
4880 if (RT_FAILURE(rc))
4881 return rc;
4882
4883 /* validate integrity */
4884 AssertLogRelMsgReturn(TermRec.cbUnit == pSSM->offUnit,
4885 ("cbUnit=%#llx offUnit=%#llx\n", TermRec.cbUnit, pSSM->offUnit),
4886 VERR_SSM_INTEGRITY_REC_TERM);
4887 AssertLogRelMsgReturn(!(TermRec.fFlags & ~SSMRECTERM_FLAGS_CRC32), ("%#x\n", TermRec.fFlags), VERR_SSM_INTEGRITY_REC_TERM);
4888 if (!(TermRec.fFlags & SSMRECTERM_FLAGS_CRC32))
4889 AssertLogRelMsgReturn(TermRec.u32StreamCRC == 0, ("%#x\n", TermRec.u32StreamCRC), VERR_SSM_INTEGRITY_REC_TERM);
4890 else if (pSSM->Strm.fChecksummed)
4891 AssertLogRelMsgReturn(TermRec.u32StreamCRC == u32StreamCRC, ("%#x, %#x\n", TermRec.u32StreamCRC, u32StreamCRC),
4892 VERR_SSM_INTEGRITY_REC_TERM_CRC);
4893
4894 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx: TERM\n", ssmR3StrmTell(&pSSM->Strm) - sizeof(SSMRECTERM), pSSM->offUnit));
4895 return VINF_SUCCESS;
4896 }
4897
4898 /*
4899 * Figure the size. The 2nd byte is encoded in UTF-8 fashion, so this
4900 * is can be highly enjoyable.
4901 */
4902 uint32_t cbHdr = 2;
4903 uint32_t cb = abHdr[1];
4904 if (!(cb & 0x80))
4905 pSSM->u.Read.cbRecLeft = cb;
4906 else
4907 {
4908 /*
4909 * Need more data. Figure how much and read it.
4910 */
4911 if (!(cb & RT_BIT(5)))
4912 cb = 2;
4913 else if (!(cb & RT_BIT(4)))
4914 cb = 3;
4915 else if (!(cb & RT_BIT(3)))
4916 cb = 4;
4917 else if (!(cb & RT_BIT(2)))
4918 cb = 5;
4919 else if (!(cb & RT_BIT(1)))
4920 cb = 6;
4921 else
4922 AssertLogRelMsgFailedReturn(("Invalid record size byte: %#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4923 cbHdr = cb + 1;
4924
4925 rc = ssmR3DataReadV2Raw(pSSM, &abHdr[2], cb - 1);
4926 if (RT_FAILURE(rc))
4927 return rc;
4928
4929 /*
4930 * Validate what we've read.
4931 */
4932 switch (cb)
4933 {
4934 case 6:
4935 AssertLogRelMsgReturn((abHdr[6] & 0xc0) == 0x80, ("6/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
4936 case 5:
4937 AssertLogRelMsgReturn((abHdr[5] & 0xc0) == 0x80, ("5/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
4938 case 4:
4939 AssertLogRelMsgReturn((abHdr[4] & 0xc0) == 0x80, ("4/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
4940 case 3:
4941 AssertLogRelMsgReturn((abHdr[3] & 0xc0) == 0x80, ("3/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
4942 case 2:
4943 AssertLogRelMsgReturn((abHdr[2] & 0xc0) == 0x80, ("2/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY_REC_HDR);
4944 break;
4945 default:
4946 return VERR_INTERNAL_ERROR;
4947 }
4948
4949 /*
4950 * Decode it and validate the range.
4951 */
4952 switch (cb)
4953 {
4954 case 6:
4955 cb = (abHdr[6] & 0x3f)
4956 | ((uint32_t)(abHdr[5] & 0x3f) << 6)
4957 | ((uint32_t)(abHdr[4] & 0x3f) << 12)
4958 | ((uint32_t)(abHdr[3] & 0x3f) << 18)
4959 | ((uint32_t)(abHdr[2] & 0x3f) << 24)
4960 | ((uint32_t)(abHdr[1] & 0x01) << 30);
4961 AssertLogRelMsgReturn(cb >= 0x04000000 && cb <= 0x7fffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4962 break;
4963 case 5:
4964 cb = (abHdr[5] & 0x3f)
4965 | ((uint32_t)(abHdr[4] & 0x3f) << 6)
4966 | ((uint32_t)(abHdr[3] & 0x3f) << 12)
4967 | ((uint32_t)(abHdr[2] & 0x3f) << 18)
4968 | ((uint32_t)(abHdr[1] & 0x03) << 24);
4969 AssertLogRelMsgReturn(cb >= 0x00200000 && cb <= 0x03ffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4970 break;
4971 case 4:
4972 cb = (abHdr[4] & 0x3f)
4973 | ((uint32_t)(abHdr[3] & 0x3f) << 6)
4974 | ((uint32_t)(abHdr[2] & 0x3f) << 12)
4975 | ((uint32_t)(abHdr[1] & 0x07) << 18);
4976 AssertLogRelMsgReturn(cb >= 0x00010000 && cb <= 0x001fffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4977 break;
4978 case 3:
4979 cb = (abHdr[3] & 0x3f)
4980 | ((uint32_t)(abHdr[2] & 0x3f) << 6)
4981 | ((uint32_t)(abHdr[1] & 0x0f) << 12);
4982#if 0 /* disabled to optimize buffering */
4983 AssertLogRelMsgReturn(cb >= 0x00000800 && cb <= 0x0000ffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4984#endif
4985 break;
4986 case 2:
4987 cb = (abHdr[2] & 0x3f)
4988 | ((uint32_t)(abHdr[1] & 0x1f) << 6);
4989#if 0 /* disabled to optimize buffering */
4990 AssertLogRelMsgReturn(cb >= 0x00000080 && cb <= 0x000007ff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY_REC_HDR);
4991#endif
4992 break;
4993 default:
4994 return VERR_INTERNAL_ERROR;
4995 }
4996
4997 pSSM->u.Read.cbRecLeft = cb;
4998 }
4999
5000 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
5001 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft,
5002 pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK,
5003 !!(pSSM->u.Read.u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT),
5004 cbHdr
5005 )); NOREF(cbHdr);
5006 return VINF_SUCCESS;
5007}
5008
5009
5010/**
5011 * Buffer miss, do an unbuffered read.
5012 *
5013 * @param pSSM SSM operation handle.
5014 * @param pvBuf Where to store the read data.
5015 * @param cbBuf Number of bytes to read.
5016 */
5017static int ssmR3DataReadUnbufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5018{
5019 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
5020 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
5021
5022 /*
5023 * Copy out what we've got in the buffer.
5024 */
5025 uint32_t off = pSSM->u.Read.offDataBuffer;
5026 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
5027 Log4(("ssmR3DataReadUnbufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
5028 if (cbInBuffer > 0)
5029 {
5030 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
5031 Assert(cbBuf > cbToCopy);
5032 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
5033 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5034 cbBuf -= cbToCopy;
5035 pSSM->u.Read.cbDataBuffer = 0;
5036 pSSM->u.Read.offDataBuffer = 0;
5037 }
5038
5039 /*
5040 * Read data.
5041 */
5042 do
5043 {
5044 /*
5045 * Read the next record header if no more data.
5046 */
5047 if (!pSSM->u.Read.cbRecLeft)
5048 {
5049 int rc = ssmR3DataReadRecHdrV2(pSSM);
5050 if (RT_FAILURE(rc))
5051 return pSSM->rc = rc;
5052 }
5053 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
5054
5055 /*
5056 * Read data from the current record.
5057 */
5058 uint32_t cbToRead;
5059 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
5060 {
5061 case SSM_REC_TYPE_RAW:
5062 {
5063 cbToRead = (uint32_t)RT_MIN(cbBuf, pSSM->u.Read.cbRecLeft);
5064 int rc = ssmR3DataReadV2Raw(pSSM, pvBuf, cbToRead);
5065 if (RT_FAILURE(rc))
5066 return pSSM->rc = rc;
5067 pSSM->u.Read.cbRecLeft -= cbToRead;
5068 break;
5069 }
5070
5071 case SSM_REC_TYPE_RAW_LZF:
5072 {
5073 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbToRead);
5074 if (RT_FAILURE(rc))
5075 return rc;
5076 if (cbToRead <= cbBuf)
5077 {
5078 rc = ssmR3DataReadV2RawLzf(pSSM, pvBuf, cbToRead);
5079 if (RT_FAILURE(rc))
5080 return rc;
5081 }
5082 else
5083 {
5084 /* The output buffer is too small, use the data buffer. */
5085 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5086 if (RT_FAILURE(rc))
5087 return rc;
5088 pSSM->u.Read.cbDataBuffer = cbToRead;
5089 cbToRead = (uint32_t)cbBuf;
5090 pSSM->u.Read.offDataBuffer = cbToRead;
5091 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5092 }
5093 break;
5094 }
5095
5096 case SSM_REC_TYPE_RAW_ZERO:
5097 {
5098 int rc = ssmR3DataReadV2RawZeroHdr(pSSM, &cbToRead);
5099 if (RT_FAILURE(rc))
5100 return rc;
5101 if (cbToRead > cbBuf)
5102 {
5103 /* Spill the remainer into the data buffer. */
5104 memset(&pSSM->u.Read.abDataBuffer[0], 0, cbToRead - cbBuf);
5105 pSSM->u.Read.cbDataBuffer = cbToRead - cbBuf;
5106 pSSM->u.Read.offDataBuffer = 0;
5107 cbToRead = (uint32_t)cbBuf;
5108 }
5109 memset(pvBuf, 0, cbToRead);
5110 break;
5111 }
5112
5113 default:
5114 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), VERR_INTERNAL_ERROR_5);
5115 }
5116
5117 cbBuf -= cbToRead;
5118 pvBuf = (uint8_t *)pvBuf + cbToRead;
5119 } while (cbBuf > 0);
5120
5121 Log4(("ssmR3DataReadUnBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
5122 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, 0, cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
5123 return VINF_SUCCESS;
5124}
5125
5126
5127/**
5128 * Buffer miss, do a buffered read.
5129 *
5130 * @param pSSM SSM operation handle.
5131 * @param pvBuf Where to store the read data.
5132 * @param cbBuf Number of bytes to read.
5133 */
5134static int ssmR3DataReadBufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5135{
5136 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
5137 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
5138
5139 /*
5140 * Copy out what we've got in the buffer.
5141 */
5142 uint32_t off = pSSM->u.Read.offDataBuffer;
5143 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
5144 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
5145 if (cbInBuffer > 0)
5146 {
5147 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
5148 Assert(cbBuf > cbToCopy);
5149 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
5150 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5151 cbBuf -= cbToCopy;
5152 pSSM->u.Read.cbDataBuffer = 0;
5153 pSSM->u.Read.offDataBuffer = 0;
5154 }
5155
5156 /*
5157 * Buffer more data.
5158 */
5159 do
5160 {
5161 /*
5162 * Read the next record header if no more data.
5163 */
5164 if (!pSSM->u.Read.cbRecLeft)
5165 {
5166 int rc = ssmR3DataReadRecHdrV2(pSSM);
5167 if (RT_FAILURE(rc))
5168 return pSSM->rc = rc;
5169 }
5170 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
5171
5172 /*
5173 * Read data from the current record.
5174 * LATER: optimize by reading directly into the output buffer for some cases.
5175 */
5176 uint32_t cbToRead;
5177 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
5178 {
5179 case SSM_REC_TYPE_RAW:
5180 {
5181 cbToRead = RT_MIN(sizeof(pSSM->u.Read.abDataBuffer), pSSM->u.Read.cbRecLeft);
5182 int rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5183 if (RT_FAILURE(rc))
5184 return pSSM->rc = rc;
5185 pSSM->u.Read.cbRecLeft -= cbToRead;
5186 pSSM->u.Read.cbDataBuffer = cbToRead;
5187 break;
5188 }
5189
5190 case SSM_REC_TYPE_RAW_LZF:
5191 {
5192 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbToRead);
5193 if (RT_FAILURE(rc))
5194 return rc;
5195 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5196 if (RT_FAILURE(rc))
5197 return rc;
5198 pSSM->u.Read.cbDataBuffer = cbToRead;
5199 break;
5200 }
5201
5202 case SSM_REC_TYPE_RAW_ZERO:
5203 {
5204 int rc = ssmR3DataReadV2RawZeroHdr(pSSM, &cbToRead);
5205 if (RT_FAILURE(rc))
5206 return rc;
5207 memset(&pSSM->u.Read.abDataBuffer[0], 0, cbToRead);
5208 pSSM->u.Read.cbDataBuffer = cbToRead;
5209 break;
5210 }
5211
5212 default:
5213 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), VERR_INTERNAL_ERROR_5);
5214 }
5215 /*pSSM->u.Read.offDataBuffer = 0;*/
5216
5217 /*
5218 * Copy data from the buffer.
5219 */
5220 uint32_t cbToCopy = (uint32_t)RT_MIN(cbBuf, cbToRead);
5221 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToCopy);
5222 cbBuf -= cbToCopy;
5223 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5224 pSSM->u.Read.offDataBuffer = cbToCopy;
5225 } while (cbBuf > 0);
5226
5227 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
5228 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
5229 cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
5230 return VINF_SUCCESS;
5231}
5232
5233
5234/**
5235 * Inlined worker that handles format checks and buffered reads.
5236 *
5237 * @param pSSM SSM operation handle.
5238 * @param pvBuf Where to store the read data.
5239 * @param cbBuf Number of bytes to read.
5240 */
5241DECLINLINE(int) ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5242{
5243 /*
5244 * Fend off previous errors and V1 data units.
5245 */
5246 if (RT_FAILURE(pSSM->rc))
5247 return pSSM->rc;
5248 if (RT_UNLIKELY(pSSM->u.Read.uFmtVerMajor == 1))
5249 return ssmR3DataReadV1(pSSM, pvBuf, cbBuf);
5250
5251 /*
5252 * Check if the requested data is buffered.
5253 */
5254 uint32_t off = pSSM->u.Read.offDataBuffer;
5255 if ( off + cbBuf > pSSM->u.Read.cbDataBuffer
5256 || cbBuf > sizeof(pSSM->u.Read.abDataBuffer))
5257 {
5258 if (cbBuf <= sizeof(pSSM->u.Read.abDataBuffer) / 8)
5259 return ssmR3DataReadBufferedV2(pSSM, pvBuf, cbBuf);
5260 return ssmR3DataReadUnbufferedV2(pSSM, pvBuf, cbBuf);
5261 }
5262
5263 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbBuf);
5264 pSSM->u.Read.offDataBuffer = off + (uint32_t)cbBuf;
5265 Log4((cbBuf
5266 ? "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n"
5267 : "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n",
5268 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
5269 cbBuf, RT_MIN(SSM_LOG_BYTES, cbBuf), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
5270
5271 return VINF_SUCCESS;
5272}
5273
5274
5275/**
5276 * Gets a structure.
5277 *
5278 * @returns VBox status code.
5279 * @param pSSM The saved state handle.
5280 * @param pvStruct The structure address.
5281 * @param paFields The array of structure fields descriptions.
5282 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
5283 */
5284VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
5285{
5286 /* begin marker. */
5287 uint32_t u32Magic;
5288 int rc = SSMR3GetU32(pSSM, &u32Magic);
5289 if (RT_FAILURE(rc))
5290 return rc;
5291 if (u32Magic != SSMR3STRUCT_BEGIN)
5292 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
5293
5294 /* put the fields */
5295 for (PCSSMFIELD pCur = paFields;
5296 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
5297 pCur++)
5298 {
5299 rc = ssmR3DataRead(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
5300 if (RT_FAILURE(rc))
5301 return rc;
5302 }
5303
5304 /* end marker */
5305 rc = SSMR3GetU32(pSSM, &u32Magic);
5306 if (RT_FAILURE(rc))
5307 return rc;
5308 if (u32Magic != SSMR3STRUCT_END)
5309 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
5310 return rc;
5311}
5312
5313
5314/**
5315 * Loads a boolean item from the current data unit.
5316 *
5317 * @returns VBox status.
5318 * @param pSSM SSM operation handle.
5319 * @param pfBool Where to store the item.
5320 */
5321VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
5322{
5323 SSM_ASSERT_READABLE_RET(pSSM);
5324 SSM_CHECK_CANCELLED_RET(pSSM);
5325 uint8_t u8; /* see SSMR3PutBool */
5326 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
5327 if (RT_SUCCESS(rc))
5328 {
5329 Assert(u8 <= 1);
5330 *pfBool = !!u8;
5331 }
5332 return rc;
5333}
5334
5335
5336/**
5337 * Loads a 8-bit unsigned integer item from the current data unit.
5338 *
5339 * @returns VBox status.
5340 * @param pSSM SSM operation handle.
5341 * @param pu8 Where to store the item.
5342 */
5343VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
5344{
5345 SSM_ASSERT_READABLE_RET(pSSM);
5346 SSM_CHECK_CANCELLED_RET(pSSM);
5347 return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
5348}
5349
5350
5351/**
5352 * Loads a 8-bit signed integer item from the current data unit.
5353 *
5354 * @returns VBox status.
5355 * @param pSSM SSM operation handle.
5356 * @param pi8 Where to store the item.
5357 */
5358VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
5359{
5360 SSM_ASSERT_READABLE_RET(pSSM);
5361 SSM_CHECK_CANCELLED_RET(pSSM);
5362 return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
5363}
5364
5365
5366/**
5367 * Loads a 16-bit unsigned integer item from the current data unit.
5368 *
5369 * @returns VBox status.
5370 * @param pSSM SSM operation handle.
5371 * @param pu16 Where to store the item.
5372 */
5373VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
5374{
5375 SSM_ASSERT_READABLE_RET(pSSM);
5376 SSM_CHECK_CANCELLED_RET(pSSM);
5377 return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
5378}
5379
5380
5381/**
5382 * Loads a 16-bit signed integer item from the current data unit.
5383 *
5384 * @returns VBox status.
5385 * @param pSSM SSM operation handle.
5386 * @param pi16 Where to store the item.
5387 */
5388VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
5389{
5390 SSM_ASSERT_READABLE_RET(pSSM);
5391 SSM_CHECK_CANCELLED_RET(pSSM);
5392 return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
5393}
5394
5395
5396/**
5397 * Loads a 32-bit unsigned integer item from the current data unit.
5398 *
5399 * @returns VBox status.
5400 * @param pSSM SSM operation handle.
5401 * @param pu32 Where to store the item.
5402 */
5403VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
5404{
5405 SSM_ASSERT_READABLE_RET(pSSM);
5406 SSM_CHECK_CANCELLED_RET(pSSM);
5407 return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
5408}
5409
5410
5411/**
5412 * Loads a 32-bit signed integer item from the current data unit.
5413 *
5414 * @returns VBox status.
5415 * @param pSSM SSM operation handle.
5416 * @param pi32 Where to store the item.
5417 */
5418VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
5419{
5420 SSM_ASSERT_READABLE_RET(pSSM);
5421 SSM_CHECK_CANCELLED_RET(pSSM);
5422 return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
5423}
5424
5425
5426/**
5427 * Loads a 64-bit unsigned integer item from the current data unit.
5428 *
5429 * @returns VBox status.
5430 * @param pSSM SSM operation handle.
5431 * @param pu64 Where to store the item.
5432 */
5433VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
5434{
5435 SSM_ASSERT_READABLE_RET(pSSM);
5436 SSM_CHECK_CANCELLED_RET(pSSM);
5437 return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
5438}
5439
5440
5441/**
5442 * Loads a 64-bit signed integer item from the current data unit.
5443 *
5444 * @returns VBox status.
5445 * @param pSSM SSM operation handle.
5446 * @param pi64 Where to store the item.
5447 */
5448VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
5449{
5450 SSM_ASSERT_READABLE_RET(pSSM);
5451 SSM_CHECK_CANCELLED_RET(pSSM);
5452 return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
5453}
5454
5455
5456/**
5457 * Loads a 128-bit unsigned integer item from the current data unit.
5458 *
5459 * @returns VBox status.
5460 * @param pSSM SSM operation handle.
5461 * @param pu128 Where to store the item.
5462 */
5463VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
5464{
5465 SSM_ASSERT_READABLE_RET(pSSM);
5466 SSM_CHECK_CANCELLED_RET(pSSM);
5467 return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
5468}
5469
5470
5471/**
5472 * Loads a 128-bit signed integer item from the current data unit.
5473 *
5474 * @returns VBox status.
5475 * @param pSSM SSM operation handle.
5476 * @param pi128 Where to store the item.
5477 */
5478VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
5479{
5480 SSM_ASSERT_READABLE_RET(pSSM);
5481 SSM_CHECK_CANCELLED_RET(pSSM);
5482 return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
5483}
5484
5485
5486/**
5487 * Loads a VBox unsigned integer item from the current data unit.
5488 *
5489 * @returns VBox status.
5490 * @param pSSM SSM operation handle.
5491 * @param pu Where to store the integer.
5492 */
5493VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
5494{
5495 SSM_ASSERT_READABLE_RET(pSSM);
5496 SSM_CHECK_CANCELLED_RET(pSSM);
5497 return ssmR3DataRead(pSSM, pu, sizeof(*pu));
5498}
5499
5500
5501/**
5502 * Loads a VBox signed integer item from the current data unit.
5503 *
5504 * @returns VBox status.
5505 * @param pSSM SSM operation handle.
5506 * @param pi Where to store the integer.
5507 */
5508VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
5509{
5510 SSM_ASSERT_READABLE_RET(pSSM);
5511 SSM_CHECK_CANCELLED_RET(pSSM);
5512 return ssmR3DataRead(pSSM, pi, sizeof(*pi));
5513}
5514
5515
5516/**
5517 * Loads a GC natural unsigned integer item from the current data unit.
5518 *
5519 * @returns VBox status.
5520 * @param pSSM SSM operation handle.
5521 * @param pu Where to store the integer.
5522 *
5523 * @deprecated Silly type with an incorrect size, don't use it.
5524 */
5525VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
5526{
5527 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
5528 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
5529}
5530
5531
5532/**
5533 * Loads a GC unsigned integer register item from the current data unit.
5534 *
5535 * @returns VBox status.
5536 * @param pSSM SSM operation handle.
5537 * @param pu Where to store the integer.
5538 */
5539VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu)
5540{
5541 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
5542 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
5543}
5544
5545
5546/**
5547 * Loads a 32 bits GC physical address item from the current data unit.
5548 *
5549 * @returns VBox status.
5550 * @param pSSM SSM operation handle.
5551 * @param pGCPhys Where to store the GC physical address.
5552 */
5553VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
5554{
5555 SSM_ASSERT_READABLE_RET(pSSM);
5556 SSM_CHECK_CANCELLED_RET(pSSM);
5557 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5558}
5559
5560
5561/**
5562 * Loads a 64 bits GC physical address item from the current data unit.
5563 *
5564 * @returns VBox status.
5565 * @param pSSM SSM operation handle.
5566 * @param pGCPhys Where to store the GC physical address.
5567 */
5568VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
5569{
5570 SSM_ASSERT_READABLE_RET(pSSM);
5571 SSM_CHECK_CANCELLED_RET(pSSM);
5572 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5573}
5574
5575
5576/**
5577 * Loads a GC physical address item from the current data unit.
5578 *
5579 * @returns VBox status.
5580 * @param pSSM SSM operation handle.
5581 * @param pGCPhys Where to store the GC physical address.
5582 */
5583VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
5584{
5585 SSM_ASSERT_READABLE_RET(pSSM);
5586 SSM_CHECK_CANCELLED_RET(pSSM);
5587
5588 /*
5589 * Default size?
5590 */
5591 if (RT_LIKELY(sizeof(*pGCPhys) == pSSM->u.Read.cbGCPhys))
5592 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5593
5594 /*
5595 * Fiddly.
5596 */
5597 Assert(sizeof(*pGCPhys) == sizeof(uint64_t) || sizeof(*pGCPhys) == sizeof(uint32_t));
5598 Assert(pSSM->u.Read.cbGCPhys == sizeof(uint64_t) || pSSM->u.Read.cbGCPhys == sizeof(uint32_t));
5599 if (pSSM->u.Read.cbGCPhys == sizeof(uint64_t))
5600 {
5601 /* 64-bit saved, 32-bit load: try truncate it. */
5602 uint64_t u64;
5603 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
5604 if (RT_FAILURE(rc))
5605 return rc;
5606 if (u64 >= _4G)
5607 return VERR_SSM_GCPHYS_OVERFLOW;
5608 *pGCPhys = (RTGCPHYS)u64;
5609 return rc;
5610 }
5611
5612 /* 32-bit saved, 64-bit load: clear the high part. */
5613 *pGCPhys = 0;
5614 return ssmR3DataRead(pSSM, pGCPhys, sizeof(uint32_t));
5615}
5616
5617
5618/**
5619 * Loads a GC virtual address item from the current data unit.
5620 *
5621 * Only applies to in the 1.1 format:
5622 * - SSMR3GetGCPtr
5623 * - SSMR3GetGCUIntPtr
5624 * - SSMR3GetGCUInt
5625 * - SSMR3GetGCUIntReg
5626 *
5627 * Put functions are not affected.
5628 *
5629 * @returns VBox status.
5630 * @param pSSM SSM operation handle.
5631 * @param cbGCPtr Size of RTGCPTR
5632 *
5633 * @remarks This interface only works with saved state version 1.1, if the
5634 * format isn't 1.1 the call will be ignored.
5635 */
5636VMMR3_INT_DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
5637{
5638 Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
5639 if (!pSSM->u.Read.fFixedGCPtrSize)
5640 {
5641 Log(("SSMR3SetGCPtrSize: %u -> %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
5642 pSSM->u.Read.cbGCPtr = cbGCPtr;
5643 pSSM->u.Read.fFixedGCPtrSize = true;
5644 }
5645 else if ( pSSM->u.Read.cbGCPtr != cbGCPtr
5646 && pSSM->u.Read.uFmtVerMajor == 1
5647 && pSSM->u.Read.uFmtVerMinor == 1)
5648 AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %u bytes; requested %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
5649
5650 return VINF_SUCCESS;
5651}
5652
5653
5654/**
5655 * Loads a GC virtual address item from the current data unit.
5656 *
5657 * @returns VBox status.
5658 * @param pSSM SSM operation handle.
5659 * @param pGCPtr Where to store the GC virtual address.
5660 */
5661VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
5662{
5663 SSM_ASSERT_READABLE_RET(pSSM);
5664 SSM_CHECK_CANCELLED_RET(pSSM);
5665
5666 /*
5667 * Default size?
5668 */
5669 if (RT_LIKELY(sizeof(*pGCPtr) == pSSM->u.Read.cbGCPtr))
5670 return ssmR3DataRead(pSSM, pGCPtr, sizeof(*pGCPtr));
5671
5672 /*
5673 * Fiddly.
5674 */
5675 Assert(sizeof(*pGCPtr) == sizeof(uint64_t) || sizeof(*pGCPtr) == sizeof(uint32_t));
5676 Assert(pSSM->u.Read.cbGCPtr == sizeof(uint64_t) || pSSM->u.Read.cbGCPtr == sizeof(uint32_t));
5677 if (pSSM->u.Read.cbGCPtr == sizeof(uint64_t))
5678 {
5679 /* 64-bit saved, 32-bit load: try truncate it. */
5680 uint64_t u64;
5681 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
5682 if (RT_FAILURE(rc))
5683 return rc;
5684 if (u64 >= _4G)
5685 return VERR_SSM_GCPTR_OVERFLOW;
5686 *pGCPtr = (RTGCPTR)u64;
5687 return rc;
5688 }
5689
5690 /* 32-bit saved, 64-bit load: clear the high part. */
5691 *pGCPtr = 0;
5692 return ssmR3DataRead(pSSM, pGCPtr, sizeof(uint32_t));
5693}
5694
5695
5696/**
5697 * Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
5698 *
5699 * @returns VBox status.
5700 * @param pSSM SSM operation handle.
5701 * @param pGCPtr Where to store the GC virtual address.
5702 */
5703VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
5704{
5705 AssertCompile(sizeof(RTGCPTR) == sizeof(*pGCPtr));
5706 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pGCPtr);
5707}
5708
5709
5710/**
5711 * Loads an RC virtual address item from the current data unit.
5712 *
5713 * @returns VBox status.
5714 * @param pSSM SSM operation handle.
5715 * @param pRCPtr Where to store the RC virtual address.
5716 */
5717VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
5718{
5719 SSM_ASSERT_READABLE_RET(pSSM);
5720 SSM_CHECK_CANCELLED_RET(pSSM);
5721 return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
5722}
5723
5724
5725/**
5726 * Loads a I/O port address item from the current data unit.
5727 *
5728 * @returns VBox status.
5729 * @param pSSM SSM operation handle.
5730 * @param pIOPort Where to store the I/O port address.
5731 */
5732VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
5733{
5734 SSM_ASSERT_READABLE_RET(pSSM);
5735 SSM_CHECK_CANCELLED_RET(pSSM);
5736 return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
5737}
5738
5739
5740/**
5741 * Loads a selector item from the current data unit.
5742 *
5743 * @returns VBox status.
5744 * @param pSSM SSM operation handle.
5745 * @param pSel Where to store the selector.
5746 */
5747VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
5748{
5749 SSM_ASSERT_READABLE_RET(pSSM);
5750 SSM_CHECK_CANCELLED_RET(pSSM);
5751 return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
5752}
5753
5754
5755/**
5756 * Loads a memory item from the current data unit.
5757 *
5758 * @returns VBox status.
5759 * @param pSSM SSM operation handle.
5760 * @param pv Where to store the item.
5761 * @param cb Size of the item.
5762 */
5763VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
5764{
5765 SSM_ASSERT_READABLE_RET(pSSM);
5766 SSM_CHECK_CANCELLED_RET(pSSM);
5767 return ssmR3DataRead(pSSM, pv, cb);
5768}
5769
5770
5771/**
5772 * Loads a string item from the current data unit.
5773 *
5774 * @returns VBox status.
5775 * @param pSSM SSM operation handle.
5776 * @param psz Where to store the item.
5777 * @param cbMax Max size of the item (including '\\0').
5778 */
5779VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
5780{
5781 return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
5782}
5783
5784
5785/**
5786 * Loads a string item from the current data unit.
5787 *
5788 * @returns VBox status.
5789 * @param pSSM SSM operation handle.
5790 * @param psz Where to store the item.
5791 * @param cbMax Max size of the item (including '\\0').
5792 * @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
5793 */
5794VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
5795{
5796 SSM_ASSERT_READABLE_RET(pSSM);
5797 SSM_CHECK_CANCELLED_RET(pSSM);
5798
5799 /* read size prefix. */
5800 uint32_t u32;
5801 int rc = SSMR3GetU32(pSSM, &u32);
5802 if (RT_SUCCESS(rc))
5803 {
5804 if (pcbStr)
5805 *pcbStr = u32;
5806 if (u32 < cbMax)
5807 {
5808 /* terminate and read string content. */
5809 psz[u32] = '\0';
5810 return ssmR3DataRead(pSSM, psz, u32);
5811 }
5812 return VERR_TOO_MUCH_DATA;
5813 }
5814 return rc;
5815}
5816
5817
5818/**
5819 * Skips a number of bytes in the current data unit.
5820 *
5821 * @returns VBox status code.
5822 * @param pSSM The SSM handle.
5823 * @param cb The number of bytes to skip.
5824 */
5825VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
5826{
5827 SSM_ASSERT_READABLE_RET(pSSM);
5828 SSM_CHECK_CANCELLED_RET(pSSM);
5829 while (cb > 0)
5830 {
5831 uint8_t abBuf[8192];
5832 size_t cbCur = RT_MIN(sizeof(abBuf), cb);
5833 cb -= cbCur;
5834 int rc = ssmR3DataRead(pSSM, abBuf, cbCur);
5835 if (RT_FAILURE(rc))
5836 return rc;
5837 }
5838
5839 return VINF_SUCCESS;
5840}
5841
5842
5843/**
5844 * Skips to the end of the current data unit.
5845 *
5846 * Since version 2 of the format, the load exec callback have to explicitly call
5847 * this API if it wish to be lazy for some reason. This is because there seldom
5848 * is a good reason to not read your entire data unit and it was hiding bugs.
5849 *
5850 * @returns VBox status code.
5851 * @param pSSM The saved state handle.
5852 */
5853VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM)
5854{
5855 SSM_ASSERT_READABLE_RET(pSSM);
5856 SSM_CHECK_CANCELLED_RET(pSSM);
5857 if (pSSM->u.Read.uFmtVerMajor >= 2)
5858 {
5859 /*
5860 * Read until we the end of data condition is raised.
5861 */
5862 pSSM->u.Read.cbDataBuffer = 0;
5863 pSSM->u.Read.offDataBuffer = 0;
5864 if (!pSSM->u.Read.fEndOfData)
5865 {
5866 do
5867 {
5868 /* read the rest of the current record */
5869 while (pSSM->u.Read.cbRecLeft)
5870 {
5871 uint8_t abBuf[8192];
5872 size_t cbToRead = RT_MIN(pSSM->u.Read.cbRecLeft, sizeof(abBuf));
5873 int rc = ssmR3DataReadV2Raw(pSSM, abBuf, cbToRead);
5874 if (RT_FAILURE(rc))
5875 return pSSM->rc = rc;
5876 pSSM->u.Read.cbRecLeft -= cbToRead;
5877 }
5878
5879 /* read the next header. */
5880 int rc = ssmR3DataReadRecHdrV2(pSSM);
5881 if (RT_FAILURE(rc))
5882 return pSSM->rc = rc;
5883 } while (!pSSM->u.Read.fEndOfData);
5884 }
5885 }
5886 /* else: Doesn't matter for the version 1 loading. */
5887
5888 return VINF_SUCCESS;
5889}
5890
5891
5892/**
5893 * Calculate the checksum of a file portion.
5894 *
5895 * @returns VBox status.
5896 * @param pStrm The stream handle
5897 * @param off Where to start checksumming.
5898 * @param cb How much to checksum.
5899 * @param pu32CRC Where to store the calculated checksum.
5900 */
5901static int ssmR3CalcChecksum(PSSMSTRM pStrm, uint64_t off, uint64_t cb, uint32_t *pu32CRC)
5902{
5903 /*
5904 * Allocate a buffer.
5905 */
5906 const size_t cbBuf = _32K;
5907 void *pvBuf = RTMemTmpAlloc(cbBuf);
5908 if (!pvBuf)
5909 return VERR_NO_TMP_MEMORY;
5910
5911 /*
5912 * Loop reading and calculating CRC32.
5913 */
5914 int rc = VINF_SUCCESS;
5915 uint32_t u32CRC = RTCrc32Start();
5916 while (cb > 0)
5917 {
5918 /* read chunk */
5919 size_t cbToRead = cbBuf;
5920 if (cb < cbBuf)
5921 cbToRead = cb;
5922 rc = ssmR3StrmPeekAt(pStrm, off, pvBuf, cbToRead, NULL);
5923 if (RT_FAILURE(rc))
5924 {
5925 AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
5926 RTMemTmpFree(pvBuf);
5927 return rc;
5928 }
5929
5930 /* advance */
5931 cb -= cbToRead;
5932 off += cbToRead;
5933
5934 /* calc crc32. */
5935 u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
5936 }
5937 RTMemTmpFree(pvBuf);
5938
5939 /* store the calculated crc */
5940 u32CRC = RTCrc32Finish(u32CRC);
5941 Log(("SSM: u32CRC=0x%08x\n", u32CRC));
5942 *pu32CRC = u32CRC;
5943
5944 return VINF_SUCCESS;
5945}
5946
5947
5948/**
5949 * Validates the header information stored in the handle.
5950 *
5951 * @returns VBox status code.
5952 *
5953 * @param pSSM The handle.
5954 * @param fHaveHostBits Set if the host bits field is valid.
5955 * @param fHaveVersion Set if we have a version.
5956 */
5957static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
5958{
5959 Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
5960 Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
5961 Assert(pSSM->u.Read.uFmtVerMinor <= 2);
5962
5963 if (fHaveVersion)
5964 {
5965 if ( pSSM->u.Read.u16VerMajor == 0
5966 || pSSM->u.Read.u16VerMajor > 1000
5967 || pSSM->u.Read.u16VerMinor > 1000
5968 || pSSM->u.Read.u32VerBuild > _1M
5969 || pSSM->u.Read.u32SvnRev == 0
5970 || pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
5971 {
5972 LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
5973 pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
5974 return VERR_SSM_INTEGRITY_VBOX_VERSION;
5975 }
5976 }
5977 else
5978 AssertLogRelReturn( pSSM->u.Read.u16VerMajor == 0
5979 && pSSM->u.Read.u16VerMinor == 0
5980 && pSSM->u.Read.u32VerBuild == 0
5981 && pSSM->u.Read.u32SvnRev == 0,
5982 VERR_SSM_INTEGRITY_VBOX_VERSION);
5983
5984 if (fHaveHostBits)
5985 {
5986 if ( pSSM->u.Read.cHostBits != 32
5987 && pSSM->u.Read.cHostBits != 64)
5988 {
5989 LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
5990 return VERR_SSM_INTEGRITY_HEADER;
5991 }
5992 }
5993 else
5994 AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_HEADER);
5995
5996 if ( pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
5997 && pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
5998 {
5999 LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
6000 return VERR_SSM_INTEGRITY_HEADER;
6001 }
6002 if ( pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
6003 && pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
6004 {
6005 LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
6006 return VERR_SSM_INTEGRITY_HEADER;
6007 }
6008
6009 return VINF_SUCCESS;
6010}
6011
6012
6013/**
6014 * Reads the header, detects the format version and performs integrity
6015 * validations.
6016 *
6017 * @returns VBox status.
6018 * @param File File to validate.
6019 * The file position is undefined on return.
6020 * @param fChecksumIt Whether to checksum the file or not. This will
6021 * be ignored if it the stream isn't a file.
6022 * @param fChecksumOnRead Whether to validate the checksum while reading
6023 * the stream instead of up front. If not possible,
6024 * verify the checksum up front.
6025 * @param pHdr Where to store the file header.
6026 */
6027static int ssmR3HeaderAndValidate(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
6028{
6029 /*
6030 * Read and check the header magic.
6031 */
6032 union
6033 {
6034 SSMFILEHDR v2_0;
6035 SSMFILEHDRV12 v1_2;
6036 SSMFILEHDRV11 v1_1;
6037 } uHdr;
6038 int rc = ssmR3StrmRead(&pSSM->Strm, &uHdr, sizeof(uHdr.v2_0.szMagic));
6039 if (RT_FAILURE(rc))
6040 {
6041 LogRel(("SSM: Failed to read file magic header. rc=%Rrc\n", rc));
6042 return rc;
6043 }
6044 if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
6045 {
6046 Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
6047 return VERR_SSM_INTEGRITY_MAGIC;
6048 }
6049
6050 /*
6051 * Find the header size and read the rest.
6052 */
6053 static const struct
6054 {
6055 char szMagic[sizeof(SSMFILEHDR_MAGIC_V2_0)];
6056 size_t cbHdr;
6057 unsigned uFmtVerMajor;
6058 unsigned uFmtVerMinor;
6059 } s_aVers[] =
6060 {
6061 { SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR), 2, 0 },
6062 { SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDRV12), 1, 2 },
6063 { SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDRV11), 1, 1 },
6064 };
6065 int iVer = RT_ELEMENTS(s_aVers);
6066 while (iVer-- > 0)
6067 if (!memcmp(uHdr.v2_0.szMagic, s_aVers[iVer].szMagic, sizeof(uHdr.v2_0.szMagic)))
6068 break;
6069 if (iVer < 0)
6070 {
6071 Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
6072 return VERR_SSM_INTEGRITY_VERSION;
6073 }
6074 pSSM->u.Read.uFmtVerMajor = s_aVers[iVer].uFmtVerMajor;
6075 pSSM->u.Read.uFmtVerMinor = s_aVers[iVer].uFmtVerMinor;
6076 pSSM->u.Read.cbFileHdr = s_aVers[iVer].cbHdr;
6077
6078 rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)&uHdr + sizeof(uHdr.v2_0.szMagic), pSSM->u.Read.cbFileHdr - sizeof(uHdr.v2_0.szMagic));
6079 if (RT_FAILURE(rc))
6080 {
6081 LogRel(("SSM: Failed to read the file header. rc=%Rrc\n", rc));
6082 return rc;
6083 }
6084
6085 /*
6086 * Make version specific adjustments.
6087 */
6088 if (pSSM->u.Read.uFmtVerMajor >= 2)
6089 {
6090 /*
6091 * Version 2.0 and later.
6092 */
6093 bool fChecksummed;
6094 if (pSSM->u.Read.uFmtVerMinor == 0)
6095 {
6096 /* validate the header. */
6097 SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
6098 if (uHdr.v2_0.u8Reserved)
6099 {
6100 LogRel(("SSM: Reserved header field isn't zero: %02x\n", uHdr.v2_0.u8Reserved));
6101 return VERR_SSM_INTEGRITY;
6102 }
6103 if ((uHdr.v2_0.fFlags & ~SSMFILEHDR_FLAGS_STREAM_CRC32))
6104 {
6105 LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
6106 return VERR_SSM_INTEGRITY;
6107 }
6108 if ( uHdr.v2_0.cbMaxDecompr > sizeof(pSSM->u.Read.abDataBuffer)
6109 || uHdr.v2_0.cbMaxDecompr < _1K
6110 || (uHdr.v2_0.cbMaxDecompr & 0xff) != 0)
6111 {
6112 LogRel(("SSM: The cbMaxDecompr header field is out of range: %#x\n", uHdr.v2_0.cbMaxDecompr));
6113 return VERR_SSM_INTEGRITY;
6114 }
6115
6116 /* set the header info. */
6117 pSSM->u.Read.cHostBits = uHdr.v2_0.cHostBits;
6118 pSSM->u.Read.u16VerMajor = uHdr.v2_0.u16VerMajor;
6119 pSSM->u.Read.u16VerMinor = uHdr.v2_0.u16VerMinor;
6120 pSSM->u.Read.u32VerBuild = uHdr.v2_0.u32VerBuild;
6121 pSSM->u.Read.u32SvnRev = uHdr.v2_0.u32SvnRev;
6122 pSSM->u.Read.cbGCPhys = uHdr.v2_0.cbGCPhys;
6123 pSSM->u.Read.cbGCPtr = uHdr.v2_0.cbGCPtr;
6124 pSSM->u.Read.fFixedGCPtrSize = true;
6125 fChecksummed = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
6126 }
6127 else
6128 AssertFailedReturn(VERR_INTERNAL_ERROR);
6129 if (!fChecksummed)
6130 ssmR3StrmDisableChecksumming(&pSSM->Strm);
6131
6132 /*
6133 * Read and validate the footer if it's a file.
6134 */
6135 if (ssmR3StrmIsFile(&pSSM->Strm))
6136 {
6137 SSMFILEFTR Footer;
6138 uint64_t offFooter;
6139 rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(SSMFILEFTR), &Footer, sizeof(Footer), &offFooter);
6140 AssertLogRelRCReturn(rc, rc);
6141 if (memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)))
6142 {
6143 LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(Footer.szMagic), &Footer.szMagic[0]));
6144 return VERR_SSM_INTEGRITY_FOOTER;
6145 }
6146 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
6147 if (Footer.offStream != offFooter)
6148 {
6149 LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
6150 return VERR_SSM_INTEGRITY_FOOTER;
6151 }
6152 if (Footer.u32Reserved)
6153 {
6154 LogRel(("SSM: Reserved footer field isn't zero: %08x\n", Footer.u32Reserved));
6155 return VERR_SSM_INTEGRITY_FOOTER;
6156 }
6157 if ( !fChecksummed
6158 && Footer.u32StreamCRC)
6159 {
6160 LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
6161 return VERR_SSM_INTEGRITY_FOOTER;
6162 }
6163
6164 pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
6165 pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
6166 }
6167 else
6168 {
6169 pSSM->u.Read.cbLoadFile = UINT64_MAX;
6170 pSSM->u.Read.u32LoadCRC = 0;
6171 }
6172
6173 /*
6174 * Validate the header info we've set in the handle.
6175 */
6176 rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
6177 if (RT_FAILURE(rc))
6178 return rc;
6179
6180 /*
6181 * Check the checksum if that's called for and possible.
6182 */
6183 if ( fChecksummed
6184 && fChecksumIt
6185 && !fChecksumOnRead
6186 && ssmR3StrmIsFile(&pSSM->Strm))
6187 {
6188 uint32_t u32CRC;
6189 rc = ssmR3CalcChecksum(&pSSM->Strm, 0, pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR), &u32CRC);
6190 if (RT_FAILURE(rc))
6191 return rc;
6192 if (u32CRC != pSSM->u.Read.u32LoadCRC)
6193 {
6194 LogRel(("SSM: Invalid CRC! Calculated %#010x, in footer %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
6195 return VERR_SSM_INTEGRITY_CRC;
6196 }
6197 }
6198 }
6199 else
6200 {
6201 /*
6202 * Version 1.x of the format.
6203 */
6204 bool fHaveHostBits = true;
6205 bool fHaveVersion = false;
6206 RTUUID MachineUuidFromHdr;
6207
6208 ssmR3StrmDisableChecksumming(&pSSM->Strm);
6209 if (pSSM->u.Read.uFmtVerMinor == 1)
6210 {
6211 pSSM->u.Read.cHostBits = 0; /* unknown */
6212 pSSM->u.Read.u16VerMajor = 0;
6213 pSSM->u.Read.u16VerMinor = 0;
6214 pSSM->u.Read.u32VerBuild = 0;
6215 pSSM->u.Read.u32SvnRev = 0;
6216 pSSM->u.Read.cbLoadFile = uHdr.v1_1.cbFile;
6217 pSSM->u.Read.u32LoadCRC = uHdr.v1_1.u32CRC;
6218 pSSM->u.Read.cbGCPhys = sizeof(RTGCPHYS);
6219 pSSM->u.Read.cbGCPtr = sizeof(RTGCPTR);
6220 pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
6221
6222 MachineUuidFromHdr = uHdr.v1_1.MachineUuid;
6223 fHaveHostBits = false;
6224 }
6225 else if (pSSM->u.Read.uFmtVerMinor == 2)
6226 {
6227 pSSM->u.Read.cHostBits = uHdr.v1_2.cHostBits;
6228 pSSM->u.Read.u16VerMajor = uHdr.v1_2.u16VerMajor;
6229 pSSM->u.Read.u16VerMinor = uHdr.v1_2.u16VerMinor;
6230 pSSM->u.Read.u32VerBuild = uHdr.v1_2.u32VerBuild;
6231 pSSM->u.Read.u32SvnRev = uHdr.v1_2.u32SvnRev;
6232 pSSM->u.Read.cbLoadFile = uHdr.v1_2.cbFile;
6233 pSSM->u.Read.u32LoadCRC = uHdr.v1_2.u32CRC;
6234 pSSM->u.Read.cbGCPhys = uHdr.v1_2.cbGCPhys;
6235 pSSM->u.Read.cbGCPtr = uHdr.v1_2.cbGCPtr;
6236 pSSM->u.Read.fFixedGCPtrSize = true;
6237
6238 MachineUuidFromHdr = uHdr.v1_2.MachineUuid;
6239 fHaveVersion = true;
6240 }
6241 else
6242 AssertFailedReturn(VERR_INTERNAL_ERROR);
6243
6244 /*
6245 * The MachineUuid must be NULL (was never used).
6246 */
6247 if (!RTUuidIsNull(&MachineUuidFromHdr))
6248 {
6249 LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
6250 return VERR_SMM_INTEGRITY_MACHINE;
6251 }
6252
6253 /*
6254 * Verify the file size.
6255 */
6256 uint64_t cbFile = ssmR3StrmGetSize(&pSSM->Strm);
6257 if (cbFile != pSSM->u.Read.cbLoadFile)
6258 {
6259 LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
6260 return VERR_SSM_INTEGRITY_SIZE;
6261 }
6262
6263 /*
6264 * Validate the header info we've set in the handle.
6265 */
6266 rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
6267 if (RT_FAILURE(rc))
6268 return rc;
6269
6270 /*
6271 * Verify the checksum if requested.
6272 *
6273 * Note! The checksum is not actually generated for the whole file,
6274 * this is of course a bug in the v1.x code that we cannot do
6275 * anything about.
6276 */
6277 if ( fChecksumIt
6278 || fChecksumOnRead)
6279 {
6280 uint32_t u32CRC;
6281 rc = ssmR3CalcChecksum(&pSSM->Strm,
6282 RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC),
6283 cbFile - pSSM->u.Read.cbFileHdr,
6284 &u32CRC);
6285 if (RT_FAILURE(rc))
6286 return rc;
6287 if (u32CRC != pSSM->u.Read.u32LoadCRC)
6288 {
6289 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
6290 return VERR_SSM_INTEGRITY_CRC;
6291 }
6292 }
6293 }
6294
6295 return VINF_SUCCESS;
6296}
6297
6298
6299/**
6300 * Open a saved state for reading.
6301 *
6302 * The file will be positioned at the first data unit upon successful return.
6303 *
6304 * @returns VBox status code.
6305 *
6306 * @param pVM The VM handle.
6307 * @param pszFilename The filename.
6308 * @param fChecksumIt Check the checksum for the entire file.
6309 * @param fChecksumOnRead Whether to validate the checksum while reading
6310 * the stream instead of up front. If not possible,
6311 * verify the checksum up front.
6312 * @param pSSM Pointer to the handle structure. This will be
6313 * completely initialized on success.
6314 * @param cBuffers The number of stream buffers.
6315 */
6316static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead,
6317 uint32_t cBuffers, PSSMHANDLE pSSM)
6318{
6319 /*
6320 * Initialize the handle.
6321 */
6322 pSSM->pVM = pVM;
6323 pSSM->enmOp = SSMSTATE_INVALID;
6324 pSSM->enmAfter = SSMAFTER_INVALID;
6325 pSSM->fCancelled = SSMHANDLE_OK;
6326 pSSM->rc = VINF_SUCCESS;
6327 pSSM->cbUnitLeftV1 = 0;
6328 pSSM->offUnit = UINT64_MAX;
6329 pSSM->pfnProgress = NULL;
6330 pSSM->pvUser = NULL;
6331 pSSM->uPercent = 0;
6332 pSSM->offEstProgress = 0;
6333 pSSM->cbEstTotal = 0;
6334 pSSM->offEst = 0;
6335 pSSM->offEstUnitEnd = 0;
6336 pSSM->uPercentPrepare = 5;
6337 pSSM->uPercentDone = 2;
6338 pSSM->pszFilename = pszFilename;
6339
6340 pSSM->u.Read.pZipDecompV1 = NULL;
6341 pSSM->u.Read.uFmtVerMajor = UINT32_MAX;
6342 pSSM->u.Read.uFmtVerMinor = UINT32_MAX;
6343 pSSM->u.Read.cbFileHdr = UINT32_MAX;
6344 pSSM->u.Read.cbGCPhys = UINT8_MAX;
6345 pSSM->u.Read.cbGCPtr = UINT8_MAX;
6346 pSSM->u.Read.fFixedGCPtrSize= false;
6347 pSSM->u.Read.u16VerMajor = UINT16_MAX;
6348 pSSM->u.Read.u16VerMinor = UINT16_MAX;
6349 pSSM->u.Read.u32VerBuild = UINT32_MAX;
6350 pSSM->u.Read.u32SvnRev = UINT32_MAX;
6351 pSSM->u.Read.cHostBits = UINT8_MAX;
6352 pSSM->u.Read.cbLoadFile = UINT64_MAX;
6353
6354 pSSM->u.Read.cbRecLeft = 0;
6355 pSSM->u.Read.cbDataBuffer = 0;
6356 pSSM->u.Read.offDataBuffer = 0;
6357 pSSM->u.Read.fEndOfData = 0;
6358 pSSM->u.Read.u8TypeAndFlags = 0;
6359
6360 /*
6361 * Try open and validate the file.
6362 */
6363 int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, false /*fWrite*/, fChecksumOnRead, cBuffers);
6364 if (RT_SUCCESS(rc))
6365 {
6366 rc = ssmR3HeaderAndValidate(pSSM, fChecksumIt, fChecksumOnRead);
6367 if (RT_SUCCESS(rc))
6368 return rc;
6369
6370 /* failure path */
6371 ssmR3StrmClose(&pSSM->Strm);
6372 }
6373 else
6374 Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n", pszFilename, rc));
6375 return rc;
6376}
6377
6378
6379/**
6380 * Find a data unit by name.
6381 *
6382 * @returns Pointer to the unit.
6383 * @returns NULL if not found.
6384 *
6385 * @param pVM VM handle.
6386 * @param pszName Data unit name.
6387 * @param uInstance The data unit instance id.
6388 */
6389static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t uInstance)
6390{
6391 size_t cchName = strlen(pszName);
6392 PSSMUNIT pUnit = pVM->ssm.s.pHead;
6393 while ( pUnit
6394 && ( pUnit->u32Instance != uInstance
6395 || pUnit->cchName != cchName
6396 || memcmp(pUnit->szName, pszName, cchName)))
6397 pUnit = pUnit->pNext;
6398 return pUnit;
6399}
6400
6401
6402/**
6403 * Executes the loading of a V1.X file.
6404 *
6405 * @returns VBox status code.
6406 * @param pVM The VM handle.
6407 * @param pSSM The saved state handle.
6408 */
6409static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
6410{
6411 int rc;
6412 char *pszName = NULL;
6413 size_t cchName = 0;
6414 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
6415 for (;;)
6416 {
6417 /*
6418 * Save the current file position and read the data unit header.
6419 */
6420 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
6421 SSMFILEUNITHDRV1 UnitHdr;
6422 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName));
6423 if (RT_SUCCESS(rc))
6424 {
6425 /*
6426 * Check the magic and see if it's valid and whether it is a end header or not.
6427 */
6428 if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
6429 {
6430 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
6431 {
6432 Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
6433 /* Complete the progress bar (pending 99% afterwards). */
6434 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
6435 break;
6436 }
6437 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
6438 offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
6439 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
6440 break;
6441 }
6442
6443 /*
6444 * Read the name.
6445 * Adjust the name buffer first.
6446 */
6447 if (cchName < UnitHdr.cchName)
6448 {
6449 if (pszName)
6450 RTMemTmpFree(pszName);
6451 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
6452 pszName = (char *)RTMemTmpAlloc(cchName);
6453 }
6454 if (pszName)
6455 {
6456 rc = ssmR3StrmRead(&pSSM->Strm, pszName, UnitHdr.cchName);
6457 if (RT_SUCCESS(rc))
6458 {
6459 if (pszName[UnitHdr.cchName - 1])
6460 {
6461 LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
6462 rc = VERR_SSM_INTEGRITY_UNIT;
6463 break;
6464 }
6465 Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
6466
6467 /*
6468 * Find the data unit in our internal table.
6469 */
6470 PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
6471 if (pUnit)
6472 {
6473 /*
6474 * Call the execute handler.
6475 */
6476 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[UnitHdr.cchName]);
6477 pSSM->offUnit = 0;
6478 if (!pUnit->u.Common.pfnLoadExec)
6479 {
6480 LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
6481 rc = VERR_SSM_NO_LOAD_EXEC;
6482 break;
6483 }
6484 switch (pUnit->enmType)
6485 {
6486 case SSMUNITTYPE_DEV:
6487 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
6488 break;
6489 case SSMUNITTYPE_DRV:
6490 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
6491 break;
6492 case SSMUNITTYPE_INTERNAL:
6493 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, SSM_PASS_FINAL);
6494 break;
6495 case SSMUNITTYPE_EXTERNAL:
6496 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PASS_FINAL);
6497 break;
6498 default:
6499 rc = VERR_INTERNAL_ERROR;
6500 break;
6501 }
6502
6503 /*
6504 * Close the reader stream.
6505 */
6506 ssmR3DataReadFinishV1(pSSM);
6507
6508 pUnit->fCalled = true;
6509 if (RT_SUCCESS(rc))
6510 rc = pSSM->rc;
6511 if (RT_SUCCESS(rc))
6512 {
6513 /*
6514 * Now, we'll check the current position to see if all, or
6515 * more than all, the data was read.
6516 *
6517 * Note! Because of buffering / compression we'll only see the
6518 * really bad ones here.
6519 */
6520 uint64_t off = ssmR3StrmTell(&pSSM->Strm);
6521 int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
6522 if (i64Diff < 0)
6523 {
6524 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
6525 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
6526 ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
6527 }
6528 else if (i64Diff > 0)
6529 {
6530 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
6531 rc = VMSetError(pVM, VERR_SSM_LOADED_TOO_MUCH, RT_SRC_POS,
6532 N_("Unit '%s' read %lld bytes too much"), pszName, i64Diff);
6533 break;
6534 }
6535
6536 pSSM->offUnit = UINT64_MAX;
6537 }
6538 else
6539 {
6540 LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
6541 pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
6542 VMSetError(pVM, rc, RT_SRC_POS, N_("Load exec failed for '%s' instance #%u (version %u)"),
6543 pszName, UnitHdr.u32Instance, UnitHdr.u32Version);
6544 break;
6545 }
6546 }
6547 else
6548 {
6549 /*
6550 * SSM unit wasn't found - ignore this when loading for the debugger.
6551 */
6552 LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
6553 rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
6554 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
6555 break;
6556 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
6557 }
6558 }
6559 }
6560 else
6561 rc = VERR_NO_TMP_MEMORY;
6562 }
6563
6564 /*
6565 * I/O errors ends up here (yea, I know, very nice programming).
6566 */
6567 if (RT_FAILURE(rc))
6568 {
6569 LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
6570 break;
6571 }
6572
6573 /*
6574 * Check for cancellation.
6575 */
6576 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
6577 {
6578 LogRel(("SSM: Cancelled!n"));
6579 rc = pSSM->rc;
6580 if (RT_SUCCESS(pSSM->rc))
6581 pSSM->rc = rc = VERR_SSM_CANCELLED;
6582 break;
6583 }
6584 }
6585
6586 RTMemTmpFree(pszName);
6587 return rc;
6588}
6589
6590
6591/**
6592 * Executes the loading of a V2.X file.
6593 *
6594 * @returns VBox status code.
6595 * @param pVM The VM handle.
6596 * @param pSSM The saved state handle.
6597 */
6598static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
6599{
6600 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
6601 for (;;)
6602 {
6603 /*
6604 * Read the unit header and check its integrity.
6605 */
6606 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
6607 uint32_t u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
6608 SSMFILEUNITHDRV2 UnitHdr;
6609 int rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName));
6610 if (RT_FAILURE(rc))
6611 return rc;
6612 if (RT_UNLIKELY( memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
6613 && memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic))))
6614 {
6615 LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
6616 offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
6617 return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_MAGIC, RT_SRC_POS,
6618 N_("Unit at %#llx (%lld): Invalid unit magic"), offUnit, offUnit);
6619 }
6620 if (UnitHdr.cbName)
6621 {
6622 AssertLogRelMsgReturn(UnitHdr.cbName <= sizeof(UnitHdr.szName),
6623 ("Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
6624 offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)),
6625 VERR_SSM_INTEGRITY_UNIT);
6626 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr.szName[0], UnitHdr.cbName);
6627 if (RT_FAILURE(rc))
6628 return rc;
6629 AssertLogRelMsgReturn(!UnitHdr.szName[UnitHdr.cbName - 1],
6630 ("Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
6631 offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName),
6632 VERR_SSM_INTEGRITY_UNIT);
6633 }
6634 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
6635 ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
6636 AssertLogRelMsgReturn(UnitHdr.offStream == offUnit,
6637 ("Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit),
6638 VERR_SSM_INTEGRITY_UNIT);
6639 AssertLogRelMsgReturn(UnitHdr.u32CurStreamCRC == u32CurStreamCRC || !pSSM->Strm.fChecksummed,
6640 ("Unit at %#llx (%lld): Stream CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, UnitHdr.u32CurStreamCRC, u32CurStreamCRC),
6641 VERR_SSM_INTEGRITY_UNIT);
6642 AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags),
6643 VERR_SSM_INTEGRITY_UNIT);
6644 if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)))
6645 {
6646 AssertLogRelMsgReturn( UnitHdr.cbName == 0
6647 && UnitHdr.u32Instance == 0
6648 && UnitHdr.u32Version == 0
6649 && UnitHdr.u32Pass == SSM_PASS_FINAL,
6650 ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
6651 VERR_SSM_INTEGRITY_UNIT);
6652
6653 /*
6654 * Complete the progress bar (pending 99% afterwards) and RETURN.
6655 */
6656 Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
6657 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
6658 return VINF_SUCCESS;
6659 }
6660 AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
6661
6662 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n",
6663 offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version));
6664
6665 /*
6666 * Find the data unit in our internal table.
6667 */
6668 PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
6669 if (pUnit)
6670 {
6671 /*
6672 * Call the execute handler.
6673 */
6674 AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
6675 ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
6676 VERR_SSM_NO_LOAD_EXEC);
6677 ssmR3DataReadBeginV2(pSSM);
6678 switch (pUnit->enmType)
6679 {
6680 case SSMUNITTYPE_DEV:
6681 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
6682 break;
6683 case SSMUNITTYPE_DRV:
6684 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
6685 break;
6686 case SSMUNITTYPE_INTERNAL:
6687 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, UnitHdr.u32Pass);
6688 break;
6689 case SSMUNITTYPE_EXTERNAL:
6690 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Pass);
6691 break;
6692 default:
6693 rc = VERR_INTERNAL_ERROR;
6694 break;
6695 }
6696 ssmR3DataReadFinishV2(pSSM);
6697 pUnit->fCalled = true;
6698 if (RT_SUCCESS(rc))
6699 rc = pSSM->rc;
6700 if (RT_SUCCESS(rc))
6701 pSSM->offUnit = UINT64_MAX;
6702 else
6703 {
6704 LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u, pass %#x): %Rrc\n",
6705 UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Pass, rc));
6706 return VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to load unit '%s'"), UnitHdr.szName);
6707 }
6708 }
6709 else
6710 {
6711 /*
6712 * SSM unit wasn't found - ignore this when loading for the debugger.
6713 */
6714 LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
6715 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
6716 return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_NOT_FOUND, RT_SRC_POS,
6717 N_("Found no handler for unit '%s' instance #%u"), UnitHdr.szName, UnitHdr.u32Instance);
6718 SSMR3SkipToEndOfUnit(pSSM);
6719 ssmR3DataReadFinishV2(pSSM);
6720 }
6721
6722 /*
6723 * Check for cancellation.
6724 */
6725 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED))
6726 {
6727 LogRel(("SSM: Cancelled!\n"));
6728 if (RT_SUCCESS(pSSM->rc))
6729 pSSM->rc = VERR_SSM_CANCELLED;
6730 return pSSM->rc;
6731 }
6732 }
6733 /* won't get here */
6734}
6735
6736
6737
6738
6739/**
6740 * Load VM save operation.
6741 *
6742 * @returns VBox status.
6743 *
6744 * @param pVM The VM handle.
6745 * @param pszFilename Name of the file to save the state in.
6746 * @param enmAfter What is planned after a successful load operation.
6747 * Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
6748 * @param pfnProgress Progress callback. Optional.
6749 * @param pvUser User argument for the progress callback.
6750 *
6751 * @thread EMT
6752 */
6753VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
6754{
6755 LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
6756 VM_ASSERT_EMT0(pVM);
6757
6758 /*
6759 * Validate input.
6760 */
6761 AssertMsgReturn( enmAfter == SSMAFTER_RESUME
6762 || enmAfter == SSMAFTER_MIGRATE
6763 || enmAfter == SSMAFTER_DEBUG_IT,
6764 ("%d\n", enmAfter),
6765 VERR_INVALID_PARAMETER);
6766
6767 /*
6768 * Create the handle and open the file.
6769 */
6770 SSMHANDLE Handle;
6771 int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, 8 /*cBuffers*/, &Handle);
6772 if (RT_SUCCESS(rc))
6773 {
6774 ssmR3StrmStartIoThread(&Handle.Strm);
6775 ssmR3SetCancellable(pVM, &Handle, true);
6776
6777 Handle.enmAfter = enmAfter;
6778 Handle.pfnProgress = pfnProgress;
6779 Handle.pvUser = pvUser;
6780
6781 if (Handle.u.Read.u16VerMajor)
6782 LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
6783 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
6784 Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
6785 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
6786 else
6787 LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
6788 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
6789 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
6790
6791 if (pfnProgress)
6792 pfnProgress(pVM, Handle.uPercent, pvUser);
6793
6794 /*
6795 * Clear the per unit flags.
6796 */
6797 PSSMUNIT pUnit;
6798 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
6799 pUnit->fCalled = false;
6800
6801 /*
6802 * Do the prepare run.
6803 */
6804 Handle.rc = VINF_SUCCESS;
6805 Handle.enmOp = SSMSTATE_LOAD_PREP;
6806 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
6807 {
6808 if (pUnit->u.Common.pfnLoadPrep)
6809 {
6810 pUnit->fCalled = true;
6811 switch (pUnit->enmType)
6812 {
6813 case SSMUNITTYPE_DEV:
6814 rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
6815 break;
6816 case SSMUNITTYPE_DRV:
6817 rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
6818 break;
6819 case SSMUNITTYPE_INTERNAL:
6820 rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
6821 break;
6822 case SSMUNITTYPE_EXTERNAL:
6823 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
6824 break;
6825 default:
6826 rc = VERR_INTERNAL_ERROR;
6827 break;
6828 }
6829 if (RT_FAILURE(rc))
6830 {
6831 LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
6832 break;
6833 }
6834 }
6835 }
6836
6837 /* pending 2% */
6838 if (pfnProgress)
6839 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
6840 Handle.uPercent = Handle.uPercentPrepare;
6841 Handle.cbEstTotal = Handle.u.Read.cbLoadFile;
6842 Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
6843
6844 /*
6845 * Do the execute run.
6846 */
6847 if (RT_SUCCESS(rc))
6848 {
6849 if (Handle.u.Read.uFmtVerMajor >= 2)
6850 rc = ssmR3LoadExecV2(pVM, &Handle);
6851 else
6852 rc = ssmR3LoadExecV1(pVM, &Handle);
6853 /* (progress should be pending 99% now) */
6854 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
6855 }
6856
6857 /*
6858 * Do the done run.
6859 */
6860 Handle.rc = rc;
6861 Handle.enmOp = SSMSTATE_LOAD_DONE;
6862 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
6863 {
6864 if ( pUnit->u.Common.pfnLoadDone
6865 && ( pUnit->fCalled
6866 || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
6867 {
6868 rc = VINF_SUCCESS;
6869 switch (pUnit->enmType)
6870 {
6871 case SSMUNITTYPE_DEV:
6872 rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
6873 break;
6874 case SSMUNITTYPE_DRV:
6875 rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
6876 break;
6877 case SSMUNITTYPE_INTERNAL:
6878 rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
6879 break;
6880 case SSMUNITTYPE_EXTERNAL:
6881 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
6882 break;
6883 default:
6884 rc = VERR_INTERNAL_ERROR;
6885 break;
6886 }
6887 if (RT_FAILURE(rc))
6888 {
6889 LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
6890 rc, pUnit->szName, pUnit->u32Instance));
6891 if (RT_SUCCESS(Handle.rc))
6892 Handle.rc = rc;
6893 break;
6894 }
6895 }
6896 }
6897 rc = Handle.rc;
6898
6899 /* progress */
6900 if (pfnProgress)
6901 pfnProgress(pVM, 99, pvUser);
6902
6903 ssmR3SetCancellable(pVM, &Handle, false);
6904 ssmR3StrmClose(&Handle.Strm);
6905 }
6906
6907 /*
6908 * Done
6909 */
6910 if (RT_SUCCESS(rc))
6911 {
6912 /* progress */
6913 if (pfnProgress)
6914 pfnProgress(pVM, 100, pvUser);
6915 Log(("SSM: Load of '%s' completed!\n", pszFilename));
6916 }
6917 return rc;
6918}
6919
6920
6921/**
6922 * Validates a file as a validate SSM saved state.
6923 *
6924 * This will only verify the file format, the format and content of individual
6925 * data units are not inspected.
6926 *
6927 * @returns VINF_SUCCESS if valid.
6928 * @returns VBox status code on other failures.
6929 *
6930 * @param pszFilename The path to the file to validate.
6931 * @param fChecksumIt Whether to checksum the file or not.
6932 *
6933 * @thread Any.
6934 */
6935VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
6936{
6937 LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
6938
6939 /*
6940 * Try open the file and validate it.
6941 */
6942 SSMHANDLE Handle;
6943 int rc = ssmR3OpenFile(NULL, pszFilename, fChecksumIt, false /*fChecksumOnRead*/, 1 /*cBuffers*/, &Handle);
6944 if (RT_SUCCESS(rc))
6945 ssmR3StrmClose(&Handle.Strm);
6946 else
6947 Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
6948 return rc;
6949}
6950
6951
6952/**
6953 * Opens a saved state file for reading.
6954 *
6955 * @returns VBox status code.
6956 *
6957 * @param pszFilename The path to the saved state file.
6958 * @param fFlags Open flags. Reserved, must be 0.
6959 * @param ppSSM Where to store the SSM handle.
6960 *
6961 * @thread Any.
6962 */
6963VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
6964{
6965 LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
6966
6967 /*
6968 * Validate input.
6969 */
6970 AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
6971 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
6972 AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
6973
6974 /*
6975 * Allocate a handle.
6976 */
6977 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
6978 AssertReturn(pSSM, VERR_NO_MEMORY);
6979
6980 /*
6981 * Try open the file and validate it.
6982 */
6983 int rc = ssmR3OpenFile(NULL, pszFilename, false /*fChecksumIt*/, true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
6984 if (RT_SUCCESS(rc))
6985 {
6986 pSSM->enmAfter = SSMAFTER_OPENED;
6987 pSSM->enmOp = SSMSTATE_OPEN_READ;
6988 *ppSSM = pSSM;
6989 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
6990 return VINF_SUCCESS;
6991 }
6992
6993 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
6994 RTMemFree(pSSM);
6995 return rc;
6996
6997}
6998
6999
7000/**
7001 * Closes a saved state file opened by SSMR3Open().
7002 *
7003 * @returns VBox status code.
7004 *
7005 * @param pSSM The SSM handle returned by SSMR3Open().
7006 *
7007 * @thread Any, but the caller is responsible for serializing calls per handle.
7008 */
7009VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
7010{
7011 LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
7012
7013 /*
7014 * Validate input.
7015 */
7016 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
7017 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
7018 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
7019 Assert(pSSM->fCancelled == SSMHANDLE_OK);
7020
7021 /*
7022 * Close the stream and free the handle.
7023 */
7024 int rc = ssmR3StrmClose(&pSSM->Strm);
7025 if (pSSM->u.Read.pZipDecompV1)
7026 {
7027 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
7028 pSSM->u.Read.pZipDecompV1 = NULL;
7029 }
7030 RTMemFree(pSSM);
7031 return rc;
7032}
7033
7034
7035/**
7036 * Worker for SSMR3Seek that seeks version 1 saved state files.
7037 *
7038 * @returns VBox status code.
7039 * @param pSSM The SSM handle.
7040 * @param pszUnit The unit to seek to.
7041 * @param iInstance The particulart insance we seek.
7042 * @param piVersion Where to store the unit version number.
7043 */
7044static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
7045{
7046 /*
7047 * Walk the data units until we find EOF or a match.
7048 */
7049 size_t cbUnitNm = strlen(pszUnit) + 1;
7050 AssertLogRelReturn(cbUnitNm <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
7051 char szName[SSM_MAX_NAME_SIZE];
7052 SSMFILEUNITHDRV1 UnitHdr;
7053 for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
7054 {
7055 /*
7056 * Read the unit header and verify it.
7057 */
7058 int rc = ssmR3StrmPeekAt(&pSSM->Strm, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName), NULL);
7059 AssertRCReturn(rc, rc);
7060 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
7061 {
7062 /*
7063 * Does what we've got match, if so read the name.
7064 */
7065 if ( UnitHdr.u32Instance == iInstance
7066 && UnitHdr.cchName == cbUnitNm)
7067 {
7068 rc = ssmR3StrmPeekAt(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName), szName, cbUnitNm, NULL);
7069 AssertRCReturn(rc, rc);
7070 AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
7071 (" Unit name '%.*s' was not properly terminated.\n", cbUnitNm, szName),
7072 VERR_SSM_INTEGRITY_UNIT);
7073
7074 /*
7075 * Does the name match?
7076 */
7077 if (!memcmp(szName, pszUnit, cbUnitNm))
7078 {
7079 rc = ssmR3StrmSeek(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName) + cbUnitNm, RTFILE_SEEK_BEGIN, 0);
7080 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[cbUnitNm]);
7081 pSSM->offUnit = 0;
7082 if (piVersion)
7083 *piVersion = UnitHdr.u32Version;
7084 return VINF_SUCCESS;
7085 }
7086 }
7087 }
7088 else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
7089 return VERR_SSM_UNIT_NOT_FOUND;
7090 else
7091 AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
7092 off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
7093 VERR_SSM_INTEGRITY_UNIT_MAGIC);
7094 }
7095 /* won't get here. */
7096}
7097
7098
7099/**
7100 * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
7101 *
7102 * @returns VBox status code.
7103 * @param pSSM The SSM handle.
7104 * @param pDir The directory buffer.
7105 * @param cbDir The size of the directory.
7106 * @param cDirEntries The number of directory entries.
7107 * @param offDir The directory offset in the file.
7108 * @param pszUnit The unit to seek to.
7109 * @param iInstance The particulart insance we seek.
7110 * @param piVersion Where to store the unit version number.
7111 */
7112static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries, uint64_t offDir,
7113 const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
7114{
7115 /*
7116 * Read it.
7117 */
7118 int rc = ssmR3StrmPeekAt(&pSSM->Strm, offDir, pDir, cbDir, NULL);
7119 AssertLogRelRCReturn(rc, rc);
7120 AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY_DIR_MAGIC);
7121 SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
7122 AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
7123 ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
7124 VERR_SSM_INTEGRITY_DIR);
7125 for (uint32_t i = 0; i < cDirEntries; i++)
7126 AssertLogRelMsgReturn(pDir->aEntries[i].off < offDir,
7127 ("i=%u off=%lld offDir=%lld\n", i, pDir->aEntries[i].off, offDir),
7128 VERR_SSM_INTEGRITY_DIR);
7129
7130 /*
7131 * Search the directory.
7132 */
7133 size_t cbUnitNm = strlen(pszUnit) + 1;
7134 uint32_t const u32NameCRC = RTCrc32(pszUnit, cbUnitNm - 1);
7135 for (uint32_t i = 0; i < cDirEntries; i++)
7136 {
7137 if ( pDir->aEntries[i].u32NameCRC == u32NameCRC
7138 && pDir->aEntries[i].u32Instance == iInstance)
7139 {
7140 /*
7141 * Read and validate the unit header.
7142 */
7143 SSMFILEUNITHDRV2 UnitHdr;
7144 size_t cbToRead = sizeof(UnitHdr);
7145 if (pDir->aEntries[i].off + cbToRead > offDir)
7146 {
7147 cbToRead = offDir - pDir->aEntries[i].off;
7148 RT_ZERO(UnitHdr);
7149 }
7150 rc = ssmR3StrmPeekAt(&pSSM->Strm, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
7151 AssertLogRelRCReturn(rc, rc);
7152
7153 AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
7154 ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
7155 VERR_SSM_INTEGRITY_UNIT);
7156 AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
7157 ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
7158 VERR_SSM_INTEGRITY_UNIT);
7159 AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
7160 ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
7161 i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
7162 VERR_SSM_INTEGRITY_UNIT);
7163 uint32_t cbUnitHdr = RT_UOFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]);
7164 AssertLogRelMsgReturn( UnitHdr.cbName > 0
7165 && UnitHdr.cbName < sizeof(UnitHdr)
7166 && cbUnitHdr <= cbToRead,
7167 ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
7168 VERR_SSM_INTEGRITY_UNIT);
7169 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
7170 ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
7171 i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
7172
7173 /*
7174 * Ok, it is valid, get on with the comparing now.
7175 */
7176 if ( UnitHdr.cbName == cbUnitNm
7177 && !memcmp(UnitHdr.szName, pszUnit, cbUnitNm))
7178 {
7179 if (piVersion)
7180 *piVersion = UnitHdr.u32Version;
7181 rc = ssmR3StrmSeek(&pSSM->Strm, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN,
7182 RTCrc32Process(UnitHdr.u32CurStreamCRC, &UnitHdr, cbUnitHdr));
7183 AssertLogRelRCReturn(rc, rc);
7184 ssmR3DataReadBeginV2(pSSM);
7185 return VINF_SUCCESS;
7186 }
7187 }
7188 }
7189
7190 return VERR_SSM_UNIT_NOT_FOUND;
7191}
7192
7193
7194/**
7195 * Worker for SSMR3Seek that seeks version 2 saved state files.
7196 *
7197 * @returns VBox status code.
7198 * @param pSSM The SSM handle.
7199 * @param pszUnit The unit to seek to.
7200 * @param iInstance The particulart insance we seek.
7201 * @param piVersion Where to store the unit version number.
7202 */
7203static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
7204{
7205 /*
7206 * Read the footer, allocate a temporary buffer for the dictionary and
7207 * pass it down to a worker to simplify cleanup.
7208 */
7209 uint64_t offFooter;
7210 SSMFILEFTR Footer;
7211 int rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(Footer), &Footer, sizeof(Footer), &offFooter);
7212 AssertLogRelRCReturn(rc, rc);
7213 AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
7214 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
7215
7216 size_t const cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[Footer.cDirEntries]);
7217 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
7218 if (RT_UNLIKELY(!pDir))
7219 return VERR_NO_TMP_MEMORY;
7220 rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, offFooter - cbDir,
7221 pszUnit, iInstance, piVersion);
7222 RTMemTmpFree(pDir);
7223
7224 return rc;
7225}
7226
7227
7228/**
7229 * Seeks to a specific data unit.
7230 *
7231 * After seeking it's possible to use the getters to on
7232 * that data unit.
7233 *
7234 * @returns VBox status code.
7235 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
7236 *
7237 * @param pSSM The SSM handle returned by SSMR3Open().
7238 * @param pszUnit The name of the data unit.
7239 * @param iInstance The instance number.
7240 * @param piVersion Where to store the version number. (Optional)
7241 *
7242 * @thread Any, but the caller is responsible for serializing calls per handle.
7243 */
7244VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
7245{
7246 LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
7247 pSSM, pszUnit, pszUnit, iInstance, piVersion));
7248
7249 /*
7250 * Validate input.
7251 */
7252 AssertPtrReturn(pSSM, VERR_INVALID_PARAMETER);
7253 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
7254 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
7255 AssertPtrReturn(pszUnit, VERR_INVALID_POINTER);
7256 AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
7257
7258 /*
7259 * Reset the state.
7260 */
7261 if (pSSM->u.Read.pZipDecompV1)
7262 {
7263 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
7264 pSSM->u.Read.pZipDecompV1 = NULL;
7265 }
7266 pSSM->cbUnitLeftV1 = 0;
7267 pSSM->offUnit = UINT64_MAX;
7268
7269 /*
7270 * Call the version specific workers.
7271 */
7272 if (pSSM->u.Read.uFmtVerMajor >= 2)
7273 pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
7274 else
7275 pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
7276 return pSSM->rc;
7277}
7278
7279
7280
7281/* ... Misc APIs ... */
7282/* ... Misc APIs ... */
7283/* ... Misc APIs ... */
7284/* ... Misc APIs ... */
7285/* ... Misc APIs ... */
7286/* ... Misc APIs ... */
7287/* ... Misc APIs ... */
7288/* ... Misc APIs ... */
7289/* ... Misc APIs ... */
7290/* ... Misc APIs ... */
7291/* ... Misc APIs ... */
7292
7293
7294
7295/**
7296 * Query what the VBox status code of the operation is.
7297 *
7298 * This can be used for putting and getting a batch of values
7299 * without bother checking the result till all the calls have
7300 * been made.
7301 *
7302 * @returns SSMAFTER enum value.
7303 * @param pSSM SSM operation handle.
7304 */
7305VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
7306{
7307 return pSSM->rc;
7308}
7309
7310
7311/**
7312 * Fail the load operation.
7313 *
7314 * This is mainly intended for sub item loaders (like timers) which
7315 * return code isn't necessarily heeded by the caller but is important
7316 * to SSM.
7317 *
7318 * @returns VBox status code of the handle, or VERR_INVALID_PARAMETER.
7319 * @param pSSM SSM operation handle.
7320 * @param iStatus Failure status code. This MUST be a VERR_*.
7321 */
7322VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
7323{
7324 Assert(pSSM->enmOp != SSMSTATE_LIVE_VOTE);
7325 if (RT_FAILURE(iStatus))
7326 {
7327 int rc = pSSM->rc;
7328 if (RT_SUCCESS(rc))
7329 pSSM->rc = rc = iStatus;
7330 return rc;
7331 }
7332 AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
7333 return VERR_INVALID_PARAMETER;
7334}
7335
7336
7337/**
7338 * Get what to do after this operation.
7339 *
7340 * @returns SSMAFTER enum value.
7341 * @param pSSM SSM operation handle.
7342 */
7343VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
7344{
7345 return pSSM->enmAfter;
7346}
7347
7348
7349/**
7350 * Get the current unit byte offset (uncompressed).
7351 *
7352 * @returns The offset. UINT64_MAX if called at a wrong time.
7353 * @param pSSM SSM operation handle.
7354 */
7355VMMR3DECL(uint64_t) SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM)
7356{
7357 AssertMsgFailed(("/** @todo this isn't correct any longer. */"));
7358 return pSSM->offUnit;
7359}
7360
7361
7362/**
7363 * Asynchronously cancels the current SSM operation ASAP.
7364 *
7365 * @returns VBox status code.
7366 * @retval VINF_SUCCESS on success.
7367 * @retval VERR_SSM_NO_PENDING_OPERATION if nothing around that can be
7368 * cancelled.
7369 * @retval VERR_SSM_ALREADY_CANCELLED if the operation as already been
7370 * cancelled.
7371 *
7372 * @param pVM The VM handle.
7373 *
7374 * @thread Any.
7375 */
7376VMMR3DECL(int) SSMR3Cancel(PVM pVM)
7377{
7378 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
7379
7380 int rc = RTCritSectEnter(&pVM->ssm.s.CancelCritSect);
7381 AssertRCReturn(rc, rc);
7382
7383 PSSMHANDLE pSSM = pVM->ssm.s.pSSM;
7384 if (pSSM)
7385 {
7386 uint32_t u32Old;
7387 if (ASMAtomicCmpXchgExU32(&pSSM->fCancelled, SSMHANDLE_CANCELLED, SSMHANDLE_OK, &u32Old))
7388 {
7389 LogRel(("SSM: Cancelled pending operation\n"));
7390 rc = VINF_SUCCESS;
7391 }
7392 else if (u32Old == SSMHANDLE_CANCELLED)
7393 rc = VERR_SSM_ALREADY_CANCELLED;
7394 else
7395 {
7396 AssertLogRelMsgFailed(("fCancelled=%RX32 enmOp=%d\n", u32Old, pSSM->enmOp));
7397 rc = VERR_INTERNAL_ERROR_2;
7398 }
7399 }
7400 else
7401 rc = VERR_SSM_NO_PENDING_OPERATION;
7402
7403 RTCritSectLeave(&pVM->ssm.s.CancelCritSect);
7404 return rc;
7405}
7406
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