VirtualBox

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

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

SSMR3ValidateFile/ConsoleImpl.cpp: Don't waste lots of time checksumming the file before creating the VM and calling VMMR3Load.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 123.2 KB
Line 
1/* $Id: SSM.cpp 21787 2009-07-24 12:51:44Z 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 CRC32 and unit size.
100 * - type 2: Terminator without any integrity checks.
101 * - type 3: Raw data record.
102 * - type 4: Named data - length prefixed name followed by the data.
103 * - types 5 thru 15 are current undefined.
104 * - bit 4: Important (set), can be skipped (clear).
105 * - bit 5: Undefined flag, must be zero.
106 * - bit 6: Undefined flag, must be zero.
107 * - bit 7: "magic" bit, always set.
108 *
109 * Record header byte 2 (optionally thru 7) is the size of the following data
110 * encoded in UTF-8 style.
111 *
112 * The data part of the unit is compressed using LZF (via RTZip).
113 *
114 * (In version 1.2 and earlier the unit header also contained the compressed
115 * size of the data, i.e. it was updated after the data was written, and the
116 * data was not record based.)
117 *
118 *
119 * @section sec_ssm_future Future Changes
120 *
121 * There are plans to extend SSM to make it easier to be both backwards and
122 * (somewhat) forwards compatible. One of the new features will be being able
123 * to classify units and data items as unimportant. Another suggested feature
124 * is naming data items, perhaps by extending the SSMR3PutStruct API.
125 *
126 */
127
128
129/*******************************************************************************
130* Header Files *
131*******************************************************************************/
132#define LOG_GROUP LOG_GROUP_SSM
133#include <VBox/ssm.h>
134#include <VBox/dbgf.h>
135#include <VBox/mm.h>
136#include "SSMInternal.h"
137#include <VBox/vm.h>
138#include <VBox/err.h>
139#include <VBox/log.h>
140#include <VBox/version.h>
141
142#include <iprt/assert.h>
143#include <iprt/file.h>
144#include <iprt/alloc.h>
145#include <iprt/uuid.h>
146#include <iprt/zip.h>
147#include <iprt/crc32.h>
148#include <iprt/thread.h>
149#include <iprt/string.h>
150
151
152/*******************************************************************************
153* Defined Constants And Macros *
154*******************************************************************************/
155/** Saved state file magic base string. */
156#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
157/** Saved state file v1.0 magic. */
158#define SSMFILEHDR_MAGIC_V1_0 "\177VirtualBox SavedState V1.0\n"
159/** Saved state file v1.1 magic. */
160#define SSMFILEHDR_MAGIC_V1_1 "\177VirtualBox SavedState V1.1\n"
161/** Saved state file v1.2 magic. */
162#define SSMFILEHDR_MAGIC_V1_2 "\177VirtualBox SavedState V1.2\n\0\0\0"
163
164/** Data unit magic. */
165#define SSMFILEUNITHDR_MAGIC "\nUnit\n"
166/** Data end marker magic. */
167#define SSMFILEUNITHDR_END "\nTheEnd"
168
169/** Start structure magic. (Isacc Asimov) */
170#define SSMR3STRUCT_BEGIN 0x19200102
171/** End structure magic. (Isacc Asimov) */
172#define SSMR3STRUCT_END 0x19920406
173
174
175/*******************************************************************************
176* Structures and Typedefs *
177*******************************************************************************/
178/** SSM state. */
179typedef enum SSMSTATE
180{
181 SSMSTATE_INVALID = 0,
182 SSMSTATE_SAVE_PREP,
183 SSMSTATE_SAVE_EXEC,
184 SSMSTATE_SAVE_DONE,
185 SSMSTATE_LOAD_PREP,
186 SSMSTATE_LOAD_EXEC,
187 SSMSTATE_LOAD_DONE,
188 SSMSTATE_OPEN_READ
189} SSMSTATE;
190
191
192/**
193 * Handle structure.
194 */
195typedef struct SSMHANDLE
196{
197 /** The file handle. */
198 RTFILE File;
199 /** The VM handle. */
200 PVM pVM;
201 /** The size of the file header.
202 * Because the file header was incorrectly aligned there we've ended up with
203 * differences between the 64-bit and 32-bit file header. */
204 size_t cbFileHdr;
205 /** The current operation. */
206 SSMSTATE enmOp;
207 /** What to do after save completes. (move the enum) */
208 SSMAFTER enmAfter;
209 /** The current rc of the save operation. */
210 int rc;
211 /** The compressor of the current data unit. */
212 PRTZIPCOMP pZipComp;
213 /** The decompressor of the current data unit. */
214 PRTZIPDECOMP pZipDecomp;
215 /** Number of compressed bytes left in the current data unit. */
216 uint64_t cbUnitLeft;
217 /** The current uncompressed offset into the data unit. */
218 uint64_t offUnit;
219
220 /** Pointer to the progress callback function. */
221 PFNVMPROGRESS pfnProgress;
222 /** User specified arguemnt to the callback function. */
223 void *pvUser;
224 /** Next completion percentage. (corresponds to offEstProgress) */
225 unsigned uPercent;
226 /** The position of the next progress callback in the estimated file. */
227 uint64_t offEstProgress;
228 /** The estimated total byte count.
229 * (Only valid after the prep.) */
230 uint64_t cbEstTotal;
231 /** Current position in the estimated file. */
232 uint64_t offEst;
233 /** End of current unit in the estimated file. */
234 uint64_t offEstUnitEnd;
235 /** the amount of % we reserve for the 'prepare' phase */
236 unsigned uPercentPrepare;
237 /** the amount of % we reserve for the 'done' stage */
238 unsigned uPercentDone;
239
240 /** RTGCPHYS size in bytes. (Only applicable when loading/reading.) */
241 unsigned cbGCPhys;
242 /** RTGCPTR size in bytes. (Only applicable when loading/reading.) */
243 unsigned cbGCPtr;
244 /** Whether cbGCPtr is fixed or settable. */
245 bool fFixedGCPtrSize;
246} SSMHANDLE;
247
248
249/**
250 * Header of the saved state file.
251 *
252 * @remarks This is a superset of SSMFILEHDRV11.
253 */
254typedef struct SSMFILEHDR
255{
256 /** Magic string which identifies this file as a version of VBox saved state
257 * file format (SSMFILEHDR_MAGIC_V1_2). */
258 char achMagic[32];
259 /** The size of this file. Used to check
260 * whether the save completed and that things are fine otherwise. */
261 uint64_t cbFile;
262 /** File checksum. The actual calculation skips past the u32CRC field. */
263 uint32_t u32CRC;
264 /** Padding. */
265 uint32_t u32Reserved;
266 /** The machine UUID. (Ignored if NIL.) */
267 RTUUID MachineUuid;
268
269 /** The major version number. */
270 uint16_t u16VerMajor;
271 /** The minor version number. */
272 uint16_t u16VerMinor;
273 /** The build number. */
274 uint32_t u32VerBuild;
275 /** The SVN revision. */
276 uint32_t u32SvnRev;
277
278 /** 32 or 64 depending on the host. */
279 uint8_t cHostBits;
280 /** The size of RTGCPHYS. */
281 uint8_t cbGCPhys;
282 /** The size of RTGCPTR. */
283 uint8_t cbGCPtr;
284 /** Padding. */
285 uint8_t au8Reserved;
286} SSMFILEHDR;
287AssertCompileSize(SSMFILEHDR, 64+16);
288AssertCompileMemberSize(SSMFILEHDR, achMagic, sizeof(SSMFILEHDR_MAGIC_V1_2));
289/** Pointer to a saved state file header. */
290typedef SSMFILEHDR *PSSMFILEHDR;
291
292
293/**
294 * Header of the saved state file, version 1.1.
295 */
296typedef struct SSMFILEHDRV11
297{
298 /** Magic string which identifies this file as a version of VBox saved state
299 * file format (SSMFILEHDR_MAGIC_V1_1). */
300 char achMagic[32];
301 /** The size of this file. Used to check
302 * whether the save completed and that things are fine otherwise. */
303 uint64_t cbFile;
304 /** File checksum. The actual calculation skips past the u32CRC field. */
305 uint32_t u32CRC;
306 /** Padding. */
307 uint32_t u32Reserved;
308 /** The machine UUID. (Ignored if NIL.) */
309 RTUUID MachineUuid;
310} SSMFILEHDRV11;
311AssertCompileSize(SSMFILEHDRV11, 64);
312/** Pointer to a saved state file header. */
313typedef SSMFILEHDRV11 *PSSMFILEHDRV11;
314
315
316/**
317 * The x86 edition of the 1.0 header.
318 */
319#pragma pack(1) /* darn, MachineUuid got missaligned! */
320typedef struct SSMFILEHDRV10X86
321{
322 /** Magic string which identifies this file as a version of VBox saved state
323 * file format (SSMFILEHDR_MAGIC_V1_0). */
324 char achMagic[32];
325 /** The size of this file. Used to check
326 * whether the save completed and that things are fine otherwise. */
327 uint64_t cbFile;
328 /** File checksum. The actual calculation skips past the u32CRC field. */
329 uint32_t u32CRC;
330 /** The machine UUID. (Ignored if NIL.) */
331 RTUUID MachineUuid;
332} SSMFILEHDRV10X86;
333#pragma pack()
334/** Pointer to a SSMFILEHDRV10X86. */
335typedef SSMFILEHDRV10X86 *PSSMFILEHDRV10X86;
336
337/**
338 * The amd64 edition of the 1.0 header.
339 */
340typedef SSMFILEHDR SSMFILEHDRV10AMD64;
341/** Pointer to SSMFILEHDRV10AMD64. */
342typedef SSMFILEHDRV10AMD64 *PSSMFILEHDRV10AMD64;
343
344
345/**
346 * Data unit header.
347 */
348typedef struct SSMFILEUNITHDR
349{
350 /** Magic (SSMFILEUNITHDR_MAGIC or SSMFILEUNITHDR_END). */
351 char achMagic[8];
352 /** Number of bytes in this data unit including the header. */
353 uint64_t cbUnit;
354 /** @todo Add uncompressed byte count as well. */
355 /** Data version. */
356 uint32_t u32Version;
357 /** Instance number. */
358 uint32_t u32Instance;
359 /** Size of the data unit name including the terminator. (bytes) */
360 uint32_t cchName;
361 /** Data unit name. */
362 char szName[1];
363} SSMFILEUNITHDR;
364/** Pointer to SSMFILEUNITHDR. */
365typedef SSMFILEUNITHDR *PSSMFILEUNITHDR;
366
367
368/*******************************************************************************
369* Internal Functions *
370*******************************************************************************/
371static int ssmR3LazyInit(PVM pVM);
372static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM);
373static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
374static int ssmR3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
375static int ssmR3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC);
376static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance);
377static int ssmR3ValidateFile(RTFILE File, bool fChecksumIt, PSSMFILEHDR pHdr, size_t *pcbFileHdr);
378static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t u32Instance);
379static int ssmR3WriteFinish(PSSMHANDLE pSSM);
380static int ssmR3Write(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
381static DECLCALLBACK(int) ssmR3WriteOut(void *pvSSM, const void *pvBuf, size_t cbBuf);
382static void ssmR3ReadFinish(PSSMHANDLE pSSM);
383static int ssmR3Read(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf);
384static DECLCALLBACK(int) ssmR3ReadIn(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead);
385
386
387/**
388 * Performs lazy initialization of the SSM.
389 *
390 * @returns VBox status code.
391 * @param pVM The VM.
392 */
393static int ssmR3LazyInit(PVM pVM)
394{
395 /*
396 * Register a saved state unit which we use to put the VirtualBox version,
397 * revision and similar stuff in.
398 */
399 pVM->ssm.s.fInitialized = true;
400 int rc = SSMR3RegisterInternal(pVM, "SSM", 0 /*u32Instance*/, 1/*u32Version*/, 64 /*cbGuess*/,
401 NULL /*pfnSavePrep*/, ssmR3SelfSaveExec, NULL /*pfnSaveDone*/,
402 NULL /*pfnSavePrep*/, ssmR3SelfLoadExec, NULL /*pfnSaveDone*/);
403 pVM->ssm.s.fInitialized = RT_SUCCESS(rc);
404 return rc;
405}
406
407
408/**
409 * For saving usful things without having to go thru the tedious process of
410 * adding it to the header.
411 *
412 * @returns VBox status code.
413 * @param pVM Pointer to the shared VM structure.
414 * @param pSSM The SSM handle.
415 */
416static DECLCALLBACK(int) ssmR3SelfSaveExec(PVM pVM, PSSMHANDLE pSSM)
417{
418 /*
419 * String table containg pairs of variable and value string.
420 * Terminated by two empty strings.
421 */
422#ifdef VBOX_OSE
423 SSMR3PutStrZ(pSSM, "OSE");
424 SSMR3PutStrZ(pSSM, "true");
425#endif
426
427 /* terminator */
428 SSMR3PutStrZ(pSSM, "");
429 return SSMR3PutStrZ(pSSM, "");
430}
431
432
433/**
434 * For load the version + revision and stuff.
435 *
436 * @returns VBox status code.
437 * @param pVM Pointer to the shared VM structure.
438 * @param pSSM The SSM handle.
439 * @param u32Version The version (1).
440 */
441static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
442{
443 AssertLogRelMsgReturn(u32Version == 1, ("%d", u32Version), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
444
445 /*
446 * String table containg pairs of variable and value string.
447 * Terminated by two empty strings.
448 */
449 for (unsigned i = 0; ; i++)
450 {
451 char szVar[128];
452 char szValue[1024];
453 int rc = SSMR3GetStrZ(pSSM, szVar, sizeof(szVar));
454 AssertRCReturn(rc, rc);
455 rc = SSMR3GetStrZ(pSSM, szValue, sizeof(szValue));
456 AssertRCReturn(rc, rc);
457 if (!szVar[0] && !szValue[0])
458 break;
459 if (i == 0)
460 LogRel(("SSM: Saved state info:\n"));
461 LogRel(("SSM: %s: %s\n", szVar, szValue));
462 }
463 return VINF_SUCCESS;
464}
465
466
467/**
468 * Internal registration worker.
469 *
470 * @returns VBox status code.
471 * @param pVM The VM handle.
472 * @param pszName Data unit name.
473 * @param u32Instance The instance id.
474 * @param u32Version The data unit version.
475 * @param cbGuess The guessed data unit size.
476 * @param pszBefore Name of data unit to be placed in front of.
477 * Optional.
478 * @param ppUnit Where to store the insterted unit node.
479 * Caller must fill in the missing details.
480 */
481static int ssmR3Register(PVM pVM, const char *pszName, uint32_t u32Instance,
482 uint32_t u32Version, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit)
483{
484 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
485 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
486 AssertReturn(!pszBefore || *pszBefore, VERR_INVALID_PARAMETER);
487
488 /*
489 * Lazy init.
490 */
491 if (!pVM->ssm.s.fInitialized)
492 {
493 int rc = ssmR3LazyInit(pVM);
494 AssertRCReturn(rc, rc);
495 }
496
497 /*
498 * Walk to the end of the list checking for duplicates as we go.
499 */
500 size_t cchBefore = pszBefore ? strlen(pszBefore) : 0;
501 PSSMUNIT pUnitBeforePrev = NULL;
502 PSSMUNIT pUnitBefore = NULL;
503 size_t cchName = strlen(pszName);
504 PSSMUNIT pUnitPrev = NULL;
505 PSSMUNIT pUnit = pVM->ssm.s.pHead;
506 while (pUnit)
507 {
508 if ( pUnit->u32Instance == u32Instance
509 && pUnit->cchName == cchName
510 && !memcmp(pUnit->szName, pszName, cchName))
511 {
512 AssertMsgFailed(("Duplicate registration %s\n", pszName));
513 return VERR_SSM_UNIT_EXISTS;
514 }
515 if ( pUnit->cchName == cchBefore
516 && !pUnitBefore
517 && !memcmp(pUnit->szName, pszBefore, cchBefore))
518 {
519 pUnitBeforePrev = pUnitPrev;
520 pUnitBefore = pUnit;
521 }
522
523 /* next */
524 pUnitPrev = pUnit;
525 pUnit = pUnit->pNext;
526 }
527
528 /*
529 * Allocate new node.
530 */
531 pUnit = (PSSMUNIT)MMR3HeapAllocZ(pVM, MM_TAG_SSM, RT_OFFSETOF(SSMUNIT, szName[cchName + 1]));
532 if (!pUnit)
533 return VERR_NO_MEMORY;
534
535 /*
536 * Fill in (some) data. (Stuff is zero'ed.)
537 */
538 pUnit->u32Version = u32Version;
539 pUnit->u32Instance = u32Instance;
540 pUnit->cbGuess = cbGuess;
541 pUnit->cchName = cchName;
542 memcpy(pUnit->szName, pszName, cchName);
543
544 /*
545 * Insert
546 */
547 if (pUnitBefore)
548 {
549 pUnit->pNext = pUnitBefore;
550 if (pUnitBeforePrev)
551 pUnitBeforePrev->pNext = pUnit;
552 else
553 pVM->ssm.s.pHead = pUnit;
554 }
555 else if (pUnitPrev)
556 pUnitPrev->pNext = pUnit;
557 else
558 pVM->ssm.s.pHead = pUnit;
559
560 *ppUnit = pUnit;
561 return VINF_SUCCESS;
562}
563
564
565/**
566 * Register a PDM Devices data unit.
567 *
568 * @returns VBox status.
569 *
570 * @param pVM The VM handle.
571 * @param pDevIns Device instance.
572 * @param pszName Data unit name.
573 * @param u32Instance The instance identifier of the data unit.
574 * This must together with the name be unique.
575 * @param u32Version Data layout version number.
576 * @param cbGuess The approximate amount of data in the unit.
577 * Only for progress indicators.
578 * @param pszBefore Name of data unit which we should be put in front
579 * of. Optional (NULL).
580 * @param pfnSavePrep Prepare save callback, optional.
581 * @param pfnSaveExec Execute save callback, optional.
582 * @param pfnSaveDone Done save callback, optional.
583 * @param pfnLoadPrep Prepare load callback, optional.
584 * @param pfnLoadExec Execute load callback, optional.
585 * @param pfnLoadDone Done load callback, optional.
586 */
587VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, const char *pszBefore,
588 PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
589 PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
590{
591 PSSMUNIT pUnit;
592 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, pszBefore, &pUnit);
593 if (RT_SUCCESS(rc))
594 {
595 pUnit->enmType = SSMUNITTYPE_DEV;
596 pUnit->u.Dev.pfnSavePrep = pfnSavePrep;
597 pUnit->u.Dev.pfnSaveExec = pfnSaveExec;
598 pUnit->u.Dev.pfnSaveDone = pfnSaveDone;
599 pUnit->u.Dev.pfnLoadPrep = pfnLoadPrep;
600 pUnit->u.Dev.pfnLoadExec = pfnLoadExec;
601 pUnit->u.Dev.pfnLoadDone = pfnLoadDone;
602 pUnit->u.Dev.pDevIns = pDevIns;
603 }
604 return rc;
605}
606
607
608/**
609 * Register a PDM driver data unit.
610 *
611 * @returns VBox status.
612 *
613 * @param pVM The VM handle.
614 * @param pDrvIns Driver instance.
615 * @param pszName Data unit name.
616 * @param u32Instance The instance identifier of the data unit.
617 * This must together with the name be unique.
618 * @param u32Version Data layout version number.
619 * @param cbGuess The approximate amount of data in the unit.
620 * Only for progress indicators.
621 * @param pfnSavePrep Prepare save callback, optional.
622 * @param pfnSaveExec Execute save callback, optional.
623 * @param pfnSaveDone Done save callback, optional.
624 * @param pfnLoadPrep Prepare load callback, optional.
625 * @param pfnLoadExec Execute load callback, optional.
626 * @param pfnLoadDone Done load callback, optional.
627 */
628VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
629 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
630 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
631{
632 PSSMUNIT pUnit;
633 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
634 if (RT_SUCCESS(rc))
635 {
636 pUnit->enmType = SSMUNITTYPE_DRV;
637 pUnit->u.Drv.pfnSavePrep = pfnSavePrep;
638 pUnit->u.Drv.pfnSaveExec = pfnSaveExec;
639 pUnit->u.Drv.pfnSaveDone = pfnSaveDone;
640 pUnit->u.Drv.pfnLoadPrep = pfnLoadPrep;
641 pUnit->u.Drv.pfnLoadExec = pfnLoadExec;
642 pUnit->u.Drv.pfnLoadDone = pfnLoadDone;
643 pUnit->u.Drv.pDrvIns = pDrvIns;
644 }
645 return rc;
646}
647
648
649/**
650 * Register a internal data unit.
651 *
652 * @returns VBox status.
653 *
654 * @param pVM The VM handle.
655 * @param pszName Data unit name.
656 * @param u32Instance The instance identifier of the data unit.
657 * This must together with the name be unique.
658 * @param u32Version Data layout version number.
659 * @param cbGuess The approximate amount of data in the unit.
660 * Only for progress indicators.
661 * @param pfnSavePrep Prepare save callback, optional.
662 * @param pfnSaveExec Execute save callback, optional.
663 * @param pfnSaveDone Done save callback, optional.
664 * @param pfnLoadPrep Prepare load callback, optional.
665 * @param pfnLoadExec Execute load callback, optional.
666 * @param pfnLoadDone Done load callback, optional.
667 */
668VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
669 PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone,
670 PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone)
671{
672 PSSMUNIT pUnit;
673 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
674 if (RT_SUCCESS(rc))
675 {
676 pUnit->enmType = SSMUNITTYPE_INTERNAL;
677 pUnit->u.Internal.pfnSavePrep = pfnSavePrep;
678 pUnit->u.Internal.pfnSaveExec = pfnSaveExec;
679 pUnit->u.Internal.pfnSaveDone = pfnSaveDone;
680 pUnit->u.Internal.pfnLoadPrep = pfnLoadPrep;
681 pUnit->u.Internal.pfnLoadExec = pfnLoadExec;
682 pUnit->u.Internal.pfnLoadDone = pfnLoadDone;
683 }
684 return rc;
685}
686
687
688/**
689 * Register an external data unit.
690 *
691 * @returns VBox status.
692 *
693 * @param pVM The VM handle.
694 * @param pszName Data unit name.
695 * @param u32Instance The instance identifier of the data unit.
696 * This must together with the name be unique.
697 * @param u32Version Data layout version number.
698 * @param cbGuess The approximate amount of data in the unit.
699 * Only for progress indicators.
700 * @param pfnSavePrep Prepare save callback, optional.
701 * @param pfnSaveExec Execute save callback, optional.
702 * @param pfnSaveDone Done save callback, optional.
703 * @param pfnLoadPrep Prepare load callback, optional.
704 * @param pfnLoadExec Execute load callback, optional.
705 * @param pfnLoadDone Done load callback, optional.
706 * @param pvUser User argument.
707 */
708VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
709 PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone,
710 PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
711{
712 PSSMUNIT pUnit;
713 int rc = ssmR3Register(pVM, pszName, u32Instance, u32Version, cbGuess, NULL, &pUnit);
714 if (RT_SUCCESS(rc))
715 {
716 pUnit->enmType = SSMUNITTYPE_EXTERNAL;
717 pUnit->u.External.pfnSavePrep = pfnSavePrep;
718 pUnit->u.External.pfnSaveExec = pfnSaveExec;
719 pUnit->u.External.pfnSaveDone = pfnSaveDone;
720 pUnit->u.External.pfnLoadPrep = pfnLoadPrep;
721 pUnit->u.External.pfnLoadExec = pfnLoadExec;
722 pUnit->u.External.pfnLoadDone = pfnLoadDone;
723 pUnit->u.External.pvUser = pvUser;
724 }
725 return rc;
726}
727
728
729/**
730 * Deregister one or more PDM Device data units.
731 *
732 * @returns VBox status.
733 *
734 * @param pVM The VM handle.
735 * @param pDevIns Device instance.
736 * @param pszName Data unit name.
737 * Use NULL to deregister all data units for that device instance.
738 * @param u32Instance The instance identifier of the data unit.
739 * This must together with the name be unique.
740 * @remark Only for dynmaic data units and dynamic unloaded modules.
741 */
742VMMR3DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance)
743{
744 /*
745 * Validate input.
746 */
747 if (!pDevIns)
748 {
749 AssertMsgFailed(("pDevIns is NULL!\n"));
750 return VERR_INVALID_PARAMETER;
751 }
752
753 /*
754 * Search the list.
755 */
756 size_t cchName = pszName ? strlen(pszName) : 0;
757 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
758 PSSMUNIT pUnitPrev = NULL;
759 PSSMUNIT pUnit = pVM->ssm.s.pHead;
760 while (pUnit)
761 {
762 if ( pUnit->enmType == SSMUNITTYPE_DEV
763 && ( !pszName
764 || ( pUnit->cchName == cchName
765 && !memcmp(pUnit->szName, pszName, cchName)))
766 && pUnit->u32Instance == u32Instance
767 )
768 {
769 if (pUnit->u.Dev.pDevIns == pDevIns)
770 {
771 /*
772 * Unlink it, advance pointer, and free the node.
773 */
774 PSSMUNIT pFree = pUnit;
775 pUnit = pUnit->pNext;
776 if (pUnitPrev)
777 pUnitPrev->pNext = pUnit;
778 else
779 pVM->ssm.s.pHead = pUnit;
780 Log(("SSM: Removed data unit '%s' (pdm dev).\n", pFree->szName));
781 MMR3HeapFree(pFree);
782 if (pszName)
783 return VINF_SUCCESS;
784 rc = VINF_SUCCESS;
785 continue;
786 }
787 else if (pszName)
788 {
789 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
790 pUnit->u.Dev.pDevIns, pDevIns, pszName));
791 return VERR_SSM_UNIT_NOT_OWNER;
792 }
793 }
794
795 /* next */
796 pUnitPrev = pUnit;
797 pUnit = pUnit->pNext;
798 }
799
800 return rc;
801}
802
803
804/**
805 * Deregister one ore more PDM Driver data units.
806 *
807 * @returns VBox status.
808 * @param pVM The VM handle.
809 * @param pDrvIns Driver instance.
810 * @param pszName Data unit name.
811 * Use NULL to deregister all data units for that driver instance.
812 * @param u32Instance The instance identifier of the data unit.
813 * This must together with the name be unique. Ignored if pszName is NULL.
814 * @remark Only for dynmaic data units and dynamic unloaded modules.
815 */
816VMMR3DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
817{
818 /*
819 * Validate input.
820 */
821 if (!pDrvIns)
822 {
823 AssertMsgFailed(("pDrvIns is NULL!\n"));
824 return VERR_INVALID_PARAMETER;
825 }
826
827 /*
828 * Search the list.
829 */
830 size_t cchName = pszName ? strlen(pszName) : 0;
831 int rc = pszName ? VERR_SSM_UNIT_NOT_FOUND : VINF_SUCCESS;
832 PSSMUNIT pUnitPrev = NULL;
833 PSSMUNIT pUnit = pVM->ssm.s.pHead;
834 while (pUnit)
835 {
836 if ( pUnit->enmType == SSMUNITTYPE_DRV
837 && ( !pszName
838 || ( pUnit->cchName == cchName
839 && !memcmp(pUnit->szName, pszName, cchName)
840 && pUnit->u32Instance == u32Instance))
841 )
842 {
843 if (pUnit->u.Drv.pDrvIns == pDrvIns)
844 {
845 /*
846 * Unlink it, advance pointer, and free the node.
847 */
848 PSSMUNIT pFree = pUnit;
849 pUnit = pUnit->pNext;
850 if (pUnitPrev)
851 pUnitPrev->pNext = pUnit;
852 else
853 pVM->ssm.s.pHead = pUnit;
854 Log(("SSM: Removed data unit '%s' (pdm drv).\n", pFree->szName));
855 MMR3HeapFree(pFree);
856 if (pszName)
857 return VINF_SUCCESS;
858 rc = VINF_SUCCESS;
859 continue;
860 }
861 else if (pszName)
862 {
863 AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
864 pUnit->u.Drv.pDrvIns, pDrvIns, pszName));
865 return VERR_SSM_UNIT_NOT_OWNER;
866 }
867 }
868
869 /* next */
870 pUnitPrev = pUnit;
871 pUnit = pUnit->pNext;
872 }
873
874 return rc;
875}
876
877
878/**
879 * Deregister a data unit.
880 *
881 * @returns VBox status.
882 * @param pVM The VM handle.
883 * @param enmType Unit type
884 * @param pszName Data unit name.
885 * @remark Only for dynmaic data units.
886 */
887static int ssmR3DeregisterByNameAndType(PVM pVM, const char *pszName, SSMUNITTYPE enmType)
888{
889 /*
890 * Validate input.
891 */
892 if (!pszName)
893 {
894 AssertMsgFailed(("pszName is NULL!\n"));
895 return VERR_INVALID_PARAMETER;
896 }
897
898 /*
899 * Search the list.
900 */
901 size_t cchName = strlen(pszName);
902 int rc = VERR_SSM_UNIT_NOT_FOUND;
903 PSSMUNIT pUnitPrev = NULL;
904 PSSMUNIT pUnit = pVM->ssm.s.pHead;
905 while (pUnit)
906 {
907 if ( pUnit->enmType == enmType
908 && pUnit->cchName == cchName
909 && !memcmp(pUnit->szName, pszName, cchName))
910 {
911 /*
912 * Unlink it, advance pointer, and free the node.
913 */
914 PSSMUNIT pFree = pUnit;
915 pUnit = pUnit->pNext;
916 if (pUnitPrev)
917 pUnitPrev->pNext = pUnit;
918 else
919 pVM->ssm.s.pHead = pUnit;
920 Log(("SSM: Removed data unit '%s' (type=%d).\n", pFree->szName, enmType));
921 MMR3HeapFree(pFree);
922 return VINF_SUCCESS;
923 }
924
925 /* next */
926 pUnitPrev = pUnit;
927 pUnit = pUnit->pNext;
928 }
929
930 return rc;
931}
932
933
934/**
935 * Deregister an internal data unit.
936 *
937 * @returns VBox status.
938 * @param pVM The VM handle.
939 * @param pszName Data unit name.
940 * @remark Only for dynmaic data units.
941 */
942VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName)
943{
944 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_INTERNAL);
945}
946
947
948/**
949 * Deregister an external data unit.
950 *
951 * @returns VBox status.
952 * @param pVM The VM handle.
953 * @param pszName Data unit name.
954 * @remark Only for dynmaic data units.
955 */
956VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName)
957{
958 return ssmR3DeregisterByNameAndType(pVM, pszName, SSMUNITTYPE_EXTERNAL);
959}
960
961
962/**
963 * Calculate the checksum of a file portion.
964 *
965 * The current implementation is a cut&past of the libkern/crc32.c file from FreeBSD.
966 *
967 * @returns VBox status.
968 * @param File Handle to the file.
969 * @param cbFile Size of the file.
970 * @param pu32CRC Where to store the calculated checksum.
971 */
972static int ssmR3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC)
973{
974 /*
975 * Allocate a buffer.
976 */
977 void *pvBuf = RTMemTmpAlloc(32*1024);
978 if (!pvBuf)
979 return VERR_NO_TMP_MEMORY;
980
981 /*
982 * Loop reading and calculating CRC32.
983 */
984 int rc = VINF_SUCCESS;
985 uint32_t u32CRC = RTCrc32Start();
986 while (cbFile)
987 {
988 /* read chunk */
989 register unsigned cbToRead = 32*1024;
990 if (cbFile < 32*1024)
991 cbToRead = (unsigned)cbFile;
992 rc = RTFileRead(File, pvBuf, cbToRead, NULL);
993 if (RT_FAILURE(rc))
994 {
995 AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
996 RTMemTmpFree(pvBuf);
997 return rc;
998 }
999
1000 /* update total */
1001 cbFile -= cbToRead;
1002
1003 /* calc crc32. */
1004 u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
1005 }
1006 RTMemTmpFree(pvBuf);
1007
1008 /* store the calculated crc */
1009 u32CRC = RTCrc32Finish(u32CRC);
1010 Log(("SSM: u32CRC=0x%08x\n", u32CRC));
1011 *pu32CRC = u32CRC;
1012
1013 return VINF_SUCCESS;
1014}
1015
1016
1017/**
1018 * Works the progress calculation.
1019 *
1020 * @param pSSM The SSM handle.
1021 * @param cbAdvance Number of bytes to advance
1022 */
1023static void ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance)
1024{
1025 /* Can't advance it beyond the estimated end of the unit. */
1026 uint64_t cbLeft = pSSM->offEstUnitEnd - pSSM->offEst;
1027 if (cbAdvance > cbLeft)
1028 cbAdvance = cbLeft;
1029 pSSM->offEst += cbAdvance;
1030
1031 /* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
1032 while (pSSM->offEst >= pSSM->offEstProgress && pSSM->uPercent <= 100-pSSM->uPercentDone)
1033 {
1034 if (pSSM->pfnProgress)
1035 pSSM->pfnProgress(pSSM->pVM, pSSM->uPercent, pSSM->pvUser);
1036 pSSM->uPercent++;
1037 pSSM->offEstProgress = (pSSM->uPercent - pSSM->uPercentPrepare) * pSSM->cbEstTotal
1038 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
1039 }
1040}
1041
1042
1043/**
1044 * Start VM save operation.
1045 *
1046 * @returns VBox status.
1047 *
1048 * @param pVM The VM handle.
1049 * @param pszFilename Name of the file to save the state in.
1050 * @param enmAfter What is planned after a successful save operation.
1051 * @param pfnProgress Progress callback. Optional.
1052 * @param pvUser User argument for the progress callback.
1053 *
1054 * @thread EMT
1055 */
1056VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
1057{
1058 LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
1059 VM_ASSERT_EMT(pVM);
1060
1061 /*
1062 * Validate input.
1063 */
1064 if ( enmAfter != SSMAFTER_DESTROY
1065 && enmAfter != SSMAFTER_CONTINUE)
1066 {
1067 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
1068 return VERR_INVALID_PARAMETER;
1069 }
1070
1071 /*
1072 * Create the handle and try open the file.
1073 *
1074 * Note that there might be quite some work to do after executing the saving,
1075 * so we reserve 20% for the 'Done' period. The checksumming and closing of
1076 * the saved state file might take a long time.
1077 */
1078 SSMHANDLE Handle = {0};
1079 Handle.File = NIL_RTFILE;
1080 Handle.pVM = pVM;
1081 Handle.cbFileHdr = sizeof(SSMFILEHDR);
1082 Handle.enmOp = SSMSTATE_INVALID;
1083 Handle.enmAfter = enmAfter;
1084 Handle.rc = VINF_SUCCESS;
1085 Handle.pZipComp = NULL;
1086 Handle.pZipDecomp = NULL;
1087 Handle.cbUnitLeft = 0;
1088 Handle.offUnit = UINT64_MAX;
1089 Handle.pfnProgress = pfnProgress;
1090 Handle.pvUser = pvUser;
1091 Handle.uPercent = 0;
1092 Handle.offEstProgress = 0;
1093 Handle.cbEstTotal = 0;
1094 Handle.offEst = 0;
1095 Handle.offEstUnitEnd = 0;
1096 Handle.uPercentPrepare = 20;
1097 Handle.uPercentDone = 2;
1098 Handle.cbGCPhys = sizeof(RTGCPHYS);
1099 Handle.cbGCPtr = sizeof(RTGCPTR);
1100 Handle.fFixedGCPtrSize = true;
1101
1102 int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
1103 if (RT_FAILURE(rc))
1104 {
1105 LogRel(("SSM: Failed to create save state file '%s', rc=%Rrc.\n", pszFilename, rc));
1106 return rc;
1107 }
1108
1109 Log(("SSM: Starting state save to file '%s'...\n", pszFilename));
1110
1111 /*
1112 * Write header.
1113 */
1114 SSMFILEHDR Hdr =
1115 {
1116 /* .achMagic[32] = */ SSMFILEHDR_MAGIC_V1_2,
1117 /* .cbFile = */ 0,
1118 /* .u32CRC = */ 0,
1119 /* .u32Reserved = */ 0,
1120 /* .MachineUuid = */ {{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}},
1121 /* .u16VerMajor = */ VBOX_VERSION_MAJOR,
1122 /* .u16VerMinor = */ VBOX_VERSION_MINOR,
1123 /* .u32VerBuild = */ VBOX_VERSION_BUILD,
1124 /* .u32SvnRev = */ VMMGetSvnRev(),
1125 /* .cHostBits = */ HC_ARCH_BITS,
1126 /* .cbGCPhys = */ sizeof(RTGCPHYS),
1127 /* .cbGCPtr = */ sizeof(RTGCPTR),
1128 /* .au8Reserved = */ 0
1129 };
1130 rc = RTFileWrite(Handle.File, &Hdr, sizeof(Hdr), NULL);
1131 if (RT_SUCCESS(rc))
1132 {
1133 /*
1134 * Clear the per unit flags.
1135 */
1136 PSSMUNIT pUnit;
1137 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1138 pUnit->fCalled = false;
1139
1140 /*
1141 * Do the prepare run.
1142 */
1143 Handle.rc = VINF_SUCCESS;
1144 Handle.enmOp = SSMSTATE_SAVE_PREP;
1145 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1146 {
1147 switch (pUnit->enmType)
1148 {
1149 case SSMUNITTYPE_DEV:
1150 if (pUnit->u.Dev.pfnSavePrep)
1151 {
1152 rc = pUnit->u.Dev.pfnSavePrep(pUnit->u.Dev.pDevIns, &Handle);
1153 pUnit->fCalled = true;
1154 }
1155 break;
1156 case SSMUNITTYPE_DRV:
1157 if (pUnit->u.Drv.pfnSavePrep)
1158 {
1159 rc = pUnit->u.Drv.pfnSavePrep(pUnit->u.Drv.pDrvIns, &Handle);
1160 pUnit->fCalled = true;
1161 }
1162 break;
1163 case SSMUNITTYPE_INTERNAL:
1164 if (pUnit->u.Internal.pfnSavePrep)
1165 {
1166 rc = pUnit->u.Internal.pfnSavePrep(pVM, &Handle);
1167 pUnit->fCalled = true;
1168 }
1169 break;
1170 case SSMUNITTYPE_EXTERNAL:
1171 if (pUnit->u.External.pfnSavePrep)
1172 {
1173 rc = pUnit->u.External.pfnSavePrep(&Handle, pUnit->u.External.pvUser);
1174 pUnit->fCalled = true;
1175 }
1176 break;
1177 }
1178 if (RT_FAILURE(rc))
1179 {
1180 LogRel(("SSM: Prepare save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1181 break;
1182 }
1183
1184 Handle.cbEstTotal += pUnit->cbGuess;
1185 }
1186
1187 /* Progress. */
1188 if (pfnProgress)
1189 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
1190 Handle.uPercent = Handle.uPercentPrepare;
1191
1192 /*
1193 * Do the execute run.
1194 */
1195 if (RT_SUCCESS(rc))
1196 {
1197 Handle.enmOp = SSMSTATE_SAVE_EXEC;
1198 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1199 {
1200 /*
1201 * Estimate.
1202 */
1203 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1204 Handle.offEstUnitEnd += pUnit->cbGuess;
1205
1206 /*
1207 * Does this unit have a callback? If, not skip it.
1208 */
1209 bool fSkip;
1210 switch (pUnit->enmType)
1211 {
1212 case SSMUNITTYPE_DEV: fSkip = pUnit->u.Dev.pfnSaveExec == NULL; break;
1213 case SSMUNITTYPE_DRV: fSkip = pUnit->u.Drv.pfnSaveExec == NULL; break;
1214 case SSMUNITTYPE_INTERNAL: fSkip = pUnit->u.Internal.pfnSaveExec == NULL; break;
1215 case SSMUNITTYPE_EXTERNAL: fSkip = pUnit->u.External.pfnSaveExec == NULL; break;
1216 default: fSkip = true; break;
1217 }
1218 if (fSkip)
1219 {
1220 pUnit->fCalled = true;
1221 continue;
1222 }
1223
1224 /*
1225 * Write data unit header
1226 */
1227 uint64_t offHdr = RTFileTell(Handle.File);
1228 SSMFILEUNITHDR UnitHdr = { SSMFILEUNITHDR_MAGIC, 0, pUnit->u32Version, pUnit->u32Instance, (uint32_t)pUnit->cchName + 1, { '\0' } };
1229 rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
1230 if (RT_SUCCESS(rc))
1231 {
1232 rc = RTFileWrite(Handle.File, &pUnit->szName[0], pUnit->cchName + 1, NULL);
1233 if (RT_SUCCESS(rc))
1234 {
1235 /*
1236 * Call the execute handler.
1237 */
1238 Handle.offUnit = 0;
1239 switch (pUnit->enmType)
1240 {
1241 case SSMUNITTYPE_DEV:
1242 rc = pUnit->u.Dev.pfnSaveExec(pUnit->u.Dev.pDevIns, &Handle);
1243 break;
1244 case SSMUNITTYPE_DRV:
1245 rc = pUnit->u.Drv.pfnSaveExec(pUnit->u.Drv.pDrvIns, &Handle);
1246 break;
1247 case SSMUNITTYPE_INTERNAL:
1248 rc = pUnit->u.Internal.pfnSaveExec(pVM, &Handle);
1249 break;
1250 case SSMUNITTYPE_EXTERNAL:
1251 pUnit->u.External.pfnSaveExec(&Handle, pUnit->u.External.pvUser);
1252 rc = Handle.rc;
1253 break;
1254 }
1255 pUnit->fCalled = true;
1256 if (RT_FAILURE(Handle.rc) && RT_SUCCESS(rc))
1257 rc = Handle.rc;
1258 if (RT_SUCCESS(rc))
1259 {
1260 /*
1261 * Flush buffer / end compression stream.
1262 */
1263 if (Handle.pZipComp)
1264 rc = ssmR3WriteFinish(&Handle);
1265 if (RT_SUCCESS(rc))
1266 {
1267 /*
1268 * Update header with correct length.
1269 */
1270 uint64_t offEnd = RTFileTell(Handle.File);
1271 rc = RTFileSeek(Handle.File, offHdr, RTFILE_SEEK_BEGIN, NULL);
1272 if (RT_SUCCESS(rc))
1273 {
1274 UnitHdr.cbUnit = offEnd - offHdr;
1275 ///@todo UnitHdr.cbUnitUncompressed = Handle.offUnit;
1276 rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
1277 if (RT_SUCCESS(rc))
1278 {
1279 rc = RTFileSeek(Handle.File, offEnd, RTFILE_SEEK_BEGIN, NULL);
1280 if (RT_SUCCESS(rc))
1281 Log(("SSM: Data unit: offset %#9llx size %9lld / %9lld '%s'\n", offHdr, UnitHdr.cbUnit, Handle.offUnit, pUnit->szName));
1282 }
1283 }
1284 Handle.offUnit = UINT64_MAX;
1285 }
1286 else
1287 {
1288 LogRel(("SSM: Failed ending compression stream. rc=%Rrc\n", rc));
1289 break;
1290 }
1291 }
1292 else
1293 {
1294 LogRel(("SSM: Execute save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1295 break;
1296 }
1297 }
1298 }
1299 if (RT_FAILURE(rc))
1300 {
1301 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc));
1302 break;
1303 }
1304 } /* for each unit */
1305
1306 /* finish the progress. */
1307 if (RT_SUCCESS(rc))
1308 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1309 }
1310 /* (progress should be pending 99% now) */
1311 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
1312
1313 /*
1314 * Do the done run.
1315 */
1316 Handle.rc = rc;
1317 Handle.enmOp = SSMSTATE_SAVE_DONE;
1318 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1319 {
1320 switch (pUnit->enmType)
1321 {
1322 case SSMUNITTYPE_DEV:
1323 if ( pUnit->u.Dev.pfnSaveDone
1324 && ( pUnit->fCalled
1325 || (!pUnit->u.Dev.pfnSavePrep && !pUnit->u.Dev.pfnSaveExec)))
1326 rc = pUnit->u.Dev.pfnSaveDone(pUnit->u.Dev.pDevIns, &Handle);
1327 break;
1328 case SSMUNITTYPE_DRV:
1329 if ( pUnit->u.Drv.pfnSaveDone
1330 && ( pUnit->fCalled
1331 || (!pUnit->u.Drv.pfnSavePrep && !pUnit->u.Drv.pfnSaveExec)))
1332 rc = pUnit->u.Drv.pfnSaveDone(pUnit->u.Drv.pDrvIns, &Handle);
1333 break;
1334 case SSMUNITTYPE_INTERNAL:
1335 if ( pUnit->u.Internal.pfnSaveDone
1336 && ( pUnit->fCalled
1337 || (!pUnit->u.Internal.pfnSavePrep && !pUnit->u.Internal.pfnSaveExec)))
1338 rc = pUnit->u.Internal.pfnSaveDone(pVM, &Handle);
1339 break;
1340 case SSMUNITTYPE_EXTERNAL:
1341 if ( pUnit->u.External.pfnSaveDone
1342 && ( pUnit->fCalled
1343 || (!pUnit->u.External.pfnSavePrep && !pUnit->u.External.pfnSaveExec)))
1344 rc = pUnit->u.External.pfnSaveDone(&Handle, pUnit->u.External.pvUser);
1345 break;
1346 }
1347 if (RT_FAILURE(rc))
1348 {
1349 LogRel(("SSM: Done save failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1350 if (RT_SUCCESS(Handle.rc))
1351 Handle.rc = rc;
1352 }
1353 }
1354 rc = Handle.rc;
1355
1356 /*
1357 * Finalize the file if successfully saved.
1358 */
1359 if (RT_SUCCESS(rc))
1360 {
1361 /* end record */
1362 SSMFILEUNITHDR UnitHdr = { SSMFILEUNITHDR_END, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), 0, '\0'};
1363 rc = RTFileWrite(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName[0]), NULL);
1364 if (RT_SUCCESS(rc))
1365 {
1366 /* get size */
1367 Hdr.cbFile = RTFileTell(Handle.File);
1368 /* calc checksum */
1369 rc = RTFileSeek(Handle.File, RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(Hdr.u32CRC), RTFILE_SEEK_BEGIN, NULL);
1370 if (RT_SUCCESS(rc))
1371 rc = ssmR3CalcChecksum(Handle.File, Hdr.cbFile - sizeof(Hdr), &Hdr.u32CRC);
1372 if (RT_SUCCESS(rc))
1373 {
1374 if (pfnProgress)
1375 pfnProgress(pVM, 90, pvUser);
1376
1377 /*
1378 * Write the update the header to the file.
1379 */
1380 rc = RTFileSeek(Handle.File, 0, RTFILE_SEEK_BEGIN, NULL);
1381 if (RT_SUCCESS(rc))
1382 rc = RTFileWrite(Handle.File, &Hdr, sizeof(Hdr), NULL);
1383 if (RT_SUCCESS(rc))
1384 {
1385 rc = RTFileClose(Handle.File);
1386 AssertRC(rc);
1387 if (pfnProgress)
1388 pfnProgress(pVM, 100, pvUser);
1389 Log(("SSM: Successfully saved the vm state to '%s'.\n", pszFilename));
1390 Log(("\n\n\n"));
1391 DBGFR3InfoLog(pVM, "cpum", "verbose");
1392 DBGFR3InfoLog(pVM, "timers", NULL);
1393 DBGFR3InfoLog(pVM, "activetimers", NULL);
1394 DBGFR3InfoLog(pVM, "ioport", NULL);
1395 DBGFR3InfoLog(pVM, "mmio", NULL);
1396 DBGFR3InfoLog(pVM, "phys", NULL);
1397 Log(("\n\n\n"));
1398 return VINF_SUCCESS;
1399 }
1400
1401 }
1402 }
1403 LogRel(("SSM: Failed to finalize state file! rc=%Rrc\n", pszFilename));
1404 }
1405 }
1406
1407 /*
1408 * Delete the file on failure and destroy any compressors.
1409 */
1410 int rc2 = RTFileClose(Handle.File);
1411 AssertRC(rc2);
1412 rc2 = RTFileDelete(pszFilename);
1413 AssertRC(rc2);
1414 if (Handle.pZipComp)
1415 RTZipCompDestroy(Handle.pZipComp);
1416
1417 return rc;
1418}
1419
1420
1421/**
1422 * Validates the integrity of a saved state file.
1423 *
1424 * @returns VBox status.
1425 * @param File File to validate.
1426 * The file position is undefined on return.
1427 * @param fChecksumIt Whether to checksum the file or not.
1428 * @param pHdr Where to store the file header.
1429 * @param pcbFileHdr Where to store the file header size.
1430 */
1431static int ssmR3ValidateFile(RTFILE File, bool fChecksumIt, PSSMFILEHDR pHdr, size_t *pcbFileHdr)
1432{
1433 /*
1434 * Read the header.
1435 */
1436 int rc = RTFileRead(File, pHdr, sizeof(*pHdr), NULL);
1437 if (RT_FAILURE(rc))
1438 {
1439 Log(("SSM: Failed to read file header. rc=%Rrc\n", rc));
1440 return rc;
1441 }
1442
1443 /*
1444 * Verify the magic and make adjustments for versions differences.
1445 */
1446 if (memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
1447 {
1448 Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(pHdr->achMagic) - 1, pHdr->achMagic));
1449 return VERR_SSM_INTEGRITY_MAGIC;
1450 }
1451
1452 size_t offCrc32 = RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(pHdr->u32CRC);
1453 *pcbFileHdr = sizeof(*pHdr);
1454 if (!memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_V1_0, sizeof(SSMFILEHDR_MAGIC_V1_0)))
1455 {
1456 if (pHdr->MachineUuid.au32[3])
1457 {
1458 SSMFILEHDRV10X86 OldHdr;
1459 memcpy(&OldHdr, pHdr, sizeof(OldHdr));
1460 pHdr->cbFile = OldHdr.cbFile;
1461 pHdr->u32CRC = OldHdr.u32CRC;
1462 pHdr->u32Reserved = 0;
1463 pHdr->MachineUuid = OldHdr.MachineUuid;
1464 pHdr->cHostBits = 32;
1465
1466 offCrc32 = RT_OFFSETOF(SSMFILEHDRV10X86, u32CRC) + sizeof(pHdr->u32CRC);
1467 *pcbFileHdr = sizeof(OldHdr);
1468 }
1469 else
1470 {
1471 SSMFILEHDRV10AMD64 OldHdr;
1472 memcpy(&OldHdr, pHdr, sizeof(OldHdr));
1473 pHdr->cbFile = OldHdr.cbFile;
1474 pHdr->u32CRC = OldHdr.u32CRC;
1475 pHdr->u32Reserved = 0;
1476 pHdr->MachineUuid = OldHdr.MachineUuid;
1477 pHdr->cHostBits = 64;
1478
1479 offCrc32 = RT_OFFSETOF(SSMFILEHDRV10AMD64, u32CRC) + sizeof(pHdr->u32CRC);
1480 *pcbFileHdr = sizeof(OldHdr);
1481 }
1482 pHdr->u16VerMajor = 0;
1483 pHdr->u16VerMinor = 0;
1484 pHdr->u32VerBuild = 0;
1485 pHdr->u32SvnRev = 0;
1486 pHdr->cbGCPhys = sizeof(uint32_t);
1487 pHdr->cbGCPtr = sizeof(uint32_t);
1488 pHdr->au8Reserved = 0;
1489 }
1490 else if (!memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDR_MAGIC_V1_1)))
1491 {
1492 *pcbFileHdr = sizeof(SSMFILEHDRV11);
1493 pHdr->u16VerMajor = 0;
1494 pHdr->u16VerMinor = 0;
1495 pHdr->u32VerBuild = 0;
1496 pHdr->u32SvnRev = 0;
1497 pHdr->cHostBits = 0; /* unknown */
1498 pHdr->cbGCPhys = sizeof(RTGCPHYS);
1499 pHdr->cbGCPtr = 0; /* settable. */
1500 pHdr->au8Reserved = 0;
1501 }
1502 else if (!memcmp(pHdr->achMagic, SSMFILEHDR_MAGIC_V1_2, sizeof(pHdr->achMagic)))
1503 {
1504 if ( pHdr->u16VerMajor == 0
1505 || pHdr->u16VerMajor > 1000
1506 || pHdr->u32SvnRev == 0
1507 || pHdr->u32SvnRev > 10000000 /*100M*/)
1508 {
1509 LogRel(("SSM: Incorrect version values: %d.%d.%d.r%d\n",
1510 pHdr->u16VerMajor, pHdr->u16VerMinor, pHdr->u32VerBuild, pHdr->u32SvnRev));
1511 return VERR_SSM_INTEGRITY_VBOX_VERSION;
1512 }
1513 if ( pHdr->cHostBits != 32
1514 && pHdr->cHostBits != 64)
1515 {
1516 LogRel(("SSM: Incorrect cHostBits value: %d\n", pHdr->cHostBits));
1517 return VERR_SSM_INTEGRITY_SIZES;
1518 }
1519 if ( pHdr->cbGCPhys != sizeof(uint32_t)
1520 && pHdr->cbGCPhys != sizeof(uint64_t))
1521 {
1522 LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pHdr->cbGCPhys));
1523 return VERR_SSM_INTEGRITY_SIZES;
1524 }
1525 if ( pHdr->cbGCPtr != sizeof(uint32_t)
1526 && pHdr->cbGCPtr != sizeof(uint64_t))
1527 {
1528 LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pHdr->cbGCPtr));
1529 return VERR_SSM_INTEGRITY_SIZES;
1530 }
1531 }
1532 else
1533 {
1534 Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(pHdr->achMagic) - 1, pHdr->achMagic));
1535 return VERR_SSM_INTEGRITY_VERSION;
1536 }
1537
1538 /*
1539 * Verify the file size.
1540 */
1541 uint64_t cbFile;
1542 rc = RTFileGetSize(File, &cbFile);
1543 if (RT_FAILURE(rc))
1544 {
1545 Log(("SSM: Failed to get file size. rc=%Rrc\n", rc));
1546 return rc;
1547 }
1548 if (cbFile != pHdr->cbFile)
1549 {
1550 Log(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pHdr->cbFile, cbFile));
1551 return VERR_SSM_INTEGRITY_SIZE;
1552 }
1553
1554 /*
1555 * Verify the checksum if requested.
1556 */
1557 if (fChecksumIt)
1558 {
1559 rc = RTFileSeek(File, offCrc32, RTFILE_SEEK_BEGIN, NULL);
1560 if (RT_FAILURE(rc))
1561 {
1562 Log(("SSM: Failed to seek to crc start. rc=%Rrc\n", rc));
1563 return rc;
1564 }
1565 uint32_t u32CRC;
1566 rc = ssmR3CalcChecksum(File, pHdr->cbFile - *pcbFileHdr, &u32CRC);
1567 if (RT_FAILURE(rc))
1568 return rc;
1569 if (u32CRC != pHdr->u32CRC)
1570 {
1571 Log(("SSM: Invalid CRC! Calculated %#08x, in header %#08x\n", u32CRC, pHdr->u32CRC));
1572 return VERR_SSM_INTEGRITY_CRC;
1573 }
1574 }
1575
1576 /*
1577 * Verify Virtual Machine UUID.
1578 */
1579 RTUUID Uuid;
1580 memset(&Uuid, 0, sizeof(Uuid));
1581/** @todo get machine uuids CFGGetUuid(, &Uuid); */
1582 if ( RTUuidCompare(&pHdr->MachineUuid, &Uuid)
1583 && !RTUuidIsNull(&pHdr->MachineUuid)) /* temporary hack, allowing NULL uuids. */
1584 {
1585 Log(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
1586 return VERR_SMM_INTEGRITY_MACHINE;
1587 }
1588
1589 return VINF_SUCCESS;
1590}
1591
1592
1593/**
1594 * Find a data unit by name.
1595 *
1596 * @returns Pointer to the unit.
1597 * @returns NULL if not found.
1598 *
1599 * @param pVM VM handle.
1600 * @param pszName Data unit name.
1601 * @param u32Instance The data unit instance id.
1602 */
1603static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t u32Instance)
1604{
1605 size_t cchName = strlen(pszName);
1606 PSSMUNIT pUnit = pVM->ssm.s.pHead;
1607 while ( pUnit
1608 && ( pUnit->u32Instance != u32Instance
1609 || pUnit->cchName != cchName
1610 || memcmp(pUnit->szName, pszName, cchName)))
1611 pUnit = pUnit->pNext;
1612 return pUnit;
1613}
1614
1615
1616/**
1617 * Load VM save operation.
1618 *
1619 * @returns VBox status.
1620 *
1621 * @param pVM The VM handle.
1622 * @param pszFilename Name of the file to save the state in.
1623 * @param enmAfter What is planned after a successful load operation.
1624 * Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
1625 * @param pfnProgress Progress callback. Optional.
1626 * @param pvUser User argument for the progress callback.
1627 *
1628 * @thread EMT
1629 */
1630VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
1631{
1632 LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
1633 VM_ASSERT_EMT(pVM);
1634
1635 /*
1636 * Validate input.
1637 */
1638 if ( enmAfter != SSMAFTER_RESUME
1639 && enmAfter != SSMAFTER_DEBUG_IT)
1640 {
1641 AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
1642 return VERR_INVALID_PARAMETER;
1643 }
1644
1645 /*
1646 * Create the handle and open the file.
1647 * Note that we reserve 20% of the time on validating the image since this might
1648 * take a long time.
1649 */
1650 SSMHANDLE Handle = {0};
1651 Handle.File = NIL_RTFILE;
1652 Handle.pVM = pVM;
1653 Handle.cbFileHdr = sizeof(SSMFILEHDR);
1654 Handle.enmOp = SSMSTATE_INVALID;
1655 Handle.enmAfter = enmAfter;
1656 Handle.rc = VINF_SUCCESS;
1657 Handle.pZipComp = NULL;
1658 Handle.pZipDecomp = NULL;
1659 Handle.cbUnitLeft = 0;
1660 Handle.offUnit = UINT64_MAX;
1661 Handle.pfnProgress = pfnProgress;
1662 Handle.pvUser = pvUser;
1663 Handle.uPercent = 0;
1664 Handle.offEstProgress = 0;
1665 Handle.cbEstTotal = 0;
1666 Handle.offEst = 0;
1667 Handle.offEstUnitEnd = 0;
1668 Handle.uPercentPrepare = 20;
1669 Handle.uPercentDone = 2;
1670 Handle.cbGCPhys = sizeof(RTGCPHYS);
1671 Handle.cbGCPtr = sizeof(RTGCPTR);
1672 Handle.fFixedGCPtrSize = false;
1673
1674 int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1675 if (RT_FAILURE(rc))
1676 {
1677 Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n", pszFilename, rc));
1678 return rc;
1679 }
1680
1681 /*
1682 * Read file header and validate it.
1683 */
1684 SSMFILEHDR Hdr;
1685 rc = ssmR3ValidateFile(Handle.File, true /* fChecksumIt */, &Hdr, &Handle.cbFileHdr);
1686 if (RT_SUCCESS(rc))
1687 {
1688 if (Hdr.cbGCPhys)
1689 Handle.cbGCPhys = Hdr.cbGCPhys;
1690 if (Hdr.cbGCPtr)
1691 {
1692 Handle.cbGCPtr = Hdr.cbGCPtr;
1693 Handle.fFixedGCPtrSize = true;
1694 }
1695
1696 if (Handle.cbFileHdr == sizeof(Hdr))
1697 LogRel(("SSM: File header: Format %.4s, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
1698 &Hdr.achMagic[sizeof(SSMFILEHDR_MAGIC_BASE) - 1],
1699 Hdr.u16VerMajor, Hdr.u16VerMinor, Hdr.u32VerBuild, Hdr.u32SvnRev,
1700 Hdr.cHostBits, Hdr.cbGCPhys, Hdr.cbGCPtr));
1701 else
1702 LogRel(("SSM: File header: Format %.4s, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
1703 &Hdr.achMagic[sizeof(SSMFILEHDR_MAGIC_BASE)-1], Hdr.cHostBits, Hdr.cbGCPhys, Hdr.cbGCPtr));
1704
1705
1706 /*
1707 * Clear the per unit flags.
1708 */
1709 PSSMUNIT pUnit;
1710 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1711 pUnit->fCalled = false;
1712
1713 /*
1714 * Do the prepare run.
1715 */
1716 Handle.rc = VINF_SUCCESS;
1717 Handle.enmOp = SSMSTATE_LOAD_PREP;
1718 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1719 {
1720 switch (pUnit->enmType)
1721 {
1722 case SSMUNITTYPE_DEV:
1723 if (pUnit->u.Dev.pfnLoadPrep)
1724 {
1725 rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
1726 pUnit->fCalled = true;
1727 }
1728 break;
1729 case SSMUNITTYPE_DRV:
1730 if (pUnit->u.Drv.pfnLoadPrep)
1731 {
1732 rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
1733 pUnit->fCalled = true;
1734 }
1735 break;
1736 case SSMUNITTYPE_INTERNAL:
1737 if (pUnit->u.Internal.pfnLoadPrep)
1738 {
1739 rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
1740 pUnit->fCalled = true;
1741 }
1742 break;
1743 case SSMUNITTYPE_EXTERNAL:
1744 if (pUnit->u.External.pfnLoadPrep)
1745 {
1746 rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
1747 pUnit->fCalled = true;
1748 }
1749 break;
1750 }
1751 if (RT_FAILURE(rc))
1752 {
1753 LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
1754 break;
1755 }
1756 }
1757
1758 /* pending 2% */
1759 if (pfnProgress)
1760 pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
1761 Handle.uPercent = Handle.uPercentPrepare;
1762 Handle.cbEstTotal = Hdr.cbFile;
1763
1764 /*
1765 * Do the execute run.
1766 */
1767 if (RT_SUCCESS(rc))
1768 rc = RTFileSeek(Handle.File, Handle.cbFileHdr, RTFILE_SEEK_BEGIN, NULL);
1769 if (RT_SUCCESS(rc))
1770 {
1771 char *pszName = NULL;
1772 size_t cchName = 0;
1773 Handle.enmOp = SSMSTATE_LOAD_EXEC;
1774 for (;;)
1775 {
1776 /*
1777 * Save the current file position and read the data unit header.
1778 */
1779 uint64_t offUnit = RTFileTell(Handle.File);
1780 SSMFILEUNITHDR UnitHdr;
1781 rc = RTFileRead(Handle.File, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
1782 if (RT_SUCCESS(rc))
1783 {
1784 /*
1785 * Check the magic and see if it's valid and whether it is a end header or not.
1786 */
1787 if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
1788 {
1789 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
1790 {
1791 Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
1792 /* Complete the progress bar (pending 99% afterwards). */
1793 Handle.offEstUnitEnd = Handle.cbEstTotal;
1794 ssmR3Progress(&Handle, Handle.cbEstTotal - Handle.offEst);
1795 break;
1796 }
1797 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
1798 offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
1799 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
1800 break;
1801 }
1802
1803 /*
1804 * Read the name.
1805 * Adjust the name buffer first.
1806 */
1807 if (cchName < UnitHdr.cchName)
1808 {
1809 if (pszName)
1810 RTMemTmpFree(pszName);
1811 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
1812 pszName = (char *)RTMemTmpAlloc(cchName);
1813 }
1814 if (pszName)
1815 {
1816 rc = RTFileRead(Handle.File, pszName, UnitHdr.cchName, NULL);
1817 if (RT_SUCCESS(rc))
1818 {
1819 if (!pszName[UnitHdr.cchName - 1])
1820 {
1821 Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
1822
1823 /*
1824 * Progress
1825 */
1826 Handle.offEstUnitEnd += UnitHdr.cbUnit;
1827
1828 /*
1829 * Find the data unit in our internal table.
1830 */
1831 pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
1832 if (pUnit)
1833 {
1834 /*
1835 * Call the execute handler.
1836 */
1837 Handle.cbUnitLeft = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
1838 Handle.offUnit = 0;
1839 switch (pUnit->enmType)
1840 {
1841 case SSMUNITTYPE_DEV:
1842 if (pUnit->u.Dev.pfnLoadExec)
1843 {
1844 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, &Handle, UnitHdr.u32Version);
1845 AssertRC(rc);
1846 }
1847 else
1848 rc = VERR_SSM_NO_LOAD_EXEC;
1849 break;
1850 case SSMUNITTYPE_DRV:
1851 if (pUnit->u.Drv.pfnLoadExec)
1852 {
1853 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, &Handle, UnitHdr.u32Version);
1854 AssertRC(rc);
1855 }
1856 else
1857 rc = VERR_SSM_NO_LOAD_EXEC;
1858 break;
1859 case SSMUNITTYPE_INTERNAL:
1860 if (pUnit->u.Internal.pfnLoadExec)
1861 {
1862 rc = pUnit->u.Internal.pfnLoadExec(pVM, &Handle, UnitHdr.u32Version);
1863 AssertRC(rc);
1864 }
1865 else
1866 rc = VERR_SSM_NO_LOAD_EXEC;
1867 break;
1868 case SSMUNITTYPE_EXTERNAL:
1869 if (pUnit->u.External.pfnLoadExec)
1870 {
1871 rc = pUnit->u.External.pfnLoadExec(&Handle, pUnit->u.External.pvUser, UnitHdr.u32Version);
1872 if (!rc)
1873 rc = Handle.rc;
1874 }
1875 else
1876 rc = VERR_SSM_NO_LOAD_EXEC;
1877 break;
1878 }
1879 if (rc != VERR_SSM_NO_LOAD_EXEC)
1880 {
1881 /*
1882 * Close the reader stream.
1883 */
1884 if (Handle.pZipDecomp)
1885 ssmR3ReadFinish(&Handle);
1886
1887 pUnit->fCalled = true;
1888 if (RT_SUCCESS(rc))
1889 rc = Handle.rc;
1890 if (RT_SUCCESS(rc))
1891 {
1892 /*
1893 * Now, we'll check the current position to see if all, or
1894 * more than all, the data was read.
1895 *
1896 * Note! Because of buffering / compression we'll only see the
1897 * really bad ones here.
1898 */
1899 uint64_t off = RTFileTell(Handle.File);
1900 int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
1901 if (i64Diff < 0)
1902 {
1903 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
1904 rc = RTFileSeek(Handle.File, offUnit + UnitHdr.cbUnit, RTFILE_SEEK_BEGIN, NULL);
1905 }
1906 else if (i64Diff > 0)
1907 {
1908 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
1909 rc = VERR_SSM_INTEGRITY;
1910 break;
1911 }
1912
1913 /* Advance the progress bar to the end of the block. */
1914 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1915 }
1916 else
1917 {
1918 /*
1919 * We failed, but if loading for the debugger ignore certain failures
1920 * just to get it all loaded (big hack).
1921 */
1922 LogRel(("SSM: LoadExec failed with rc=%Rrc for unit '%s'!\n", rc, pszName));
1923 if ( Handle.enmAfter != SSMAFTER_DEBUG_IT
1924 || rc != VERR_SSM_LOADED_TOO_MUCH)
1925 break;
1926 Handle.rc = rc = VINF_SUCCESS;
1927 ssmR3Progress(&Handle, Handle.offEstUnitEnd - Handle.offEst);
1928 }
1929 Handle.offUnit = UINT64_MAX;
1930 }
1931 else
1932 {
1933 LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
1934 rc = VERR_SSM_INTEGRITY;
1935 break;
1936 }
1937 }
1938 else
1939 {
1940 /*
1941 * SSM unit wasn't found - ignore this when loading for the debugger.
1942 */
1943 LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
1944 rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
1945 if (Handle.enmAfter != SSMAFTER_DEBUG_IT)
1946 break;
1947 rc = RTFileSeek(Handle.File, offUnit + UnitHdr.cbUnit, RTFILE_SEEK_BEGIN, NULL);
1948 }
1949 }
1950 else
1951 {
1952 LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
1953 rc = VERR_SSM_INTEGRITY;
1954 break;
1955 }
1956 }
1957 }
1958 else
1959 rc = VERR_NO_TMP_MEMORY;
1960 }
1961
1962 /*
1963 * I/O errors ends up here (yea, I know, very nice programming).
1964 */
1965 if (RT_FAILURE(rc))
1966 {
1967 LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
1968 break;
1969 }
1970 }
1971 }
1972 /* (progress should be pending 99% now) */
1973 AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
1974
1975 /*
1976 * Do the done run.
1977 */
1978 Handle.rc = rc;
1979 Handle.enmOp = SSMSTATE_LOAD_DONE;
1980 for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
1981 {
1982 rc = VINF_SUCCESS;
1983 switch (pUnit->enmType)
1984 {
1985 case SSMUNITTYPE_DEV:
1986 if ( pUnit->u.Dev.pfnLoadDone
1987 && ( pUnit->fCalled
1988 || (!pUnit->u.Dev.pfnLoadPrep && !pUnit->u.Dev.pfnLoadExec)))
1989 rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
1990 break;
1991 case SSMUNITTYPE_DRV:
1992 if ( pUnit->u.Drv.pfnLoadDone
1993 && ( pUnit->fCalled
1994 || (!pUnit->u.Drv.pfnLoadPrep && !pUnit->u.Drv.pfnLoadExec)))
1995 rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
1996 break;
1997 case SSMUNITTYPE_INTERNAL:
1998 if (pUnit->u.Internal.pfnLoadDone
1999 && ( pUnit->fCalled
2000 || (!pUnit->u.Internal.pfnLoadPrep && !pUnit->u.Internal.pfnLoadExec)))
2001 rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
2002 break;
2003 case SSMUNITTYPE_EXTERNAL:
2004 if (pUnit->u.External.pfnLoadDone
2005 && ( pUnit->fCalled
2006 || (!pUnit->u.Internal.pfnLoadPrep && !pUnit->u.Internal.pfnLoadExec)))
2007 rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
2008 break;
2009 }
2010 if (RT_FAILURE(rc))
2011 {
2012 LogRel(("SSM: Done load failed with rc=%Rrc for data unit '%s'.\n", rc, pUnit->szName));
2013 if (RT_SUCCESS(Handle.rc))
2014 Handle.rc = rc;
2015 }
2016 }
2017 rc = Handle.rc;
2018
2019 /* progress */
2020 if (pfnProgress)
2021 pfnProgress(pVM, 99, pvUser);
2022 }
2023
2024 /*
2025 * Done
2026 */
2027 int rc2 = RTFileClose(Handle.File);
2028 AssertRC(rc2);
2029 if (RT_SUCCESS(rc))
2030 {
2031 /* progress */
2032 if (pfnProgress)
2033 pfnProgress(pVM, 100, pvUser);
2034 Log(("SSM: Load of '%s' completed!\n", pszFilename));
2035 Log(("\n\n\n"));
2036 DBGFR3InfoLog(pVM, "cpum", "verbose");
2037 DBGFR3InfoLog(pVM, "timers", NULL);
2038 DBGFR3InfoLog(pVM, "activetimers", NULL);
2039 DBGFR3InfoLog(pVM, "ioport", NULL);
2040 DBGFR3InfoLog(pVM, "mmio", NULL);
2041 DBGFR3InfoLog(pVM, "phys", NULL);
2042 Log(("\n\n\n"));
2043 }
2044 return rc;
2045}
2046
2047
2048/**
2049 * Validates a file as a validate SSM saved state.
2050 *
2051 * This will only verify the file format, the format and content of individual
2052 * data units are not inspected.
2053 *
2054 * @returns VINF_SUCCESS if valid.
2055 * @returns VBox status code on other failures.
2056 *
2057 * @param pszFilename The path to the file to validate.
2058 * @param fChecksumIt Whether to checksum the file or not.
2059 *
2060 * @thread Any.
2061 */
2062VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
2063{
2064 LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
2065
2066 /*
2067 * Try open the file and validate it.
2068 */
2069 RTFILE File;
2070 int rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
2071 if (RT_SUCCESS(rc))
2072 {
2073 size_t cbFileHdr;
2074 SSMFILEHDR Hdr;
2075 rc = ssmR3ValidateFile(File, fChecksumIt, &Hdr, &cbFileHdr);
2076 RTFileClose(File);
2077 }
2078 else
2079 Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
2080 return rc;
2081}
2082
2083
2084/**
2085 * Opens a saved state file for reading.
2086 *
2087 * @returns VBox status code.
2088 *
2089 * @param pszFilename The path to the saved state file.
2090 * @param fFlags Open flags. Reserved, must be 0.
2091 * @param ppSSM Where to store the SSM handle.
2092 *
2093 * @thread Any.
2094 */
2095VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
2096{
2097 LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
2098
2099 /*
2100 * Validate input.
2101 */
2102 AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
2103 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2104 AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
2105
2106 /*
2107 * Allocate a handle.
2108 */
2109 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
2110 AssertReturn(pSSM, VERR_NO_MEMORY);
2111
2112 /*
2113 * Try open the file and validate it.
2114 */
2115 int rc = RTFileOpen(&pSSM->File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
2116 if (RT_SUCCESS(rc))
2117 {
2118 SSMFILEHDR Hdr;
2119 size_t cbFileHdr;
2120 rc = ssmR3ValidateFile(pSSM->File, true /* fChecksumIt */, &Hdr, &cbFileHdr);
2121 if (RT_SUCCESS(rc))
2122 {
2123 //pSSM->pVM = NULL;
2124 pSSM->cbFileHdr = cbFileHdr;
2125 pSSM->enmOp = SSMSTATE_OPEN_READ;
2126 pSSM->enmAfter = SSMAFTER_OPENED;
2127 //pSSM->rc = VINF_SUCCESS;
2128 //pSSM->pZipComp = NULL;
2129 //pSSM->pZipDecomp = NULL;
2130 //pSSM->cbUnitLeft = 0;
2131 pSSM->offUnit = UINT64_MAX;
2132 //pSSM->pfnProgress = NULL;
2133 //pSSM->pvUser = NULL;
2134 //pSSM->uPercent = 0;
2135 //pSSM->offEstProgress= 0;
2136 //pSSM->cbEstTotal = 0;
2137 //pSSM->offEst = 0;
2138 //pSSM->offEstUnitEnd = 0;
2139 pSSM->uPercentPrepare = 20;
2140 pSSM->uPercentDone = 2;
2141 pSSM->cbGCPhys = Hdr.cbGCPhys ? Hdr.cbGCPhys : sizeof(RTGCPHYS);
2142 pSSM->cbGCPtr = sizeof(RTGCPTR);
2143 pSSM->fFixedGCPtrSize = false;
2144 if (Hdr.cbGCPtr)
2145 {
2146 pSSM->cbGCPtr = Hdr.cbGCPtr;
2147 pSSM->fFixedGCPtrSize = true;
2148 }
2149
2150 *ppSSM = pSSM;
2151 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
2152 return VINF_SUCCESS;
2153 }
2154
2155 Log(("SSMR3Open: Validation of '%s' failed, rc=%Rrc.\n", pszFilename, rc));
2156 RTFileClose(pSSM->File);
2157 }
2158 else
2159 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc));
2160 RTMemFree(pSSM);
2161 return rc;
2162
2163}
2164
2165
2166/**
2167 * Closes a saved state file opened by SSMR3Open().
2168 *
2169 * @returns VBox status code.
2170 *
2171 * @param pSSM The SSM handle returned by SSMR3Open().
2172 *
2173 * @thread Any, but the caller is responsible for serializing calls per handle.
2174 */
2175VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
2176{
2177 LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
2178
2179 /*
2180 * Validate input.
2181 */
2182 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
2183 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
2184 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
2185
2186 /*
2187 * Close the file and free the handle.
2188 */
2189 int rc = RTFileClose(pSSM->File);
2190 AssertRC(rc);
2191 RTMemFree(pSSM);
2192 return rc;
2193}
2194
2195
2196/**
2197 * Seeks to a specific data unit.
2198 *
2199 * After seeking it's possible to use the getters to on
2200 * that data unit.
2201 *
2202 * @returns VBox status code.
2203 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
2204 *
2205 * @param pSSM The SSM handle returned by SSMR3Open().
2206 * @param pszUnit The name of the data unit.
2207 * @param iInstance The instance number.
2208 * @param piVersion Where to store the version number. (Optional)
2209 *
2210 * @thread Any, but the caller is responsible for serializing calls per handle.
2211 */
2212VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
2213{
2214 LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
2215 pSSM, pszUnit, pszUnit, iInstance, piVersion));
2216
2217 /*
2218 * Validate input.
2219 */
2220 AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
2221 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
2222 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
2223 AssertMsgReturn(VALID_PTR(pszUnit), ("%p\n", pszUnit), VERR_INVALID_POINTER);
2224 AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
2225
2226 /*
2227 * Reset the state.
2228 */
2229 if (pSSM->pZipDecomp)
2230 {
2231 RTZipDecompDestroy(pSSM->pZipDecomp);
2232 pSSM->pZipDecomp = NULL;
2233 }
2234 pSSM->rc = VERR_SSM_UNIT_NOT_FOUND;
2235 pSSM->cbUnitLeft = 0;
2236 pSSM->offUnit = UINT64_MAX;
2237
2238 /*
2239 * Walk the data units until we find EOF or a match.
2240 */
2241 size_t cchUnit = strlen(pszUnit) + 1;
2242 int rc = VINF_SUCCESS;
2243 char *pszName = NULL;
2244 size_t cchName = 0;
2245 SSMFILEUNITHDR UnitHdr;
2246 for (RTFOFF off = pSSM->cbFileHdr; ; off += UnitHdr.cbUnit)
2247 {
2248 /*
2249 * Read the unit header and verify it.
2250 */
2251 rc = RTFileReadAt(pSSM->File, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDR, szName), NULL);
2252 AssertRC(rc);
2253 if (RT_SUCCESS(rc))
2254 {
2255 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
2256 {
2257 /*
2258 * Does it match thus far or should we just skip along?
2259 */
2260 if ( UnitHdr.u32Instance != iInstance
2261 && UnitHdr.cchName != cchUnit)
2262 continue;
2263
2264 /*
2265 * Read the name.
2266 * Adjust the name buffer first.
2267 */
2268 if (cchName < UnitHdr.cchName)
2269 {
2270 if (pszName)
2271 RTMemTmpFree(pszName);
2272 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
2273 pszName = (char *)RTMemTmpAlloc(cchName);
2274 }
2275 rc = VERR_NO_MEMORY;
2276 if (pszName)
2277 {
2278 rc = RTFileRead(pSSM->File, pszName, UnitHdr.cchName, NULL);
2279 AssertRC(rc);
2280 if (RT_SUCCESS(rc))
2281 {
2282 if (!pszName[UnitHdr.cchName - 1])
2283 {
2284 /*
2285 * Does the name match? If not continue with the next item.
2286 */
2287 if (memcmp(pszName, pszUnit, cchUnit))
2288 continue;
2289
2290 pSSM->rc = rc = VINF_SUCCESS;
2291 pSSM->cbUnitLeft = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDR, szName[UnitHdr.cchName]);
2292 pSSM->offUnit = 0;
2293 if (piVersion)
2294 *piVersion = UnitHdr.u32Version;
2295 }
2296 else
2297 {
2298 AssertMsgFailed((" Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
2299 rc = VERR_SSM_INTEGRITY;
2300 }
2301 }
2302 }
2303 }
2304 else
2305 {
2306 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
2307 rc = VERR_SSM_UNIT_NOT_FOUND;
2308 else
2309 {
2310 AssertMsgFailed(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
2311 off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
2312 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
2313 }
2314 }
2315 }
2316
2317 /* error or success, two continue statements cover the iterating */
2318 break;
2319 }
2320
2321 RTMemFree(pszName);
2322 return rc;
2323}
2324
2325
2326/**
2327 * Finishes a data unit.
2328 * All buffers and compressor instances are flushed and destroyed.
2329 *
2330 * @returns VBox status.
2331 * @param pSSM SSM operation handle.
2332 */
2333static int ssmR3WriteFinish(PSSMHANDLE pSSM)
2334{
2335 //Log2(("ssmR3WriteFinish: %#010llx start\n", RTFileTell(pSSM->File)));
2336 if (!pSSM->pZipComp)
2337 return VINF_SUCCESS;
2338
2339 int rc = RTZipCompFinish(pSSM->pZipComp);
2340 if (RT_SUCCESS(rc))
2341 {
2342 rc = RTZipCompDestroy(pSSM->pZipComp);
2343 if (RT_SUCCESS(rc))
2344 {
2345 pSSM->pZipComp = NULL;
2346 //Log2(("ssmR3WriteFinish: %#010llx done\n", RTFileTell(pSSM->File)));
2347 return VINF_SUCCESS;
2348 }
2349 }
2350 if (RT_SUCCESS(pSSM->rc))
2351 pSSM->rc = rc;
2352 Log2(("ssmR3WriteFinish: failure rc=%Rrc\n", rc));
2353 return rc;
2354}
2355
2356
2357/**
2358 * Writes something to the current data item in the saved state file.
2359 *
2360 * @returns VBox status.
2361 * @param pSSM SSM operation handle.
2362 * @param pvBuf The bits to write.
2363 * @param cbBuf The number of bytes to write.
2364 */
2365static int ssmR3Write(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
2366{
2367 Log2(("ssmR3Write: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
2368
2369 /*
2370 * Check that everything is fine.
2371 */
2372 if (RT_SUCCESS(pSSM->rc))
2373 {
2374 /*
2375 * First call starts the compression.
2376 */
2377 if (!pSSM->pZipComp)
2378 {
2379 //int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_ZLIB, RTZIPLEVEL_FAST);
2380 int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_LZF, RTZIPLEVEL_FAST);
2381 //int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmR3WriteOut, RTZIPTYPE_STORE, RTZIPLEVEL_FAST);
2382 if (RT_FAILURE(rc))
2383 return rc;
2384 }
2385
2386 /*
2387 * Write the data item in 128kb chunks for progress indicator reasons.
2388 */
2389 while (cbBuf > 0)
2390 {
2391 size_t cbChunk = RT_MIN(cbBuf, 128*1024);
2392 pSSM->rc = RTZipCompress(pSSM->pZipComp, pvBuf, cbChunk);
2393 if (RT_FAILURE(pSSM->rc))
2394 break;
2395 ssmR3Progress(pSSM, cbChunk);
2396 pSSM->offUnit += cbChunk;
2397 cbBuf -= cbChunk;
2398 pvBuf = (char *)pvBuf + cbChunk;
2399 }
2400 }
2401
2402 return pSSM->rc;
2403}
2404
2405
2406/**
2407 * Callback for flusing the output buffer of a compression stream.
2408 *
2409 * @returns VBox status.
2410 * @param pvSSM SSM operation handle.
2411 * @param pvBuf Compressed data.
2412 * @param cbBuf Size of the compressed data.
2413 */
2414static DECLCALLBACK(int) ssmR3WriteOut(void *pvSSM, const void *pvBuf, size_t cbBuf)
2415{
2416 //Log2(("ssmR3WriteOut: %#010llx cbBuf=%#x\n", RTFileTell(((PSSMHANDLE)pvSSM)->File), cbBuf));
2417 int rc = RTFileWrite(((PSSMHANDLE)pvSSM)->File, pvBuf, cbBuf, NULL);
2418 if (RT_SUCCESS(rc))
2419 return rc;
2420 Log(("ssmR3WriteOut: RTFileWrite(,,%d) -> %d\n", cbBuf, rc));
2421 return rc;
2422}
2423
2424
2425/**
2426 * Puts a structure.
2427 *
2428 * @returns VBox status code.
2429 * @param pSSM The saved state handle.
2430 * @param pvStruct The structure address.
2431 * @param paFields The array of structure fields descriptions.
2432 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
2433 */
2434VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
2435{
2436 /* begin marker. */
2437 int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
2438 if (RT_FAILURE(rc))
2439 return rc;
2440
2441 /* put the fields */
2442 for (PCSSMFIELD pCur = paFields;
2443 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
2444 pCur++)
2445 {
2446 rc = ssmR3Write(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
2447 if (RT_FAILURE(rc))
2448 return rc;
2449 }
2450
2451 /* end marker */
2452 return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
2453}
2454
2455
2456/**
2457 * Saves a boolean item to the current data unit.
2458 *
2459 * @returns VBox status.
2460 * @param pSSM SSM operation handle.
2461 * @param fBool Item to save.
2462 */
2463VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
2464{
2465 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2466 {
2467 uint8_t u8 = fBool; /* enforce 1 byte size */
2468 return ssmR3Write(pSSM, &u8, sizeof(u8));
2469 }
2470 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2471 return VERR_SSM_INVALID_STATE;
2472}
2473
2474
2475/**
2476 * Saves a 8-bit unsigned integer item to the current data unit.
2477 *
2478 * @returns VBox status.
2479 * @param pSSM SSM operation handle.
2480 * @param u8 Item to save.
2481 */
2482VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
2483{
2484 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2485 return ssmR3Write(pSSM, &u8, sizeof(u8));
2486 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2487 return VERR_SSM_INVALID_STATE;
2488}
2489
2490
2491/**
2492 * Saves a 8-bit signed integer item to the current data unit.
2493 *
2494 * @returns VBox status.
2495 * @param pSSM SSM operation handle.
2496 * @param i8 Item to save.
2497 */
2498VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
2499{
2500 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2501 return ssmR3Write(pSSM, &i8, sizeof(i8));
2502 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2503 return VERR_SSM_INVALID_STATE;
2504}
2505
2506
2507/**
2508 * Saves a 16-bit unsigned integer item to the current data unit.
2509 *
2510 * @returns VBox status.
2511 * @param pSSM SSM operation handle.
2512 * @param u16 Item to save.
2513 */
2514VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
2515{
2516 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2517 return ssmR3Write(pSSM, &u16, sizeof(u16));
2518 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2519 return VERR_SSM_INVALID_STATE;
2520}
2521
2522
2523/**
2524 * Saves a 16-bit signed integer item to the current data unit.
2525 *
2526 * @returns VBox status.
2527 * @param pSSM SSM operation handle.
2528 * @param i16 Item to save.
2529 */
2530VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
2531{
2532 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2533 return ssmR3Write(pSSM, &i16, sizeof(i16));
2534 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2535 return VERR_SSM_INVALID_STATE;
2536}
2537
2538
2539/**
2540 * Saves a 32-bit unsigned integer item to the current data unit.
2541 *
2542 * @returns VBox status.
2543 * @param pSSM SSM operation handle.
2544 * @param u32 Item to save.
2545 */
2546VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
2547{
2548 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2549 return ssmR3Write(pSSM, &u32, sizeof(u32));
2550 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2551 return VERR_SSM_INVALID_STATE;
2552}
2553
2554
2555/**
2556 * Saves a 32-bit signed integer item to the current data unit.
2557 *
2558 * @returns VBox status.
2559 * @param pSSM SSM operation handle.
2560 * @param i32 Item to save.
2561 */
2562VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
2563{
2564 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2565 return ssmR3Write(pSSM, &i32, sizeof(i32));
2566 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2567 return VERR_SSM_INVALID_STATE;
2568}
2569
2570
2571/**
2572 * Saves a 64-bit unsigned integer item to the current data unit.
2573 *
2574 * @returns VBox status.
2575 * @param pSSM SSM operation handle.
2576 * @param u64 Item to save.
2577 */
2578VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
2579{
2580 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2581 return ssmR3Write(pSSM, &u64, sizeof(u64));
2582 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2583 return VERR_SSM_INVALID_STATE;
2584}
2585
2586
2587/**
2588 * Saves a 64-bit signed integer item to the current data unit.
2589 *
2590 * @returns VBox status.
2591 * @param pSSM SSM operation handle.
2592 * @param i64 Item to save.
2593 */
2594VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
2595{
2596 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2597 return ssmR3Write(pSSM, &i64, sizeof(i64));
2598 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2599 return VERR_SSM_INVALID_STATE;
2600}
2601
2602
2603/**
2604 * Saves a 128-bit unsigned integer item to the current data unit.
2605 *
2606 * @returns VBox status.
2607 * @param pSSM SSM operation handle.
2608 * @param u128 Item to save.
2609 */
2610VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
2611{
2612 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2613 return ssmR3Write(pSSM, &u128, sizeof(u128));
2614 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2615 return VERR_SSM_INVALID_STATE;
2616}
2617
2618
2619/**
2620 * Saves a 128-bit signed integer item to the current data unit.
2621 *
2622 * @returns VBox status.
2623 * @param pSSM SSM operation handle.
2624 * @param i128 Item to save.
2625 */
2626VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
2627{
2628 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2629 return ssmR3Write(pSSM, &i128, sizeof(i128));
2630 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2631 return VERR_SSM_INVALID_STATE;
2632}
2633
2634
2635/**
2636 * Saves a VBox unsigned integer item to the current data unit.
2637 *
2638 * @returns VBox status.
2639 * @param pSSM SSM operation handle.
2640 * @param u Item to save.
2641 */
2642VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
2643{
2644 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2645 return ssmR3Write(pSSM, &u, sizeof(u));
2646 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2647 return VERR_SSM_INVALID_STATE;
2648}
2649
2650
2651/**
2652 * Saves a VBox signed integer item to the current data unit.
2653 *
2654 * @returns VBox status.
2655 * @param pSSM SSM operation handle.
2656 * @param i Item to save.
2657 */
2658VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
2659{
2660 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2661 return ssmR3Write(pSSM, &i, sizeof(i));
2662 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2663 return VERR_SSM_INVALID_STATE;
2664}
2665
2666
2667/**
2668 * Saves a GC natural unsigned integer item to the current data unit.
2669 *
2670 * @returns VBox status.
2671 * @param pSSM SSM operation handle.
2672 * @param u Item to save.
2673 *
2674 * @deprecated Silly type, don't use it.
2675 */
2676VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
2677{
2678 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2679 return ssmR3Write(pSSM, &u, sizeof(u));
2680 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2681 return VERR_SSM_INVALID_STATE;
2682}
2683
2684
2685/**
2686 * Saves a GC unsigned integer register item to the current data unit.
2687 *
2688 * @returns VBox status.
2689 * @param pSSM SSM operation handle.
2690 * @param u Item to save.
2691 */
2692VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
2693{
2694 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2695 return ssmR3Write(pSSM, &u, sizeof(u));
2696 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2697 return VERR_SSM_INVALID_STATE;
2698}
2699
2700
2701/**
2702 * Saves a 32 bits GC physical address item to the current data unit.
2703 *
2704 * @returns VBox status.
2705 * @param pSSM SSM operation handle.
2706 * @param GCPhys The item to save
2707 */
2708VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
2709{
2710 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2711 return ssmR3Write(pSSM, &GCPhys, sizeof(GCPhys));
2712 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2713 return VERR_SSM_INVALID_STATE;
2714}
2715
2716
2717/**
2718 * Saves a 64 bits GC physical address item to the current data unit.
2719 *
2720 * @returns VBox status.
2721 * @param pSSM SSM operation handle.
2722 * @param GCPhys The item to save
2723 */
2724VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
2725{
2726 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2727 return ssmR3Write(pSSM, &GCPhys, sizeof(GCPhys));
2728 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2729 return VERR_SSM_INVALID_STATE;
2730}
2731
2732
2733/**
2734 * Saves a GC physical address item to the current data unit.
2735 *
2736 * @returns VBox status.
2737 * @param pSSM SSM operation handle.
2738 * @param GCPhys The item to save
2739 */
2740VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
2741{
2742 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2743 return ssmR3Write(pSSM, &GCPhys, sizeof(GCPhys));
2744 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2745 return VERR_SSM_INVALID_STATE;
2746}
2747
2748
2749/**
2750 * Saves a GC virtual address item to the current data unit.
2751 *
2752 * @returns VBox status.
2753 * @param pSSM SSM operation handle.
2754 * @param GCPtr The item to save.
2755 */
2756VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
2757{
2758 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2759 return ssmR3Write(pSSM, &GCPtr, sizeof(GCPtr));
2760 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2761 return VERR_SSM_INVALID_STATE;
2762}
2763
2764
2765/**
2766 * Saves an RC virtual address item to the current data unit.
2767 *
2768 * @returns VBox status.
2769 * @param pSSM SSM operation handle.
2770 * @param RCPtr The item to save.
2771 */
2772VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
2773{
2774 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2775 return ssmR3Write(pSSM, &RCPtr, sizeof(RCPtr));
2776 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2777 return VERR_SSM_INVALID_STATE;
2778}
2779
2780
2781/**
2782 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
2783 *
2784 * @returns VBox status.
2785 * @param pSSM SSM operation handle.
2786 * @param GCPtr The item to save.
2787 */
2788VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
2789{
2790 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2791 return ssmR3Write(pSSM, &GCPtr, sizeof(GCPtr));
2792 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2793 return VERR_SSM_INVALID_STATE;
2794}
2795
2796
2797/**
2798 * Saves a I/O port address item to the current data unit.
2799 *
2800 * @returns VBox status.
2801 * @param pSSM SSM operation handle.
2802 * @param IOPort The item to save.
2803 */
2804VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
2805{
2806 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2807 return ssmR3Write(pSSM, &IOPort, sizeof(IOPort));
2808 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2809 return VERR_SSM_INVALID_STATE;
2810}
2811
2812
2813/**
2814 * Saves a selector item to the current data unit.
2815 *
2816 * @returns VBox status.
2817 * @param pSSM SSM operation handle.
2818 * @param Sel The item to save.
2819 */
2820VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
2821{
2822 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2823 return ssmR3Write(pSSM, &Sel, sizeof(Sel));
2824 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2825 return VERR_SSM_INVALID_STATE;
2826}
2827
2828
2829/**
2830 * Saves a memory item to the current data unit.
2831 *
2832 * @returns VBox status.
2833 * @param pSSM SSM operation handle.
2834 * @param pv Item to save.
2835 * @param cb Size of the item.
2836 */
2837VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
2838{
2839 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2840 return ssmR3Write(pSSM, pv, cb);
2841 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2842 return VERR_SSM_INVALID_STATE;
2843}
2844
2845
2846/**
2847 * Saves a zero terminated string item to the current data unit.
2848 *
2849 * @returns VBox status.
2850 * @param pSSM SSM operation handle.
2851 * @param psz Item to save.
2852 */
2853VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
2854{
2855 if (pSSM->enmOp == SSMSTATE_SAVE_EXEC)
2856 {
2857 size_t cch = strlen(psz);
2858 if (cch > 1024*1024)
2859 {
2860 AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
2861 return VERR_TOO_MUCH_DATA;
2862 }
2863 uint32_t u32 = (uint32_t)cch;
2864 int rc = ssmR3Write(pSSM, &u32, sizeof(u32));
2865 if (rc)
2866 return rc;
2867 return ssmR3Write(pSSM, psz, cch);
2868 }
2869 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
2870 return VERR_SSM_INVALID_STATE;
2871}
2872
2873
2874
2875
2876
2877/**
2878 * Closes the decompressor of a data unit.
2879 *
2880 * @param pSSM SSM operation handle.
2881 */
2882static void ssmR3ReadFinish(PSSMHANDLE pSSM)
2883{
2884 int rc = RTZipDecompDestroy(pSSM->pZipDecomp);
2885 AssertRC(rc);
2886 pSSM->pZipDecomp = NULL;
2887}
2888
2889
2890/**
2891 * Internal read worker.
2892 *
2893 * @param pSSM SSM operation handle.
2894 * @param pvBuf Where to store the read data.
2895 * @param cbBuf Number of bytes to read.
2896 */
2897static int ssmR3Read(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf)
2898{
2899 /*
2900 * Check that everything is fine.
2901 */
2902 if (RT_SUCCESS(pSSM->rc))
2903 {
2904 /*
2905 * Open the decompressor on the first read.
2906 */
2907 if (!pSSM->pZipDecomp)
2908 {
2909 pSSM->rc = RTZipDecompCreate(&pSSM->pZipDecomp, pSSM, ssmR3ReadIn);
2910 if (RT_FAILURE(pSSM->rc))
2911 return pSSM->rc;
2912 }
2913
2914 /*
2915 * Do the requested read.
2916 * Use 32kb chunks to work the progress indicator.
2917 */
2918 pSSM->rc = RTZipDecompress(pSSM->pZipDecomp, pvBuf, cbBuf, NULL);
2919 if (RT_SUCCESS(pSSM->rc))
2920 {
2921 Log2(("ssmR3Read: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
2922 pSSM->offUnit += cbBuf;
2923 }
2924 else
2925 AssertMsgFailed(("rc=%Rrc cbBuf=%#x\n", pSSM->rc, cbBuf));
2926 }
2927
2928 return pSSM->rc;
2929}
2930
2931
2932/**
2933 * Callback for reading compressed data into the input buffer of the
2934 * decompressor.
2935 *
2936 * @returns VBox status code.
2937 * @param pvSSM The SSM handle.
2938 * @param pvBuf Where to store the compressed data.
2939 * @param cbBuf Size of the buffer.
2940 * @param pcbRead Number of bytes actually stored in the buffer.
2941 */
2942static DECLCALLBACK(int) ssmR3ReadIn(void *pvSSM, void *pvBuf, size_t cbBuf, size_t *pcbRead)
2943{
2944 PSSMHANDLE pSSM = (PSSMHANDLE)pvSSM;
2945 size_t cbRead = cbBuf;
2946 if (pSSM->cbUnitLeft < cbBuf)
2947 cbRead = (size_t)pSSM->cbUnitLeft;
2948 if (cbRead)
2949 {
2950 //Log2(("ssmR3ReadIn: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->File), cbBuf, cbRead));
2951 int rc = RTFileRead(pSSM->File, pvBuf, cbRead, NULL);
2952 if (RT_SUCCESS(rc))
2953 {
2954 pSSM->cbUnitLeft -= cbRead;
2955 if (pcbRead)
2956 *pcbRead = cbRead;
2957 ssmR3Progress(pSSM, cbRead);
2958 return VINF_SUCCESS;
2959 }
2960 Log(("ssmR3ReadIn: RTFileRead(,,%d) -> %d\n", cbRead, rc));
2961 return rc;
2962 }
2963
2964 /** @todo weed out lazy saving */
2965 if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
2966 AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
2967 return VERR_SSM_LOADED_TOO_MUCH;
2968}
2969
2970
2971/**
2972 * Gets a structure.
2973 *
2974 * @returns VBox status code.
2975 * @param pSSM The saved state handle.
2976 * @param pvStruct The structure address.
2977 * @param paFields The array of structure fields descriptions.
2978 * The array must be terminated by a SSMFIELD_ENTRY_TERM().
2979 */
2980VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)
2981{
2982 /* begin marker. */
2983 uint32_t u32Magic;
2984 int rc = SSMR3GetU32(pSSM, &u32Magic);
2985 if (RT_FAILURE(rc))
2986 return rc;
2987 if (u32Magic != SSMR3STRUCT_BEGIN)
2988 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
2989
2990 /* put the fields */
2991 for (PCSSMFIELD pCur = paFields;
2992 pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
2993 pCur++)
2994 {
2995 rc = ssmR3Read(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
2996 if (RT_FAILURE(rc))
2997 return rc;
2998 }
2999
3000 /* end marker */
3001 rc = SSMR3GetU32(pSSM, &u32Magic);
3002 if (RT_FAILURE(rc))
3003 return rc;
3004 if (u32Magic != SSMR3STRUCT_END)
3005 AssertMsgFailedReturn(("u32Magic=%#RX32\n", u32Magic), VERR_SSM_STRUCTURE_MAGIC);
3006 return rc;
3007}
3008
3009
3010/**
3011 * Loads a boolean item from the current data unit.
3012 *
3013 * @returns VBox status.
3014 * @param pSSM SSM operation handle.
3015 * @param pfBool Where to store the item.
3016 */
3017VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
3018{
3019 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3020 {
3021 uint8_t u8; /* see SSMR3PutBool */
3022 int rc = ssmR3Read(pSSM, &u8, sizeof(u8));
3023 if (RT_SUCCESS(rc))
3024 {
3025 Assert(u8 <= 1);
3026 *pfBool = !!u8;
3027 }
3028 return rc;
3029 }
3030 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3031 return VERR_SSM_INVALID_STATE;
3032}
3033
3034
3035/**
3036 * Loads a 8-bit unsigned integer item from the current data unit.
3037 *
3038 * @returns VBox status.
3039 * @param pSSM SSM operation handle.
3040 * @param pu8 Where to store the item.
3041 */
3042VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
3043{
3044 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3045 return ssmR3Read(pSSM, pu8, sizeof(*pu8));
3046 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3047 return VERR_SSM_INVALID_STATE;
3048}
3049
3050
3051/**
3052 * Loads a 8-bit signed integer item from the current data unit.
3053 *
3054 * @returns VBox status.
3055 * @param pSSM SSM operation handle.
3056 * @param pi8 Where to store the item.
3057 */
3058VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
3059{
3060 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3061 return ssmR3Read(pSSM, pi8, sizeof(*pi8));
3062 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3063 return VERR_SSM_INVALID_STATE;
3064}
3065
3066
3067/**
3068 * Loads a 16-bit unsigned integer item from the current data unit.
3069 *
3070 * @returns VBox status.
3071 * @param pSSM SSM operation handle.
3072 * @param pu16 Where to store the item.
3073 */
3074VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
3075{
3076 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3077 return ssmR3Read(pSSM, pu16, sizeof(*pu16));
3078 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3079 return VERR_SSM_INVALID_STATE;
3080}
3081
3082
3083/**
3084 * Loads a 16-bit signed integer item from the current data unit.
3085 *
3086 * @returns VBox status.
3087 * @param pSSM SSM operation handle.
3088 * @param pi16 Where to store the item.
3089 */
3090VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
3091{
3092 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3093 return ssmR3Read(pSSM, pi16, sizeof(*pi16));
3094 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3095 return VERR_SSM_INVALID_STATE;
3096}
3097
3098
3099/**
3100 * Loads a 32-bit unsigned integer item from the current data unit.
3101 *
3102 * @returns VBox status.
3103 * @param pSSM SSM operation handle.
3104 * @param pu32 Where to store the item.
3105 */
3106VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
3107{
3108 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3109 return ssmR3Read(pSSM, pu32, sizeof(*pu32));
3110 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3111 return VERR_SSM_INVALID_STATE;
3112}
3113
3114
3115/**
3116 * Loads a 32-bit signed integer item from the current data unit.
3117 *
3118 * @returns VBox status.
3119 * @param pSSM SSM operation handle.
3120 * @param pi32 Where to store the item.
3121 */
3122VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
3123{
3124 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3125 return ssmR3Read(pSSM, pi32, sizeof(*pi32));
3126 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3127 return VERR_SSM_INVALID_STATE;
3128}
3129
3130
3131/**
3132 * Loads a 64-bit unsigned integer item from the current data unit.
3133 *
3134 * @returns VBox status.
3135 * @param pSSM SSM operation handle.
3136 * @param pu64 Where to store the item.
3137 */
3138VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
3139{
3140 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3141 return ssmR3Read(pSSM, pu64, sizeof(*pu64));
3142 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3143 return VERR_SSM_INVALID_STATE;
3144}
3145
3146
3147/**
3148 * Loads a 64-bit signed integer item from the current data unit.
3149 *
3150 * @returns VBox status.
3151 * @param pSSM SSM operation handle.
3152 * @param pi64 Where to store the item.
3153 */
3154VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
3155{
3156 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3157 return ssmR3Read(pSSM, pi64, sizeof(*pi64));
3158 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3159 return VERR_SSM_INVALID_STATE;
3160}
3161
3162
3163/**
3164 * Loads a 128-bit unsigned integer item from the current data unit.
3165 *
3166 * @returns VBox status.
3167 * @param pSSM SSM operation handle.
3168 * @param pu128 Where to store the item.
3169 */
3170VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
3171{
3172 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3173 return ssmR3Read(pSSM, pu128, sizeof(*pu128));
3174 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3175 return VERR_SSM_INVALID_STATE;
3176}
3177
3178
3179/**
3180 * Loads a 128-bit signed integer item from the current data unit.
3181 *
3182 * @returns VBox status.
3183 * @param pSSM SSM operation handle.
3184 * @param pi128 Where to store the item.
3185 */
3186VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
3187{
3188 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3189 return ssmR3Read(pSSM, pi128, sizeof(*pi128));
3190 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3191 return VERR_SSM_INVALID_STATE;
3192}
3193
3194
3195/**
3196 * Loads a VBox unsigned integer item from the current data unit.
3197 *
3198 * @returns VBox status.
3199 * @param pSSM SSM operation handle.
3200 * @param pu Where to store the integer.
3201 */
3202VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
3203{
3204 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3205 return ssmR3Read(pSSM, pu, sizeof(*pu));
3206 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3207 return VERR_SSM_INVALID_STATE;
3208}
3209
3210
3211/**
3212 * Loads a VBox signed integer item from the current data unit.
3213 *
3214 * @returns VBox status.
3215 * @param pSSM SSM operation handle.
3216 * @param pi Where to store the integer.
3217 */
3218VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
3219{
3220 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3221 return ssmR3Read(pSSM, pi, sizeof(*pi));
3222 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3223 return VERR_SSM_INVALID_STATE;
3224}
3225
3226
3227/**
3228 * Loads a GC natural unsigned integer item from the current data unit.
3229 *
3230 * @returns VBox status.
3231 * @param pSSM SSM operation handle.
3232 * @param pu Where to store the integer.
3233 *
3234 * @deprecated Silly type with an incorrect size, don't use it.
3235 */
3236VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu)
3237{
3238 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
3239 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
3240}
3241
3242
3243/**
3244 * Loads a GC unsigned integer register item from the current data unit.
3245 *
3246 * @returns VBox status.
3247 * @param pSSM SSM operation handle.
3248 * @param pu Where to store the integer.
3249 */
3250VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu)
3251{
3252 AssertCompile(sizeof(RTGCPTR) == sizeof(*pu));
3253 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pu);
3254}
3255
3256
3257/**
3258 * Loads a 32 bits GC physical address item from the current data unit.
3259 *
3260 * @returns VBox status.
3261 * @param pSSM SSM operation handle.
3262 * @param pGCPhys Where to store the GC physical address.
3263 */
3264VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
3265{
3266 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3267 return ssmR3Read(pSSM, pGCPhys, sizeof(*pGCPhys));
3268 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3269 return VERR_SSM_INVALID_STATE;
3270}
3271
3272
3273/**
3274 * Loads a 64 bits GC physical address item from the current data unit.
3275 *
3276 * @returns VBox status.
3277 * @param pSSM SSM operation handle.
3278 * @param pGCPhys Where to store the GC physical address.
3279 */
3280VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
3281{
3282 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3283 return ssmR3Read(pSSM, pGCPhys, sizeof(*pGCPhys));
3284 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3285 return VERR_SSM_INVALID_STATE;
3286}
3287
3288
3289/**
3290 * Loads a GC physical address item from the current data unit.
3291 *
3292 * @returns VBox status.
3293 * @param pSSM SSM operation handle.
3294 * @param pGCPhys Where to store the GC physical address.
3295 */
3296VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
3297{
3298 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3299 {
3300 if (sizeof(*pGCPhys) != pSSM->cbGCPhys)
3301 {
3302 Assert(sizeof(*pGCPhys) == sizeof(uint64_t) || sizeof(*pGCPhys) == sizeof(uint32_t));
3303 Assert(pSSM->cbGCPhys == sizeof(uint64_t) || pSSM->cbGCPhys == sizeof(uint32_t));
3304 if (pSSM->cbGCPhys == sizeof(uint64_t))
3305 {
3306 /* 64-bit saved, 32-bit load: try truncate it. */
3307 uint64_t u64;
3308 int rc = ssmR3Read(pSSM, &u64, pSSM->cbGCPhys);
3309 if (RT_FAILURE(rc))
3310 return rc;
3311 if (u64 >= _4G)
3312 return VERR_SSM_GCPHYS_OVERFLOW;
3313 *pGCPhys = (RTGCPHYS)u64;
3314 return rc;
3315 }
3316 /* 32-bit saved, 64-bit load: clear the high part. */
3317 *pGCPhys = 0;
3318 }
3319 return ssmR3Read(pSSM, pGCPhys, pSSM->cbGCPhys);
3320 }
3321 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3322 return VERR_SSM_INVALID_STATE;
3323}
3324
3325
3326/**
3327 * Loads a GC virtual address item from the current data unit.
3328 *
3329 * Only applies to in the 1.1 format:
3330 * - SSMR3GetGCPtr
3331 * - SSMR3GetGCUIntPtr
3332 * - SSMR3GetGCUInt
3333 * - SSMR3GetGCUIntReg
3334 *
3335 * Put functions are not affected.
3336 *
3337 * @returns VBox status.
3338 * @param pSSM SSM operation handle.
3339 * @param cbGCPtr Size of RTGCPTR
3340 *
3341 * @remarks This interface only works with saved state version 1.1, if the
3342 * format isn't 1.1 the call will be ignored.
3343 */
3344VMMR3DECL(int) SSMR3SetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr)
3345{
3346 Assert(cbGCPtr == sizeof(RTGCPTR32) || cbGCPtr == sizeof(RTGCPTR64));
3347 if (!pSSM->fFixedGCPtrSize)
3348 {
3349 Log(("SSMR3SetGCPtrSize: %d -> %d bytes\n", pSSM->cbGCPtr, cbGCPtr));
3350 pSSM->cbGCPtr = cbGCPtr;
3351 pSSM->fFixedGCPtrSize = true;
3352 }
3353 else if ( pSSM->cbGCPtr != cbGCPtr
3354 && pSSM->cbFileHdr == sizeof(SSMFILEHDRV11))
3355 AssertMsgFailed(("SSMR3SetGCPtrSize: already fixed at %d bytes; requested %d bytes\n", pSSM->cbGCPtr, cbGCPtr));
3356
3357 return VINF_SUCCESS;
3358}
3359
3360
3361/**
3362 * Loads a GC virtual address item from the current data unit.
3363 *
3364 * @returns VBox status.
3365 * @param pSSM SSM operation handle.
3366 * @param pGCPtr Where to store the GC virtual address.
3367 */
3368VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
3369{
3370 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3371 {
3372 if (sizeof(*pGCPtr) != pSSM->cbGCPtr)
3373 {
3374 Assert(sizeof(*pGCPtr) == sizeof(uint64_t) || sizeof(*pGCPtr) == sizeof(uint32_t));
3375 Assert(pSSM->cbGCPtr == sizeof(uint64_t) || pSSM->cbGCPtr == sizeof(uint32_t));
3376 if (pSSM->cbGCPtr == sizeof(uint64_t))
3377 {
3378 /* 64-bit saved, 32-bit load: try truncate it. */
3379 uint64_t u64;
3380 int rc = ssmR3Read(pSSM, &u64, pSSM->cbGCPhys);
3381 if (RT_FAILURE(rc))
3382 return rc;
3383 if (u64 >= _4G)
3384 return VERR_SSM_GCPTR_OVERFLOW;
3385 *pGCPtr = (RTGCPTR)u64;
3386 return rc;
3387 }
3388 /* 32-bit saved, 64-bit load: clear the high part. */
3389 *pGCPtr = 0;
3390 }
3391 return ssmR3Read(pSSM, pGCPtr, pSSM->cbGCPtr);
3392 }
3393 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3394 return VERR_SSM_INVALID_STATE;
3395}
3396
3397
3398/**
3399 * Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
3400 *
3401 * @returns VBox status.
3402 * @param pSSM SSM operation handle.
3403 * @param pGCPtr Where to store the GC virtual address.
3404 */
3405VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)
3406{
3407 AssertCompile(sizeof(RTGCPTR) == sizeof(*pGCPtr));
3408 return SSMR3GetGCPtr(pSSM, (PRTGCPTR)pGCPtr);
3409}
3410
3411
3412/**
3413 * Loads an RC virtual address item from the current data unit.
3414 *
3415 * @returns VBox status.
3416 * @param pSSM SSM operation handle.
3417 * @param pRCPtr Where to store the RC virtual address.
3418 */
3419VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
3420{
3421 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3422 return ssmR3Read(pSSM, pRCPtr, sizeof(*pRCPtr));
3423
3424 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3425 return VERR_SSM_INVALID_STATE;
3426}
3427
3428
3429/**
3430 * Loads a I/O port address item from the current data unit.
3431 *
3432 * @returns VBox status.
3433 * @param pSSM SSM operation handle.
3434 * @param pIOPort Where to store the I/O port address.
3435 */
3436VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
3437{
3438 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3439 return ssmR3Read(pSSM, pIOPort, sizeof(*pIOPort));
3440 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3441 return VERR_SSM_INVALID_STATE;
3442}
3443
3444
3445/**
3446 * Loads a selector item from the current data unit.
3447 *
3448 * @returns VBox status.
3449 * @param pSSM SSM operation handle.
3450 * @param pSel Where to store the selector.
3451 */
3452VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
3453{
3454 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3455 return ssmR3Read(pSSM, pSel, sizeof(*pSel));
3456 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3457 return VERR_SSM_INVALID_STATE;
3458}
3459
3460
3461/**
3462 * Loads a memory item from the current data unit.
3463 *
3464 * @returns VBox status.
3465 * @param pSSM SSM operation handle.
3466 * @param pv Where to store the item.
3467 * @param cb Size of the item.
3468 */
3469VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
3470{
3471 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3472 return ssmR3Read(pSSM, pv, cb);
3473 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3474 return VERR_SSM_INVALID_STATE;
3475}
3476
3477
3478/**
3479 * Loads a string item from the current data unit.
3480 *
3481 * @returns VBox status.
3482 * @param pSSM SSM operation handle.
3483 * @param psz Where to store the item.
3484 * @param cbMax Max size of the item (including '\\0').
3485 */
3486VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax)
3487{
3488 return SSMR3GetStrZEx(pSSM, psz, cbMax, NULL);
3489}
3490
3491
3492/**
3493 * Loads a string item from the current data unit.
3494 *
3495 * @returns VBox status.
3496 * @param pSSM SSM operation handle.
3497 * @param psz Where to store the item.
3498 * @param cbMax Max size of the item (including '\\0').
3499 * @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
3500 */
3501VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
3502{
3503 if (pSSM->enmOp == SSMSTATE_LOAD_EXEC || pSSM->enmOp == SSMSTATE_OPEN_READ)
3504 {
3505 /* read size prefix. */
3506 uint32_t u32;
3507 int rc = SSMR3GetU32(pSSM, &u32);
3508 if (RT_SUCCESS(rc))
3509 {
3510 if (pcbStr)
3511 *pcbStr = u32;
3512 if (u32 < cbMax)
3513 {
3514 /* terminate and read string content. */
3515 psz[u32] = '\0';
3516 return ssmR3Read(pSSM, psz, u32);
3517 }
3518 return VERR_TOO_MUCH_DATA;
3519 }
3520 return rc;
3521 }
3522 AssertMsgFailed(("Invalid state %d\n", pSSM->enmOp));
3523 return VERR_SSM_INVALID_STATE;
3524}
3525
3526
3527/**
3528 * Skips a number of bytes in the current data unit.
3529 *
3530 * @returns VBox status code.
3531 * @param pSSM The SSM handle.
3532 * @param cb The number of bytes to skip.
3533 */
3534VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
3535{
3536 AssertMsgReturn( pSSM->enmOp == SSMSTATE_LOAD_EXEC
3537 || pSSM->enmOp == SSMSTATE_OPEN_READ,
3538 ("Invalid state %d\n", pSSM->enmOp),
3539 VERR_SSM_INVALID_STATE);
3540 while (cb > 0)
3541 {
3542 uint8_t abBuf[8192];
3543 size_t cbCur = RT_MIN(sizeof(abBuf), cb);
3544 cb -= cbCur;
3545 int rc = ssmR3Read(pSSM, abBuf, cbCur);
3546 if (RT_FAILURE(rc))
3547 return rc;
3548 }
3549
3550 return VINF_SUCCESS;
3551}
3552
3553
3554/**
3555 * Query what the VBox status code of the operation is.
3556 *
3557 * This can be used for putting and getting a batch of values
3558 * without bother checking the result till all the calls have
3559 * been made.
3560 *
3561 * @returns SSMAFTER enum value.
3562 * @param pSSM SSM operation handle.
3563 */
3564VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM)
3565{
3566 return pSSM->rc;
3567}
3568
3569
3570/**
3571 * Fail the load operation.
3572 *
3573 * This is mainly intended for sub item loaders (like timers) which
3574 * return code isn't necessarily heeded by the caller but is important
3575 * to SSM.
3576 *
3577 * @returns SSMAFTER enum value.
3578 * @param pSSM SSM operation handle.
3579 * @param iStatus Failure status code. This MUST be a VERR_*.
3580 */
3581VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus)
3582{
3583 if (RT_FAILURE(iStatus))
3584 {
3585 if (RT_SUCCESS(pSSM->rc))
3586 pSSM->rc = iStatus;
3587 return pSSM->rc = iStatus;
3588 }
3589 AssertMsgFailed(("iStatus=%d %Rrc\n", iStatus, iStatus));
3590 return VERR_INVALID_PARAMETER;
3591}
3592
3593
3594/**
3595 * Get what to do after this operation.
3596 *
3597 * @returns SSMAFTER enum value.
3598 * @param pSSM SSM operation handle.
3599 */
3600VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM)
3601{
3602 return pSSM->enmAfter;
3603}
3604
3605
3606/**
3607 * Get the current unit byte offset (uncompressed).
3608 *
3609 * @returns The offset. UINT64_MAX if called at a wrong time.
3610 * @param pSSM SSM operation handle.
3611 */
3612VMMR3DECL(uint64_t) SSMR3HandleGetUnitOffset(PSSMHANDLE pSSM)
3613{
3614 return pSSM->offUnit;
3615}
3616
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