VirtualBox

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

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

VMM/doxygen: More links.

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