VirtualBox

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

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

VMM/SSM: fix logging bug

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