VirtualBox

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

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

SSM,VMM,Devices,Main,VBoxBFE: Live snapshot/migration SSM API adjustments.

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