VirtualBox

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

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

SSM,PCI: We must restore the PCI configuration registers before PGM so that the MMIO mappings are in sync. Should fix #3903 and #1587.

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