VirtualBox

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

Last change on this file since 21845 was 21799, checked in by vboxsync, 16 years ago

Fixed old SSMR3Seek.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 172.5 KB
Line 
1/* $Id: SSM-new.cpp 21799 2009-07-25 23:34:24Z 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: Named data - length prefixed name followed by the data.
102 * - types 4 thru 15 are current undefined.
103 * - bit 4: Important (set), can be skipped (clear).
104 * - bit 5: Undefined flag, must be zero.
105 * - bit 6: Undefined flag, must be zero.
106 * - bit 7: "magic" bit, always set.
107 *
108 * Record header byte 2 (optionally thru 7) is the size of the following data
109 * encoded in UTF-8 style.
110 *
111 * The data part of the unit is compressed using LZF (via RTZip).
112 *
113 * (In version 1.2 and earlier the unit header also contained the compressed
114 * size of the data, i.e. it was updated after the data was written, and the
115 * data was not record based.)
116 *
117 *
118 * @section sec_ssm_future Future Changes
119 *
120 * There are plans to extend SSM to make it easier to be both backwards and
121 * (somewhat) forwards compatible. One of the new features will be being able
122 * to classify units and data items as unimportant (added to the format in
123 * v2.0). Another suggested feature is naming data items (also added to the
124 * format in v2.0), perhaps by extending the SSMR3PutStruct API. Both features
125 * will require API changes, the naming may possibly require both buffering of
126 * the stream as well as some helper managing them.
127 */
128
129
130/*******************************************************************************
131* Header Files *
132*******************************************************************************/
133#define LOG_GROUP LOG_GROUP_SSM
134#include <VBox/ssm.h>
135#include <VBox/dbgf.h>
136#include <VBox/mm.h>
137#include "SSMInternal.h"
138#include <VBox/vm.h>
139#include <VBox/err.h>
140#include <VBox/log.h>
141#include <VBox/version.h>
142
143#include <iprt/assert.h>
144#include <iprt/file.h>
145#include <iprt/alloc.h>
146#include <iprt/uuid.h>
147#include <iprt/zip.h>
148#include <iprt/crc32.h>
149#include <iprt/thread.h>
150#include <iprt/string.h>
151
152
153/*******************************************************************************
154* Defined Constants And Macros *
155*******************************************************************************/
156/** The special value for the final phase. */
157#define SSM_PHASE_FINAL UINT32_MAX
158
159/** The max length of a unit name. */
160#define SSM_MAX_NAME_SIZE 48
161
162/** Saved state file magic base string. */
163#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
164/** Saved state file magic indicating version 1.x. */
165#define SSMFILEHDR_MAGIC_V1_X "\177VirtualBox SavedState V1."
166/** Saved state file v1.1 magic. */
167#define SSMFILEHDR_MAGIC_V1_1 "\177VirtualBox SavedState V1.1\n"
168/** Saved state file v1.2 magic. */
169#define SSMFILEHDR_MAGIC_V1_2 "\177VirtualBox SavedState V1.2\n\0\0\0"
170/** Saved state file v2.0 magic. */
171#define SSMFILEHDR_MAGIC_V2_0 "\177VirtualBox SavedState V2.0\n\0\0\0"
172
173/** @name SSMFILEHDR::fFlags
174 * @{ */
175/** The stream is checkesummed up to the footer using CRC-32. */
176#define SSMFILEHDR_FLAGS_STREAM_CRC32 RT_BIT_32(0)
177/** @} */
178
179/** The directory magic. */
180#define SSMFILEDIR_MAGIC "\nDir\n\0\0"
181
182/** Saved state file v2.0 magic. */
183#define SSMFILEFTR_MAGIC "\nFooter"
184
185/** Data unit magic. */
186#define SSMFILEUNITHDR_MAGIC "\nUnit\n\0"
187/** Data end marker magic. */
188#define SSMFILEUNITHDR_END "\nTheEnd"
189
190
191/** @name Record Types (data unit)
192 * @{ */
193/** The record type mask. */
194#define SSM_REC_TYPE_MASK UINT8_C(0x0f)
195/** Invalid record. */
196#define SSM_REC_TYPE_INVALID 0
197/** Normal termination record, see SSMRECTERM. */
198#define SSM_REC_TYPE_TERM 1
199/** Raw data. The data follows the size field without further ado. */
200#define SSM_REC_TYPE_RAW 2
201/** Named data items.
202 * A length prefix zero terminated string (i.e. max 255) followed by the data. */
203#define SSM_REC_TYPE_NAMED 3
204/** Macro for validating the record type.
205 * This can be used with the flags+type byte, no need to mask out the type first. */
206#define SSM_REC_TYPE_IS_VALID(u8Type) ( ((u8Type) & SSM_REC_TYPE_MASK) > SSM_REC_TYPE_INVALID \
207 && ((u8Type) & SSM_REC_TYPE_MASK) <= SSM_REC_TYPE_NAMED )
208/** @} */
209
210/** The flag mask. */
211#define SSM_REC_FLAGS_MASK UINT8_C(0xf0)
212/** The record is important if this flag is set, if clear it can be omitted. */
213#define SSM_REC_FLAGS_IMPORTANT UINT8_C(0x10)
214/** This flag is always set. */
215#define SSM_REC_FLAGS_FIXED UINT8_C(0x80)
216/** Macro for validating the flags.
217 * No need to mask the flags out of the flags+type byte before invoking this macro. */
218#define SSM_REC_FLAGS_ARE_VALID(fFlags) ( ((fFlags) & UINT8_C(0xe0)) == UINT8_C(0x80) )
219
220/** Macro for validating the type and flags byte in a data record. */
221#define SSM_REC_ARE_TYPE_AND_FLAGS_VALID(u8) ( SSM_REC_FLAGS_ARE_VALID(u8) && SSM_REC_TYPE_IS_VALID(u8) )
222
223/** @name SSMRECTERM::fFlags
224 * @{ */
225/** There is CRC-32 for the data. */
226#define SSMRECTERM_FLAGS_CRC32 UINT16_C(0x0001)
227/** @} */
228
229/** Start structure magic. (Isacc Asimov) */
230#define SSMR3STRUCT_BEGIN 0x19200102
231/** End structure magic. (Isacc Asimov) */
232#define SSMR3STRUCT_END 0x19920406
233
234
235/** Number of bytes to log in Log2 and Log4 statements. */
236#define SSM_LOG_BYTES 16
237
238
239/** Macro for checking the u32CRC field of a structure.
240 * The Msg can assume there are u32ActualCRC and u32CRC in the context. */
241#define SSM_CHECK_CRC32_RET(p, cb, Msg) \
242 do \
243 { \
244 uint32_t u32CRC = (p)->u32CRC; \
245 (p)->u32CRC = 0; \
246 uint32_t u32ActualCRC = RTCrc32((p), (cb)); \
247 (p)->u32CRC = u32CRC; \
248 AssertLogRelMsgReturn(u32ActualCRC == u32CRC, Msg, VERR_SSM_INTEGRITY_CRC); \
249 } while (0)
250
251
252/*******************************************************************************
253* Structures and Typedefs *
254*******************************************************************************/
255/** SSM state. */
256typedef enum SSMSTATE
257{
258 SSMSTATE_INVALID = 0,
259 SSMSTATE_SAVE_PREP,
260 SSMSTATE_SAVE_EXEC,
261 SSMSTATE_SAVE_DONE,
262 SSMSTATE_LOAD_PREP,
263 SSMSTATE_LOAD_EXEC,
264 SSMSTATE_LOAD_DONE,
265 SSMSTATE_OPEN_READ
266} SSMSTATE;
267
268
269/**
270 * Handle structure.
271 */
272typedef struct SSMHANDLE
273{
274 /** The file handle. */
275 RTFILE hFile;
276 /** The VM handle. */
277 PVM pVM;
278 /** The current operation. */
279 SSMSTATE enmOp;
280 /** What to do after save completes. (move the enum) */
281 SSMAFTER enmAfter;
282 /** The current rc of the save operation. */
283 int rc;
284 /** Number of compressed bytes left in the current data unit (V1). */
285 uint64_t cbUnitLeftV1;
286 /** The current uncompressed offset into the data unit. */
287 uint64_t offUnit;
288 /** Whether we're checksumming the unit or not. */
289 bool fUnitChecksummed;
290 /** The unit CRC. */
291 uint32_t u32UnitCRC;
292
293 /** Pointer to the progress callback function. */
294 PFNVMPROGRESS pfnProgress;
295 /** User specified arguemnt to the callback function. */
296 void *pvUser;
297 /** Next completion percentage. (corresponds to offEstProgress) */
298 unsigned uPercent;
299 /** The position of the next progress callback in the estimated file. */
300 uint64_t offEstProgress;
301 /** The estimated total byte count.
302 * (Only valid after the prep.) */
303 uint64_t cbEstTotal;
304 /** Current position in the estimated file. */
305 uint64_t offEst;
306 /** End of current unit in the estimated file. */
307 uint64_t offEstUnitEnd;
308 /** the amount of % we reserve for the 'prepare' phase */
309 unsigned uPercentPrepare;
310 /** the amount of % we reserve for the 'done' stage */
311 unsigned uPercentDone;
312
313 /** Whether we're checksumming reads/writes. */
314 bool fChecksummed;
315 /** The stream CRC if fChecksummed is set. */
316 uint32_t u32StreamCRC;
317
318 union
319 {
320 /** Write data. */
321 struct
322 {
323 /** The compressor of the current data unit. */
324 PRTZIPCOMP pZipComp;
325 /** Offset into the databuffer. */
326 uint32_t offDataBuffer;
327 /** Space for the record header. */
328 uint8_t abRecHdr[1+7];
329 /** Data buffer. */
330 uint8_t abDataBuffer[4096];
331 } Write;
332
333 /** Read data. */
334 struct
335 {
336 /** The decompressor of the current data unit. */
337 PRTZIPDECOMP pZipDecomp;
338 /** The major format version number. */
339 uint32_t uFmtVerMajor;
340 /** The minor format version number. */
341 uint32_t uFmtVerMinor;
342
343 /** V2: Unread bytes in the current record. */
344 uint32_t cbRecLeft;
345 /** V2: Bytes in the data buffer. */
346 uint32_t cbDataBuffer;
347 /** V2: Current buffer position. */
348 uint32_t offDataBuffer;
349 /** V2: End of data indicator. */
350 bool fEndOfData;
351 /** V2: The type and flags byte fo the current record. */
352 uint8_t u8TypeAndFlags;
353
354 /** RTGCPHYS size in bytes. (Only applicable when loading/reading.) */
355 unsigned cbGCPhys;
356 /** RTGCPTR size in bytes. (Only applicable when loading/reading.) */
357 unsigned cbGCPtr;
358 /** Whether cbGCPtr is fixed or settable. */
359 bool fFixedGCPtrSize;
360
361
362 /** @name Header info (set by ssmR3ValidateFile)
363 * @{ */
364 /** The size of the file header. */
365 size_t cbFileHdr;
366 /** The major version number. */
367 uint16_t u16VerMajor;
368 /** The minor version number. */
369 uint16_t u16VerMinor;
370 /** The build number. */
371 uint32_t u32VerBuild;
372 /** The SVN revision. */
373 uint32_t u32SvnRev;
374 /** 32 or 64 depending on the host. */
375 uint8_t cHostBits;
376 /** The CRC of the loaded file. */
377 uint32_t u32LoadCRC;
378 /** The size of the load file. */
379 uint64_t cbLoadFile;
380 /** @} */
381
382 /** V2: Data buffer. */
383 uint8_t abDataBuffer[4096];
384 } Read;
385 } u;
386} SSMHANDLE;
387
388
389/**
390 * Header of the saved state file.
391 *
392 * Added in r5xxxx on 2009-07-2?, VirtualBox v3.0.51.
393 */
394typedef struct SSMFILEHDR
395{
396 /** Magic string which identifies this file as a version of VBox saved state
397 * file format (SSMFILEHDR_MAGIC_V2_0). */
398 char szMagic[32];
399 /** The major version number. */
400 uint16_t u16VerMajor;
401 /** The minor version number. */
402 uint16_t u16VerMinor;
403 /** The build number. */
404 uint32_t u32VerBuild;
405 /** The SVN revision. */
406 uint32_t u32SvnRev;
407 /** 32 or 64 depending on the host. */
408 uint8_t cHostBits;
409 /** The size of RTGCPHYS. */
410 uint8_t cbGCPhys;
411 /** The size of RTGCPTR. */
412 uint8_t cbGCPtr;
413 /** Reserved header space - must be zero. */
414 uint8_t u8Reserved;
415 /** The number of units that (may) have stored data in the file. */
416 uint32_t cUnits;
417 /** Flags, see SSMFILEHDR_FLAGS_XXX. */
418 uint32_t fFlags;
419 /** Reserved header space - must be zero. */
420 uint32_t u32Reserved;
421 /** The checksum of this header.
422 * This field is set to zero when calculating the checksum. */
423 uint32_t u32CRC;
424} SSMFILEHDR;
425AssertCompileSize(SSMFILEHDR, 64);
426AssertCompileMemberOffset(SSMFILEHDR, u32CRC, 60);
427AssertCompileMemberSize(SSMFILEHDR, szMagic, sizeof(SSMFILEHDR_MAGIC_V2_0));
428/** Pointer to a saved state file header. */
429typedef SSMFILEHDR *PSSMFILEHDR;
430/** Pointer to a const saved state file header. */
431typedef SSMFILEHDR const *PCSSMFILEHDR;
432
433
434/**
435 * Header of the saved state file.
436 *
437 * Added in r40980 on 2008-12-15, VirtualBox v2.0.51.
438 *
439 * @remarks This is a superset of SSMFILEHDRV11.
440 */
441typedef struct SSMFILEHDRV12
442{
443 /** Magic string which identifies this file as a version of VBox saved state
444 * file format (SSMFILEHDR_MAGIC_V1_2). */
445 char achMagic[32];
446 /** The size of this file. Used to check
447 * whether the save completed and that things are fine otherwise. */
448 uint64_t cbFile;
449 /** File checksum. The actual calculation skips past the u32CRC field. */
450 uint32_t u32CRC;
451 /** Padding. */
452 uint32_t u32Reserved;
453 /** The machine UUID. (Ignored if NIL.) */
454 RTUUID MachineUuid;
455
456 /** The major version number. */
457 uint16_t u16VerMajor;
458 /** The minor version number. */
459 uint16_t u16VerMinor;
460 /** The build number. */
461 uint32_t u32VerBuild;
462 /** The SVN revision. */
463 uint32_t u32SvnRev;
464
465 /** 32 or 64 depending on the host. */
466 uint8_t cHostBits;
467 /** The size of RTGCPHYS. */
468 uint8_t cbGCPhys;
469 /** The size of RTGCPTR. */
470 uint8_t cbGCPtr;
471 /** Padding. */
472 uint8_t au8Reserved;
473} SSMFILEHDRV12;
474AssertCompileSize(SSMFILEHDRV12, 64+16);
475AssertCompileMemberOffset(SSMFILEHDRV12, u32CRC, 40);
476AssertCompileMemberSize(SSMFILEHDRV12, achMagic, sizeof(SSMFILEHDR_MAGIC_V1_2));
477/** Pointer to a saved state file header. */
478typedef SSMFILEHDRV12 *PSSMFILEHDRV12;
479
480
481/**
482 * Header of the saved state file, version 1.1.
483 *
484 * Added in r23677 on 2007-08-17, VirtualBox v1.4.1.
485 */
486typedef struct SSMFILEHDRV11
487{
488 /** Magic string which identifies this file as a version of VBox saved state
489 * file format (SSMFILEHDR_MAGIC_V1_1). */
490 char achMagic[32];
491 /** The size of this file. Used to check
492 * whether the save completed and that things are fine otherwise. */
493 uint64_t cbFile;
494 /** File checksum. The actual calculation skips past the u32CRC field. */
495 uint32_t u32CRC;
496 /** Padding. */
497 uint32_t u32Reserved;
498 /** The machine UUID. (Ignored if NIL.) */
499 RTUUID MachineUuid;
500} SSMFILEHDRV11;
501AssertCompileSize(SSMFILEHDRV11, 64);
502AssertCompileMemberOffset(SSMFILEHDRV11, u32CRC, 40);
503/** Pointer to a saved state file header. */
504typedef SSMFILEHDRV11 *PSSMFILEHDRV11;
505
506
507/**
508 * Data unit header.
509 */
510typedef struct SSMFILEUNITHDR
511{
512 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
513 char szMagic[8];
514 /** The offset in the saved state stream of the start of this unit.
515 * This is mainly intended for sanity checking. */
516 uint64_t offStream;
517 /** The checksum of this structure, including the whole name.
518 * Calculated with this field set to zero. */
519 uint32_t u32CRC;
520 /** Data version. */
521 uint32_t u32Version;
522 /** Instance number. */
523 uint32_t u32Instance;
524 /** Data phase number. */
525 uint32_t u32Phase;
526 /** Flags reserved for future extensions. Must be zero. */
527 uint32_t fFlags;
528 /** Size of the data unit name including the terminator. (bytes) */
529 uint32_t cbName;
530 /** Data unit name, variable size. */
531 char szName[SSM_MAX_NAME_SIZE];
532} SSMFILEUNITHDR;
533AssertCompileMemberOffset(SSMFILEUNITHDR, szName, 40);
534AssertCompileMemberSize(SSMFILEUNITHDR, szMagic, sizeof(SSMFILEUNITHDR_MAGIC));
535AssertCompileMemberSize(SSMFILEUNITHDR, szMagic, sizeof(SSMFILEUNITHDR_END));
536/** Pointer to SSMFILEUNITHDR. */
537typedef SSMFILEUNITHDR *PSSMFILEUNITHDR;
538
539
540/**
541 * Data unit header.
542 *
543 * This is used by v1.0, v1.1 and v1.2 of the format.
544 */
545typedef struct SSMFILEUNITHDRV1
546{
547 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
548 char achMagic[8];
549 /** Number of bytes in this data unit including the header. */
550 uint64_t cbUnit;
551 /** Data version. */
552 uint32_t u32Version;
553 /** Instance number. */
554 uint32_t u32Instance;
555 /** Size of the data unit name including the terminator. (bytes) */
556 uint32_t cchName;
557 /** Data unit name. */
558 char szName[1];
559} SSMFILEUNITHDRV1;
560/** Pointer to SSMFILEUNITHDR. */
561typedef SSMFILEUNITHDRV1 *PSSMFILEUNITHDRV1;
562
563
564/**
565 * Termination data record.
566 */
567typedef struct SSMRECTERM
568{
569 uint8_t u8TypeAndFlags;
570 /** The record size (sizeof(SSMRECTERM) - 2). */
571 uint8_t cbRec;
572 /** Flags, see SSMRECTERM_FLAGS_CRC32. */
573 uint16_t fFlags;
574 /** The checksum of the data up to the start of this record. */
575 uint32_t u32CRC;
576 /** The length of this data unit in bytes (including this record). */
577 uint64_t cbUnit;
578} SSMRECTERM;
579AssertCompileSize(SSMRECTERM, 16);
580AssertCompileMemberAlignment(SSMRECTERM, cbUnit, 8);
581/** Pointer to a termination record. */
582typedef SSMRECTERM *PSSMRECTERM;
583/** Pointer to a const termination record. */
584typedef SSMRECTERM const *PCSSMRECTERM;
585
586
587/**
588 * Directory entry.
589 */
590typedef struct SSMFILEDIRENTRY
591{
592 /** The offset of the data unit. */
593 uint64_t off;
594 /** The instance number. */
595 uint32_t u32Instance;
596 /** The CRC-32 of the name excluding the terminator. (lazy bird) */
597 uint32_t u32NameCRC;
598} SSMFILEDIRENTRY;
599AssertCompileSize(SSMFILEDIRENTRY, 16);
600/** Pointer to a directory entry. */
601typedef SSMFILEDIRENTRY *PSSMFILEDIRENTRY;
602/** Pointer to a const directory entry. */
603typedef SSMFILEDIRENTRY const *PCSSMFILEDIRENTRY;
604
605/**
606 * Directory for the data units from the final phase.
607 *
608 * This is used to speed up SSMR3Seek (it would have to decompress and parse the
609 * whole stream otherwise).
610 */
611typedef struct SSMFILEDIR
612{
613 /** Magic string (SSMFILEDIR_MAGIC). */
614 char szMagic[8];
615 /** The CRC-32 for the whole directory.
616 * Calculated with this field set to zero. */
617 uint32_t u32CRC;
618 /** The number of directory entries. */
619 uint32_t cEntries;
620 /** The directory entries (variable size). */
621 SSMFILEDIRENTRY aEntries[1];
622} SSMFILEDIR;
623AssertCompileSize(SSMFILEDIR, 32);
624/** Pointer to a directory. */
625typedef SSMFILEDIR *PSSMFILEDIR;
626/** Pointer to a const directory. */
627typedef SSMFILEDIR *PSSMFILEDIR;
628
629
630/**
631 * Footer structure
632 */
633typedef struct SSMFILEFTR
634{
635 /** Magic string (SSMFILEFTR_MAGIC). */
636 char szMagic[8];
637 /** The offset of this record in the stream. */
638 uint64_t offStream;
639 /** The CRC for the stream.
640 * This is set to zero if SSMFILEHDR_FLAGS_STREAM_CRC32 is clear. */
641 uint32_t u32StreamCRC;
642 /** Number directory entries. */
643 uint32_t cDirEntries;
644 /** Reserved footer space - must be zero. */
645 uint32_t u32Reserved;
646 /** The CRC-32 for this structure.
647 * Calculated with this field set to zero. */
648 uint32_t u32CRC;
649} SSMFILEFTR;
650AssertCompileSize(SSMFILEFTR, 32);
651/** Pointer to a footer. */
652typedef SSMFILEFTR *PSSMFILEFTR;
653/** Pointer to a const footer. */
654typedef SSMFILEFTR const *PCSSMFILEFTR;
655
656
657/*******************************************************************************
658* Internal Functions *
659*******************************************************************************/
660static int ssmR3LazyInit(PVM pVM);
661static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM);
662static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
663static int ssmR3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
664static int ssmR3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC);
665static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance);
666static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t u32Instance);
667static int ssmR3DataWriteFinish(PSSMHANDLE pSSM);
668static void ssmR3DataWriteBegin(PSSMHANDLE pSSM);
669static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
670static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM);
671static int ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
672static void ssmR3DataReadFinishV1(PSSMHANDLE pSSM);
673static void ssmR3DataReadBeginV2(PSSMHANDLE pSSM);
674static void ssmR3DataReadFinishV2(PSSMHANDLE pSSM);
675static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM);
676static int ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf);
677
678
679/**
680 * Performs lazy initialization of the SSM.
681 *
682 * @returns VBox status code.
683 * @param pVM The VM.
684 */
685static int ssmR3LazyInit(PVM pVM)
686{
687 /*
688 * Register a saved state unit which we use to put the VirtualBox version,
689 * revision and similar stuff in.
690 */
691 pVM->ssm.s.fInitialized = true;
692 int rc = SSMR3RegisterInternal(pVM, "SSM", 0 /*u32Instance*/, 1/*u32Version*/, 64 /*cbGuess*/,
693 NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
694 NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
695 pVM->ssm.s.fInitialized = RT_SUCCESS(rc);
696 return rc;
697}
698
699
700/**
701 * For saving usful things without having to go thru the tedious process of
702 * adding it to the header.
703 *
704 * @returns VBox status code.
705 * @param pVM Pointer to the shared VM structure.
706 * @param pSSM The SSM handle.
707 */
708static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM)
709{
710 /*
711 * String table containg pairs of variable and value string.
712 * Terminated by two empty strings.
713 */
714#ifdef VBOX_OSE
715 SSMR3PutStrZ(pSSM, "OSE");
716 SSMR3PutStrZ(pSSM, "true");
717#endif
718
719 /* terminator */
720 SSMR3PutStrZ(pSSM, "");
721 return SSMR3PutStrZ(pSSM, "");
722}
723
724
725/**
726 * For load the version + revision and stuff.
727 *
728 * @returns VBox status code.
729 * @param pVM Pointer to the shared VM structure.
730 * @param pSSM The SSM handle.
731 * @param u32Version The version (1).
732 */
733static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
734{
735 AssertLogRelMsgReturn(u32Version == 1, ("%d", u32Version), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
736
737 /*
738 * String table containg pairs of variable and value string.
739 * Terminated by two empty strings.
740 */
741 for (unsigned i = 0; ; i++)
742 {
743 char szVar[128];
744 char szValue[1024];
745 int rc = SSMR3GetStrZ(pSSM, szVar, sizeof(szVar));
746 AssertRCReturn(rc, rc);
747 rc = SSMR3GetStrZ(pSSM, szValue, sizeof(szValue));
748 AssertRCReturn(rc, rc);
749 if (!szVar[0] && !szValue[0])
750 break;
751 if (i == 0)
752 LogRel(("SSM: Saved state info:\n"));
753 LogRel(("SSM: %s: %s\n", szVar, szValue));
754 }
755 return VINF_SUCCESS;
756}
757
758
759/**
760 * Internal registration worker.
761 *
762 * @returns VBox status code.
763 * @param pVM The VM handle.
764 * @param pszName Data unit name.
765 * @param u32Instance The instance id.
766 * @param u32Version The data unit version.
767 * @param cbGuess The guessed data unit size.
768 * @param pszBefore Name of data unit to be placed in front of.
769 * Optional.
770 * @param ppUnit Where to store the insterted unit node.
771 * Caller must fill in the missing details.
772 */
773static int ssmR3Register(PVM pVM, const char *pszName, uint32_t u32Instance,
774 uint32_t u32Version, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit)
775{
776 /*
777 * Validate input.
778 */
779 AssertPtr(pszName);
780 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
781 size_t cchName = strlen(pszName);
782 AssertMsgReturn(cchName < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchName, SSM_MAX_NAME_SIZE, pszName), VERR_OUT_OF_RANGE);
783
784 AssertReturn(!pszBefore || *pszBefore, VERR_INVALID_PARAMETER);
785 size_t cchBefore = pszBefore ? strlen(pszBefore) : 0;
786 AssertMsgReturn(cchBefore < SSM_MAX_NAME_SIZE, ("%zu >= %u: %s\n", cchBefore, SSM_MAX_NAME_SIZE, pszBefore), VERR_OUT_OF_RANGE);
787
788 /*
789 * Lazy init.
790 */
791 if (!pVM->ssm.s.fInitialized)
792 {
793 int rc = ssmR3LazyInit(pVM);
794 AssertRCReturn(rc, rc);
795 }
796
797 /*
798 * Walk to the end of the list checking for duplicates as we go.
799 */
800 PSSMUNIT pUnitBeforePrev = NULL;
801 PSSMUNIT pUnitBefore = NULL;
802 PSSMUNIT pUnitPrev = NULL;
803 PSSMUNIT pUnit = pVM->ssm.s.pHead;
804 while (pUnit)
805 {
806 if ( pUnit->u32Instance == u32Instance
807 && pUnit->cchName == cchName
808 && !memcmp(pUnit->szName, pszName, cchName))
809 {
810 AssertMsgFailed(("Duplicate registration %s\n", pszName));
811 return VERR_SSM_UNIT_EXISTS;
812 }
813 if ( pUnit->cchName == cchBefore
814 && !pUnitBefore
815 && !memcmp(pUnit->szName, pszBefore, cchBefore))
816 {
817 pUnitBeforePrev = pUnitPrev;
818 pUnitBefore = pUnit;
819 }
820
821 /* next */
822 pUnitPrev = pUnit;
823 pUnit = pUnit->pNext;
824 }
825
826 /*
827 * Allocate new node.
828 */
829 pUnit = (PSSMUNIT)MMR3HeapAllocZ(pVM, MM_TAG_SSM, RT_OFFSETOF(SSMUNIT, szName[cchName + 1]));
830 if (!pUnit)
831 return VERR_NO_MEMORY;
832
833 /*
834 * Fill in (some) data. (Stuff is zero'ed.)
835 */
836 pUnit->u32Version = u32Version;
837 pUnit->u32Instance = u32Instance;
838 pUnit->cbGuess = cbGuess;
839 pUnit->cchName = cchName;
840 memcpy(pUnit->szName, pszName, cchName);
841
842 /*
843 * Insert
844 */
845 if (pUnitBefore)
846 {
847 pUnit->pNext = pUnitBefore;
848 if (pUnitBeforePrev)
849 pUnitBeforePrev->pNext = pUnit;
850 else
851 pVM->ssm.s.pHead = pUnit;
852 }
853 else if (pUnitPrev)
854 pUnitPrev->pNext = pUnit;
855 else
856 pVM->ssm.s.pHead = pUnit;
857 pVM->ssm.s.cUnits++;
858
859 *ppUnit = pUnit;
860 return VINF_SUCCESS;
861}
862
863
864/**
865 * Register a PDM Devices data unit.
866 *
867 * @returns VBox status.
868 *
869 * @param pVM The VM handle.
870 * @param pDevIns Device instance.
871 * @param pszName Data unit name.
872 * @param u32Instance The instance identifier of the data unit.
873 * This must together with the name be unique.
874 * @param u32Version Data layout version number.
875 * @param cbGuess The approximate amount of data in the unit.
876 * Only for progress indicators.
877 * @param pszBefore Name of data unit which we should be put in front
878 * of. Optional (NULL).
879 * @param pfnSavePrep Prepare save callback, optional.
880 * @param pfnSaveExec Execute save callback, optional.
881 * @param pfnSaveDone Done save callback, optional.
882 * @param pfnLoadPrep Prepare load callback, optional.
883 * @param pfnLoadExec Execute load callback, optional.
884 * @param pfnLoadDone Done load callback, optional.
885 */
886VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore,
887 PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
888 PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
889{
890 PSSMUNIT pUnit;
891 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, pszBefore, &pUnit);
892 if (RT_SUCCESS(rc))
893 {
894 pUnit->enmType = SSMUNITTYPE_DEV;
895 pUnit->u.Dev.pfnSavePrep = pfnSavePrep;
896 pUnit->u.Dev.pfnSaveExec = pfnSaveExec;
897 pUnit->u.Dev.pfnSaveDone = pfnSaveDone;
898 pUnit->u.Dev.pfnLoadPrep = pfnLoadPrep;
899 pUnit->u.Dev.pfnLoadExec = pfnLoadExec;
900 pUnit->u.Dev.pfnLoadDone = pfnLoadDone;
901 pUnit->u.Dev.pDevIns = pDevIns;
902 }
903 return rc;
904}
905
906
907/**
908 * Register a PDM driver data unit.
909 *
910 * @returns VBox status.
911 *
912 * @param pVM The VM handle.
913 * @param pDrvIns Driver instance.
914 * @param pszName Data unit name.
915 * @param u32Instance The instance identifier of the data unit.
916 * This must together with the name be unique.
917 * @param u32Version Data layout version number.
918 * @param cbGuess The approximate amount of data in the unit.
919 * Only for progress indicators.
920 * @param pfnSavePrep Prepare save callback, optional.
921 * @param pfnSaveExec Execute save callback, optional.
922 * @param pfnSaveDone Done save callback, optional.
923 * @param pfnLoadPrep Prepare load callback, optional.
924 * @param pfnLoadExec Execute load callback, optional.
925 * @param pfnLoadDone Done load callback, optional.
926 */
927VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
928 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
929 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
930{
931 PSSMUNIT pUnit;
932 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
933 if (RT_SUCCESS(rc))
934 {
935 pUnit->enmType = SSMUNITTYPE_DRV;
936 pUnit->u.Drv.pfnSavePrep = pfnSavePrep;
937 pUnit->u.Drv.pfnSaveExec = pfnSaveExec;
938 pUnit->u.Drv.pfnSaveDone = pfnSaveDone;
939 pUnit->u.Drv.pfnLoadPrep = pfnLoadPrep;
940 pUnit->u.Drv.pfnLoadExec = pfnLoadExec;
941 pUnit->u.Drv.pfnLoadDone = pfnLoadDone;
942 pUnit->u.Drv.pDrvIns = pDrvIns;
943 }
944 return rc;
945}
946
947
948/**
949 * Register a internal data unit.
950 *
951 * @returns VBox status.
952 *
953 * @param pVM The VM handle.
954 * @param pszName Data unit name.
955 * @param u32Instance The instance identifier of the data unit.
956 * This must together with the name be unique.
957 * @param u32Version Data layout version number.
958 * @param cbGuess The approximate amount of data in the unit.
959 * Only for progress indicators.
960 * @param pfnSavePrep Prepare save callback, optional.
961 * @param pfnSaveExec Execute save callback, optional.
962 * @param pfnSaveDone Done save callback, optional.
963 * @param pfnLoadPrep Prepare load callback, optional.
964 * @param pfnLoadExec Execute load callback, optional.
965 * @param pfnLoadDone Done load callback, optional.
966 */
967VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
968 PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
969 PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone)
970{
971 PSSMUNIT pUnit;
972 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
973 if (RT_SUCCESS(rc))
974 {
975 pUnit->enmType = SSMUNITTYPE_INTERNAL;
976 pUnit->u.Internal.pfnSavePrep = pfnSavePrep;
977 pUnit->u.Internal.pfnSaveExec = pfnSaveExec;
978 pUnit->u.Internal.pfnSaveDone = pfnSaveDone;
979 pUnit->u.Internal.pfnLoadPrep = pfnLoadPrep;
980 pUnit->u.Internal.pfnLoadExec = pfnLoadExec;
981 pUnit->u.Internal.pfnLoadDone = pfnLoadDone;
982 }
983 return rc;
984}
985
986
987/**
988 * Register an external data unit.
989 *
990 * @returns VBox status.
991 *
992 * @param pVM The VM handle.
993 * @param pszName Data unit name.
994 * @param u32Instance The instance identifier of the data unit.
995 * This must together with the name be unique.
996 * @param u32Version Data layout version number.
997 * @param cbGuess The approximate amount of data in the unit.
998 * Only for progress indicators.
999 * @param pfnSavePrep Prepare save callback, optional.
1000 * @param pfnSaveExec Execute save callback, optional.
1001 * @param pfnSaveDone Done save callback, optional.
1002 * @param pfnLoadPrep Prepare load callback, optional.
1003 * @param pfnLoadExec Execute load callback, optional.
1004 * @param pfnLoadDone Done load callback, optional.
1005 * @param pvUser User argument.
1006 */
1007VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
1008 PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
1009 PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
1010{
1011 PSSMUNIT pUnit;
1012 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
1013 if (RT_SUCCESS(rc))
1014 {
1015 pUnit->enmType = SSMUNITTYPE_EXTERNAL;
1016 pUnit->u.External.pfnSavePrep = pfnSavePrep;
1017 pUnit->u.External.pfnSaveExec = pfnSaveExec;
1018 pUnit->u.External.pfnSaveDone = pfnSaveDone;
1019 pUnit->u.External.pfnLoadPrep = pfnLoadPrep;
1020 pUnit->u.External.pfnLoadExec = pfnLoadExec;
1021 pUnit->u.External.pfnLoadDone = pfnLoadDone;
1022 pUnit->u.External.pvUser = pvUser;
1023 }
1024 return rc;
1025}
1026
1027
1028/**
1029 * Deregister one or more PDM Device data units.
1030 *
1031 * @returns VBox status.
1032 *
1033 * @param pVM The VM handle.
1034 * @param pDevIns Device instance.
1035 * @param pszName Data unit name.
1036 * Use NULL to deregister all data units for that device instance.
1037 * @param u32Instance The instance identifier of the data unit.
1038 * This must together with the name be unique.
1039 * @remark Only for dynmaic data units and dynamic unloaded modules.
1040 */
1041VMMR3DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance)
1042{
1043 /*
1044 * Validate input.
1045 */
1046 if (!pDevIns)
1047 {
1048 AssertMsgFailed(("pDevIns is NULL!\n"));
1049 return VERR_INVALID_PARAMETER;
1050 }
1051
1052 /*
1053 * Search the list.
1054 */
1055 size_t cchName = pszName ? strlen(pszName) : 0;
1056 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1057 PSSMUNIT pUnitPrev = NULL;
1058 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1059 while (pUnit)
1060 {
1061 if ( pUnit->enmType == SSMUNITTYPE_DEV
1062 && ( !pszName
1063 || ( pUnit->cchName == cchName
1064 && !memcmp(pUnit->szName, pszName, cchName)))
1065 && pUnit->u32Instance == u32Instance
1066 )
1067 {
1068 if (pUnit->u.Dev.pDevIns == pDevIns)
1069 {
1070 /*
1071 * Unlink it, advance pointer, and free the node.
1072 */
1073 PSSMUNIT pFree = pUnit;
1074 pUnit = pUnit->pNext;
1075 if (pUnitPrev)
1076 pUnitPrev->pNext = pUnit;
1077 else
1078 pVM->ssm.s.pHead = pUnit;
1079 pVM->ssm.s.cUnits--;
1080 Log(("SSM: Removed data unit '%s' (pdm dev).\n", pFree->szName));
1081 MMR3HeapFree(pFree);
1082
1083 if (pszName)
1084 return VINF_SUCCESS;
1085 rc = VINF_SUCCESS;
1086 continue;
1087 }
1088 else if (pszName)
1089 {
1090 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1091 pUnit->u.Dev.pDevIns, pDevIns, pszName));
1092 return VERR_SSM_UNIT_NOT_OWNER;
1093 }
1094 }
1095
1096 /* next */
1097 pUnitPrev = pUnit;
1098 pUnit = pUnit->pNext;
1099 }
1100
1101 return rc;
1102}
1103
1104
1105/**
1106 * Deregister one ore more PDM Driver data units.
1107 *
1108 * @returns VBox status.
1109 * @param pVM The VM handle.
1110 * @param pDrvIns Driver instance.
1111 * @param pszName Data unit name.
1112 * Use NULL to deregister all data units for that driver instance.
1113 * @param u32Instance The instance identifier of the data unit.
1114 * This must together with the name be unique. Ignored if pszName is NULL.
1115 * @remark Only for dynmaic data units and dynamic unloaded modules.
1116 */
1117VMMR3DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
1118{
1119 /*
1120 * Validate input.
1121 */
1122 if (!pDrvIns)
1123 {
1124 AssertMsgFailed(("pDrvIns is NULL!\n"));
1125 return VERR_INVALID_PARAMETER;
1126 }
1127
1128 /*
1129 * Search the list.
1130 */
1131 size_t cchName = pszName ? strlen(pszName) : 0;
1132 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
1133 PSSMUNIT pUnitPrev = NULL;
1134 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1135 while (pUnit)
1136 {
1137 if ( pUnit->enmType == SSMUNITTYPE_DRV
1138 && ( !pszName
1139 || ( pUnit->cchName == cchName
1140 && !memcmp(pUnit->szName, pszName, cchName)
1141 && pUnit->u32Instance == u32Instance))
1142 )
1143 {
1144 if (pUnit->u.Drv.pDrvIns == pDrvIns)
1145 {
1146 /*
1147 * Unlink it, advance pointer, and free the node.
1148 */
1149 PSSMUNIT pFree = pUnit;
1150 pUnit = pUnit->pNext;
1151 if (pUnitPrev)
1152 pUnitPrev->pNext = pUnit;
1153 else
1154 pVM->ssm.s.pHead = pUnit;
1155 pVM->ssm.s.cUnits--;
1156 Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
1157 MMR3HeapFree(pFree);
1158
1159 if (pszName)
1160 return VINF_SUCCESS;
1161 rc = VINF_SUCCESS;
1162 continue;
1163 }
1164 else if (pszName)
1165 {
1166 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
1167 pUnit->u.Drv.pDrvIns, pDrvIns, pszName));
1168 return VERR_SSM_UNIT_NOT_OWNER;
1169 }
1170 }
1171
1172 /* next */
1173 pUnitPrev = pUnit;
1174 pUnit = pUnit->pNext;
1175 }
1176
1177 return rc;
1178}
1179
1180
1181/**
1182 * Deregister a data unit.
1183 *
1184 * @returns VBox status.
1185 * @param pVM The VM handle.
1186 * @param enmType Unit type
1187 * @param pszName Data unit name.
1188 * @remark Only for dynmaic data units.
1189 */
1190static int ssmR3DeregisterByNameAndType(PVM pVM, const char *pszName, SSMUNITTYPE enmType)
1191{
1192 /*
1193 * Validate input.
1194 */
1195 if (!pszName)
1196 {
1197 AssertMsgFailed(("pszName is NULL!\n"));
1198 return VERR_INVALID_PARAMETER;
1199 }
1200
1201 /*
1202 * Search the list.
1203 */
1204 size_t cchName = strlen(pszName);
1205 int rc = VERR_SSM_UNIT_NOT_FOUND;
1206 PSSMUNIT pUnitPrev = NULL;
1207 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1208 while (pUnit)
1209 {
1210 if ( pUnit->enmType == enmType
1211 && pUnit->cchName == cchName
1212 && !memcmp(pUnit->szName, pszName, cchName))
1213 {
1214 /*
1215 * Unlink it, advance pointer, and free the node.
1216 */
1217 PSSMUNIT pFree = pUnit;
1218 pUnit = pUnit->pNext;
1219 if (pUnitPrev)
1220 pUnitPrev->pNext = pUnit;
1221 else
1222 pVM->ssm.s.pHead = pUnit;
1223 pVM->ssm.s.cUnits--;
1224 Log(("SSM: Removed data unit '%s' (type=%d).\n", pFree->szName, enmType));
1225 MMR3HeapFree(pFree);
1226 return VINF_SUCCESS;
1227 }
1228
1229 /* next */
1230 pUnitPrev = pUnit;
1231 pUnit = pUnit->pNext;
1232 }
1233
1234 return rc;
1235}
1236
1237
1238/**
1239 * Deregister an internal data unit.
1240 *
1241 * @returns VBox status.
1242 * @param pVM The VM handle.
1243 * @param pszName Data unit name.
1244 * @remark Only for dynmaic data units.
1245 */
1246VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName)
1247{
1248 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_INTERNAL);
1249}
1250
1251
1252/**
1253 * Deregister an external data unit.
1254 *
1255 * @returns VBox status.
1256 * @param pVM The VM handle.
1257 * @param pszName Data unit name.
1258 * @remark Only for dynmaic data units.
1259 */
1260VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName)
1261{
1262 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_EXTERNAL);
1263}
1264
1265
1266/**
1267 * Stream output routine.
1268 *
1269 * @returns VBox status code.
1270 * @param pSSM The SSM handle.
1271 * @param pvBuf What to write.
1272 * @param cbToWrite How much to write.
1273 */
1274static int ssmR3StrmWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbToWrite)
1275{
1276 Assert(pSSM->enmOp <= SSMSTATE_SAVE_DONE);
1277 int rc = RTFileWrite(pSSM->hFile, pvBuf, cbToWrite, NULL);
1278 if (RT_SUCCESS(rc))
1279 {
1280 if (pSSM->fChecksummed)
1281 pSSM->u32StreamCRC = RTCrc32Process(pSSM->u32StreamCRC, pvBuf, cbToWrite);
1282 return VINF_SUCCESS;
1283 }
1284
1285 LogRel(("ssmR3StrmWrite: RTFileWrite(,,%zu) -> %Rrc\n", cbToWrite, rc));
1286 if (RT_SUCCESS(pSSM->rc))
1287 pSSM->rc = rc;
1288 return rc;
1289}
1290
1291
1292/**
1293 * Stream input routine.
1294 *
1295 * @returns VBox status code.
1296 * @param pSSM The SSM handle.
1297 * @param pvBuf Where to put what we read.
1298 * @param cbToRead How much to read.
1299 */
1300static int ssmR3StrmRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbToRead)
1301{
1302 Assert(pSSM->enmOp >= SSMSTATE_LOAD_PREP);
1303 int rc = RTFileRead(pSSM->hFile, pvBuf, cbToRead, NULL);
1304 if (RT_SUCCESS(rc))
1305 {
1306 if (pSSM->fChecksummed)
1307 pSSM->u32StreamCRC = RTCrc32Process(pSSM->u32StreamCRC, pvBuf, cbToRead);
1308 return VINF_SUCCESS;
1309 }
1310
1311 LogRel(("ssmR3StrmRead: RTFileRead(,,%zu) -> %Rrc\n", cbToRead, rc));
1312 if (RT_SUCCESS(pSSM->rc))
1313 pSSM->rc = rc;
1314 return rc;
1315}
1316
1317
1318/**
1319 * Flush any buffered data.
1320 *
1321 * @returns VBox status code.
1322 * @param pSSM The SSM handle.
1323 */
1324static int ssmR3StrmFlush(PSSMHANDLE pSSM)
1325{
1326 /* no buffering yet. */
1327 return VINF_SUCCESS;
1328}
1329
1330
1331/**
1332 * Tell current stream position.
1333 *
1334 * @returns stream position.
1335 * @param pSSM The SSM handle.
1336 */
1337static uint64_t ssmR3StrmTell(PSSMHANDLE pSSM)
1338{
1339 return RTFileTell(pSSM->hFile);
1340}
1341
1342
1343
1344/**
1345 * Calculate the checksum of a file portion.
1346 *
1347 * @returns VBox status.
1348 * @param File Handle to the file. Positioned where to start
1349 * checksumming.
1350 * @param cbFile The portion of the file to checksum.
1351 * @param pu32CRC Where to store the calculated checksum.
1352 */
1353static int ssmR3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC)
1354{
1355 /*
1356 * Allocate a buffer.
1357 */
1358 void *pvBuf = RTMemTmpAlloc(32*1024);
1359 if (!pvBuf)
1360 return VERR_NO_TMP_MEMORY;
1361
1362 /*
1363 * Loop reading and calculating CRC32.
1364 */
1365 int rc = VINF_SUCCESS;
1366 uint32_t u32CRC = RTCrc32Start();
1367 while (cbFile)
1368 {
1369 /* read chunk */
1370 register unsigned cbToRead = 32*1024;
1371 if (cbFile < 32*1024)
1372 cbToRead = (unsigned)cbFile;
1373 rc = RTFileRead(File, pvBuf, cbToRead, NULL);
1374 if (RT_FAILURE(rc))
1375 {
1376 AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
1377 RTMemTmpFree(pvBuf);
1378 return rc;
1379 }
1380
1381 /* update total */
1382 cbFile -= cbToRead;
1383
1384 /* calc crc32. */
1385 u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
1386 }
1387 RTMemTmpFree(pvBuf);
1388
1389 /* store the calculated crc */
1390 u32CRC = RTCrc32Finish(u32CRC);
1391 Log(("SSM: u32CRC=0x%08x\n", u32CRC));
1392 *pu32CRC = u32CRC;
1393
1394 return VINF_SUCCESS;
1395}
1396
1397
1398/**
1399 * Works the progress calculation.
1400 *
1401 * @param pSSM The SSM handle.
1402 * @param cbAdvance Number of bytes to advance
1403 */
1404static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
1405{
1406 /* Can't advance it beyond the estimated end of the unit. */
1407 uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
1408 if (cbAdvance > cbLeft)
1409 cbAdvance = cbLeft;
1410 pSSM->offEst += cbAdvance;
1411
1412 /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
1413 while ( pSSM->offEst >= pSSM->offEstProgress
1414 && pSSM->uPercent <= 100-pSSM->uPercentDone)
1415 {
1416 if (pSSM->pfnProgress)
1417 pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
1418 pSSM->uPercent++;
1419 pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal
1420 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
1421 }
1422}
1423
1424
1425/**
1426 * Writes the directory.
1427 *
1428 * @returns VBox status code.
1429 * @param pVM The VM handle.
1430 * @param pSSM The SSM handle.
1431 * @param pcEntries Where to return the number of directory entries.
1432 */
1433static int ssmR3WriteDirectory(PVM pVM, PSSMHANDLE pSSM, uint32_t *pcEntries)
1434{
1435 /*
1436 * Grab some temporary memory for the dictionary.
1437 */
1438 size_t cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pVM->ssm.s.cUnits]);
1439 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
1440 if (!pDir)
1441 {
1442 LogRel(("ssmR3WriteDirectory: failed to allocate %zu bytes!\n", cbDir));
1443 return VERR_NO_TMP_MEMORY;
1444 }
1445
1446 /*
1447 * Initialize it.
1448 */
1449 memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic));
1450 pDir->u32CRC = 0;
1451 pDir->cEntries = 0;
1452
1453 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1454 if (pUnit->offStream != RTFOFF_MIN)
1455 {
1456 PSSMFILEDIRENTRY pEntry = &pDir->aEntries[pDir->cEntries++];
1457 Assert(pDir->cEntries <= pVM->ssm.s.cUnits);
1458 pEntry->off = pUnit->offStream;
1459 pEntry->u32Instance = pUnit->u32Instance;
1460 pEntry->u32NameCRC = RTCrc32(pUnit->szName, pUnit->cchName);
1461 }
1462
1463 /*
1464 * Calculate the actual size and CRC-32, then write the directory
1465 * out to the stream.
1466 */
1467 *pcEntries = pDir->cEntries;
1468 cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[pDir->cEntries]);
1469 pDir->u32CRC = RTCrc32(pDir, cbDir);
1470 int rc = ssmR3StrmWrite(pSSM, pDir, cbDir);
1471 RTMemTmpFree(pDir);
1472 return rc;
1473}
1474
1475
1476/**
1477 * Start VM save operation.
1478 *
1479 * @returns VBox status.
1480 *
1481 * @param pVM The VM handle.
1482 * @param pszFilename Name of the file to save the state in.
1483 * @param enmAfter What is planned after a successful save operation.
1484 * @param pfnProgress Progress callback. Optional.
1485 * @param pvUser User argument for the progress callback.
1486 *
1487 * @thread EMT
1488 */
1489VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
1490{
1491 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
1492 VM_ASSERT_EMT(pVM);
1493
1494 /*
1495 * Validate input.
1496 */
1497 if ( enmAfter != SSMAFTER_DESTROY
1498 && enmAfter != SSMAFTER_CONTINUE)
1499 {
1500 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
1501 return VERR_INVALID_PARAMETER;
1502 }
1503
1504 /*
1505 * Create the handle and try open the file.
1506 *
1507 * Note that there might be quite some work to do after executing the saving,
1508 * so we reserve 20% for the 'Done' period. The checksumming and closing of
1509 * the saved state file might take a long time.
1510 */
1511 SSMHANDLE Handle = {0};
1512 Handle.hFile = NIL_RTFILE;
1513 Handle.pVM = pVM;
1514 Handle.enmOp = SSMSTATE_INVALID;
1515 Handle.enmAfter = enmAfter;
1516 Handle.rc = VINF_SUCCESS;
1517 Handle.cbUnitLeftV1 = 0;
1518 Handle.offUnit = UINT64_MAX;
1519 Handle.fUnitChecksummed = false;
1520 Handle.u32UnitCRC = 0;
1521 Handle.pfnProgress = pfnProgress;
1522 Handle.pvUser = pvUser;
1523 Handle.uPercent = 0;
1524 Handle.offEstProgress = 0;
1525 Handle.cbEstTotal = 0;
1526 Handle.offEst = 0;
1527 Handle.offEstUnitEnd = 0;
1528 Handle.uPercentPrepare = 20;
1529 Handle.uPercentDone = 2;
1530 Handle.fChecksummed = true;
1531 Handle.u32StreamCRC = RTCrc32Start();
1532 Handle.u.Write.pZipComp = NULL;
1533 Handle.u.Write.offDataBuffer = 0;
1534
1535 int rc = RTFileOpen(&Handle.hFile, pszFilename, RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
1536 if (RT_FAILURE(rc))
1537 {
1538 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));
1539 return rc;
1540 }
1541
1542 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
1543
1544 /*
1545 * Write header.
1546 */
1547 union
1548 {
1549 SSMFILEHDR FileHdr;
1550 SSMFILEUNITHDR UnitHdr;
1551 SSMFILEFTR Footer;
1552 } u;
1553
1554 memcpy(&u.FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(u.FileHdr.szMagic));
1555 u.FileHdr.u16VerMajor = VBOX_VERSION_MAJOR;
1556 u.FileHdr.u16VerMinor = VBOX_VERSION_MINOR;
1557 u.FileHdr.u32VerBuild = VBOX_VERSION_BUILD;
1558 u.FileHdr.u32SvnRev = VMMGetSvnRev(),
1559 u.FileHdr.cHostBits = HC_ARCH_BITS;
1560 u.FileHdr.cbGCPhys = sizeof(RTGCPHYS);
1561 u.FileHdr.cbGCPtr = sizeof(RTGCPTR);
1562 u.FileHdr.u8Reserved = 0;
1563 u.FileHdr.cUnits = pVM->ssm.s.cUnits;
1564 u.FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32;
1565 u.FileHdr.u32Reserved = 0;
1566 u.FileHdr.u32CRC = 0;
1567 u.FileHdr.u32CRC = RTCrc32(&u.FileHdr, sizeof(u.FileHdr));
1568 rc = ssmR3StrmWrite(&Handle, &u.FileHdr, sizeof(u.FileHdr));
1569 if (RT_SUCCESS(rc))
1570 {
1571 /*
1572 * Clear the per unit flags and offsets.
1573 */
1574 PSSMUNIT pUnit;
1575 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1576 {
1577 pUnit->fCalled = false;
1578 pUnit->offStream = RTFOFF_MIN;
1579 }
1580
1581 /*
1582 * Do the prepare run.
1583 */
1584 Handle.rc = VINF_SUCCESS;
1585 Handle.enmOp = SSMSTATE_SAVE_PREP;
1586 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1587 {
1588 if (pUnit->u.Common.pfnSavePrep)
1589 {
1590 switch (pUnit->enmType)
1591 {
1592 case SSMUNITTYPE_DEV:
1593 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle);
1594 break;
1595 case SSMUNITTYPE_DRV:
1596 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle);
1597 break;
1598 case SSMUNITTYPE_INTERNAL:
1599 rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle);
1600 break;
1601 case SSMUNITTYPE_EXTERNAL:
1602 rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser);
1603 break;
1604 }
1605 pUnit->fCalled = true;
1606 if (RT_FAILURE(rc))
1607 {
1608 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1609 break;
1610 }
1611 }
1612
1613 Handle.cbEstTotal += pUnit->cbGuess;
1614 }
1615
1616 /* Progress. */
1617 if (pfnProgress)
1618 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
1619 Handle.uPercent = Handle.uPercentPrepare;
1620
1621 /*
1622 * Do the execute run.
1623 */
1624 if (RT_SUCCESS(rc))
1625 {
1626 Handle.enmOp = SSMSTATE_SAVE_EXEC;
1627 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1628 {
1629 /*
1630 * Estimate.
1631 */
1632 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1633 Handle.offEstUnitEnd += pUnit->cbGuess;
1634
1635 /*
1636 * Does this unit have a callback? If, not skip it.
1637 */
1638 if (!pUnit->u.Common.pfnSaveExec)
1639 {
1640 pUnit->fCalled = true;
1641 continue;
1642 }
1643 pUnit->offStream = ssmR3StrmTell(&Handle);
1644
1645 /*
1646 * Write data unit header
1647 */
1648 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(u.UnitHdr.szMagic));
1649 u.UnitHdr.offStream = pUnit->offStream;
1650 u.UnitHdr.u32CRC = 0;
1651 u.UnitHdr.u32Version = pUnit->u32Version;
1652 u.UnitHdr.u32Instance = pUnit->u32Instance;
1653 u.UnitHdr.u32Phase = SSM_PHASE_FINAL;
1654 u.UnitHdr.fFlags = 0;
1655 u.UnitHdr.cbName = (uint32_t)pUnit->cchName + 1;
1656 memcpy(&u.UnitHdr.szName[0], &pUnit->szName[0], u.UnitHdr.cbName);
1657 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[u.UnitHdr.cbName]));
1658 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
1659 u.UnitHdr.offStream, u.UnitHdr.szName, u.UnitHdr.u32Instance, u.UnitHdr.u32Phase, u.UnitHdr.u32Version));
1660 rc = ssmR3StrmWrite(&Handle, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[u.UnitHdr.cbName]));
1661 if (RT_SUCCESS(rc))
1662 {
1663 /*
1664 * Call the execute handler.
1665 */
1666 ssmR3DataWriteBegin(&Handle);
1667 switch (pUnit->enmType)
1668 {
1669 case SSMUNITTYPE_DEV:
1670 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle);
1671 break;
1672 case SSMUNITTYPE_DRV:
1673 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle);
1674 break;
1675 case SSMUNITTYPE_INTERNAL:
1676 rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle);
1677 break;
1678 case SSMUNITTYPE_EXTERNAL:
1679 pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser);
1680 rc = Handle.rc;
1681 break;
1682 }
1683 pUnit->fCalled = true;
1684 if (RT_SUCCESS(rc))
1685 rc = ssmR3DataFlushBuffer(&Handle); /* will return SSMHANDLE::rc if its set */
1686 if (RT_SUCCESS(rc))
1687 {
1688 /*
1689 * Write the termination record and flush the compression stream.
1690 */
1691 SSMRECTERM TermRec;
1692 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM;
1693 TermRec.cbRec = sizeof(TermRec) - 2;
1694 if (Handle.fUnitChecksummed)
1695 {
1696 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32;
1697 TermRec.u32CRC = RTCrc32Finish(Handle.u32UnitCRC);
1698 }
1699 else
1700 {
1701 TermRec.fFlags = 0;
1702 TermRec.u32CRC = 0;
1703 }
1704 TermRec.cbUnit = Handle.offUnit + sizeof(TermRec);
1705 rc = ssmR3DataWriteRaw(&Handle, &TermRec, sizeof(TermRec));
1706 if (RT_SUCCESS(rc))
1707 rc = ssmR3DataWriteFinish(&Handle);
1708 if (RT_SUCCESS(rc))
1709 {
1710 Handle.offUnit = UINT64_MAX;
1711 Handle.u32UnitCRC = 0;
1712 }
1713 else
1714 {
1715 LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc));
1716 break;
1717 }
1718 }
1719 else
1720 {
1721 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1722 break;
1723 }
1724 }
1725 if (RT_FAILURE(rc))
1726 {
1727 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
1728 break;
1729 }
1730 } /* for each unit */
1731
1732 /* finish the progress. */
1733 if (RT_SUCCESS(rc))
1734 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1735 }
1736 /* (progress should be pending 99% now) */
1737 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
1738
1739 /*
1740 * Do the done run.
1741 */
1742 Handle.rc = rc;
1743 Handle.enmOp = SSMSTATE_SAVE_DONE;
1744 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1745 {
1746 if ( pUnit->u.Common.pfnSaveDone
1747 && ( pUnit->fCalled
1748 || (!pUnit->u.Common.pfnSavePrep && !pUnit->u.Common.pfnSaveExec)))
1749 {
1750 switch (pUnit->enmType)
1751 {
1752 case SSMUNITTYPE_DEV:
1753 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle);
1754 break;
1755 case SSMUNITTYPE_DRV:
1756 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle);
1757 break;
1758 case SSMUNITTYPE_INTERNAL:
1759 rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle);
1760 break;
1761 case SSMUNITTYPE_EXTERNAL:
1762 rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser);
1763 break;
1764 }
1765 if (RT_FAILURE(rc))
1766 {
1767 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1768 if (RT_SUCCESS(Handle.rc))
1769 Handle.rc = rc;
1770 }
1771 }
1772 }
1773 rc = Handle.rc;
1774
1775 /*
1776 * Finalize the file if successfully saved.
1777 */
1778 if (RT_SUCCESS(rc))
1779 {
1780 /* Write the end unit. */
1781 memcpy(&u.UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(u.UnitHdr.szMagic));
1782 u.UnitHdr.offStream = ssmR3StrmTell(&Handle);
1783 u.UnitHdr.u32Version = 0;
1784 u.UnitHdr.u32Instance = 0;
1785 u.UnitHdr.u32Phase = SSM_PHASE_FINAL;
1786 u.UnitHdr.fFlags = 0;
1787 u.UnitHdr.cbName = 0;
1788 u.UnitHdr.u32CRC = 0;
1789 u.UnitHdr.u32CRC = RTCrc32(&u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]));
1790 Log(("SSM: Unit at %#9llx: END UNIT\n", u.UnitHdr.offStream));
1791 rc = ssmR3StrmWrite(&Handle, &u.UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]));
1792 if (RT_SUCCESS(rc))
1793 {
1794 /* Write the directory for the final units and then the footer. */
1795 rc = ssmR3WriteDirectory(pVM, &Handle, &u.Footer.cDirEntries);
1796 /* Flush the stream buffers so that the CRC is up to date. */
1797 if (RT_SUCCESS(rc))
1798 rc = ssmR3StrmFlush(&Handle);
1799 if (RT_SUCCESS(rc))
1800 {
1801 memcpy(u.Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(u.Footer.szMagic));
1802 u.Footer.offStream = ssmR3StrmTell(&Handle);
1803 u.Footer.u32StreamCRC = Handle.fChecksummed ? RTCrc32Finish(Handle.u32StreamCRC) : 0;
1804 u.Footer.u32Reserved = 0;
1805 u.Footer.u32CRC = 0;
1806 u.Footer.u32CRC = RTCrc32(&u.Footer, sizeof(u.Footer));
1807 Log(("SSM: Footer at %#9llx: \n", u.Footer.offStream));
1808 rc = ssmR3StrmWrite(&Handle, &u.Footer, sizeof(u.Footer));
1809 if (RT_SUCCESS(rc))
1810 {
1811 rc = RTFileClose(Handle.hFile);
1812 AssertRC(rc);
1813 if (pfnProgress)
1814 pfnProgress(pVM, 100, pvUser);
1815 Log(("SSM: Successfully saved the vm state to '%s'.\n", pszFilename));
1816 return VINF_SUCCESS;
1817 }
1818 }
1819 }
1820 LogRel(("SSM: Failed to finalize state file! rc=%Rrc\n", rc));
1821 }
1822 }
1823
1824 /*
1825 * Delete the file on failure and destroy any compressors.
1826 */
1827 int rc2 = RTFileClose(Handle.hFile);
1828 AssertRC(rc2);
1829 rc2 = RTFileDelete(pszFilename);
1830 AssertRC(rc2);
1831 if (Handle.u.Write.pZipComp)
1832 RTZipCompDestroy(Handle.u.Write.pZipComp);
1833
1834 return rc;
1835}
1836
1837
1838/**
1839 * Validates the header information stored in the handle.
1840 *
1841 * @returns VBox status code.
1842 *
1843 * @param pSSM The handle.
1844 * @param fHaveHostBits Set if the host bits field is valid.
1845 * @param fHaveVersion Set if we have a version.
1846 */
1847static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
1848{
1849 Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
1850 Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
1851 Assert(pSSM->u.Read.uFmtVerMinor <= 2);
1852
1853 if (fHaveVersion)
1854 {
1855 if ( pSSM->u.Read.u16VerMajor == 0
1856 || pSSM->u.Read.u16VerMajor > 1000
1857 || pSSM->u.Read.u16VerMinor > 1000
1858 || pSSM->u.Read.u32VerBuild > _1M
1859 || pSSM->u.Read.u32SvnRev == 0
1860 || pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
1861 {
1862 LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
1863 pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
1864 return VERR_SSM_INTEGRITY_VBOX_VERSION;
1865 }
1866 }
1867 else
1868 AssertLogRelReturn( pSSM->u.Read.u16VerMajor == 0
1869 && pSSM->u.Read.u16VerMinor == 0
1870 && pSSM->u.Read.u32VerBuild == 0
1871 && pSSM->u.Read.u32SvnRev == 0,
1872 VERR_SSM_INTEGRITY_VBOX_VERSION);
1873
1874 if (fHaveHostBits)
1875 {
1876 if ( pSSM->u.Read.cHostBits != 32
1877 && pSSM->u.Read.cHostBits != 64)
1878 {
1879 LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
1880 return VERR_SSM_INTEGRITY_SIZES;
1881 }
1882 }
1883 else
1884 AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_SIZES);
1885
1886 if ( pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
1887 && pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
1888 {
1889 LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
1890 return VERR_SSM_INTEGRITY_SIZES;
1891 }
1892 if ( pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
1893 && pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
1894 {
1895 LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
1896 return VERR_SSM_INTEGRITY_SIZES;
1897 }
1898
1899 return VINF_SUCCESS;
1900}
1901
1902
1903/**
1904 * Validates the integrity of a saved state file.
1905 *
1906 * @returns VBox status.
1907 * @param File File to validate.
1908 * The file position is undefined on return.
1909 * @param fChecksumIt Whether to checksum the file or not.
1910 * @param fChecksumOnRead Whether to validate the checksum while reading
1911 * the stream instead of up front. If not possible,
1912 * verify the checksum up front.
1913 * @param pHdr Where to store the file header.
1914 */
1915static int ssmR3ValidateFile(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
1916{
1917 /*
1918 * Read the header.
1919 */
1920 union
1921 {
1922 SSMFILEHDR v2_0;
1923 SSMFILEHDRV12 v1_2;
1924 SSMFILEHDRV11 v1_1;
1925 } uHdr;
1926 int rc = RTFileRead(pSSM->hFile, &uHdr, sizeof(uHdr), NULL);
1927 if (RT_FAILURE(rc))
1928 {
1929 LogRel(("SSM: Failed to read file header. rc=%Rrc\n", rc));
1930 return rc;
1931 }
1932
1933 /*
1934 * Verify the magic and make adjustments for versions differences.
1935 */
1936 if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
1937 {
1938 Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
1939 return VERR_SSM_INTEGRITY_MAGIC;
1940 }
1941 if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_V1_X, sizeof(SSMFILEHDR_MAGIC_V1_X) - 1))
1942 {
1943 /*
1944 * Version 2.0 and later.
1945 */
1946 bool fChecksummed;
1947 if (!memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR_MAGIC_V2_0)))
1948 {
1949 /* validate the header. */
1950 SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
1951 if ( uHdr.v2_0.u8Reserved
1952 || uHdr.v2_0.u32Reserved)
1953 {
1954 LogRel(("SSM: Reserved header fields aren't zero: %02x %08x\n", uHdr.v2_0.u8Reserved, uHdr.v2_0.u32Reserved));
1955 return VERR_SSM_INTEGRITY;
1956 }
1957 if ((uHdr.v2_0.fFlags & ~SSMFILEHDR_FLAGS_STREAM_CRC32))
1958 {
1959 LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
1960 return VERR_SSM_INTEGRITY;
1961 }
1962
1963 /* set the header info. */
1964 pSSM->u.Read.uFmtVerMajor = 2;
1965 pSSM->u.Read.uFmtVerMinor = 2;
1966 pSSM->u.Read.cbFileHdr = sizeof(uHdr.v2_0);
1967 pSSM->u.Read.cHostBits = uHdr.v2_0.cHostBits;
1968 pSSM->u.Read.u16VerMajor = uHdr.v2_0.u16VerMajor;
1969 pSSM->u.Read.u16VerMinor = uHdr.v2_0.u16VerMinor;
1970 pSSM->u.Read.u32VerBuild = uHdr.v2_0.u32VerBuild;
1971 pSSM->u.Read.u32SvnRev = uHdr.v2_0.u32SvnRev;
1972 pSSM->u.Read.cbGCPhys = uHdr.v2_0.cbGCPhys;
1973 pSSM->u.Read.cbGCPtr = uHdr.v2_0.cbGCPtr;
1974 pSSM->u.Read.fFixedGCPtrSize = true;
1975 fChecksummed = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
1976 }
1977 else
1978 {
1979 Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
1980 return VERR_SSM_INTEGRITY_VERSION;
1981 }
1982
1983 /*
1984 * Read and validate the footer.
1985 */
1986 SSMFILEFTR Footer;
1987 uint64_t offFooter;
1988 rc = RTFileSeek(pSSM->hFile, -(RTFOFF)sizeof(Footer), RTFILE_SEEK_END, &offFooter);
1989 AssertLogRelRCReturn(rc, rc);
1990 rc = RTFileRead(pSSM->hFile, &Footer, sizeof(Footer), NULL);
1991 AssertLogRelRCReturn(rc, rc);
1992 if (memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)))
1993 {
1994 LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(Footer.szMagic), &Footer.szMagic[0]));
1995 return VERR_SSM_INTEGRITY;
1996 }
1997 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
1998 if (Footer.offStream != offFooter)
1999 {
2000 LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
2001 return VERR_SSM_INTEGRITY;
2002 }
2003 if (Footer.u32Reserved)
2004 {
2005 LogRel(("SSM: Reserved footer field isn't zero: %08x\n", Footer.u32Reserved));
2006 return VERR_SSM_INTEGRITY;
2007 }
2008 if ( !fChecksummed
2009 && Footer.u32StreamCRC)
2010 {
2011 LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
2012 return VERR_SSM_INTEGRITY;
2013 }
2014
2015 pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
2016 pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
2017
2018 /*
2019 * Validate the header info we've set in the handle.
2020 */
2021 rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
2022 if (RT_FAILURE(rc))
2023 return rc;
2024
2025 /*
2026 * Check the checksum if that's called for and possible.
2027 */
2028 if ( fChecksummed
2029 && fChecksumIt)
2030 {
2031 rc = RTFileSeek(pSSM->hFile, 0, RTFILE_SEEK_BEGIN, NULL);
2032 AssertLogRelRCReturn(rc, rc);
2033 uint32_t u32CRC;
2034 rc = ssmR3CalcChecksum(pSSM->hFile, offFooter, &u32CRC);
2035 if (RT_FAILURE(rc))
2036 return rc;
2037 if (u32CRC != pSSM->u.Read.u32LoadCRC)
2038 {
2039 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
2040 return VERR_SSM_INTEGRITY_CRC;
2041 }
2042 }
2043 }
2044 else
2045 {
2046 /*
2047 * Version 1.x of the format.
2048 */
2049 bool fHaveHostBits = true;
2050 bool fHaveVersion = false;
2051 RTUUID MachineUuidFromHdr;
2052
2053 pSSM->fChecksummed = false;
2054 pSSM->u.Read.uFmtVerMajor = 1;
2055 if (!memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDR_MAGIC_V1_1)))
2056 {
2057 pSSM->u.Read.uFmtVerMinor = 1;
2058 pSSM->u.Read.cbFileHdr = sizeof(uHdr.v1_1);
2059 pSSM->u.Read.cHostBits = 0; /* unknown */
2060 pSSM->u.Read.u16VerMajor = 0;
2061 pSSM->u.Read.u16VerMinor = 0;
2062 pSSM->u.Read.u32VerBuild = 0;
2063 pSSM->u.Read.u32SvnRev = 0;
2064 pSSM->u.Read.cbLoadFile = uHdr.v1_1.cbFile;
2065 pSSM->u.Read.u32LoadCRC = uHdr.v1_1.u32CRC;
2066 pSSM->u.Read.cbGCPhys = sizeof(RTGCPHYS);
2067 pSSM->u.Read.cbGCPtr = sizeof(RTGCPTR);
2068 pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
2069
2070 MachineUuidFromHdr = uHdr.v1_1.MachineUuid;
2071 fHaveHostBits = false;
2072 }
2073 else if (!memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDR_MAGIC_V1_2)))
2074 {
2075 pSSM->u.Read.uFmtVerMinor = 2;
2076 pSSM->u.Read.cbFileHdr = sizeof(uHdr.v1_2);
2077 pSSM->u.Read.cHostBits = uHdr.v1_2.cHostBits;
2078 pSSM->u.Read.u16VerMajor = uHdr.v1_2.u16VerMajor;
2079 pSSM->u.Read.u16VerMinor = uHdr.v1_2.u16VerMinor;
2080 pSSM->u.Read.u32VerBuild = uHdr.v1_2.u32VerBuild;
2081 pSSM->u.Read.u32SvnRev = uHdr.v1_2.u32SvnRev;
2082 pSSM->u.Read.cbLoadFile = uHdr.v1_2.cbFile;
2083 pSSM->u.Read.u32LoadCRC = uHdr.v1_2.u32CRC;
2084 pSSM->u.Read.cbGCPhys = uHdr.v1_2.cbGCPhys;
2085 pSSM->u.Read.cbGCPtr = uHdr.v1_2.cbGCPtr;
2086 pSSM->u.Read.fFixedGCPtrSize = true;
2087
2088 MachineUuidFromHdr = uHdr.v1_2.MachineUuid;
2089 fHaveVersion = true;
2090 }
2091 else
2092 {
2093 LogRel(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
2094 return VERR_SSM_INTEGRITY_VERSION;
2095 }
2096
2097 /*
2098 * The MachineUuid must be NULL (was never used).
2099 */
2100 if (!RTUuidIsNull(&MachineUuidFromHdr))
2101 {
2102 LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
2103 return VERR_SMM_INTEGRITY_MACHINE;
2104 }
2105
2106 /*
2107 * Verify the file size.
2108 */
2109 uint64_t cbFile;
2110 rc = RTFileGetSize(pSSM->hFile, &cbFile);
2111 AssertLogRelRCReturn(rc, rc);
2112 if (cbFile != pSSM->u.Read.cbLoadFile)
2113 {
2114 LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
2115 return VERR_SSM_INTEGRITY_SIZE;
2116 }
2117
2118 /*
2119 * Validate the header info we've set in the handle.
2120 */
2121 rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
2122 if (RT_FAILURE(rc))
2123 return rc;
2124
2125 /*
2126 * Verify the checksum if requested.
2127 *
2128 * Note! The checksum is not actually generated for the whole file,
2129 * this is of course a bug in the v1.x code that we cannot do
2130 * anything about.
2131 */
2132 if ( fChecksumIt
2133 || fChecksumOnRead)
2134 {
2135 rc = RTFileSeek(pSSM->hFile, RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC), RTFILE_SEEK_BEGIN, NULL);
2136 AssertLogRelRCReturn(rc, rc);
2137 uint32_t u32CRC;
2138 rc = ssmR3CalcChecksum(pSSM->hFile, cbFile - pSSM->u.Read.cbFileHdr, &u32CRC);
2139 if (RT_FAILURE(rc))
2140 return rc;
2141 if (u32CRC != pSSM->u.Read.u32LoadCRC)
2142 {
2143 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
2144 return VERR_SSM_INTEGRITY_CRC;
2145 }
2146 }
2147 }
2148
2149 return VINF_SUCCESS;
2150}
2151
2152
2153/**
2154 * Open a saved state for reading.
2155 *
2156 * The file will be positioned at the first data unit upon successful return.
2157 *
2158 * @returns VBox status code.
2159 *
2160 * @param pVM The VM handle.
2161 * @param pszFilename The filename.
2162 * @param fChecksumIt Check the checksum for the entire file.
2163 * @param fChecksumOnRead Whether to validate the checksum while reading
2164 * the stream instead of up front. If not possible,
2165 * verify the checksum up front.
2166 * @param pSSM Pointer to the handle structure. This will be
2167 * completely initialized on success.
2168 */
2169static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead, PSSMHANDLE pSSM)
2170{
2171 /*
2172 * Initialize the handle.
2173 */
2174 pSSM->hFile = NIL_RTFILE;
2175 pSSM->pVM = pVM;
2176 pSSM->enmOp = SSMSTATE_INVALID;
2177 pSSM->enmAfter = SSMAFTER_INVALID;
2178 pSSM->rc = VINF_SUCCESS;
2179 pSSM->cbUnitLeftV1 = 0;
2180 pSSM->offUnit = UINT64_MAX;
2181 pSSM->fUnitChecksummed = 0;
2182 pSSM->u32UnitCRC = 0;
2183 pSSM->pfnProgress = NULL;
2184 pSSM->pvUser = NULL;
2185 pSSM->uPercent = 0;
2186 pSSM->offEstProgress = 0;
2187 pSSM->cbEstTotal = 0;
2188 pSSM->offEst = 0;
2189 pSSM->offEstUnitEnd = 0;
2190 pSSM->uPercentPrepare = 5;
2191 pSSM->uPercentDone = 2;
2192 pSSM->fChecksummed = fChecksumOnRead;
2193 pSSM->u32StreamCRC = 0;
2194
2195 pSSM->u.Read.pZipDecomp = NULL;
2196 pSSM->u.Read.uFmtVerMajor = UINT32_MAX;
2197 pSSM->u.Read.uFmtVerMinor = UINT32_MAX;
2198 pSSM->u.Read.cbFileHdr = UINT32_MAX;
2199 pSSM->u.Read.cbGCPhys = UINT8_MAX;
2200 pSSM->u.Read.cbGCPtr = UINT8_MAX;
2201 pSSM->u.Read.fFixedGCPtrSize= false;
2202 pSSM->u.Read.u16VerMajor = UINT16_MAX;
2203 pSSM->u.Read.u16VerMinor = UINT16_MAX;
2204 pSSM->u.Read.u32VerBuild = UINT32_MAX;
2205 pSSM->u.Read.u32SvnRev = UINT32_MAX;
2206 pSSM->u.Read.cHostBits = UINT8_MAX;
2207 pSSM->u.Read.cbLoadFile = UINT64_MAX;
2208
2209 pSSM->u.Read.cbRecLeft = 0;
2210 pSSM->u.Read.cbDataBuffer = 0;
2211 pSSM->u.Read.offDataBuffer = 0;
2212 pSSM->u.Read.fEndOfData = 0;
2213 pSSM->u.Read.u8TypeAndFlags = 0;
2214
2215 /*
2216 * Try open and validate the file.
2217 */
2218 int rc = RTFileOpen(&pSSM->hFile, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
2219 if (RT_SUCCESS(rc))
2220 {
2221 rc = ssmR3ValidateFile(pSSM, fChecksumIt, fChecksumOnRead);
2222 if (RT_SUCCESS(rc))
2223 {
2224 rc = RTFileSeek(pSSM->hFile, pSSM->u.Read.cbFileHdr, RTFILE_SEEK_BEGIN, NULL);
2225 if (RT_SUCCESS(rc))
2226 return rc;
2227 }
2228
2229 RTFileClose(pSSM->hFile);
2230 }
2231 else
2232 Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n", pszFilename, rc));
2233 pSSM->hFile = NIL_RTFILE;
2234 return rc;
2235}
2236
2237
2238/**
2239 * Find a data unit by name.
2240 *
2241 * @returns Pointer to the unit.
2242 * @returns NULL if not found.
2243 *
2244 * @param pVM VM handle.
2245 * @param pszName Data unit name.
2246 * @param u32Instance The data unit instance id.
2247 */
2248static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t u32Instance)
2249{
2250 size_t cchName = strlen(pszName);
2251 PSSMUNIT pUnit = pVM->ssm.s.pHead;
2252 while ( pUnit
2253 && ( pUnit->u32Instance != u32Instance
2254 || pUnit->cchName != cchName
2255 || memcmp(pUnit->szName, pszName, cchName)))
2256 pUnit = pUnit->pNext;
2257 return pUnit;
2258}
2259
2260
2261/**
2262 * Executes the loading of a V1.X file.
2263 *
2264 * @returns VBox status code.
2265 * @param pVM The VM handle.
2266 * @param pSSM The saved state handle.
2267 */
2268static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
2269{
2270 int rc;
2271 char *pszName = NULL;
2272 size_t cchName = 0;
2273 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
2274 for (;;)
2275 {
2276 /*
2277 * Save the current file position and read the data unit header.
2278 */
2279 uint64_t offUnit = ssmR3StrmTell(pSSM);
2280 SSMFILEUNITHDRV1 UnitHdr;
2281 rc = ssmR3StrmRead(pSSM, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName));
2282 if (RT_SUCCESS(rc))
2283 {
2284 /*
2285 * Check the magic and see if it's valid and whether it is a end header or not.
2286 */
2287 if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
2288 {
2289 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
2290 {
2291 Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
2292 /* Complete the progress bar (pending 99% afterwards). */
2293 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
2294 break;
2295 }
2296 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
2297 offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
2298 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
2299 break;
2300 }
2301
2302 /*
2303 * Read the name.
2304 * Adjust the name buffer first.
2305 */
2306 if (cchName < UnitHdr.cchName)
2307 {
2308 if (pszName)
2309 RTMemTmpFree(pszName);
2310 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
2311 pszName = (char *)RTMemTmpAlloc(cchName);
2312 }
2313 if (pszName)
2314 {
2315 rc = ssmR3StrmRead(pSSM, pszName, UnitHdr.cchName);
2316 if (RT_SUCCESS(rc))
2317 {
2318 if (pszName[UnitHdr.cchName - 1])
2319 {
2320 LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
2321 rc = VERR_SSM_INTEGRITY;
2322 break;
2323 }
2324 Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
2325
2326 /*
2327 * Find the data unit in our internal table.
2328 */
2329 PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
2330 if (pUnit)
2331 {
2332 /*
2333 * Call the execute handler.
2334 */
2335 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
2336 pSSM->offUnit = 0;
2337 if (!pUnit->u.Common.pfnLoadExec)
2338 {
2339 LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
2340 rc = VERR_SSM_NO_LOAD_EXEC;
2341 break;
2342 }
2343 switch (pUnit->enmType)
2344 {
2345 case SSMUNITTYPE_DEV:
2346 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version);
2347 break;
2348 case SSMUNITTYPE_DRV:
2349 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version);
2350 break;
2351 case SSMUNITTYPE_INTERNAL:
2352 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version);
2353 break;
2354 case SSMUNITTYPE_EXTERNAL:
2355 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version);
2356 break;
2357 }
2358
2359 /*
2360 * Close the reader stream.
2361 */
2362 ssmR3DataReadFinishV1(pSSM);
2363
2364 pUnit->fCalled = true;
2365 if (RT_SUCCESS(rc))
2366 rc = pSSM->rc;
2367 if (RT_SUCCESS(rc))
2368 {
2369 /*
2370 * Now, we'll check the current position to see if all, or
2371 * more than all, the data was read.
2372 *
2373 * Note! Because of buffering / compression we'll only see the
2374 * really bad ones here.
2375 */
2376 uint64_t off = ssmR3StrmTell(pSSM);
2377 int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
2378 if (i64Diff < 0)
2379 {
2380 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
2381 rc = RTFileSeek(pSSM->hFile, offUnit + UnitHdr.cbUnit, RTFILE_SEEK_BEGIN, NULL);
2382 ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
2383 }
2384 else if (i64Diff > 0)
2385 {
2386 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
2387 rc = VERR_SSM_INTEGRITY;
2388 break;
2389 }
2390
2391 pSSM->offUnit = UINT64_MAX;
2392 }
2393 else
2394 {
2395 LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
2396 pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
2397 rc = VERR_SSM_INTEGRITY;
2398 break;
2399 }
2400 }
2401 else
2402 {
2403 /*
2404 * SSM unit wasn't found - ignore this when loading for the debugger.
2405 */
2406 LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
2407 rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
2408 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
2409 break;
2410 rc = RTFileSeek(pSSM->hFile, offUnit + UnitHdr.cbUnit, RTFILE_SEEK_BEGIN, NULL);
2411 }
2412 }
2413 }
2414 else
2415 rc = VERR_NO_TMP_MEMORY;
2416 }
2417
2418 /*
2419 * I/O errors ends up here (yea, I know, very nice programming).
2420 */
2421 if (RT_FAILURE(rc))
2422 {
2423 LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
2424 break;
2425 }
2426 }
2427
2428 RTMemTmpFree(pszName);
2429 return rc;
2430}
2431
2432
2433/**
2434 * Executes the loading of a V2.X file.
2435 *
2436 * @returns VBox status code.
2437 * @param pVM The VM handle.
2438 * @param pSSM The saved state handle.
2439 */
2440static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
2441{
2442 pSSM->enmOp = SSMSTATE_LOAD_EXEC;
2443 for (;;)
2444 {
2445 /*
2446 * Read the unit header and check its integrity.
2447 */
2448 uint64_t offUnit = ssmR3StrmTell(pSSM);
2449 SSMFILEUNITHDR UnitHdr;
2450 int rc = ssmR3StrmRead(pSSM, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName));
2451 if (RT_FAILURE(rc))
2452 return rc;
2453 if (RT_UNLIKELY( memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
2454 && memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic))))
2455 {
2456 LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
2457 offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
2458 return VERR_SSM_INTEGRITY_UNIT_MAGIC;
2459 }
2460 if (UnitHdr.cbName)
2461 {
2462 if (RT_UNLIKELY(UnitHdr.cbName > sizeof(UnitHdr.szName)))
2463 {
2464 LogRel(("SSM: Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
2465 offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)));
2466 return VERR_SSM_INTEGRITY;
2467 }
2468 rc = ssmR3StrmRead(pSSM, &UnitHdr.szName[0], UnitHdr.cbName);
2469 if (RT_FAILURE(rc))
2470 return rc;
2471 if (RT_UNLIKELY(UnitHdr.szName[UnitHdr.cbName - 1]))
2472 {
2473 LogRel(("SSM: Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
2474 offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName));
2475 return VERR_SSM_INTEGRITY;
2476 }
2477 }
2478 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]),
2479 ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
2480 if (RT_UNLIKELY(UnitHdr.offStream != offUnit))
2481 {
2482 LogRel(("SSM: Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit));
2483 return VERR_SSM_INTEGRITY;
2484 }
2485 AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags), VERR_SSM_INTEGRITY);
2486 if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)))
2487 {
2488 AssertLogRelMsgReturn( UnitHdr.cbName == 0
2489 && UnitHdr.u32Instance == 0
2490 && UnitHdr.u32Version == 0
2491 && UnitHdr.u32Phase == SSM_PHASE_FINAL,
2492 ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
2493 VERR_SSM_INTEGRITY);
2494
2495 /*
2496 * Complete the progress bar (pending 99% afterwards) and RETURN.
2497 */
2498 Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
2499 ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
2500 return VINF_SUCCESS;
2501 }
2502 AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
2503
2504 Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
2505 offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version));
2506
2507 /*
2508 * Find the data unit in our internal table.
2509 */
2510 PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
2511 if (pUnit)
2512 {
2513 /*
2514 * Call the execute handler.
2515 */
2516 AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
2517 ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
2518 VERR_SSM_NO_LOAD_EXEC);
2519 ssmR3DataReadBeginV2(pSSM);
2520 switch (pUnit->enmType)
2521 {
2522 case SSMUNITTYPE_DEV:
2523 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version);
2524 break;
2525 case SSMUNITTYPE_DRV:
2526 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version);
2527 break;
2528 case SSMUNITTYPE_INTERNAL:
2529 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version);
2530 break;
2531 case SSMUNITTYPE_EXTERNAL:
2532 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version);
2533 break;
2534 }
2535 ssmR3DataReadFinishV2(pSSM);
2536 pUnit->fCalled = true;
2537 if (RT_SUCCESS(rc))
2538 rc = pSSM->rc;
2539 if (RT_SUCCESS(rc))
2540 pSSM->offUnit = UINT64_MAX;
2541 else
2542 {
2543 LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u): %Rrc\n",
2544 UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Phase, rc));
2545 return rc;
2546 }
2547 }
2548 else
2549 {
2550 /*
2551 * SSM unit wasn't found - ignore this when loading for the debugger.
2552 */
2553 LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
2554 //if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
2555 return VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
2556 /** @todo Read data unit to /dev/null. */
2557 }
2558 }
2559 /* won't get here */
2560}
2561
2562
2563
2564
2565/**
2566 * Load VM save operation.
2567 *
2568 * @returns VBox status.
2569 *
2570 * @param pVM The VM handle.
2571 * @param pszFilename Name of the file to save the state in.
2572 * @param enmAfter What is planned after a successful load operation.
2573 * Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
2574 * @param pfnProgress Progress callback. Optional.
2575 * @param pvUser User argument for the progress callback.
2576 *
2577 * @thread EMT
2578 */
2579VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
2580{
2581 LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
2582 VM_ASSERT_EMT(pVM);
2583
2584 /*
2585 * Validate input.
2586 */
2587 if ( enmAfter != SSMAFTER_RESUME
2588 && enmAfter != SSMAFTER_DEBUG_IT)
2589 {
2590 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
2591 return VERR_INVALID_PARAMETER;
2592 }
2593
2594 /*
2595 * Create the handle and open the file.
2596 */
2597 SSMHANDLE Handle;
2598 int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, &Handle);
2599 if (RT_SUCCESS(rc))
2600 {
2601 Handle.enmAfter = enmAfter;
2602 Handle.pfnProgress = pfnProgress;
2603 Handle.pvUser = pvUser;
2604
2605 if (Handle.u.Read.u16VerMajor)
2606 LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
2607 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
2608 Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
2609 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
2610 else
2611 LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
2612 Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
2613 Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
2614
2615 if (pfnProgress)
2616 pfnProgress(pVM, Handle.uPercent, pvUser);
2617
2618 /*
2619 * Clear the per unit flags.
2620 */
2621 PSSMUNIT pUnit;
2622 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2623 pUnit->fCalled = false;
2624
2625 /*
2626 * Do the prepare run.
2627 */
2628 Handle.rc = VINF_SUCCESS;
2629 Handle.enmOp = SSMSTATE_LOAD_PREP;
2630 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2631 {
2632 if (pUnit->u.Common.pfnLoadPrep)
2633 {
2634 pUnit->fCalled = true;
2635 switch (pUnit->enmType)
2636 {
2637 case SSMUNITTYPE_DEV:
2638 rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
2639 break;
2640 case SSMUNITTYPE_DRV:
2641 rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
2642 break;
2643 case SSMUNITTYPE_INTERNAL:
2644 rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
2645 break;
2646 case SSMUNITTYPE_EXTERNAL:
2647 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
2648 break;
2649 }
2650 if (RT_FAILURE(rc))
2651 {
2652 LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
2653 break;
2654 }
2655 }
2656 }
2657
2658 /* pending 2% */
2659 if (pfnProgress)
2660 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
2661 Handle.uPercent = Handle.uPercentPrepare;
2662 Handle.cbEstTotal = Handle.u.Read.cbLoadFile;
2663 Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
2664
2665 /*
2666 * Do the execute run.
2667 */
2668 if (RT_SUCCESS(rc))
2669 {
2670 if (Handle.u.Read.uFmtVerMajor >= 2)
2671 rc = ssmR3LoadExecV2(pVM, &Handle);
2672 else
2673 rc = ssmR3LoadExecV1(pVM, &Handle);
2674 /* (progress should be pending 99% now) */
2675 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
2676 }
2677
2678 /*
2679 * Do the done run.
2680 */
2681 Handle.rc = rc;
2682 Handle.enmOp = SSMSTATE_LOAD_DONE;
2683 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
2684 {
2685 if ( pUnit->u.Common.pfnLoadDone
2686 && ( pUnit->fCalled
2687 || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
2688 {
2689 rc = VINF_SUCCESS;
2690 switch (pUnit->enmType)
2691 {
2692 case SSMUNITTYPE_DEV:
2693 rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
2694 break;
2695 case SSMUNITTYPE_DRV:
2696 rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
2697 break;
2698 case SSMUNITTYPE_INTERNAL:
2699 rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
2700 break;
2701 case SSMUNITTYPE_EXTERNAL:
2702 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
2703 break;
2704 }
2705 if (RT_FAILURE(rc))
2706 {
2707 LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
2708 rc, pUnit->szName, pUnit->u32Instance));
2709 if (RT_SUCCESS(Handle.rc))
2710 Handle.rc = rc;
2711 }
2712 }
2713 }
2714 rc = Handle.rc;
2715
2716 /* progress */
2717 if (pfnProgress)
2718 pfnProgress(pVM, 99, pvUser);
2719 }
2720
2721 /*
2722 * Done
2723 */
2724 int rc2 = RTFileClose(Handle.hFile);
2725 AssertRC(rc2);
2726 if (RT_SUCCESS(rc))
2727 {
2728 /* progress */
2729 if (pfnProgress)
2730 pfnProgress(pVM, 100, pvUser);
2731 Log(("SSM: Load of '%s' completed!\n", pszFilename));
2732 }
2733 return rc;
2734}
2735
2736
2737/**
2738 * Validates a file as a validate SSM saved state.
2739 *
2740 * This will only verify the file format, the format and content of individual
2741 * data units are not inspected.
2742 *
2743 * @returns VINF_SUCCESS if valid.
2744 * @returns VBox status code on other failures.
2745 *
2746 * @param pszFilename The path to the file to validate.
2747 * @param fChecksumIt Whether to checksum the file or not.
2748 *
2749 * @thread Any.
2750 */
2751VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
2752{
2753 LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
2754
2755 /*
2756 * Try open the file and validate it.
2757 */
2758 SSMHANDLE Handle;
2759 int rc = ssmR3OpenFile(NULL, pszFilename, fChecksumIt, false /*fChecksumOnRead*/, &Handle);
2760 if (RT_SUCCESS(rc))
2761 RTFileClose(Handle.hFile);
2762 else
2763 Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
2764 return rc;
2765}
2766
2767
2768/**
2769 * Opens a saved state file for reading.
2770 *
2771 * @returns VBox status code.
2772 *
2773 * @param pszFilename The path to the saved state file.
2774 * @param fFlags Open flags. Reserved, must be 0.
2775 * @param ppSSM Where to store the SSM handle.
2776 *
2777 * @thread Any.
2778 */
2779VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
2780{
2781 LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
2782
2783 /*
2784 * Validate input.
2785 */
2786 AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
2787 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2788 AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
2789
2790 /*
2791 * Allocate a handle.
2792 */
2793 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
2794 AssertReturn(pSSM, VERR_NO_MEMORY);
2795
2796 /*
2797 * Try open the file and validate it.
2798 */
2799 int rc = ssmR3OpenFile(NULL, pszFilename, true /*fChecksumIt*/, false /*fChecksumOnRead*/, pSSM);
2800 if (RT_SUCCESS(rc))
2801 {
2802 pSSM->enmAfter = SSMAFTER_OPENED;
2803 pSSM->enmOp = SSMSTATE_OPEN_READ;
2804 *ppSSM = pSSM;
2805 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
2806 return VINF_SUCCESS;
2807 }
2808
2809 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
2810 RTMemFree(pSSM);
2811 return rc;
2812
2813}
2814
2815
2816/**
2817 * Closes a saved state file opened by SSMR3Open().
2818 *
2819 * @returns VBox status code.
2820 *
2821 * @param pSSM The SSM handle returned by SSMR3Open().
2822 *
2823 * @thread Any, but the caller is responsible for serializing calls per handle.
2824 */
2825VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
2826{
2827 LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
2828
2829 /*
2830 * Validate input.
2831 */
2832 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
2833 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
2834 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
2835
2836 /*
2837 * Close the file and free the handle.
2838 */
2839 int rc = RTFileClose(pSSM->hFile);
2840 AssertRC(rc);
2841 if (pSSM->u.Read.pZipDecomp)
2842 {
2843 RTZipDecompDestroy(pSSM->u.Read.pZipDecomp);
2844 pSSM->u.Read.pZipDecomp = NULL;
2845 }
2846 RTMemFree(pSSM);
2847 return rc;
2848}
2849
2850
2851/**
2852 * Worker for SSMR3Seek that seeks version 1 saved state files.
2853 *
2854 * @returns VBox status code.
2855 * @param pSSM The SSM handle.
2856 * @param pszUnit The unit to seek to.
2857 * @param iInstance The particulart insance we seek.
2858 * @param piVersion Where to store the unit version number.
2859 */
2860static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
2861{
2862 /*
2863 * Walk the data units until we find EOF or a match.
2864 */
2865 size_t cbUnit = strlen(pszUnit) + 1;
2866 AssertLogRelReturn(cbUnit <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
2867 char szName[SSM_MAX_NAME_SIZE];
2868 SSMFILEUNITHDRV1 UnitHdr;
2869 for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
2870 {
2871 /*
2872 * Read the unit header and verify it.
2873 */
2874 int rc = RTFileReadAt(pSSM->hFile, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
2875 AssertRCReturn(rc, rc);
2876 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
2877 {
2878 /*
2879 * Does what we've got match, if so read the name.
2880 */
2881 if ( UnitHdr.u32Instance == iInstance
2882 && UnitHdr.cchName == cbUnit)
2883 {
2884 rc = RTFileRead(pSSM->hFile, szName, cbUnit, NULL);
2885 AssertRCReturn(rc, rc);
2886 AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
2887 (" Unit name '%.*s' was not properly terminated.\n", cbUnit, szName),
2888 VERR_SSM_INTEGRITY);
2889
2890 /*
2891 * Does the name match?
2892 */
2893 if (!memcmp(szName, pszUnit, cbUnit))
2894 {
2895 pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[cbUnit]);
2896 pSSM->offUnit = 0;
2897 if (piVersion)
2898 *piVersion = UnitHdr.u32Version;
2899 return VINF_SUCCESS;
2900 }
2901 }
2902 }
2903 else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
2904 return VERR_SSM_UNIT_NOT_FOUND;
2905 else
2906 AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
2907 off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
2908 VERR_SSM_INTEGRITY_UNIT_MAGIC);
2909 }
2910 /* won't get here. */
2911}
2912
2913
2914/**
2915 * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
2916 *
2917 * @returns VBox status code.
2918 * @param pSSM The SSM handle.
2919 * @param pszUnit The unit to seek to.
2920 * @param iInstance The particulart insance we seek.
2921 * @param piVersion Where to store the unit version number.
2922 */
2923static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries,
2924 const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
2925{
2926 /*
2927 * Read it.
2928 */
2929 uint64_t const offDir = pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR) - cbDir;
2930 int rc = RTFileReadAt(pSSM->hFile, offDir, pDir, cbDir, NULL);
2931 AssertLogRelRCReturn(rc, rc);
2932 AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY);
2933 SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
2934 AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
2935 ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
2936 VERR_SSM_INTEGRITY);
2937 for (uint32_t i = 0; i < cDirEntries; i++)
2938 AssertLogRelMsgReturn(pDir->aEntries[i].off < offDir,
2939 ("i=%u off=%lld offDir=%lld\n", i, pDir->aEntries[i].off, offDir),
2940 VERR_SSM_INTEGRITY);
2941
2942 /*
2943 * Search the directory.
2944 */
2945 size_t cbUnit = strlen(pszUnit) + 1;
2946 uint32_t const u32NameCRC = RTCrc32(pszUnit, cbUnit - 1);
2947 for (uint32_t i = 0; i < cDirEntries; i++)
2948 {
2949 if ( pDir->aEntries[i].u32NameCRC == u32NameCRC
2950 && pDir->aEntries[i].u32Instance == iInstance)
2951 {
2952 /*
2953 * Read and validate the unit header.
2954 */
2955 SSMFILEUNITHDR UnitHdr;
2956 size_t cbToRead = sizeof(UnitHdr);
2957 if (pDir->aEntries[i].off + cbToRead > offDir)
2958 {
2959 cbToRead = offDir - pDir->aEntries[i].off;
2960 RT_ZERO(UnitHdr);
2961 }
2962 rc = RTFileReadAt(pSSM->hFile, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
2963 AssertLogRelRCReturn(rc, rc);
2964
2965 AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
2966 ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
2967 VERR_SSM_INTEGRITY);
2968 AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
2969 ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
2970 VERR_SSM_INTEGRITY);
2971 AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
2972 ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
2973 i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
2974 VERR_SSM_INTEGRITY);
2975 uint32_t cbUnitHdr = RT_UOFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]);
2976 AssertLogRelMsgReturn( UnitHdr.cbName > 0
2977 && UnitHdr.cbName < sizeof(UnitHdr)
2978 && cbUnitHdr <= cbToRead,
2979 ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
2980 VERR_SSM_INTEGRITY);
2981 SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cbName]),
2982 ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
2983 i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
2984
2985 /*
2986 * Ok, it is valid, get on with the comparing now.
2987 */
2988 if ( UnitHdr.cbName == cbUnit
2989 && !memcmp(UnitHdr.szName, pszUnit, cbUnit))
2990 {
2991 if (piVersion)
2992 *piVersion = UnitHdr.u32Version;
2993 rc = RTFileSeek(pSSM->hFile, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN, NULL);
2994 AssertLogRelRCReturn(rc, rc);
2995
2996 ssmR3DataReadBeginV2(pSSM);
2997 return VINF_SUCCESS;
2998 }
2999 }
3000 }
3001
3002 return VERR_SSM_UNIT_NOT_FOUND;
3003}
3004
3005
3006/**
3007 * Worker for SSMR3Seek that seeks version 2 saved state files.
3008 *
3009 * @returns VBox status code.
3010 * @param pSSM The SSM handle.
3011 * @param pszUnit The unit to seek to.
3012 * @param iInstance The particulart insance we seek.
3013 * @param piVersion Where to store the unit version number.
3014 */
3015static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
3016{
3017 /*
3018 * Read the footer, allocate a temporary buffer for the dictionary and
3019 * pass it down to a worker to simplify cleanup.
3020 */
3021 SSMFILEFTR Footer;
3022 int rc = RTFileReadAt(pSSM->hFile, pSSM->u.Read.cbLoadFile - sizeof(Footer), &Footer, sizeof(Footer), NULL);
3023 AssertLogRelRCReturn(rc, rc);
3024 AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
3025 SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
3026
3027 size_t const cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[Footer.cDirEntries]);
3028 PSSMFILEDIR pDir = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
3029 if (RT_UNLIKELY(!pDir))
3030 return VERR_NO_TMP_MEMORY;
3031 rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, pszUnit, iInstance, piVersion);
3032 RTMemTmpFree(pDir);
3033
3034 return rc;
3035}
3036
3037
3038
3039/**
3040 * Seeks to a specific data unit.
3041 *
3042 * After seeking it's possible to use the getters to on
3043 * that data unit.
3044 *
3045 * @returns VBox status code.
3046 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
3047 *
3048 * @param pSSM The SSM handle returned by SSMR3Open().
3049 * @param pszUnit The name of the data unit.
3050 * @param iInstance The instance number.
3051 * @param piVersion Where to store the version number. (Optional)
3052 *
3053 * @thread Any, but the caller is responsible for serializing calls per handle.
3054 */
3055VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
3056{
3057 LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
3058 pSSM, pszUnit, pszUnit, iInstance, piVersion));
3059
3060 /*
3061 * Validate input.
3062 */
3063 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
3064 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
3065 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
3066 AssertMsgReturn(VALID_PTR(pszUnit), ("%p\n", pszUnit), VERR_INVALID_POINTER);
3067 AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
3068
3069 /*
3070 * Reset the state.
3071 */
3072 if (pSSM->u.Read.pZipDecomp)
3073 {
3074 RTZipDecompDestroy(pSSM->u.Read.pZipDecomp);
3075 pSSM->u.Read.pZipDecomp = NULL;
3076 }
3077 pSSM->cbUnitLeftV1 = 0;
3078 pSSM->offUnit = UINT64_MAX;
3079
3080 /*
3081 * Call the version specific workers.
3082 */
3083 if (pSSM->u.Read.uFmtVerMajor >= 2)
3084 pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
3085 else
3086 pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
3087 return pSSM->rc;
3088}
3089
3090
3091/**
3092 * Finishes a data unit.
3093 * All buffers and compressor instances are flushed and destroyed.
3094 *
3095 * @returns VBox status.
3096 * @param pSSM SSM operation handle.
3097 */
3098static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
3099{
3100 //Log2(("ssmR3DataWriteFinish: %#010llx start\n", RTFileTell(pSSM->File)));
3101 int rc = ssmR3DataFlushBuffer(pSSM);
3102 if (RT_SUCCESS(rc))
3103 {
3104 if (!pSSM->u.Write.pZipComp)
3105 return VINF_SUCCESS;
3106
3107 int rc = RTZipCompFinish(pSSM->u.Write.pZipComp);
3108 if (RT_SUCCESS(rc))
3109 {
3110 rc = RTZipCompDestroy(pSSM->u.Write.pZipComp);
3111 if (RT_SUCCESS(rc))
3112 {
3113 pSSM->u.Write.pZipComp = NULL;
3114 //Log2(("ssmR3DataWriteFinish: %#010llx done\n", RTFileTell(pSSM->File)));
3115 return VINF_SUCCESS;
3116 }
3117 }
3118 }
3119
3120 if (RT_SUCCESS(pSSM->rc))
3121 pSSM->rc = rc;
3122 Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
3123 return rc;
3124}
3125
3126
3127/**
3128 * Callback for flusing the output buffer of a compression stream.
3129 *
3130 * @returns VBox status.
3131 * @param pSSM The saved state handle.
3132 * @param pvBuf Compressed data.
3133 * @param cbBuf Size of the compressed data.
3134 */
3135static DECLCALLBACK(int) ssmR3WriteOut(void *pvSSM, const void *pvBuf, size_t cbBuf)
3136{
3137 return ssmR3StrmWrite((PSSMHANDLE)pvSSM, pvBuf, cbBuf);
3138}
3139
3140
3141/**
3142 * Begins writing the data of a data unit.
3143 *
3144 * Errors are signalled via pSSM->rc.
3145 *
3146 * @param pSSM The saved state handle.
3147 */
3148static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
3149{
3150 Assert(!pSSM->u.Write.pZipComp);
3151
3152 pSSM->u.Write.pZipComp = NULL;
3153 pSSM->offUnit = 0;
3154 if (pSSM->fUnitChecksummed)
3155 pSSM->u32UnitCRC = RTCrc32Start();
3156
3157 //int rc = RTZipCompCreate(&pSSM->u.Write.pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_ZLIB, RTZIPLEVEL_FAST);
3158 int rc = RTZipCompCreate(&pSSM->u.Write.pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_LZF, RTZIPLEVEL_FAST);
3159 //int rc = RTZipCompCreate(&pSSM->u.Write.pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_STORE, RTZIPLEVEL_FAST);
3160 if (RT_FAILURE(rc) && RT_SUCCESS(pSSM->rc))
3161 pSSM->rc = rc;
3162}
3163
3164
3165/**
3166 * Writes a record to the current data item in the saved state file.
3167 *
3168 * @returns VBox status code. Sets pSSM->rc on failure.
3169 * @param pSSM The saved state handle.
3170 * @param pvBuf The bits to write.
3171 * @param cbBuf The number of bytes to write.
3172 */
3173static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3174{
3175 Log2(("ssmR3DataWriteRaw: %08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n", pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
3176
3177 /*
3178 * Check that everything is fine.
3179 */
3180 if (RT_FAILURE(pSSM->rc))
3181 return pSSM->rc;
3182
3183 /*
3184 * Do the stream checksumming before we write the data.
3185 */
3186 if (pSSM->fUnitChecksummed)
3187 pSSM->u32UnitCRC = RTCrc32Process(pSSM->u32UnitCRC, pvBuf, cbBuf);
3188
3189 /*
3190 * Write the data item in 1MB chunks for progress indicator reasons.
3191 */
3192 while (cbBuf > 0)
3193 {
3194 size_t cbChunk = RT_MIN(cbBuf, _1M);
3195 int rc = pSSM->rc = RTZipCompress(pSSM->u.Write.pZipComp, pvBuf, cbChunk);
3196 if (RT_FAILURE(rc))
3197 return rc;
3198 ssmR3Progress(pSSM, cbChunk);
3199 pSSM->offUnit += cbChunk;
3200 cbBuf -= cbChunk;
3201 pvBuf = (char *)pvBuf + cbChunk;
3202 }
3203
3204 return VINF_SUCCESS;
3205}
3206
3207/**
3208 * Writes a record header for the specified amount of data.
3209 *
3210 * @returns VBox status code. Sets pSSM->rc on failure.
3211 * @param pSSM The saved state handle
3212 * @param cb The amount of data.
3213 * @param u8TypeAndFlags The record type and flags.
3214 */
3215static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
3216{
3217 size_t cbHdr;
3218 uint8_t abHdr[8];
3219 abHdr[0] = u8TypeAndFlags;
3220 if (cb < 0x80)
3221 {
3222 cbHdr = 2;
3223 abHdr[1] = cb;
3224 }
3225 else if (cb < 0x00000800)
3226 {
3227 cbHdr = 3;
3228 abHdr[1] = 0xc0 | (cb >> 6);
3229 abHdr[2] = 0x80 | (cb & 0x3f);
3230 }
3231 else if (cb < 0x00010000)
3232 {
3233 cbHdr = 4;
3234 abHdr[1] = 0xe0 | (cb >> 12);
3235 abHdr[2] = 0x80 | ((cb >> 6) & 0x3f);
3236 abHdr[3] = 0x80 | (cb & 0x3f);
3237 }
3238 else if (cb < 0x00200000)
3239 {
3240 cbHdr = 5;
3241 abHdr[1] = 0xf0 | (cb >> 18);
3242 abHdr[2] = 0x80 | ((cb >> 12) & 0x3f);
3243 abHdr[3] = 0x80 | ((cb >> 6) & 0x3f);
3244 abHdr[4] = 0x80 | (cb & 0x3f);
3245 }
3246 else if (cb < 0x04000000)
3247 {
3248 cbHdr = 6;
3249 abHdr[1] = 0xf8 | (cb >> 24);
3250 abHdr[2] = 0x80 | ((cb >> 18) & 0x3f);
3251 abHdr[3] = 0x80 | ((cb >> 12) & 0x3f);
3252 abHdr[4] = 0x80 | ((cb >> 6) & 0x3f);
3253 abHdr[5] = 0x80 | (cb & 0x3f);
3254 }
3255 else if (cb <= 0x7fffffff)
3256 {
3257 cbHdr = 7;
3258 abHdr[1] = 0xfc | (cb >> 30);
3259 abHdr[2] = 0x80 | ((cb >> 24) & 0x3f);
3260 abHdr[3] = 0x80 | ((cb >> 18) & 0x3f);
3261 abHdr[4] = 0x80 | ((cb >> 12) & 0x3f);
3262 abHdr[5] = 0x80 | ((cb >> 6) & 0x3f);
3263 abHdr[6] = 0x80 | (cb & 0x3f);
3264 }
3265 else
3266 AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_INTERNAL_ERROR);
3267
3268 Log3(("ssmR3DataWriteRecHdr: %08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
3269 pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
3270
3271 return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
3272}
3273
3274
3275/**
3276 * Worker that flushes the buffered data.
3277 *
3278 * @returns VBox status code. Will set pSSM->rc on error.
3279 * @param pSSM The saved state handle.
3280 */
3281static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
3282{
3283 uint32_t cb = pSSM->u.Write.offDataBuffer;
3284 if (!cb)
3285 return pSSM->rc;
3286
3287 /*
3288 * Create a record header.
3289 */
3290 uint32_t cbTotal = cb + 1;
3291 uint8_t *pbHdr = &pSSM->u.Write.abRecHdr[sizeof(pSSM->u.Write.abRecHdr) - 1];
3292 if (cb < 0x80)
3293 {
3294 cbTotal += 1;
3295 pbHdr -= 1;
3296 pbHdr[1] = cb;
3297 }
3298 else if (cb < 0x00000800)
3299 {
3300 cbTotal += 2;
3301 pbHdr -= 2;
3302 pbHdr[1] = 0xc0 | (cb >> 6);
3303 pbHdr[2] = 0x80 | (cb & 0x3f);
3304 }
3305 else if (cb < 0x00010000)
3306 {
3307 cbTotal += 3;
3308 pbHdr -= 3;
3309 pbHdr[1] = 0xe0 | (cb >> 12);
3310 pbHdr[2] = 0x80 | ((cb >> 6) & 0x3f);
3311 pbHdr[3] = 0x80 | (cb & 0x3f);
3312 }
3313 else if (cb < 0x00200000)
3314 {
3315 cbTotal += 4;
3316 pbHdr -= 4;
3317 pbHdr[1] = 0xf0 | (cb >> 18);
3318 pbHdr[2] = 0x80 | ((cb >> 12) & 0x3f);
3319 pbHdr[3] = 0x80 | ((cb >> 6) & 0x3f);
3320 pbHdr[4] = 0x80 | (cb & 0x3f);
3321 }
3322 else if (cb < 0x04000000)
3323 {
3324 cbTotal += 5;
3325 pbHdr -= 5;
3326 pbHdr[1] = 0xf8 | (cb >> 24);
3327 pbHdr[2] = 0x80 | ((cb >> 18) & 0x3f);
3328 pbHdr[3] = 0x80 | ((cb >> 12) & 0x3f);
3329 pbHdr[4] = 0x80 | ((cb >> 6) & 0x3f);
3330 pbHdr[5] = 0x80 | (cb & 0x3f);
3331 }
3332 else if (cb <= 0x7fffffff)
3333 {
3334 cbTotal += 6;
3335 pbHdr -= 6;
3336 pbHdr[1] = 0xfc | (cb >> 30);
3337 pbHdr[2] = 0x80 | ((cb >> 24) & 0x3f);
3338 pbHdr[3] = 0x80 | ((cb >> 18) & 0x3f);
3339 pbHdr[4] = 0x80 | ((cb >> 12) & 0x3f);
3340 pbHdr[5] = 0x80 | ((cb >> 6) & 0x3f);
3341 pbHdr[6] = 0x80 | (cb & 0x3f);
3342 }
3343 else
3344 AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), VERR_INTERNAL_ERROR);
3345 pbHdr[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
3346
3347 Log3(("ssmR3DataFlushBuffer: %08llx/%08x: Type=RAW fImportant=true cbHdr=%u\n",
3348 pSSM->offUnit + (cbTotal - cb), cb, (cbTotal - cb) ));
3349
3350 /*
3351 * Write it and reset the buffer.
3352 */
3353 int rc = ssmR3DataWriteRaw(pSSM, pbHdr, cbTotal);
3354 pSSM->u.Write.offDataBuffer = 0;
3355 return rc;
3356}
3357
3358
3359/**
3360 * ssmR3DataWrite worker that writes big stuff.
3361 *
3362 * @returns VBox status code
3363 * @param pSSM The saved state handle.
3364 * @param pvBuf The bits to write.
3365 * @param cbBuf The number of bytes to write.
3366 */
3367static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3368{
3369 int rc = ssmR3DataFlushBuffer(pSSM);
3370 if (RT_SUCCESS(rc))
3371 {
3372 rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
3373 if (RT_SUCCESS(rc))
3374 rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
3375 }
3376 return rc;
3377}
3378
3379/**
3380 * ssmR3DataWrite worker that is called when there isn't enough room in the
3381 * buffer for the current chunk of data.
3382 *
3383 * This will first flush the buffer and then add the new bits to it.
3384 *
3385 * @returns VBox status code
3386 * @param pSSM The saved state handle.
3387 * @param pvBuf The bits to write.
3388 * @param cbBuf The number of bytes to write.
3389 */
3390static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3391{
3392 int rc = ssmR3DataFlushBuffer(pSSM);
3393 if (RT_SUCCESS(rc))
3394 {
3395 memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
3396 pSSM->u.Write.offDataBuffer = cbBuf;
3397 }
3398 return rc;
3399}
3400
3401
3402/**
3403 * Writes data to the current data unit.
3404 *
3405 * This is an inlined wrapper that optimizes the small writes that so many of
3406 * the APIs make.
3407 *
3408 * @returns VBox status code
3409 * @param pSSM The saved state handle.
3410 * @param pvBuf The bits to write.
3411 * @param cbBuf The number of bytes to write.
3412 */
3413DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
3414{
3415 if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
3416 return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
3417 if (!cbBuf)
3418 return VINF_SUCCESS;
3419
3420 uint32_t off = pSSM->u.Write.offDataBuffer;
3421 if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
3422 return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
3423
3424 memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
3425 pSSM->u.Write.offDataBuffer = off + cbBuf;
3426 return VINF_SUCCESS;
3427}
3428
3429
3430/**
3431 * Puts a structure.
3432 *
3433 * @returns VBox status code.
3434 * @param pSSM The saved state handle.
3435 * @param pvStruct The structure address.
3436 * @param paFields The array of structure fields descriptions.
3437 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
3438 */
3439VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
3440{
3441 /* begin marker. */
3442 int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
3443 if (RT_FAILURE(rc))
3444 return rc;
3445
3446 /* put the fields */
3447 for (PCSSMFIELD pCur = paFields;
3448 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
3449 pCur++)
3450 {
3451 rc = ssmR3DataWrite(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
3452 if (RT_FAILURE(rc))
3453 return rc;
3454 }
3455
3456 /* end marker */
3457 return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
3458}
3459
3460
3461/**
3462 * Saves a boolean item to the current data unit.
3463 *
3464 * @returns VBox status.
3465 * @param pSSM SSM operation handle.
3466 * @param fBool Item to save.
3467 */
3468VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
3469{
3470 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3471 {
3472 uint8_t u8 = fBool; /* enforce 1 byte size */
3473 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
3474 }
3475 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3476 return VERR_SSM_INVALID_STATE;
3477}
3478
3479
3480/**
3481 * Saves a 8-bit unsigned integer item to the current data unit.
3482 *
3483 * @returns VBox status.
3484 * @param pSSM SSM operation handle.
3485 * @param u8 Item to save.
3486 */
3487VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
3488{
3489 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3490 return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
3491 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3492 return VERR_SSM_INVALID_STATE;
3493}
3494
3495
3496/**
3497 * Saves a 8-bit signed integer item to the current data unit.
3498 *
3499 * @returns VBox status.
3500 * @param pSSM SSM operation handle.
3501 * @param i8 Item to save.
3502 */
3503VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
3504{
3505 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3506 return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
3507 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3508 return VERR_SSM_INVALID_STATE;
3509}
3510
3511
3512/**
3513 * Saves a 16-bit unsigned integer item to the current data unit.
3514 *
3515 * @returns VBox status.
3516 * @param pSSM SSM operation handle.
3517 * @param u16 Item to save.
3518 */
3519VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
3520{
3521 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3522 return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
3523 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3524 return VERR_SSM_INVALID_STATE;
3525}
3526
3527
3528/**
3529 * Saves a 16-bit signed integer item to the current data unit.
3530 *
3531 * @returns VBox status.
3532 * @param pSSM SSM operation handle.
3533 * @param i16 Item to save.
3534 */
3535VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
3536{
3537 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3538 return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
3539 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3540 return VERR_SSM_INVALID_STATE;
3541}
3542
3543
3544/**
3545 * Saves a 32-bit unsigned integer item to the current data unit.
3546 *
3547 * @returns VBox status.
3548 * @param pSSM SSM operation handle.
3549 * @param u32 Item to save.
3550 */
3551VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
3552{
3553 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3554 return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
3555 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3556 return VERR_SSM_INVALID_STATE;
3557}
3558
3559
3560/**
3561 * Saves a 32-bit signed integer item to the current data unit.
3562 *
3563 * @returns VBox status.
3564 * @param pSSM SSM operation handle.
3565 * @param i32 Item to save.
3566 */
3567VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
3568{
3569 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3570 return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
3571 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3572 return VERR_SSM_INVALID_STATE;
3573}
3574
3575
3576/**
3577 * Saves a 64-bit unsigned integer item to the current data unit.
3578 *
3579 * @returns VBox status.
3580 * @param pSSM SSM operation handle.
3581 * @param u64 Item to save.
3582 */
3583VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
3584{
3585 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3586 return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
3587 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3588 return VERR_SSM_INVALID_STATE;
3589}
3590
3591
3592/**
3593 * Saves a 64-bit signed integer item to the current data unit.
3594 *
3595 * @returns VBox status.
3596 * @param pSSM SSM operation handle.
3597 * @param i64 Item to save.
3598 */
3599VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
3600{
3601 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3602 return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
3603 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3604 return VERR_SSM_INVALID_STATE;
3605}
3606
3607
3608/**
3609 * Saves a 128-bit unsigned integer item to the current data unit.
3610 *
3611 * @returns VBox status.
3612 * @param pSSM SSM operation handle.
3613 * @param u128 Item to save.
3614 */
3615VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
3616{
3617 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3618 return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
3619 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3620 return VERR_SSM_INVALID_STATE;
3621}
3622
3623
3624/**
3625 * Saves a 128-bit signed integer item to the current data unit.
3626 *
3627 * @returns VBox status.
3628 * @param pSSM SSM operation handle.
3629 * @param i128 Item to save.
3630 */
3631VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
3632{
3633 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3634 return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
3635 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3636 return VERR_SSM_INVALID_STATE;
3637}
3638
3639
3640/**
3641 * Saves a VBox unsigned integer item to the current data unit.
3642 *
3643 * @returns VBox status.
3644 * @param pSSM SSM operation handle.
3645 * @param u Item to save.
3646 */
3647VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
3648{
3649 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3650 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3651 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3652 return VERR_SSM_INVALID_STATE;
3653}
3654
3655
3656/**
3657 * Saves a VBox signed integer item to the current data unit.
3658 *
3659 * @returns VBox status.
3660 * @param pSSM SSM operation handle.
3661 * @param i Item to save.
3662 */
3663VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
3664{
3665 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3666 return ssmR3DataWrite(pSSM, &i, sizeof(i));
3667 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3668 return VERR_SSM_INVALID_STATE;
3669}
3670
3671
3672/**
3673 * Saves a GC natural unsigned integer item to the current data unit.
3674 *
3675 * @returns VBox status.
3676 * @param pSSM SSM operation handle.
3677 * @param u Item to save.
3678 *
3679 * @deprecated Silly type, don't use it.
3680 */
3681VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
3682{
3683 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3684 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3685 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3686 return VERR_SSM_INVALID_STATE;
3687}
3688
3689
3690/**
3691 * Saves a GC unsigned integer register item to the current data unit.
3692 *
3693 * @returns VBox status.
3694 * @param pSSM SSM operation handle.
3695 * @param u Item to save.
3696 */
3697VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
3698{
3699 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3700 return ssmR3DataWrite(pSSM, &u, sizeof(u));
3701 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3702 return VERR_SSM_INVALID_STATE;
3703}
3704
3705
3706/**
3707 * Saves a 32 bits GC physical address item to the current data unit.
3708 *
3709 * @returns VBox status.
3710 * @param pSSM SSM operation handle.
3711 * @param GCPhys The item to save
3712 */
3713VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
3714{
3715 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3716 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3717 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3718 return VERR_SSM_INVALID_STATE;
3719}
3720
3721
3722/**
3723 * Saves a 64 bits GC physical address item to the current data unit.
3724 *
3725 * @returns VBox status.
3726 * @param pSSM SSM operation handle.
3727 * @param GCPhys The item to save
3728 */
3729VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
3730{
3731 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3732 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3733 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3734 return VERR_SSM_INVALID_STATE;
3735}
3736
3737
3738/**
3739 * Saves a GC physical address item to the current data unit.
3740 *
3741 * @returns VBox status.
3742 * @param pSSM SSM operation handle.
3743 * @param GCPhys The item to save
3744 */
3745VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
3746{
3747 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3748 return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
3749 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3750 return VERR_SSM_INVALID_STATE;
3751}
3752
3753
3754/**
3755 * Saves a GC virtual address item to the current data unit.
3756 *
3757 * @returns VBox status.
3758 * @param pSSM SSM operation handle.
3759 * @param GCPtr The item to save.
3760 */
3761VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
3762{
3763 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3764 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
3765 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3766 return VERR_SSM_INVALID_STATE;
3767}
3768
3769
3770/**
3771 * Saves an RC virtual address item to the current data unit.
3772 *
3773 * @returns VBox status.
3774 * @param pSSM SSM operation handle.
3775 * @param RCPtr The item to save.
3776 */
3777VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
3778{
3779 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3780 return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
3781 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3782 return VERR_SSM_INVALID_STATE;
3783}
3784
3785
3786/**
3787 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
3788 *
3789 * @returns VBox status.
3790 * @param pSSM SSM operation handle.
3791 * @param GCPtr The item to save.
3792 */
3793VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
3794{
3795 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3796 return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
3797 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3798 return VERR_SSM_INVALID_STATE;
3799}
3800
3801
3802/**
3803 * Saves a I/O port address item to the current data unit.
3804 *
3805 * @returns VBox status.
3806 * @param pSSM SSM operation handle.
3807 * @param IOPort The item to save.
3808 */
3809VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
3810{
3811 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3812 return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
3813 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3814 return VERR_SSM_INVALID_STATE;
3815}
3816
3817
3818/**
3819 * Saves a selector item to the current data unit.
3820 *
3821 * @returns VBox status.
3822 * @param pSSM SSM operation handle.
3823 * @param Sel The item to save.
3824 */
3825VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
3826{
3827 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3828 return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
3829 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3830 return VERR_SSM_INVALID_STATE;
3831}
3832
3833
3834/**
3835 * Saves a memory item to the current data unit.
3836 *
3837 * @returns VBox status.
3838 * @param pSSM SSM operation handle.
3839 * @param pv Item to save.
3840 * @param cb Size of the item.
3841 */
3842VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
3843{
3844 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3845 return ssmR3DataWrite(pSSM, pv, cb);
3846 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3847 return VERR_SSM_INVALID_STATE;
3848}
3849
3850
3851/**
3852 * Saves a zero terminated string item to the current data unit.
3853 *
3854 * @returns VBox status.
3855 * @param pSSM SSM operation handle.
3856 * @param psz Item to save.
3857 */
3858VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
3859{
3860 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
3861 {
3862 size_t cch = strlen(psz);
3863 if (cch > _1M)
3864 {
3865 AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
3866 return VERR_TOO_MUCH_DATA;
3867 }
3868 uint32_t u32 = (uint32_t)cch;
3869 int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
3870 if (rc)
3871 return rc;
3872 return ssmR3DataWrite(pSSM, psz, cch);
3873 }
3874 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3875 return VERR_SSM_INVALID_STATE;
3876}
3877
3878
3879
3880
3881
3882/**
3883 * Closes the decompressor of a data unit.
3884 *
3885 * @param pSSM SSM operation handle.
3886 */
3887static void ssmR3DataReadFinishV1(PSSMHANDLE pSSM)
3888{
3889 if (pSSM->u.Read.pZipDecomp)
3890 {
3891 int rc = RTZipDecompDestroy(pSSM->u.Read.pZipDecomp);
3892 AssertRC(rc);
3893 pSSM->u.Read.pZipDecomp = NULL;
3894 }
3895}
3896
3897
3898/**
3899 * Callback for reading compressed data into the input buffer of the
3900 * decompressor, for saved file format version 1.
3901 *
3902 * @returns VBox status code.
3903 * @param pvSSM The SSM handle.
3904 * @param pvBuf Where to store the compressed data.
3905 * @param cbBuf Size of the buffer.
3906 * @param pcbRead Number of bytes actually stored in the buffer.
3907 */
3908static DECLCALLBACK(int) ssmR3ReadInV1(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
3909{
3910 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
3911 size_t cbRead = cbBuf;
3912 if (pSSM->cbUnitLeftV1 < cbBuf)
3913 cbRead = (size_t)pSSM->cbUnitLeftV1;
3914 if (cbRead)
3915 {
3916 //Log2(("ssmR3ReadInV1: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->File), cbBuf, cbRead));
3917 int rc = ssmR3StrmRead(pSSM, pvBuf, cbRead);
3918 if (RT_SUCCESS(rc))
3919 {
3920 pSSM->cbUnitLeftV1 -= cbRead;
3921 if (pcbRead)
3922 *pcbRead = cbRead;
3923 ssmR3Progress(pSSM, cbRead);
3924 return VINF_SUCCESS;
3925 }
3926 return rc;
3927 }
3928
3929 /** @todo weed out lazy saving */
3930 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
3931 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
3932 return VERR_SSM_LOADED_TOO_MUCH;
3933}
3934
3935
3936/**
3937 * Internal read worker for reading data from a version 1 unit.
3938 *
3939 * @param pSSM SSM operation handle.
3940 * @param pvBuf Where to store the read data.
3941 * @param cbBuf Number of bytes to read.
3942 */
3943static int ssmR3DataReadV1(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
3944{
3945 /*
3946 * Open the decompressor on the first read.
3947 */
3948 if (!pSSM->u.Read.pZipDecomp)
3949 {
3950 pSSM->rc = RTZipDecompCreate(&pSSM->u.Read.pZipDecomp, pSSM, ssmR3ReadInV1);
3951 if (RT_FAILURE(pSSM->rc))
3952 return pSSM->rc;
3953 }
3954
3955 /*
3956 * Do the requested read.
3957 */
3958 int rc = pSSM->rc = RTZipDecompress(pSSM->u.Read.pZipDecomp, pvBuf, cbBuf, NULL);
3959 if (RT_SUCCESS(rc))
3960 {
3961 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 ? "..." : ""));
3962 pSSM->offUnit += cbBuf;
3963 return VINF_SUCCESS;
3964 }
3965 AssertMsgFailed(("rc=%Rrc cbBuf=%#x\n", rc, cbBuf));
3966 return rc;
3967}
3968
3969
3970/**
3971 * Callback for reading compressed data into the input buffer of the
3972 * decompressor, for saved file format version 2.
3973 *
3974 * @returns VBox status code.
3975 * @param pvSSM The SSM handle.
3976 * @param pvBuf Where to store the compressed data.
3977 * @param cbBuf Size of the buffer.
3978 * @param pcbRead Number of bytes actually stored in the buffer.
3979 */
3980static DECLCALLBACK(int) ssmR3ReadInV2(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
3981{
3982 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
3983 //Log2(("ssmR3ReadInV2: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->hFile), cbBuf, cbRead));
3984 int rc = ssmR3StrmRead(pSSM, pvBuf, cbBuf);
3985 if (RT_SUCCESS(rc))
3986 {
3987 if (pcbRead)
3988 *pcbRead = cbBuf;
3989 ssmR3Progress(pSSM, cbBuf);
3990 return VINF_SUCCESS;
3991 }
3992 /** @todo weed out lazy saving */
3993 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
3994 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
3995 return VERR_SSM_LOADED_TOO_MUCH;
3996}
3997
3998
3999/**
4000 * Creates the decompressor for the data unit.
4001 *
4002 * pSSM->rc will be set on error.
4003 *
4004 * @param pSSM SSM operation handle.
4005 */
4006static void ssmR3DataReadBeginV2(PSSMHANDLE pSSM)
4007{
4008 Assert(!pSSM->u.Read.pZipDecomp);
4009 Assert(!pSSM->u.Read.cbDataBuffer || pSSM->u.Read.cbDataBuffer == pSSM->u.Read.offDataBuffer);
4010 Assert(!pSSM->u.Read.cbRecLeft);
4011
4012 pSSM->offUnit = 0;
4013 pSSM->u.Read.pZipDecomp = NULL;
4014 pSSM->u.Read.cbRecLeft = 0;
4015 pSSM->u.Read.cbDataBuffer = 0;
4016 pSSM->u.Read.offDataBuffer = 0;
4017 pSSM->u.Read.fEndOfData = false;
4018 pSSM->u.Read.u8TypeAndFlags = 0;
4019
4020 int rc = RTZipDecompCreate(&pSSM->u.Read.pZipDecomp, pSSM, ssmR3ReadInV2);
4021 if (RT_FAILURE(rc) && RT_SUCCESS(pSSM->rc))
4022 pSSM->rc = rc;
4023}
4024
4025
4026/**
4027 * Checks for the termination record and closes the decompressor.
4028 *
4029 * pSSM->rc will be set on error.
4030 *
4031 * @param pSSM SSM operation handle.
4032 */
4033static void ssmR3DataReadFinishV2(PSSMHANDLE pSSM)
4034{
4035 if (RT_UNLIKELY(!pSSM->u.Read.pZipDecomp))
4036 {
4037 Assert(RT_FAILURE_NP(pSSM->rc));
4038 return;
4039 }
4040
4041 /*
4042 * If we haven't encountered the end of the record, it must be the next one.
4043 */
4044 if ( !pSSM->u.Read.fEndOfData
4045 && RT_SUCCESS(pSSM->rc))
4046 {
4047 int rc = ssmR3DataReadRecHdrV2(pSSM);
4048 if ( RT_SUCCESS(rc)
4049 && !pSSM->u.Read.fEndOfData)
4050 rc = VERR_SSM_LOADED_TOO_MUCH; /** @todo More error codes! */
4051 pSSM->rc = rc;
4052 }
4053
4054 /*
4055 * Destroy the decompressor.
4056 */
4057 int rc = RTZipDecompDestroy(pSSM->u.Read.pZipDecomp);
4058 if (RT_FAILURE(rc))
4059 {
4060 AssertRC(rc);
4061 if (RT_SUCCESS(pSSM->rc))
4062 pSSM->rc = rc;
4063 }
4064 pSSM->u.Read.pZipDecomp = NULL;
4065}
4066
4067
4068/**
4069 * Read reader that does the decompression and keeps the offset and CRC members
4070 * up to date.
4071 *
4072 * Does not set SSM::rc.
4073 *
4074 * @returns VBox status code.
4075 * @param pSSM The saved state handle.
4076 * @param pvBuf Where to put the bits
4077 * @param cbBuf How many bytes to read.
4078 */
4079DECLINLINE(int) ssmR3DataReadV2Raw(PSSMHANDLE pSSM, void *pvBuf, size_t cbToRead)
4080{
4081 int rc = RTZipDecompress(pSSM->u.Read.pZipDecomp, pvBuf, cbToRead, NULL);
4082 if (RT_FAILURE(rc))
4083 return rc;
4084 pSSM->offUnit += cbToRead;
4085 if (pSSM->fUnitChecksummed)
4086 pSSM->u32UnitCRC = RTCrc32Process(pSSM->u32UnitCRC, pvBuf, cbToRead);
4087 return VINF_SUCCESS;
4088}
4089
4090
4091/**
4092 * Worker for reading the record header.
4093 *
4094 * It sets pSSM->u.Read.cbRecLeft, pSSM->u.Read.u8TypeAndFlags and
4095 * pSSM->u.Read.fEndOfData. When a termination record is encounter, it will be
4096 * read in full and validated, the fEndOfData indicator is set, and VINF_SUCCESS
4097 * is returned.
4098 *
4099 * @returns VBox status code.
4100 * @param pSSM The saved state handle.
4101 */
4102static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM)
4103{
4104 AssertLogRelReturn(!pSSM->u.Read.fEndOfData, VERR_SSM_LOADED_TOO_MUCH);
4105
4106 /*
4107 * Read the two mandatory bytes.
4108 */
4109 uint32_t u32UnitCRC = pSSM->u32UnitCRC;
4110 uint8_t abHdr[8];
4111 int rc = ssmR3DataReadV2Raw(pSSM, abHdr, 2);
4112 if (RT_FAILURE(rc))
4113 return rc;
4114
4115 /*
4116 * Validate the first byte and check for the termination records.
4117 */
4118 pSSM->u.Read.u8TypeAndFlags = abHdr[0];
4119 AssertLogRelMsgReturn(SSM_REC_ARE_TYPE_AND_FLAGS_VALID(abHdr[0]), ("%#x %#x\n", abHdr[0], abHdr[1]), VERR_SSM_INTEGRITY);
4120 if ((abHdr[0] & SSM_REC_TYPE_MASK) == SSM_REC_TYPE_TERM)
4121 {
4122 pSSM->u.Read.cbRecLeft = 0;
4123 pSSM->u.Read.fEndOfData = true;
4124 AssertLogRelMsgReturn(abHdr[1] == sizeof(SSMRECTERM) - 2, ("%#x\n", abHdr[1]), VERR_SSM_INTEGRITY);
4125 AssertLogRelMsgReturn(abHdr[0] & SSM_REC_FLAGS_IMPORTANT, ("%#x\n", abHdr[0]), VERR_SSM_INTEGRITY);
4126
4127 /* get the rest */
4128 SSMRECTERM TermRec;
4129 int rc = ssmR3DataReadV2Raw(pSSM, (uint8_t *)&TermRec + 2, sizeof(SSMRECTERM) - 2);
4130 if (RT_FAILURE(rc))
4131 return rc;
4132
4133 /* validate integrity */
4134 AssertLogRelMsgReturn(TermRec.cbUnit == pSSM->offUnit,
4135 ("cbUnit=%#llx offUnit=%#llx\n", TermRec.cbUnit, pSSM->offUnit),
4136 VERR_SSM_INTEGRITY);
4137 AssertLogRelMsgReturn(!(TermRec.fFlags & ~SSMRECTERM_FLAGS_CRC32), ("%#x\n", TermRec.fFlags), VERR_SSM_INTEGRITY);
4138 if (!(TermRec.fFlags & SSMRECTERM_FLAGS_CRC32))
4139 AssertLogRelMsgReturn(TermRec.u32CRC == 0, ("%#x\n", TermRec.u32CRC), VERR_SSM_INTEGRITY);
4140 else if (pSSM->fUnitChecksummed)
4141 {
4142 u32UnitCRC = RTCrc32Finish(u32UnitCRC);
4143 AssertLogRelMsgReturn(TermRec.u32CRC == u32UnitCRC, ("%#x, %#x\n", TermRec.u32CRC, u32UnitCRC), VERR_SSM_INTEGRITY_CRC);
4144 }
4145
4146 Log3(("ssmR3DataReadRecHdrV2: %08llx: TERM\n", pSSM->offUnit));
4147 return VINF_SUCCESS;
4148 }
4149
4150 /*
4151 * Figure the size. The 2nd byte is encoded in UTF-8 fashion, so this
4152 * is can be highly enjoyable.
4153 */
4154 uint32_t cbHdr = 2;
4155 uint32_t cb = abHdr[1];
4156 if (!(cb & 0x80))
4157 pSSM->u.Read.cbRecLeft = cb;
4158 else
4159 {
4160 /*
4161 * Need more data. Figure how much and read it.
4162 */
4163 if (!(cb & RT_BIT(5)))
4164 cb = 2;
4165 else if (!(cb & RT_BIT(4)))
4166 cb = 3;
4167 else if (!(cb & RT_BIT(3)))
4168 cb = 4;
4169 else if (!(cb & RT_BIT(2)))
4170 cb = 5;
4171 else if (!(cb & RT_BIT(1)))
4172 cb = 6;
4173 else
4174 AssertLogRelMsgFailedReturn(("Invalid record size byte: %#x\n", cb), VERR_SSM_INTEGRITY);
4175 cbHdr = cb + 1;
4176
4177 rc = ssmR3DataReadV2Raw(pSSM, &abHdr[2], cb - 1);
4178 if (RT_FAILURE(rc))
4179 return rc;
4180Log(("ssmR3DataReadRecHdrV2: cb=%u %.*Rhxs\n", cb, cb + 1, abHdr));
4181
4182 /*
4183 * Validate what we've read.
4184 */
4185 switch (cb)
4186 {
4187 case 6:
4188 AssertLogRelMsgReturn((abHdr[6] & 0xc0) == 0x80, ("6/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
4189 case 5:
4190 AssertLogRelMsgReturn((abHdr[5] & 0xc0) == 0x80, ("5/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
4191 case 4:
4192 AssertLogRelMsgReturn((abHdr[4] & 0xc0) == 0x80, ("4/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
4193 case 3:
4194 AssertLogRelMsgReturn((abHdr[3] & 0xc0) == 0x80, ("3/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
4195 case 2:
4196 AssertLogRelMsgReturn((abHdr[2] & 0xc0) == 0x80, ("2/%u: %.*Rhxs\n", cb, cb + 1, &abHdr[0]), VERR_SSM_INTEGRITY);
4197 break;
4198 default:
4199 return VERR_INTERNAL_ERROR;
4200 }
4201
4202 /*
4203 * Decode it and validate the range.
4204 */
4205 switch (cb)
4206 {
4207 case 6:
4208 cb = (abHdr[6] & 0x3f)
4209 | ((uint32_t)(abHdr[5] & 0x3f) << 6)
4210 | ((uint32_t)(abHdr[4] & 0x3f) << 12)
4211 | ((uint32_t)(abHdr[3] & 0x3f) << 18)
4212 | ((uint32_t)(abHdr[2] & 0x3f) << 24)
4213 | ((uint32_t)(abHdr[1] & 0x01) << 30);
4214 AssertLogRelMsgReturn(cb >= 0x04000000 && cb <= 0x7fffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
4215 break;
4216 case 5:
4217 cb = (abHdr[5] & 0x3f)
4218 | ((uint32_t)(abHdr[4] & 0x3f) << 6)
4219 | ((uint32_t)(abHdr[3] & 0x3f) << 12)
4220 | ((uint32_t)(abHdr[2] & 0x3f) << 18)
4221 | ((uint32_t)(abHdr[1] & 0x03) << 24);
4222 AssertLogRelMsgReturn(cb >= 0x00200000 && cb <= 0x03ffffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
4223 break;
4224 case 4:
4225 cb = (abHdr[4] & 0x3f)
4226 | ((uint32_t)(abHdr[3] & 0x3f) << 6)
4227 | ((uint32_t)(abHdr[2] & 0x3f) << 12)
4228 | ((uint32_t)(abHdr[1] & 0x07) << 18);
4229 AssertLogRelMsgReturn(cb >= 0x00010000 && cb <= 0x001fffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
4230 break;
4231 case 3:
4232 cb = (abHdr[3] & 0x3f)
4233 | ((uint32_t)(abHdr[2] & 0x3f) << 6)
4234 | ((uint32_t)(abHdr[1] & 0x0f) << 12);
4235 AssertLogRelMsgReturn(cb >= 0x00000800 && cb <= 0x0000ffff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
4236 break;
4237 case 2:
4238 cb = (abHdr[2] & 0x3f)
4239 | ((uint32_t)(abHdr[1] & 0x1f) << 6);
4240 AssertLogRelMsgReturn(cb >= 0x00000080 && cb <= 0x000007ff, ("cb=%#x\n", cb), VERR_SSM_INTEGRITY);
4241 break;
4242 default:
4243 return VERR_INTERNAL_ERROR;
4244 }
4245
4246 pSSM->u.Read.cbRecLeft = cb;
4247 }
4248
4249 Log3(("ssmR3DataReadRecHdrV2: %08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
4250 pSSM->offUnit, pSSM->u.Read.cbRecLeft,
4251 pSSM->u.Read.u8TypeAndFlags & SSM_REC_TYPE_MASK,
4252 !!(pSSM->u.Read.u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT),
4253 cbHdr
4254 )); NOREF(cbHdr);
4255 return VINF_SUCCESS;
4256}
4257
4258
4259/**
4260 * Buffer miss, do an unbuffered read.
4261 *
4262 * @param pSSM SSM operation handle.
4263 * @param pvBuf Where to store the read data.
4264 * @param cbBuf Number of bytes to read.
4265 */
4266static int ssmR3DataReadUnbufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
4267{
4268 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
4269 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
4270
4271 /*
4272 * Copy out what we've got in the buffer.
4273 */
4274 uint32_t off = pSSM->u.Read.offDataBuffer;
4275 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
4276 Log4(("ssmR3DataReadUnbufferedV2: %08llx/%08x/%08x: cbBuf=%#x\n", pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
4277 if (cbInBuffer > 0)
4278 {
4279 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
4280 Assert(cbBuf > cbToCopy);
4281 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
4282 pvBuf = (uint8_t *)pvBuf + cbToCopy;
4283 cbBuf -= cbToCopy;
4284 pSSM->u.Read.cbDataBuffer = 0;
4285 pSSM->u.Read.offDataBuffer = 0;
4286 }
4287
4288 /*
4289 * Read data.
4290 */
4291 do
4292 {
4293 /*
4294 * Read the next record header if no more data.
4295 */
4296 if (!pSSM->u.Read.cbRecLeft)
4297 {
4298 int rc = ssmR3DataReadRecHdrV2(pSSM);
4299 if (RT_FAILURE(rc))
4300 return pSSM->rc = rc;
4301 }
4302 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
4303
4304 /*
4305 * Read data from the current record.
4306 */
4307 size_t cbToRead = RT_MIN(cbBuf, pSSM->u.Read.cbRecLeft);
4308 int rc = ssmR3DataReadV2Raw(pSSM, pvBuf, cbToRead);
4309 if (RT_FAILURE(rc))
4310 return pSSM->rc = rc;
4311 pSSM->u.Read.cbRecLeft -= cbToRead;
4312 cbBuf -= cbToRead;
4313 pvBuf = (uint8_t *)pvBuf + cbToRead;
4314 } while (cbBuf > 0);
4315
4316 Log4(("ssmR3DataReadUnBufferedV2: %08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
4317 pSSM->offUnit, pSSM->u.Read.cbRecLeft, 0, cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
4318 return VINF_SUCCESS;
4319}
4320
4321
4322/**
4323 * Buffer miss, do a buffered read.
4324 *
4325 * @param pSSM SSM operation handle.
4326 * @param pvBuf Where to store the read data.
4327 * @param cbBuf Number of bytes to read.
4328 */
4329static int ssmR3DataReadBufferedV2(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
4330{
4331 void const *pvBufOrg = pvBuf; NOREF(pvBufOrg);
4332 size_t const cbBufOrg = cbBuf; NOREF(cbBufOrg);
4333
4334 /*
4335 * Copy out what we've got in the buffer.
4336 */
4337 uint32_t off = pSSM->u.Read.offDataBuffer;
4338 int32_t cbInBuffer = pSSM->u.Read.cbDataBuffer - off;
4339 Log4(("ssmR3DataReadBufferedV2: %08llx/%08x/%08x: cbBuf=%#x\n", pSSM->offUnit, pSSM->u.Read.cbRecLeft, cbInBuffer, cbBufOrg));
4340 if (cbInBuffer > 0)
4341 {
4342 uint32_t const cbToCopy = (uint32_t)cbInBuffer;
4343 Assert(cbBuf > cbToCopy);
4344 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbToCopy);
4345 pvBuf = (uint8_t *)pvBuf + cbToCopy;
4346 cbBuf -= cbToCopy;
4347 pSSM->u.Read.cbDataBuffer = 0;
4348 pSSM->u.Read.offDataBuffer = 0;
4349 }
4350
4351 /*
4352 * Buffer more data.
4353 */
4354 do
4355 {
4356 /*
4357 * Read the next record header if no more data.
4358 */
4359 if (!pSSM->u.Read.cbRecLeft)
4360 {
4361 int rc = ssmR3DataReadRecHdrV2(pSSM);
4362 if (RT_FAILURE(rc))
4363 return pSSM->rc = rc;
4364 }
4365 AssertLogRelMsgReturn(!pSSM->u.Read.fEndOfData, ("cbBuf=%zu", cbBuf), pSSM->rc = VERR_SSM_LOADED_TOO_MUCH);
4366
4367 /*
4368 * Read data from the current record.
4369 * LATER: optimize by reading directly into the output buffer for some cases.
4370 */
4371 size_t cbToRead = RT_MIN(sizeof(pSSM->u.Read.abDataBuffer), pSSM->u.Read.cbRecLeft);
4372 int rc = ssmR3DataReadV2Raw(pSSM, &pSSM->u.Read.abDataBuffer[0], cbToRead);
4373 if (RT_FAILURE(rc))
4374 return pSSM->rc = rc;
4375 pSSM->u.Read.cbRecLeft -= cbToRead;
4376 pSSM->u.Read.cbDataBuffer = cbToRead;
4377 /*pSSM->u.Read.offDataBuffer = 0;*/
4378
4379 /*
4380 * Copy data from the buffer.
4381 */
4382 size_t cbToCopy = RT_MIN(cbBuf, cbToRead);
4383 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[0], cbToCopy);
4384 cbBuf -= cbToCopy;
4385 pvBuf = (uint8_t *)pvBuf + cbToCopy;
4386 pSSM->u.Read.offDataBuffer = cbToCopy;
4387 } while (cbBuf > 0);
4388
4389 Log4(("ssmR3DataReadBufferedV2: %08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n",
4390 pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
4391 cbBufOrg, RT_MIN(SSM_LOG_BYTES, cbBufOrg), pvBufOrg, cbBufOrg > SSM_LOG_BYTES ? "..." : ""));
4392 return VINF_SUCCESS;
4393}
4394
4395
4396/**
4397 * Inlined worker that handles format checks and buffered reads.
4398 *
4399 * @param pSSM SSM operation handle.
4400 * @param pvBuf Where to store the read data.
4401 * @param cbBuf Number of bytes to read.
4402 */
4403DECLINLINE(int) ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
4404{
4405 /*
4406 * Fend off previous errors and V1 data units.
4407 */
4408 if (RT_FAILURE(pSSM->rc))
4409 return pSSM->rc;
4410 if (RT_UNLIKELY(pSSM->u.Read.uFmtVerMajor == 1))
4411 return ssmR3DataReadV1(pSSM, pvBuf, cbBuf);
4412
4413 /*
4414 * Check if the requested data is buffered.
4415 */
4416 uint32_t off = pSSM->u.Read.offDataBuffer;
4417 if ( off + cbBuf > pSSM->u.Read.cbDataBuffer
4418 || cbBuf > sizeof(pSSM->u.Read.abDataBuffer))
4419 {
4420 if (cbBuf <= sizeof(pSSM->u.Read.abDataBuffer) / 8)
4421 return ssmR3DataReadBufferedV2(pSSM, pvBuf, cbBuf);
4422 return ssmR3DataReadUnbufferedV2(pSSM, pvBuf, cbBuf);
4423 }
4424
4425 memcpy(pvBuf, &pSSM->u.Read.abDataBuffer[off], cbBuf);
4426 pSSM->u.Read.offDataBuffer = off + cbBuf;
4427 Log4((cbBuf
4428 ? "ssmR3DataRead: %08llx/%08x/%08x: cbBuf=%#x %.*Rhxs%s\n"
4429 : "ssmR3DataRead: %08llx/%08x/%08x: cbBuf=%#x\n",
4430 pSSM->offUnit, pSSM->u.Read.cbRecLeft, pSSM->u.Read.cbDataBuffer - pSSM->u.Read.offDataBuffer,
4431 cbBuf, RT_MIN(SSM_LOG_BYTES, cbBuf), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
4432
4433 return VINF_SUCCESS;
4434}
4435
4436
4437/**
4438 * Gets a structure.
4439 *
4440 * @returns VBox status code.
4441 * @param pSSM The saved state handle.
4442 * @param pvStruct The structure address.
4443 * @param paFields The array of structure fields descriptions.
4444 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
4445 */
4446VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
4447{
4448 /* begin marker. */
4449 uint32_t u32Magic;
4450 int rc = SSMR3GetU32(pSSM, &u32Magic);
4451 if (RT_FAILURE(rc))
4452 return rc;
4453 if (u32Magic != SSMR3STRUCT_BEGIN)
4454 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
4455
4456 /* put the fields */
4457 for (PCSSMFIELD pCur = paFields;
4458 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
4459 pCur++)
4460 {
4461 rc = ssmR3DataRead(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
4462 if (RT_FAILURE(rc))
4463 return rc;
4464 }
4465
4466 /* end marker */
4467 rc = SSMR3GetU32(pSSM, &u32Magic);
4468 if (RT_FAILURE(rc))
4469 return rc;
4470 if (u32Magic != SSMR3STRUCT_END)
4471 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
4472 return rc;
4473}
4474
4475
4476/**
4477 * Loads a boolean item from the current data unit.
4478 *
4479 * @returns VBox status.
4480 * @param pSSM SSM operation handle.
4481 * @param pfBool Where to store the item.
4482 */
4483VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
4484{
4485 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4486 {
4487 uint8_t u8; /* see SSMR3PutBool */
4488 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
4489 if (RT_SUCCESS(rc))
4490 {
4491 Assert(u8 <= 1);
4492 *pfBool = !!u8;
4493 }
4494 return rc;
4495 }
4496 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4497 return VERR_SSM_INVALID_STATE;
4498}
4499
4500
4501/**
4502 * Loads a 8-bit unsigned integer item from the current data unit.
4503 *
4504 * @returns VBox status.
4505 * @param pSSM SSM operation handle.
4506 * @param pu8 Where to store the item.
4507 */
4508VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
4509{
4510 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4511 return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
4512 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4513 return VERR_SSM_INVALID_STATE;
4514}
4515
4516
4517/**
4518 * Loads a 8-bit signed integer item from the current data unit.
4519 *
4520 * @returns VBox status.
4521 * @param pSSM SSM operation handle.
4522 * @param pi8 Where to store the item.
4523 */
4524VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
4525{
4526 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4527 return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
4528 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4529 return VERR_SSM_INVALID_STATE;
4530}
4531
4532
4533/**
4534 * Loads a 16-bit unsigned integer item from the current data unit.
4535 *
4536 * @returns VBox status.
4537 * @param pSSM SSM operation handle.
4538 * @param pu16 Where to store the item.
4539 */
4540VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
4541{
4542 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4543 return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
4544 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4545 return VERR_SSM_INVALID_STATE;
4546}
4547
4548
4549/**
4550 * Loads a 16-bit signed integer item from the current data unit.
4551 *
4552 * @returns VBox status.
4553 * @param pSSM SSM operation handle.
4554 * @param pi16 Where to store the item.
4555 */
4556VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
4557{
4558 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4559 return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
4560 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4561 return VERR_SSM_INVALID_STATE;
4562}
4563
4564
4565/**
4566 * Loads a 32-bit unsigned integer item from the current data unit.
4567 *
4568 * @returns VBox status.
4569 * @param pSSM SSM operation handle.
4570 * @param pu32 Where to store the item.
4571 */
4572VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
4573{
4574 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4575 return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
4576 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4577 return VERR_SSM_INVALID_STATE;
4578}
4579
4580
4581/**
4582 * Loads a 32-bit signed integer item from the current data unit.
4583 *
4584 * @returns VBox status.
4585 * @param pSSM SSM operation handle.
4586 * @param pi32 Where to store the item.
4587 */
4588VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
4589{
4590 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4591 return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
4592 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4593 return VERR_SSM_INVALID_STATE;
4594}
4595
4596
4597/**
4598 * Loads a 64-bit unsigned integer item from the current data unit.
4599 *
4600 * @returns VBox status.
4601 * @param pSSM SSM operation handle.
4602 * @param pu64 Where to store the item.
4603 */
4604VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
4605{
4606 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4607 return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
4608 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4609 return VERR_SSM_INVALID_STATE;
4610}
4611
4612
4613/**
4614 * Loads a 64-bit signed integer item from the current data unit.
4615 *
4616 * @returns VBox status.
4617 * @param pSSM SSM operation handle.
4618 * @param pi64 Where to store the item.
4619 */
4620VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
4621{
4622 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4623 return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
4624 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4625 return VERR_SSM_INVALID_STATE;
4626}
4627
4628
4629/**
4630 * Loads a 128-bit unsigned integer item from the current data unit.
4631 *
4632 * @returns VBox status.
4633 * @param pSSM SSM operation handle.
4634 * @param pu128 Where to store the item.
4635 */
4636VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
4637{
4638 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4639 return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
4640 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4641 return VERR_SSM_INVALID_STATE;
4642}
4643
4644
4645/**
4646 * Loads a 128-bit signed integer item from the current data unit.
4647 *
4648 * @returns VBox status.
4649 * @param pSSM SSM operation handle.
4650 * @param pi128 Where to store the item.
4651 */
4652VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
4653{
4654 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4655 return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
4656 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4657 return VERR_SSM_INVALID_STATE;
4658}
4659
4660
4661/**
4662 * Loads a VBox unsigned integer item from the current data unit.
4663 *
4664 * @returns VBox status.
4665 * @param pSSM SSM operation handle.
4666 * @param pu Where to store the integer.
4667 */
4668VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
4669{
4670 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4671 return ssmR3DataRead(pSSM, pu, sizeof(*pu));
4672 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4673 return VERR_SSM_INVALID_STATE;
4674}
4675
4676
4677/**
4678 * Loads a VBox signed integer item from the current data unit.
4679 *
4680 * @returns VBox status.
4681 * @param pSSM SSM operation handle.
4682 * @param pi Where to store the integer.
4683 */
4684VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
4685{
4686 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4687 return ssmR3DataRead(pSSM, pi, sizeof(*pi));
4688 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4689 return VERR_SSM_INVALID_STATE;
4690}
4691
4692
4693/**
4694 * Loads a GC natural unsigned integer item from the current data unit.
4695 *
4696 * @returns VBox status.
4697 * @param pSSM SSM operation handle.
4698 * @param pu Where to store the integer.
4699 *
4700 * @deprecated Silly type with an incorrect size, don't use it.
4701 */
4702VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
4703{
4704 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
4705 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
4706}
4707
4708
4709/**
4710 * Loads a GC unsigned integer register item from the current data unit.
4711 *
4712 * @returns VBox status.
4713 * @param pSSM SSM operation handle.
4714 * @param pu Where to store the integer.
4715 */
4716VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu)
4717{
4718 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
4719 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
4720}
4721
4722
4723/**
4724 * Loads a 32 bits GC physical address item from the current data unit.
4725 *
4726 * @returns VBox status.
4727 * @param pSSM SSM operation handle.
4728 * @param pGCPhys Where to store the GC physical address.
4729 */
4730VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
4731{
4732 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4733 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
4734 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4735 return VERR_SSM_INVALID_STATE;
4736}
4737
4738
4739/**
4740 * Loads a 64 bits GC physical address item from the current data unit.
4741 *
4742 * @returns VBox status.
4743 * @param pSSM SSM operation handle.
4744 * @param pGCPhys Where to store the GC physical address.
4745 */
4746VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
4747{
4748 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4749 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
4750 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4751 return VERR_SSM_INVALID_STATE;
4752}
4753
4754
4755/**
4756 * Loads a GC physical address item from the current data unit.
4757 *
4758 * @returns VBox status.
4759 * @param pSSM SSM operation handle.
4760 * @param pGCPhys Where to store the GC physical address.
4761 */
4762VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
4763{
4764 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4765 {
4766 if (RT_LIKELY(sizeof(*pGCPhys) == pSSM->u.Read.cbGCPhys))
4767 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
4768
4769 /*
4770 * Fiddly.
4771 */
4772 Assert(sizeof(*pGCPhys) == sizeof(uint64_t) || sizeof(*pGCPhys) == sizeof(uint32_t));
4773 Assert(pSSM->u.Read.cbGCPhys == sizeof(uint64_t) || pSSM->u.Read.cbGCPhys == sizeof(uint32_t));
4774 if (pSSM->u.Read.cbGCPhys == sizeof(uint64_t))
4775 {
4776 /* 64-bit saved, 32-bit load: try truncate it. */
4777 uint64_t u64;
4778 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
4779 if (RT_FAILURE(rc))
4780 return rc;
4781 if (u64 >= _4G)
4782 return VERR_SSM_GCPHYS_OVERFLOW;
4783 *pGCPhys = (RTGCPHYS)u64;
4784 return rc;
4785 }
4786
4787 /* 32-bit saved, 64-bit load: clear the high part. */
4788 *pGCPhys = 0;
4789 return ssmR3DataRead(pSSM, pGCPhys, sizeof(uint32_t));
4790 }
4791 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4792 return VERR_SSM_INVALID_STATE;
4793}
4794
4795
4796/**
4797 * Loads a GC virtual address item from the current data unit.
4798 *
4799 * Only applies to in the 1.1 format:
4800 * - SSMR3GetGCPtr
4801 * - SSMR3GetGCUIntPtr
4802 * - SSMR3GetGCUInt
4803 * - SSMR3GetGCUIntReg
4804 *
4805 * Put functions are not affected.
4806 *
4807 * @returns VBox status.
4808 * @param pSSM SSM operation handle.
4809 * @param cbGCPtr Size of RTGCPTR
4810 *
4811 * @remarks This interface only works with saved state version 1.1, if the
4812 * format isn't 1.1 the call will be ignored.
4813 */
4814VMMR3DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
4815{
4816 Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
4817 if (!pSSM->u.Read.fFixedGCPtrSize)
4818 {
4819 Log(("SSMR3SetGCPtrSize: %u -> %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
4820 pSSM->u.Read.cbGCPtr = cbGCPtr;
4821 pSSM->u.Read.fFixedGCPtrSize = true;
4822 }
4823 else if ( pSSM->u.Read.cbGCPtr != cbGCPtr
4824 && pSSM->u.Read.cbFileHdr == sizeof(SSMFILEHDRV11))
4825 AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %u bytes; requested %u bytes\n", pSSM->u.Read.cbGCPtr, cbGCPtr));
4826
4827 return VINF_SUCCESS;
4828}
4829
4830
4831/**
4832 * Loads a GC virtual address item from the current data unit.
4833 *
4834 * @returns VBox status.
4835 * @param pSSM SSM operation handle.
4836 * @param pGCPtr Where to store the GC virtual address.
4837 */
4838VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
4839{
4840 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4841 {
4842 if (RT_LIKELY(sizeof(*pGCPtr) == pSSM->u.Read.cbGCPtr))
4843 return ssmR3DataRead(pSSM, pGCPtr, sizeof(*pGCPtr));
4844
4845 /*
4846 * Fiddly.
4847 */
4848 Assert(sizeof(*pGCPtr) == sizeof(uint64_t) || sizeof(*pGCPtr) == sizeof(uint32_t));
4849 Assert(pSSM->u.Read.cbGCPtr == sizeof(uint64_t) || pSSM->u.Read.cbGCPtr == sizeof(uint32_t));
4850 if (pSSM->u.Read.cbGCPtr == sizeof(uint64_t))
4851 {
4852 /* 64-bit saved, 32-bit load: try truncate it. */
4853 uint64_t u64;
4854 int rc = ssmR3DataRead(pSSM, &u64, sizeof(uint64_t));
4855 if (RT_FAILURE(rc))
4856 return rc;
4857 if (u64 >= _4G)
4858 return VERR_SSM_GCPTR_OVERFLOW;
4859 *pGCPtr = (RTGCPTR)u64;
4860 return rc;
4861 }
4862
4863 /* 32-bit saved, 64-bit load: clear the high part. */
4864 *pGCPtr = 0;
4865 return ssmR3DataRead(pSSM, pGCPtr, sizeof(uint32_t));
4866 }
4867 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4868 return VERR_SSM_INVALID_STATE;
4869}
4870
4871
4872/**
4873 * Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
4874 *
4875 * @returns VBox status.
4876 * @param pSSM SSM operation handle.
4877 * @param pGCPtr Where to store the GC virtual address.
4878 */
4879VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
4880{
4881 AssertCompile(sizeof(RTGCPTR) == sizeof(*pGCPtr));
4882 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pGCPtr);
4883}
4884
4885
4886/**
4887 * Loads an RC virtual address item from the current data unit.
4888 *
4889 * @returns VBox status.
4890 * @param pSSM SSM operation handle.
4891 * @param pRCPtr Where to store the RC virtual address.
4892 */
4893VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
4894{
4895 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4896 return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
4897
4898 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4899 return VERR_SSM_INVALID_STATE;
4900}
4901
4902
4903/**
4904 * Loads a I/O port address item from the current data unit.
4905 *
4906 * @returns VBox status.
4907 * @param pSSM SSM operation handle.
4908 * @param pIOPort Where to store the I/O port address.
4909 */
4910VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
4911{
4912 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4913 return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
4914 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4915 return VERR_SSM_INVALID_STATE;
4916}
4917
4918
4919/**
4920 * Loads a selector item from the current data unit.
4921 *
4922 * @returns VBox status.
4923 * @param pSSM SSM operation handle.
4924 * @param pSel Where to store the selector.
4925 */
4926VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
4927{
4928 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4929 return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
4930 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4931 return VERR_SSM_INVALID_STATE;
4932}
4933
4934
4935/**
4936 * Loads a memory item from the current data unit.
4937 *
4938 * @returns VBox status.
4939 * @param pSSM SSM operation handle.
4940 * @param pv Where to store the item.
4941 * @param cb Size of the item.
4942 */
4943VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
4944{
4945 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4946 return ssmR3DataRead(pSSM, pv, cb);
4947 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4948 return VERR_SSM_INVALID_STATE;
4949}
4950
4951
4952/**
4953 * Loads a string item from the current data unit.
4954 *
4955 * @returns VBox status.
4956 * @param pSSM SSM operation handle.
4957 * @param psz Where to store the item.
4958 * @param cbMax Max size of the item (including '\\0').
4959 */
4960VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
4961{
4962 return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
4963}
4964
4965
4966/**
4967 * Loads a string item from the current data unit.
4968 *
4969 * @returns VBox status.
4970 * @param pSSM SSM operation handle.
4971 * @param psz Where to store the item.
4972 * @param cbMax Max size of the item (including '\\0').
4973 * @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
4974 */
4975VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
4976{
4977 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
4978 {
4979 /* read size prefix. */
4980 uint32_t u32;
4981 int rc = SSMR3GetU32(pSSM, &u32);
4982 if (RT_SUCCESS(rc))
4983 {
4984 if (pcbStr)
4985 *pcbStr = u32;
4986 if (u32 < cbMax)
4987 {
4988 /* terminate and read string content. */
4989 psz[u32] = '\0';
4990 return ssmR3DataRead(pSSM, psz, u32);
4991 }
4992 return VERR_TOO_MUCH_DATA;
4993 }
4994 return rc;
4995 }
4996 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
4997 return VERR_SSM_INVALID_STATE;
4998}
4999
5000
5001/**
5002 * Skips a number of bytes in the current data unit.
5003 *
5004 * @returns VBox status code.
5005 * @param pSSM The SSM handle.
5006 * @param cb The number of bytes to skip.
5007 */
5008VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
5009{
5010 AssertMsgReturn( pSSM->enmOp == SSMSTATE_LOAD_EXEC
5011 || pSSM->enmOp == SSMSTATE_OPEN_READ,
5012 ("Invalid state %d\n", pSSM->enmOp),
5013 VERR_SSM_INVALID_STATE);
5014 while (cb > 0)
5015 {
5016 uint8_t abBuf[8192];
5017 size_t cbCur = RT_MIN(sizeof(abBuf), cb);
5018 cb -= cbCur;
5019 int rc = ssmR3DataRead(pSSM, abBuf, cbCur);
5020 if (RT_FAILURE(rc))
5021 return rc;
5022 }
5023
5024 return VINF_SUCCESS;
5025}
5026
5027
5028/**
5029 * Query what the VBox status code of the operation is.
5030 *
5031 * This can be used for putting and getting a batch of values
5032 * without bother checking the result till all the calls have
5033 * been made.
5034 *
5035 * @returns SSMAFTER enum value.
5036 * @param pSSM SSM operation handle.
5037 */
5038VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
5039{
5040 return pSSM->rc;
5041}
5042
5043
5044/**
5045 * Fail the load operation.
5046 *
5047 * This is mainly intended for sub item loaders (like timers) which
5048 * return code isn't necessarily heeded by the caller but is important
5049 * to SSM.
5050 *
5051 * @returns SSMAFTER enum value.
5052 * @param pSSM SSM operation handle.
5053 * @param iStatus Failure status code. This MUST be a VERR_*.
5054 */
5055VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
5056{
5057 if (RT_FAILURE(iStatus))
5058 {
5059 if (RT_SUCCESS(pSSM->rc))
5060 pSSM->rc = iStatus;
5061 return pSSM->rc = iStatus;
5062 }
5063 AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
5064 return VERR_INVALID_PARAMETER;
5065}
5066
5067
5068/**
5069 * Get what to do after this operation.
5070 *
5071 * @returns SSMAFTER enum value.
5072 * @param pSSM SSM operation handle.
5073 */
5074VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
5075{
5076 return pSSM->enmAfter;
5077}
5078
5079
5080/**
5081 * Get the current unit byte offset (uncompressed).
5082 *
5083 * @returns The offset. UINT64_MAX if called at a wrong time.
5084 * @param pSSM SSM operation handle.
5085 */
5086VMMR3DECL(uint64_t) SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM)
5087{
5088 return pSSM->offUnit;
5089}
5090
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