VirtualBox

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

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

SSM: Save the build type and host os+arch, feed the strings from the makefile.

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