VirtualBox

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

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

More assertions

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