summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/testcase/tstSSM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/testcase/tstSSM.cpp')
-rw-r--r--src/VBox/VMM/testcase/tstSSM.cpp935
1 files changed, 935 insertions, 0 deletions
diff --git a/src/VBox/VMM/testcase/tstSSM.cpp b/src/VBox/VMM/testcase/tstSSM.cpp
new file mode 100644
index 00000000..6f157aaf
--- /dev/null
+++ b/src/VBox/VMM/testcase/tstSSM.cpp
@@ -0,0 +1,935 @@
+/* $Id: tstSSM.cpp $ */
+/** @file
+ * Saved State Manager Testcase.
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/vmm/ssm.h>
+#include "VMInternal.h" /* createFakeVM */
+#include <VBox/vmm/vm.h>
+#include <VBox/vmm/uvm.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/stam.h>
+
+#include <VBox/log.h>
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <iprt/assert.h>
+#include <iprt/file.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+#include <iprt/path.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define TSTSSM_BIG_CONFIG 1
+
+#ifdef TSTSSM_BIG_CONFIG
+# define TSTSSM_ITEM_SIZE (512*_1M)
+#else
+# define TSTSSM_ITEM_SIZE (5*_1M)
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+const uint8_t gabPage[PAGE_SIZE] = {0};
+const char gachMem1[] = "sdfg\1asdfa\177hjkl;sdfghjkl;dfghjkl;dfghjkl;\0\0asdf;kjasdf;lkjasd;flkjasd;lfkjasd\0;lfk";
+#ifdef TSTSSM_BIG_CONFIG
+uint8_t gabBigMem[_1M];
+#else
+uint8_t gabBigMem[8*_1M];
+#endif
+
+
+/** initializes gabBigMem with some non zero stuff. */
+void initBigMem(void)
+{
+#if 0
+ uint32_t *puch = (uint32_t *)&gabBigMem[0];
+ uint32_t *puchEnd = (uint32_t *)&gabBigMem[sizeof(gabBigMem)];
+ uint32_t u32 = 0xdeadbeef;
+ for (; puch < puchEnd; puch++)
+ {
+ *puch = u32;
+ u32 += 19;
+ u32 = (u32 << 1) | (u32 >> 31);
+ }
+#else
+ uint8_t *pb = &gabBigMem[0];
+ uint8_t *pbEnd = &gabBigMem[sizeof(gabBigMem)];
+ for (; pb < pbEnd; pb += 16)
+ {
+ char szTmp[17];
+ RTStrPrintf(szTmp, sizeof(szTmp), "aaaa%08Xzzzz", (uint32_t)(uintptr_t)pb);
+ memcpy(pb, szTmp, 16);
+ }
+
+ /* add some zero pages */
+ memset(&gabBigMem[sizeof(gabBigMem) / 4], 0, PAGE_SIZE * 4);
+ memset(&gabBigMem[sizeof(gabBigMem) / 4 * 3], 0, PAGE_SIZE * 4);
+#endif
+}
+
+/**
+ * Execute state save operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ */
+DECLCALLBACK(int) Item01Save(PVM pVM, PSSMHANDLE pSSM)
+{
+ uint64_t u64Start = RTTimeNanoTS();
+ NOREF(pVM);
+
+ /*
+ * Test writing some memory block.
+ */
+ int rc = SSMR3PutMem(pSSM, gachMem1, sizeof(gachMem1));
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01: #1 - SSMR3PutMem -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Test writing a zeroterminated string.
+ */
+ rc = SSMR3PutStrZ(pSSM, "String");
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01: #1 - SSMR3PutMem -> %Rrc\n", rc);
+ return rc;
+ }
+
+
+ /*
+ * Test the individual integer put functions to see that they all work.
+ * (Testcases are also known as "The Land of The Ugly Code"...)
+ */
+#define ITEM(suff,bits, val) \
+ rc = SSMR3Put##suff(pSSM, val); \
+ if (RT_FAILURE(rc)) \
+ { \
+ RTPrintf("Item01: #" #suff " - SSMR3Put" #suff "(," #val ") -> %Rrc\n", rc); \
+ return rc; \
+ }
+ /* copy & past with the load one! */
+ ITEM(U8, uint8_t, 0xff);
+ ITEM(U8, uint8_t, 0x0);
+ ITEM(U8, uint8_t, 1);
+ ITEM(U8, uint8_t, 42);
+ ITEM(U8, uint8_t, 230);
+ ITEM(S8, int8_t, -128);
+ ITEM(S8, int8_t, 127);
+ ITEM(S8, int8_t, 12);
+ ITEM(S8, int8_t, -76);
+ ITEM(U16, uint16_t, 0xffff);
+ ITEM(U16, uint16_t, 0x0);
+ ITEM(S16, int16_t, 32767);
+ ITEM(S16, int16_t, -32768);
+ ITEM(U32, uint32_t, 4294967295U);
+ ITEM(U32, uint32_t, 0);
+ ITEM(U32, uint32_t, 42);
+ ITEM(U32, uint32_t, 2342342344U);
+ ITEM(S32, int32_t, -2147483647-1);
+ ITEM(S32, int32_t, 2147483647);
+ ITEM(S32, int32_t, 42);
+ ITEM(S32, int32_t, 568459834);
+ ITEM(S32, int32_t, -58758999);
+ ITEM(U64, uint64_t, 18446744073709551615ULL);
+ ITEM(U64, uint64_t, 0);
+ ITEM(U64, uint64_t, 42);
+ ITEM(U64, uint64_t, 593023944758394234ULL);
+ ITEM(S64, int64_t, 9223372036854775807LL);
+ ITEM(S64, int64_t, -9223372036854775807LL - 1);
+ ITEM(S64, int64_t, 42);
+ ITEM(S64, int64_t, 21398723459873LL);
+ ITEM(S64, int64_t, -5848594593453453245LL);
+#undef ITEM
+
+ uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Saved 1st item in %'RI64 ns\n", u64Elapsed);
+ return 0;
+}
+
+/**
+ * Prepare state load operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ * @param uVersion The data layout version.
+ * @param uPass The data pass.
+ */
+DECLCALLBACK(int) Item01Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+ NOREF(pVM); NOREF(uPass);
+ if (uVersion != 0)
+ {
+ RTPrintf("Item01: uVersion=%#x, expected 0\n", uVersion);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the memory block.
+ */
+ char achTmp[sizeof(gachMem1)];
+ int rc = SSMR3GetMem(pSSM, achTmp, sizeof(gachMem1));
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01: #1 - SSMR3GetMem -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Load the string.
+ */
+ rc = SSMR3GetStrZ(pSSM, achTmp, sizeof(achTmp));
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01: #2 - SSMR3GetStrZ -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Test the individual integer put functions to see that they all work.
+ * (Testcases are also known as "The Land of The Ugly Code"...)
+ */
+#define ITEM(suff, type, val) \
+ do { \
+ type var = {0}; \
+ rc = SSMR3Get##suff(pSSM, &var); \
+ if (RT_FAILURE(rc)) \
+ { \
+ RTPrintf("Item01: #" #suff " - SSMR3Get" #suff "(," #val ") -> %Rrc\n", rc); \
+ return rc; \
+ } \
+ if (var != val) \
+ { \
+ RTPrintf("Item01: #" #suff " - SSMR3Get" #suff "(," #val ") -> %d returned wrong value!\n", rc); \
+ return VERR_GENERAL_FAILURE; \
+ } \
+ } while (0)
+ /* copy & past with the load one! */
+ ITEM(U8, uint8_t, 0xff);
+ ITEM(U8, uint8_t, 0x0);
+ ITEM(U8, uint8_t, 1);
+ ITEM(U8, uint8_t, 42);
+ ITEM(U8, uint8_t, 230);
+ ITEM(S8, int8_t, -128);
+ ITEM(S8, int8_t, 127);
+ ITEM(S8, int8_t, 12);
+ ITEM(S8, int8_t, -76);
+ ITEM(U16, uint16_t, 0xffff);
+ ITEM(U16, uint16_t, 0x0);
+ ITEM(S16, int16_t, 32767);
+ ITEM(S16, int16_t, -32768);
+ ITEM(U32, uint32_t, 4294967295U);
+ ITEM(U32, uint32_t, 0);
+ ITEM(U32, uint32_t, 42);
+ ITEM(U32, uint32_t, 2342342344U);
+ ITEM(S32, int32_t, -2147483647-1);
+ ITEM(S32, int32_t, 2147483647);
+ ITEM(S32, int32_t, 42);
+ ITEM(S32, int32_t, 568459834);
+ ITEM(S32, int32_t, -58758999);
+ ITEM(U64, uint64_t, 18446744073709551615ULL);
+ ITEM(U64, uint64_t, 0);
+ ITEM(U64, uint64_t, 42);
+ ITEM(U64, uint64_t, 593023944758394234ULL);
+ ITEM(S64, int64_t, 9223372036854775807LL);
+ ITEM(S64, int64_t, -9223372036854775807LL - 1);
+ ITEM(S64, int64_t, 42);
+ ITEM(S64, int64_t, 21398723459873LL);
+ ITEM(S64, int64_t, -5848594593453453245LL);
+#undef ITEM
+
+ return 0;
+}
+
+
+/**
+ * Execute state save operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ */
+DECLCALLBACK(int) Item02Save(PVM pVM, PSSMHANDLE pSSM)
+{
+ NOREF(pVM);
+ uint64_t u64Start = RTTimeNanoTS();
+
+ /*
+ * Put the size.
+ */
+ uint32_t cb = sizeof(gabBigMem);
+ int rc = SSMR3PutU32(pSSM, cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: PutU32 -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Put 8MB of memory to the file in 3 chunks.
+ */
+ uint8_t *pbMem = &gabBigMem[0];
+ uint32_t cbChunk = cb / 47;
+ rc = SSMR3PutMem(pSSM, pbMem, cbChunk);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: PutMem(,%p,%#x) -> %Rrc\n", pbMem, cbChunk, rc);
+ return rc;
+ }
+ cb -= cbChunk;
+ pbMem += cbChunk;
+
+ /* next piece. */
+ cbChunk *= 19;
+ rc = SSMR3PutMem(pSSM, pbMem, cbChunk);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: PutMem(,%p,%#x) -> %Rrc\n", pbMem, cbChunk, rc);
+ return rc;
+ }
+ cb -= cbChunk;
+ pbMem += cbChunk;
+
+ /* last piece. */
+ cbChunk = cb;
+ rc = SSMR3PutMem(pSSM, pbMem, cbChunk);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: PutMem(,%p,%#x) -> %Rrc\n", pbMem, cbChunk, rc);
+ return rc;
+ }
+
+ uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Saved 2nd item in %'RI64 ns\n", u64Elapsed);
+ return 0;
+}
+
+/**
+ * Prepare state load operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ * @param uVersion The data layout version.
+ * @param uPass The data pass.
+ */
+DECLCALLBACK(int) Item02Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+ NOREF(pVM); NOREF(uPass);
+ if (uVersion != 0)
+ {
+ RTPrintf("Item02: uVersion=%#x, expected 0\n", uVersion);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the size.
+ */
+ uint32_t cb;
+ int rc = SSMR3GetU32(pSSM, &cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: SSMR3GetU32 -> %Rrc\n", rc);
+ return rc;
+ }
+ if (cb != sizeof(gabBigMem))
+ {
+ RTPrintf("Item02: loaded size doesn't match the real thing. %#x != %#x\n", cb, sizeof(gabBigMem));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the memory chunk by chunk.
+ */
+ uint8_t *pbMem = &gabBigMem[0];
+ char achTmp[16383];
+ uint32_t cbChunk = sizeof(achTmp);
+ while (cb > 0)
+ {
+ cbChunk -= 7;
+ if (cbChunk < 64)
+ cbChunk = sizeof(achTmp) - (cbChunk % 47);
+ if (cbChunk > cb)
+ cbChunk = cb;
+ rc = SSMR3GetMem(pSSM, &achTmp[0], cbChunk);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02: SSMR3GetMem(,,%#x) -> %d offset %#x\n", cbChunk, rc, pbMem - &gabBigMem[0]);
+ return rc;
+ }
+ if (memcmp(achTmp, pbMem, cbChunk))
+ {
+ RTPrintf("Item02: compare failed. mem offset=%#x cbChunk=%#x\n", pbMem - &gabBigMem[0], cbChunk);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /* next */
+ pbMem += cbChunk;
+ cb -= cbChunk;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Execute state save operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ */
+DECLCALLBACK(int) Item03Save(PVM pVM, PSSMHANDLE pSSM)
+{
+ NOREF(pVM);
+ uint64_t u64Start = RTTimeNanoTS();
+
+ /*
+ * Put the size.
+ */
+ uint32_t cb = TSTSSM_ITEM_SIZE;
+ int rc = SSMR3PutU32(pSSM, cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item03: PutU32 -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Put 512 MB page by page.
+ */
+ const uint8_t *pu8Org = &gabBigMem[0];
+ while (cb > 0)
+ {
+ rc = SSMR3PutMem(pSSM, pu8Org, PAGE_SIZE);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item03: PutMem(,%p,%#x) -> %Rrc\n", pu8Org, PAGE_SIZE, rc);
+ return rc;
+ }
+
+ /* next */
+ cb -= PAGE_SIZE;
+ pu8Org += PAGE_SIZE;
+ if (pu8Org >= &gabBigMem[sizeof(gabBigMem)])
+ pu8Org = &gabBigMem[0];
+ }
+
+ uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Saved 3rd item in %'RI64 ns\n", u64Elapsed);
+ return 0;
+}
+
+/**
+ * Prepare state load operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ * @param uVersion The data layout version.
+ * @param uPass The data pass.
+ */
+DECLCALLBACK(int) Item03Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+ NOREF(pVM); NOREF(uPass);
+ if (uVersion != 123)
+ {
+ RTPrintf("Item03: uVersion=%#x, expected 123\n", uVersion);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the size.
+ */
+ uint32_t cb;
+ int rc = SSMR3GetU32(pSSM, &cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item03: SSMR3GetU32 -> %Rrc\n", rc);
+ return rc;
+ }
+ if (cb != TSTSSM_ITEM_SIZE)
+ {
+ RTPrintf("Item03: loaded size doesn't match the real thing. %#x != %#x\n", cb, TSTSSM_ITEM_SIZE);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the memory page by page.
+ */
+ const uint8_t *pu8Org = &gabBigMem[0];
+ while (cb > 0)
+ {
+ char achPage[PAGE_SIZE];
+ rc = SSMR3GetMem(pSSM, &achPage[0], PAGE_SIZE);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item03: SSMR3GetMem(,,%#x) -> %Rrc offset %#x\n", PAGE_SIZE, rc, TSTSSM_ITEM_SIZE - cb);
+ return rc;
+ }
+ if (memcmp(achPage, pu8Org, PAGE_SIZE))
+ {
+ RTPrintf("Item03: compare failed. mem offset=%#x\n", TSTSSM_ITEM_SIZE - cb);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /* next */
+ cb -= PAGE_SIZE;
+ pu8Org += PAGE_SIZE;
+ if (pu8Org >= &gabBigMem[sizeof(gabBigMem)])
+ pu8Org = &gabBigMem[0];
+ }
+
+ return 0;
+}
+
+
+/**
+ * Execute state save operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ */
+DECLCALLBACK(int) Item04Save(PVM pVM, PSSMHANDLE pSSM)
+{
+ NOREF(pVM);
+ uint64_t u64Start = RTTimeNanoTS();
+
+ /*
+ * Put the size.
+ */
+ uint32_t cb = 512*_1M;
+ int rc = SSMR3PutU32(pSSM, cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item04: PutU32 -> %Rrc\n", rc);
+ return rc;
+ }
+
+ /*
+ * Put 512 MB page by page.
+ */
+ while (cb > 0)
+ {
+ rc = SSMR3PutMem(pSSM, gabPage, PAGE_SIZE);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item04: PutMem(,%p,%#x) -> %Rrc\n", gabPage, PAGE_SIZE, rc);
+ return rc;
+ }
+
+ /* next */
+ cb -= PAGE_SIZE;
+ }
+
+ uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Saved 4th item in %'RI64 ns\n", u64Elapsed);
+ return 0;
+}
+
+/**
+ * Prepare state load operation.
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM handle.
+ * @param pSSM SSM operation handle.
+ * @param uVersion The data layout version.
+ * @param uPass The data pass.
+ */
+DECLCALLBACK(int) Item04Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+ NOREF(pVM); NOREF(uPass);
+ if (uVersion != 42)
+ {
+ RTPrintf("Item04: uVersion=%#x, expected 42\n", uVersion);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the size.
+ */
+ uint32_t cb;
+ int rc = SSMR3GetU32(pSSM, &cb);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item04: SSMR3GetU32 -> %Rrc\n", rc);
+ return rc;
+ }
+ if (cb != 512*_1M)
+ {
+ RTPrintf("Item04: loaded size doesn't match the real thing. %#x != %#x\n", cb, 512*_1M);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /*
+ * Load the memory page by page.
+ */
+ while (cb > 0)
+ {
+ char achPage[PAGE_SIZE];
+ rc = SSMR3GetMem(pSSM, &achPage[0], PAGE_SIZE);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item04: SSMR3GetMem(,,%#x) -> %Rrc offset %#x\n", PAGE_SIZE, rc, 512*_1M - cb);
+ return rc;
+ }
+ if (memcmp(achPage, gabPage, PAGE_SIZE))
+ {
+ RTPrintf("Item04: compare failed. mem offset=%#x\n", 512*_1M - cb);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /* next */
+ cb -= PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Creates a mockup VM structure for testing SSM.
+ *
+ * @returns 0 on success, 1 on failure.
+ * @param ppVM Where to store Pointer to the VM.
+ *
+ * @todo Move this to VMM/VM since it's stuff done by several testcases.
+ */
+static int createFakeVM(PVM *ppVM)
+{
+ /*
+ * Allocate and init the UVM structure.
+ */
+ PUVM pUVM = (PUVM)RTMemPageAllocZ(sizeof(*pUVM));
+ AssertReturn(pUVM, 1);
+ pUVM->u32Magic = UVM_MAGIC;
+ pUVM->vm.s.idxTLS = RTTlsAlloc();
+ int rc = RTTlsSet(pUVM->vm.s.idxTLS, &pUVM->aCpus[0]);
+ if (RT_SUCCESS(rc))
+ {
+ pUVM->aCpus[0].pUVM = pUVM;
+ pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf();
+
+ rc = STAMR3InitUVM(pUVM);
+ if (RT_SUCCESS(rc))
+ {
+ rc = MMR3InitUVM(pUVM);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Allocate and init the VM structure.
+ */
+ PVM pVM = (PVM)RTMemPageAllocZ(sizeof(VM) + sizeof(VMCPU));
+ rc = pVM ? VINF_SUCCESS : VERR_NO_PAGE_MEMORY;
+ if (RT_SUCCESS(rc))
+ {
+ pVM->enmVMState = VMSTATE_CREATED;
+ pVM->pVMR3 = pVM;
+ pVM->pUVM = pUVM;
+ pVM->cCpus = 1;
+
+ PVMCPU pVCpu = (PVMCPU)(pVM + 1);
+ pVCpu->pVMR3 = pVM;
+ pVCpu->hNativeThread = RTThreadNativeSelf();
+ pVM->apCpusR3[0] = pVCpu;
+
+ pUVM->pVM = pVM;
+ *ppVM = pVM;
+ return 0;
+ }
+
+ RTPrintf("Fatal error: failed to allocated pages for the VM structure, rc=%Rrc\n", rc);
+ }
+ else
+ RTPrintf("Fatal error: MMR3InitUVM failed, rc=%Rrc\n", rc);
+ }
+ else
+ RTPrintf("Fatal error: SSMR3InitUVM failed, rc=%Rrc\n", rc);
+ }
+ else
+ RTPrintf("Fatal error: RTTlsSet failed, rc=%Rrc\n", rc);
+
+ *ppVM = NULL;
+ return 1;
+}
+
+
+/**
+ * Destroy the VM structure.
+ *
+ * @param pVM Pointer to the VM.
+ *
+ * @todo Move this to VMM/VM since it's stuff done by several testcases.
+ */
+static void destroyFakeVM(PVM pVM)
+{
+ STAMR3TermUVM(pVM->pUVM);
+ MMR3TermUVM(pVM->pUVM);
+}
+
+
+/**
+ * Entry point.
+ */
+int main(int argc, char **argv)
+{
+ /*
+ * Init runtime and static data.
+ */
+ int rc = RTR3InitExe(argc, &argv, 0);
+ AssertRCReturn(rc, RTEXITCODE_INIT);
+ RTPrintf("tstSSM: TESTING...\n");
+ initBigMem();
+ const char *pszFilename = "SSMTestSave#1";
+
+ /*
+ * Create an fake VM structure and init SSM.
+ */
+ PVM pVM;
+ if (createFakeVM(&pVM))
+ return 1;
+
+ /*
+ * Register a few callbacks.
+ */
+ rc = SSMR3RegisterInternal(pVM, "SSM Testcase Data Item no.1 (all types)", 1, 0, 256,
+ NULL, NULL, NULL,
+ NULL, Item01Save, NULL,
+ NULL, Item01Load, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Register #1 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ rc = SSMR3RegisterInternal(pVM, "SSM Testcase Data Item no.2 (rand mem)", 2, 0, _1M * 8,
+ NULL, NULL, NULL,
+ NULL, Item02Save, NULL,
+ NULL, Item02Load, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Register #2 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ rc = SSMR3RegisterInternal(pVM, "SSM Testcase Data Item no.3 (big mem)", 0, 123, 512*_1M,
+ NULL, NULL, NULL,
+ NULL, Item03Save, NULL,
+ NULL, Item03Load, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Register #3 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ rc = SSMR3RegisterInternal(pVM, "SSM Testcase Data Item no.4 (big zero mem)", 0, 42, 512*_1M,
+ NULL, NULL, NULL,
+ NULL, Item04Save, NULL,
+ NULL, Item04Load, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Register #4 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ /*
+ * Attempt a save.
+ */
+ uint64_t u64Start = RTTimeNanoTS();
+ rc = SSMR3Save(pVM, pszFilename, NULL, NULL, SSMAFTER_DESTROY, NULL, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Save #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Saved in %'RI64 ns\n", u64Elapsed);
+
+ RTFSOBJINFO Info;
+ rc = RTPathQueryInfo(pszFilename, &Info, RTFSOBJATTRADD_NOTHING);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("tstSSM: failed to query file size: %Rrc\n", rc);
+ return 1;
+ }
+ RTPrintf("tstSSM: file size %'RI64 bytes\n", Info.cbObject);
+
+ /*
+ * Attempt a load.
+ */
+ u64Start = RTTimeNanoTS();
+ rc = SSMR3Load(pVM, pszFilename, NULL /*pStreamOps*/, NULL /*pStreamOpsUser*/,
+ SSMAFTER_RESUME, NULL /*pfnProgress*/, NULL /*pvProgressUser*/);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Load #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Loaded in %'RI64 ns\n", u64Elapsed);
+
+ /*
+ * Validate it.
+ */
+ u64Start = RTTimeNanoTS();
+ rc = SSMR3ValidateFile(pszFilename, false /* fChecksumIt*/ );
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3ValidateFile #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Validated without checksumming in %'RI64 ns\n", u64Elapsed);
+
+ u64Start = RTTimeNanoTS();
+ rc = SSMR3ValidateFile(pszFilename, true /* fChecksumIt */);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3ValidateFile #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Validated and checksummed in %'RI64 ns\n", u64Elapsed);
+
+ /*
+ * Open it and read.
+ */
+ u64Start = RTTimeNanoTS();
+ PSSMHANDLE pSSM;
+ rc = SSMR3Open(pszFilename, 0, &pSSM);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Open #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Opened in %'RI64 ns\n", u64Elapsed);
+
+ /* negative */
+ u64Start = RTTimeNanoTS();
+ rc = SSMR3Seek(pSSM, "some unit that doesn't exist", 0, NULL);
+ if (rc != VERR_SSM_UNIT_NOT_FOUND)
+ {
+ RTPrintf("SSMR3Seek #1 negative -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Failed seek in %'RI64 ns\n", u64Elapsed);
+
+ /* another negative, now only the instance number isn't matching. */
+ rc = SSMR3Seek(pSSM, "SSM Testcase Data Item no.2 (rand mem)", 0, NULL);
+ if (rc != VERR_SSM_UNIT_NOT_FOUND)
+ {
+ RTPrintf("SSMR3Seek #1 unit 2 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ /* 2nd unit */
+ rc = SSMR3Seek(pSSM, "SSM Testcase Data Item no.2 (rand mem)", 2, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Seek #1 unit 2 -> %Rrc [2]\n", rc);
+ return 1;
+ }
+ uint32_t uVersion = 0xbadc0ded;
+ rc = SSMR3Seek(pSSM, "SSM Testcase Data Item no.2 (rand mem)", 2, &uVersion);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Seek #1 unit 2 -> %Rrc [3]\n", rc);
+ return 1;
+ }
+ u64Start = RTTimeNanoTS();
+ rc = Item02Load(NULL, pSSM, uVersion, SSM_PASS_FINAL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item02Load #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Loaded 2nd item in %'RI64 ns\n", u64Elapsed);
+
+ /* 1st unit */
+ uVersion = 0xbadc0ded;
+ rc = SSMR3Seek(pSSM, "SSM Testcase Data Item no.1 (all types)", 1, &uVersion);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Seek #1 unit 1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Start = RTTimeNanoTS();
+ rc = Item01Load(NULL, pSSM, uVersion, SSM_PASS_FINAL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01Load #1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Loaded 1st item in %'RI64 ns\n", u64Elapsed);
+
+ /* 3st unit */
+ uVersion = 0xbadc0ded;
+ rc = SSMR3Seek(pSSM, "SSM Testcase Data Item no.3 (big mem)", 0, &uVersion);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Seek #3 unit 1 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Start = RTTimeNanoTS();
+ rc = Item03Load(NULL, pSSM, uVersion, SSM_PASS_FINAL);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("Item01Load #3 -> %Rrc\n", rc);
+ return 1;
+ }
+ u64Elapsed = RTTimeNanoTS() - u64Start;
+ RTPrintf("tstSSM: Loaded 3rd item in %'RI64 ns\n", u64Elapsed);
+
+ /* close */
+ rc = SSMR3Close(pSSM);
+ if (RT_FAILURE(rc))
+ {
+ RTPrintf("SSMR3Close #1 -> %Rrc\n", rc);
+ return 1;
+ }
+
+ destroyFakeVM(pVM);
+
+ /* delete */
+ RTFileDelete(pszFilename);
+
+ RTPrintf("tstSSM: SUCCESS\n");
+ return 0;
+}
+