VirtualBox

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

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

SSM: Added the read ahead thread.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 206.5 KB
Line 
1/* $Id: SSM-new.cpp 21900 2009-07-30 17:31:36Z 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 * (SSMFILEUNITHDR) 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 SSMFILEUNITHDR
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} SSMFILEUNITHDR;
622AssertCompileMemberOffset(SSMFILEUNITHDR, szName, 44);
623AssertCompileMemberSize(SSMFILEUNITHDR, szMagic, sizeof(SSMFILEUNITHDR_MAGIC));
624AssertCompileMemberSize(SSMFILEUNITHDR, szMagic, sizeof(SSMFILEUNITHDR_END));
625/** Pointer to SSMFILEUNITHDR. */
626typedef SSMFILEUNITHDR *PSSMFILEUNITHDR;
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 */
1365static int ssmR3StrmInit(PSSMSTRM pStrm, bool fChecksummed)
1366{
1367 /*
1368 * Init the common data members.
1369 */
1370 pStrm->fTerminating = false;
1371 pStrm->fNeedSeek = false;
1372 pStrm->rc = VINF_SUCCESS;
1373 pStrm->hIoThread = NIL_RTTHREAD;
1374 pStrm->offNeedSeekTo= UINT64_MAX;
1375
1376 pStrm->pHead = NULL;
1377 pStrm->pFree = NULL;
1378 pStrm->hEvtHead = NIL_RTSEMEVENT;
1379 pStrm->hEvtFree = NIL_RTSEMEVENT;
1380
1381 pStrm->pPending = NULL;
1382 pStrm->pCur = NULL;
1383 pStrm->offCurStream = 0;
1384 pStrm->off = 0;
1385 pStrm->fChecksummed = fChecksummed;
1386 pStrm->u32StreamCRC = fChecksummed ? RTCrc32Start() : 0;
1387 pStrm->offStreamCRC = 0;
1388
1389 /*
1390 * Allocate the buffers. Page align them in case that makes the kernel
1391 * and/or cpu happier in some way.
1392 */
1393 int rc = VINF_SUCCESS;
1394 for (unsigned i = 0; i < 4; i++)
1395 {
1396 PSSMSTRMBUF pBuf = (PSSMSTRMBUF)RTMemPageAllocZ(sizeof(*pBuf));
1397 if (!pBuf)
1398 {
1399 if (i > 2)
1400 {
1401 LogRel(("ssmR3StrmAllocBuffer: WARNING: Could only get %d stream buffers.\n", i));
1402 break;
1403 }
1404 LogRel(("ssmR3StrmAllocBuffer: Failed to allocate stream buffers. (i=%d)\n", i));
1405 return VERR_NO_MEMORY;
1406 }
1407
1408 /* link it */
1409 pBuf->pNext = pStrm->pFree;
1410 pStrm->pFree = pBuf;
1411 }
1412
1413 /*
1414 * Create the event semaphores.
1415 */
1416 rc = RTSemEventCreate(&pStrm->hEvtHead);
1417 if (RT_FAILURE(rc))
1418 return rc;
1419 rc = RTSemEventCreate(&pStrm->hEvtFree);
1420 if (RT_FAILURE(rc))
1421 return rc;
1422
1423 return VINF_SUCCESS;
1424}
1425
1426
1427/**
1428 * Destroys a list of buffers.
1429 *
1430 * @param pHead Pointer to the head.
1431 */
1432static void ssmR3StrmDestroyBufList(PSSMSTRMBUF pHead)
1433{
1434 while (pHead)
1435 {
1436 PSSMSTRMBUF pCur = pHead;
1437 pHead = pCur->pNext;
1438 pCur->pNext = NULL;
1439 RTMemPageFree(pCur);
1440 }
1441}
1442
1443
1444/**
1445 * Cleans up a stream after ssmR3StrmInit has been called (regardless of it
1446 * succeeded or not).
1447 *
1448 * @param pStrm The stream handle.
1449 */
1450static void ssmR3StrmDelete(PSSMSTRM pStrm)
1451{
1452 RTMemPageFree(pStrm->pCur);
1453 pStrm->pCur = NULL;
1454 ssmR3StrmDestroyBufList(pStrm->pHead);
1455 pStrm->pHead = NULL;
1456 ssmR3StrmDestroyBufList(pStrm->pPending);
1457 pStrm->pPending = NULL;
1458 ssmR3StrmDestroyBufList(pStrm->pFree);
1459 pStrm->pFree = NULL;
1460
1461 RTSemEventDestroy(pStrm->hEvtHead);
1462 pStrm->hEvtHead = NIL_RTSEMEVENT;
1463
1464 RTSemEventDestroy(pStrm->hEvtFree);
1465 pStrm->hEvtFree = NIL_RTSEMEVENT;
1466}
1467
1468
1469/**
1470 * Opens a file stream.
1471 *
1472 * @returns VBox status code.
1473 * @param pStrm The stream manager structure.
1474 * @param pszFilename The file to open or create.
1475 * @param fWrite Whether to open for writing or reading.
1476 * @param fChecksummed Whether the stream is to be checksummed while
1477 * written/read.
1478 */
1479static int ssmR3StrmOpenFile(PSSMSTRM pStrm, const char *pszFilename, bool fWrite, bool fChecksummed)
1480{
1481 int rc = ssmR3StrmInit(pStrm, fChecksummed);
1482 if (RT_SUCCESS(rc))
1483 {
1484 uint32_t fFlags = fWrite
1485 ? RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE
1486 : RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
1487 rc = RTFileOpen(&pStrm->hFile, pszFilename, fFlags);
1488 if (RT_SUCCESS(rc))
1489 {
1490 pStrm->fWrite = fWrite;
1491 return VINF_SUCCESS;
1492 }
1493 }
1494
1495 ssmR3StrmDelete(pStrm);
1496 pStrm->rc = rc;
1497 return rc;
1498}
1499
1500
1501/**
1502 * Raise an error condition on the stream.
1503 *
1504 * @returns true if we raised the error condition, false if the stream already
1505 * had an error condition set.
1506 *
1507 * @param pStrm The stream handle.
1508 * @param rc The VBox error status code.
1509 *
1510 * @thread Any.
1511 */
1512DECLINLINE(bool) ssmR3StrmSetError(PSSMSTRM pStrm, int rc)
1513{
1514 Assert(RT_FAILURE_NP(rc));
1515 return ASMAtomicCmpXchgS32(&pStrm->rc, rc, VINF_SUCCESS);
1516}
1517
1518
1519/**
1520 * Puts a buffer into the free list.
1521 *
1522 * @param pStrm The stream handle.
1523 * @param pBuf The buffer.
1524 *
1525 * @thread The consumer.
1526 */
1527static void ssmR3StrmPutFreeBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
1528{
1529 for (;;)
1530 {
1531 PSSMSTRMBUF pCurFreeHead = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pFree);
1532 ASMAtomicUoWritePtr((void * volatile *)&pBuf->pNext, pCurFreeHead);
1533 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pFree, pBuf, pCurFreeHead))
1534 {
1535 int rc = RTSemEventSignal(pStrm->hEvtFree);
1536 AssertRC(rc);
1537 return;
1538 }
1539 }
1540}
1541
1542
1543/**
1544 * Gets a free buffer, waits for one if necessary.
1545 *
1546 * @returns Pointer to the buffer on success. NULL if we're terminating.
1547 * @param pStrm The stream handle.
1548 *
1549 * @thread The producer.
1550 */
1551static PSSMSTRMBUF ssmR3StrmGetFreeBuf(PSSMSTRM pStrm)
1552{
1553 for (;;)
1554 {
1555 PSSMSTRMBUF pMine = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pFree);
1556 if (!pMine)
1557 {
1558 if (pStrm->fTerminating)
1559 return NULL;
1560 if (RT_FAILURE(pStrm->rc))
1561 return NULL;
1562 if ( pStrm->fWrite
1563 && pStrm->hIoThread == NIL_RTTHREAD)
1564 {
1565 int rc = ssmR3StrmWriteBuffers(pStrm);
1566 if (RT_FAILURE(rc))
1567 return NULL;
1568 }
1569 int rc = RTSemEventWaitNoResume(pStrm->hEvtFree, 30000);
1570 if ( rc == VERR_SEM_DESTROYED
1571 || pStrm->fTerminating)
1572 return NULL;
1573 continue;
1574 }
1575
1576 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pFree, pMine->pNext, pMine))
1577 {
1578 pMine->offStream = UINT64_MAX;
1579 pMine->cb = 0;
1580 pMine->pNext = NULL;
1581 pMine->fEndOfStream = false;
1582 return pMine;
1583 }
1584 }
1585}
1586
1587
1588/**
1589 * Puts a buffer onto the queue.
1590 *
1591 * @param pBuf The buffer.
1592 *
1593 * @thread The producer.
1594 */
1595static void ssmR3StrmPutBuf(PSSMSTRM pStrm, PSSMSTRMBUF pBuf)
1596{
1597 for (;;)
1598 {
1599 PSSMSTRMBUF pCurHead = (PSSMSTRMBUF)ASMAtomicUoReadPtr((void * volatile *)&pStrm->pHead);
1600 ASMAtomicUoWritePtr((void * volatile *)&pBuf->pNext, pCurHead);
1601 if (ASMAtomicCmpXchgPtr((void * volatile *)&pStrm->pHead, pBuf, pCurHead))
1602 {
1603 int rc = RTSemEventSignal(pStrm->hEvtHead);
1604 AssertRC(rc);
1605 return;
1606 }
1607 }
1608}
1609
1610
1611/**
1612 * Reverses the list.
1613 *
1614 * @returns The head of the reversed list.
1615 * @param pHead The head of the list to reverse.
1616 */
1617static PSSMSTRMBUF ssmR3StrmReverseList(PSSMSTRMBUF pHead)
1618{
1619 PSSMSTRMBUF pRevHead = NULL;
1620 while (pHead)
1621 {
1622 PSSMSTRMBUF pCur = pHead;
1623 pHead = pCur->pNext;
1624 pCur->pNext = pRevHead;
1625 pRevHead = pCur;
1626 }
1627 return pRevHead;
1628}
1629
1630
1631/**
1632 * Gets one buffer from the queue, will wait for one to become ready if
1633 * necessary.
1634 *
1635 * @returns Pointer to the buffer on success. NULL if we're terminating.
1636 * @param pBuf The buffer.
1637 *
1638 * @thread The consumer.
1639 */
1640static PSSMSTRMBUF ssmR3StrmGetBuf(PSSMSTRM pStrm)
1641{
1642 for (;;)
1643 {
1644 PSSMSTRMBUF pMine = pStrm->pPending;
1645 if (pMine)
1646 {
1647 pStrm->pPending = pMine->pNext;
1648 pMine->pNext = NULL;
1649 return pMine;
1650 }
1651
1652 pMine = (PSSMSTRMBUF)ASMAtomicXchgPtr((void * volatile *)&pStrm->pHead, NULL);
1653 if (pMine)
1654 pStrm->pPending = ssmR3StrmReverseList(pMine);
1655 else
1656 {
1657 if (pStrm->fTerminating)
1658 return NULL;
1659 if (RT_FAILURE(pStrm->rc))
1660 return NULL;
1661 if ( !pStrm->fWrite
1662 && pStrm->hIoThread == NIL_RTTHREAD)
1663 {
1664 int rc = ssmR3StrmReadMore(pStrm);
1665 if (RT_FAILURE(rc))
1666 return NULL;
1667 continue;
1668 }
1669
1670 int rc = RTSemEventWaitNoResume(pStrm->hEvtHead, 30000);
1671 if ( rc == VERR_SEM_DESTROYED
1672 || pStrm->fTerminating)
1673 return NULL;
1674 }
1675 }
1676}
1677
1678
1679/**
1680 * Flushes the current buffer (both write and read streams).
1681 *
1682 * @param pStrm The stream handle.
1683 */
1684static void ssmR3StrmFlushCurBuf(PSSMSTRM pStrm)
1685{
1686 if (pStrm->pCur)
1687 {
1688 PSSMSTRMBUF pBuf = pStrm->pCur;
1689 pStrm->pCur = NULL;
1690
1691 if (pStrm->fWrite)
1692 {
1693 uint32_t cb = pStrm->off;
1694 pBuf->cb = cb;
1695 pBuf->offStream = pStrm->offCurStream;
1696 if ( pStrm->fChecksummed
1697 && pStrm->offStreamCRC < cb)
1698 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
1699 &pBuf->abData[pStrm->offStreamCRC],
1700 cb - pStrm->offStreamCRC);
1701 pStrm->offCurStream += cb;
1702 pStrm->off = 0;
1703 pStrm->offStreamCRC = 0;
1704
1705 ssmR3StrmPutBuf(pStrm, pBuf);
1706 }
1707 else
1708 {
1709 uint32_t cb = pBuf->cb;
1710 if ( pStrm->fChecksummed
1711 && pStrm->offStreamCRC < cb)
1712 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC,
1713 &pBuf->abData[pStrm->offStreamCRC],
1714 cb - pStrm->offStreamCRC);
1715 pStrm->offCurStream += cb;
1716 pStrm->off = 0;
1717 pStrm->offStreamCRC = 0;
1718
1719 ssmR3StrmPutFreeBuf(pStrm, pBuf);
1720 }
1721 }
1722}
1723
1724
1725/**
1726 * Flush buffered data.
1727 *
1728 * @returns VBox status code.
1729 * @param pStrm The stream handle.
1730 *
1731 * @thread The producer thread.
1732 */
1733static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm)
1734{
1735 Assert(!pStrm->pCur);
1736 Assert(pStrm->fWrite);
1737
1738 /*
1739 * Just return if the stream has a pending error condition.
1740 */
1741 int rc = pStrm->rc;
1742 if (RT_FAILURE(rc))
1743 return rc;
1744
1745 /*
1746 * Grab the pending list and write it out.
1747 */
1748 PSSMSTRMBUF pHead = (PSSMSTRMBUF)ASMAtomicXchgPtr((void * volatile *)&pStrm->pHead, NULL);
1749 if (!pHead)
1750 return VINF_SUCCESS;
1751 pHead = ssmR3StrmReverseList(pHead);
1752
1753 while (pHead)
1754 {
1755 /* pop */
1756 PSSMSTRMBUF pCur = pHead;
1757 pHead = pCur->pNext;
1758
1759 /* flush */
1760 int rc = RTFileWriteAt(pStrm->hFile, pCur->offStream, &pCur->abData[0], pCur->cb, NULL);
1761 if ( RT_FAILURE(rc)
1762 && ssmR3StrmSetError(pStrm, rc))
1763 LogRel(("ssmR3StrmWriteBuffers: RTFileWriteAt failed with rc=%Rrc at offStream=%#llx\n", rc, pCur->offStream));
1764
1765 /* free it */
1766 ssmR3StrmPutFreeBuf(pStrm, pCur);
1767 }
1768
1769 return pStrm->rc;
1770}
1771
1772
1773/**
1774 * Closes the stream after first flushing any pending write.
1775 *
1776 * @returns VBox status code.
1777 * @param pStrm The stream handle.
1778 */
1779static int ssmR3StrmClose(PSSMSTRM pStrm)
1780{
1781 /*
1782 * Flush, terminate the I/O thread, and close the stream.
1783 */
1784 if (pStrm->fWrite)
1785 {
1786 ssmR3StrmFlushCurBuf(pStrm);
1787 if (pStrm->hIoThread == NIL_RTTHREAD)
1788 ssmR3StrmWriteBuffers(pStrm);
1789 }
1790
1791 if (pStrm->hIoThread != NIL_RTTHREAD)
1792 {
1793 ASMAtomicWriteBool(&pStrm->fTerminating, true);
1794 int rc2 = RTSemEventSignal(pStrm->fWrite ? pStrm->hEvtHead : pStrm->hEvtFree); AssertLogRelRC(rc2);
1795 int rc3 = RTThreadWait(pStrm->hIoThread, RT_INDEFINITE_WAIT, NULL); AssertLogRelRC(rc3);
1796 pStrm->hIoThread = NIL_RTTHREAD;
1797 }
1798
1799 int rc = RTFileClose(pStrm->hFile);
1800 if (RT_FAILURE(rc))
1801 ssmR3StrmSetError(pStrm, rc);
1802 pStrm->hFile = NIL_RTFILE;
1803
1804 rc = pStrm->rc;
1805 ssmR3StrmDelete(pStrm);
1806
1807 return rc;
1808}
1809
1810
1811/**
1812 * Stream output routine.
1813 *
1814 * @returns VBox status code.
1815 * @param pStrm The stream handle.
1816 * @param pvBuf What to write.
1817 * @param cbToWrite How much to write.
1818 *
1819 * @thread The producer in a write stream (never the I/O thread).
1820 */
1821static int ssmR3StrmWrite(PSSMSTRM pStrm, const void *pvBuf, size_t cbToWrite)
1822{
1823 AssertReturn(cbToWrite > 0, VINF_SUCCESS);
1824 Assert(pStrm->fWrite);
1825
1826 /*
1827 * Squeeze as much as possible into the current buffer.
1828 */
1829 PSSMSTRMBUF pBuf = pStrm->pCur;
1830 if (RT_LIKELY(pBuf))
1831 {
1832 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
1833 if (RT_LIKELY(cbLeft >= cbToWrite))
1834 {
1835 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbToWrite);
1836 pStrm->off += (uint32_t)cbToWrite;
1837 return VINF_SUCCESS;
1838 }
1839
1840 if (cbLeft > 0)
1841 {
1842 memcpy(&pBuf->abData[pStrm->off], pvBuf, cbLeft);
1843 pStrm->off += cbLeft;
1844 cbToWrite -= cbLeft;
1845 pvBuf = (uint8_t const *)pvBuf + cbLeft;
1846 }
1847 Assert(pStrm->off == RT_SIZEOFMEMB(SSMSTRMBUF, abData));
1848 }
1849
1850 /*
1851 * Need one or more new buffers.
1852 */
1853 do
1854 {
1855 /*
1856 * Flush the current buffer and replace it with a new one.
1857 */
1858 ssmR3StrmFlushCurBuf(pStrm);
1859 pBuf = ssmR3StrmGetFreeBuf(pStrm);
1860 if (!pBuf)
1861 break;
1862 pStrm->pCur = pBuf;
1863 Assert(pStrm->off == 0);
1864
1865 /*
1866 * Copy data to the buffer.
1867 */
1868 uint32_t cbCopy = RT_SIZEOFMEMB(SSMSTRMBUF, abData);
1869 if (cbCopy > cbToWrite)
1870 cbCopy = (uint32_t)cbToWrite;
1871 memcpy(&pBuf->abData[0], pvBuf, cbCopy);
1872 pStrm->off = cbCopy;
1873 cbToWrite -= cbCopy;
1874 pvBuf = (uint8_t const *)pvBuf + cbCopy;
1875 } while (cbToWrite > 0);
1876
1877 return pStrm->rc;
1878}
1879
1880
1881/**
1882 * Reserves space in the current buffer so the caller can write directly to the
1883 * buffer instead of doing double buffering.
1884 *
1885 * @returns VBox status code
1886 * @param pStrm The stream handle.
1887 * @param cb The amount of buffer space to reserve.
1888 * @param ppb Where to return the pointer.
1889 */
1890static int ssmR3StrmReserveWriteBufferSpace(PSSMSTRM pStrm, size_t cb, uint8_t **ppb)
1891{
1892 Assert(pStrm->fWrite);
1893 Assert(RT_SIZEOFMEMB(SSMSTRMBUF, abData) / 4 >= cb);
1894
1895 /*
1896 * Check if there is room in the current buffer, it not flush it.
1897 */
1898 PSSMSTRMBUF pBuf = pStrm->pCur;
1899 if (pBuf)
1900 {
1901 uint32_t cbLeft = RT_SIZEOFMEMB(SSMSTRMBUF, abData) - pStrm->off;
1902 if (cbLeft >= cb)
1903 {
1904 *ppb = &pBuf->abData[pStrm->off];
1905 return VINF_SUCCESS;
1906 }
1907
1908 ssmR3StrmFlushCurBuf(pStrm);
1909 }
1910
1911 /*
1912 * Get a fresh buffer and return a pointer into it.
1913 */
1914 pBuf = ssmR3StrmGetFreeBuf(pStrm);
1915 if (pBuf)
1916 {
1917 pStrm->pCur = pBuf;
1918 Assert(pStrm->off == 0);
1919 *ppb = &pBuf->abData[0];
1920 }
1921 else
1922 *ppb = NULL; /* make gcc happy. */
1923 return pStrm->rc;
1924}
1925
1926
1927/**
1928 * Commits buffer space reserved by ssmR3StrmReserveWriteBufferSpace.
1929 *
1930 * @returns VBox status code.
1931 * @param pStrm The stream handle.
1932 * @param cb The amount of buffer space to commit. This can be less
1933 * that what was reserved initially.
1934 */
1935static int ssmR3StrmCommitWriteBufferSpace(PSSMSTRM pStrm, size_t cb)
1936{
1937 Assert(pStrm->pCur);
1938 Assert(pStrm->off + cb <= RT_SIZEOFMEMB(SSMSTRMBUF, abData));
1939 pStrm->off += cb;
1940 return VINF_SUCCESS;
1941}
1942
1943
1944/**
1945 * Read more from the stream.
1946 *
1947 * @returns VBox status code. VERR_EOF gets translated into VINF_EOF.
1948 * @param pStrm The stream handle.
1949 *
1950 * @thread The I/O thread when we got one, otherwise the stream user.
1951 */
1952static int ssmR3StrmReadMore(PSSMSTRM pStrm)
1953{
1954 int rc;
1955 Log6(("ssmR3StrmReadMore:\n"));
1956
1957 /*
1958 * Undo seek done by ssmR3StrmPeekAt.
1959 */
1960 if (pStrm->fNeedSeek)
1961 {
1962 rc = RTFileSeek(pStrm->hFile, pStrm->offNeedSeekTo, RTFILE_SEEK_BEGIN, NULL);
1963 if (RT_FAILURE(rc))
1964 {
1965 if (ssmR3StrmSetError(pStrm, rc))
1966 LogRel(("ssmR3StrmReadMore: RTFileSeek(,%#llx,) failed with rc=%Rrc\n", pStrm->offNeedSeekTo, rc));
1967 return rc;
1968 }
1969 pStrm->fNeedSeek = false;
1970 pStrm->offNeedSeekTo = UINT64_MAX;
1971 }
1972
1973 /*
1974 * Get a free buffer and try fill it up.
1975 */
1976 PSSMSTRMBUF pBuf = ssmR3StrmGetFreeBuf(pStrm);
1977 if (!pBuf)
1978 return pStrm->rc;
1979
1980 pBuf->offStream = RTFileTell(pStrm->hFile);
1981 size_t cbRead = sizeof(pBuf->abData);
1982 rc = RTFileRead(pStrm->hFile, &pBuf->abData[0], cbRead, &cbRead);
1983 if ( RT_SUCCESS(rc)
1984 && cbRead > 0)
1985 {
1986 pBuf->cb = (uint32_t)cbRead;
1987 pBuf->fEndOfStream = false;
1988 Log6(("ssmR3StrmReadMore: %#010llx %#x\n", pBuf->offStream, pBuf->cb));
1989 ssmR3StrmPutBuf(pStrm, pBuf);
1990 }
1991 else if ( ( RT_SUCCESS_NP(rc)
1992 && cbRead == 0)
1993 || rc == VERR_EOF)
1994 {
1995 pBuf->cb = 0;
1996 pBuf->fEndOfStream = true;
1997 Log6(("ssmR3StrmReadMore: %#010llx 0 EOF!\n", pBuf->offStream));
1998 ssmR3StrmPutBuf(pStrm, pBuf);
1999 rc = VINF_EOF;
2000 }
2001 else
2002 {
2003 Log6(("ssmR3StrmReadMore: %#010llx rc=%Rrc!\n", pBuf->offStream, rc));
2004 if (ssmR3StrmSetError(pStrm, rc))
2005 LogRel(("ssmR3StrmReadMore: RTFileRead(,,%#x,) -> %Rrc at offset %#llx\n",
2006 sizeof(pBuf->abData), rc, pBuf->offStream));
2007 ssmR3StrmPutFreeBuf(pStrm, pBuf);
2008 }
2009 return rc;
2010}
2011
2012
2013/**
2014 * Stream input routine.
2015 *
2016 * @returns VBox status code.
2017 * @param pStrm The stream handle.
2018 * @param pvBuf Where to put what we read.
2019 * @param cbToRead How much to read.
2020 */
2021static int ssmR3StrmRead(PSSMSTRM pStrm, void *pvBuf, size_t cbToRead)
2022{
2023 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2024 Assert(!pStrm->fWrite);
2025
2026 /*
2027 * Read from the current buffer if we got one.
2028 */
2029 PSSMSTRMBUF pBuf = pStrm->pCur;
2030 if (RT_LIKELY(pBuf))
2031 {
2032 Assert(pStrm->off <= pBuf->cb);
2033 uint32_t cbLeft = pBuf->cb - pStrm->off;
2034 if (cbLeft >= cbToRead)
2035 {
2036 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbToRead);
2037 pStrm->off += (uint32_t)cbToRead;
2038 Assert(pStrm->off <= pBuf->cb);
2039 return VINF_SUCCESS;
2040 }
2041 if (cbLeft)
2042 {
2043 memcpy(pvBuf, &pBuf->abData[pStrm->off], cbLeft);
2044 pStrm->off += cbLeft;
2045 cbToRead -= cbLeft;
2046 pvBuf = (uint8_t *)pvBuf + cbLeft;
2047 }
2048 else if (pBuf->fEndOfStream)
2049 return VERR_EOF;
2050 Assert(pStrm->off == pBuf->cb);
2051 }
2052
2053 /*
2054 * Get more buffers from the stream.
2055 */
2056 int rc = VINF_SUCCESS;
2057 do
2058 {
2059 /*
2060 * Check for EOF first - never flush the EOF buffer.
2061 */
2062 if ( pBuf
2063 && pBuf->fEndOfStream)
2064 return VERR_EOF;
2065
2066 /*
2067 * Flush the current buffer and get the next one.
2068 */
2069 ssmR3StrmFlushCurBuf(pStrm);
2070 PSSMSTRMBUF pBuf = ssmR3StrmGetBuf(pStrm);
2071 if (!pBuf)
2072 {
2073 rc = pStrm->rc;
2074 break;
2075 }
2076 pStrm->pCur = pBuf;
2077 Assert(pStrm->off == 0);
2078 Assert(pStrm->offCurStream == pBuf->offStream);
2079 if (!pBuf->cb)
2080 {
2081 Assert(pBuf->fEndOfStream);
2082 return VERR_EOF;
2083 }
2084
2085 /*
2086 * Read data from the buffer.
2087 */
2088 uint32_t cbCopy = pBuf->cb;
2089 if (cbCopy > cbToRead)
2090 cbCopy = (uint32_t)cbToRead;
2091 memcpy(pvBuf, &pBuf->abData[0], cbCopy);
2092 pStrm->off = cbCopy;
2093 cbToRead -= cbCopy;
2094 pvBuf = (uint8_t *)pvBuf + cbCopy;
2095 Assert(!pStrm->pCur || pStrm->off <= pStrm->pCur->cb);
2096 } while (cbToRead > 0);
2097
2098 return rc;
2099}
2100
2101
2102/**
2103 * Reads data from the stream but instead of copying it to some output buffer
2104 * the caller gets a pointer to into the current stream buffer.
2105 *
2106 * The returned pointer becomes invalid after the next stream operation!
2107 *
2108 * @returns Pointer to the read data residing in the stream buffer. NULL is
2109 * returned if the request amount of data isn't available in the
2110 * buffer. The caller must fall back on ssmR3StrmRead when this
2111 * happens.
2112 *
2113 * @param pStrm The stream handle.
2114 * @param cbToRead The number of bytes to tread.
2115 */
2116static uint8_t const *ssmR3StrmReadDirect(PSSMSTRM pStrm, size_t cbToRead)
2117{
2118 AssertReturn(cbToRead > 0, VINF_SUCCESS);
2119 Assert(!pStrm->fWrite);
2120
2121 /*
2122 * Too lazy to fetch more data for the odd case that we're
2123 * exactly at the boundrary between two buffers.
2124 */
2125 PSSMSTRMBUF pBuf = pStrm->pCur;
2126 if (RT_LIKELY(pBuf))
2127 {
2128 Assert(pStrm->off <= pBuf->cb);
2129 uint32_t cbLeft = pBuf->cb - pStrm->off;
2130 if (cbLeft >= cbToRead)
2131 {
2132 uint8_t const *pb = &pBuf->abData[pStrm->off];
2133 pStrm->off += (uint32_t)cbToRead;
2134 Assert(pStrm->off <= pBuf->cb);
2135 return pb;
2136 }
2137 }
2138 return NULL;
2139}
2140
2141
2142/**
2143 * Tell current stream position.
2144 *
2145 * @returns stream position.
2146 * @param pStrm The stream handle.
2147 */
2148static uint64_t ssmR3StrmTell(PSSMSTRM pStrm)
2149{
2150 return pStrm->offCurStream + pStrm->off;
2151}
2152
2153
2154/**
2155 * Gets the intermediate stream CRC up to the current position.
2156 *
2157 * @returns CRC.
2158 * @param pStrm The stream handle.
2159 */
2160static uint32_t ssmR3StrmCurCRC(PSSMSTRM pStrm)
2161{
2162 if (!pStrm->fChecksummed)
2163 return 0;
2164 if (pStrm->offStreamCRC < pStrm->off)
2165 {
2166 PSSMSTRMBUF pBuf = pStrm->pCur; Assert(pBuf);
2167 pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC, &pBuf->abData[pStrm->offStreamCRC], pStrm->off - pStrm->offStreamCRC);
2168//if (pStrm->offStreamCRC == 0 && pStrm->off == 0x40)
2169// LogAlways(("ssmR3StrmCurCRC: %08x\n%.64Rhxd\n", pStrm->u32StreamCRC, pBuf->abData));
2170 pStrm->offStreamCRC = pStrm->off;
2171 }
2172 else
2173 Assert(pStrm->offStreamCRC == pStrm->off);
2174 return pStrm->u32StreamCRC;
2175}
2176
2177
2178/**
2179 * Gets the final stream CRC up to the current position.
2180 *
2181 * @returns CRC.
2182 * @param pStrm The stream handle.
2183 */
2184static uint32_t ssmR3StrmFinalCRC(PSSMSTRM pStrm)
2185{
2186 if (!pStrm->fChecksummed)
2187 return 0;
2188 return RTCrc32Finish(ssmR3StrmCurCRC(pStrm));
2189}
2190
2191
2192/**
2193 * Disables checksumming of the stream.
2194 *
2195 * @param pStrm The stream handle.
2196 */
2197static void ssmR3StrmDisableChecksumming(PSSMSTRM pStrm)
2198{
2199 pStrm->fChecksummed = false;
2200}
2201
2202
2203/**
2204 * Used by SSMR3Seek to position the stream at the new unit.
2205 *
2206 * @returns VBox stutus code.
2207 * @param pStrm The strem handle.
2208 * @param off The seek offset.
2209 * @param uMethod The seek method.
2210 * @param u32CurCRC The current CRC at the seek position.
2211 */
2212static int ssmR3StrmSeek(PSSMSTRM pStrm, int64_t off, uint32_t uMethod, uint32_t u32CurCRC)
2213{
2214 AssertReturn(!pStrm->fWrite, VERR_NOT_SUPPORTED);
2215 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
2216
2217 uint64_t offStream;
2218 int rc = RTFileSeek(pStrm->hFile, off, uMethod, &offStream);
2219 if (RT_SUCCESS(rc))
2220 {
2221 pStrm->fNeedSeek = false;
2222 pStrm->offNeedSeekTo= UINT64_MAX;
2223 pStrm->offCurStream = offStream;
2224 pStrm->off = 0;
2225 pStrm->offStreamCRC = 0;
2226 if (pStrm->fChecksummed)
2227 pStrm->u32StreamCRC = u32CurCRC;
2228 if (pStrm->pCur)
2229 {
2230 ssmR3StrmPutFreeBuf(pStrm, pStrm->pCur);
2231 pStrm->pCur = NULL;
2232 }
2233 }
2234 return rc;
2235}
2236
2237
2238/**
2239 * Skip some bytes in the stream.
2240 *
2241 * This is only used if someone didn't read all of their data in the V1 format,
2242 * so don't bother making this very efficient yet.
2243 *
2244 * @returns VBox status code.
2245 * @param pStrm The stream handle.
2246 * @param offDst The destination offset.
2247 */
2248static int ssmR3StrmSkipTo(PSSMSTRM pStrm, uint64_t offDst)
2249{
2250 /* dead simple - lazy bird! */
2251 for (;;)
2252 {
2253 uint64_t offCur = ssmR3StrmTell(pStrm);
2254 AssertReturn(offCur <= offDst, VERR_INTERNAL_ERROR_4);
2255 if (offCur == offDst)
2256 return VINF_SUCCESS;
2257
2258 uint8_t abBuf[4096];
2259 size_t cbToRead = RT_MIN(sizeof(abBuf), offDst - offCur);
2260 int rc = ssmR3StrmRead(pStrm, abBuf, cbToRead);
2261 if (RT_FAILURE(rc))
2262 return rc;
2263 }
2264}
2265
2266
2267/**
2268 * Get the size of the file.
2269 *
2270 * This does not work for non-file streams!
2271 *
2272 * @returns The file size, or UINT64_MAX if not a file stream.
2273 * @param pStrm The stream handle.
2274 */
2275static uint64_t ssmR3StrmGetSize(PSSMSTRM pStrm)
2276{
2277 uint64_t cbFile;
2278 int rc = RTFileGetSize(pStrm->hFile, &cbFile);
2279 AssertLogRelRCReturn(rc, UINT64_MAX);
2280 return cbFile;
2281}
2282
2283
2284/***
2285 * Tests if the stream is a file stream or not.
2286 *
2287 * @returns true / false.
2288 * @param pStrm The stream handle.
2289 */
2290static bool ssmR3StrmIsFile(PSSMSTRM pStrm)
2291{
2292 return pStrm->hFile != NIL_RTFILE;
2293}
2294
2295
2296/**
2297 * Peeks at data in a file stream without buffering anything (or upsetting
2298 * the buffering for that matter).
2299 *
2300 * @returns VBox status code.
2301 * @param pStrm The stream handle
2302 * @param off The offset to start peeking at. Use a negative offset to
2303 * peek at something relative to the end of the file.
2304 * @param pvBuf Output buffer.
2305 * @param cbToRead How much to read.
2306 * @param poff Where to optionally store the position. Useful when
2307 * using a negative off.
2308 *
2309 * @remarks Failures occuring while peeking will not be raised on the stream.
2310 */
2311static int ssmR3StrmPeekAt(PSSMSTRM pStrm, RTFOFF off, void *pvBuf, size_t cbToRead, uint64_t *poff)
2312{
2313 AssertReturn(!pStrm->fWrite && pStrm->hFile != NIL_RTFILE, VERR_NOT_SUPPORTED);
2314 AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
2315
2316 if (!pStrm->fNeedSeek)
2317 {
2318 pStrm->fNeedSeek = true;
2319 pStrm->offNeedSeekTo = pStrm->offCurStream + (pStrm->pCur ? pStrm->pCur->cb : 0);
2320 }
2321
2322 int rc = RTFileSeek(pStrm->hFile, off, off >= 0 ? RTFILE_SEEK_BEGIN : RTFILE_SEEK_END, poff);
2323 if (RT_SUCCESS(rc))
2324 rc = RTFileRead(pStrm->hFile, pvBuf, cbToRead, NULL);
2325
2326 return rc;
2327}
2328
2329
2330/**
2331 * The I/O thread.
2332 *
2333 * @returns VINF_SUCCESS (ignored).
2334 * @param hSelf The thread handle.
2335 * @param pvStrm The stream handle.
2336 */
2337static DECLCALLBACK(int) ssmR3StrmIoThread(RTTHREAD hSelf, void *pvStrm)
2338{
2339 PSSMSTRM pStrm = (PSSMSTRM)pvStrm;
2340 ASMAtomicWriteHandle(&pStrm->hIoThread, hSelf); /* paranoia */
2341
2342 Log(("ssmR3StrmIoThread: starts working\n"));
2343 if (pStrm->fWrite)
2344 {
2345 /*
2346 * Write until error or terminated.
2347 */
2348 for (;;)
2349 {
2350
2351 }
2352 }
2353 else
2354 {
2355 /*
2356 * Read until end of file, error or termination.
2357 */
2358 for (;;)
2359 {
2360 if (ASMAtomicReadBool(&pStrm->fTerminating))
2361 {
2362 Log(("ssmR3StrmIoThread: quitting reading because of pending termination.\n"));
2363 break;
2364 }
2365
2366 int rc = ssmR3StrmReadMore(pStrm);
2367 if ( RT_FAILURE(rc)
2368 || rc == VINF_EOF)
2369 {
2370 Log(("ssmR3StrmIoThread: quitting reading with rc=%Rrc\n", rc));
2371 break;
2372 }
2373 if (RT_FAILURE(pStrm->rc))
2374 {
2375 Log(("ssmR3StrmIoThread: quitting reading with stream rc=%Rrc\n", pStrm->rc));
2376 break;
2377 }
2378 }
2379 }
2380
2381 return VINF_SUCCESS;
2382}
2383
2384
2385/**
2386 * Starts the I/O thread for the specified stream.
2387 *
2388 * @param pStrm The stream handle.
2389 */
2390static void ssmR3StrmStartIoThread(PSSMSTRM pStrm)
2391{
2392 Assert(pStrm->hIoThread == NIL_RTTHREAD);
2393
2394 RTTHREAD hThread;
2395 int rc = RTThreadCreate(&hThread, ssmR3StrmIoThread, pStrm, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SSM-IO");
2396 AssertRCReturnVoid(rc);
2397 ASMAtomicWriteHandle(&pStrm->hIoThread, hThread); /* paranoia */
2398}
2399
2400
2401/**
2402 * Works the progress calculation.
2403 *
2404 * @param pSSM The SSM handle.
2405 * @param cbAdvance Number of bytes to advance
2406 */
2407static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
2408{
2409 /* Can't advance it beyond the estimated end of the unit. */
2410 uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
2411 if (cbAdvance > cbLeft)
2412 cbAdvance = cbLeft;
2413 pSSM->offEst += cbAdvance;
2414
2415 /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
2416 while ( pSSM->offEst >= pSSM->offEstProgress
2417 && pSSM->uPercent <= 100-pSSM->uPercentDone)
2418 {
2419 if (pSSM->pfnProgress)
2420 pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
2421 pSSM->uPercent++;
2422 pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal
2423 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
2424 }
2425}
2426
2427
2428/**
2429 * Writes the directory.
2430 *
2431 * @returns VBox status code.
2432 * @param pVM The VM handle.
2433 * @param pSSM The SSM handle.
2434 * @param pcEntries Where to return the number of directory entries.
2435 */
2436static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries)
2437{
2438 /*
2439 * Grab some temporary memory for the dictionary.
2440 */
2441 size_t cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pVM->ssm.s.cUnits]);
2442 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
2443 if (!pDir)
2444 {
2445 LogRel(("ssmR3WriteDirectory: failed to allocate %zu bytes!\n", cbDir));
2446 return VERR_NO_TMP_MEMORY;
2447 }
2448
2449 /*
2450 * Initialize it.
2451 */
2452 memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic));
2453 pDir->u32CRC = 0;
2454 pDir->cEntries = 0;
2455
2456 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2457 if (pUnit->offStream != RTFOFF_MIN)
2458 {
2459 PSSMFILEDIRENTRY pEntry = &pDir->aEntries[pDir->cEntries++];
2460 Assert(pDir->cEntries <= pVM->ssm.s.cUnits);
2461 pEntry->off = pUnit->offStream;
2462 pEntry->u32Instance = pUnit->u32Instance;
2463 pEntry->u32NameCRC = RTCrc32(pUnit->szName, pUnit->cchName);
2464 }
2465
2466 /*
2467 * Calculate the actual size and CRC-32, then write the directory
2468 * out to the stream.
2469 */
2470 *pcEntries = pDir->cEntries;
2471 cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pDir->cEntries]);
2472 pDir->u32CRC = RTCrc32(pDir, cbDir);
2473 int rc = ssmR3StrmWrite(&pSSM->Strm, pDir, cbDir);
2474 RTMemTmpFree(pDir);
2475 return rc;
2476}
2477
2478
2479/**
2480 * Start VM save operation.
2481 *
2482 * @returns VBox status.
2483 *
2484 * @param pVM The VM handle.
2485 * @param pszFilename Name of the file to save the state in.
2486 * @param enmAfter What is planned after a successful save operation.
2487 * @param pfnProgress Progress callback. Optional.
2488 * @param pvUser User argument for the progress callback.
2489 *
2490 * @thread EMT
2491 */
2492VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
2493{
2494 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
2495 VM_ASSERT_EMT(pVM);
2496
2497 /*
2498 * Validate input.
2499 */
2500 if ( enmAfter != SSMAFTER_DESTROY
2501 && enmAfter != SSMAFTER_CONTINUE)
2502 {
2503 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
2504 return VERR_INVALID_PARAMETER;
2505 }
2506
2507 /*
2508 * Create the handle and try open the file.
2509 *
2510 * Note that there might be quite some work to do after executing the saving,
2511 * so we reserve 20% for the 'Done' period. The checksumming and closing of
2512 * the saved state file might take a long time.
2513 */
2514 SSMHANDLE Handle;
2515 RT_ZERO(Handle);
2516 Handle.pVM = pVM;
2517 Handle.enmOp = SSMSTATE_INVALID;
2518 Handle.enmAfter = enmAfter;
2519 Handle.rc = VINF_SUCCESS;
2520 Handle.cbUnitLeftV1 = 0;
2521 Handle.offUnit = UINT64_MAX;
2522 Handle.pfnProgress = pfnProgress;
2523 Handle.pvUser = pvUser;
2524 Handle.uPercent = 0;
2525 Handle.offEstProgress = 0;
2526 Handle.cbEstTotal = 0;
2527 Handle.offEst = 0;
2528 Handle.offEstUnitEnd = 0;
2529 Handle.uPercentPrepare = 20;
2530 Handle.uPercentDone = 2;
2531 Handle.u.Write.offDataBuffer = 0;
2532
2533 int rc = ssmR3StrmOpenFile(&Handle.Strm, pszFilename, true /*fWrite*/, true /*fChecksummed*/);
2534 if (RT_FAILURE(rc))
2535 {
2536 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));
2537 return rc;
2538 }
2539
2540 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
2541
2542 /*
2543 * Write header.
2544 */
2545 union
2546 {
2547 SSMFILEHDR FileHdr;
2548 SSMFILEUNITHDR UnitHdr;
2549 SSMFILEFTR Footer;
2550 } u;
2551
2552 memcpy(&u.FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(u.FileHdr.szMagic));
2553 u.FileHdr.u16VerMajor = VBOX_VERSION_MAJOR;
2554 u.FileHdr.u16VerMinor = VBOX_VERSION_MINOR;
2555 u.FileHdr.u32VerBuild = VBOX_VERSION_BUILD;
2556 u.FileHdr.u32SvnRev = VMMGetSvnRev(),
2557 u.FileHdr.cHostBits = HC_ARCH_BITS;
2558 u.FileHdr.cbGCPhys = sizeof(RTGCPHYS);
2559 u.FileHdr.cbGCPtr = sizeof(RTGCPTR);
2560 u.FileHdr.u8Reserved = 0;
2561 u.FileHdr.cUnits = pVM->ssm.s.cUnits;
2562 u.FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32;
2563 u.FileHdr.cbMaxDecompr = RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer);
2564 u.FileHdr.u32CRC = 0;
2565 u.FileHdr.u32CRC = RTCrc32(&u.FileHdr, sizeof(u.FileHdr));
2566 rc = ssmR3StrmWrite(&Handle.Strm, &u.FileHdr, sizeof(u.FileHdr));
2567 if (RT_SUCCESS(rc))
2568 {
2569 /*
2570 * Clear the per unit flags and offsets.
2571 */
2572 PSSMUNIT pUnit;
2573 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2574 {
2575 pUnit->fCalled = false;
2576 pUnit->offStream = RTFOFF_MIN;
2577 }
2578
2579 /*
2580 * Do the prepare run.
2581 */
2582 Handle.rc = VINF_SUCCESS;
2583 Handle.enmOp = SSMSTATE_SAVE_PREP;
2584 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2585 {
2586 if (pUnit->u.Common.pfnSavePrep)
2587 {
2588 switch (pUnit->enmType)
2589 {
2590 case SSMUNITTYPE_DEV:
2591 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle);
2592 break;
2593 case SSMUNITTYPE_DRV:
2594 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle);
2595 break;
2596 case SSMUNITTYPE_INTERNAL:
2597 rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle);
2598 break;
2599 case SSMUNITTYPE_EXTERNAL:
2600 rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser);
2601 break;
2602 }
2603 pUnit->fCalled = true;
2604 if (RT_FAILURE(rc))
2605 {
2606 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
2607 break;
2608 }
2609 }
2610
2611 Handle.cbEstTotal += pUnit->cbGuess;
2612 }
2613
2614 /* Progress. */
2615 if (pfnProgress)
2616 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
2617 Handle.uPercent = Handle.uPercentPrepare;
2618
2619 /*
2620 * Do the execute run.
2621 */
2622 if (RT_SUCCESS(rc))
2623 {
2624 Handle.enmOp = SSMSTATE_SAVE_EXEC;
2625 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2626 {
2627 /*
2628 * Estimate.
2629 */
2630 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
2631 Handle.offEstUnitEnd += pUnit->cbGuess;
2632
2633 /*
2634 * Does this unit have a callback? If, not skip it.
2635 */
2636 if (!pUnit->u.Common.pfnSaveExec)
2637 {
2638 pUnit->fCalled = true;
2639 continue;
2640 }
2641 pUnit->offStream = ssmR3StrmTell(&Handle.Strm);
2642
2643 /*
2644 * Write data unit header
2645 */
2646 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(u.UnitHdr.szMagic));
2647 u.UnitHdr.offStream = pUnit->offStream;
2648 u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm);
2649 u.UnitHdr.u32CRC = 0;
2650 u.UnitHdr.u32Version = pUnit->u32Version;
2651 u.UnitHdr.u32Instance = pUnit->u32Instance;
2652 u.UnitHdr.u32Phase = SSM_PHASE_FINAL;
2653 u.UnitHdr.fFlags = 0;
2654 u.UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
2655 memcpy(&u.UnitHdr.szName[0], &pUnit->szName[0], u.UnitHdr.cbName);
2656 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[u.UnitHdr.cbName]));
2657 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
2658 u.UnitHdr.offStream, u.UnitHdr.szName, u.UnitHdr.u32Instance, u.UnitHdr.u32Phase, u.UnitHdr.u32Version));
2659 rc = ssmR3StrmWrite(&Handle.Strm, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[u.UnitHdr.cbName]));
2660 if (RT_SUCCESS(rc))
2661 {
2662 /*
2663 * Call the execute handler.
2664 */
2665 ssmR3DataWriteBegin(&Handle);
2666 switch (pUnit->enmType)
2667 {
2668 case SSMUNITTYPE_DEV:
2669 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle);
2670 break;
2671 case SSMUNITTYPE_DRV:
2672 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle);
2673 break;
2674 case SSMUNITTYPE_INTERNAL:
2675 rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle);
2676 break;
2677 case SSMUNITTYPE_EXTERNAL:
2678 pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser);
2679 rc = Handle.rc;
2680 break;
2681 }
2682 pUnit->fCalled = true;
2683 if (RT_SUCCESS(rc))
2684 rc = ssmR3DataFlushBuffer(&Handle); /* will return SSMHANDLE::rc if its set */
2685 if (RT_SUCCESS(rc))
2686 {
2687 /*
2688 * Write the termination record and flush the compression stream.
2689 */
2690 SSMRECTERM TermRec;
2691 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
2692 TermRec.cbRec = sizeof(TermRec) - 2;
2693 if (Handle.Strm.fChecksummed)
2694 {
2695 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
2696 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&Handle.Strm), &TermRec, 2));
2697 }
2698 else
2699 {
2700 TermRec.fFlags = 0;
2701 TermRec.u32StreamCRC = 0;
2702 }
2703 TermRec.cbUnit = Handle.offUnit + sizeof(TermRec);
2704 rc = ssmR3DataWriteRaw(&Handle, &TermRec, sizeof(TermRec));
2705 if (RT_SUCCESS(rc))
2706 rc = ssmR3DataWriteFinish(&Handle);
2707 if (RT_SUCCESS(rc))
2708 Handle.offUnit = UINT64_MAX;
2709 else
2710 {
2711 LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc));
2712 break;
2713 }
2714 }
2715 else
2716 {
2717 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
2718 break;
2719 }
2720 }
2721 if (RT_FAILURE(rc))
2722 {
2723 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
2724 break;
2725 }
2726 } /* for each unit */
2727
2728 /* finish the progress. */
2729 if (RT_SUCCESS(rc))
2730 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
2731 }
2732 /* (progress should be pending 99% now) */
2733 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
2734
2735 /*
2736 * Do the done run.
2737 */
2738 Handle.rc = rc;
2739 Handle.enmOp = SSMSTATE_SAVE_DONE;
2740 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2741 {
2742 if ( pUnit->u.Common.pfnSaveDone
2743 && ( pUnit->fCalled
2744 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
2745 {
2746 switch (pUnit->enmType)
2747 {
2748 case SSMUNITTYPE_DEV:
2749 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle);
2750 break;
2751 case SSMUNITTYPE_DRV:
2752 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle);
2753 break;
2754 case SSMUNITTYPE_INTERNAL:
2755 rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle);
2756 break;
2757 case SSMUNITTYPE_EXTERNAL:
2758 rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser);
2759 break;
2760 }
2761 if (RT_FAILURE(rc))
2762 {
2763 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
2764 if (RT_SUCCESS(Handle.rc))
2765 Handle.rc = rc;
2766 }
2767 }
2768 }
2769 rc = Handle.rc;
2770
2771 /*
2772 * Finalize the file if successfully saved.
2773 */
2774 if (RT_SUCCESS(rc))
2775 {
2776 /* Write the end unit. */
2777 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(u.UnitHdr.szMagic));
2778 u.UnitHdr.offStream = ssmR3StrmTell(&Handle.Strm);
2779 u.UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&Handle.Strm);
2780 u.UnitHdr.u32CRC = 0;
2781 u.UnitHdr.u32Version = 0;
2782 u.UnitHdr.u32Instance = 0;
2783 u.UnitHdr.u32Phase = SSM_PHASE_FINAL;
2784 u.UnitHdr.fFlags = 0;
2785 u.UnitHdr.cbName = 0;
2786 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]));
2787 Log(("SSM: Unit at %#9llx: END UNIT\n", u.UnitHdr.offStream));
2788 rc = ssmR3StrmWrite(&Handle.Strm, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]));
2789 if (RT_SUCCESS(rc))
2790 {
2791 /* Write the directory for the final units and then the footer. */
2792 rc = ssmR3WriteDirectory(pVM, &Handle, &u.Footer.cDirEntries);
2793 if (RT_SUCCESS(rc))
2794 {
2795 memcpy(u.Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(u.Footer.szMagic));
2796 u.Footer.offStream = ssmR3StrmTell(&Handle.Strm);
2797 u.Footer.u32StreamCRC = ssmR3StrmFinalCRC(&Handle.Strm);
2798 u.Footer.u32Reserved = 0;
2799 u.Footer.u32CRC = 0;
2800 u.Footer.u32CRC = RTCrc32(&u.Footer, sizeof(u.Footer));
2801 Log(("SSM: Footer at %#9llx: \n", u.Footer.offStream));
2802 rc = ssmR3StrmWrite(&Handle.Strm, &u.Footer, sizeof(u.Footer));
2803 if (RT_SUCCESS(rc))
2804 {
2805 rc = ssmR3StrmClose(&Handle.Strm);
2806 if (RT_SUCCESS(rc))
2807 {
2808 if (pfnProgress)
2809 pfnProgress(pVM, 100, pvUser);
2810 Log(("SSM: Successfully saved the vm state to '%s'.\n", pszFilename));
2811 return VINF_SUCCESS;
2812 }
2813 return rc;
2814 }
2815 }
2816 }
2817 LogRel(("SSM: Failed to finalize state file! rc=%Rrc\n", rc));
2818 }
2819 }
2820
2821 /*
2822 * Delete the file on failure.
2823 */
2824 ssmR3StrmClose(&Handle.Strm);
2825 int rc2 = RTFileDelete(pszFilename);
2826 AssertRC(rc2);
2827
2828 return rc;
2829}
2830
2831
2832/**
2833 * Calculate the checksum of a file portion.
2834 *
2835 * @returns VBox status.
2836 * @param pStrm The stream handle
2837 * @param off Where to start checksumming.
2838 * @param cb How much to checksum.
2839 * @param pu32CRC Where to store the calculated checksum.
2840 */
2841static int ssmR3CalcChecksum(PSSMSTRM pStrm, uint64_t off, uint64_t cb, uint32_t *pu32CRC)
2842{
2843 /*
2844 * Allocate a buffer.
2845 */
2846 const size_t cbBuf = _32K;
2847 void *pvBuf = RTMemTmpAlloc(cbBuf);
2848 if (!pvBuf)
2849 return VERR_NO_TMP_MEMORY;
2850
2851 /*
2852 * Loop reading and calculating CRC32.
2853 */
2854 int rc = VINF_SUCCESS;
2855 uint32_t u32CRC = RTCrc32Start();
2856 while (cb > 0)
2857 {
2858 /* read chunk */
2859 size_t cbToRead = cbBuf;
2860 if (cb < cbBuf)
2861 cbToRead = cb;
2862 rc = ssmR3StrmPeekAt(pStrm, off, pvBuf, cbToRead, NULL);
2863 if (RT_FAILURE(rc))
2864 {
2865 AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
2866 RTMemTmpFree(pvBuf);
2867 return rc;
2868 }
2869
2870 /* advance */
2871 cb -= cbToRead;
2872 off += cbToRead;
2873
2874 /* calc crc32. */
2875 u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
2876 }
2877 RTMemTmpFree(pvBuf);
2878
2879 /* store the calculated crc */
2880 u32CRC = RTCrc32Finish(u32CRC);
2881 Log(("SSM: u32CRC=0x%08x\n", u32CRC));
2882 *pu32CRC = u32CRC;
2883
2884 return VINF_SUCCESS;
2885}
2886
2887
2888/**
2889 * Validates the header information stored in the handle.
2890 *
2891 * @returns VBox status code.
2892 *
2893 * @param pSSM The handle.
2894 * @param fHaveHostBits Set if the host bits field is valid.
2895 * @param fHaveVersion Set if we have a version.
2896 */
2897static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
2898{
2899 Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
2900 Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
2901 Assert(pSSM->u.Read.uFmtVerMinor <= 2);
2902
2903 if (fHaveVersion)
2904 {
2905 if ( pSSM->u.Read.u16VerMajor == 0
2906 || pSSM->u.Read.u16VerMajor > 1000
2907 || pSSM->u.Read.u16VerMinor > 1000
2908 || pSSM->u.Read.u32VerBuild > _1M
2909 || pSSM->u.Read.u32SvnRev == 0
2910 || pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
2911 {
2912 LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
2913 pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
2914 return VERR_SSM_INTEGRITY_VBOX_VERSION;
2915 }
2916 }
2917 else
2918 AssertLogRelReturn( pSSM->u.Read.u16VerMajor == 0
2919 && pSSM->u.Read.u16VerMinor == 0
2920 && pSSM->u.Read.u32VerBuild == 0
2921 && pSSM->u.Read.u32SvnRev == 0,
2922 VERR_SSM_INTEGRITY_VBOX_VERSION);
2923
2924 if (fHaveHostBits)
2925 {
2926 if ( pSSM->u.Read.cHostBits != 32
2927 && pSSM->u.Read.cHostBits != 64)
2928 {
2929 LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
2930 return VERR_SSM_INTEGRITY_SIZES;
2931 }
2932 }
2933 else
2934 AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_SIZES);
2935
2936 if ( pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
2937 && pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
2938 {
2939 LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
2940 return VERR_SSM_INTEGRITY_SIZES;
2941 }
2942 if ( pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
2943 && pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
2944 {
2945 LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
2946 return VERR_SSM_INTEGRITY_SIZES;
2947 }
2948
2949 return VINF_SUCCESS;
2950}
2951
2952
2953/**
2954 * Reads the header, detects the format version and performs integrity
2955 * validations.
2956 *
2957 * @returns VBox status.
2958 * @param File File to validate.
2959 * The file position is undefined on return.
2960 * @param fChecksumIt Whether to checksum the file or not. This will
2961 * be ignored if it the stream isn't a file.
2962 * @param fChecksumOnRead Whether to validate the checksum while reading
2963 * the stream instead of up front. If not possible,
2964 * verify the checksum up front.
2965 * @param pHdr Where to store the file header.
2966 */
2967static int ssmR3HeaderAndValidate(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
2968{
2969 /*
2970 * Read and check the header magic.
2971 */
2972 union
2973 {
2974 SSMFILEHDR v2_0;
2975 SSMFILEHDRV12 v1_2;
2976 SSMFILEHDRV11 v1_1;
2977 } uHdr;
2978 int rc = ssmR3StrmRead(&pSSM->Strm, &uHdr, sizeof(uHdr.v2_0.szMagic));
2979 if (RT_FAILURE(rc))
2980 {
2981 LogRel(("SSM: Failed to read file magic header. rc=%Rrc\n", rc));
2982 return rc;
2983 }
2984 if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
2985 {
2986 Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
2987 return VERR_SSM_INTEGRITY_MAGIC;
2988 }
2989
2990 /*
2991 * Find the header size and read the rest.
2992 */
2993 static const struct
2994 {
2995 char szMagic[sizeof(SSMFILEHDR_MAGIC_V2_0)];
2996 size_t cbHdr;
2997 unsigned uFmtVerMajor;
2998 unsigned uFmtVerMinor;
2999 } s_aVers[] =
3000 {
3001 { SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR), 2, 0 },
3002 { SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDRV12), 1, 2 },
3003 { SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDRV11), 1, 1 },
3004 };
3005 int iVer = RT_ELEMENTS(s_aVers);
3006 while (iVer-- > 0)
3007 if (!memcmp(uHdr.v2_0.szMagic, s_aVers[iVer].szMagic, sizeof(uHdr.v2_0.szMagic)))
3008 break;
3009 if (iVer < 0)
3010 {
3011 Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
3012 return VERR_SSM_INTEGRITY_VERSION;
3013 }
3014 pSSM->u.Read.uFmtVerMajor = s_aVers[iVer].uFmtVerMajor;
3015 pSSM->u.Read.uFmtVerMinor = s_aVers[iVer].uFmtVerMinor;
3016 pSSM->u.Read.cbFileHdr = s_aVers[iVer].cbHdr;
3017
3018 rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)&uHdr + sizeof(uHdr.v2_0.szMagic), pSSM->u.Read.cbFileHdr - sizeof(uHdr.v2_0.szMagic));
3019 if (RT_FAILURE(rc))
3020 {
3021 LogRel(("SSM: Failed to read the file header. rc=%Rrc\n", rc));
3022 return rc;
3023 }
3024
3025 /*
3026 * Make version specific adjustments.
3027 */
3028 if (pSSM->u.Read.uFmtVerMajor >= 2)
3029 {
3030 /*
3031 * Version 2.0 and later.
3032 */
3033 bool fChecksummed;
3034 if (pSSM->u.Read.uFmtVerMinor == 0)
3035 {
3036 /* validate the header. */
3037 SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
3038 if (uHdr.v2_0.u8Reserved)
3039 {
3040 LogRel(("SSM: Reserved header field isn't zero: %02x\n", uHdr.v2_0.u8Reserved));
3041 return VERR_SSM_INTEGRITY;
3042 }
3043 if ((uHdr.v2_0.fFlags & ~SSMFILEHDR_FLAGS_STREAM_CRC32))
3044 {
3045 LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
3046 return VERR_SSM_INTEGRITY;
3047 }
3048 if ( uHdr.v2_0.cbMaxDecompr > sizeof(pSSM->u.Read.abDataBuffer)
3049 || uHdr.v2_0.cbMaxDecompr < _1K
3050 || (uHdr.v2_0.cbMaxDecompr & 0xff) != 0)
3051 {
3052 LogRel(("SSM: The cbMaxDecompr header field is out of range: %#x\n", uHdr.v2_0.cbMaxDecompr));
3053 return VERR_SSM_INTEGRITY;
3054 }
3055
3056 /* set the header info. */
3057 pSSM->u.Read.cHostBits = uHdr.v2_0.cHostBits;
3058 pSSM->u.Read.u16VerMajor = uHdr.v2_0.u16VerMajor;
3059 pSSM->u.Read.u16VerMinor = uHdr.v2_0.u16VerMinor;
3060 pSSM->u.Read.u32VerBuild = uHdr.v2_0.u32VerBuild;
3061 pSSM->u.Read.u32SvnRev = uHdr.v2_0.u32SvnRev;
3062 pSSM->u.Read.cbGCPhys = uHdr.v2_0.cbGCPhys;
3063 pSSM->u.Read.cbGCPtr = uHdr.v2_0.cbGCPtr;
3064 pSSM->u.Read.fFixedGCPtrSize = true;
3065 fChecksummed = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
3066 }
3067 else
3068 AssertFailedReturn(VERR_INTERNAL_ERROR);
3069
3070 /*
3071 * Read and validate the footer if it's a file.
3072 */
3073 if (ssmR3StrmIsFile(&pSSM->Strm))
3074 {
3075 SSMFILEFTR Footer;
3076 uint64_t offFooter;
3077 rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(SSMFILEFTR), &Footer, sizeof(Footer), &offFooter);
3078 AssertLogRelRCReturn(rc, rc);
3079 if (memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)))
3080 {
3081 LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(Footer.szMagic), &Footer.szMagic[0]));
3082 return VERR_SSM_INTEGRITY;
3083 }
3084 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
3085 if (Footer.offStream != offFooter)
3086 {
3087 LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
3088 return VERR_SSM_INTEGRITY;
3089 }
3090 if (Footer.u32Reserved)
3091 {
3092 LogRel(("SSM: Reserved footer field isn't zero: %08x\n", Footer.u32Reserved));
3093 return VERR_SSM_INTEGRITY;
3094 }
3095 if ( !fChecksummed
3096 && Footer.u32StreamCRC)
3097 {
3098 LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
3099 return VERR_SSM_INTEGRITY;
3100 }
3101
3102 pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
3103 pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
3104 }
3105 else
3106 {
3107 pSSM->u.Read.cbLoadFile = UINT64_MAX;
3108 pSSM->u.Read.u32LoadCRC = 0;
3109 }
3110
3111 /*
3112 * Validate the header info we've set in the handle.
3113 */
3114 rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
3115 if (RT_FAILURE(rc))
3116 return rc;
3117
3118 /*
3119 * Check the checksum if that's called for and possible.
3120 */
3121 if ( fChecksummed
3122 && fChecksumIt
3123 && !fChecksumOnRead
3124 && ssmR3StrmIsFile(&pSSM->Strm))
3125 {
3126 uint32_t u32CRC;
3127 rc = ssmR3CalcChecksum(&pSSM->Strm, 0, pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR), &u32CRC);
3128 if (RT_FAILURE(rc))
3129 return rc;
3130 if (u32CRC != pSSM->u.Read.u32LoadCRC)
3131 {
3132 LogRel(("SSM: Invalid CRC! Calculated %#010x, in footer %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
3133 return VERR_SSM_INTEGRITY_CRC;
3134 }
3135 }
3136 }
3137 else
3138 {
3139 /*
3140 * Version 1.x of the format.
3141 */
3142 bool fHaveHostBits = true;
3143 bool fHaveVersion = false;
3144 RTUUID MachineUuidFromHdr;
3145
3146 ssmR3StrmDisableChecksumming(&pSSM->Strm);
3147 if (pSSM->u.Read.uFmtVerMinor == 1)
3148 {
3149 pSSM->u.Read.cHostBits = 0; /* unknown */
3150 pSSM->u.Read.u16VerMajor = 0;
3151 pSSM->u.Read.u16VerMinor = 0;
3152 pSSM->u.Read.u32VerBuild = 0;
3153 pSSM->u.Read.u32SvnRev = 0;
3154 pSSM->u.Read.cbLoadFile = uHdr.v1_1.cbFile;
3155 pSSM->u.Read.u32LoadCRC = uHdr.v1_1.u32CRC;
3156 pSSM->u.Read.cbGCPhys = sizeof(RTGCPHYS);
3157 pSSM->u.Read.cbGCPtr = sizeof(RTGCPTR);
3158 pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
3159
3160 MachineUuidFromHdr = uHdr.v1_1.MachineUuid;
3161 fHaveHostBits = false;
3162 }
3163 else if (pSSM->u.Read.uFmtVerMinor == 2)
3164 {
3165 pSSM->u.Read.cHostBits = uHdr.v1_2.cHostBits;
3166 pSSM->u.Read.u16VerMajor = uHdr.v1_2.u16VerMajor;
3167 pSSM->u.Read.u16VerMinor = uHdr.v1_2.u16VerMinor;
3168 pSSM->u.Read.u32VerBuild = uHdr.v1_2.u32VerBuild;
3169 pSSM->u.Read.u32SvnRev = uHdr.v1_2.u32SvnRev;
3170 pSSM->u.Read.cbLoadFile = uHdr.v1_2.cbFile;
3171 pSSM->u.Read.u32LoadCRC = uHdr.v1_2.u32CRC;
3172 pSSM->u.Read.cbGCPhys = uHdr.v1_2.cbGCPhys;
3173 pSSM->u.Read.cbGCPtr = uHdr.v1_2.cbGCPtr;
3174 pSSM->u.Read.fFixedGCPtrSize = true;
3175
3176 MachineUuidFromHdr = uHdr.v1_2.MachineUuid;
3177 fHaveVersion = true;
3178 }
3179 else
3180 AssertFailedReturn(VERR_INTERNAL_ERROR);
3181
3182 /*
3183 * The MachineUuid must be NULL (was never used).
3184 */
3185 if (!RTUuidIsNull(&MachineUuidFromHdr))
3186 {
3187 LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
3188 return VERR_SMM_INTEGRITY_MACHINE;
3189 }
3190
3191 /*
3192 * Verify the file size.
3193 */
3194 uint64_t cbFile = ssmR3StrmGetSize(&pSSM->Strm);
3195 if (cbFile != pSSM->u.Read.cbLoadFile)
3196 {
3197 LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
3198 return VERR_SSM_INTEGRITY_SIZE;
3199 }
3200
3201 /*
3202 * Validate the header info we've set in the handle.
3203 */
3204 rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
3205 if (RT_FAILURE(rc))
3206 return rc;
3207
3208 /*
3209 * Verify the checksum if requested.
3210 *
3211 * Note! The checksum is not actually generated for the whole file,
3212 * this is of course a bug in the v1.x code that we cannot do
3213 * anything about.
3214 */
3215 if ( fChecksumIt
3216 || fChecksumOnRead)
3217 {
3218 uint32_t u32CRC;
3219 rc = ssmR3CalcChecksum(&pSSM->Strm,
3220 RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC),
3221 cbFile - pSSM->u.Read.cbFileHdr,
3222 &u32CRC);
3223 if (RT_FAILURE(rc))
3224 return rc;
3225 if (u32CRC != pSSM->u.Read.u32LoadCRC)
3226 {
3227 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
3228 return VERR_SSM_INTEGRITY_CRC;
3229 }
3230 }
3231 }
3232
3233 return VINF_SUCCESS;
3234}
3235
3236
3237/**
3238 * Open a saved state for reading.
3239 *
3240 * The file will be positioned at the first data unit upon successful return.
3241 *
3242 * @returns VBox status code.
3243 *
3244 * @param pVM The VM handle.
3245 * @param pszFilename The filename.
3246 * @param fChecksumIt Check the checksum for the entire file.
3247 * @param fChecksumOnRead Whether to validate the checksum while reading
3248 * the stream instead of up front. If not possible,
3249 * verify the checksum up front.
3250 * @param pSSM Pointer to the handle structure. This will be
3251 * completely initialized on success.
3252 */
3253static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead, PSSMHANDLE pSSM)
3254{
3255 /*
3256 * Initialize the handle.
3257 */
3258 pSSM->pVM = pVM;
3259 pSSM->enmOp = SSMSTATE_INVALID;
3260 pSSM->enmAfter = SSMAFTER_INVALID;
3261 pSSM->rc = VINF_SUCCESS;
3262 pSSM->cbUnitLeftV1 = 0;
3263 pSSM->offUnit = UINT64_MAX;
3264 pSSM->pfnProgress = NULL;
3265 pSSM->pvUser = NULL;
3266 pSSM->uPercent = 0;
3267 pSSM->offEstProgress = 0;
3268 pSSM->cbEstTotal = 0;
3269 pSSM->offEst = 0;
3270 pSSM->offEstUnitEnd = 0;
3271 pSSM->uPercentPrepare = 5;
3272 pSSM->uPercentDone = 2;
3273
3274 pSSM->u.Read.pZipDecompV1 = NULL;
3275 pSSM->u.Read.uFmtVerMajor = UINT32_MAX;
3276 pSSM->u.Read.uFmtVerMinor = UINT32_MAX;
3277 pSSM->u.Read.cbFileHdr = UINT32_MAX;
3278 pSSM->u.Read.cbGCPhys = UINT8_MAX;
3279 pSSM->u.Read.cbGCPtr = UINT8_MAX;
3280 pSSM->u.Read.fFixedGCPtrSize= false;
3281 pSSM->u.Read.u16VerMajor = UINT16_MAX;
3282 pSSM->u.Read.u16VerMinor = UINT16_MAX;
3283 pSSM->u.Read.u32VerBuild = UINT32_MAX;
3284 pSSM->u.Read.u32SvnRev = UINT32_MAX;
3285 pSSM->u.Read.cHostBits = UINT8_MAX;
3286 pSSM->u.Read.cbLoadFile = UINT64_MAX;
3287
3288 pSSM->u.Read.cbRecLeft = 0;
3289 pSSM->u.Read.cbDataBuffer = 0;
3290 pSSM->u.Read.offDataBuffer = 0;
3291 pSSM->u.Read.fEndOfData = 0;
3292 pSSM->u.Read.u8TypeAndFlags = 0;
3293
3294 /*
3295 * Try open and validate the file.
3296 */
3297 int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, false /*fWrite*/, fChecksumOnRead);
3298 if (RT_SUCCESS(rc))
3299 {
3300 rc = ssmR3HeaderAndValidate(pSSM, fChecksumIt, fChecksumOnRead);
3301 if (RT_SUCCESS(rc))
3302 return rc;
3303
3304 /* failure path */
3305 ssmR3StrmClose(&pSSM->Strm);
3306 }
3307 else
3308 Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n", pszFilename, rc));
3309 return rc;
3310}
3311
3312
3313/**
3314 * Find a data unit by name.
3315 *
3316 * @returns Pointer to the unit.
3317 * @returns NULL if not found.
3318 *
3319 * @param pVM VM handle.
3320 * @param pszName Data unit name.
3321 * @param u32Instance The data unit instance id.
3322 */
3323static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t u32Instance)
3324{
3325 size_t cchName = strlen(pszName);
3326 PSSMUNIT pUnit = pVM->ssm.s.pHead;
3327 while ( pUnit
3328 && ( pUnit->u32Instance != u32Instance
3329 || pUnit->cchName != cchName
3330 || memcmp(pUnit->szName, pszName, cchName)))
3331 pUnit = pUnit->pNext;
3332 return pUnit;
3333}
3334
3335
3336/**
3337 * Executes the loading of a V1.X file.
3338 *
3339 * @returns VBox status code.
3340 * @param pVM The VM handle.
3341 * @param pSSM The saved state handle.
3342 */
3343static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
3344{
3345 int rc;
3346 char *pszName = NULL;
3347 size_t cchName = 0;
3348 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
3349 for (;;)
3350 {
3351 /*
3352 * Save the current file position and read the data unit header.
3353 */
3354 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
3355 SSMFILEUNITHDRV1 UnitHdr;
3356 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName));
3357 if (RT_SUCCESS(rc))
3358 {
3359 /*
3360 * Check the magic and see if it's valid and whether it is a end header or not.
3361 */
3362 if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
3363 {
3364 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
3365 {
3366 Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
3367 /* Complete the progress bar (pending 99% afterwards). */
3368 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
3369 break;
3370 }
3371 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
3372 offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
3373 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
3374 break;
3375 }
3376
3377 /*
3378 * Read the name.
3379 * Adjust the name buffer first.
3380 */
3381 if (cchName < UnitHdr.cchName)
3382 {
3383 if (pszName)
3384 RTMemTmpFree(pszName);
3385 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
3386 pszName = (char *)RTMemTmpAlloc(cchName);
3387 }
3388 if (pszName)
3389 {
3390 rc = ssmR3StrmRead(&pSSM->Strm, pszName, UnitHdr.cchName);
3391 if (RT_SUCCESS(rc))
3392 {
3393 if (pszName[UnitHdr.cchName - 1])
3394 {
3395 LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
3396 rc = VERR_SSM_INTEGRITY;
3397 break;
3398 }
3399 Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
3400
3401 /*
3402 * Find the data unit in our internal table.
3403 */
3404 PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
3405 if (pUnit)
3406 {
3407 /*
3408 * Call the execute handler.
3409 */
3410 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
3411 pSSM->offUnit = 0;
3412 if (!pUnit->u.Common.pfnLoadExec)
3413 {
3414 LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
3415 rc = VERR_SSM_NO_LOAD_EXEC;
3416 break;
3417 }
3418 switch (pUnit->enmType)
3419 {
3420 case SSMUNITTYPE_DEV:
3421 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version);
3422 break;
3423 case SSMUNITTYPE_DRV:
3424 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version);
3425 break;
3426 case SSMUNITTYPE_INTERNAL:
3427 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version);
3428 break;
3429 case SSMUNITTYPE_EXTERNAL:
3430 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version);
3431 break;
3432 }
3433
3434 /*
3435 * Close the reader stream.
3436 */
3437 ssmR3DataReadFinishV1(pSSM);
3438
3439 pUnit->fCalled = true;
3440 if (RT_SUCCESS(rc))
3441 rc = pSSM->rc;
3442 if (RT_SUCCESS(rc))
3443 {
3444 /*
3445 * Now, we'll check the current position to see if all, or
3446 * more than all, the data was read.
3447 *
3448 * Note! Because of buffering / compression we'll only see the
3449 * really bad ones here.
3450 */
3451 uint64_t off = ssmR3StrmTell(&pSSM->Strm);
3452 int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
3453 if (i64Diff < 0)
3454 {
3455 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
3456 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
3457 ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
3458 }
3459 else if (i64Diff > 0)
3460 {
3461 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
3462 rc = VERR_SSM_INTEGRITY;
3463 break;
3464 }
3465
3466 pSSM->offUnit = UINT64_MAX;
3467 }
3468 else
3469 {
3470 LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
3471 pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
3472 rc = VERR_SSM_INTEGRITY;
3473 break;
3474 }
3475 }
3476 else
3477 {
3478 /*
3479 * SSM unit wasn't found - ignore this when loading for the debugger.
3480 */
3481 LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
3482 rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
3483 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
3484 break;
3485 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
3486 }
3487 }
3488 }
3489 else
3490 rc = VERR_NO_TMP_MEMORY;
3491 }
3492
3493 /*
3494 * I/O errors ends up here (yea, I know, very nice programming).
3495 */
3496 if (RT_FAILURE(rc))
3497 {
3498 LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
3499 break;
3500 }
3501 }
3502
3503 RTMemTmpFree(pszName);
3504 return rc;
3505}
3506
3507
3508/**
3509 * Executes the loading of a V2.X file.
3510 *
3511 * @returns VBox status code.
3512 * @param pVM The VM handle.
3513 * @param pSSM The saved state handle.
3514 */
3515static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
3516{
3517 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
3518 for (;;)
3519 {
3520 /*
3521 * Read the unit header and check its integrity.
3522 */
3523 uint64_t offUnit = ssmR3StrmTell(&pSSM->Strm);
3524 uint32_t u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
3525 SSMFILEUNITHDR UnitHdr;
3526 int rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName));
3527 if (RT_FAILURE(rc))
3528 return rc;
3529 if (RT_UNLIKELY( memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
3530 && memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic))))
3531 {
3532 LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
3533 offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
3534 return VERR_SSM_INTEGRITY_UNIT_MAGIC;
3535 }
3536 if (UnitHdr.cbName)
3537 {
3538 if (RT_UNLIKELY(UnitHdr.cbName > sizeof(UnitHdr.szName)))
3539 {
3540 LogRel(("SSM: Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
3541 offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)));
3542 return VERR_SSM_INTEGRITY;
3543 }
3544 rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr.szName[0], UnitHdr.cbName);
3545 if (RT_FAILURE(rc))
3546 return rc;
3547 if (RT_UNLIKELY(UnitHdr.szName[UnitHdr.cbName - 1]))
3548 {
3549 LogRel(("SSM: Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
3550 offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName));
3551 return VERR_SSM_INTEGRITY;
3552 }
3553 }
3554 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]),
3555 ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
3556 if (RT_UNLIKELY(UnitHdr.offStream != offUnit))
3557 {
3558 LogRel(("SSM: Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit));
3559 return VERR_SSM_INTEGRITY;
3560 }
3561 AssertLogRelMsgReturn(UnitHdr.u32CurStreamCRC == u32CurStreamCRC || !pSSM->Strm.fChecksummed,
3562 ("Unit at %#llx (%lld): Stream CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, UnitHdr.u32CurStreamCRC, u32CurStreamCRC), VERR_SSM_INTEGRITY);
3563 AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags), VERR_SSM_INTEGRITY);
3564 if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)))
3565 {
3566 AssertLogRelMsgReturn( UnitHdr.cbName == 0
3567 && UnitHdr.u32Instance == 0
3568 && UnitHdr.u32Version == 0
3569 && UnitHdr.u32Phase == SSM_PHASE_FINAL,
3570 ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
3571 VERR_SSM_INTEGRITY);
3572
3573 /*
3574 * Complete the progress bar (pending 99% afterwards) and RETURN.
3575 */
3576 Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
3577 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
3578 return VINF_SUCCESS;
3579 }
3580 AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
3581
3582 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
3583 offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version));
3584
3585 /*
3586 * Find the data unit in our internal table.
3587 */
3588 PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
3589 if (pUnit)
3590 {
3591 /*
3592 * Call the execute handler.
3593 */
3594 AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
3595 ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
3596 VERR_SSM_NO_LOAD_EXEC);
3597 ssmR3DataReadBeginV2(pSSM);
3598 switch (pUnit->enmType)
3599 {
3600 case SSMUNITTYPE_DEV:
3601 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version);
3602 break;
3603 case SSMUNITTYPE_DRV:
3604 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version);
3605 break;
3606 case SSMUNITTYPE_INTERNAL:
3607 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version);
3608 break;
3609 case SSMUNITTYPE_EXTERNAL:
3610 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version);
3611 break;
3612 }
3613 ssmR3DataReadFinishV2(pSSM);
3614 pUnit->fCalled = true;
3615 if (RT_SUCCESS(rc))
3616 rc = pSSM->rc;
3617 if (RT_SUCCESS(rc))
3618 pSSM->offUnit = UINT64_MAX;
3619 else
3620 {
3621 LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u): %Rrc\n",
3622 UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Phase, rc));
3623 return rc;
3624 }
3625 }
3626 else
3627 {
3628 /*
3629 * SSM unit wasn't found - ignore this when loading for the debugger.
3630 */
3631 LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
3632 //if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
3633 return VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
3634 /** @todo Read data unit to /dev/null. */
3635 }
3636 }
3637 /* won't get here */
3638}
3639
3640
3641
3642
3643/**
3644 * Load VM save operation.
3645 *
3646 * @returns VBox status.
3647 *
3648 * @param pVM The VM handle.
3649 * @param pszFilename Name of the file to save the state in.
3650 * @param enmAfter What is planned after a successful load operation.
3651 * Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
3652 * @param pfnProgress Progress callback. Optional.
3653 * @param pvUser User argument for the progress callback.
3654 *
3655 * @thread EMT
3656 */
3657VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
3658{
3659 LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
3660 VM_ASSERT_EMT(pVM);
3661
3662 /*
3663 * Validate input.
3664 */
3665 if ( enmAfter != SSMAFTER_RESUME
3666 && enmAfter != SSMAFTER_DEBUG_IT)
3667 {
3668 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
3669 return VERR_INVALID_PARAMETER;
3670 }
3671
3672 /*
3673 * Create the handle and open the file.
3674 */
3675 SSMHANDLE Handle;
3676 int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, &Handle);
3677 if (RT_SUCCESS(rc))
3678 {
3679 ssmR3StrmStartIoThread(&Handle.Strm);
3680
3681 Handle.enmAfter = enmAfter;
3682 Handle.pfnProgress = pfnProgress;
3683 Handle.pvUser = pvUser;
3684
3685 if (Handle.u.Read.u16VerMajor)
3686 LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
3687 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
3688 Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
3689 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
3690 else
3691 LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
3692 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
3693 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
3694
3695 if (pfnProgress)
3696 pfnProgress(pVM, Handle.uPercent, pvUser);
3697
3698 /*
3699 * Clear the per unit flags.
3700 */
3701 PSSMUNIT pUnit;
3702 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3703 pUnit->fCalled = false;
3704
3705 /*
3706 * Do the prepare run.
3707 */
3708 Handle.rc = VINF_SUCCESS;
3709 Handle.enmOp = SSMSTATE_LOAD_PREP;
3710 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3711 {
3712 if (pUnit->u.Common.pfnLoadPrep)
3713 {
3714 pUnit->fCalled = true;
3715 switch (pUnit->enmType)
3716 {
3717 case SSMUNITTYPE_DEV:
3718 rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
3719 break;
3720 case SSMUNITTYPE_DRV:
3721 rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
3722 break;
3723 case SSMUNITTYPE_INTERNAL:
3724 rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
3725 break;
3726 case SSMUNITTYPE_EXTERNAL:
3727 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
3728 break;
3729 }
3730 if (RT_FAILURE(rc))
3731 {
3732 LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
3733 break;
3734 }
3735 }
3736 }
3737
3738 /* pending 2% */
3739 if (pfnProgress)
3740 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
3741 Handle.uPercent = Handle.uPercentPrepare;
3742 Handle.cbEstTotal = Handle.u.Read.cbLoadFile;
3743 Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
3744
3745 /*
3746 * Do the execute run.
3747 */
3748 if (RT_SUCCESS(rc))
3749 {
3750 if (Handle.u.Read.uFmtVerMajor >= 2)
3751 rc = ssmR3LoadExecV2(pVM, &Handle);
3752 else
3753 rc = ssmR3LoadExecV1(pVM, &Handle);
3754 /* (progress should be pending 99% now) */
3755 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
3756 }
3757
3758 /*
3759 * Do the done run.
3760 */
3761 Handle.rc = rc;
3762 Handle.enmOp = SSMSTATE_LOAD_DONE;
3763 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
3764 {
3765 if ( pUnit->u.Common.pfnLoadDone
3766 && ( pUnit->fCalled
3767 || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
3768 {
3769 rc = VINF_SUCCESS;
3770 switch (pUnit->enmType)
3771 {
3772 case SSMUNITTYPE_DEV:
3773 rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
3774 break;
3775 case SSMUNITTYPE_DRV:
3776 rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
3777 break;
3778 case SSMUNITTYPE_INTERNAL:
3779 rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
3780 break;
3781 case SSMUNITTYPE_EXTERNAL:
3782 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
3783 break;
3784 }
3785 if (RT_FAILURE(rc))
3786 {
3787 LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
3788 rc, pUnit->szName, pUnit->u32Instance));
3789 if (RT_SUCCESS(Handle.rc))
3790 Handle.rc = rc;
3791 }
3792 }
3793 }
3794 rc = Handle.rc;
3795
3796 /* progress */
3797 if (pfnProgress)
3798 pfnProgress(pVM, 99, pvUser);
3799
3800 ssmR3StrmClose(&Handle.Strm);
3801 }
3802
3803 /*
3804 * Done
3805 */
3806 if (RT_SUCCESS(rc))
3807 {
3808 /* progress */
3809 if (pfnProgress)
3810 pfnProgress(pVM, 100, pvUser);
3811 Log(("SSM: Load of '%s' completed!\n", pszFilename));
3812 }
3813 return rc;
3814}
3815
3816
3817/**
3818 * Validates a file as a validate SSM saved state.
3819 *
3820 * This will only verify the file format, the format and content of individual
3821 * data units are not inspected.
3822 *
3823 * @returns VINF_SUCCESS if valid.
3824 * @returns VBox status code on other failures.
3825 *
3826 * @param pszFilename The path to the file to validate.
3827 * @param fChecksumIt Whether to checksum the file or not.
3828 *
3829 * @thread Any.
3830 */
3831VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
3832{
3833 LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
3834
3835 /*
3836 * Try open the file and validate it.
3837 */
3838 SSMHANDLE Handle;
3839 int rc = ssmR3OpenFile(NULL, pszFilename, fChecksumIt, false /*fChecksumOnRead*/, &Handle);
3840 if (RT_SUCCESS(rc))
3841 ssmR3StrmClose(&Handle.Strm);
3842 else
3843 Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
3844 return rc;
3845}
3846
3847
3848/**
3849 * Opens a saved state file for reading.
3850 *
3851 * @returns VBox status code.
3852 *
3853 * @param pszFilename The path to the saved state file.
3854 * @param fFlags Open flags. Reserved, must be 0.
3855 * @param ppSSM Where to store the SSM handle.
3856 *
3857 * @thread Any.
3858 */
3859VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
3860{
3861 LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
3862
3863 /*
3864 * Validate input.
3865 */
3866 AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
3867 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
3868 AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
3869
3870 /*
3871 * Allocate a handle.
3872 */
3873 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
3874 AssertReturn(pSSM, VERR_NO_MEMORY);
3875
3876 /*
3877 * Try open the file and validate it.
3878 */
3879 int rc = ssmR3OpenFile(NULL, pszFilename, false /*fChecksumIt*/, true /*fChecksumOnRead*/, pSSM);
3880 if (RT_SUCCESS(rc))
3881 {
3882 pSSM->enmAfter = SSMAFTER_OPENED;
3883 pSSM->enmOp = SSMSTATE_OPEN_READ;
3884 *ppSSM = pSSM;
3885 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
3886 return VINF_SUCCESS;
3887 }
3888
3889 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
3890 RTMemFree(pSSM);
3891 return rc;
3892
3893}
3894
3895
3896/**
3897 * Closes a saved state file opened by SSMR3Open().
3898 *
3899 * @returns VBox status code.
3900 *
3901 * @param pSSM The SSM handle returned by SSMR3Open().
3902 *
3903 * @thread Any, but the caller is responsible for serializing calls per handle.
3904 */
3905VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
3906{
3907 LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
3908
3909 /*
3910 * Validate input.
3911 */
3912 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
3913 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
3914 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
3915
3916 /*
3917 * Close the stream and free the handle.
3918 */
3919 int rc = ssmR3StrmClose(&pSSM->Strm);
3920 if (pSSM->u.Read.pZipDecompV1)
3921 {
3922 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
3923 pSSM->u.Read.pZipDecompV1 = NULL;
3924 }
3925 RTMemFree(pSSM);
3926 return rc;
3927}
3928
3929
3930/**
3931 * Worker for SSMR3Seek that seeks version 1 saved state files.
3932 *
3933 * @returns VBox status code.
3934 * @param pSSM The SSM handle.
3935 * @param pszUnit The unit to seek to.
3936 * @param iInstance The particulart insance we seek.
3937 * @param piVersion Where to store the unit version number.
3938 */
3939static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
3940{
3941 /*
3942 * Walk the data units until we find EOF or a match.
3943 */
3944 size_t cbUnitNm = strlen(pszUnit) + 1;
3945 AssertLogRelReturn(cbUnitNm <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
3946 char szName[SSM_MAX_NAME_SIZE];
3947 SSMFILEUNITHDRV1 UnitHdr;
3948 for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
3949 {
3950 /*
3951 * Read the unit header and verify it.
3952 */
3953 int rc = ssmR3StrmPeekAt(&pSSM->Strm, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
3954 AssertRCReturn(rc, rc);
3955 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
3956 {
3957 /*
3958 * Does what we've got match, if so read the name.
3959 */
3960 if ( UnitHdr.u32Instance == iInstance
3961 && UnitHdr.cchName == cbUnitNm)
3962 {
3963 rc = ssmR3StrmPeekAt(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDR, szName), szName, cbUnitNm, NULL);
3964 AssertRCReturn(rc, rc);
3965 AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
3966 (" Unit name '%.*s' was not properly terminated.\n", cbUnitNm, szName),
3967 VERR_SSM_INTEGRITY);
3968
3969 /*
3970 * Does the name match?
3971 */
3972 if (!memcmp(szName, pszUnit, cbUnitNm))
3973 {
3974 rc = ssmR3StrmSeek(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDR, szName) + cbUnitNm, RTFILE_SEEK_BEGIN, 0);
3975 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[cbUnitNm]);
3976 pSSM->offUnit = 0;
3977 if (piVersion)
3978 *piVersion = UnitHdr.u32Version;
3979 return VINF_SUCCESS;
3980 }
3981 }
3982 }
3983 else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
3984 return VERR_SSM_UNIT_NOT_FOUND;
3985 else
3986 AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
3987 off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
3988 VERR_SSM_INTEGRITY_UNIT_MAGIC);
3989 }
3990 /* won't get here. */
3991}
3992
3993
3994/**
3995 * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
3996 *
3997 * @returns VBox status code.
3998 * @param pSSM The SSM handle.
3999 * @param pDir The directory buffer.
4000 * @param cbDir The size of the directory.
4001 * @param cDirEntries The number of directory entries.
4002 * @param offDir The directory offset in the file.
4003 * @param pszUnit The unit to seek to.
4004 * @param iInstance The particulart insance we seek.
4005 * @param piVersion Where to store the unit version number.
4006 */
4007static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries, uint64_t offDir,
4008 const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
4009{
4010 /*
4011 * Read it.
4012 */
4013 int rc = ssmR3StrmPeekAt(&pSSM->Strm, offDir, pDir, cbDir, NULL);
4014 AssertLogRelRCReturn(rc, rc);
4015 AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY);
4016 SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
4017 AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
4018 ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
4019 VERR_SSM_INTEGRITY);
4020 for (uint32_t i = 0; i < cDirEntries; i++)
4021 AssertLogRelMsgReturn(pDir->aEntries[i].off < offDir,
4022 ("i=%u off=%lld offDir=%lld\n", i, pDir->aEntries[i].off, offDir),
4023 VERR_SSM_INTEGRITY);
4024
4025 /*
4026 * Search the directory.
4027 */
4028 size_t cbUnitNm = strlen(pszUnit) + 1;
4029 uint32_t const u32NameCRC = RTCrc32(pszUnit, cbUnitNm - 1);
4030 for (uint32_t i = 0; i < cDirEntries; i++)
4031 {
4032 if ( pDir->aEntries[i].u32NameCRC == u32NameCRC
4033 && pDir->aEntries[i].u32Instance == iInstance)
4034 {
4035 /*
4036 * Read and validate the unit header.
4037 */
4038 SSMFILEUNITHDR UnitHdr;
4039 size_t cbToRead = sizeof(UnitHdr);
4040 if (pDir->aEntries[i].off + cbToRead > offDir)
4041 {
4042 cbToRead = offDir - pDir->aEntries[i].off;
4043 RT_ZERO(UnitHdr);
4044 }
4045 rc = ssmR3StrmPeekAt(&pSSM->Strm, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
4046 AssertLogRelRCReturn(rc, rc);
4047
4048 AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
4049 ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
4050 VERR_SSM_INTEGRITY);
4051 AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
4052 ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
4053 VERR_SSM_INTEGRITY);
4054 AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
4055 ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
4056 i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
4057 VERR_SSM_INTEGRITY);
4058 uint32_t cbUnitHdr = RT_UOFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]);
4059 AssertLogRelMsgReturn( UnitHdr.cbName > 0
4060 && UnitHdr.cbName < sizeof(UnitHdr)
4061 && cbUnitHdr <= cbToRead,
4062 ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
4063 VERR_SSM_INTEGRITY);
4064 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]),
4065 ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
4066 i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
4067
4068 /*
4069 * Ok, it is valid, get on with the comparing now.
4070 */
4071 if ( UnitHdr.cbName == cbUnitNm
4072 && !memcmp(UnitHdr.szName, pszUnit, cbUnitNm))
4073 {
4074 if (piVersion)
4075 *piVersion = UnitHdr.u32Version;
4076 rc = ssmR3StrmSeek(&pSSM->Strm, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN,
4077 RTCrc32Process(UnitHdr.u32CurStreamCRC, &UnitHdr, cbUnitHdr));
4078 AssertLogRelRCReturn(rc, rc);
4079 ssmR3DataReadBeginV2(pSSM);
4080 return VINF_SUCCESS;
4081 }
4082 }
4083 }
4084
4085 return VERR_SSM_UNIT_NOT_FOUND;
4086}
4087
4088
4089/**
4090 * Worker for SSMR3Seek that seeks version 2 saved state files.
4091 *
4092 * @returns VBox status code.
4093 * @param pSSM The SSM handle.
4094 * @param pszUnit The unit to seek to.
4095 * @param iInstance The particulart insance we seek.
4096 * @param piVersion Where to store the unit version number.
4097 */
4098static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
4099{
4100 /*
4101 * Read the footer, allocate a temporary buffer for the dictionary and
4102 * pass it down to a worker to simplify cleanup.
4103 */
4104 uint64_t offFooter;
4105 SSMFILEFTR Footer;
4106 int rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(Footer), &Footer, sizeof(Footer), &offFooter);
4107 AssertLogRelRCReturn(rc, rc);
4108 AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
4109 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
4110
4111 size_t const cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[Footer.cDirEntries]);
4112 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
4113 if (RT_UNLIKELY(!pDir))
4114 return VERR_NO_TMP_MEMORY;
4115 rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, offFooter - cbDir,
4116 pszUnit, iInstance, piVersion);
4117 RTMemTmpFree(pDir);
4118
4119 return rc;
4120}
4121
4122
4123
4124/**
4125 * Seeks to a specific data unit.
4126 *
4127 * After seeking it's possible to use the getters to on
4128 * that data unit.
4129 *
4130 * @returns VBox status code.
4131 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
4132 *
4133 * @param pSSM The SSM handle returned by SSMR3Open().
4134 * @param pszUnit The name of the data unit.
4135 * @param iInstance The instance number.
4136 * @param piVersion Where to store the version number. (Optional)
4137 *
4138 * @thread Any, but the caller is responsible for serializing calls per handle.
4139 */
4140VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
4141{
4142 LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
4143 pSSM, pszUnit, pszUnit, iInstance, piVersion));
4144
4145 /*
4146 * Validate input.
4147 */
4148 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
4149 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
4150 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
4151 AssertMsgReturn(VALID_PTR(pszUnit), ("%p\n", pszUnit), VERR_INVALID_POINTER);
4152 AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
4153
4154 /*
4155 * Reset the state.
4156 */
4157 if (pSSM->u.Read.pZipDecompV1)
4158 {
4159 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
4160 pSSM->u.Read.pZipDecompV1 = NULL;
4161 }
4162 pSSM->cbUnitLeftV1 = 0;
4163 pSSM->offUnit = UINT64_MAX;
4164
4165 /*
4166 * Call the version specific workers.
4167 */
4168 if (pSSM->u.Read.uFmtVerMajor >= 2)
4169 pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
4170 else
4171 pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
4172 return pSSM->rc;
4173}
4174
4175
4176/**
4177 * Finishes a data unit.
4178 * All buffers and compressor instances are flushed and destroyed.
4179 *
4180 * @returns VBox status.
4181 * @param pSSM SSM operation handle.
4182 */
4183static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
4184{
4185 //Log2(("ssmR3DataWriteFinish: %#010llx start\n", ssmR3StrmTell(&pSSM->Strm)));
4186 int rc = ssmR3DataFlushBuffer(pSSM);
4187 if (RT_SUCCESS(rc))
4188 return VINF_SUCCESS;
4189
4190 if (RT_SUCCESS(pSSM->rc))
4191 pSSM->rc = rc;
4192 Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
4193 return rc;
4194}
4195
4196
4197/**
4198 * Begins writing the data of a data unit.
4199 *
4200 * Errors are signalled via pSSM->rc.
4201 *
4202 * @param pSSM The saved state handle.
4203 */
4204static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
4205{
4206 pSSM->offUnit = 0;
4207}
4208
4209
4210/**
4211 * Writes a record to the current data item in the saved state file.
4212 *
4213 * @returns VBox status code. Sets pSSM->rc on failure.
4214 * @param pSSM The saved state handle.
4215 * @param pvBuf The bits to write.
4216 * @param cbBuf The number of bytes to write.
4217 */
4218static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
4219{
4220 Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
4221 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
4222
4223 /*
4224 * Check that everything is fine.
4225 */
4226 if (RT_FAILURE(pSSM->rc))
4227 return pSSM->rc;
4228
4229 /*
4230 * Write the data item in 1MB chunks for progress indicator reasons.
4231 */
4232 while (cbBuf > 0)
4233 {
4234 size_t cbChunk = RT_MIN(cbBuf, _1M);
4235 int rc = ssmR3StrmWrite(&pSSM->Strm, pvBuf, cbChunk);
4236 if (RT_FAILURE(rc))
4237 return rc;
4238 ssmR3Progress(pSSM, cbChunk);
4239 pSSM->offUnit += cbChunk;
4240 cbBuf -= cbChunk;
4241 pvBuf = (char *)pvBuf + cbChunk;
4242 }
4243
4244 return VINF_SUCCESS;
4245}
4246
4247
4248/**
4249 * Writes a record header for the specified amount of data.
4250 *
4251 * @returns VBox status code. Sets pSSM->rc on failure.
4252 * @param pSSM The saved state handle
4253 * @param cb The amount of data.
4254 * @param u8TypeAndFlags The record type and flags.
4255 */
4256static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
4257{
4258 size_t cbHdr;
4259 uint8_t abHdr[8];
4260 abHdr[0] = u8TypeAndFlags;
4261 if (cb < 0x80)
4262 {
4263 cbHdr = 2;
4264 abHdr[1] = (uint8_t)cb;
4265 }
4266 else if (cb < 0x00000800)
4267 {
4268 cbHdr = 3;
4269 abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
4270 abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
4271 }
4272 else if (cb < 0x00010000)
4273 {
4274 cbHdr = 4;
4275 abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
4276 abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
4277 abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
4278 }
4279 else if (cb < 0x00200000)
4280 {
4281 cbHdr = 5;
4282 abHdr[1] = (uint8_t)(0xf0 | (cb >> 18));
4283 abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
4284 abHdr[3] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
4285 abHdr[4] = (uint8_t)(0x80 | (cb & 0x3f));
4286 }
4287 else if (cb < 0x04000000)
4288 {
4289 cbHdr = 6;
4290 abHdr[1] = (uint8_t)(0xf8 | (cb >> 24));
4291 abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
4292 abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
4293 abHdr[4] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
4294 abHdr[5] = (uint8_t)(0x80 | (cb & 0x3f));
4295 }
4296 else if (cb <= 0x7fffffff)
4297 {
4298 cbHdr = 7;
4299 abHdr[1] = (uint8_t)(0xfc | (cb >> 30));
4300 abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
4301 abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
4302 abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
4303 abHdr[5] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
4304 abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
4305 }
4306 else
4307 AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_INTERNAL_ERROR);
4308
4309 Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
4310 ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
4311
4312 return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
4313}
4314
4315
4316/**
4317 * Worker that flushes the buffered data.
4318 *
4319 * @returns VBox status code. Will set pSSM->rc on error.
4320 * @param pSSM The saved state handle.
4321 */
4322static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
4323{
4324 /*
4325 * Check how much there current is in the buffer.
4326 */
4327 uint32_t cb = pSSM->u.Write.offDataBuffer;
4328 if (!cb)
4329 return pSSM->rc;
4330 pSSM->u.Write.offDataBuffer = 0;
4331
4332 /*
4333 * Write a record header and then the data.
4334 * (No need for fancy optimizations here any longer since the stream is
4335 * fully buffered.)
4336 */
4337 int rc = ssmR3DataWriteRecHdr(pSSM, cb, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
4338 if (RT_SUCCESS(rc))
4339 rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
4340 return rc;
4341}
4342
4343
4344/**
4345 * ssmR3DataWrite worker that writes big stuff.
4346 *
4347 * @returns VBox status code
4348 * @param pSSM The saved state handle.
4349 * @param pvBuf The bits to write.
4350 * @param cbBuf The number of bytes to write.
4351 */
4352static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
4353{
4354 int rc = ssmR3DataFlushBuffer(pSSM);
4355 if (RT_SUCCESS(rc))
4356 {
4357 /*
4358 * Compress it if it's a page or more in size.
4359 */
4360 for (;;)
4361 {
4362 if (cbBuf >= SSM_ZIP_BLOCK_SIZE)
4363 {
4364 AssertCompile(1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE < 0x00010000);
4365 uint8_t *pb;
4366 rc = ssmR3StrmReserveWriteBufferSpace(&pSSM->Strm, 1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE, &pb);
4367 if (RT_FAILURE(rc))
4368 break;
4369 size_t cbRec = SSM_ZIP_BLOCK_SIZE - (SSM_ZIP_BLOCK_SIZE / 16);
4370 rc = RTZipBlockCompress(RTZIPTYPE_LZF, RTZIPLEVEL_FAST, 0 /*fFlags*/,
4371 pvBuf, SSM_ZIP_BLOCK_SIZE,
4372 pb + 1 + 3 + 1, cbRec, &cbRec);
4373 if (RT_SUCCESS(rc))
4374 {
4375 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF;
4376 pb[4] = SSM_ZIP_BLOCK_SIZE / _1K;
4377 cbRec += 1;
4378 }
4379 else
4380 {
4381 pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
4382 memcpy(&pb[4], pvBuf, SSM_ZIP_BLOCK_SIZE);
4383 cbRec = SSM_ZIP_BLOCK_SIZE;
4384 }
4385 pb[1] = (uint8_t)(0xe0 | ( cbRec >> 12));
4386 pb[2] = (uint8_t)(0x80 | ((cbRec >> 6) & 0x3f));
4387 pb[3] = (uint8_t)(0x80 | ( cbRec & 0x3f));
4388 cbRec += 1 + 3;
4389 rc = ssmR3StrmCommitWriteBufferSpace(&pSSM->Strm, cbRec);
4390 if (RT_FAILURE(rc))
4391 break;
4392
4393 pSSM->offUnit += cbRec;
4394 ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
4395
4396 /* advance */
4397 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
4398 return VINF_SUCCESS;
4399 cbBuf -= SSM_ZIP_BLOCK_SIZE;
4400 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
4401 }
4402 else
4403 {
4404 /*
4405 * Less than one block left, store it the simple way.
4406 */
4407 rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
4408 if (RT_SUCCESS(rc))
4409 rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
4410 break;
4411 }
4412 }
4413 }
4414 return rc;
4415}
4416
4417
4418/**
4419 * ssmR3DataWrite worker that is called when there isn't enough room in the
4420 * buffer for the current chunk of data.
4421 *
4422 * This will first flush the buffer and then add the new bits to it.
4423 *
4424 * @returns VBox status code
4425 * @param pSSM The saved state handle.
4426 * @param pvBuf The bits to write.
4427 * @param cbBuf The number of bytes to write.
4428 */
4429static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
4430{
4431 int rc = ssmR3DataFlushBuffer(pSSM);
4432 if (RT_SUCCESS(rc))
4433 {
4434 memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
4435 pSSM->u.Write.offDataBuffer = (uint32_t)cbBuf;
4436 }
4437 return rc;
4438}
4439
4440
4441/**
4442 * Writes data to the current data unit.
4443 *
4444 * This is an inlined wrapper that optimizes the small writes that so many of
4445 * the APIs make.
4446 *
4447 * @returns VBox status code
4448 * @param pSSM The saved state handle.
4449 * @param pvBuf The bits to write.
4450 * @param cbBuf The number of bytes to write.
4451 */
4452DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
4453{
4454 if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
4455 return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
4456 if (!cbBuf)
4457 return VINF_SUCCESS;
4458
4459 uint32_t off = pSSM->u.Write.offDataBuffer;
4460 if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
4461 return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
4462
4463 memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
4464 pSSM->u.Write.offDataBuffer = off + (uint32_t)cbBuf;
4465 return VINF_SUCCESS;
4466}
4467
4468
4469/**
4470 * Puts a structure.
4471 *
4472 * @returns VBox status code.
4473 * @param pSSM The saved state handle.
4474 * @param pvStruct The structure address.
4475 * @param paFields The array of structure fields descriptions.
4476 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
4477 */
4478VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
4479{
4480 /* begin marker. */
4481 int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
4482 if (RT_FAILURE(rc))
4483 return rc;
4484
4485 /* put the fields */
4486 for (PCSSMFIELD pCur = paFields;
4487 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
4488 pCur++)
4489 {
4490 rc = ssmR3DataWrite(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
4491 if (RT_FAILURE(rc))
4492 return rc;
4493 }
4494
4495 /* end marker */
4496 return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
4497}
4498
4499
4500/**
4501 * Saves a boolean item to the current data unit.
4502 *
4503 * @returns VBox status.
4504 * @param pSSM SSM operation handle.
4505 * @param fBool Item to save.
4506 */
4507VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
4508{
4509 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4510 {
4511 uint8_t u8 = fBool; /* enforce 1 byte size */
4512 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
4513 }
4514 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4515 return VERR_SSM_INVALID_STATE;
4516}
4517
4518
4519/**
4520 * Saves a 8-bit unsigned integer item to the current data unit.
4521 *
4522 * @returns VBox status.
4523 * @param pSSM SSM operation handle.
4524 * @param u8 Item to save.
4525 */
4526VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
4527{
4528 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4529 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
4530 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4531 return VERR_SSM_INVALID_STATE;
4532}
4533
4534
4535/**
4536 * Saves a 8-bit signed integer item to the current data unit.
4537 *
4538 * @returns VBox status.
4539 * @param pSSM SSM operation handle.
4540 * @param i8 Item to save.
4541 */
4542VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
4543{
4544 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4545 return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
4546 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4547 return VERR_SSM_INVALID_STATE;
4548}
4549
4550
4551/**
4552 * Saves a 16-bit unsigned integer item to the current data unit.
4553 *
4554 * @returns VBox status.
4555 * @param pSSM SSM operation handle.
4556 * @param u16 Item to save.
4557 */
4558VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
4559{
4560 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4561 return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
4562 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4563 return VERR_SSM_INVALID_STATE;
4564}
4565
4566
4567/**
4568 * Saves a 16-bit signed integer item to the current data unit.
4569 *
4570 * @returns VBox status.
4571 * @param pSSM SSM operation handle.
4572 * @param i16 Item to save.
4573 */
4574VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
4575{
4576 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4577 return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
4578 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4579 return VERR_SSM_INVALID_STATE;
4580}
4581
4582
4583/**
4584 * Saves a 32-bit unsigned integer item to the current data unit.
4585 *
4586 * @returns VBox status.
4587 * @param pSSM SSM operation handle.
4588 * @param u32 Item to save.
4589 */
4590VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
4591{
4592 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4593 return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
4594 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4595 return VERR_SSM_INVALID_STATE;
4596}
4597
4598
4599/**
4600 * Saves a 32-bit signed integer item to the current data unit.
4601 *
4602 * @returns VBox status.
4603 * @param pSSM SSM operation handle.
4604 * @param i32 Item to save.
4605 */
4606VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
4607{
4608 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4609 return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
4610 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4611 return VERR_SSM_INVALID_STATE;
4612}
4613
4614
4615/**
4616 * Saves a 64-bit unsigned integer item to the current data unit.
4617 *
4618 * @returns VBox status.
4619 * @param pSSM SSM operation handle.
4620 * @param u64 Item to save.
4621 */
4622VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
4623{
4624 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4625 return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
4626 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4627 return VERR_SSM_INVALID_STATE;
4628}
4629
4630
4631/**
4632 * Saves a 64-bit signed integer item to the current data unit.
4633 *
4634 * @returns VBox status.
4635 * @param pSSM SSM operation handle.
4636 * @param i64 Item to save.
4637 */
4638VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
4639{
4640 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4641 return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
4642 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4643 return VERR_SSM_INVALID_STATE;
4644}
4645
4646
4647/**
4648 * Saves a 128-bit unsigned integer item to the current data unit.
4649 *
4650 * @returns VBox status.
4651 * @param pSSM SSM operation handle.
4652 * @param u128 Item to save.
4653 */
4654VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
4655{
4656 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4657 return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
4658 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4659 return VERR_SSM_INVALID_STATE;
4660}
4661
4662
4663/**
4664 * Saves a 128-bit signed integer item to the current data unit.
4665 *
4666 * @returns VBox status.
4667 * @param pSSM SSM operation handle.
4668 * @param i128 Item to save.
4669 */
4670VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
4671{
4672 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4673 return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
4674 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4675 return VERR_SSM_INVALID_STATE;
4676}
4677
4678
4679/**
4680 * Saves a VBox unsigned integer item to the current data unit.
4681 *
4682 * @returns VBox status.
4683 * @param pSSM SSM operation handle.
4684 * @param u Item to save.
4685 */
4686VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
4687{
4688 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4689 return ssmR3DataWrite(pSSM, &u, sizeof(u));
4690 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4691 return VERR_SSM_INVALID_STATE;
4692}
4693
4694
4695/**
4696 * Saves a VBox signed integer item to the current data unit.
4697 *
4698 * @returns VBox status.
4699 * @param pSSM SSM operation handle.
4700 * @param i Item to save.
4701 */
4702VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
4703{
4704 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4705 return ssmR3DataWrite(pSSM, &i, sizeof(i));
4706 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4707 return VERR_SSM_INVALID_STATE;
4708}
4709
4710
4711/**
4712 * Saves a GC natural unsigned integer item to the current data unit.
4713 *
4714 * @returns VBox status.
4715 * @param pSSM SSM operation handle.
4716 * @param u Item to save.
4717 *
4718 * @deprecated Silly type, don't use it.
4719 */
4720VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
4721{
4722 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4723 return ssmR3DataWrite(pSSM, &u, sizeof(u));
4724 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4725 return VERR_SSM_INVALID_STATE;
4726}
4727
4728
4729/**
4730 * Saves a GC unsigned integer register item to the current data unit.
4731 *
4732 * @returns VBox status.
4733 * @param pSSM SSM operation handle.
4734 * @param u Item to save.
4735 */
4736VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
4737{
4738 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4739 return ssmR3DataWrite(pSSM, &u, sizeof(u));
4740 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4741 return VERR_SSM_INVALID_STATE;
4742}
4743
4744
4745/**
4746 * Saves a 32 bits GC physical address item to the current data unit.
4747 *
4748 * @returns VBox status.
4749 * @param pSSM SSM operation handle.
4750 * @param GCPhys The item to save
4751 */
4752VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
4753{
4754 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4755 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
4756 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4757 return VERR_SSM_INVALID_STATE;
4758}
4759
4760
4761/**
4762 * Saves a 64 bits GC physical address item to the current data unit.
4763 *
4764 * @returns VBox status.
4765 * @param pSSM SSM operation handle.
4766 * @param GCPhys The item to save
4767 */
4768VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
4769{
4770 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4771 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
4772 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4773 return VERR_SSM_INVALID_STATE;
4774}
4775
4776
4777/**
4778 * Saves a GC physical address item to the current data unit.
4779 *
4780 * @returns VBox status.
4781 * @param pSSM SSM operation handle.
4782 * @param GCPhys The item to save
4783 */
4784VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
4785{
4786 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4787 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
4788 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4789 return VERR_SSM_INVALID_STATE;
4790}
4791
4792
4793/**
4794 * Saves a GC virtual address item to the current data unit.
4795 *
4796 * @returns VBox status.
4797 * @param pSSM SSM operation handle.
4798 * @param GCPtr The item to save.
4799 */
4800VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
4801{
4802 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4803 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
4804 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4805 return VERR_SSM_INVALID_STATE;
4806}
4807
4808
4809/**
4810 * Saves an RC virtual address item to the current data unit.
4811 *
4812 * @returns VBox status.
4813 * @param pSSM SSM operation handle.
4814 * @param RCPtr The item to save.
4815 */
4816VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
4817{
4818 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4819 return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
4820 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4821 return VERR_SSM_INVALID_STATE;
4822}
4823
4824
4825/**
4826 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
4827 *
4828 * @returns VBox status.
4829 * @param pSSM SSM operation handle.
4830 * @param GCPtr The item to save.
4831 */
4832VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
4833{
4834 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4835 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
4836 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4837 return VERR_SSM_INVALID_STATE;
4838}
4839
4840
4841/**
4842 * Saves a I/O port address item to the current data unit.
4843 *
4844 * @returns VBox status.
4845 * @param pSSM SSM operation handle.
4846 * @param IOPort The item to save.
4847 */
4848VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
4849{
4850 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4851 return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
4852 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4853 return VERR_SSM_INVALID_STATE;
4854}
4855
4856
4857/**
4858 * Saves a selector item to the current data unit.
4859 *
4860 * @returns VBox status.
4861 * @param pSSM SSM operation handle.
4862 * @param Sel The item to save.
4863 */
4864VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
4865{
4866 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4867 return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
4868 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4869 return VERR_SSM_INVALID_STATE;
4870}
4871
4872
4873/**
4874 * Saves a memory item to the current data unit.
4875 *
4876 * @returns VBox status.
4877 * @param pSSM SSM operation handle.
4878 * @param pv Item to save.
4879 * @param cb Size of the item.
4880 */
4881VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
4882{
4883 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4884 return ssmR3DataWrite(pSSM, pv, cb);
4885 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4886 return VERR_SSM_INVALID_STATE;
4887}
4888
4889
4890/**
4891 * Saves a zero terminated string item to the current data unit.
4892 *
4893 * @returns VBox status.
4894 * @param pSSM SSM operation handle.
4895 * @param psz Item to save.
4896 */
4897VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
4898{
4899 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
4900 {
4901 size_t cch = strlen(psz);
4902 if (cch > _1M)
4903 {
4904 AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
4905 return VERR_TOO_MUCH_DATA;
4906 }
4907 uint32_t u32 = (uint32_t)cch;
4908 int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
4909 if (rc)
4910 return rc;
4911 return ssmR3DataWrite(pSSM, psz, cch);
4912 }
4913 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4914 return VERR_SSM_INVALID_STATE;
4915}
4916
4917
4918
4919
4920
4921/**
4922 * Closes the decompressor of a data unit.
4923 *
4924 * @param pSSM SSM operation handle.
4925 */
4926static void ssmR3DataReadFinishV1(PSSMHANDLE pSSM)
4927{
4928 if (pSSM->u.Read.pZipDecompV1)
4929 {
4930 int rc = RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
4931 AssertRC(rc);
4932 pSSM->u.Read.pZipDecompV1 = NULL;
4933 }
4934}
4935
4936
4937/**
4938 * Callback for reading compressed data into the input buffer of the
4939 * decompressor, for saved file format version 1.
4940 *
4941 * @returns VBox status code.
4942 * @param pvSSM The SSM handle.
4943 * @param pvBuf Where to store the compressed data.
4944 * @param cbBuf Size of the buffer.
4945 * @param pcbRead Number of bytes actually stored in the buffer.
4946 */
4947static DECLCALLBACK(int) ssmR3ReadInV1(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
4948{
4949 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
4950 size_t cbRead = cbBuf;
4951 if (pSSM->cbUnitLeftV1 < cbBuf)
4952 cbRead = (size_t)pSSM->cbUnitLeftV1;
4953 if (cbRead)
4954 {
4955 //Log2(("ssmR3ReadInV1: %#010llx cbBug=%#x cbRead=%#x\n", ssmR3StrmTell(&pSSM->Strm), cbBuf, cbRead));
4956 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbRead);
4957 if (RT_SUCCESS(rc))
4958 {
4959 pSSM->cbUnitLeftV1 -= cbRead;
4960 if (pcbRead)
4961 *pcbRead = cbRead;
4962 ssmR3Progress(pSSM, cbRead);
4963 return VINF_SUCCESS;
4964 }
4965 return rc;
4966 }
4967
4968 /** @todo weed out lazy saving */
4969 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
4970 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
4971 return VERR_SSM_LOADED_TOO_MUCH;
4972}
4973
4974
4975/**
4976 * Internal read worker for reading data from a version 1 unit.
4977 *
4978 * @param pSSM SSM operation handle.
4979 * @param pvBuf Where to store the read data.
4980 * @param cbBuf Number of bytes to read.
4981 */
4982static int ssmR3DataReadV1(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
4983{
4984 /*
4985 * Open the decompressor on the first read.
4986 */
4987 if (!pSSM->u.Read.pZipDecompV1)
4988 {
4989 pSSM->rc = RTZipDecompCreate(&pSSM->u.Read.pZipDecompV1, pSSM, ssmR3ReadInV1);
4990 if (RT_FAILURE(pSSM->rc))
4991 return pSSM->rc;
4992 }
4993
4994 /*
4995 * Do the requested read.
4996 */
4997 int rc = pSSM->rc = RTZipDecompress(pSSM->u.Read.pZipDecompV1, pvBuf, cbBuf, NULL);
4998 if (RT_SUCCESS(rc))
4999 {
5000 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 ? "..." : ""));
5001 pSSM->offUnit += cbBuf;
5002 return VINF_SUCCESS;
5003 }
5004 AssertMsgFailed(("rc=%Rrc cbBuf=%#x\n", rc, cbBuf));
5005 return rc;
5006}
5007
5008
5009/**
5010 * Creates the decompressor for the data unit.
5011 *
5012 * pSSM->rc will be set on error.
5013 *
5014 * @param pSSM SSM operation handle.
5015 */
5016static void ssmR3DataReadBeginV2(PSSMHANDLE pSSM)
5017{
5018 Assert(!pSSM->u.Read.cbDataBuffer || pSSM->u.Read.cbDataBuffer == pSSM->u.Read.offDataBuffer);
5019 Assert(!pSSM->u.Read.cbRecLeft);
5020
5021 pSSM->offUnit = 0;
5022 pSSM->u.Read.cbRecLeft = 0;
5023 pSSM->u.Read.cbDataBuffer = 0;
5024 pSSM->u.Read.offDataBuffer = 0;
5025 pSSM->u.Read.fEndOfData = false;
5026 pSSM->u.Read.u8TypeAndFlags = 0;
5027}
5028
5029
5030/**
5031 * Checks for the termination record and closes the decompressor.
5032 *
5033 * pSSM->rc will be set on error.
5034 *
5035 * @param pSSM SSM operation handle.
5036 */
5037static void ssmR3DataReadFinishV2(PSSMHANDLE pSSM)
5038{
5039 /*
5040 * If we haven't encountered the end of the record, it must be the next one.
5041 */
5042 if ( !pSSM->u.Read.fEndOfData
5043 && RT_SUCCESS(pSSM->rc))
5044 {
5045 int rc = ssmR3DataReadRecHdrV2(pSSM);
5046 if ( RT_SUCCESS(rc)
5047 && !pSSM->u.Read.fEndOfData)
5048 rc = VERR_SSM_LOADED_TOO_MUCH; /** @todo More error codes! */
5049 pSSM->rc = rc;
5050 }
5051}
5052
5053
5054/**
5055 * Read reader that keep works the progress indicator and unit offset.
5056 *
5057 * Does not set SSM::rc.
5058 *
5059 * @returns VBox status code.
5060 * @param pSSM The saved state handle.
5061 * @param pvBuf Where to put the bits
5062 * @param cbBuf How many bytes to read.
5063 */
5064DECLINLINE(int) ssmR3DataReadV2Raw(PSSMHANDLE pSSM, void *pvBuf, size_t cbToRead)
5065{
5066 int rc = ssmR3StrmRead(&pSSM->Strm, pvBuf, cbToRead);
5067 if (RT_SUCCESS(rc))
5068 {
5069 pSSM->offUnit += cbToRead;
5070 ssmR3Progress(pSSM, cbToRead);
5071 return VINF_SUCCESS;
5072 }
5073
5074 /** @todo weed out lazy saving */
5075 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
5076 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
5077 return VERR_SSM_LOADED_TOO_MUCH;
5078}
5079
5080
5081/**
5082 * Reads and checks the LZF "header".
5083 *
5084 * @returns VBox status code.
5085 * @param pSSM The saved state handle..
5086 * @param pcbDecompr Where to store the size of the decompressed data.
5087 */
5088DECLINLINE(int) ssmR3DataReadV2RawLzfHdr(PSSMHANDLE pSSM, uint32_t *pcbDecompr)
5089{
5090 *pcbDecompr = 0; /* shuts up gcc. */
5091 AssertLogRelMsgReturn( pSSM->u.Read.cbRecLeft > 1
5092 && pSSM->u.Read.cbRecLeft <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abComprBuffer) + 2,
5093 ("%#x\n", pSSM->u.Read.cbRecLeft),
5094 VERR_SSM_INTEGRITY);
5095
5096/** @todo this isn't very efficient, we know we have to read it all, so both
5097 * reading the first byte separately. */
5098 uint8_t cKB;
5099 int rc = ssmR3DataReadV2Raw(pSSM, &cKB, 1);
5100 if (RT_FAILURE(rc))
5101 return rc;
5102 pSSM->u.Read.cbRecLeft -= sizeof(cKB);
5103
5104 uint32_t cbDecompr = (uint32_t)cKB * _1K;
5105 AssertLogRelMsgReturn( cbDecompr >= pSSM->u.Read.cbRecLeft
5106 && cbDecompr <= RT_SIZEOFMEMB(SSMHANDLE, u.Read.abDataBuffer),
5107 ("%#x\n", cbDecompr),
5108 VERR_SSM_INTEGRITY);
5109
5110 *pcbDecompr = cbDecompr;
5111 return VINF_SUCCESS;
5112}
5113
5114
5115/**
5116 * Reads an LZF block from the stream and decompresses into the specified
5117 * buffer.
5118 *
5119 * @returns VBox status code.
5120 * @param SSM The saved state handle.
5121 * @param pvDst Pointer to the output buffer.
5122 * @param cbDecompr The size of the decompressed data.
5123 */
5124static int ssmR3DataReadV2RawLzf(PSSMHANDLE pSSM, void *pvDst, size_t cbDecompr)
5125{
5126 int rc;
5127 uint32_t cbCompr = pSSM->u.Read.cbRecLeft;
5128 pSSM->u.Read.cbRecLeft = 0;
5129
5130 /*
5131 * Try use the stream buffer directly to avoid copying things around.
5132 */
5133 uint8_t const *pb = ssmR3StrmReadDirect(&pSSM->Strm, cbCompr);
5134 if (pb)
5135 {
5136 pSSM->offUnit += cbCompr;
5137 ssmR3Progress(pSSM, cbCompr);
5138 }
5139 else
5140 {
5141 rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abComprBuffer[0], cbCompr);
5142 if (RT_FAILURE(rc))
5143 return rc;
5144 pb = &pSSM->u.Read.abComprBuffer[0];
5145 }
5146
5147 /*
5148 * Decompress it.
5149 */
5150 size_t cbDstActual;
5151 rc = RTZipBlockDecompress(RTZIPTYPE_LZF, 0 /*fFlags*/,
5152 pb, cbCompr, NULL /*pcbSrcActual*/,
5153 pvDst, cbDecompr, &cbDstActual);
5154 if (RT_SUCCESS(rc))
5155 {
5156 AssertLogRelMsgReturn(cbDstActual == cbDecompr, ("%#x %#x\n", cbDstActual, cbDecompr), VERR_SSM_INTEGRITY);
5157 return VINF_SUCCESS;
5158 }
5159 return rc;
5160}
5161
5162
5163/**
5164 * Worker for reading the record header.
5165 *
5166 * It sets pSSM->u.Read.cbRecLeft, pSSM->u.Read.u8TypeAndFlags and
5167 * pSSM->u.Read.fEndOfData. When a termination record is encounter, it will be
5168 * read in full and validated, the fEndOfData indicator is set, and VINF_SUCCESS
5169 * is returned.
5170 *
5171 * @returns VBox status code.
5172 * @param pSSM The saved state handle.
5173 */
5174static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM)
5175{
5176 AssertLogRelReturn(!pSSM->u.Read.fEndOfData, VERR_SSM_LOADED_TOO_MUCH);
5177
5178 /*
5179 * Read the two mandatory bytes.
5180 */
5181 uint8_t abHdr[8];
5182 int rc = ssmR3DataReadV2Raw(pSSM, abHdr, 2);
5183 if (RT_FAILURE(rc))
5184 return rc;
5185
5186 /*
5187 * Validate the first byte and check for the termination records.
5188 */
5189 pSSM->u.Read.u8TypeAndFlags = abHdr[0];
5190 AssertLogRelMsgReturn(SSM_REC_ARE_TYPE_AND_FLAGS_VALID(abHdr[0]), ("%#x %#x\n", abHdr[0], abHdr[1]), VERR_SSM_INTEGRITY);
5191 if ((abHdr[0] & SSM_REC_TYPE_MASK) == SSM_REC_TYPE_TERM)
5192 {
5193 pSSM->u.Read.cbRecLeft = 0;
5194 pSSM->u.Read.fEndOfData = true;
5195 AssertLogRelMsgReturn(abHdr[1] == sizeof(SSMRECTERM) - 2, ("%#x\n", abHdr[1]), VERR_SSM_INTEGRITY);
5196 AssertLogRelMsgReturn(abHdr[0] & SSM_REC_FLAGS_IMPORTANT, ("%#x\n", abHdr[0]), VERR_SSM_INTEGRITY);
5197
5198 /* get the rest */
5199 uint32_t u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm);
5200 SSMRECTERM TermRec;
5201 int rc = ssmR3DataReadV2Raw(pSSM, (uint8_t *)&TermRec + 2, sizeof(SSMRECTERM) - 2);
5202 if (RT_FAILURE(rc))
5203 return rc;
5204
5205 /* validate integrity */
5206 AssertLogRelMsgReturn(TermRec.cbUnit == pSSM->offUnit,
5207 ("cbUnit=%#llx offUnit=%#llx\n", TermRec.cbUnit, pSSM->offUnit),
5208 VERR_SSM_INTEGRITY);
5209 AssertLogRelMsgReturn(!(TermRec.fFlags & ~SSMRECTERM_FLAGS_CRC32), ("%#x\n", TermRec.fFlags), VERR_SSM_INTEGRITY);
5210 if (!(TermRec.fFlags & SSMRECTERM_FLAGS_CRC32))
5211 AssertLogRelMsgReturn(TermRec.u32StreamCRC == 0, ("%#x\n", TermRec.u32StreamCRC), VERR_SSM_INTEGRITY);
5212 else if (pSSM->Strm.fChecksummed)
5213 AssertLogRelMsgReturn(TermRec.u32StreamCRC == u32StreamCRC, ("%#x, %#x\n", TermRec.u32StreamCRC, u32StreamCRC), VERR_SSM_INTEGRITY_CRC);
5214
5215 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx: TERM\n", ssmR3StrmTell(&pSSM->Strm) - sizeof(SSMRECTERM), pSSM->offUnit));
5216 return VINF_SUCCESS;
5217 }
5218
5219 /*
5220 * Figure the size. The 2nd byte is encoded in UTF-8 fashion, so this
5221 * is can be highly enjoyable.
5222 */
5223 uint32_t cbHdr = 2;
5224 uint32_t cb = abHdr[1];
5225 if (!(cb & 0x80))
5226 pSSM->u.Read.cbRecLeft = cb;
5227 else
5228 {
5229 /*
5230 * Need more data. Figure how much and read it.
5231 */
5232 if (!(cb & RT_BIT(5)))
5233 cb = 2;
5234 else if (!(cb & RT_BIT(4)))
5235 cb = 3;
5236 else if (!(cb & RT_BIT(3)))
5237 cb = 4;
5238 else if (!(cb & RT_BIT(2)))
5239 cb = 5;
5240 else if (!(cb & RT_BIT(1)))
5241 cb = 6;
5242 else
5243 AssertLogRelMsgFailedReturn(("Invalid record size byte: %#x\n", cb), VERR_SSM_INTEGRITY);
5244 cbHdr = cb + 1;
5245
5246 rc = ssmR3DataReadV2Raw(pSSM, &abHdr[2], cb - 1);
5247 if (RT_FAILURE(rc))
5248 return rc;
5249
5250 /*
5251 * Validate what we've read.
5252 */
5253 switch (cb)
5254 {
5255 case 6:
5256 AssertLogRelMsgReturn((abHdr[6] & 0xc0) == 0x80, ("6/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
5257 case 5:
5258 AssertLogRelMsgReturn((abHdr[5] & 0xc0) == 0x80, ("5/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
5259 case 4:
5260 AssertLogRelMsgReturn((abHdr[4] & 0xc0) == 0x80, ("4/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
5261 case 3:
5262 AssertLogRelMsgReturn((abHdr[3] & 0xc0) == 0x80, ("3/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
5263 case 2:
5264 AssertLogRelMsgReturn((abHdr[2] & 0xc0) == 0x80, ("2/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
5265 break;
5266 default:
5267 return VERR_INTERNAL_ERROR;
5268 }
5269
5270 /*
5271 * Decode it and validate the range.
5272 */
5273 switch (cb)
5274 {
5275 case 6:
5276 cb = (abHdr[6] & 0x3f)
5277 | ((uint32_t)(abHdr[5] & 0x3f) << 6)
5278 | ((uint32_t)(abHdr[4] & 0x3f) << 12)
5279 | ((uint32_t)(abHdr[3] & 0x3f) << 18)
5280 | ((uint32_t)(abHdr[2] & 0x3f) << 24)
5281 | ((uint32_t)(abHdr[1] & 0x01) << 30);
5282 AssertLogRelMsgReturn(cb >= 0x04000000 && cb <= 0x7fffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
5283 break;
5284 case 5:
5285 cb = (abHdr[5] & 0x3f)
5286 | ((uint32_t)(abHdr[4] & 0x3f) << 6)
5287 | ((uint32_t)(abHdr[3] & 0x3f) << 12)
5288 | ((uint32_t)(abHdr[2] & 0x3f) << 18)
5289 | ((uint32_t)(abHdr[1] & 0x03) << 24);
5290 AssertLogRelMsgReturn(cb >= 0x00200000 && cb <= 0x03ffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
5291 break;
5292 case 4:
5293 cb = (abHdr[4] & 0x3f)
5294 | ((uint32_t)(abHdr[3] & 0x3f) << 6)
5295 | ((uint32_t)(abHdr[2] & 0x3f) << 12)
5296 | ((uint32_t)(abHdr[1] & 0x07) << 18);
5297 AssertLogRelMsgReturn(cb >= 0x00010000 && cb <= 0x001fffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
5298 break;
5299 case 3:
5300 cb = (abHdr[3] & 0x3f)
5301 | ((uint32_t)(abHdr[2] & 0x3f) << 6)
5302 | ((uint32_t)(abHdr[1] & 0x0f) << 12);
5303#if 0 /* disabled to optimize buffering */
5304 AssertLogRelMsgReturn(cb >= 0x00000800 && cb <= 0x0000ffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
5305#endif
5306 break;
5307 case 2:
5308 cb = (abHdr[2] & 0x3f)
5309 | ((uint32_t)(abHdr[1] & 0x1f) << 6);
5310#if 0 /* disabled to optimize buffering */
5311 AssertLogRelMsgReturn(cb >= 0x00000080 && cb <= 0x000007ff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
5312#endif
5313 break;
5314 default:
5315 return VERR_INTERNAL_ERROR;
5316 }
5317
5318 pSSM->u.Read.cbRecLeft = cb;
5319 }
5320
5321 Log3(("ssmR3DataReadRecHdrV2: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
5322 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft,
5323 pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK,
5324 !!(pSSM->u.Read.u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT),
5325 cbHdr
5326 )); NOREF(cbHdr);
5327 return VINF_SUCCESS;
5328}
5329
5330
5331/**
5332 * Buffer miss, do an unbuffered read.
5333 *
5334 * @param pSSM SSM operation handle.
5335 * @param pvBuf Where to store the read data.
5336 * @param cbBuf Number of bytes to read.
5337 */
5338static int ssmR3DataReadUnbufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5339{
5340 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
5341 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
5342
5343 /*
5344 * Copy out what we've got in the buffer.
5345 */
5346 uint32_t off = pSSM->u.Read.offDataBuffer;
5347 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
5348 Log4(("ssmR3DataReadUnbufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
5349 if (cbInBuffer > 0)
5350 {
5351 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
5352 Assert(cbBuf > cbToCopy);
5353 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
5354 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5355 cbBuf -= cbToCopy;
5356 pSSM->u.Read.cbDataBuffer = 0;
5357 pSSM->u.Read.offDataBuffer = 0;
5358 }
5359
5360 /*
5361 * Read data.
5362 */
5363 do
5364 {
5365 /*
5366 * Read the next record header if no more data.
5367 */
5368 if (!pSSM->u.Read.cbRecLeft)
5369 {
5370 int rc = ssmR3DataReadRecHdrV2(pSSM);
5371 if (RT_FAILURE(rc))
5372 return pSSM->rc = rc;
5373 }
5374 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
5375
5376 /*
5377 * Read data from the current record.
5378 */
5379 uint32_t cbToRead;
5380 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
5381 {
5382 case SSM_REC_TYPE_RAW:
5383 {
5384 cbToRead = (uint32_t)RT_MIN(cbBuf, pSSM->u.Read.cbRecLeft);
5385 int rc = ssmR3DataReadV2Raw(pSSM, pvBuf, cbToRead);
5386 if (RT_FAILURE(rc))
5387 return pSSM->rc = rc;
5388 pSSM->u.Read.cbRecLeft -= cbToRead;
5389 break;
5390 }
5391
5392 case SSM_REC_TYPE_RAW_LZF:
5393 {
5394 uint32_t cbDecompr;
5395 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbDecompr);
5396 if (RT_FAILURE(rc))
5397 return rc;
5398 if (cbBuf >= cbDecompr)
5399 {
5400 cbToRead = cbDecompr;
5401 rc = ssmR3DataReadV2RawLzf(pSSM, pvBuf, cbDecompr);
5402 if (RT_FAILURE(rc))
5403 return rc;
5404 }
5405 else
5406 {
5407 /* output buffer is too small, use the data buffer. */
5408 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbDecompr);
5409 if (RT_FAILURE(rc))
5410 return rc;
5411 cbToRead = (uint32_t)cbBuf;
5412 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5413 pSSM->u.Read.cbDataBuffer = cbDecompr;
5414 pSSM->u.Read.offDataBuffer = cbToRead;
5415 }
5416 break;
5417 }
5418
5419 default:
5420 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), VERR_INTERNAL_ERROR_5);
5421 }
5422
5423 cbBuf -= cbToRead;
5424 pvBuf = (uint8_t *)pvBuf + cbToRead;
5425 } while (cbBuf > 0);
5426
5427 Log4(("ssmR3DataReadUnBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
5428 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, 0, cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
5429 return VINF_SUCCESS;
5430}
5431
5432
5433/**
5434 * Buffer miss, do a buffered read.
5435 *
5436 * @param pSSM SSM operation handle.
5437 * @param pvBuf Where to store the read data.
5438 * @param cbBuf Number of bytes to read.
5439 */
5440static int ssmR3DataReadBufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5441{
5442 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
5443 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
5444
5445 /*
5446 * Copy out what we've got in the buffer.
5447 */
5448 uint32_t off = pSSM->u.Read.offDataBuffer;
5449 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
5450 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n", ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
5451 if (cbInBuffer > 0)
5452 {
5453 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
5454 Assert(cbBuf > cbToCopy);
5455 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
5456 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5457 cbBuf -= cbToCopy;
5458 pSSM->u.Read.cbDataBuffer = 0;
5459 pSSM->u.Read.offDataBuffer = 0;
5460 }
5461
5462 /*
5463 * Buffer more data.
5464 */
5465 do
5466 {
5467 /*
5468 * Read the next record header if no more data.
5469 */
5470 if (!pSSM->u.Read.cbRecLeft)
5471 {
5472 int rc = ssmR3DataReadRecHdrV2(pSSM);
5473 if (RT_FAILURE(rc))
5474 return pSSM->rc = rc;
5475 }
5476 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
5477
5478 /*
5479 * Read data from the current record.
5480 * LATER: optimize by reading directly into the output buffer for some cases.
5481 */
5482 uint32_t cbToRead;
5483 switch (pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK)
5484 {
5485 case SSM_REC_TYPE_RAW:
5486 {
5487 cbToRead = RT_MIN(sizeof(pSSM->u.Read.abDataBuffer), pSSM->u.Read.cbRecLeft);
5488 int rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5489 if (RT_FAILURE(rc))
5490 return pSSM->rc = rc;
5491 pSSM->u.Read.cbRecLeft -= cbToRead;
5492 pSSM->u.Read.cbDataBuffer = cbToRead;
5493 break;
5494 }
5495
5496 case SSM_REC_TYPE_RAW_LZF:
5497 {
5498 uint32_t cbDecompr;
5499 int rc = ssmR3DataReadV2RawLzfHdr(pSSM, &cbDecompr);
5500 if (RT_FAILURE(rc))
5501 return rc;
5502 cbToRead = cbDecompr;
5503 rc = ssmR3DataReadV2RawLzf(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
5504 if (RT_FAILURE(rc))
5505 return rc;
5506 pSSM->u.Read.cbDataBuffer = cbToRead;
5507 break;
5508 }
5509
5510 default:
5511 AssertMsgFailedReturn(("%x\n", pSSM->u.Read.u8TypeAndFlags), VERR_INTERNAL_ERROR_5);
5512 }
5513 /*pSSM->u.Read.offDataBuffer = 0;*/
5514
5515 /*
5516 * Copy data from the buffer.
5517 */
5518 uint32_t cbToCopy = (uint32_t)RT_MIN(cbBuf, cbToRead);
5519 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToCopy);
5520 cbBuf -= cbToCopy;
5521 pvBuf = (uint8_t *)pvBuf + cbToCopy;
5522 pSSM->u.Read.offDataBuffer = cbToCopy;
5523 } while (cbBuf > 0);
5524
5525 Log4(("ssmR3DataReadBufferedV2: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
5526 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
5527 cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
5528 return VINF_SUCCESS;
5529}
5530
5531
5532/**
5533 * Inlined worker that handles format checks and buffered reads.
5534 *
5535 * @param pSSM SSM operation handle.
5536 * @param pvBuf Where to store the read data.
5537 * @param cbBuf Number of bytes to read.
5538 */
5539DECLINLINE(int) ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
5540{
5541 /*
5542 * Fend off previous errors and V1 data units.
5543 */
5544 if (RT_FAILURE(pSSM->rc))
5545 return pSSM->rc;
5546 if (RT_UNLIKELY(pSSM->u.Read.uFmtVerMajor == 1))
5547 return ssmR3DataReadV1(pSSM, pvBuf, cbBuf);
5548
5549 /*
5550 * Check if the requested data is buffered.
5551 */
5552 uint32_t off = pSSM->u.Read.offDataBuffer;
5553 if ( off + cbBuf > pSSM->u.Read.cbDataBuffer
5554 || cbBuf > sizeof(pSSM->u.Read.abDataBuffer))
5555 {
5556 if (cbBuf <= sizeof(pSSM->u.Read.abDataBuffer) / 8)
5557 return ssmR3DataReadBufferedV2(pSSM, pvBuf, cbBuf);
5558 return ssmR3DataReadUnbufferedV2(pSSM, pvBuf, cbBuf);
5559 }
5560
5561 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbBuf);
5562 pSSM->u.Read.offDataBuffer = off + (uint32_t)cbBuf;
5563 Log4((cbBuf
5564 ? "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n"
5565 : "ssmR3DataRead: %08llx|%08llx/%08x/%08x: cbBuf=%#x\n",
5566 ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
5567 cbBuf, RT_MIN(SSM_LOG_BYTES, cbBuf), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
5568
5569 return VINF_SUCCESS;
5570}
5571
5572
5573/**
5574 * Gets a structure.
5575 *
5576 * @returns VBox status code.
5577 * @param pSSM The saved state handle.
5578 * @param pvStruct The structure address.
5579 * @param paFields The array of structure fields descriptions.
5580 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
5581 */
5582VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
5583{
5584 /* begin marker. */
5585 uint32_t u32Magic;
5586 int rc = SSMR3GetU32(pSSM, &u32Magic);
5587 if (RT_FAILURE(rc))
5588 return rc;
5589 if (u32Magic != SSMR3STRUCT_BEGIN)
5590 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
5591
5592 /* put the fields */
5593 for (PCSSMFIELD pCur = paFields;
5594 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
5595 pCur++)
5596 {
5597 rc = ssmR3DataRead(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
5598 if (RT_FAILURE(rc))
5599 return rc;
5600 }
5601
5602 /* end marker */
5603 rc = SSMR3GetU32(pSSM, &u32Magic);
5604 if (RT_FAILURE(rc))
5605 return rc;
5606 if (u32Magic != SSMR3STRUCT_END)
5607 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
5608 return rc;
5609}
5610
5611
5612/**
5613 * Loads a boolean item from the current data unit.
5614 *
5615 * @returns VBox status.
5616 * @param pSSM SSM operation handle.
5617 * @param pfBool Where to store the item.
5618 */
5619VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
5620{
5621 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5622 {
5623 uint8_t u8; /* see SSMR3PutBool */
5624 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
5625 if (RT_SUCCESS(rc))
5626 {
5627 Assert(u8 <= 1);
5628 *pfBool = !!u8;
5629 }
5630 return rc;
5631 }
5632 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5633 return VERR_SSM_INVALID_STATE;
5634}
5635
5636
5637/**
5638 * Loads a 8-bit unsigned integer item from the current data unit.
5639 *
5640 * @returns VBox status.
5641 * @param pSSM SSM operation handle.
5642 * @param pu8 Where to store the item.
5643 */
5644VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
5645{
5646 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5647 return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
5648 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5649 return VERR_SSM_INVALID_STATE;
5650}
5651
5652
5653/**
5654 * Loads a 8-bit signed integer item from the current data unit.
5655 *
5656 * @returns VBox status.
5657 * @param pSSM SSM operation handle.
5658 * @param pi8 Where to store the item.
5659 */
5660VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
5661{
5662 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5663 return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
5664 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5665 return VERR_SSM_INVALID_STATE;
5666}
5667
5668
5669/**
5670 * Loads a 16-bit unsigned integer item from the current data unit.
5671 *
5672 * @returns VBox status.
5673 * @param pSSM SSM operation handle.
5674 * @param pu16 Where to store the item.
5675 */
5676VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
5677{
5678 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5679 return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
5680 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5681 return VERR_SSM_INVALID_STATE;
5682}
5683
5684
5685/**
5686 * Loads a 16-bit signed integer item from the current data unit.
5687 *
5688 * @returns VBox status.
5689 * @param pSSM SSM operation handle.
5690 * @param pi16 Where to store the item.
5691 */
5692VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
5693{
5694 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5695 return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
5696 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5697 return VERR_SSM_INVALID_STATE;
5698}
5699
5700
5701/**
5702 * Loads a 32-bit unsigned integer item from the current data unit.
5703 *
5704 * @returns VBox status.
5705 * @param pSSM SSM operation handle.
5706 * @param pu32 Where to store the item.
5707 */
5708VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
5709{
5710 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5711 return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
5712 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5713 return VERR_SSM_INVALID_STATE;
5714}
5715
5716
5717/**
5718 * Loads a 32-bit signed integer item from the current data unit.
5719 *
5720 * @returns VBox status.
5721 * @param pSSM SSM operation handle.
5722 * @param pi32 Where to store the item.
5723 */
5724VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
5725{
5726 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5727 return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
5728 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5729 return VERR_SSM_INVALID_STATE;
5730}
5731
5732
5733/**
5734 * Loads a 64-bit unsigned integer item from the current data unit.
5735 *
5736 * @returns VBox status.
5737 * @param pSSM SSM operation handle.
5738 * @param pu64 Where to store the item.
5739 */
5740VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
5741{
5742 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5743 return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
5744 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5745 return VERR_SSM_INVALID_STATE;
5746}
5747
5748
5749/**
5750 * Loads a 64-bit signed integer item from the current data unit.
5751 *
5752 * @returns VBox status.
5753 * @param pSSM SSM operation handle.
5754 * @param pi64 Where to store the item.
5755 */
5756VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
5757{
5758 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5759 return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
5760 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5761 return VERR_SSM_INVALID_STATE;
5762}
5763
5764
5765/**
5766 * Loads a 128-bit unsigned integer item from the current data unit.
5767 *
5768 * @returns VBox status.
5769 * @param pSSM SSM operation handle.
5770 * @param pu128 Where to store the item.
5771 */
5772VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
5773{
5774 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5775 return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
5776 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5777 return VERR_SSM_INVALID_STATE;
5778}
5779
5780
5781/**
5782 * Loads a 128-bit signed integer item from the current data unit.
5783 *
5784 * @returns VBox status.
5785 * @param pSSM SSM operation handle.
5786 * @param pi128 Where to store the item.
5787 */
5788VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
5789{
5790 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5791 return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
5792 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5793 return VERR_SSM_INVALID_STATE;
5794}
5795
5796
5797/**
5798 * Loads a VBox unsigned integer item from the current data unit.
5799 *
5800 * @returns VBox status.
5801 * @param pSSM SSM operation handle.
5802 * @param pu Where to store the integer.
5803 */
5804VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
5805{
5806 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5807 return ssmR3DataRead(pSSM, pu, sizeof(*pu));
5808 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5809 return VERR_SSM_INVALID_STATE;
5810}
5811
5812
5813/**
5814 * Loads a VBox signed integer item from the current data unit.
5815 *
5816 * @returns VBox status.
5817 * @param pSSM SSM operation handle.
5818 * @param pi Where to store the integer.
5819 */
5820VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
5821{
5822 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5823 return ssmR3DataRead(pSSM, pi, sizeof(*pi));
5824 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5825 return VERR_SSM_INVALID_STATE;
5826}
5827
5828
5829/**
5830 * Loads a GC natural unsigned integer item from the current data unit.
5831 *
5832 * @returns VBox status.
5833 * @param pSSM SSM operation handle.
5834 * @param pu Where to store the integer.
5835 *
5836 * @deprecated Silly type with an incorrect size, don't use it.
5837 */
5838VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
5839{
5840 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
5841 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
5842}
5843
5844
5845/**
5846 * Loads a GC unsigned integer register item from the current data unit.
5847 *
5848 * @returns VBox status.
5849 * @param pSSM SSM operation handle.
5850 * @param pu Where to store the integer.
5851 */
5852VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu)
5853{
5854 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
5855 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
5856}
5857
5858
5859/**
5860 * Loads a 32 bits GC physical address item from the current data unit.
5861 *
5862 * @returns VBox status.
5863 * @param pSSM SSM operation handle.
5864 * @param pGCPhys Where to store the GC physical address.
5865 */
5866VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
5867{
5868 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5869 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5870 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5871 return VERR_SSM_INVALID_STATE;
5872}
5873
5874
5875/**
5876 * Loads a 64 bits GC physical address item from the current data unit.
5877 *
5878 * @returns VBox status.
5879 * @param pSSM SSM operation handle.
5880 * @param pGCPhys Where to store the GC physical address.
5881 */
5882VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
5883{
5884 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5885 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5886 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5887 return VERR_SSM_INVALID_STATE;
5888}
5889
5890
5891/**
5892 * Loads a GC physical address item from the current data unit.
5893 *
5894 * @returns VBox status.
5895 * @param pSSM SSM operation handle.
5896 * @param pGCPhys Where to store the GC physical address.
5897 */
5898VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
5899{
5900 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5901 {
5902 if (RT_LIKELY(sizeof(*pGCPhys) == pSSM->u.Read.cbGCPhys))
5903 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
5904
5905 /*
5906 * Fiddly.
5907 */
5908 Assert(sizeof(*pGCPhys) == sizeof(uint64_t) || sizeof(*pGCPhys) == sizeof(uint32_t));
5909 Assert(pSSM->u.Read.cbGCPhys == sizeof(uint64_t) || pSSM->u.Read.cbGCPhys == sizeof(uint32_t));
5910 if (pSSM->u.Read.cbGCPhys == sizeof(uint64_t))
5911 {
5912 /* 64-bit saved, 32-bit load: try truncate it. */
5913 uint64_t u64;
5914 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
5915 if (RT_FAILURE(rc))
5916 return rc;
5917 if (u64 >= _4G)
5918 return VERR_SSM_GCPHYS_OVERFLOW;
5919 *pGCPhys = (RTGCPHYS)u64;
5920 return rc;
5921 }
5922
5923 /* 32-bit saved, 64-bit load: clear the high part. */
5924 *pGCPhys = 0;
5925 return ssmR3DataRead(pSSM, pGCPhys, sizeof(uint32_t));
5926 }
5927 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
5928 return VERR_SSM_INVALID_STATE;
5929}
5930
5931
5932/**
5933 * Loads a GC virtual address item from the current data unit.
5934 *
5935 * Only applies to in the 1.1 format:
5936 * - SSMR3GetGCPtr
5937 * - SSMR3GetGCUIntPtr
5938 * - SSMR3GetGCUInt
5939 * - SSMR3GetGCUIntReg
5940 *
5941 * Put functions are not affected.
5942 *
5943 * @returns VBox status.
5944 * @param pSSM SSM operation handle.
5945 * @param cbGCPtr Size of RTGCPTR
5946 *
5947 * @remarks This interface only works with saved state version 1.1, if the
5948 * format isn't 1.1 the call will be ignored.
5949 */
5950VMMR3DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
5951{
5952 Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
5953 if (!pSSM->u.Read.fFixedGCPtrSize)
5954 {
5955 Log(("SSMR3SetGCPtrSize: %u -> %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
5956 pSSM->u.Read.cbGCPtr = cbGCPtr;
5957 pSSM->u.Read.fFixedGCPtrSize = true;
5958 }
5959 else if ( pSSM->u.Read.cbGCPtr != cbGCPtr
5960 && pSSM->u.Read.cbFileHdr == sizeof(SSMFILEHDRV11))
5961 AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %u bytes; requested %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
5962
5963 return VINF_SUCCESS;
5964}
5965
5966
5967/**
5968 * Loads a GC virtual address item from the current data unit.
5969 *
5970 * @returns VBox status.
5971 * @param pSSM SSM operation handle.
5972 * @param pGCPtr Where to store the GC virtual address.
5973 */
5974VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
5975{
5976 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
5977 {
5978 if (RT_LIKELY(sizeof(*pGCPtr) == pSSM->u.Read.cbGCPtr))
5979 return ssmR3DataRead(pSSM, pGCPtr, sizeof(*pGCPtr));
5980
5981 /*
5982 * Fiddly.
5983 */
5984 Assert(sizeof(*pGCPtr) == sizeof(uint64_t) || sizeof(*pGCPtr) == sizeof(uint32_t));
5985 Assert(pSSM->u.Read.cbGCPtr == sizeof(uint64_t) || pSSM->u.Read.cbGCPtr == sizeof(uint32_t));
5986 if (pSSM->u.Read.cbGCPtr == sizeof(uint64_t))
5987 {
5988 /* 64-bit saved, 32-bit load: try truncate it. */
5989 uint64_t u64;
5990 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
5991 if (RT_FAILURE(rc))
5992 return rc;
5993 if (u64 >= _4G)
5994 return VERR_SSM_GCPTR_OVERFLOW;
5995 *pGCPtr = (RTGCPTR)u64;
5996 return rc;
5997 }
5998
5999 /* 32-bit saved, 64-bit load: clear the high part. */
6000 *pGCPtr = 0;
6001 return ssmR3DataRead(pSSM, pGCPtr, sizeof(uint32_t));
6002 }
6003 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6004 return VERR_SSM_INVALID_STATE;
6005}
6006
6007
6008/**
6009 * Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
6010 *
6011 * @returns VBox status.
6012 * @param pSSM SSM operation handle.
6013 * @param pGCPtr Where to store the GC virtual address.
6014 */
6015VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
6016{
6017 AssertCompile(sizeof(RTGCPTR) == sizeof(*pGCPtr));
6018 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pGCPtr);
6019}
6020
6021
6022/**
6023 * Loads an RC virtual address item from the current data unit.
6024 *
6025 * @returns VBox status.
6026 * @param pSSM SSM operation handle.
6027 * @param pRCPtr Where to store the RC virtual address.
6028 */
6029VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
6030{
6031 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
6032 return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
6033
6034 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6035 return VERR_SSM_INVALID_STATE;
6036}
6037
6038
6039/**
6040 * Loads a I/O port address item from the current data unit.
6041 *
6042 * @returns VBox status.
6043 * @param pSSM SSM operation handle.
6044 * @param pIOPort Where to store the I/O port address.
6045 */
6046VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
6047{
6048 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
6049 return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
6050 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6051 return VERR_SSM_INVALID_STATE;
6052}
6053
6054
6055/**
6056 * Loads a selector item from the current data unit.
6057 *
6058 * @returns VBox status.
6059 * @param pSSM SSM operation handle.
6060 * @param pSel Where to store the selector.
6061 */
6062VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
6063{
6064 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
6065 return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
6066 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6067 return VERR_SSM_INVALID_STATE;
6068}
6069
6070
6071/**
6072 * Loads a memory item from the current data unit.
6073 *
6074 * @returns VBox status.
6075 * @param pSSM SSM operation handle.
6076 * @param pv Where to store the item.
6077 * @param cb Size of the item.
6078 */
6079VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
6080{
6081 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
6082 return ssmR3DataRead(pSSM, pv, cb);
6083 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6084 return VERR_SSM_INVALID_STATE;
6085}
6086
6087
6088/**
6089 * Loads a string item from the current data unit.
6090 *
6091 * @returns VBox status.
6092 * @param pSSM SSM operation handle.
6093 * @param psz Where to store the item.
6094 * @param cbMax Max size of the item (including '\\0').
6095 */
6096VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
6097{
6098 return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
6099}
6100
6101
6102/**
6103 * Loads a string item from the current data unit.
6104 *
6105 * @returns VBox status.
6106 * @param pSSM SSM operation handle.
6107 * @param psz Where to store the item.
6108 * @param cbMax Max size of the item (including '\\0').
6109 * @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
6110 */
6111VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
6112{
6113 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
6114 {
6115 /* read size prefix. */
6116 uint32_t u32;
6117 int rc = SSMR3GetU32(pSSM, &u32);
6118 if (RT_SUCCESS(rc))
6119 {
6120 if (pcbStr)
6121 *pcbStr = u32;
6122 if (u32 < cbMax)
6123 {
6124 /* terminate and read string content. */
6125 psz[u32] = '\0';
6126 return ssmR3DataRead(pSSM, psz, u32);
6127 }
6128 return VERR_TOO_MUCH_DATA;
6129 }
6130 return rc;
6131 }
6132 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
6133 return VERR_SSM_INVALID_STATE;
6134}
6135
6136
6137/**
6138 * Skips a number of bytes in the current data unit.
6139 *
6140 * @returns VBox status code.
6141 * @param pSSM The SSM handle.
6142 * @param cb The number of bytes to skip.
6143 */
6144VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
6145{
6146 AssertMsgReturn( pSSM->enmOp == SSMSTATE_LOAD_EXEC
6147 || pSSM->enmOp == SSMSTATE_OPEN_READ,
6148 ("Invalid state %d\n", pSSM->enmOp),
6149 VERR_SSM_INVALID_STATE);
6150 while (cb > 0)
6151 {
6152 uint8_t abBuf[8192];
6153 size_t cbCur = RT_MIN(sizeof(abBuf), cb);
6154 cb -= cbCur;
6155 int rc = ssmR3DataRead(pSSM, abBuf, cbCur);
6156 if (RT_FAILURE(rc))
6157 return rc;
6158 }
6159
6160 return VINF_SUCCESS;
6161}
6162
6163
6164/**
6165 * Query what the VBox status code of the operation is.
6166 *
6167 * This can be used for putting and getting a batch of values
6168 * without bother checking the result till all the calls have
6169 * been made.
6170 *
6171 * @returns SSMAFTER enum value.
6172 * @param pSSM SSM operation handle.
6173 */
6174VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
6175{
6176 return pSSM->rc;
6177}
6178
6179
6180/**
6181 * Fail the load operation.
6182 *
6183 * This is mainly intended for sub item loaders (like timers) which
6184 * return code isn't necessarily heeded by the caller but is important
6185 * to SSM.
6186 *
6187 * @returns SSMAFTER enum value.
6188 * @param pSSM SSM operation handle.
6189 * @param iStatus Failure status code. This MUST be a VERR_*.
6190 */
6191VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
6192{
6193 if (RT_FAILURE(iStatus))
6194 {
6195 if (RT_SUCCESS(pSSM->rc))
6196 pSSM->rc = iStatus;
6197 return pSSM->rc = iStatus;
6198 }
6199 AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
6200 return VERR_INVALID_PARAMETER;
6201}
6202
6203
6204/**
6205 * Get what to do after this operation.
6206 *
6207 * @returns SSMAFTER enum value.
6208 * @param pSSM SSM operation handle.
6209 */
6210VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
6211{
6212 return pSSM->enmAfter;
6213}
6214
6215
6216/**
6217 * Get the current unit byte offset (uncompressed).
6218 *
6219 * @returns The offset. UINT64_MAX if called at a wrong time.
6220 * @param pSSM SSM operation handle.
6221 */
6222VMMR3DECL(uint64_t) SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM)
6223{
6224 return pSSM->offUnit;
6225}
6226
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