VirtualBox

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

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

Deal with GCPtr differences between 1.6 & 2.0 saved states.

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