VirtualBox

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

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

The 64-bit MSC warning hunt stops for today.

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