VirtualBox

source: vbox/trunk/src/VBox/VMM/SSM-new.cpp@ 21985

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

SSM: fixed bug in the I/o thread write loop causing truncated files.

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