VirtualBox

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

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

SSM, CPUM: Moved the GCPtr/GCPhys sizes into the file header instead of out sourcing it to CPUM, bumped header version (warning: not forward compatible). Assumes 32-bit RTGCPTR on 32-bit hosts using the old header, this will conflict with saved states from the last few days because of 64-bit guest on 32-bit hosts changes but there is no way around that. (64-bit hosts are not affected by this latter issue as they've been using 64-bit guest pointers since 2.0.)

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