VirtualBox

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

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

Added SSMR3DeregisterExternal

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