VirtualBox

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

Last change on this file since 768 was 23, checked in by vboxsync, 18 years ago

string.h & stdio.h + header cleanups.

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