VirtualBox

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

Last change on this file since 1714 was 990, checked in by vboxsync, 18 years ago

spaces

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